/* ============================================================================
   Workspace — the shared workbench chrome for the Developer and Translator
   views (specs 006 / 007).

   Two ideas drive this file:

   1. The data model is a containment chain (Projekt > Modul > Messageset >
      Nachricht). The command bar renders that chain as ONE connected control
      with chevrons between the segments, so the toolbar states a fact about
      the data instead of stacking four labelled dropdowns.

   2. Identifiers are code, prose is language. Tags, module names and
      messageset keys are pasted into source files, so they get the mono voice
      (--kk-mono, türkis); developer text and translations stay in Barlow.

   Row geometry is fixed on purpose: <Virtualize> needs a stable ItemSize, and
   a stable row height is also what keeps the icon columns from stretching
   rows. The cell editor therefore floats ABOVE the grid instead of growing
   its row.
   ============================================================================ */

/* ── Command bar ─────────────────────────────────────────────────────────── */

.ws-bar {
    flex: 0 0 auto;
    position: sticky;
    top: 0;
    z-index: 40;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--kk-bg-card);
    border-bottom: 1px solid var(--kk-grid-line-strong);
}

.ws-ident {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    font-weight: 700;
    font-size: 0.875rem;
    letter-spacing: 0.01em;
    color: var(--kk-text-primary);
    white-space: nowrap;
}

.ws-ident i {
    color: var(--kk-tuerkis);
    font-size: 0.9rem;
}

.ws-divider {
    width: 1px;
    align-self: stretch;
    margin-inline: 0.15rem;
    background: var(--kk-grid-line-strong);
}

.ws-spacer {
    flex: 1 1 auto;
}

/* ── Scope chain: Projekt › Modul › Messageset ───────────────────────────── */

.scope {
    display: flex;
    align-items: center;
    height: 34px;
    background: var(--kk-bg-deep);
    border: 1px solid var(--kk-border);
    border-radius: 6px;
    min-width: 0;
}

.scope:focus-within {
    border-color: var(--kk-lila);
}

.scope-seg {
    display: flex;
    align-items: center;
    min-width: 0;
}

.scope-select {
    appearance: none;
    -webkit-appearance: none;
    max-width: 200px;
    min-width: 96px;
    height: 32px;
    padding: 0 1.35rem 0 0.55rem;
    border: 0;
    background-color: transparent;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23AA5AFF' stroke-width='2'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.35rem center;
    background-size: 11px;
    color: var(--kk-text-secondary);
    font-family: inherit;
    font-size: 0.8125rem;
    text-overflow: ellipsis;
    cursor: pointer;
}

/* A segment that carries a value is part of the current scope — say so. */
.scope-select.is-set {
    color: var(--kk-text-primary);
    font-weight: 600;
}

.scope-select:focus {
    outline: 2px solid var(--kk-lila);
    outline-offset: -2px;
}

.scope-select:disabled {
    color: var(--kk-text-muted);
    cursor: not-allowed;
    opacity: 0.55;
}

.scope-select option {
    background: var(--kk-bg-card);
    color: var(--kk-text-primary);
}

.scope-clear {
    border: 0;
    background: transparent;
    color: var(--kk-text-muted);
    padding: 0 0.3rem 0 0;
    font-size: 0.7rem;
    line-height: 1;
    cursor: pointer;
}

.scope-clear:hover {
    color: var(--kk-orange);
}

.scope-chev {
    flex: 0 0 auto;
    color: var(--kk-text-muted);
    font-size: 0.6rem;
    padding-inline: 0.1rem;
}

/* The target language is not part of the containment chain — it is the axis
   you translate INTO — so it sits in its own control, not in the chain. */
.scope--language .scope-select.is-set {
    color: var(--kk-tuerkis);
}

/* ── Search ──────────────────────────────────────────────────────────────── */

.ws-search {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    flex: 1 1 260px;
    min-width: 200px;
    max-width: 460px;
    height: 34px;
    padding: 0 0.4rem;
    background: var(--kk-bg-deep);
    border: 1px solid var(--kk-border);
    border-radius: 6px;
}

.ws-search:focus-within {
    border-color: var(--kk-lila);
    box-shadow: 0 0 0 0.15rem rgba(170, 90, 255, 0.15);
}

.ws-search > i {
    color: var(--kk-text-muted);
    font-size: 0.8rem;
}

.ws-search-input {
    flex: 1 1 auto;
    min-width: 0;
    height: 30px;
    border: 0;
    background: transparent;
    color: var(--kk-text-primary);
    font-family: inherit;
    font-size: 0.8125rem;
}

.ws-search-input:focus {
    outline: none;
}

.ws-search-input::placeholder {
    color: var(--kk-text-muted);
}

.ws-search-input:disabled {
    cursor: not-allowed;
}

/* Scope-of-search toggles live inside the field they modify. */
.facet {
    border: 1px solid transparent;
    border-radius: 4px;
    background: transparent;
    color: var(--kk-text-muted);
    font-family: inherit;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    padding: 0.08rem 0.35rem;
    cursor: pointer;
    white-space: nowrap;
}

.facet:hover {
    color: var(--kk-text-secondary);
}

.facet.is-on {
    background: rgba(170, 90, 255, 0.18);
    border-color: var(--kk-border-hover);
    color: var(--kk-text-primary);
}

.facet:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: 1px;
}

.ws-icon-btn {
    border: 0;
    background: transparent;
    color: var(--kk-text-muted);
    font-size: 0.75rem;
    line-height: 1;
    padding: 0.2rem;
    cursor: pointer;
}

.ws-icon-btn:hover {
    color: var(--kk-text-primary);
}

/* ── Result counter ──────────────────────────────────────────────────────── */

.ws-count {
    display: inline-flex;
    align-items: baseline;
    gap: 0.3rem;
    font-size: 0.75rem;
    color: var(--kk-text-muted);
    white-space: nowrap;
}

.ws-count strong {
    font-family: var(--kk-mono);
    font-size: 0.8125rem;
    font-variant-numeric: tabular-nums;
    color: var(--kk-text-primary);
}

/* ── Progress ────────────────────────────────────────────────────────────────
   Information, not a control — it stays in the command bar rather than moving into
   the opt-in tools row, and adds no affordance to the default view.
   ========================================================================== */

.ws-progress {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-left: 0.15rem;
}

.ws-progress-pct {
    font-family: var(--kk-mono);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--kk-text-secondary);
}

.ws-progress-bar {
    display: inline-block;
    position: relative;
    width: 56px;
    height: 3px;
    border-radius: 2px;
    background: var(--kk-grid-line-strong);
    overflow: hidden;
}

.ws-progress-fill {
    display: block;
    height: 100%;
    background: var(--kk-tuerkis);
    transition: width 0.2s ease;
}

@media (prefers-reduced-motion: reduce) {
    .ws-progress-fill {
        transition: none;
    }
}

/* "von 1.840" — the denominator is context, so it stays quieter than the count. */
.ws-count-of {
    font-family: var(--kk-mono);
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
    color: var(--kk-text-muted);
}

/* ── Tools row ───────────────────────────────────────────────────────────────
   Everything here is opt-in. The command bar above is the whole default UI; this
   row only exists once the translator asks for it, which is why the toggle carries
   a marker when a filter is active — a hidden row must never hide state.
   ========================================================================== */

.ws-tools-toggle {
    position: relative;
    font-size: 0.8125rem;
}

.ws-tools-toggle.is-open {
    color: var(--kk-text-primary);
}

.ws-tools-toggle.is-marked::after {
    content: "";
    position: absolute;
    top: 0.05rem;
    right: 0.02rem;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--kk-tuerkis);
}

.ws-bar2 {
    flex: 0 0 auto;
    position: sticky;
    top: 0;
    z-index: 39;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1.1rem;
    padding: 0.5rem 0.75rem;
    background: var(--kk-bg-deep);
    border-bottom: 1px solid var(--kk-grid-line-strong);
}

.ws-group {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    min-width: 0;
}

.ws-group-label {
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--kk-text-muted);
    white-space: nowrap;
}

.ws-bar2 .ws-group-label {
    font-size: 0.6875rem;
}

.ws-chips {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    flex-wrap: wrap;
}

/* The tools row now holds two things only — what to show of the data, and which
   of it — so its chips are the row's whole point and are sized as real buttons.
   The micro-toggles .facet describes still exist, but only where they belong:
   inside the search field, modifying the control they sit in. */
.ws-bar2 .ws-chips {
    gap: 0.3rem;
}

.ws-bar2 .facet {
    padding: 0.25rem 0.6rem;
    border-color: var(--kk-border);
    border-radius: 5px;
    font-size: 0.75rem;
    letter-spacing: 0;
    text-transform: none;
    color: var(--kk-text-secondary);
}

.ws-bar2 .facet:hover {
    background: var(--kk-bg-card-hover);
    border-color: var(--kk-border-hover);
    color: var(--kk-text-primary);
}

.ws-bar2 .facet.is-on {
    background: rgba(170, 90, 255, 0.18);
    border-color: var(--kk-lila);
    color: var(--kk-text-primary);
}

/* A column chip says "this column is on screen", not "this filter is running" —
   a state, not an action. The dot makes that readable without having to compare
   fill colours across the row. */
.ws-bar2 .ws-chips--columns .facet::before {
    content: "";
    display: inline-block;
    width: 7px;
    height: 7px;
    margin-right: 0.4rem;
    border: 1px solid currentColor;
    border-radius: 50%;
    opacity: 0.7;
    vertical-align: 0;
}

.ws-bar2 .ws-chips--columns .facet.is-on::before {
    background: var(--kk-tuerkis);
    border-color: var(--kk-tuerkis);
    opacity: 1;
}

.ws-bar2 .ws-linkbtn {
    font-size: 0.75rem;
}

/* The way back to everything that USED to be in this row. */
.ws-linkbtn--settings:hover {
    color: var(--kk-tuerkis);
}

.ws-linkbtn {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    border: 0;
    background: transparent;
    padding: 0;
    font-family: inherit;
    font-size: 0.6875rem;
    color: var(--kk-text-muted);
    cursor: pointer;
}

.ws-linkbtn:hover {
    color: var(--kk-lila);
    text-decoration: underline;
}

.ws-linkbtn:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: 1px;
}

.ws-actions {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.ws-actions .btn {
    height: 34px;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.8125rem;
    white-space: nowrap;
}

/* ── Grid ────────────────────────────────────────────────────────────────── */

.grid {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    position: relative;
    background: var(--kk-bg-deep);
}

.grid-head {
    position: sticky;
    top: 0;
    z-index: 30;
    display: grid;
    grid-template-columns: var(--cols);
    min-width: var(--grid-min-w, 720px);
    height: 30px;
    background: var(--kk-bg-card);
    border-bottom: 1px solid var(--kk-grid-line-strong);
}

.gh {
    /* Anchors the absolutely positioned .gh-resize handle to this column. */
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.3rem;
    min-width: 0;
    padding: 0 0.5rem;
    border: 0;
    border-right: 1px solid var(--kk-grid-line);
    background: transparent;
    color: var(--kk-text-secondary);
    font-family: inherit;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
}

.gh:last-child {
    border-right: 0;
}

.gh--icon,
.gh--sort {
    padding: 0;
}

/* ── Column resize handle ────────────────────────────────────────────────────
   Sits on the column's trailing edge. Wider than it looks — a 1px target is not
   grabbable — but only visible on hover, so the header stays quiet at rest.
   ========================================================================== */

.gh-resize {
    position: absolute;
    top: 0;
    right: -3px;
    width: 7px;
    height: 100%;
    cursor: col-resize;
    z-index: 2;
    touch-action: none;
}

.gh-resize::after {
    content: "";
    position: absolute;
    top: 20%;
    left: 3px;
    width: 1px;
    height: 60%;
    background: transparent;
}

.gh:hover .gh-resize::after,
.gh-resize:hover::after {
    background: var(--kk-lila);
}

/* Keep the pointer as a resize cursor for the whole drag, even where it leaves
   the handle, and stop the drag from selecting header text. */
body.is-col-resizing {
    cursor: col-resize;
    user-select: none;
}

.gh-btn {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    width: 100%;
    height: 100%;
    min-width: 0;
    padding: 0 0.5rem;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-align: left;
    white-space: nowrap;
    overflow: hidden;
    cursor: pointer;
}

.gh-btn:hover {
    color: var(--kk-text-primary);
    background: rgba(170, 90, 255, 0.07);
}

.gh-btn:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: -2px;
}

.gh-label {
    overflow: hidden;
    text-overflow: ellipsis;
}

.gh.is-sorted {
    color: var(--kk-text-primary);
    box-shadow: inset 0 -2px 0 var(--kk-lila);
}

.sort-ind {
    font-size: 0.6rem;
    opacity: 0.3;
}

.gh.is-sorted .sort-ind {
    opacity: 1;
    color: var(--kk-lila);
}

.grid-body {
    min-width: var(--grid-min-w, 720px);
}

.grid-row {
    display: grid;
    grid-template-columns: var(--cols);
    min-width: var(--grid-min-w, 720px);
    height: var(--kk-row-h);
    border-bottom: 1px solid var(--kk-grid-line);
}

/* The overscan band deliberately keeps far more rows in the DOM than fit on screen —
   that is what buys a scroll gesture without a server round trip (GridVirtualisation) —
   and this is what stops the browser paying for the ones nobody is looking at: they are
   skipped for layout and paint until they come near the viewport. No
   contain-intrinsic-size is needed with it, and none is given: the row's height is a
   fixed contract with Virtualize and its width comes from the block above it, so a
   skipped row is already fully sized without ever measuring its contents.

   Never the open editor's row. content-visibility implies paint containment, and the
   editor is absolutely positioned precisely so that it can overflow its row. */
.grid-row:not(.is-editing) {
    content-visibility: auto;
}

.grid-row:hover {
    background: var(--kk-bg-card-hover);
}

/* The open editor floats over the rows below it, so its row needs to win the
   stacking order — but stay under the sticky column header. */
.grid-row.is-editing {
    position: relative;
    z-index: 20;
    background: var(--kk-bg-card-hover);
}

/* A row on its way out must not keep a hover response it can no longer act on. */
.grid-row.is-deleting {
    opacity: 0.35;
    pointer-events: none;
}

/* ── Cells ───────────────────────────────────────────────────────────────── */

.cell {
    position: relative;
    display: flex;
    align-items: center;
    min-width: 0;
    padding: 0 0.5rem;
    border-right: 1px solid var(--kk-grid-line);
    font-size: 0.8125rem;
}

.cell:last-child {
    border-right: 0;
}

.cell-text {
    width: 100%;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ── Density ─────────────────────────────────────────────────────────────────
   Taller rows let a long translation be read without opening its editor. The row
   height stays FIXED at every density — Virtualize derives scroll position from it,
   so rows that size themselves to their content would desynchronise the scrollbar.
   The compact rules above are left untouched, so the default view renders exactly as
   it did before densities existed.
   ========================================================================== */

.workspace.is-multiline .cell {
    align-items: flex-start;
    padding-top: 0.3rem;
}

.workspace.is-multiline .cell-text {
    white-space: normal;
    text-overflow: clip;
    display: -webkit-box;
    -webkit-line-clamp: var(--cell-lines, 2);
    line-clamp: var(--cell-lines, 2);
    -webkit-box-orient: vertical;
    line-height: 1.25;
}

/* ── Geändert column ─────────────────────────────────────────────────────── */

.cell--changed .cell-text {
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.cell--muted .cell-text {
    color: var(--kk-text-secondary);
}

.cell--mono .cell-text,
.cell--mono .cell-editor input {
    font-family: var(--kk-mono);
    font-size: 0.78125rem;
    letter-spacing: -0.01em;
    color: var(--kk-tuerkis);
}

/* The translator's tag column — same look as .cell--mono, which is how the messageset
   beside it and the editable tag in the developer workspace are rendered. It is a
   column of its own now: the developer text that used to sit under it as a muted
   sub-line is a full text column beside Deutsch (007 FR-009a). */
.mono-tag {
    font-family: var(--kk-mono);
    font-size: 0.78125rem;
    letter-spacing: -0.01em;
    color: var(--kk-tuerkis);
}

.cell--edit {
    cursor: text;
}

/* Editability is shown by a hairline that lights up on the row you are on —
   the pencil buttons that used to carry this were 800 extra DOM nodes. */
.cell--edit::after {
    content: "";
    position: absolute;
    left: 0;
    top: 5px;
    bottom: 5px;
    width: 2px;
    background: var(--kk-lila);
    opacity: 0;
    transition: opacity 0.12s ease;
}

.grid-row:hover .cell--edit::after {
    opacity: 0.3;
}

.cell--edit:hover::after {
    opacity: 1;
}

/* The focus ring belongs to EVERY cell, not just the editable ones: the arrow keys
   walk the whole row, and a read-only cell that swallowed the ring would lose the
   reader's place mid-row. Editable cells light their hairline on top of it. */
.cell:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: -2px;
}

.cell--edit:focus-visible::after {
    opacity: 1;
}

/* An empty cell still has to look like somewhere you can type. */
.cell-placeholder {
    color: var(--kk-text-muted);
    font-style: italic;
}

.cell--icon {
    padding: 0;
    justify-content: center;
}

.icon-btn {
    appearance: none;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--kk-text-muted);
    font-size: 0.75rem;
    line-height: 1;
    display: grid;
    place-items: center;
    cursor: pointer;
    transition: color 0.12s ease, background-color 0.12s ease;
}

.icon-btn:hover {
    color: var(--kk-tuerkis);
    background: rgba(105, 245, 200, 0.1);
}

.icon-btn--danger:hover {
    color: var(--kk-orange);
    background: rgba(255, 102, 0, 0.12);
}

.icon-btn:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: -2px;
}

/* ── Cell editor (floats over the grid, never resizes its row) ───────────── */

/* Flush with the cell, never past it: a 1px overhang on the last column was
   enough to give the grid a horizontal scrollbar it did not need. */
.cell-editor {
    position: absolute;
    inset-inline: 0;
    top: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    padding: 0.3rem;
    min-height: var(--kk-row-h);
    background: var(--kk-bg-card);
    border: 1px solid var(--kk-lila);
    border-radius: 5px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.6);
}

.cell-editor textarea,
.cell-editor input {
    width: 100%;
    min-width: 0;
    max-height: 40vh;
    resize: none;
    overflow: auto;
    padding: 0.15rem 0.35rem;
    background: var(--kk-bg-deep);
    color: var(--kk-text-primary);
    border: 1px solid var(--kk-border);
    border-radius: 4px;
    font-family: inherit;
    font-size: 0.8125rem;
    line-height: 1.35;
}

.cell-editor textarea:focus,
.cell-editor input:focus {
    outline: none;
    border-color: var(--kk-border-hover);
}

/* ── Editor extras ───────────────────────────────────────────────────────────
   "Deutsch übernehmen" plus any translation already used for the same German
   source. Offered only for an empty cell, so this row is absent while correcting
   an existing translation.
   ========================================================================== */

.edit-extras {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    margin-bottom: 0.3rem;
}

.ed-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    max-width: 100%;
    border: 1px solid var(--kk-border);
    border-radius: 4px;
    background: var(--kk-bg-deep);
    color: var(--kk-text-secondary);
    font-family: inherit;
    font-size: 0.75rem;
    padding: 0.1rem 0.4rem;
    cursor: pointer;
    text-align: left;
}

.ed-chip:hover {
    border-color: var(--kk-lila);
    color: var(--kk-text-primary);
}

.ed-chip:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: 1px;
}

/* A suggestion can be a whole sentence; it must not push the editor wider. */
.ed-chip--suggestion {
    overflow: hidden;
}

.ed-chip--suggestion > :not(.ed-chip-count) {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ed-chip-count {
    flex: 0 0 auto;
    font-family: var(--kk-mono);
    font-size: 0.6875rem;
    color: var(--kk-text-muted);
}

.edit-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.25rem;
}

.edit-hint {
    margin-right: auto;
    font-size: 0.6875rem;
    color: var(--kk-text-muted);
    white-space: nowrap;
}

.ed-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
    border: 1px solid transparent;
    border-radius: 4px;
    padding: 0.1rem 0.45rem;
    font-family: inherit;
    font-size: 0.75rem;
    line-height: 1.3;
    cursor: pointer;
}

.ed-btn--ok {
    background: var(--kk-tuerkis);
    color: var(--kk-bg-deep);
    font-weight: 600;
}

.ed-btn--ok:hover {
    background: var(--kk-tuerkis-dunkel);
}

.ed-btn--cancel {
    background: transparent;
    border-color: var(--kk-border);
    color: var(--kk-text-secondary);
}

.ed-btn--cancel:hover {
    color: var(--kk-text-primary);
    border-color: var(--kk-border-hover);
}

.ed-btn--danger {
    background: var(--kk-orange);
    color: #fff;
    font-weight: 600;
}

.ed-btn--danger:hover {
    background: #e55c00;
}

.ed-btn:focus-visible {
    outline: 2px solid var(--kk-lila);
    outline-offset: 1px;
}

/* ── Row-level delete confirmation ───────────────────────────────────────── */

/* The confirmation replaces the row it is about, at the same height. Nothing
   new appears anywhere else on the page. */
.row-confirm {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0 0.5rem;
    font-size: 0.75rem;
    color: var(--kk-text-primary);
    background: rgba(255, 102, 0, 0.14);
    box-shadow: inset 3px 0 0 var(--kk-orange);
}

.row-confirm .confirm-subject {
    margin-right: auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--kk-mono);
    color: var(--kk-text-secondary);
}

/* ── New-entry line (Developer) ──────────────────────────────────────────── */

/* Laid out on the same column track as the grid, so it reads as the next row
   rather than as a detached form. */
.ws-newrow {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: var(--cols);
    min-width: var(--grid-min-w, 720px);
    align-items: center;
    background: var(--kk-bg-card);
    border-top: 1px solid var(--kk-grid-line-strong);
}

.ws-newrow-cell {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    min-width: 0;
    padding: 0.3rem 0.5rem;
}

.ws-newrow input {
    width: 100%;
    min-width: 0;
    height: 28px;
    padding: 0 0.35rem;
    background: var(--kk-bg-deep);
    color: var(--kk-text-primary);
    border: 1px solid var(--kk-border);
    border-radius: 4px;
    font-family: inherit;
    font-size: 0.8125rem;
}

.ws-newrow input.mono {
    font-family: var(--kk-mono);
    font-size: 0.78125rem;
}

.ws-newrow input:focus {
    outline: none;
    border-color: var(--kk-lila);
}

.ws-newrow .btn {
    height: 28px;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.75rem;
    white-space: nowrap;
}

.ws-newrow-lead {
    display: grid;
    place-items: center;
    color: var(--kk-text-muted);
    font-size: 0.75rem;
}

/* ── Empty / status states ───────────────────────────────────────────────── */

.ws-empty {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    padding: 2rem 1rem;
    color: var(--kk-text-muted);
    text-align: center;
}

.ws-empty i {
    font-size: 1.75rem;
    opacity: 0.5;
}

.ws-empty .ws-empty-hint {
    font-size: 0.8125rem;
}

.ws-note {
    flex: 0 0 auto;
    padding: 0.4rem 0.75rem;
    font-size: 0.8125rem;
    color: var(--kk-text-primary);
    background: rgba(10, 174, 254, 0.08);
    border-bottom: 1px solid var(--kk-grid-line);
}

/* ── Narrow viewports ────────────────────────────────────────────────────── */

@media (max-width: 991.98px) {
    .ws-bar {
        gap: 0.4rem;
    }

    .scope {
        flex: 1 1 100%;
    }

    .scope-seg {
        flex: 1 1 0;
    }

    .scope-select {
        width: 100%;
        max-width: none;
    }

    .ws-search {
        max-width: none;
    }

    .ws-spacer {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .cell--edit::after,
    .icon-btn {
        transition: none;
    }
}
