/* agentmundo PWA — design language per architecture-v2 §5.
   Machine facts monospace, human labels sans. Two weights (400/500). Sentence case. One accent.
   Near-monochrome. Semantic color rationed. Motion <=120ms except the stream. */

/* ============================================================================================================
   SLICE A — Command Deck design tokens (ADDITIVE, applied to NOTHING yet).
   Folds DESIGN-TOKENS.md §1–6 into custom properties + self-hosted fonts + namespaced keyframes. This layer
   DEFINES the vocabulary the migration will consume slice-by-slice; it changes ZERO existing computed style.
   Everything here is namespaced `--cd-*` / `cd-*` so it cannot collide with the live tokens (--accent, --mono,
   the `am-dot`/`chip-pulse` keyframes, …). The live UI names none of these families/vars/keyframes, so the
   fonts are never fetched and the keyframes/tokens are inert until a future slice references them.
   ============================================================================================================ */

/* §1 — SELF-HOSTED fonts (no external CDN; the PWA is offline over Tailscale). Space Grotesk is a variable
   font (wght 300–700 → one file covers 400/500/600/700); IBM Plex Mono is static 400/500/600. woff2 extracted
   from the desktop demo bundle → src/web/fonts/. Nothing sets these families yet, so nothing loads them yet. */
@font-face { font-family: 'Space Grotesk'; font-style: normal; font-weight: 300 700; font-display: swap; src: url('./fonts/space-grotesk.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('./fonts/ibm-plex-mono-400.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('./fonts/ibm-plex-mono-500.woff2') format('woff2'); }
@font-face { font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 600; font-display: swap; src: url('./fonts/ibm-plex-mono-600.woff2') format('woff2'); }

:root {
  /* §1 — type families (consumed later; the live UI keeps --sans/--mono) */
  --cd-font-sans: 'Space Grotesk', system-ui, sans-serif;
  --cd-font-mono: 'IBM Plex Mono', ui-monospace, monospace;

  /* §2 — base palette, neutral surfaces (hue 265, low chroma) */
  --cd-bg-void: oklch(0.1 0.01 265);        /* deepest — code/command insets */
  --cd-bg-app: oklch(0.13 0.012 265);       /* app / phone-frame background */
  --cd-bg-app-2: oklch(0.15 0.012 265);     /* outer backdrop / desktop canvas */
  --cd-surface-sheet: oklch(0.17 0.014 265);/* the decision sheet */
  --cd-surface-1: oklch(0.2 0.015 265);     /* buttons, drop targets, tags */
  --cd-surface-2: oklch(0.22 0.02 265);     /* chips, secondary fills */
  --cd-line-1: oklch(0.24 0.015 265);       /* faint dividers, idle relay track */
  --cd-line-2: oklch(0.28 0.02 265);        /* default borders */
  --cd-line-3: oklch(0.3 0.02 265);         /* sheet / control borders */
  --cd-line-strong: oklch(0.32 0.02 265);   /* sidebar / section edges (desktop) */

  /* §2 — text + muted scale */
  --cd-text-hi: oklch(0.95 0 0);
  --cd-text: oklch(0.94 0 0);
  --cd-text-2: oklch(0.9 0 0);
  --cd-text-body: oklch(0.82 0.01 265);     /* stream lines */
  --cd-muted-1: oklch(0.72 0.02 265);
  --cd-muted-2: oklch(0.62 0.02 265);
  --cd-muted-3: oklch(0.58 0.02 265);
  --cd-muted-4: oklch(0.5 0.02 265);        /* uppercase mono labels */

  /* §3 — the THREE ceremony gravities (keep distinct; never a generic "confirm") */
  /* 3a. approval / ordinary passkey — BLUE (hue 260) */
  --cd-approval: oklch(0.6 0.13 260);                 /* anchor */
  --cd-approval-btn: oklch(0.62 0.14 260);
  --cd-approval-btn-hover: oklch(0.68 0.14 260);
  --cd-approval-label: oklch(0.72 0.15 260);
  --cd-approval-chip-bg: oklch(0.24 0.06 260);
  --cd-approval-chip-border: oklch(0.6 0.13 260 / 0.5);
  --cd-approval-chip-dot: oklch(0.78 0.14 260);
  --cd-approval-chip-text: oklch(0.9 0.05 260);
  --cd-approval-overlay: oklch(0.72 0.14 260);
  /* 3b. wall refusal — GOLD (hue 85); calm gold, NO authorize button */
  --cd-wall: oklch(0.8 0.13 85);                      /* anchor: label, command, button text */
  --cd-wall-cmd-border: oklch(0.4 0.1 85 / 0.4);
  --cd-wall-glow: oklch(0.8 0.13 85 / 0.45);          /* am/cd-gold peak */
  --cd-wall-btn-border: oklch(0.5 0.1 85 / 0.5);
  --cd-wall-btn-hover: oklch(0.3 0.06 85 / 0.3);
  /* 3c. production — RED (hue 30); heaviest, two-step confirm→passkey */
  --cd-prod: oklch(0.58 0.2 30);                      /* anchor / primary button */
  --cd-prod-btn-hover: oklch(0.64 0.2 30);
  --cd-prod-label: oklch(0.72 0.2 30);
  --cd-prod-ring: oklch(0.6 0.2 30 / 0.6);            /* confirm inset-ring / glow */
  --cd-prod-domain: oklch(0.75 0.19 30);             /* live-domain name emphasis */
  --cd-prod-cmd: oklch(0.78 0.16 30);
  --cd-prod-cmd-border: oklch(0.4 0.15 30 / 0.4);
  --cd-prod-overlay: oklch(0.7 0.2 30);

  /* §4 — division colors (one hue per agent division) */
  --cd-div-engineering: oklch(0.70 0.15 250);   /* blue */
  --cd-div-design: oklch(0.72 0.16 330);        /* magenta */
  --cd-div-security: oklch(0.68 0.17 32);       /* red-orange */
  --cd-div-testing: oklch(0.72 0.15 155);       /* green */
  --cd-div-specialized: oklch(0.80 0.15 95);    /* gold */
  --cd-div-product: oklch(0.74 0.13 205);       /* cyan */
  /* stream tags */
  --cd-tag-you: oklch(0.95 0 0);
  --cd-tag-system: oklch(0.55 0.02 265);

  /* §5 — semantic */
  --cd-ok: oklch(0.72 0.15 155);                /* daemon reachable / done / success (shares hue 155 w/ testing) */
  --cd-link: oklch(0.74 0.13 205);
  --cd-link-hover: oklch(0.82 0.13 205);

  /* §5b — Slice AL8: the four aliveness states, by ROLE. A panel's state drives five surfaces at once (bar, dot,
     chip, border, shadow), so each state needs a fill, a text colour and a dot, not just an anchor. Working takes
     the approval family unchanged. Needs-you takes the GOLD family — in this product gold already means the
     system has stopped and wants the operator, and an agent's question is that, so a new near-gold hue would have
     been a second colour saying the same thing — but the family had command and button roles and no CHIP, which
     is what the three below add. Error is a family the sheet did not have at all: the only red here belongs to
     production, and an agent failing is not a deploy, so borrowing it would have made the two read alike. */
  --cd-wall-chip-bg: oklch(0.26 0.06 85);
  --cd-wall-chip-text: oklch(0.9 0.06 85);
  --cd-wall-chip-dot: oklch(0.82 0.14 85);
  --cd-error: oklch(0.6 0.17 25);               /* anchor: border, bar */
  --cd-error-chip-bg: oklch(0.25 0.07 25);
  --cd-error-chip-border: oklch(0.6 0.17 25 / 0.5);
  --cd-error-chip-text: oklch(0.9 0.07 25);
  --cd-error-chip-dot: oklch(0.72 0.18 25);
  /* the panel's own lift, so a state ring never has to be written as a raw shadow colour */
  --cd-shadow-panel: oklch(0.05 0 0 / 0.45);

  /* §5c — Slice AL12: the three artifact kinds, by role. A kind here is a fact about a FILE — read off the
     extension of a path the daemon attributed — never about the agent that wrote it, so these are named for what
     they describe. Three anchors and one shared fill: the kind is carried by its edge and its label, which is as
     much colour as a fact this small should spend. */
  --cd-kind-image: oklch(0.72 0.16 320);
  --cd-kind-data: oklch(0.70 0.14 285);
  --cd-kind-file: oklch(0.70 0.12 150);
  --cd-kind-fill: oklch(0.19 0.015 265);
}

/* §6 — motion vocabulary (keyframe → meaning). Defined here, referenced by NOTHING yet. cd- prefixed so they
   never collide with the live `am-dot` / `chip-pulse`. Meanings: pulse=working · turn=needs-you ·
   flow=handoff · gold=wall-refusal · fp+spin=passkey · ring/breathe=live · sheet/rise/slidein=entrances ·
   eq=stream-work · scan=ambient. (steady / no animation = resolved.) */
@keyframes cd-pulse { 0%,100% { transform: scale(1); } 50% { transform: scale(1.1); } }
@keyframes cd-ring { 0% { transform: scale(.75); opacity: .55; } 100% { transform: scale(2); opacity: 0; } }
@keyframes cd-breathe { 0%,100% { opacity: .45; } 50% { opacity: 1; } }
@keyframes cd-turn { 0%,100% { transform: rotate(0); } 30% { transform: rotate(-7deg); } 70% { transform: rotate(7deg); } }
@keyframes cd-flow { 0% { transform: translateX(-8px); opacity: .3; } 50% { opacity: 1; } 100% { transform: translateX(8px); opacity: .3; } }
/* cd-gold is defined in the Slice UI13 block at the foot of this sheet: its two stops are named roles now, and
   this layer defines tokens without consuming any, so a keyframe reading one cannot live here. */
@keyframes cd-fp { 0% { transform: scale(.85); opacity: .4; } 100% { transform: scale(1.5); opacity: 0; } }
@keyframes cd-spin { to { transform: rotate(360deg); } }
@keyframes cd-sheet { from { transform: translateY(102%); } to { transform: translateY(0); } }
@keyframes cd-rise { from { transform: translateY(14px); opacity: 0; } to { transform: translateY(0); opacity: 1; } }
@keyframes cd-slidein { from { transform: translateX(26px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes cd-eq { 0%,100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }
@keyframes cd-scan { from { transform: translateY(-120%); } to { transform: translateY(760%); } }
/* Slice AL8 additions to the same vocabulary. caret=output still arriving · sweep=work in progress along a bar ·
   pop=something you just sent landed. The three the aliveness layer needed and this list did not already have;
   its pulse, rise and slidein cover the rest, so nothing here duplicates a meaning already spelled above. */
@keyframes cd-caret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
@keyframes cd-sweep { 0% { transform: translateX(-100%); } 100% { transform: translateX(320%); } }
@keyframes cd-pop { from { opacity: 0; transform: scale(0.85); } 60% { transform: scale(1.06); } to { opacity: 1; transform: scale(1); } }
/* Slice AL9 — dash=output travelling a route. The vocabulary's flow means the same thing but moves the element;
   a connector is a stroke, so what travels along it is the dash pattern rather than the line. */
@keyframes cd-dash { to { stroke-dashoffset: -16; } }
/* ==================================== end Slice A token layer ==================================== */

:root {
  /* Slice UI14 — the one thing a token cannot reach. A native select, its dropdown, a scrollbar and a focus ring
     are drawn by the browser, not by this sheet, and without this they follow the OPERATING SYSTEM: the light
     theme rendered a black dropdown on a dark desktop, and the dark theme has always rendered a white one on a
     light desktop. It moves no author colour; it tells the browser which of its own two palettes to use. */
  color-scheme: dark;
  --topbar-h: 48px;           /* the persistent nav strip height; overlays offset below it (Slice 13c) */
  --bg: #0e0f11;
  --surface: #16181b;
  --surface-2: #1c1f23;
  --fg: #e6e7e9;
  --muted: #8b8f96;
  --line: #26292e;
  --accent: #5b8cff;          /* selection + primary action ONLY */
  --success: #3fb950;         /* complete */
  --danger: #f0603f;          /* failed / abort */
  --guardrail: #d6a13a;       /* reserved — guardrail/blocked, used NOWHERE else */
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* ============================================================================================================
   SLICE UI0 — the five custom properties that were USED but never DEFINED. Guard slice: no design, no layout,
   no component. Four of the five already rendered correctly because every use carried an inline fallback; the
   other two did not, and that was a live defect:

     `border: 1px solid var(--cd-line)` is a SHORTHAND. An unresolvable var() inside one makes the whole
     declaration invalid at computed-value time, so every longhand resets — including border-style: none.
     `.prompt-card` (S3a), `.pcd-btn`/`.pcd-q` (S8/S16/S24) and `.flow-native-btn` therefore drew NO BORDER
     at all, and `.prompt-card.is-selected { border-color: var(--cd-ok) }` could never paint: the selected
     card's only signal was the ✓ check. `var(--cd-muted)` (not a shorthand) merely inherited the parent
     colour, so meta text read at full strength instead of muted.

   The two broken ones are ALIASES into the existing scale, chosen from what the surrounding rules already say:
   --cd-line-2 is documented "default borders" and `.prompt-card:hover` escalates to --cd-line-3, which only
   reads as an escalation if the rest state sits below it; --cd-muted-2 is the mid muted the analogous quiet
   secondary line (.idle-deck-quiet) already uses. They are ALIASES, not hex, because sliceS3a asserts the S3a
   block is --cd-* only — and they live HERE, outside the Slice-A layer, because slice39 #6 asserts that layer
   consumes no var(--cd-*) of its own.

   The other three are pinned to their CURRENT EFFECTIVE FALLBACK so not one computed value moves:
   --ok and --card keep their exact hex, and --cd-prod-btn-bg takes --cd-bg-void (what 2 of its 3 uses already
   fell back to); the third use (.lib-trash[data-armed]) names --cd-surface-2 directly just below, which is
   what IT already fell back to. A token that resolved two different ways was never a token.

   sliceUI0's CSS-VARS-RESOLVE check is the durable half of this: it fails on the NEXT undefined property.
   ============================================================================================================ */
:root {
  --cd-line: var(--cd-line-2);      /* default control/card border — the unqualified member of the line scale */
  --cd-muted: var(--cd-muted-2);    /* default muted text — the unqualified member of the muted scale */
  --cd-prod-btn-bg: var(--cd-bg-void); /* destructive-control fill; matches the fallback its two uses had */
  --ok: #4caf72;                    /* success-in-a-.reason-slot; exact former fallback — colour unchanged */
  --card: #14151a;                  /* sticky batch-row backdrop; exact former fallback — colour unchanged */

  /* ── Slice UI2 — THE TYPE SCALE. 26 values in three unit systems (px, a parallel rem scale, and a
     handful of em) collapsed to seven steps in one. Named by ROLE: a rule asks for the job the text is
     doing, not for a number, so the scale can be retuned in one place. px because the layout API next to
     it is px and the em values were relative to parents that are not the root — one unit, no arithmetic. */
  --cd-type-micro:   9px;   /* the smallest thing that is still a label */
  --cd-type-kicker: 10px;   /* uppercase section kickers, tag chips */
  --cd-type-meta:   11px;   /* secondary/among-the-furniture: hints, counts, states */
  --cd-type-body:   12px;   /* the default reading size of the instrument panel */
  --cd-type-lead:   13px;   /* the first line of a card; a named thing */
  --cd-type-title:  14px;   /* panel and card titles */
  --cd-type-display:16px;   /* page-level headings and the document default */

  /* ── Slice UI2 — THE SPACING SCALE. Seven steps covering the real distribution; EXACT matches only,
     nothing snapped, so adopting it moved no pixel. Values off the scale (1/3/5/7/9/11/18/30px) stay
     literal on purpose — inventing a step for a one-off makes the scale less useful, not more. */
  --cd-space-1:  2px;
  --cd-space-2:  4px;
  --cd-space-3:  6px;
  --cd-space-4:  8px;
  --cd-space-5: 10px;
  --cd-space-6: 12px;
  --cd-space-7: 16px;
}


/* ==================================== end Slice UI0 token definitions ==================================== */

* { box-sizing: border-box; }
/* The hidden attribute must win: .card/.view set `display:flex`, an author rule that would
   otherwise override the UA `[hidden]{display:none}` and leave cards/views permanently visible
   (the reauth card could never be dismissed). !important makes the attribute authoritative. */
[hidden] { display: none !important; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--bg); color: var(--fg);
  font-family: var(--cd-font-sans, var(--sans)); font-weight: 400; font-size: var(--cd-type-display); line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
.mono { font-family: var(--cd-font-mono, var(--mono)); font-weight: 400; }
button { font-family: var(--cd-font-sans, var(--sans)); font-weight: 500; }

/* Slice 13c — the topbar is the persistent nav. It sits ABOVE every overlay (z-index) so its home
   affordance and the run chip are reachable from any view; overlays start BELOW it (--topbar-h). */
#topbar {
  display: flex; align-items: center; gap: var(--cd-space-5);
  height: var(--topbar-h, 48px); padding: 0 14px; border-bottom: 1px solid var(--line); box-sizing: border-box;
  position: fixed; top: 0; left: 0; right: 0; background: var(--bg); z-index: var(--cd-z-nav);
}
/* Slice CHROME-A — the pre-tabbar body offset is DELETED, not left to lose by source order. It set
   padding-top to --topbar-h alone; the correct rule below adds --tabbar-h for the fixed tab strip, and won
   only because it appears later — one reorder from sliding every tab surface 44px under the tabbar. Two rules
   at equal specificity setting the same property is a coin balanced on its edge; removing the loser leaves a
   single composed offset that cannot be flipped. The offset stays the two tokens ADDED, never a literal 92. */
#brand { font-weight: 500; letter-spacing: 0.2px; background: transparent; border: 0; color: var(--fg); cursor: pointer; padding: var(--cd-space-2) var(--cd-space-1); font-size: var(--cd-type-display); }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: var(--cd-space-5); } /* pushed right; chip sits left of it */

/* ══ Slice UI6 — THE NARROW-WIDTH PASS ═══════════════════════════════════════════════════════════════════════
   MEASURED, NOT REASONED. scrollWidth against clientWidth across twelve surfaces at seven widths found exactly
   ONE that overflows: this one. The canvas, the panels, the catalog, the transcript, the compose deck and the
   rails all report zero at 320 and at 1200 alike, so the forty-odd nowrap declarations elsewhere are left alone
   — they were measured, and they are fine. This pass is one fix, not a sweep.

   THE TOPBAR OVERFLOWS AT EVERY WIDTH BELOW 1200, not only on phones: 705px over at 320, 635 at 390, 257 at 768
   and still 125 at 900 with a grant live. It carries a wordmark, four chips and a three-item cluster — 1010px of
   content in a 375px bar, of which the grant chip alone is 322 (a sentence wrapped around two nested buttons).

   WHY IT SCROLLS AND DOES NOT WRAP. Wrapping grows the header, and the header height is a layout API with 23+
   consumers: every overlay offsets below it. The token would have to grow with it, and being static it would
   reserve the taller height permanently — costing a phone a whole extra row even when no run is live and every
   chip is hidden. So the row is kept and the strip scrolls; the header height never moves.

   WHY THERE ARE NO STICKY ANCHORS. Pinning the wordmark left and the cluster right was tried and MEASURED: the
   two of them consume 332 of 375px, leaving a 43px window through which no chip is ever fully visible. Pinning
   the edges of a bar this full does not rescue it, it strands it.

   WHAT IS VISIBLE AT REST IS THEREFORE A CHOICE, and it is made below by ordering rather than by hiding: the run
   chip and the grant chip come first, because those are the two the operator must never miss — the way back to a
   live run, and the fact that writes are currently allowed. Everything else is one swipe away. Nothing is
   hidden: a grant the operator cannot see is the exact failure that chip exists to prevent. */
#topbar { overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
#topbar::-webkit-scrollbar { width: 0; height: 0; }
#topbar > * { flex: 0 0 auto; }

/* ── the phone band ──────────────────────────────────────────────────────────────────────────────────────────
   The width is measured, not conventional: 600 is where the compacted strip stops being able to show both
   indicators at rest. Below it the grant chip's sentence collapses — the chip keeps its colour, its fast toggle
   and its revoke control, so the indicator survives and only the paragraph goes — and the two indicators are
   ordered ahead of the wordmark so both are visible without scrolling. */
/* The ORDERING runs to the full narrow band, not just the phone: at 768 the strip scrolls but the grant chip
   sits past the fold at rest, which is the same invisible-grant problem in a milder form. The label collapse
   below is phone-only — a tablet has room for the sentence. */
@media (max-width: 899px) {
  #topbar > #run-chip { order: -2; }
  #topbar > #grant-chip { order: -1; }
  /* Slice AL10 — the rail toggle lives in this band and only in it: above it the rail and the canvas both have
     room and the control has nothing to do. Folded in here rather than declared as a sixth stacked block.
     Slice AL14 — COMPOUND ON PURPOSE. Its resting rule sits ~2500 lines below this block, and a media query buys
     no specificity: at equal weight the later declaration wins, so the moment that rule stopped being dropped it
     would have hidden the toggle in this band too. Naming the row it is built into makes this the heavier
     selector, so the band wins on weight rather than on where the two happen to sit in the file. */
  .alive-canvas-ctls .alive-rail-toggle { display: inline-flex; }
  .workspace-rail[data-collapsed="true"] { display: none; }
  /* Slice UI15b — THE DRAWER, which UI15 specified and did not build. Below the stacked breakpoint there is no
     rail column, so a catalog of 262 rows sat in the flow and pushed every surface down its own length. Out of
     flow it costs the page nothing, and it clears both persistent bars for the reason every floating surface
     here does: its own first row is its search box, and a row the strip paints over is a row nobody can use.
     It starts closed — the markup carries the collapsed attribute, which only this band reads — and the control
     the canvas already had opens it. No new behaviour and no new breakpoint: this is the band's own block. */
  #workspace-rail { position: absolute; top: calc(var(--topbar-h) + var(--tabbar-h)); left: 0; z-index: var(--cd-z-panel);
    width: min(320px, 100%); max-height: calc(100vh - var(--topbar-h) - var(--tabbar-h)); overflow-y: auto;
    box-shadow: 0 10px 30px -12px rgba(var(--cd-shadow-rgb), 0.5); }
  /* Slice UI15c — THE DRAWER IS REACHABLE FROM EVERY TAB, AND CLOSES ITSELF. UI15b answered the trap the
     hit-test found by only letting the drawer open where its control lived; that was right while the catalog
     was browsing and wrong once the rail became the surface a crew and a flow are selected FROM, because it
     would leave phone widths with no list at all. So the restriction is lifted and the two controls it stood in
     for are real: the drawer carries its own close, and the opener sits in global chrome. */
  /* COMPOUND, for the reason AL14 recorded: these two are switched off in a block ~2700 lines below this one,
     a media query buys no specificity, and at equal weight the later declaration wins — so written plainly this
     rule would lose and the drawer would have two controls that never render. Naming the surface each is built
     into makes the band the heavier selector. */
  .topbar-right > .catalog-open, .workspace-rail .catalog-close { display: inline-flex; }
}
@media (max-width: 599px) {
  #topbar > #grant-chip > #grant-chip-label { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip-path: inset(50%); white-space: nowrap; }
  #topbar > #grant-chip { gap: var(--cd-space-2); }
}

/* The run chip — quiet → visible → LOUD. needs-you carries the auto-deny countdown and pulses. */
/* ── Slice UI3 — THE CHIP, once ────────────────────────────────────────────────────────────────────────────────
   Five pills — the run chip, the sequence chip, the mode chip, the grant chip and the division filter — each
   declared the same box for itself: a mono face, a fully-rounded edge, a line that does not break. They are one
   thing wearing five names, so the box is written here once and the five names ALIAS it.
   They remain five separate selectors on purpose: #mode-chip's approval colour, .grant-chip's guardrail edge and
   #run-chip's stateful backgrounds are pinned inside their own rule bodies by slices that own those surfaces, and
   an alias that swallowed them would break those checks while claiming to be a refactor. What moved is what no
   check asserts and every rule repeated. */
/* Slice AL4 — the hand-off summary chip joins the UI3 chip box rather than declaring a second one. Prepended to
   the selector list on purpose: appending would have split the run of selectors another slice matches as one
   string, so the new surface reuses the primitive without moving anything that was already pinned to it. */
/* Slice AL9 — the needs-you count joins the same box, prepended for the same reason AL4's was: appending would
   split the run of selectors another slice matches as one string. It is a button rather than a span because it
   goes somewhere when tapped, and the box does not care which. */
.alive-directive-chip, .alive-needs-chip, .handoff-chip, #run-chip, #seq-chip, .mode-chip, .grant-chip, .alive-div-chip {
  display: inline-flex; align-items: center;
  font-family: var(--cd-font-mono, var(--mono));
  border-radius: 999px;
  white-space: nowrap;
}

/* ── Slice UI3 — THE TAG, once ─────────────────────────────────────────────────────────────────────────────────
   The other chip family is not a pill at all: it is a bare uppercase label — a division name, a look, a demo
   marker. Five rules repeated the same three declarations. Letter-spacing stays per-alias because the two
   families genuinely differ there (0.04em for the library's inline tags, 0.08em for the alive surface's
   division labels), and flattening that would be a restyle wearing a refactor's clothes. */
.lib-tag.lib-look, .lib-tag.lib-demo-ref, .lib-tag.lib-demo-tag, .alive-card-div, .alive-panel-div {
  font-size: var(--cd-type-kicker);
  text-transform: uppercase;
}
#run-chip { border: 0; padding: 4px 11px; font-size: var(--cd-type-body); cursor: pointer; }
#run-chip[data-state="working"] { background: var(--cd-chip-quiet-bg); color: var(--muted); }
#run-chip[data-state="awaiting"] { background: var(--cd-chip-attention-bg); color: var(--cd-chip-attention-text); }
#run-chip[data-state="needs-you"] { background: var(--cd-chip-loud-bg); color: var(--cd-chip-loud-text); font-weight: 700; animation: chip-pulse 1s ease-in-out infinite; }
@keyframes chip-pulse { 0%,100% { box-shadow: 0 0 0 0 rgba(var(--cd-chip-loud-ring-rgb), 0.6); } 50% { box-shadow: 0 0 0 6px rgba(var(--cd-chip-loud-ring-rgb), 0); } }
@media (prefers-reduced-motion: reduce) { #run-chip[data-state="needs-you"] { animation: none; } }
.state { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); }
.state[data-state="reachable"] { color: var(--success); }
.state[data-state="unreachable"] { color: var(--danger); }

#app { max-width: 720px; margin: 0 auto; padding: var(--cd-space-7); }
.view { display: flex; flex-direction: column; gap: var(--cd-space-7); }

.field { display: flex; flex-direction: column; gap: var(--cd-space-3); }
.label { font-size: var(--cd-type-body); color: var(--muted); }
.hint { font-size: var(--cd-type-body); color: var(--muted); margin: var(--cd-space-2) 0 0; }

select, textarea, input {
  background: var(--surface); color: var(--fg); border: 1px solid var(--line);
  border-radius: 8px; padding: var(--cd-space-5) var(--cd-space-6); font-size: var(--cd-type-title); width: 100%;
}
/* Checkboxes/radios must NEVER inherit the text-input width:100% + padding — a full-width checkbox eats its
   whole flex row and starves the label to 0 width (the per-letter/per-word toggle-label bug). Native size. */
input[type="checkbox"], input[type="radio"] { width: auto; min-width: auto; padding: 0; flex: 0 0 auto; }
textarea { resize: vertical; min-height: 88px; }
select:focus, textarea:focus, button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

details summary { cursor: pointer; display: flex; gap: var(--cd-space-4); align-items: baseline; list-style: none; }
details summary::-webkit-details-marker { display: none; }
#resolved { list-style: none; padding: var(--cd-space-4) 0 0; margin: 0; font-size: var(--cd-type-lead); color: var(--muted); }
#resolved li { padding: var(--cd-space-1) 0; }
#resolved li.suppressed { opacity: 0.55; }

button {
  border: 1px solid var(--line); background: var(--surface-2); color: var(--fg);
  border-radius: 8px; padding: var(--cd-space-6) var(--cd-space-7); font-size: var(--cd-type-display); cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease;
}
button:disabled { opacity: 0.45; cursor: not-allowed; }
.primary { background: var(--accent); border-color: var(--accent); color: var(--cd-on-accent); }
.danger { background: transparent; border-color: var(--danger); color: var(--danger); }
.danger-ghost { border: none; background: transparent; color: var(--danger); padding: var(--cd-space-2) var(--cd-space-4); }
.ghost { background: transparent; }
.reason { color: var(--danger); font-size: var(--cd-type-lead); margin: 0; }

/* summary (trust signal) */
#summary { display: flex; flex-direction: column; gap: var(--cd-space-3); }
/* Slice UI6 — this rule used to declare a whole grid box and have every one of those declarations overridden
   further down, where the same element was redesigned into a stacked presence. They were never two components
   sharing a name: same element, same span structure, one superseded rule. Only the corner radius ever survived
   the override, so only the corner radius remains. */
.agent-row { border-radius: 8px; }
.agent-row .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--muted); }
.agent-row[data-state="running"] .dot { background: var(--accent); }
.agent-row[data-state="awaiting"] .dot { background: var(--guardrail); } /* waiting on the operator */
.agent-row[data-state="complete"] .dot { background: var(--success); }
.agent-row[data-state="failed"] .dot { background: var(--danger); }
.agent-row .id { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-lead); }
.agent-row .meta { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); }
/* motion library (Slice 22/23): ONE component — panel (desktop) / drawer (phone). CONTENT-FIT is enforced,
   because the last layout bug was overflow: grid/flex children default to min-width:auto and REFUSE to shrink
   below their content width, overflowing the track. So the panel AND every flex/grid descendant get
   min-width:0; the panel clips horizontally (nothing escapes, no horizontal scrollbar); long names ellipsise.
   No element inside the panel carries a fixed width wider than the ~320px column. */
.motion-store { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: var(--cd-space-6);
  display: flex; flex-direction: column; gap: var(--cd-space-6); min-width: 0; box-sizing: border-box; }
.motion-store, .motion-store * { min-width: 0; }           /* THE FIX: nothing inside refuses to shrink to the column */
.motion-store-head { display: flex; align-items: center; justify-content: space-between; }
.motion-entries { display: flex; gap: var(--cd-space-4); }
.motion-entries button { flex: 1 1 0; }                    /* two equal buttons, side by side, shrink to the column */
.motion-drop { border: 1px dashed var(--line); border-radius: 8px; padding: var(--cd-space-6); font-size: var(--cd-type-body); color: var(--muted); text-align: center; overflow-wrap: anywhere; }
.motion-drop.over { border-color: var(--accent); color: var(--fg); }
.linklike { color: var(--accent); cursor: pointer; text-decoration: underline; }
.motion-bar { display: flex; align-items: center; gap: var(--cd-space-5); flex-wrap: wrap; }
.motion-summary-line { font-size: var(--cd-type-body); color: var(--muted); }
/* Slice 34 — git from the phone. Same card idiom as the motion store; a blanket min-width:0 so the mono output
   and long command line never force the column wide (the four-times-bitten overflow trap). */
.git-bar { display: flex; align-items: center; gap: var(--cd-space-5); flex-wrap: wrap; }
.git-bar-note { font-size: var(--cd-type-body); color: var(--muted); }
.git-panel { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: var(--cd-space-6);
  display: flex; flex-direction: column; gap: var(--cd-space-5); margin-top: var(--cd-space-6); }
.git-panel, .git-panel * { min-width: 0; }                 /* nothing inside refuses to shrink to the column */
.git-panel[hidden] { display: none; }
.git-panel-head { display: flex; align-items: center; justify-content: space-between; }
/* Slice 35 — the quick-action grid. Grouped (read / ship / tag); every button WRAPS within the column and never
   forces horizontal overflow (the min-width:0 blanket above holds). Ship/tag buttons carry the accent edge so a
   passkey op reads distinct from a safe read. This is the regression-prone panel — buttons must wrap clean. */
.git-actions { display: flex; flex-direction: column; gap: var(--cd-space-4); }
.git-group { display: flex; flex-direction: column; gap: var(--cd-space-2); }
.git-group-label { font-size: var(--cd-type-meta); text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); }
.git-btns { display: flex; gap: var(--cd-space-3); flex-wrap: wrap; }        /* wrap within the column — no overflow at any width */
.git-action { font-size: var(--cd-type-body); padding: 5px 10px; white-space: nowrap; }   /* a label never breaks mid-token */
.git-action.ship { border-color: var(--accent); color: var(--accent); }    /* a passkey op — visually distinct */
.git-field { display: flex; flex-direction: column; gap: var(--cd-space-4); border: 1px solid var(--line); border-radius: 8px;
  padding: var(--cd-space-5); background: var(--surface-2); }
.git-field[hidden] { display: none; }
.git-preview { margin: 0; font-size: var(--cd-type-body); color: var(--muted); overflow-wrap: anywhere; }
.git-field-actions { display: flex; gap: var(--cd-space-4); flex-wrap: wrap; }
/* Slice 37 — the vercel panel reuses the git card idiom (.git-panel/.git-actions/.git-btns/.git-action). The
   PRODUCTION tier is visually distinct (danger edge + a live-domain label) so the operator can never mistake a
   prod deploy for a preview, and the live-domain confirm is a prominent block, not a body line. min-width:0
   blanket (inherited from .git-panel *) keeps long command output contained. */
/* Slice C/42 — the PRODUCTION red gravity (the HEAVIEST). Reskins the Slice-37 two-step to --cd-prod per
   production-confirm-*.png: a glowing red confirm border, the live-domain warning, a SOLID-red "promote" with the
   ☉ seal (the passkey to come) beside a quiet "keep it as a preview". PRESENTATION ONLY — the real two-step
   (confirm→passkey), the token-can't-ship-prod invariant, every id/handler are untouched (the prod passkey itself
   is the OS-native prompt, correctly not app-reskinnable). Layout bits (padding/flex) are preserved. */
.vercel-prod-label { color: var(--cd-prod-label); text-transform: uppercase; letter-spacing: 0.06em; }
.vercel-prod { border-color: var(--cd-prod); color: var(--cd-prod); }   /* a production op — the live-domain stakes */
/* Slice S25 — the SELECTED project's live deploy links (Production / Preview): two quiet always-present rows. A
   resolved URL is a link; a null is a muted state word ('not linked' / 'no deploy yet' / 'resolving…'), never a guess. */
.vercel-links { display: flex; flex-direction: column; gap: var(--cd-space-2); margin: var(--cd-space-1) 0 var(--cd-space-2); }
.vercel-link-row { display: flex; align-items: baseline; gap: var(--cd-space-4); font-size: var(--cd-type-body); min-width: 0; }
.vercel-link-label { color: var(--cd-muted-3, var(--muted)); text-transform: uppercase; letter-spacing: 0.05em; flex: 0 0 auto; width: 74px; }
.vercel-link-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vercel-link-val a { color: var(--accent); text-decoration: none; }
.vercel-link-val a:hover { text-decoration: underline; }
.vercel-link-val.empty { color: var(--muted); }
.vercel-prod-confirm {
  border: 1px solid var(--cd-prod); border-radius: 8px; padding: var(--cd-space-6); display: flex;
  flex-direction: column; gap: var(--cd-space-4); background: color-mix(in oklch, var(--cd-prod) 8%, transparent);
  box-shadow: inset 0 0 0 1px var(--cd-prod-ring), 0 0 22px -6px var(--cd-prod-ring);
  animation: cd-prod-glow 2s ease-in-out infinite;                      /* the design's glowing red border */
}
.vercel-prod-confirm[hidden] { display: none; }
.vercel-prod-warning { margin: 0; font-size: var(--cd-type-lead); color: var(--cd-prod-label); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }
.vercel-prod-cmd { margin: 0; font-size: var(--cd-type-body); color: var(--cd-prod-cmd); overflow-wrap: anywhere; }
.vercel-prod-actions { display: flex; gap: var(--cd-space-4); flex-wrap: wrap; }
/* the SOLID-red promote — the heaviest, most deliberate control; ☉ seals the passkey to come (the OS prompt). */
#vercel-prod-go { background: var(--cd-prod); border-color: var(--cd-prod); color: var(--cd-text-hi); flex: 1; }
#vercel-prod-go:hover { background: var(--cd-prod-btn-hover); border-color: var(--cd-prod-btn-hover); }
#vercel-prod-go::before { content: "\2609\00a0"; }
/* the quiet out — declining prod, staying a preview. Neutral, clearly secondary to the red promote. */
#vercel-prod-cancel { color: var(--cd-muted-1); border: 1px solid var(--cd-line-3); background: transparent; }
#vercel-prod-cancel:hover { background: var(--cd-surface-1); color: var(--cd-text-2); }
/* the glowing red border pulse — the live-domain stakes, breathing. OFF under reduced-motion. */
@keyframes cd-prod-glow {
  0%, 100% { box-shadow: inset 0 0 0 1px var(--cd-prod-ring), 0 0 8px -6px var(--cd-prod-ring); }
  50% { box-shadow: inset 0 0 0 1.5px var(--cd-prod-ring), 0 0 26px -2px var(--cd-prod-ring); }
}
@media (prefers-reduced-motion: reduce) { .vercel-prod-confirm { animation: none; } }
/* ==================================== end Slice C/42 production reskin ==================================== */
#vercel-status-line { color: var(--muted); }
#vercel-status-line[data-kind="blocked"] { color: var(--guardrail); }  /* the WALL refused it — guardrail, not error */
#vercel-status-line[data-kind="ok"] { color: var(--success); }
#vercel-status-line[data-kind="fail"] { color: var(--danger); }
/* Slice 38 — Feature A: the per-ref "agent reads the bytes" opt-in (a secondary row under an attached ref).
   Feature B: the download panel reuses the git card idiom; a refused download shows guardrail (the wall refused). */
.lib-readable { display: flex; align-items: center; gap: var(--cd-space-3); font-size: var(--cd-type-meta); color: var(--muted); margin: 2px 0 0 26px; }
.lib-readable input { width: auto; }
/* SLICE M16 — "add as asset" on a ref row: its OWN sub-row (like .lib-readable) so the dense main row never
   crowds at phone width. A compact, low-emphasis action; the demo variant is gold (--cd-wall) to echo the
   demo/guardrail language — a promoted demo preview stays visibly "not yours". --cd-* only, no hardcoded color. */
.lib-actions { display: flex; flex-wrap: wrap; gap: var(--cd-space-3); margin: 3px 0 0 26px; }
.lib-add-asset { flex: 0 1 auto; max-width: 100%; font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-meta);
  color: var(--cd-link); background: var(--cd-surface-1); border: 1px solid var(--cd-line-3); border-radius: 6px;
  padding: 3px 8px; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; }
.lib-add-asset:hover { color: var(--cd-link-hover); border-color: var(--cd-line-strong); background: var(--cd-surface-2); }
.lib-add-asset.is-demo { color: var(--cd-wall); border-color: var(--cd-wall-btn-border); }
.lib-add-asset.is-demo:hover { background: var(--cd-wall-btn-hover); border-color: var(--cd-wall); }
@media (prefers-reduced-motion: reduce) { .lib-add-asset { transition: none; } }
/* SLICE M35 — inline two-step trash on the .lib-actions sub-row. Idle: a compact, low-emphasis icon pushed to the
   trailing edge (margin-left:auto), so on a ref row it sits AFTER "add as asset". ARMED: the destructive red
   gravity (--cd-prod) with the confirm wording — visually UNMISTAKABLE that a second tap deletes. --cd-* only. */
.lib-trash { flex: 0 0 auto; margin-left: auto; font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-meta);
  color: var(--cd-muted-2); background: var(--cd-surface-1); border: 1px solid var(--cd-line-3); border-radius: 6px;
  padding: 3px 8px; cursor: pointer; white-space: nowrap; line-height: 1.2;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease; }
.lib-trash:hover { color: var(--cd-text-body); border-color: var(--cd-line-strong); background: var(--cd-surface-2); }
.lib-trash[data-armed="true"] { color: var(--cd-prod); border-color: var(--cd-prod); background: var(--cd-surface-2); font-weight: 600; white-space: normal; }
@media (prefers-reduced-motion: reduce) { .lib-trash { transition: none; } }
/* end Slice M16 add-as-asset */
#download-status { color: var(--muted); }
#download-status[data-kind="blocked"] { color: var(--guardrail); }
#download-status[data-kind="ok"] { color: var(--success); }
#download-status[data-kind="fail"] { color: var(--danger); }
/* Slice 36 — new-project creation. A bounded, gated affordance under the working-directory select. Same card
   idiom; min-width:0 blanket so the resolved path preview and long names never force the column wide. A blocked
   request (the WALL refused) renders in guardrail, distinct from a real error. */
.newproj-bar { display: flex; }
.newproj { background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: var(--cd-space-6);
  display: flex; flex-direction: column; gap: var(--cd-space-5); }
.newproj, .newproj * { min-width: 0; }
.newproj[hidden] { display: none; }
.newproj-preview { margin: 0; font-size: var(--cd-type-body); color: var(--muted); overflow-wrap: anywhere; }
.newproj-preview[hidden] { display: none; }
.newproj-actions { display: flex; gap: var(--cd-space-4); flex-wrap: wrap; }
#newproj-status { color: var(--muted); }
#newproj-status[data-kind="blocked"] { color: var(--guardrail); }  /* the WALL refused it — guardrail, not error */
#newproj-status[data-kind="ok"] { color: var(--success); }
#newproj-status[data-kind="fail"] { color: var(--danger); }
.git-out { background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; padding: var(--cd-space-5);
  font-size: var(--cd-type-body); color: var(--fg); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 40vh;
  overflow: auto; margin: 0; }
.git-out[hidden] { display: none; }
#git-status-line { color: var(--muted); }
#git-status-line[data-kind="blocked"] { color: var(--guardrail); }  /* the WALL refused it — guardrail, not error */
#git-status-line[data-kind="ok"] { color: var(--success); }
#git-status-line[data-kind="fail"] { color: var(--danger); }
/* Slice 31 — the STEPPER: three collapsible steps, one open at a time. A step head is a full-width button (n +
   title + a right-aligned summary when collapsed); the body shows only for the open step (JS toggles [hidden]).
   Everything keeps min-width:0 (inherited from .motion-store *) so the narrow drawer never overflows. */
.stepper { display: flex; flex-direction: column; gap: var(--cd-space-4); min-width: 0; }
.step { border: 1px solid var(--line); border-radius: 8px; min-width: 0; overflow: hidden; }
.step-head { display: flex; align-items: center; gap: var(--cd-space-4); width: 100%; padding: var(--cd-space-4) var(--cd-space-5); background: var(--surface-2); border: none; color: var(--fg); cursor: pointer; text-align: left; min-width: 0; box-sizing: border-box; }
.step-head.open { background: transparent; border-bottom: 1px solid var(--line); }
.step-head[hidden] { display: none; }
.step-n { flex: 0 0 auto; width: 18px; height: 18px; border-radius: 50%; background: var(--line); color: var(--fg); font-size: var(--cd-type-meta); display: inline-flex; align-items: center; justify-content: center; }
.step-head.open .step-n { background: var(--accent); }
.step-title { flex: 0 0 auto; font-size: var(--cd-type-body); font-weight: 600; }
.step-summary { flex: 1 1 auto; min-width: 0; font-size: var(--cd-type-meta); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: right; }
.step-body { padding: var(--cd-space-5); display: flex; flex-direction: column; gap: var(--cd-space-5); min-width: 0; }
/* master tabs (step ①): equal-width, the active one highlighted; the panels are the existing lib lists. */
.lib-tabs { display: flex; gap: var(--cd-space-2); }
.lib-tab { flex: 1 1 0; min-width: 0; font-size: var(--cd-type-meta); padding: var(--cd-space-2) var(--cd-space-3); border-radius: 6px; border: 1px solid var(--line); background: var(--surface-2); color: var(--muted); cursor: pointer; white-space: nowrap; }
.lib-tab.on { border-color: var(--accent); color: var(--fg); }
.lib-panel { min-width: 0; }
/* the .motion-kind checkbox toggles (upload-as-ref, Slice 26 fetch-demos): checkbox pinned left; the label sits
   DIRECTLY beside it and wraps at WORD boundaries to 2–3 lines if long. The label must keep usable width
   (flex:1 grows it to fill the row) and wrap NORMALLY — NOT overflow-wrap:anywhere, which collapses the
   min-content to one character and, in a narrow flex child, wraps every letter onto its own line (the bug).
   (Slice 28 removed the .links-toggle global switch, so these rules are now .motion-kind only.) */
.motion-kind { display: flex; align-items: flex-start; gap: var(--cd-space-3); font-size: var(--cd-type-meta); color: var(--muted); }
.motion-kind input { flex: 0 0 auto; margin: 1px 0 0; }
.motion-kind > span { flex: 1 1 auto; white-space: normal; overflow-wrap: normal; word-break: normal; }
.paste-form { display: flex; flex-direction: column; gap: var(--cd-space-4); }
/* text inputs + textarea fill the column; a checkbox (Slice 26 opt-in) must NOT — width:100% here would beat
   the global input[type=checkbox]{width:auto} reset (equal specificity, later rule) and collapse its toggle
   label to one word per line (the Slice 22-23 bug, re-triggered inside the paste form). Exclude it. */
.paste-form input:not([type="checkbox"]):not([type="radio"]), .paste-form textarea { width: 100%; box-sizing: border-box; }
.paste-actions { display: flex; gap: var(--cd-space-4); }
.paste-actions #paste-save { flex: 1; }
.motion-lib { display: flex; flex-direction: column; gap: 14px; }
.lib-group h4 { font-size: var(--cd-type-meta); text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin: 0 0 var(--cd-space-3); }
.lib-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cd-space-1); font-size: var(--cd-type-body); }
.lib-list:empty::after { content: 'none yet'; color: var(--muted); font-size: var(--cd-type-meta); }
.lib-item { border-radius: 6px; }
.lib-item.attached { background: var(--surface-2); }
/* ONE flex line: checkbox(fixed) · icon(fixed) · name(flex:1, ELLIPSIS) · tag(fixed-ish, ellipsis backstop). */
.lib-main { display: flex; align-items: center; gap: var(--cd-space-4); padding: 5px 6px; }
.lib-main input[type="checkbox"], .lib-icon { flex: 0 0 auto; }
.lib-icon { font-size: var(--cd-type-lead); line-height: 1; width: 16px; text-align: center; }
/* Slice 33 — browser-native asset thumbnail (fixed box, cover, no shrink). In the ASSETS list it replaces the
   emoji; in the bind row it sits beside the <select> (slightly larger). Fixed-size so it never fights min-width:0. */
.lib-thumb { flex: 0 0 auto; width: 28px; height: 28px; border-radius: 4px; object-fit: cover; background: var(--cd-media-mat); border: 1px solid var(--line); cursor: pointer; display: block; }
.bind-thumb { width: 34px; height: 34px; }
/* SLICE M26 — a prompt's demo visuals at the SELECTION step. Desktop: an always-visible inline thumbnail strip
   in the row. Mobile (<900px, the existing phone breakpoint): the strip hides and the row peeks a panel on tap.
   Real images via the M12 authed path; --cd-* only; motion-free. Fill-slots is untouched. */
.lib-thumb-strip { display: none; }                     /* hidden by default; shown on desktop below */
.strip-thumb { flex: 0 0 auto; width: 26px; height: 26px; border-radius: 4px; object-fit: cover; border: 1px solid var(--cd-line-2); background: var(--cd-bg-void); cursor: pointer; }
.lib-peek { display: none; }                            /* hidden by default; shown on mobile when this row is peeked */
.peek-cell { display: flex; flex-direction: column; align-items: center; gap: 3px; }
.peek-thumb { width: 92px; height: 64px; border-radius: 6px; object-fit: cover; border: 1px solid var(--cd-line-2); background: var(--cd-bg-void); cursor: pointer; }
.peek-cap { font-size: var(--cd-type-kicker); color: var(--cd-muted-3); max-width: 92px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.peek-none { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-muted-3); font-style: italic; }  /* honest absence */
@media (min-width: 900px) { /* DESKTOP — the strip is always visible; the peek is never shown even if toggled */
  .lib-thumb-strip { display: inline-flex; align-items: center; gap: var(--cd-space-2); flex: 1 1 auto; flex-wrap: wrap; margin: 0 var(--cd-space-2); }
  .lib-item[data-kind="prompt"] .lib-name { flex: 0 1 auto; }
}
@media (max-width: 899px) { /* MOBILE — tap-to-peek */
  .lib-item[data-kind="prompt"] .lib-main.peekable { cursor: pointer; }
  .lib-item[data-kind="prompt"][data-peek="true"] .lib-peek { display: flex; flex-wrap: wrap; gap: var(--cd-space-6); padding: 6px 6px 8px 28px; }
}
/* end Slice M26 prompt visuals */
.lib-name { flex: 1 1 auto; min-width: 0; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-tag { flex: 0 1 auto; font-size: var(--cd-type-meta); max-width: 55%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-tag.lib-meta { color: var(--muted); }
.lib-tag.lib-bound { color: var(--success); }
.lib-tag.lib-unbound-tag { color: var(--guardrail); }
.lib-tag.lib-look { color: var(--accent); letter-spacing: 0.04em; }
/* Slice 26 — a fetched demo preview: amber "caution, not yours" (never bindable, never shipped). */
.lib-tag.lib-demo-ref { color: var(--guardrail); letter-spacing: 0.04em; }
.lib-bind { display: flex; gap: var(--cd-space-3); padding: 0 6px 5px 30px; }
.lib-bind select, .lib-bind .slot-input { flex: 1 1 auto; }
/* Slice 28 — the per-slot "bind my own | use demo" segmented control (replaces Slice 25's global switch). Two
   small buttons under each slot row; the chosen one is highlighted, and "use demo" is disabled (dimmed) when the
   slot has no recorded demo URL. min-width:0 keeps them from blowing out the narrow panel. */
.slot-choice { display: flex; gap: var(--cd-space-2); padding: 0 6px 4px 30px; }
.slot-choice-btn { flex: 0 1 auto; min-width: 0; font-size: var(--cd-type-kicker); padding: 2px 7px; border-radius: 6px; border: 1px solid var(--line); background: var(--surface-2); color: var(--muted); cursor: pointer; white-space: nowrap; }
.slot-choice-btn.on { border-color: var(--accent); color: var(--fg); }
.slot-choice-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.slot-demo-url { padding: 0 6px 5px 30px; font-size: var(--cd-type-kicker); color: var(--guardrail); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Slice 30 — slots GROUPED BY PROMPT: a header (name + count + per-prompt bulk controls) above each prompt's rows. */
.slot-group { margin: 0 0 var(--cd-space-5); }
.slot-group:last-child { margin-bottom: 0; }
.slot-group-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--cd-space-2) var(--cd-space-4); padding: 2px 6px 5px; border-bottom: 1px solid var(--line); margin-bottom: var(--cd-space-2); }
.slot-group-name { flex: 1 1 auto; min-width: 0; font-size: var(--cd-type-meta); font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slot-group-count { flex: 0 0 auto; font-size: var(--cd-type-kicker); color: var(--muted); }
.slot-group-bulk { flex: 1 0 100%; display: flex; gap: var(--cd-space-2); }
.slot-bulk-btn { flex: 0 1 auto; min-width: 0; font-size: var(--cd-type-kicker); padding: var(--cd-space-1) var(--cd-space-4); border-radius: 6px; border: 1px solid var(--line); background: var(--surface-2); color: var(--muted); cursor: pointer; white-space: nowrap; }
.slot-bulk-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--fg); }
.slot-bulk-btn:disabled { opacity: 0.4; cursor: not-allowed; }
/* Slice 29 — the per-slot DEMO PREVIEW: a small local thumbnail (fetched Slice 26 ref) + a label. Display only. */
.slot-preview { display: flex; align-items: center; gap: var(--cd-space-4); padding: 0 6px 6px 30px; min-width: 0; }
.slot-thumb { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 6px; object-fit: cover; border: 1px solid var(--line); background: var(--cd-media-mat); cursor: pointer; }
.slot-thumb-empty { display: flex; align-items: center; justify-content: center; text-align: center; font-size: var(--cd-type-micro); line-height: 1.1; color: var(--muted); cursor: default; background: var(--surface-2); }
.slot-fetch { flex: 0 0 auto; font-size: var(--cd-type-kicker); padding: 3px 8px; border-radius: 6px; border: 1px solid var(--accent); background: transparent; color: var(--accent); cursor: pointer; white-space: nowrap; }
.slot-preview-label { flex: 1 1 auto; min-width: 0; font-size: var(--cd-type-kicker); color: var(--guardrail); white-space: normal; overflow-wrap: normal; }
.lib-tag.lib-demo-tag { color: var(--guardrail); letter-spacing: 0.04em; }

/* the left (task) column: its inputs must not blow out the track either — a long project path in the <select>
   or a wide textarea is clamped to the column. */
.submit-main select, .submit-main textarea, .submit-main input { max-width: 100%; box-sizing: border-box; }

/* desktop (≥900px): a centered two-column WORK AREA. BOTH columns get min-width:0 (the left via minmax(0,1fr)
   + .submit-main min-width:0; the right via the fixed 320px track + #motion-store min-width:0). The shell is
   widened to 1040px; the stream view keeps its 720px reading width. */
@media (min-width: 900px) {
  /* Slice 44 — the persistent WORKSPACE grid: rail | center. The rail persists across idle AND run; the center
     column holds whichever view is active (idle command deck ↔ crew deck) — showView's submit↔stream toggle is now
     the CENTER-SWAP inside this frame. #view-submit keeps its OWN inner two-column grid (Slice 22/31) inside the
     center cell, so that pinned layout is preserved. */
  #app { max-width: 1320px; display: grid; grid-template-columns: 360px minmax(0, 1fr); grid-template-areas: "rail center"; gap: 22px; align-items: start; }
  /* Slice UI17 — BOUNDED, so the pane inside it has something to fill. The rail is a sticky column here and had
     no height cap, so a pane with overflow-y grew to its content and put its own foot below the fold — its last
     control unreachable by pointer at both desktop widths. Capping the RAIL rather than the pane is what makes
     this correct regardless of what the head above the pane contains: any subtraction naming the head's height
     would be a number that stops being right the moment the head changes, which is the shape of the last two
     defects. Below the stacked breakpoint the drawer's own max-height already does this, which is why the fault
     never showed there. */
  #workspace-rail { grid-area: rail; position: sticky; top: calc(var(--topbar-h) + var(--tabbar-h));
    align-self: start; display: flex; flex-direction: column; min-height: 0;
    max-height: calc(100vh - var(--topbar-h) - var(--tabbar-h)); }
  #view-submit, #view-stream { grid-area: center; min-width: 0; }
  #view-stream { max-width: none; margin: 0; }
  /* Slice UI18 — ONE column. Slice 31 split this view in two because the right track held the import panel; the
     panel is in the rail now, so the second track had nothing in it and 373 of 771 pixels were empty at 1200 —
     measured, not guessed. The two rules below it went the same way: a sticky cap for a panel that is no longer
     here, and a hide for the entry point that was only ever justified by "the panel is always visible at this
     width". It is not, so hiding the way in left the import path with no labelled entrance on the desk at all,
     which is the reachability failure this slice exists to avoid. Both deleted rather than overridden. */
  #view-submit { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }
  .submit-main { min-width: 0; display: flex; flex-direction: column; gap: 14px; }
}
/* phone (<900px): the library is a slide-over drawer BELOW the topbar (run chip stays visible), with a close
   (Slice 13c — no trap). It must not eat the reply box or the proposal card, so it lives in the submit view. */
@media (max-width: 899px) {
  .submit-main { display: flex; flex-direction: column; gap: 14px; }
  #motion-store { position: fixed; inset: var(--topbar-h) 0 0 auto; width: min(88vw, 360px); max-width: 360px;
    transform: translateX(100%); transition: transform 0.2s ease; z-index: var(--cd-z-modal); overflow-x: hidden; overflow-y: auto; border-radius: 0;
    /* Slice UI11 — this drawer is the surface the offset slice missed. It is only a floating sheet BELOW this
       breakpoint (above it the same element is an in-flow sticky panel), and it is only measurable once its own
       tab is selected and it is opened — so the earlier sweep found it collapsed and excluded it as not-a-surface.
       Opened, its close control sat under the strip and hit-testing returned the strip rather than the control.
       The top component is restated here rather than folded into the shorthand above, which another check reads
       by exact text; a later declaration in the same rule wins without disturbing it. */
    top: calc(var(--topbar-h) + var(--tabbar-h)); }
  #motion-store.open { transform: translateX(0); box-shadow: -8px 0 24px rgba(var(--cd-shadow-rgb), 0.4); }
}

/* write-grant chip (Slice 19): live for the whole grant, with a countdown + one-tap revoke. Uses --guardrail
   (the reserved attention colour) because a standing write authorization is exactly what must stay visible. */
.grant-chip { gap: var(--cd-space-4); font-size: var(--cd-type-body);
  color: var(--guardrail); border: 1px solid var(--guardrail); border-radius: 999px; padding: 3px 6px 3px 10px; }
.grant-chip button { font-size: var(--cd-type-meta); padding: var(--cd-space-1) var(--cd-space-4); border-radius: 999px; background: transparent;
  border: 1px solid var(--guardrail); color: var(--guardrail); cursor: pointer; }
.grant-btn { width: 100%; margin-top: var(--cd-space-4); }

/* pipeline instrument (Slice 17): honest stage N of M; running emphasized, complete receded, queued quiet. */
.pipeline-head { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); letter-spacing: 0.02em; margin: 0 var(--cd-space-1) var(--cd-space-1); }
.agent-row[data-state="running"] { background: var(--surface-2); box-shadow: inset 2px 0 0 var(--accent); }
.agent-row[data-state="running"] .id { color: var(--fg); font-weight: 600; }
.agent-row[data-state="running"] .status { color: var(--fg); }
.agent-row[data-state="complete"] { opacity: 0.55; }         /* done work recedes */
.agent-row[data-state="complete"] .status { color: var(--success); }
.agent-row[data-state="pending"] { opacity: 0.7; }           /* queued is quiet */
.agent-row[data-state="awaiting"] .status { color: var(--guardrail); }

/* stream */
#stream-wrap { position: relative; }
#stream {
  background: var(--cd-bg-transcript); border: 1px solid var(--line); border-radius: 8px;
  padding: var(--cd-space-6); margin: 0; font-size: var(--cd-type-body); line-height: 1.55;
  height: 46vh; overflow: auto; word-break: break-word;
  display: flex; flex-direction: column; gap: var(--cd-space-5);
}
/* transcript turns — who said what must always be unmistakable */
.turn { margin: 0; }
.turn.agent { font-family: var(--cd-font-mono, var(--mono)); white-space: pre-wrap; color: var(--fg); }
/* Slice M48 — copy/download controls on a SUBSTANTIAL agent turn, on their OWN trailing sub-row (M35 precedent) so the
   text is never crowded at 390px. Low-emphasis chips; --cd-* tokens only, no hardcoded colors. "copied" is the tap
   feedback (approval-blue); "copy failed" is honest (--cd-prod). Reduced-motion honored (no transition). */
.agent-controls { display: flex; flex-wrap: wrap; gap: var(--cd-space-3); margin: var(--cd-space-1) 0 var(--cd-space-3); }
.agent-ctl { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-kicker); color: var(--cd-muted-2); background: var(--cd-bg-void);
  border: 1px solid var(--cd-line-2); border-radius: 6px; padding: 3px 10px; cursor: pointer;
  transition: color .15s ease, border-color .15s ease; }
.agent-ctl:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.agent-ctl[data-state="copied"] { color: var(--cd-approval-label); border-color: var(--cd-approval); }
.agent-ctl[data-state="failed"] { color: var(--cd-prod); border-color: var(--cd-prod); }
@media (prefers-reduced-motion: reduce) { .agent-ctl { transition: none; } }
.turn.operator {
  font-family: var(--cd-font-sans, var(--sans)); white-space: pre-wrap; align-self: flex-end; max-width: 85%;
  background: var(--surface-2); border: 1px solid var(--line); border-left: 2px solid var(--accent);
  border-radius: 8px; padding: var(--cd-space-4) var(--cd-space-5); color: var(--fg);
}
.turn.operator .who { display: block; font-size: var(--cd-type-meta); color: var(--muted); margin-bottom: var(--cd-space-1); }
.turn.note { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); }
/* Slice M55 — an error line, collapsed with a ×N count like M42's wall-blocks. Attention tint (it is a failure the
   operator should register); the count reads in the same tint so a storm shows as "[error] … ×47" at a glance. */
.turn.note.err { color: var(--cd-prod); overflow-wrap: anywhere; }
.turn.note.err .err-count { font-weight: 600; color: var(--cd-prod); }
/* SLICE M18 — run legibility. Faint AUTO-APPROVED-ACTIVITY lines (real M6 rungrant events) + an honest HEARTBEAT
   (real running state + elapsed silence, never implied progress) + an in-pane APPROVAL-WAIT line. Matches the
   transcript's token vocabulary (var(--muted)/--mono, like .turn.note); the approval line uses the guardrail gold
   (operator-action, same language as the needs-you chip). No hardcoded colors. Motion-free by construction — there
   is no spinner/animation here to imply unobserved work (the pre-existing .dots already honor reduced-motion). */
.turn.activity { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); opacity: 0.8; overflow-wrap: anywhere; }
.turn.activity .act-text::before { content: '↳ '; opacity: 0.6; }
.turn.activity .act-count { color: var(--muted); opacity: 0.7; }
.turn.heartbeat { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); font-style: italic; opacity: 0.85; }
.turn.awaiting-approval { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--guardrail); }
/* end Slice M18 run legibility */
/* Slice M42 — a WALL REFUSAL surfaced INLINE in the transcript. Destructive/attention red (--cd-prod, the same token
   M35's armed delete + M36's overwrite warning use) with its own block so it is catchable at a glance while scrolling,
   never another undifferentiated text line. The reason is shown VERBATIM and wraps (overflow-wrap) so it stays legible
   and uncrowded at 390px. No hardcoded colors. Motion-free by construction (no spinner/animation — nothing implies
   unobserved work), so it needs no reduced-motion override. It authorizes nothing (no button — text only). */
.turn.blocked { display: flex; flex-direction: column; gap: 3px; margin: 5px 0; padding: var(--cd-space-4) var(--cd-space-5);
  border: 1px solid var(--cd-prod); border-left-width: 3px; border-radius: 8px; background: var(--cd-prod-btn-bg, var(--cd-bg-void)); }
.turn.blocked .blocked-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--cd-space-2) var(--cd-space-4); }
.turn.blocked .blocked-tag { font-size: var(--cd-type-meta); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--cd-prod); }
.turn.blocked .blocked-who { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; }
.turn.blocked .blocked-count { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); font-weight: 600; color: var(--cd-prod); }
.turn.blocked .blocked-reason { margin: 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--cd-prod); overflow-wrap: anywhere; white-space: pre-wrap; }
.turn.blocked .blocked-what { margin: 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; white-space: pre-wrap; }
/* Slice M43 — the death card's VERBATIM reason line (why the run died, e.g. a stage timeout). --cd-prod attention,
   visually consistent with M42's wall-block reason above; monospace, wraps so a long reason stays legible + uncrowded
   at 390px. Hidden when a run carries no reason (older runs) — no empty label. No hardcoded colors. */
#died-card #died-reason { margin: 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--cd-prod); overflow-wrap: anywhere; white-space: pre-wrap; }
#died-card #died-reason[hidden] { display: none; }
/* Slice M50 — the run-branch line on a terminal/completed card: which branch the work is on (or why git was skipped),
   stated in the daemon's own note. Muted by default; an ACTIVE branch reads in the link tint (something to go review),
   a SKIP stays muted (informational). --cd-* tokens only; textContent only. */
.card-branch { margin: var(--cd-space-4) 0 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); line-height: 1.5; color: var(--cd-muted-1); overflow-wrap: anywhere; }
.card-branch[data-git="active"] { color: var(--cd-link); }
.card-branch[hidden] { display: none; }
/* Slice M54 — the trust-mode line on a terminal card. auto-approve reads in attention tint (a notable posture the
   operator should register); manual stays muted (the default, reassuring). --cd-* tokens only. */
.card-trust { margin: var(--cd-space-3) 0 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); line-height: 1.5; color: var(--cd-muted-1); overflow-wrap: anywhere; }
.card-trust[data-trust="auto"] { color: var(--cd-prod-label); }
.card-trust[hidden] { display: none; }
/* Slice M44 — the touched-files list on a terminal (died/abandoned) card: project-relative paths, muted (they are
   context for "review at desk", not the attention line), wrapping so they stay legible + uncrowded at 390px, and
   scrollable if a run touched many. Capped with a "+N more" line in code. No hardcoded colors. Hidden when empty. */
.died-files { list-style: none; margin: var(--cd-space-1) 0 0; padding: var(--cd-space-3) var(--cd-space-4); display: flex; flex-direction: column; gap: var(--cd-space-1);
  max-height: 132px; overflow-y: auto; border-left: 2px solid var(--cd-line-2, var(--line)); background: var(--cd-bg-void, transparent); border-radius: 6px; }
.died-files[hidden] { display: none; }
.died-files .died-file { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; }
.died-files .died-file-more { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--cd-muted-3, var(--cd-muted-2)); font-style: italic; }
/* Slice 24 — an agent self-check screenshot, inline in the transcript (the operator sees what it built). */
.turn.shot { margin: var(--cd-space-2) 0; display: flex; flex-direction: column; gap: var(--cd-space-2); }
.turn.shot figcaption { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--muted); overflow-wrap: anywhere; }
.shot-img { max-width: 100%; border: 1px solid var(--line); border-radius: 8px; background: var(--cd-media-mat); }
/* stage handoff marker in the transcript (Slice 17): "─ prev complete · next now running ─" */
.turn.divider { display: flex; align-items: center; gap: var(--cd-space-5); margin: var(--cd-space-1) 0; }
.turn.divider .rule { flex: 1; height: 1px; background: var(--line); }
.turn.divider .label { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--muted); white-space: nowrap; letter-spacing: 0.02em; }
#scroll-bottom { position: absolute; right: 10px; bottom: 10px; font-size: var(--cd-type-body); padding: var(--cd-space-3) var(--cd-space-5); }

/* ============================================================================================================
   SLICE D/43 — the run/stream DECK: the living-crew relay. PRESENTATION ONLY, driven entirely by the REAL WS
   state renderSummary already sets (.agent-row[data-state] from stage.start/end/proposal/…, [data-div] from the
   real roster). Presence is AMBIENT and keyed to real state — pulse↔active, turn↔needs-you, relay↔handoff — never
   fabricated. Reuses the Slice-A cd-* keyframes + --cd-* tokens. Every id/handler + the honest status text are
   untouched. reduced-motion → state via colour/ring/position, ZERO animation (the run stays fully legible).
   ============================================================================================================ */

/* the crew STRIP — horizontal presences (was a vertical list); wraps for a large crew. .pipeline-head stays
   #summary's first child (slice17), reflowed to a caption above. */
#summary { flex-direction: row; flex-wrap: wrap; align-items: flex-start; justify-content: center; gap: 18px 10px; padding: var(--cd-space-2) 0 var(--cd-space-3); }
.pipeline-head { flex-basis: 100%; text-align: center; font-family: var(--cd-font-mono, var(--mono)); text-transform: uppercase; letter-spacing: 0.1em; font-size: var(--cd-type-kicker); color: var(--cd-muted-4); margin: 0; }

/* each .agent-row → a PRESENCE (glyph on top, id + status below). CSS reflow only — the row's span structure and
   its .status / dataset.state (slice17) are untouched. */
.agent-row { display: flex; flex-direction: column; align-items: center; gap: var(--cd-space-3); position: relative;
  grid-template-columns: none; background: transparent; border: none; box-shadow: none; padding: var(--cd-space-1); min-width: 60px; max-width: 96px; }
.agent-row .files { display: none; }                                   /* the file count lives in the transcript */
.agent-row .id { order: 2; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-micro); text-align: center; color: var(--cd-muted-2); max-width: 92px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agent-row .status { order: 3; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-micro); text-transform: uppercase; letter-spacing: 0.05em; color: var(--cd-muted-4); text-align: center; }

/* the GLYPH — the .dot becomes a division-coloured diamond (clip-path, so transforms animate freely; drop-shadow
   glows follow the clipped shape). currentColor carries the division/state hue. */
.agent-row .dot { order: 1; width: 32px; height: 32px; border-radius: 0; background: currentColor;
  clip-path: polygon(50% 3%, 97% 50%, 50% 97%, 3% 50%); color: var(--cd-muted-3); transition: color .3s ease, filter .3s ease; }

/* the RELAY connector — to the next presence, coloured by progress. CSS ::before (NOT a #summary child — slice17).
   (The handoff SLIDE lives on the transcript divider below, created once per real handoff.) */
.agent-row:not(:last-child)::before { content: ""; position: absolute; top: 15px; right: -10px; width: 12px; height: 2px; border-radius: 2px; background: var(--cd-line-1); }
.agent-row[data-state="complete"]:not(:last-child)::before, .agent-row[data-state="running"]:not(:last-child)::before { background: var(--cd-line-3); }

/* division colours — the real roster's 6 named divisions → the design hues; the other 11 fall back to neutral. */
.agent-row[data-div="engineering"] .dot { color: var(--cd-div-engineering); }
.agent-row[data-div="design"] .dot { color: var(--cd-div-design); }
.agent-row[data-div="security"] .dot { color: var(--cd-div-security); }
.agent-row[data-div="testing"] .dot { color: var(--cd-div-testing); }
.agent-row[data-div="specialized"] .dot { color: var(--cd-div-specialized); }
.agent-row[data-div="product"] .dot { color: var(--cd-div-product); }
/* the diamond ALWAYS carries its division hue (currentColor). The old slice-17 rules recoloured the tiny status
   dot BY STATE (running=accent, complete=success, …) at a higher specificity than `.agent-row .dot`; neutralise
   them so the presence stays division-identified and state is carried by MOTION + opacity + glow instead. */
.agent-row[data-state="running"] .dot, .agent-row[data-state="awaiting"] .dot,
.agent-row[data-state="complete"] .dot, .agent-row[data-state="failed"] .dot { background: currentColor; }

/* STATE presence (keyed to REAL WS state). running = ACTIVE → pulse + glow, name lit. awaiting = NEEDS-YOU → turn
   toward you + a blue attention ring/glow + AWAITING-YOU label (unmissable). complete = settled. pending = dim. */
.agent-row[data-state="running"] { background: transparent; box-shadow: none; } /* slice17's running rule (surface-2 fill + inset accent bar) is for the old list row; the presence marks active by pulse+glow+lit name instead. The original rule text is untouched (slice17 still greps it). */
.agent-row[data-state="running"] .dot { animation: cd-pulse 2s ease-in-out infinite; filter: drop-shadow(0 0 6px currentColor); }
.agent-row[data-state="running"] .id { color: var(--cd-text); font-weight: 600; }
.agent-row[data-state="running"] .status { color: var(--cd-muted-1); }
.agent-row[data-state="awaiting"] .dot { animation: cd-turn 2.2s ease-in-out infinite; filter: drop-shadow(0 0 9px var(--cd-approval)); }
.agent-row[data-state="awaiting"]::after { content: ""; position: absolute; top: -4px; left: 50%; transform: translateX(-50%); width: 46px; height: 46px; border-radius: 50%; border: 1.5px solid var(--cd-approval); opacity: .55; animation: cd-ring 2s ease-out infinite; }
.agent-row[data-state="awaiting"] .id { color: var(--cd-approval-chip-text); font-weight: 600; }
.agent-row[data-state="awaiting"] .status { color: var(--cd-approval-label); font-weight: 600; }
.agent-row[data-state="complete"] { opacity: 0.58; }                  /* slice17: complete carries `opacity` (settled) */
.agent-row[data-state="failed"] .dot { color: var(--cd-prod); }       /* a failed stage — red */
.agent-row[data-state="pending"] { opacity: 0.42; }                   /* queued, dim */

/* the honest STATUS line — the real "…is working…" text is kept; only the colour is in-language. */
#run-activity { color: var(--cd-muted-1); }

/* the REVEAL — an agent presents a screenshot it took. Rises in (created once per real screenshot). */
.turn.shot { animation: cd-rise .5s ease; border: 1px solid var(--cd-approval-chip-border); border-radius: 12px; padding: var(--cd-space-4); }
.turn.shot figcaption { color: var(--cd-approval-label); }

/* the HANDOFF relay — the transcript divider slides in on a REAL handoff (appendTransition creates it once).
   slice17 keeps display:flex + .rule background + .label. */
.turn.divider { animation: cd-slidein .34s ease; }
.turn.divider .rule { background: var(--cd-line-2); }
.turn.divider .label { color: var(--cd-muted-1); font-family: var(--cd-font-mono, var(--mono)); }

/* reduced-motion — ALL presence/relay motion off; the run stays FULLY legible via colour + a STATIC ring +
   position + the honest labels. Needs-you is still unmissable (static blue ring + AWAITING-YOU + the red
   run-chip). Accessibility hard requirement. */
@media (prefers-reduced-motion: reduce) {
  .agent-row .dot, .agent-row[data-state="awaiting"]::after, .turn.shot, .turn.divider { animation: none !important; }
}
/* ==================================== end Slice D/43 run-deck reskin ==================================== */

/* Slice D/43 — DESKTOP two-column deck (≥900px): crew + status + reply on the left, the stream feed on the right
   (the design's two-column workspace). Overrides the Slice-31 centred single column; phone stacks (default). */
@media (min-width: 900px) {
  #view-stream { max-width: 1040px; display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    grid-template-areas: "crew stream" "status stream" "reply stream" "actions stream"; gap: 12px 20px; align-items: start; }
  #view-stream #summary { grid-area: crew; }
  #view-stream #run-activity { grid-area: status; }
  #view-stream #stream-wrap { grid-area: stream; }
  #view-stream #stream { height: 64vh; }
  #view-stream #reply-panel, #view-stream #deny-retry { grid-area: reply; }
  #view-stream .stream-actions { grid-area: actions; }
}

/* reply panel — present only while the agent awaits the operator */
#reply-panel { display: flex; flex-direction: column; gap: var(--cd-space-5); border-top: 1px solid var(--line); padding-top: var(--cd-space-6); }
.choices { display: flex; flex-direction: column; gap: var(--cd-space-4); }
.choices:empty { display: none; }
.choices button { text-align: left; }
.reply-actions { display: flex; gap: var(--cd-space-5); }
.reply-actions #reply-send { flex: 1; }
/* Slice 18 — a structured question (AskUserQuestion) shown in the reply panel: the agent's question text,
   above its option buttons. Accent-barred like an operator prompt; NO passkey (a question is not a mutation). */
.reply-question { border-left: 2px solid var(--accent); background: var(--surface); border-radius: 6px; padding: var(--cd-space-4) var(--cd-space-5); }
.reply-question .q-text { font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-lead); color: var(--fg); margin: 0 0 var(--cd-space-3); }
.reply-question .q-text:last-child { margin: 0; }
#prop-deny-reason { margin-top: var(--cd-space-1); }
.retry { display: flex; align-items: center; gap: var(--cd-space-4); color: var(--guardrail);
  font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-lead); }
#abort { align-self: stretch; }

/* cards / overlays */
.card {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: var(--cd-z-panel);
  background: var(--surface); border: 1px solid var(--line); border-radius: 12px;
  padding: var(--cd-space-7); display: flex; flex-direction: column; gap: var(--cd-space-5);
  max-width: 700px; margin: 0 auto;
}
.card.blocked { border-color: var(--guardrail); }
.card.died { border-color: var(--danger); }
.card-kind { font-size: var(--cd-type-body); color: var(--muted); text-transform: none; }
.card-kind.guardrail { color: var(--guardrail); }
.card-kind.danger-text { color: var(--danger); }
.card-meta { font-size: var(--cd-type-body); color: var(--muted); }
/* ── Slice AI10 — THE COMMAND WRAPS, AND IS STILL VERBATIM ──────────────────────────────────────────────────
   WHAT THE OLD RULE PROTECTED, and it is protected still. slice6 #17 ("VERBATIM — proposed command not
   truncated") is three conjuncts: the whole string reaches the DOM, nothing slices it in JS, and the sheet does
   not let the browser eat its whitespace. The contrast `white-space: pre` was chosen against is the CSS DEFAULT,
   `normal`, which collapses runs of spaces and drops newlines outright — THAT is what would have made the
   command on screen differ from the command about to run.
   `pre-wrap` is identical to `pre` in every one of those respects: same whitespace preservation, same newline
   preservation. The single difference is that a long line BREAKS instead of running off the edge. So what the
   rule protects is unchanged and only the line breaks are presentational — which is why this is a stylesheet
   change and the client is untouched.
   WHY IT HAD TO CHANGE: this was the one string in the application the operator must read completely before
   authorising it, and at 390 it sat behind a horizontal scrollbar. Wrapping does not truncate; a scrollbar on
   the tail of a command is how the tail goes unread.
   NOT A THIRD TREATMENT — the opposite. `pre-wrap` + `overflow-wrap: anywhere` is this sheet's existing idiom
   for verbatim text (the transcript turns, the wall-refusal reason, the death reason, the vendor diff, the
   band's own command box). Before this, these two elements were the ONLY `white-space: pre` in the file: an
   exception of one, now removed. `overflow-wrap: anywhere` is what breaks a single unbroken token — a long
   path, a base64 blob, a URL — which plain wrapping cannot, and which is exactly the shape that forced the
   horizontal scrollbar in the first place.
   The vertical cap and its scroll stay: a command longer than the sheet still scrolls DOWN, and still whole. */
#prop-command, #blk-command {
  background: var(--cd-bg-transcript); border: 1px solid var(--line); border-radius: 8px;
  padding: var(--cd-space-5) var(--cd-space-6); margin: 0; font-size: var(--cd-type-lead); max-height: 40vh;
  overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; /* verbatim, never truncated — wraps, then scrolls down */
}
.card-actions { display: flex; gap: var(--cd-space-5); }
.card-actions button { flex: 1; }

/* ============================================================================================================
   SLICE B/40 — decision-sheet ceremony RESKIN (PRESENTATION ONLY). Consumes the Slice-A --cd-* tokens on the
   EXISTING markup — no id moved, no handler touched, the real passkey/approve/deny/grant wiring and the ceremony
   order are unchanged. Scoped to #proposal-card (BLUE approval gravity) and #blocked-card (GOLD wall-refusal
   gravity) so the other .card users (died / enroll / reauth / abandoned) are UNTOUCHED. The refusal card gains no
   authorize control — it stays dismiss-only by structure.
   ============================================================================================================ */

/* --- Approval / proposal → BLUE gravity. Blue reads on the label + the ☉ passkey button + the activity; the
   sheet itself stays neutral (as in approval-*.png), so it is clearly distinct from the gold refusal. --- */
#proposal-card .card-kind {
  color: var(--cd-approval-label); font-family: var(--cd-font-mono, var(--mono));
  text-transform: uppercase; letter-spacing: 0.08em; font-size: var(--cd-type-meta);
}
#proposal-card #prop-command { background: var(--cd-bg-void); }        /* Slice AI10 — the wrapping treatment stays from the shared rule; this overrides only the background */
#proposal-card #prop-approve { background: var(--cd-approval-btn); border-color: var(--cd-approval-btn); color: var(--cd-bg-app); }
#proposal-card #prop-approve:hover { background: var(--cd-approval-btn-hover); border-color: var(--cd-approval-btn-hover); }
#proposal-card #prop-approve::before { content: "\2609\00a0"; }       /* ☉ the passkey seal (from the design) */
#proposal-card #prop-activity { color: var(--cd-approval); }

/* --- Question / reply → the design's bordered option idiom (blue hover); sendReply/sendChoose unchanged. --- */
#reply-panel .reply-question { border-left-color: var(--cd-approval); }
#reply-panel .choices button { border: 1px solid var(--cd-line-3); background: var(--cd-surface-1); border-radius: 12px; }
#reply-panel .choices button:hover { border-color: var(--cd-approval); background: var(--cd-approval-chip-bg); }

/* --- Wall refusal / blocked → GOLD gravity: the calm-gold glow, the struck-through refused command, the explicit
   no-passkey note, and ONLY a dismiss ("understood") control. Id specificity beats the generic .card.blocked
   rules, so only this card turns gold. --- */
#blocked-card { border-color: var(--cd-wall); animation: cd-gold 2.4s ease-in-out infinite; }
#blocked-card .card-kind.guardrail { color: var(--cd-wall); text-transform: uppercase; letter-spacing: 0.08em; font-size: var(--cd-type-meta); }
#blocked-card #blk-command {
  color: var(--cd-wall); border-color: var(--cd-wall-cmd-border); background: var(--cd-bg-void);
  text-decoration: line-through;                                     /* the refused command, struck through */
}
#blocked-card .cd-no-passkey { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-wall); }
#blocked-card #blk-dismiss { border: 1px solid var(--cd-wall-btn-border); color: var(--cd-wall); }
#blocked-card #blk-dismiss:hover { background: var(--cd-wall-btn-hover); }

/* reduced-motion — the gold flash is off; the card stays gold, just static (the token gate the design specifies). */
@media (prefers-reduced-motion: reduce) { #blocked-card { animation: none; } }
/* ==================================== end Slice B/40 ceremony reskin ==================================== */

/* ============================================================================================================
   SLICE B.1/41 — complete the approval card in-language (PRESENTATION ONLY). Slice B designed the approve seal;
   this designs its secondary controls — deny, deny-reason, grant — so the whole card reads as ONE Command Deck
   surface, no undesigned leftovers. Scoped to #proposal-card; every id/handler/behavior is unchanged (deny still
   denies with its reason, grant still mints the real write-window). No new motion — these are static controls,
   not states — the restrained choice. A coherent gravity system: blue = approve, NEUTRAL = decline, gold = wall
   refusal, red = production (Slice C).
   ============================================================================================================ */

/* --- Deny → the CALM counter-gravity. Not the blue seal, not the gold wall, not red-production/danger: a quiet,
   deliberate "I'm declining this" — neutral recede, secondary to approve. --- */
#proposal-card #prop-deny {
  background: transparent; border: 1px solid var(--cd-line-3); color: var(--cd-muted-1);
}
#proposal-card #prop-deny:hover { background: var(--cd-surface-1); border-color: var(--cd-muted-3); color: var(--cd-text-2); }

/* --- Deny-reason → the design's dark input language (matches the question reply field), blue focus. Always
   visible (revealing it only on deny would be a behaviour change — kept presentation-only, see the slice note). --- */
#proposal-card #prop-deny-reason {
  background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); color: var(--cd-text-body); border-radius: 10px;
}
#proposal-card #prop-deny-reason:focus { border-color: var(--cd-approval); outline: none; }
#proposal-card #prop-deny-reason::placeholder { color: var(--cd-muted-4); }

/* --- Grant → the SCOPED affirmative: a blue-tinted OUTLINE (the blue family, so clearly a "yes"), but lighter
   than the full filled passkey seal — no ☉ glyph. A scoped yes, not the seal. --- */
#proposal-card #prop-grant.grant-btn {
  border: 1px solid var(--cd-approval-chip-border); color: var(--cd-approval); background: var(--cd-approval-chip-bg);
}
#proposal-card #prop-grant.grant-btn:hover { border-color: var(--cd-approval); background: var(--cd-approval-chip-bg); color: var(--cd-approval-chip-text); }
/* ==================================== end Slice B.1/41 approval completion ==================================== */

/* preview (Slice 8) — a bottom-docked sheet so the transcript peeks above and "back to run" is one
   tap; the full-screen toggle grows it to the whole viewport for a 390px landing-page view. */
.stream-actions { display: flex; gap: var(--cd-space-5); }
.stream-actions #abort { flex: 1; }
/* ── Slice UI4 — THE OVERLAY, once ─────────────────────────────────────────────────────────────────────────────
   Thirteen full-screen overlays each declared the same column for themselves. It is declared here once and the
   thirteen ids alias it, exactly as Chip and Tag were done.
   WHAT THIS RULE DELIBERATELY DOES NOT TAKE: the positioning. Eight verifies pin an overlay's opening
   declarations as exact contiguous text — the offset below the topbar is a layout contract several slices assert
   per id — so position and inset stay in each rule where those checks can still see them. A primitive that
   absorbed them would read as tidier and would break eight slices, which is not a trade.
   AND IT MUST NOT WIN AGAINST [hidden]. The attribute rule carries !important precisely because a display here
   would otherwise keep a dismissed card on screen; this rule is deliberately un-important so the attribute
   always wins. The reauth card is the one that proves it — it can only be dismissed if [hidden] beats this. */
#settings-overlay, #history-overlay, #history-detail-overlay, #author-overlay, #agent-config-overlay,
#vendor-overlay, #plan-overlay, #sequence-overlay, #asset-modal-overlay, #studio-modal-overlay,
#naming-modal-overlay, #picker-overlay {
  display: flex;
  flex-direction: column;
}

#preview-overlay {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--cd-z-modal);
  height: 74vh; display: flex; flex-direction: column; overflow: hidden;
  background: var(--bg); border-top: 1px solid var(--line); border-radius: 12px 12px 0 0;
}
#preview-overlay.fullscreen { top: 0; height: 100vh; border-radius: 0; }
#preview-bar {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between;
  padding: var(--cd-space-5) var(--cd-space-6); border-bottom: 1px solid var(--line); background: var(--surface);
}
/* Slice ID1 — RENAMED with the span it was always for. Under the shared id this rule also matched the deploy
   panel's label, and an id outranks a class: it overrode .preview-label's kicker size and, worse, beat the
   [data-src] colours M30 wrote to distinguish a URL deployed THIS RUN from an existing one — resolved, both
   states computed var(--muted). That distinction has been dead for as long as the duplicate has existed. */
#preview-overlay-label { font-size: var(--cd-type-lead); color: var(--muted); }
.preview-actions { display: flex; gap: var(--cd-space-4); }
#preview-frame { flex: 1 1 auto; width: 100%; border: 0; background: var(--cd-preview-paper); }

/* devices / settings (Slice 11) — the first settings-shaped surface. Minimal, per §5. */
.topbar-right { display: flex; align-items: center; gap: var(--cd-space-6); }
#open-settings { font-size: var(--cd-type-body); padding: var(--cd-space-3) var(--cd-space-5); }
#settings-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--bg); }
#settings-bar { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; padding: var(--cd-space-6); border-bottom: 1px solid var(--line); background: var(--surface); }
#settings-error { margin: var(--cd-space-4) var(--cd-space-6) 0; }
#settings-body { flex: 1 1 auto; overflow: auto; padding: var(--cd-space-7); display: flex; flex-direction: column; gap: var(--cd-space-7); }
/* Slice REVOKE2 — the sessions list is the SAME list, so it is the same rule rather than a second one that has to
   be kept in step. Caught in the render, not by a check: the new list inherited the browser's default bullets and
   indentation and read as a different kind of thing sitting under the credentials it belongs beside. */
#cred-list,
#session-list { list-style: none; padding: var(--cd-space-4) 0 0; margin: 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-lead); }
#cred-list li,
#session-list li { display: flex; align-items: center; gap: var(--cd-space-5); padding: var(--cd-space-2) 0; }
#enroll-token-box { display: flex; flex-direction: column; gap: var(--cd-space-4); }
#enroll-link { width: 100%; }

/* override picker (Slice 9) — 260 agents on 390px. Search-first, sections, in-flow pin/unpin. */
.agents-head { display: flex; align-items: center; justify-content: space-between; }
#forced-list { list-style: none; padding: var(--cd-space-3) 0 0; margin: 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-lead); color: var(--fg); }
#forced-list li { display: flex; align-items: center; gap: var(--cd-space-4); padding: 3px 0; }
#forced-list .forced-empty { color: var(--muted); }
.forced-remove { border: none; background: transparent; color: var(--danger); padding: 0 var(--cd-space-3); font-size: var(--cd-type-display); line-height: 1; cursor: pointer; }
.plusauto { display: flex; align-items: center; gap: var(--cd-space-4); font-size: var(--cd-type-lead); color: var(--muted); margin: var(--cd-space-3) 0 0; }
.plusauto input { width: auto; }
.link { border: none; background: transparent; color: var(--accent); padding: 0; font-size: var(--cd-type-lead); cursor: pointer; text-decoration: underline; }

#picker-overlay {
  position: fixed; inset: 0; z-index: var(--cd-z-modal);
  background: var(--bg);
}
#picker-bar { flex: 0 0 auto; display: flex; gap: var(--cd-space-4); padding: var(--cd-space-6); border-bottom: 1px solid var(--line); background: var(--surface); position: sticky; top: 0; }
#picker-bar #picker-search { flex: 1; }
#picker-error { margin: var(--cd-space-4) var(--cd-space-6) 0; }
#picker-list { flex: 1 1 auto; overflow: auto; padding: 4px 0 24px; }
.picker-section { border-bottom: 1px solid var(--line); }
.picker-section > summary { cursor: pointer; padding: var(--cd-space-6); font-size: var(--cd-type-body); color: var(--muted); text-transform: uppercase; letter-spacing: 0.4px; list-style: none; }
.picker-section > summary::-webkit-details-marker { display: none; }
.picker-division { padding-bottom: var(--cd-space-2); }
.division-head { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--muted); padding: var(--cd-space-3) var(--cd-space-6) var(--cd-space-1); }
/* Slice UI16 — two columns, not three. The leading 32px track held the select control, and selection left this
   surface with the list; what stays here curates the roster and has nothing to select. */
.agent-item { display: grid; grid-template-columns: 1fr auto; gap: var(--cd-space-5); align-items: start; padding: var(--cd-space-4) var(--cd-space-6); border-top: 1px solid var(--line); }
.agent-info { min-width: 0; }
.agent-name { font-weight: 500; font-size: var(--cd-type-title); display: flex; align-items: baseline; gap: var(--cd-space-3); }
.agent-desc { font-size: var(--cd-type-body); color: var(--muted); line-height: 1.4; margin-top: var(--cd-space-1); }
.src-badge { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-kicker); padding: 1px 5px; border-radius: 4px; border: 1px solid var(--line); color: var(--muted); }
.src-badge.local { color: var(--accent); border-color: var(--accent); } /* provenance never ambiguous */
.agent-item.is-local { border-left: 2px solid var(--accent); }
.row-actions { display: flex; align-items: center; gap: var(--cd-space-3); flex-wrap: wrap; justify-content: flex-end; }
.pin-toggle { align-self: center; font-size: var(--cd-type-body); padding: var(--cd-space-3) var(--cd-space-5); }
.pin-toggle.pinned { color: var(--guardrail); border-color: var(--guardrail); }
.author-btn { font-size: var(--cd-type-body); padding: var(--cd-space-3) var(--cd-space-5); }
.reason.note { color: var(--muted); } /* fallback: a heads-up, not an error */

/* author overlay (Slice 10) */
#picker-bar #picker-new { flex: 0 0 auto; }
#author-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--bg); }
#author-bar { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; padding: var(--cd-space-6); border-bottom: 1px solid var(--line); background: var(--surface); position: sticky; top: 0; }
#author-title { font-size: var(--cd-type-lead); color: var(--muted); }
.author-top-actions { display: flex; gap: var(--cd-space-4); }
#author-error { margin: var(--cd-space-4) var(--cd-space-6) 0; }
#author-form { flex: 1 1 auto; overflow: auto; padding: var(--cd-space-6); display: flex; flex-direction: column; gap: var(--cd-space-6); }
#author-body { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); line-height: 1.5; }

/* Slice M63 — per-agent CONFIG overlay (flags + skill attachment). Design-token layer only (--cd-*). Full-screen
   sheet like the author editor; each flag/skill is a checkbox row with its real description (flags) or its
   description-first label (skills). */
#agent-config-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--cd-bg-void); }
#agent-config-bar { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--cd-line-2); }
#agent-config-title { font-size: var(--cd-type-lead); color: var(--cd-text-hi); }
#agent-config-error { margin: 8px 14px 0; }
#agent-config-body { flex: 1 1 auto; overflow: auto; padding: 14px; display: flex; flex-direction: column; gap: var(--cd-space-7); max-width: 720px; margin: 0 auto; width: 100%; box-sizing: border-box; }
.agent-config-applied { font-size: var(--cd-type-meta); color: var(--cd-muted-2); margin: 0; }
/* ============================== Slice AL5 — the same overlay, presented as a slide-over ==============================
   Every rule is gated on the mode attribute, which only exists while the surface was opened from a live panel, so
   the picker's full-screen presentation is byte-for-byte what it was. Nothing here changes what is IN the overlay —
   the controls, their classes and their dataset are the picker's, unchanged, because the collector that reads them
   is document-wide and must keep finding exactly one set. */
#agent-config-alive-note { margin: 8px 14px 0; color: var(--cd-muted-2); font-size: var(--cd-type-meta); }
/* The top offset clears the TAB STRIP as well as the topbar. Every overlay in this file starts at --topbar-h with
   a z-index below the strip's, so the strip covers the first 44px of each — which is where this surface keeps its
   save and cancel controls. That is a pre-existing condition on the shared surface and not this slice's to change
   across seven overlays; what this slice can do is not inherit it on the surface it adds. */
#agent-config-overlay[data-mode="slideover"] { inset: calc(var(--topbar-h) + var(--tabbar-h)) 0 0 auto; width: min(480px, 100vw);
  border-left: 1px solid var(--cd-line-2); box-shadow: -18px 0 40px rgba(var(--cd-shadow-rgb), 0.5); }
#agent-config-overlay[data-mode="slideover"] #agent-config-body { max-width: none; }
/* At phone width a 480px rail would BE the screen with a sliver of canvas behind it, which reads as a broken
   full-screen rather than a panel beside something. Below that it is simply the full surface again. */
@media (max-width: 599px) { #agent-config-overlay[data-mode="slideover"] { inset: calc(var(--topbar-h) + var(--tabbar-h)) 0 0 0; width: auto; border-left: 0; box-shadow: none; } }
.agent-config-section { display: flex; flex-direction: column; gap: var(--cd-space-4); }
.agent-config-h { margin: 0; font-size: var(--cd-type-body); font-weight: 600; color: var(--cd-text-2); text-transform: uppercase; letter-spacing: 0.04em; }
.agent-config-flag, .agent-config-skill, .agent-config-model-row { display: flex; align-items: flex-start; gap: var(--cd-space-5); padding: 9px 11px; border: 1px solid var(--cd-line-2); border-radius: 8px; background: var(--cd-surface-1); cursor: pointer; }
.agent-config-flag-cb, .agent-config-skill-cb, .agent-config-model-rb { width: 16px; height: 16px; margin-top: 1px; accent-color: var(--cd-approval); flex: 0 0 auto; cursor: pointer; }
.agent-config-flag-txt, .agent-config-skill-txt, .agent-config-model-txt { display: flex; flex-direction: column; gap: var(--cd-space-1); min-width: 0; }
.agent-config-flag-name { font-size: var(--cd-type-body); color: var(--cd-text-hi); }
.agent-config-flag-desc { font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; }
/* Slice MDL1 — the model rows JOIN the flag and skill rules above rather than restating them: three sibling
   controls in one surface that look different would read as three different kinds of decision. Only the two
   leaves the shared rules do not already cover are named here, and both take the same roles their siblings do. */
.agent-config-model-name { font-size: var(--cd-type-body); color: var(--cd-text-hi); }
.agent-config-model-hint { font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; }
.agent-config-skill-desc { font-size: var(--cd-type-body); color: var(--cd-text); overflow-wrap: anywhere; }
.agent-config-skill-slug { font-size: var(--cd-type-meta); color: var(--cd-muted-3); overflow-wrap: anywhere; }
.agent-config-empty { font-size: var(--cd-type-body); color: var(--cd-muted-3); margin: 0; padding: var(--cd-space-4) var(--cd-space-1); }
.agent-config-vendor { align-self: flex-start; font-size: var(--cd-type-meta); padding: var(--cd-space-2) var(--cd-space-5); }
/* Slice SKILLCAT — the skills picker's category sections. Purely presentational: these rules space and label the
   groups, they never touch a row's markup (.agent-config-skill* above is unchanged). The container becomes a flex
   column so the sections separate cleanly — which also makes .agent-config-vendor's existing align-self: flex-start
   do what it was always written to do. The heading is quieter than .agent-config-h so a category reads as a
   subdivision of "skills", not as a peer of the "behavior flags" / "skills" section headings. */
#agent-config-skills { display: flex; flex-direction: column; gap: var(--cd-space-7); }
.agent-config-skillcat { display: flex; flex-direction: column; gap: var(--cd-space-3); }
.agent-config-skillcat-h { display: flex; align-items: center; gap: var(--cd-space-4); width: 100%; margin: 0 0 var(--cd-space-1); padding: 0 0 5px; border: 0; border-bottom: 1px solid var(--cd-line-2); background: none; text-align: left; cursor: pointer; font-family: inherit; font-size: var(--cd-type-meta); font-weight: 600; color: var(--cd-muted-2); text-transform: uppercase; letter-spacing: 0.06em; }
.agent-config-skillcat-h:hover { color: var(--cd-text-2); }
.agent-config-skillcat-h::before { content: '▾'; font-size: var(--cd-type-micro); line-height: 1; opacity: 0.75; }
.agent-config-skillcat.is-collapsed .agent-config-skillcat-h::before { content: '▸'; }
/* Both numbers are always shown and both are labelled — a bare "(13)" on a closed header reads as "13 selected".
   Muted at zero, highlighted only when something is actually selected, so the eye still finds the live categories. */
.agent-config-skillcat-n { margin-left: auto; flex: 0 0 auto; text-transform: none; letter-spacing: 0; color: var(--cd-muted-3); font-weight: 400; }
.agent-config-skillcat-n.is-on { color: var(--cd-approval); font-weight: 500; }
.agent-config-skillcat-body { display: flex; flex-direction: column; gap: var(--cd-space-3); }
/* HIDE, never detach: saveAgentConfig's document-wide :checked query is blind to CSS, so a hidden checkbox still
   saves — but a row removed from the DOM would silently drop that skill from the agent. Collapsing is display only. */
.agent-config-skillcat.is-collapsed .agent-config-skillcat-body { display: none; }

/* Slice M64 — vendor-a-skill overlay. --cd-* tokens only. The review is the control: each skill shows its full body
   verbatim (a scrollable <pre>), description, sha, size, and the exact file tree. Flags are amber HINTS, not a verdict. */
#vendor-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: calc(var(--cd-z-modal) + 1); background: var(--cd-bg-void); }
#vendor-bar { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--cd-line-2); }
#vendor-title { font-size: var(--cd-type-lead); color: var(--cd-text-hi); }
#vendor-error { margin: 8px 14px 0; }
#vendor-body { flex: 1 1 auto; overflow: auto; padding: 14px; display: flex; flex-direction: column; gap: var(--cd-space-6); max-width: 820px; margin: 0 auto; width: 100%; box-sizing: border-box; }
.vendor-fetch-row { display: flex; gap: var(--cd-space-4); }
#vendor-url { flex: 1 1 auto; min-width: 0; padding: var(--cd-space-4) var(--cd-space-5); border: 1px solid var(--cd-line-3); border-radius: 8px; background: var(--cd-bg-void); color: var(--cd-text); font-size: var(--cd-type-body); }
.vendor-note { font-size: var(--cd-type-meta); color: var(--cd-muted-2); margin: 0; line-height: 1.5; }
.vendor-note code { color: var(--cd-wall); }
.vendor-status { font-size: var(--cd-type-body); color: var(--cd-text-2); margin: 0; }
.vendor-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cd-space-5); }
.vendor-skill { border: 1px solid var(--cd-line-2); border-radius: 8px; background: var(--cd-surface-1); padding: var(--cd-space-5) var(--cd-space-6); display: flex; flex-direction: column; gap: var(--cd-space-3); }
.vendor-skill-head { display: flex; align-items: flex-start; gap: var(--cd-space-5); cursor: pointer; }
.vendor-cb { width: 16px; height: 16px; margin-top: var(--cd-space-1); accent-color: var(--cd-approval); flex: 0 0 auto; cursor: pointer; }
.vendor-skill-meta { display: flex; flex-direction: column; gap: var(--cd-space-1); min-width: 0; }
.vendor-skill-name { font-size: var(--cd-type-body); color: var(--cd-text-hi); display: flex; align-items: center; gap: var(--cd-space-3); flex-wrap: wrap; }
.vendor-update { font-size: var(--cd-type-kicker); color: var(--cd-wall); border: 1px solid color-mix(in oklch, var(--cd-wall) 45%, transparent); border-radius: 4px; padding: 0 5px; }
.vendor-skill-desc { font-size: var(--cd-type-body); color: var(--cd-text); overflow-wrap: anywhere; }
.vendor-skill-sub { font-size: var(--cd-type-meta); color: var(--cd-muted-3); }
.vendor-flags { font-size: var(--cd-type-meta); color: var(--cd-wall); overflow-wrap: anywhere; }
.vendor-files { font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; }
.vendor-refused { font-size: var(--cd-type-meta); color: var(--cd-muted-3); overflow-wrap: anywhere; }
.vendor-body-wrap { border-top: 1px solid var(--cd-line-2); padding-top: var(--cd-space-3); }
.vendor-body-wrap summary { font-size: var(--cd-type-meta); color: var(--cd-link); cursor: pointer; }
.vendor-body, .vendor-diff { max-height: 320px; overflow: auto; margin: var(--cd-space-3) 0 0; padding: var(--cd-space-4) var(--cd-space-5); background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); border-radius: 6px; font-size: var(--cd-type-meta); line-height: 1.5; color: var(--cd-text-body); white-space: pre-wrap; overflow-wrap: anywhere; }

/* honest activity — indeterminate "working", never a progress bar and never a percentage (a fake
   percent is a lie). Three quiet dots that pulse; they say "working" without claiming how far. */
.activity { display: flex; align-items: center; gap: var(--cd-space-4); font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--muted); }
.activity[hidden] { display: none; }
.dots { display: inline-flex; gap: var(--cd-space-2); align-items: center; color: var(--muted); }
.dots i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; opacity: 0.28; animation: am-dot 1.4s infinite ease-in-out both; }
.dots i:nth-child(2) { animation-delay: 0.16s; }
.dots i:nth-child(3) { animation-delay: 0.32s; }
@keyframes am-dot { 0%, 80%, 100% { opacity: 0.25; } 40% { opacity: 0.9; } }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
  .dots i { animation: none !important; opacity: 0.55; } /* static cluster still reads as "working" */
}

@media (min-width: 720px) {
  #stream { height: 60vh; }
  .card { bottom: 24px; }
}

/* Slice 12b — the batch (write_many) card. Every op listed, grouped by directory, create/overwrite
   marked per row. The list scrolls (tall card is correct) but is NEVER truncated — every file is present. */
#prop-batch { margin: var(--cd-space-3) 0; }
.batch-header { font-weight: 600; margin: 0 0 var(--cd-space-3); }
.batch-list { list-style: none; margin: 0; padding: 0; max-height: 46vh; overflow-y: auto; border: 1px solid var(--cd-border); border-radius: 6px; }
.batch-dir { padding: 5px 8px 2px; opacity: 0.62; font-size: var(--cd-type-body); position: sticky; top: 0; background: var(--card); }
.batch-row { display: flex; align-items: baseline; gap: var(--cd-space-4); padding: var(--cd-space-1) var(--cd-space-4) var(--cd-space-1) var(--cd-space-7); }
.batch-act { flex: 0 0 auto; font-size: var(--cd-type-micro); text-transform: uppercase; letter-spacing: 0.03em; padding: 1px 5px; border-radius: 3px; }
.batch-create { color: var(--cd-row-create-text); background: var(--cd-row-create-bg); }
.batch-overwrite { color: var(--cd-row-overwrite-text); background: var(--cd-row-overwrite-bg); font-weight: 700; } /* loud, not a subtle icon */
.batch-path { flex: 1 1 auto; word-break: break-all; }

/* Slice 13b — run history. Summaries only in the list (never a transcript); tapping a row opens the
   journal in the transcript view. outcome shown plainly — no success language, no green checks. */
/* Slice 23 — the library asset modal (below the topbar, with a close — no trap, Slice 13c). The links toggle
   and the per-slot binding section. */
#asset-modal-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--bg); }
#asset-modal-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--line); }
#asset-modal-body { padding: var(--cd-space-7); overflow: auto; display: flex; flex-direction: column; gap: var(--cd-space-6); align-items: flex-start; max-width: 720px; margin: 0 auto; width: 100%; box-sizing: border-box; }
#asset-preview { width: 100%; display: flex; justify-content: center; }
.asset-media { max-width: 100%; max-height: 60vh; border-radius: 8px; background: var(--cd-media-mat); }
.asset-sever-note { font-size: var(--cd-type-body); color: var(--muted); border-left: 2px solid var(--line); padding-left: var(--cd-space-5); }
/* Slice S30 — the media studio modal shares the asset-modal full-screen overlay idiom (the result image reuses .asset-media). */
#studio-modal-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--bg); }
#studio-modal-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--line); }
#studio-modal-body { padding: var(--cd-space-7); overflow: auto; display: flex; flex-direction: column; gap: var(--cd-space-6); align-items: stretch; max-width: 720px; margin: 0 auto; width: 100%; box-sizing: border-box; }
#studio-prompt { width: 100%; box-sizing: border-box; resize: vertical; }
#studio-result { width: 100%; display: flex; justify-content: center; }
#studio-actions { display: flex; align-items: center; gap: var(--cd-space-6); }
/* Slice S31 — reference-image strip + picker in the studio modal. */
.studio-refs-strip { display: flex; flex-wrap: wrap; gap: var(--cd-space-4); align-items: center; min-height: 24px; }
.studio-refs-actions { display: flex; align-items: center; gap: var(--cd-space-6); margin-top: var(--cd-space-4); }
.studio-ref-chip { position: relative; display: inline-flex; }
.studio-ref-thumb { width: 56px; height: 56px; object-fit: cover; border-radius: 6px; border: 1px solid var(--line); background: var(--cd-media-mat); }
.studio-ref-x { position: absolute; top: -6px; right: -6px; width: 18px; height: 18px; border-radius: 50%; border: none; background: var(--line); color: var(--fg); font-size: var(--cd-type-body); line-height: 1; cursor: pointer; padding: 0; }
.studio-ref-picker { display: flex; flex-wrap: wrap; gap: var(--cd-space-4); margin-top: var(--cd-space-4); max-height: 240px; overflow: auto; padding: var(--cd-space-4); border: 1px solid var(--line); border-radius: 8px; }
.studio-ref-option { display: flex; flex-direction: column; align-items: center; gap: var(--cd-space-2); width: 84px; background: none; border: 1px solid transparent; border-radius: 8px; padding: var(--cd-space-3); cursor: pointer; color: var(--fg); }
.studio-ref-option.is-picked { border-color: var(--accent); }
.studio-ref-optname { font-size: var(--cd-type-kicker); max-width: 72px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Slice S32 — image/video kind toggle + the spend-confirm panel. */
.studio-kind-toggle { display: inline-flex; gap: 0; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.studio-kind-btn { background: none; border: none; color: var(--muted); padding: var(--cd-space-3) var(--cd-space-7); cursor: pointer; font: inherit; }
.studio-kind-btn.is-active { background: var(--accent); color: var(--cd-on-accent); }
.studio-spend-confirm { border: 1px solid var(--danger); border-radius: 8px; padding: var(--cd-space-6); display: flex; flex-direction: column; gap: var(--cd-space-4); }
.studio-spend-actions { display: flex; gap: var(--cd-space-6); }
.asset-modal-actions { display: flex; gap: var(--cd-space-6); align-items: center; }
/* Slice AR3 — the flow composer modal. Same full-screen overlay idiom as the studio modal above; it reuses
   .field/.label/.hint/.activity, .studio-refs-strip/.studio-ref-picker (the S31 primitives) and .studio-kind-toggle
   (the S32 mode toggle), so only the composer-specific blocks are new. */
/* .field is a flex COLUMN, so an inline-flex child still stretches to its width — the mode toggle rendered as a
   full-width bar with "boomerang-loop" reading as a text input. Pin it to its content. (Render-caught, not predicted.) */
/* crew — an ORDERED strip of picked agents (order is the stored order) + a grouped picker of vetted agents. */
/* input slots */
/* saved flows + the run surface */
/* Slice AR5 — three views inside the one modal, plus live per-stage progress. */
/* a demo asset while browsing FOR a run: visibly not pickable (AR4 refuses it at prepare either way) */
/* (the .motion-kind toggle rules live with the motion library block above) */

/* --- Slice S14a — the BROWSE-library modal. A dimmed backdrop + a large centered panel: a horizontal section-tab
   strip AND a vertical side rail (both switch the active section — browse-all mode), over a card body that renders
   buildPromptCard verbatim (so the S13 image / S12 hover / S8 trashcan styles all apply as-is). Live tokens, matching
   the asset modal. On narrow widths the desktop side rail folds away — the tab strip carries section switching. --- */
#library-modal-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: color-mix(in oklab, var(--bg) 78%, transparent); display: flex; align-items: center; justify-content: center; padding: var(--cd-space-7); box-sizing: border-box; }
#library-modal { display: flex; flex-direction: column; width: min(1040px, 100%); max-height: min(88vh, 900px); background: var(--surface); border: 1px solid var(--line); border-radius: 14px; overflow: hidden; box-shadow: 0 20px 60px rgba(var(--cd-shadow-rgb), 0.5); }
/* Slice NAME1 — the bar WRAPS, because it gained a fourth child. Measured at 320: with the door in it the bar's
   content is 308 wide in a 271 box, so nowrap put 37 pixels of it past the edge — the door and the close control
   are the two things in here that must never be off-screen. Wrapping drops the pair to a second row instead. */
#library-modal-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cd-space-6); padding: var(--cd-space-6) var(--cd-space-7); border-bottom: 1px solid var(--line); }
#library-modal-bar > .mono:first-child { color: var(--fg); font-weight: 600; min-width: 0; }
.lm-count { margin-left: auto; color: var(--muted); }
/* Slice NAME1 — the naming door. It sits between the count and close, so `margin-left: auto` on the count keeps
   pushing the group right and the bar's own flex handles the rest — no width arithmetic, and it wraps with the
   bar rather than pinning it wide at 320. It carries the APPROVAL role: this starts a paid model call whose
   result the operator then reviews, which is the same gravity the proposal card uses, and the role is defined
   in both themes so it does not have to be restated here. */
.lm-name-action { flex: 0 0 auto; border-color: var(--cd-approval); color: var(--cd-approval-label); }
.lm-name-action[hidden] { display: none; }
.lm-tabs { display: flex; gap: var(--cd-space-3); overflow-x: auto; padding: var(--cd-space-5) var(--cd-space-7); border-bottom: 1px solid var(--line); scrollbar-width: thin; }
.lm-tab { flex: 0 0 auto; font: inherit; font-size: var(--cd-type-body); padding: var(--cd-space-3) var(--cd-space-6); border-radius: 999px; border: 1px solid var(--line); background: var(--surface-2); color: var(--fg); cursor: pointer; white-space: nowrap; }
.lm-tab:hover { border-color: var(--accent); }
.lm-tab.is-active { background: var(--accent); border-color: var(--accent); color: var(--cd-on-accent); }
#library-modal-main { display: flex; flex: 1; min-height: 0; }
.lm-rail { flex: 0 0 210px; overflow-y: auto; border-right: 1px solid var(--line); padding: var(--cd-space-5) var(--cd-space-4); display: flex; flex-direction: column; gap: var(--cd-space-1); }
.lm-rail-item { display: flex; align-items: center; justify-content: space-between; gap: var(--cd-space-4); text-align: left; font: inherit; font-size: var(--cd-type-lead); padding: var(--cd-space-4) var(--cd-space-5); border-radius: 8px; border: 0; background: transparent; color: var(--fg); cursor: pointer; }
.lm-rail-item:hover { background: var(--surface-2); }
.lm-rail-item.is-active { background: var(--surface-2); color: var(--fg); box-shadow: inset 2px 0 0 var(--accent); }
.lm-rail-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lm-rail-count { flex: 0 0 auto; font-size: var(--cd-type-meta); color: var(--muted); }
.lm-body { flex: 1; min-width: 0; overflow-y: auto; padding: var(--cd-space-7); }
.lm-empty { color: var(--muted); }
@media (max-width: 720px) {
  #library-modal { width: 100%; max-height: 92vh; }
  .lm-rail { display: none; } /* the side rail is a desktop affordance; the tab strip carries section switching on narrow widths */
}
@media (prefers-reduced-motion: reduce) { #library-modal { box-shadow: 0 8px 24px rgba(var(--cd-shadow-rgb), 0.5); } }
/* Slice S17 — the Assets/Refs tabs inside the modal. The tab body mounts the EXISTING inline asset/ref list (.lib-list
   / .lib-cat / .lib-item styles apply as-is), preceded by a modal upload bar. The two media tabs read subtly distinct
   from the section tabs. */
.lm-tab-media { border-style: dashed; }
.lm-rail-media .lm-rail-name { font-style: italic; }
.lm-media { display: flex; flex-direction: column; gap: var(--cd-space-5); }
.lm-media-bar { display: flex; align-items: center; gap: var(--cd-space-5); }
.lm-upload-btn { flex: 0 0 auto; font: inherit; font-size: var(--cd-type-body); padding: var(--cd-space-3) var(--cd-space-6); border-radius: 8px; border: 1px solid var(--accent); background: var(--surface-2); color: var(--fg); cursor: pointer; }
.lm-upload-btn:hover { background: var(--accent); color: var(--cd-on-accent); }
.lm-media-hint { color: var(--muted); font-size: var(--cd-type-meta); }
.lm-media .lib-list { margin: 0; padding: 0; list-style: none; }
/* Slice S19 — modal-wide search bar (between the bar and the tab strip). Live-filters the current tab; .lm-hidden hides
   a filtered-out card/row/category (display:none keeps S22's mouseleave teardown working). Empty-state hint for no match. */
.lm-search-row { padding: var(--cd-space-5) var(--cd-space-7) 0; }
.lm-search { width: 100%; box-sizing: border-box; font: inherit; font-size: var(--cd-type-lead); padding: var(--cd-space-4) var(--cd-space-6); border-radius: 8px; border: 1px solid var(--line); background: var(--surface-2); color: var(--fg); }
.lm-search::placeholder { color: var(--muted); }
.lm-search:focus { outline: none; border-color: var(--accent); }
.lm-hidden { display: none !important; }
.lm-empty-search { color: var(--muted); padding: var(--cd-space-7); margin: 0; }

/* --- Slice M61 — batched asset-naming REVIEW modal. Design-token layer only (--cd-*). Three row states, visually
   distinct so honest weakness is unmistakable: a PROPOSAL (opt-in, the new name in --cd-ok), a WEAK "couldn’t infer"
   row (muted, dashed, no checkbox — a thin-material guess is never offered), and an EXCLUDED row (--cd-wall left edge
   — the gate refused; the operator SEES it worked). Nothing is pre-selected. --- */
.lib-name-action { align-self: flex-start; font-size: var(--cd-type-meta); padding: var(--cd-space-2) var(--cd-space-5); }
#naming-modal-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--cd-bg-void); }
#naming-modal-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--cd-line-2); }
#naming-modal-title { color: var(--cd-text-hi); }
#naming-modal-body { padding: 14px; overflow: auto; flex: 1; display: flex; flex-direction: column; gap: var(--cd-space-6); max-width: 760px; margin: 0 auto; width: 100%; box-sizing: border-box; }
.naming-status { color: var(--cd-text-2); font-size: var(--cd-type-lead); margin: 0; }
.naming-legend { display: flex; flex-wrap: wrap; gap: 6px 14px; font-size: var(--cd-type-meta); color: var(--cd-muted-2); }
.naming-legend-item { display: inline-flex; align-items: center; gap: var(--cd-space-3); }
.naming-swatch { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.naming-swatch.sw-proposal { background: var(--cd-ok); }
.naming-swatch.sw-weak { background: transparent; border: 1px dashed var(--cd-muted-3); }
.naming-swatch.sw-excluded { background: var(--cd-wall); }
.naming-rows { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cd-space-3); }
.naming-row { display: flex; align-items: flex-start; gap: var(--cd-space-5); padding: 9px 11px; border: 1px solid var(--cd-line-2); border-radius: 8px; background: var(--cd-surface-1); min-width: 0; }
.naming-row-proposal { border-left: 3px solid var(--cd-ok); }
.naming-row-excluded { border-left: 3px solid var(--cd-wall); background: color-mix(in oklch, var(--cd-wall) 6%, transparent); }
.naming-row-weak, .naming-row-skip { background: transparent; border-style: dashed; border-left: 3px dashed var(--cd-muted-3); opacity: 0.85; }
.naming-check { flex: 0 0 auto; width: 20px; display: flex; justify-content: center; padding-top: 1px; }
.naming-cb { width: 16px; height: 16px; accent-color: var(--cd-approval); cursor: pointer; }
.naming-check-none { color: var(--cd-muted-4); font-size: var(--cd-type-lead); line-height: 18px; }
.naming-main { display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 8px; min-width: 0; flex: 1; }
.naming-cur { color: var(--cd-muted-2); overflow-wrap: anywhere; }
.naming-arrow { color: var(--cd-muted-3); flex: 0 0 auto; }
.naming-new { color: var(--cd-ok); overflow-wrap: anywhere; }
.naming-adj { color: var(--cd-muted-3); font-size: var(--cd-type-meta); }
.naming-tag { font-size: var(--cd-type-kicker); letter-spacing: 0.04em; text-transform: uppercase; padding: 1px 6px; border-radius: 4px; flex: 0 0 auto; }
.naming-row-excluded .naming-tag { color: var(--cd-wall); border: 1px solid color-mix(in oklch, var(--cd-wall) 45%, transparent); }
.naming-row-weak .naming-tag, .naming-row-skip .naming-tag { color: var(--cd-muted-2); border: 1px solid var(--cd-line-3); }
.naming-reason { color: var(--cd-muted-3); font-size: var(--cd-type-body); overflow-wrap: anywhere; }
.naming-guess { color: var(--cd-muted-4); font-size: var(--cd-type-meta); font-style: italic; overflow-wrap: anywhere; width: 100%; }
.naming-note { color: var(--cd-muted-3); font-size: var(--cd-type-body); padding: var(--cd-space-2) var(--cd-space-1); }
#naming-modal-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--cd-space-6); padding: 12px 14px; border-top: 1px solid var(--cd-line-2); background: var(--cd-surface-1); }
.naming-count { color: var(--cd-muted-2); font-size: var(--cd-type-body); }
#naming-apply:disabled { opacity: 0.45; cursor: default; }
#history-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--bg); }
#history-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; }
#history-list { list-style: none; margin: 0; padding: var(--cd-space-4); overflow-y: auto; flex: 1; }
/* Slice M29 — the show-all toggle bar; hidden when there are no empty runs to fold away */
#history-filterbar { display: flex; align-items: center; justify-content: space-between; gap: var(--cd-space-5); padding: var(--cd-space-4) var(--cd-space-6); font-size: var(--cd-type-body); }
#history-hidden-note { opacity: 0.7; }
#history-showall { font-size: var(--cd-type-kicker); }
.hist-empty { opacity: 0.6; padding: var(--cd-space-7); text-align: center; }
.hist-row { padding: var(--cd-space-5) var(--cd-space-6); border-radius: 8px; margin-bottom: var(--cd-space-4); cursor: pointer; }
.hist-empty-run { opacity: 0.55; } /* a revealed empty scratch run — dimmed, still fully legible */
.hist-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--cd-space-5); margin-bottom: var(--cd-space-2); } /* OUTCOME leads the row */
.hist-task { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-bottom: var(--cd-space-2); } /* one line, truncated */
.hist-meta { display: flex; gap: var(--cd-space-5); align-items: baseline; font-size: var(--cd-type-body); opacity: 0.8; }
.hist-summary { font-weight: 500; }
.hist-outcome { text-transform: uppercase; letter-spacing: 0.03em; font-size: var(--cd-type-lead); font-weight: 600; }
.hist-counts { font-size: var(--cd-type-body); opacity: 0.62; margin-top: var(--cd-space-2); }

/* Slice 13c — run detail overlay. Its OWN container (#detail-stream), never #stream, so opening it during
   a live run cannot touch the live transcript. Below the topbar; back → history. */
#history-detail-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: calc(var(--cd-z-modal) + 1); background: var(--bg); }
#history-detail-bar { display: flex; align-items: center; gap: var(--cd-space-5); padding: var(--cd-space-4) var(--cd-space-6); border-bottom: 1px solid var(--line); }
#history-detail-title { color: var(--muted); font-size: var(--cd-type-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#detail-stream { flex: 1; overflow: auto; padding: var(--cd-space-6); display: flex; flex-direction: column; gap: var(--cd-space-5); font-size: var(--cd-type-body); line-height: 1.55; }

/* Slice 14 — the advisory Bash flag on the proposal card. Guardrail amber (not danger red): it is a prompt
   to READ, not a block and not a claim of containment. The command below it stays fully approvable. */
.prop-flag { margin: 0; padding: var(--cd-space-4) var(--cd-space-5); border: 1px solid var(--guardrail); border-radius: 8px;
  color: var(--guardrail); font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); background: var(--cd-flag-bg); }
/* Slice M54 — why a proposal prompts despite auto-approve (informational, the guard working — not an alarm). */
.prop-autoapprove { margin: 0; padding: var(--cd-space-4) var(--cd-space-5); border: 1px solid var(--cd-line-3); border-radius: 8px;
  color: var(--cd-muted-1); font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); line-height: 1.5; background: var(--cd-surface-1); overflow-wrap: anywhere; }
.prop-autoapprove[hidden] { display: none; }

/* ============================================================================================================
   SLICE E/44 — the persistent WORKSPACE shell + idle command deck. PRESENTATION/LAYOUT only: the two views merge
   into one persistent frame via CSS grid on #app (see the ≥900 block) + the relocated projects rail. Every id and
   handler is intact; showView is unchanged (its toggle is the center-swap). Tokens only; reduced-motion honored.
   ============================================================================================================ */

/* the projects RAIL — persistent workspace context. Registered roots only (Slice 36 source; no disk scan, no home
   dir). In-language surface; the selector control keeps working (its row-list reskin is a later compose slice). */
.workspace-rail { display: flex; flex-direction: column; gap: var(--cd-space-6); padding: 14px;
  border: 1px solid var(--cd-line-2); border-radius: 14px; background: var(--cd-surface-sheet); }
.workspace-rail .rail-head { display: flex; align-items: baseline; gap: var(--cd-space-4); }
.workspace-rail .rail-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-kicker); color: var(--cd-muted-4); }
.workspace-rail .field { gap: var(--cd-space-3); }
.workspace-rail select { background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); color: var(--cd-text); border-radius: 9px; }
.workspace-rail select:focus { outline: none; border-color: var(--cd-approval); }
.workspace-rail .newproj-bar { margin-top: var(--cd-space-1); }

/* the idle COMMAND DECK frame — the quiet deck (not the raw submit form) when no run is active. #view-submit is
   only shown in the idle state, so this frame is idle-only by construction. The compose controls keep working; the
   head spans both inner columns at ≥900. */
.idle-deck-head { display: flex; flex-direction: column; gap: var(--cd-space-1); margin: 0 0 var(--cd-space-2); }
@media (min-width: 900px) { .idle-deck-head { grid-column: 1 / -1; } }
.idle-deck-kicker { text-transform: uppercase; letter-spacing: 0.14em; font-size: var(--cd-type-kicker); color: var(--cd-muted-4); }
.idle-deck-quiet { font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-lead); color: var(--cd-muted-2); }

/* the TOP NAV in-language — same #topbar, same ids/handlers; the surface + nav read as the Command Deck. */
#topbar { background: var(--cd-bg-app); border-bottom: 1px solid var(--cd-line-2); }
#topbar #brand { color: var(--cd-text-hi); }
#topbar #open-history, #topbar #open-settings { color: var(--cd-muted-1); border: 1px solid var(--cd-line-2);
  background: transparent; border-radius: 8px; }
#topbar #open-history:hover, #topbar #open-settings:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
#daemon-state[data-state="reachable"] { color: var(--cd-ok); }
#daemon-state[data-state="unreachable"] { color: var(--cd-prod); }

/* phone (<900px): the workspace COLLAPSES to a single column — the rail becomes the top section (it is a normal
   block child of the non-grid #app below the breakpoint), then the center view. One responsive component. */
@media (max-width: 899px) {
  .workspace-rail { border-radius: 12px; }
}

/* reduced-motion — the shell is static (no shell animation); it stays fully legible. Any focus transition off. */
@media (prefers-reduced-motion: reduce) {
  .workspace-rail select { transition: none; }
}
/* ==================================== end Slice E/44 workspace shell ==================================== */

/* ============================================================================================================
   SLICE F/45 — the compose controls + the projects rail ROWS, in the Command Deck language. Presentation for the
   compose controls (task / agent-selection / run — same ids/handlers); the project ROWS are a presentation layer
   over the hidden #project <select> (same value doRun reads, same registered-roots data). Tokens only.
   ============================================================================================================ */

/* the projects rail as clickable ROWS (design fidelity) — each row is one registered root; the active one is lit
   in the approval-blue attention hue. Rows DRIVE the hidden #project select (no divergent selection path). */
.project-rows { display: flex; flex-direction: column; gap: var(--cd-space-2); }
.project-row { width: 100%; text-align: left; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body);
  color: var(--cd-muted-1); background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); border-radius: 9px;
  padding: var(--cd-space-4) var(--cd-space-5); cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: border-color .15s ease, color .15s ease, background .15s ease; }
.project-row:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.project-row[data-active] { color: var(--cd-approval-chip-text); border-color: var(--cd-approval);
  background: color-mix(in oklch, var(--cd-approval) 12%, transparent); box-shadow: inset 2px 0 0 var(--cd-approval); }
/* Slice M45 — an IN-USE project (locked by an active run): disabled + dimmed, not clickable, with a wall-gold reason
   line (informational guardrail weight — NOT the death red). Not hidden. Uncrowded at 390px (the reason wraps). */
.project-row[data-in-use] { cursor: not-allowed; opacity: 0.6; border-style: dashed; }
.project-row[data-in-use]:hover { color: var(--cd-muted-1); border-color: var(--cd-line-2); } /* no hover affordance — it is not selectable */
.project-row-reason { display: block; margin-top: 3px; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-kicker); color: var(--cd-wall); white-space: normal; overflow-wrap: anywhere; }

/* the compose controls in-language (same ids/handlers — presentation only). */
#task { background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); color: var(--cd-text); border-radius: 11px; }
#task:focus { outline: none; border-color: var(--cd-approval); }
#task::placeholder { color: var(--cd-muted-4); }
/* the RUN button — the "give the go" affirmative: the approval-blue fill, the deck's primary action. */
#run { background: var(--cd-approval-btn); color: var(--cd-text-hi); border: 0; border-radius: 12px; font-weight: 600; }
#run:disabled { background: var(--cd-line-2); color: var(--cd-muted-3); }
/* agent-selection — in-language: the "auto — routing picks…" hint muted, the choose control a quiet in-language
   affordance, the resolved list legible. */
#agents-field .label, #agents-hint, #agents-summary { color: var(--cd-muted-2); }
#open-picker { color: var(--cd-muted-1); border: 1px solid var(--cd-line-2); background: transparent; border-radius: 9px; }
#open-picker:hover { color: var(--cd-text); border-color: var(--cd-line-3); }

/* reduced-motion — the row transitions are decorative; the active state is carried by colour + the inset bar
   (not motion), so state stays fully legible with animation/transition off. */
@media (prefers-reduced-motion: reduce) {
  .project-row { transition: none; }
}
/* ==================================== end Slice F/45 compose + rows ==================================== */

/* ============================================================================================================
   SLICE G/46 — the OPERATIONAL PANELS (git · vercel · download) in the Command Deck TIER-GRAVITY language.
   PRESENTATION ONLY: every button's real action, passkey requirement, wall-gating, and DOM id is untouched — the
   git wall (Slice 34/35), the vercel three-tier wall (Slice 37), and the download validator/denylist (Slice 38)
   are unchanged; only the controls' LOOK changes. CSS-only (no markup, no app.js — no marker bump). ONE tier→
   gravity language, the same across all three panels:
     read / safe (no passkey)      → NEUTRAL  (--cd-muted / --cd-line — a quiet edge, no passkey signalled)
     ship / preview (passkey)      → BLUE     (--cd-approval — the passkey weight)
     production / live (heavier)   → RED      (--cd-prod — Slice C; MATCHED AROUND here, never restyled)
     blocked / desk-only (refused) → GOLD     (--cd-wall — where the wall refuses an op)
   Tokens only; no hardcoded colours. No new animation (reduced-motion inherited).
   ============================================================================================================ */

/* panel chrome — the three panels share .git-panel; reskin the card + head label + tier labels + field inset to
   the deck's sheet/line tokens so all three read as one surface (the vercel-prod-label stays Slice-C red). */
.git-panel { background: var(--cd-surface-sheet); border-color: var(--cd-line-2); }
.git-panel-head > .label { color: var(--cd-text-2); }
.git-group-label { color: var(--cd-muted-4); }
.git-field { border-color: var(--cd-line-2); background: var(--cd-bg-void); }
.git-preview { color: var(--cd-muted-2); }

/* READ (neutral) — git status/log/diff/branch + vercel ls/inspect/logs/whoami/projects/domains/env: a safe read,
   quiet neutral edge, no passkey signalled. Targets .git-action that is NOT a ship and NOT a prod op, so the
   Slice-C .vercel-prod red is untouched. */
.git-action:not(.ship):not(.vercel-prod) { color: var(--cd-muted-1); border-color: var(--cd-line-2); background: var(--cd-bg-void); }
.git-action:not(.ship):not(.vercel-prod):hover { color: var(--cd-text); border-color: var(--cd-line-3); }

/* SHIP / PREVIEW (blue) — the passkey weight: git add/commit/tag/push (+ combined) and vercel deploy/pull/build
   (+ combined) all carry .ship. Blue edge = "this asks for your passkey", distinct from a neutral read. */
.git-action.ship { color: var(--cd-approval-label); border-color: var(--cd-approval); background: transparent; }
.git-action.ship:hover { color: var(--cd-approval-btn-hover); border-color: var(--cd-approval-btn-hover); }

/* the ship-capable PRIMARY runs — "ship it" / run git / run vercel: solid blue, the deck's primary passkey action
   (matches the compose #run). #download-go is deliberately NOT here — a download is a read (neutral, below). */
#git-field-go, #git-run, #vercel-run { background: var(--cd-approval-btn); border-color: var(--cd-approval-btn); color: var(--cd-text-hi); }
#git-field-go:hover, #git-run:hover, #vercel-run:hover { background: var(--cd-approval-btn-hover); border-color: var(--cd-approval-btn-hover); }

/* DOWNLOAD (neutral) — a download is a READ (session-gated, NO passkey; the Slice-38 validator does the gating),
   so its CTA reads NEUTRAL, never the blue passkey weight — prominent but clearly not a ship. */
#download-go { background: var(--cd-surface-1); border-color: var(--cd-line-3); color: var(--cd-text); }
#download-go:hover { background: var(--cd-surface-2); border-color: var(--cd-line-strong); }

/* BLOCKED / desk-only (gold) — where the wall REFUSES an op, each panel's status line reads --cd-wall (the deck's
   gold) so a refusal reads as "the wall stopped this", never as an ordinary result. git · vercel · download. The
   ok/fail result kinds are run feedback, not a tier gravity — left as-is. */
#git-status-line[data-kind="blocked"],
#vercel-status-line[data-kind="blocked"],
#download-status[data-kind="blocked"] { color: var(--cd-wall); }
/* ==================================== end Slice G/46 operational panels ==================================== */

/* ============================================================================================================
   SLICE H/47 — the SECONDARY SCREENS (history/mission-logs · devices/enrollment · re-auth) in the Command Deck
   language. PRESENTATION ONLY: every handler, id, and — critically — the WebAuthn enrollment / re-auth / remove-
   credential flow is untouched; CSS/classes only (no markup, no app.js — no marker bump). Reuses the E/F/G
   surfaces: list rows (like the project rows), cards (like the ceremony cards), in-language inputs/buttons.
   Outcome labels reuse the ESTABLISHED gravities (nothing invented):
     complete → steady neutral · died/aborted → red (--cd-prod) · abandoned/interrupted → gold (--cd-wall) ·
     running → active blue (--cd-approval).
   Passkey-triggering controls (authenticate / enroll / add-a-device) → blue (--cd-approval, the passkey weight);
   a benign dismiss ("done") → neutral. Tokens only; no hardcoded colours.
   ============================================================================================================ */

/* --- History / mission logs — the overlay chrome, the run rows (the E/F list language), the outcome labels. --- */
/* SLICE M21 — the PLAN review overlay. Full-panel like history, but deliberately NOT the run deck: a distinct
   banner ("review only — nothing has run"), a left accent rule, and calm --cd-* type. Text is escaped in JS;
   this is pure presentation. Motion-free. The ⚠ unverified-path chip is guardrail gold; a "cannot" verdict is
   red. --cd-* only, no hardcoded colors. */
#plan-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: var(--cd-z-modal); background: var(--cd-bg-app); }
#plan-bar { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-bottom: 1px solid var(--cd-line-2); background: var(--cd-surface-sheet); }
#plan-bar > .mono { color: var(--cd-wall); text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--cd-type-meta); }
.plan-body { flex: 1; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: var(--cd-space-6); max-width: 760px; width: 100%; margin: 0 auto; box-sizing: border-box; }
.plan-body p { margin: 0; overflow-wrap: anywhere; }
.plan-head { display: flex; flex-direction: column; gap: var(--cd-space-2); border-left: 2px solid var(--cd-wall); padding-left: var(--cd-space-5); }
.plan-kind { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); text-transform: uppercase; letter-spacing: 0.08em; color: var(--cd-wall); }
.plan-task { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-lead); color: var(--cd-text-2); }
.plan-approach { font-size: var(--cd-type-lead); color: var(--cd-text-body); }
.plan-subtasks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cd-space-5); counter-reset: pst; }
.plan-subtask { border: 1px solid var(--cd-line-2); border-radius: 8px; padding: var(--cd-space-5) var(--cd-space-6); display: flex; flex-direction: column; gap: 5px; background: var(--cd-surface-1); }
.plan-st-title { font-size: var(--cd-type-lead); font-weight: 600; color: var(--cd-text); counter-increment: pst; }
.plan-st-title::before { content: counter(pst) ". "; color: var(--cd-muted-3); }
.plan-st-scope { font-size: var(--cd-type-body); color: var(--cd-text-body); }
.plan-st-excludes { font-size: var(--cd-type-body); color: var(--cd-muted-2); }
.plan-st-deps { font-size: var(--cd-type-meta); color: var(--cd-link); font-family: var(--cd-font-mono, var(--mono)); }
.plan-st-touches { font-size: var(--cd-type-meta); color: var(--cd-muted-3); font-family: var(--cd-font-mono, var(--mono)); overflow-wrap: anywhere; }
.plan-touch { color: var(--cd-muted-1); }
.plan-touch.unverified { color: var(--cd-wall); }
.plan-uncertainty { border: 1px dashed var(--cd-wall-btn-border); border-radius: 8px; padding: var(--cd-space-4) var(--cd-space-5); background: var(--cd-wall-btn-hover); }
.plan-uncertainty-h { font-size: var(--cd-type-meta); text-transform: uppercase; letter-spacing: 0.05em; color: var(--cd-wall); }
.plan-uncertainty-t { font-size: var(--cd-type-body); color: var(--cd-text-body); }
.plan-meta { font-size: var(--cd-type-meta); color: var(--cd-muted-3); font-family: var(--cd-font-mono, var(--mono)); }
.plan-verdict { font-size: var(--cd-type-title); color: var(--cd-ok); }
.plan-verdict.cannot { color: var(--cd-prod); }
.plan-reason { font-size: var(--cd-type-body); color: var(--cd-text-body); }
.plan-footer { font-size: var(--cd-type-meta); color: var(--cd-muted-3); border-top: 1px solid var(--cd-line-1); padding-top: var(--cd-space-4); }
#plan-btn { margin-left: var(--cd-space-4); }
/* end Slice M21 planner */
/* SLICE M22 — the plan-run-in-order button (on the plan view) + the SEQUENCE view. ⚠️ Distinct from a single run
   AND a plan: an approved plan executing its sub-tasks in order. Honest per-sub-task state chips (complete/running/
   stopped/never-ran). --cd-* only, no hardcoded colors; motion-free. The "run in order" button is emphasised
   (--cd-prod) because it EXECUTES; the sequence status is green/red/muted by state. */
.plan-run-seq { border-top: 1px solid var(--cd-line-2); padding-top: var(--cd-space-5); display: flex; flex-direction: column; gap: var(--cd-space-4); }
.plan-run-seq-note { font-size: var(--cd-type-meta); color: var(--cd-wall); }
.plan-run-seq-btn { align-self: flex-start; font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-lead); color: var(--cd-text-hi);
  background: var(--cd-prod); border: 1px solid var(--cd-prod); border-radius: 8px; padding: 8px 14px; cursor: pointer; }
.plan-run-seq-btn:hover { background: var(--cd-prod-btn-hover); border-color: var(--cd-prod-btn-hover); }
#seq-chip { font-size: var(--cd-type-body); padding: var(--cd-space-2) var(--cd-space-5);
  border: 1px solid var(--cd-line-3); background: var(--cd-surface-1); color: var(--cd-text-2); cursor: pointer; }
#seq-chip[data-status="running"] { border-color: var(--cd-approval); color: var(--cd-approval-label); }
#seq-chip[data-status="stopped"] { border-color: var(--cd-prod); color: var(--cd-prod-label); }
#seq-chip[data-status="complete"] { border-color: var(--cd-ok); color: var(--cd-ok); }
#sequence-overlay { position: fixed; inset: var(--topbar-h) 0 0 0; z-index: calc(var(--cd-z-modal) + 1); background: var(--cd-bg-app); }
#sequence-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--cd-space-4); padding: 12px 14px; border-bottom: 1px solid var(--cd-line-2); background: var(--cd-surface-sheet); }
#sequence-bar > .mono { color: var(--cd-text-2); text-transform: uppercase; letter-spacing: 0.06em; font-size: var(--cd-type-meta); }
#sequence-bar button { margin-left: var(--cd-space-3); }
.sequence-body { flex: 1; overflow-y: auto; padding: 14px 16px; display: flex; flex-direction: column; gap: var(--cd-space-6); max-width: 760px; width: 100%; margin: 0 auto; box-sizing: border-box; }
.sequence-body p { margin: 0; overflow-wrap: anywhere; }
.seq-head { display: flex; flex-direction: column; gap: var(--cd-space-2); border-left: 2px solid var(--cd-line-strong); padding-left: var(--cd-space-5); }
.seq-status { font-size: var(--cd-type-title); font-family: var(--cd-font-mono, var(--mono)); text-transform: uppercase; letter-spacing: 0.05em; }
.seq-status[data-status="running"] { color: var(--cd-approval-label); }
.seq-status[data-status="complete"] { color: var(--cd-ok); }
.seq-status[data-status="stopped"] { color: var(--cd-prod); }
.seq-sub { font-size: var(--cd-type-body); color: var(--cd-muted-1); }
.seq-stop { font-size: var(--cd-type-body); color: var(--cd-prod); }
.seq-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cd-space-4); }
.seq-item { border: 1px solid var(--cd-line-2); border-radius: 8px; padding: 9px 11px; display: flex; flex-direction: column; gap: 3px; background: var(--cd-surface-1); }
.seq-item[data-state="complete"] { border-left: 3px solid var(--cd-ok); }
.seq-item[data-state="running"] { border-left: 3px solid var(--cd-approval); }
.seq-item[data-state="died"], .seq-item[data-state="abandoned"], .seq-item[data-state="aborted"] { border-left: 3px solid var(--cd-prod); }
.seq-item[data-state="pending"] { opacity: 0.6; border-left: 3px solid var(--cd-line-2); }
.seq-item-title { display: flex; align-items: baseline; gap: var(--cd-space-4); font-size: var(--cd-type-lead); font-weight: 600; color: var(--cd-text); }
.seq-badge { flex: 0 0 auto; font-family: var(--cd-font-mono, var(--mono)); }
.seq-item[data-state="complete"] .seq-badge { color: var(--cd-ok); }
.seq-item[data-state="died"] .seq-badge, .seq-item[data-state="abandoned"] .seq-badge, .seq-item[data-state="aborted"] .seq-badge { color: var(--cd-prod); }
.seq-item[data-state="running"] .seq-badge { color: var(--cd-approval-label); }
.seq-item-state { font-size: var(--cd-type-meta); color: var(--cd-muted-2); font-family: var(--cd-font-mono, var(--mono)); }
.seq-footer { font-size: var(--cd-type-meta); color: var(--cd-muted-3); border-top: 1px solid var(--cd-line-1); padding-top: var(--cd-space-4); }
/* Slice M23 Part 4 — the plain-English stop panel: headline (bold, red for a stop), what-it-means, what-to-do,
   and the real quote (question / build error / drifted files) in a bounded scroll. --cd-* only, motion-free. */
.seq-stopdetail { border: 1px solid var(--cd-prod-cmd-border); border-left: 3px solid var(--cd-prod); border-radius: 8px;
  padding: var(--cd-space-5) var(--cd-space-6); display: flex; flex-direction: column; gap: var(--cd-space-3); background: var(--cd-surface-1); }
.seq-sd-headline { font-size: var(--cd-type-lead); font-weight: 600; color: var(--cd-prod-label); }
.seq-sd-meaning { font-size: var(--cd-type-body); color: var(--cd-text-body); }
.seq-sd-action { font-size: var(--cd-type-body); color: var(--cd-approval-label); }
.seq-sd-quote { margin: var(--cd-space-1) 0 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--cd-muted-1);
  background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); border-radius: 6px; padding: var(--cd-space-4) var(--cd-space-5);
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 30vh; overflow: auto; }
.seq-sd-preserved { font-size: var(--cd-type-meta); color: var(--cd-muted-2); }
/* end Slice M22 sequencer */
#history-overlay { background: var(--cd-bg-app); }
#history-bar { border-bottom: 1px solid var(--cd-line-2); background: var(--cd-surface-sheet); }
#history-bar > .mono { color: var(--cd-text-2); }
.hist-empty { color: var(--cd-muted-3); }
/* Slice M29 — filterbar + richer row in the design language */
#history-filterbar { border-bottom: 1px solid var(--cd-line-2); background: var(--cd-surface-sheet); }
#history-hidden-note { color: var(--cd-muted-2); }
.hist-row { border: 1px solid var(--cd-line-2); background: var(--cd-bg-void); color: var(--cd-text-body); }
.hist-row:hover { border-color: var(--cd-line-3); }
.hist-task { color: var(--cd-text); }
.hist-meta { color: var(--cd-muted-2); }
.hist-summary { color: var(--cd-text-body); }
.hist-proj, .hist-date { color: var(--cd-muted-2); }
.hist-counts { color: var(--cd-muted-3); }
/* outcome labels — the established gravities (steady neutral / red / gold / active blue). "no green checks, no
   success language" (see app.js): complete is a QUIET terminal, colour is spent on what needs attention. */
.hist-outcome[data-outcome="complete"] { color: var(--cd-text-body); }
.hist-outcome[data-outcome="died"], .hist-outcome[data-outcome="aborted"] { color: var(--cd-prod); }
.hist-outcome[data-outcome="abandoned"], .hist-outcome[data-outcome="interrupted"] { color: var(--cd-wall); }
.hist-outcome[data-outcome="running"] { color: var(--cd-approval-label); }
/* the run-detail overlay chrome (its own container — never #stream). */
#history-detail-overlay { background: var(--cd-bg-app); }
#history-detail-bar { border-bottom: 1px solid var(--cd-line-2); }
#history-detail-title { color: var(--cd-muted-1); }

/* --- Devices / enrollment — the overlay chrome, the credential list, add-a-device, the enroll link. The WebAuthn
   enrollment + the remove-credential path are UNTOUCHED; only their look changes. --- */
#settings-overlay { background: var(--cd-bg-app); }
/* SLICE M25 — the restart-daemon control + its honest states. restarting = wall/gold (in progress), reconnected =
   ok/green (observed), refused/didn't-come-back = prod/red. --cd-* only; motion-free. */
.restart-field { border-top: 1px solid var(--cd-line-2); padding-top: 14px; }
#restart-daemon { align-self: flex-start; }
.restart-status { margin: var(--cd-space-3) 0 0; font-size: var(--cd-type-body); overflow-wrap: anywhere; color: var(--cd-muted-2); }
.restart-status[data-state="restarting"] { color: var(--cd-wall); }
.restart-status[data-state="reconnected"] { color: var(--cd-ok); }
.restart-status[data-state="refused"] { color: var(--cd-prod); }
.restart-status[data-state="didnt-come-back"] { color: var(--cd-prod); }
/* end Slice M25 restart-daemon */
#settings-bar { border-bottom: 1px solid var(--cd-line-2); background: var(--cd-surface-sheet); }
#settings-bar > .mono { color: var(--cd-text-2); }
#cred-list li,
#session-list li { color: var(--cd-text-body); }
/* the remove-credential control — a quiet neutral link (NOT the passkey blue); the confirm() dialog carries the
   caution. Scoped to these two lists so the global .link is untouched. Revoking a session is the same kind of
   quiet, confirmed removal as removing a credential, so it takes the same weight rather than a louder one. */
#cred-list .link,
#session-list .link { color: var(--cd-muted-1); }
#cred-list .link:hover,
#session-list .link:hover { color: var(--cd-text); }
/* add-a-device begins a passkey enrollment → the blue enrollment weight (a quiet blue-edged ghost). */
#add-device { color: var(--cd-approval-label); border: 1px solid var(--cd-approval); background: transparent; }
#add-device:hover:not(:disabled) { color: var(--cd-approval-btn-hover); border-color: var(--cd-approval-btn-hover); }
#enroll-link { background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); color: var(--cd-text); }

/* the two benign DISMISS controls of the read overlays ("done") → neutral, NOT the passkey blue. */
#history-close, #settings-close { background: var(--cd-surface-1); border-color: var(--cd-line-3); color: var(--cd-text); }
#history-close:hover, #settings-close:hover { background: var(--cd-surface-2); border-color: var(--cd-line-strong); }

/* --- Re-auth + enroll-this-device cards → the ceremony-card language (matches #proposal-card), SCOPED BY ID so
   the shared .card base (died / blocked / proposal) is UNTOUCHED. The passkey buttons are the blue weight; the
   WebAuthn re-auth / enrollment path behind them is byte-for-byte unchanged. --- */
#reauth, #enroll-card { background: var(--cd-surface-sheet); border-color: var(--cd-line-2); }
#reauth .card-kind, #enroll-card .card-kind { color: var(--cd-muted-2); font-family: var(--cd-font-mono, var(--mono));
  text-transform: uppercase; letter-spacing: 0.08em; font-size: var(--cd-type-meta); }
#reauth > p, #enroll-card .card-meta { color: var(--cd-muted-1); }
#enroll-label { background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); color: var(--cd-text); }
/* the passkey-triggering primaries — authenticate / enroll → solid approval-blue (the passkey weight). */
#reauth-go, #enroll-go { background: var(--cd-approval-btn); border-color: var(--cd-approval-btn); color: var(--cd-text-hi); }
#reauth-go:hover, #enroll-go:hover { background: var(--cd-approval-btn-hover); border-color: var(--cd-approval-btn-hover); }
#auth-activity, #enroll-activity { color: var(--cd-approval); }
/* ==================================== end Slice H/47 secondary screens ==================================== */

/* ============================================================================================================
   SLICE I/48 — the QUESTION/REPLY controls (the LAST partial) in the Command Deck language. This completes the
   migration: with the reply input + choice buttons + send now in-language, the question sheet is fully in-language
   (Slice B did the sheet + choice-button chrome; this finishes the free-text input, the send, and the card
   coherence). PRESENTATION ONLY: sendReply (free text) / sendChoose (choices), the both-paths behavior (Slice 7
   #12 — free text accepted even when choices exist), and every id are untouched. CSS-only (no markup, no app.js —
   no marker bump). Reuses the E/F input language + the established button language. Scoped to #reply-panel so
   nothing leaks. Tokens only; no hardcoded colours.
   ============================================================================================================ */

/* panel chrome + question text — finish what Slice B started (B set the border-left + the choice-button chrome). */
#reply-panel { border-top-color: var(--cd-line-2); }
#reply-panel .reply-question { background: var(--cd-surface-1); border-radius: 10px; } /* border-left-color = cd-approval (Slice B) */
#reply-panel .reply-question .q-text { color: var(--cd-text); }

/* the free-text reply input → the E/F input language (matches #task): the void inset, the cd border, blue focus. */
#reply-text { background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); color: var(--cd-text); border-radius: 11px; }
#reply-text:focus { outline: none; border-color: var(--cd-approval); }
#reply-text::placeholder { color: var(--cd-muted-4); }

/* the choice buttons carry the cd border/fill/hover from Slice B; give the label the deck text colour so a choice
   reads fully in-language (left-align preserved from .choices button). Both paths stay live — sendChoose unchanged. */
#reply-panel .choices button { color: var(--cd-text-2); }

/* SEND → the approval-blue affirmative (matches #run / #git-field-go — the "send it" primary). sendReply unchanged. */
#reply-panel #reply-send { background: var(--cd-approval-btn); border-color: var(--cd-approval-btn); color: var(--cd-text-hi); }
#reply-panel #reply-send:hover { background: var(--cd-approval-btn-hover); border-color: var(--cd-approval-btn-hover); }

/* advance / end-run — the secondary lifecycle controls sharing the .reply-actions row: neutral in-language (NOT
   the passkey blue), so the whole card reads coherent. Benign lifecycle, no gravity. */
#reply-panel #advance-run, #reply-panel #end-run { color: var(--cd-muted-1); border: 1px solid var(--cd-line-2); background: transparent; }
#reply-panel #advance-run:hover, #reply-panel #end-run:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
/* ==================================== end Slice I/48 question/reply controls ==================================== */

/* ============================================================================================================
   SLICE J/49 — three live-run presentation fixes (collapsible dirs · universal selection-blue · sticky panels).
   Presentation + contained UI-state only: no change to the selection source (#project / registered roots / Slice-36
   containment), any git/vercel/download button's action or wall-gating (Slices 34/35/37/38), any handler, WS, or
   daemon code. Tokens only.
   ============================================================================================================ */

/* --- Task 1 — the COLLAPSIBLE directory list. The head always shows the SELECTED dir (synced by syncProjectHead);
   the toggle flips data-open, which CSS uses to show/hide the full row list. Pure show/hide over the SAME #project
   selection — collapsed by default (10+ projects otherwise eat the page). --- */
.project-collapse { display: flex; flex-direction: column; gap: var(--cd-space-2); }
.project-head { display: flex; align-items: center; justify-content: space-between; gap: var(--cd-space-4); width: 100%;
  text-align: left; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); color: var(--cd-text);
  background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); border-radius: 9px; padding: var(--cd-space-4) var(--cd-space-5); cursor: pointer; }
.project-head:hover { border-color: var(--cd-line-3); }
.project-head-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.project-head-chev { flex: 0 0 auto; color: var(--cd-muted-3); transition: transform 0.15s ease; }
.project-collapse[data-open="true"] .project-head-chev { transform: rotate(180deg); }
.project-collapse[data-open="false"] #project-rows { display: none; } /* collapsed: only the head (selected dir) shows */

/* --- Task 2 — the UNIVERSAL selected/active signal: the SAME approval-blue the active project row uses. Every
   persistent/used selection carries a tinted-CHIP fill (color-mix tint + --cd-approval border), so a chosen state is
   instantly readable everywhere. Kept DISTINCT from the ship/passkey-blue by FILL LEVEL: selected = translucent TINT;
   Slice-G ship-edge = NO fill (transparent outline); Slice-G ship-primary = SOLID opaque fill. Three fill levels,
   one hue — "active/chosen" never reads as "will ask a passkey". --- */
.lib-tab.on { border-color: var(--cd-approval); color: var(--cd-approval-chip-text);
  background: color-mix(in oklch, var(--cd-approval) 14%, transparent); }
.slot-choice-btn.on { border-color: var(--cd-approval); color: var(--cd-approval-chip-text);
  background: color-mix(in oklch, var(--cd-approval) 16%, transparent); }
/* Slice UI16 — the selection blue FOLLOWS SELECTION. It read the curation surface's row until selection moved to
   the rail; the pattern is unchanged and so are the alphas, only the surface expressing it is the one that now
   holds the state. Slice 49's universality claim is the reason this had to move rather than be dropped. */
.alive-card[data-picked="true"] { background: color-mix(in oklch, var(--cd-approval) 8%, transparent); }
.alive-card[data-picked="true"] .alive-card-pick { border-color: var(--cd-approval); color: var(--cd-approval-chip-text);
  background: color-mix(in oklch, var(--cd-approval) 18%, transparent); }
.step-head.open .step-n { background: var(--cd-approval); }
/* checked native toggles carry the same blue (accent-color) — the selection signal is consistent down to checkboxes. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--cd-approval); }

/* --- Task 3 — the STICKY operational panels. The git/vercel/download toggles + panels now live in #ops-rail inside
   the persistent workspace rail (relocated intact — same ids/handlers/walls), so they persist across idle AND run
   and are reachable to push/deploy mid-run. Layout only; the panels keep their own .git-panel styling. --- */
.ops-rail { display: flex; flex-direction: column; gap: var(--cd-space-5); margin-top: var(--cd-space-2); border-top: 1px solid var(--cd-line-1); padding-top: var(--cd-space-6); }
.ops-rail .git-bar { flex-wrap: wrap; row-gap: var(--cd-space-3); }
.ops-rail .git-panel { margin-top: 0; } /* the rail's flex gap handles spacing (was margin-top:12px in the deck) */

/* reduced-motion — the only motion here is the chevron rotate (decorative); the open/closed state is carried by
   layout (rows shown/hidden) + the chevron's static direction, so it stays legible with transition off. */
@media (prefers-reduced-motion: reduce) {
  .project-head-chev { transition: none; }
}
/* ==================================== end Slice J/49 live-run fixes ==================================== */

/* ============================================================================================================
   SLICE K/50 — the COMPLETED-RUN card. A successfully completed run lands here (the fall-through bug that rendered
   the DEATH card for a success is fixed in app.js). Scoped by id to #completed-card so the shared .card base + the
   died/abandoned/proposal/reauth cards are UNTOUCHED. In Slice-D's RESOLVED vocabulary: the crew RESTS — division-
   identified, STEADY, no motion (state is carried by the settled presence, not a celebration). Calm/honest, no
   success-green. Tokens only.
   ============================================================================================================ */
#completed-card { background: var(--cd-surface-sheet); border-color: var(--cd-line-2); }
#completed-card .card-kind { color: var(--cd-muted-2); font-family: var(--cd-font-mono, var(--mono));
  text-transform: uppercase; letter-spacing: 0.08em; font-size: var(--cd-type-meta); } /* steady/calm — NOT a green success shout */
#completed-summary { margin: 0; font-size: var(--cd-type-lead); color: var(--cd-muted-1); } /* the honest counts (stages · files) */
/* SLICE M20 — the build-verification status on the completion card. Four honest states, each visually distinct:
   verified/repaired = --cd-ok (green, an observed pass), failed = --cd-prod (red, an observed failure — the run
   still completed), skipped = --cd-wall (gold, an honest "not verified"). The real error renders in a bounded,
   scrollable pre so a long build error can't blow the card. --cd-* only; no motion. */
.completed-verify { margin: 0; font-size: var(--cd-type-body); font-family: var(--cd-font-mono, var(--mono)); color: var(--cd-muted-2); overflow-wrap: anywhere; }
.completed-verify[data-status="verified"], .completed-verify[data-status="repaired"] { color: var(--cd-ok); }
.completed-verify[data-status="failed"] { color: var(--cd-prod); }
.completed-verify[data-status="skipped"] { color: var(--cd-wall); }
.completed-verify-error { margin: 0; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-meta); color: var(--cd-muted-1);
  background: var(--cd-bg-void); border: 1px solid var(--cd-prod-cmd-border); border-radius: 8px; padding: var(--cd-space-4) var(--cd-space-5);
  white-space: pre-wrap; overflow-wrap: anywhere; max-height: 34vh; overflow: auto; }
.completed-verify-error[hidden] { display: none; }
/* end Slice M20 build-verify */

/* Slice M37 — the Vercel preview LINK on the completion card. Its own block (kicker line + wrapping URL) so it reads
   uncrowded at 390px; echoes the sidebar preview-panel's tokens. Hidden entirely when there is no real URL. */
.completed-deploy { display: flex; flex-direction: column; gap: 3px; margin: var(--cd-space-1) 0; }
.completed-deploy[hidden] { display: none; }
.completed-deploy-kicker { text-transform: uppercase; letter-spacing: 0.1em; font-size: var(--cd-type-kicker); color: var(--cd-approval-label); }
.completed-deploy-link { font-size: var(--cd-type-body); color: var(--cd-approval-chip-text); text-decoration: underline; word-break: break-all; overflow-wrap: anywhere; }
.completed-deploy-link:hover { color: var(--cd-text-hi); }
/* Slice M37 — the "tap to retry" affordance on a timed-out route/history (recoverable, one user-initiated retry). */
.retry-link { color: var(--cd-wall); }
/* Slice M36 — the agent-to-agent coherence warning block on the completion card. Destructive/attention red
   (--cd-prod, the same token M35's armed delete uses), its own block so it reads uncrowded at 390px. Hidden on a
   clean run. Honesty sub-line is muted (it qualifies the warning: intent, not a confirmed double-write). */
.completed-overwrites { display: flex; flex-direction: column; gap: var(--cd-space-1); margin: var(--cd-space-2) 0; padding: var(--cd-space-4) var(--cd-space-5);
  border: 1px solid var(--cd-prod); border-radius: 8px; background: var(--cd-prod-btn-bg, var(--cd-bg-void)); }
.completed-overwrites[hidden] { display: none; }
.completed-overwrites-head { margin: 0; font-size: var(--cd-type-body); font-weight: 600; color: var(--cd-prod); }
.completed-overwrites-sub { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-muted-2); }
.completed-overwrites-row { margin: 1px 0 0; font-size: var(--cd-type-meta); color: var(--cd-prod); overflow-wrap: anywhere; }

/* Slice M62 — SPEC-ADHERENCE notice on the completion card. A missing named file uses the wall/gate amber (a caught
   drift, not a hard failure — the run completed). A clean "all named files present" is muted-ok. --cd-* only. */
.completed-spec { display: flex; flex-direction: column; gap: var(--cd-space-1); margin: var(--cd-space-2) 0; padding: var(--cd-space-4) var(--cd-space-5);
  border: 1px solid var(--cd-wall); border-radius: 8px; background: var(--cd-bg-void); }
.completed-spec[hidden] { display: none; }
.completed-spec[data-state="present"] { border-color: color-mix(in oklch, var(--cd-ok) 55%, transparent); }
.completed-spec-head { margin: 0; font-size: var(--cd-type-body); font-weight: 600; color: var(--cd-wall); }
.completed-spec[data-state="present"] .completed-spec-head { color: var(--cd-ok); font-weight: 500; }
.completed-spec-row { margin: 1px 0 0; font-size: var(--cd-type-meta); color: var(--cd-wall); overflow-wrap: anywhere; }
.completed-spec-note { margin: var(--cd-space-1) 0 0; font-size: var(--cd-type-meta); color: var(--cd-muted-3); }
/* Slice M67 — SECOND RUNG: a "created, but looks like a placeholder" advisory. Amber (--cd-wall) even on a present
   (green-bordered) card, since a real file can still be a stub — the substance rung is a caught drift, not a failure.
   Own class so the [data-state="present"] green-head rule above never turns it green. --cd-* only. */
.completed-spec-stub-head { margin: var(--cd-space-2) 0 0; font-size: var(--cd-type-body); font-weight: 600; color: var(--cd-wall); }
/* Slice M70 — the Design plan block on the completed card: a read-only, scrollable panel showing the crew's proposal
   (what it WOULD build). Capped-height with overflow so a long plan never blows out the card. --cd-* only. */
.completed-plan { display: flex; flex-direction: column; gap: var(--cd-space-2); margin: var(--cd-space-3) 0; padding: var(--cd-space-5) var(--cd-space-6);
  border: 1px solid var(--cd-line-3); border-radius: 8px; background: var(--cd-bg-void); }
.completed-plan[hidden] { display: none; }
.completed-plan-head { margin: 0; font-size: var(--cd-type-body); font-weight: 600; color: var(--cd-text-2); }
.completed-plan-body { max-height: 320px; overflow-y: auto; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body);
  line-height: 1.5; color: var(--cd-text-2); white-space: pre-wrap; overflow-wrap: anywhere; }
/* Slice M71 — the "Implement this plan" button: turns the surfaced plan into a real Implement build. Accent-filled so
   it reads as a genuine action (leaving Design safety), not a passive link. --cd-* only. */
.completed-plan-foot { display: flex; flex-direction: column; gap: var(--cd-space-2); margin: var(--cd-space-4) 0 0; }
.implement-plan-btn { align-self: flex-start; font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); font-weight: 600;
  padding: 7px 14px; border-radius: 8px; border: 1px solid var(--cd-approval);
  background: color-mix(in oklch, var(--cd-approval) 18%, transparent); color: var(--cd-approval-chip-text); cursor: pointer; }
.implement-plan-btn:hover { background: color-mix(in oklch, var(--cd-approval) 28%, transparent); }
.implement-plan-btn:disabled { opacity: 0.6; cursor: default; }
.implement-plan-err { margin: var(--cd-space-1) 0 0; font-size: var(--cd-type-meta); color: var(--cd-wall); overflow-wrap: anywhere; }

/* the crew that ran — resting division-presences (steady diamonds; no pulse/turn — the run is resolved). */
.completed-crew { display: flex; flex-wrap: wrap; gap: 14px 12px; padding: var(--cd-space-1) 0; }
.completed-crew:empty { display: none; }
.completed-agent { display: flex; flex-direction: column; align-items: center; gap: 5px; min-width: 56px; max-width: 96px; opacity: 0.72; } /* settled — done work recedes (Slice-D "complete" reads calm) */
.completed-glyph { width: 26px; height: 26px; background: currentColor; color: var(--cd-muted-3);
  clip-path: polygon(50% 3%, 97% 50%, 50% 97%, 3% 50%); } /* the division diamond, steady (no animation) */
.completed-agent[data-div="engineering"] { color: var(--cd-div-engineering); }
.completed-agent[data-div="design"] { color: var(--cd-div-design); }
.completed-agent[data-div="security"] { color: var(--cd-div-security); }
.completed-agent[data-div="testing"] { color: var(--cd-div-testing); }
.completed-agent[data-div="specialized"] { color: var(--cd-div-specialized); }
.completed-agent[data-div="product"] { color: var(--cd-div-product); }
.completed-agent-name { font-size: var(--cd-type-micro); text-align: center; color: var(--cd-muted-2); max-width: 92px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.completed-agent-meta { font-size: var(--cd-type-micro); text-transform: uppercase; letter-spacing: 0.05em; color: var(--cd-muted-4); text-align: center; }

/* reduced-motion — the card carries NO animation (the crew is steady by design), so nothing to disable; it stays
   fully legible. (Rule present so the discipline is explicit + greppable.) */
@media (prefers-reduced-motion: reduce) {
  .completed-glyph { animation: none; }
}
/* ==================================== end Slice K/50 completed-run card ==================================== */

/* ============================================================================================================
   SLICE J.1/51 — the operational panels OPEN AS AN OVERLAY, not inline. Slice J made the git/vercel/download
   toggles persistent in the rail (kept). But an opened panel expanded INLINE in #ops-rail — growing the rail past
   the viewport, wedging a tall panel into a narrow column, and PUSHING THE PAGE into a scroll. Fix (position/scroll
   ONLY): an OPEN panel (:not([hidden])) becomes a fixed bottom-sheet overlay — OUT of the rail's flow, so the rail
   no longer grows and the page no longer scrolls; it scrolls WITHIN itself if tall. The toggle open/close
   (hidden=false/true), every button/action/wall/id, and the Slice-G look are untouched. Tokens only.
   ============================================================================================================ */
#git-panel:not([hidden]), #vercel-panel:not([hidden]), #download-panel:not([hidden]) {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: calc(var(--cd-z-panel) + 2); /* over the rail and the sheet it sits on */
  width: auto; max-width: 460px; margin: 0 auto; /* centered sheet (overrides .ops-rail .git-panel margin) */
  max-height: min(82vh, calc(100vh - var(--topbar-h) - 24px)); overflow-y: auto; overflow-x: hidden; /* scroll WITHIN, never the page */
  box-shadow: 0 24px 60px -18px color-mix(in oklch, var(--cd-bg-void) 82%, transparent); /* lifted off the workspace */
  animation: cd-rise 0.28s ease; /* a gentle rise (in-language with the reveal); OFF under reduced-motion below */
}
/* reduced-motion — no slide/rise; the panel simply appears (fixed), fully legible without motion. */
@media (prefers-reduced-motion: reduce) {
  #git-panel:not([hidden]), #vercel-panel:not([hidden]), #download-panel:not([hidden]) { animation: none; }
}
/* ==================================== end Slice J.1/51 panel overlay ==================================== */

/* ============================================================================================================
   SLICE L/52 — ADDITIVE agent selection is legible. Manual picks now AUGMENT auto (union) by default, so the
   operator's ADDED agents are marked with the selection-blue (Slice J — the same "active/chosen" signal), both in
   the forced-list preview and in the resolved (routed) union. Auto's picks stay neutral; the added manual picks
   read blue. Presentation for the marking only — the union/de-dupe/order/validation is the router's existing path.
   Tokens only.
   ============================================================================================================ */
#forced-list li.forced-added { color: var(--cd-approval-chip-text); } /* the operator's added picks — selection-blue */
#resolved li.resolved-added { color: var(--cd-approval-chip-text); } /* the same in the routed union preview */
/* ==================================== end Slice L/52 additive selection ==================================== */

/* ============================================================================================================
   SLICE J.2/53 — no overlay may obscure its OWN functionality (topbar-clearance audit). The fixed topbar (z-60)
   covers the top --topbar-h of the viewport; an overlay that starts at top:0 hides its own header/search/close
   BEHIND it. The full-screen overlays already offset by --topbar-h (settings/history/author/asset-modal); THREE
   did not clear it — fixed here (position/size only; no handler/id/wall change):
     1) #picker-overlay opened at inset:0 → the search bar + "done" sat UNDER the topbar (the reported bug). Offset
        below it; #picker-bar is a flex:0-0-auto header and #picker-list is the scroll region, so the search stays
        pinned/visible while the roster scrolls beneath it.
     2) #preview-overlay.fullscreen went top:0 → its bar (exit-fullscreen/close) sat under the topbar. Offset below.
     3) .card (proposal / blocked / production / completed / reauth / enroll / died / abandoned) grew UP from
        bottom:12 with NO bound → a tall card's header could reach under the topbar. Bounded to clear the topbar +
        scroll WITHIN itself (the J.1 discipline), so its kind/header stays visible.
   Tokens only (offsets are var(--topbar-h); no colours touched). reduced-motion unaffected (no animation added).
   ============================================================================================================ */
#picker-overlay { inset: var(--topbar-h) 0 0 0; } /* clear the topbar — the search bar + close are now visible */
#preview-overlay.fullscreen { top: var(--topbar-h); height: calc(100vh - var(--topbar-h)); } /* the bar clears the topbar */
.card { max-height: calc(100vh - var(--topbar-h) - 24px); overflow-y: auto; } /* a tall card scrolls within, never under the topbar */
/* ==================================== end Slice J.2/53 overlay clearance ==================================== */

/* ============================================================================================================
   SLICE N/56 — the FAST-MODE toggle (lives in the grant chip; only shown while a write-grant is live). OFF reads
   as the chip's quiet outline; ON carries the approval-blue "active" signal (Slice J selection-blue) so an armed
   fast mode is unmistakable. It's a reflection of the daemon state — the airtight inspectFastCommand allow-list is
   the real boundary; network/destructive/npm/anything-unrecognized still gate regardless. Tokens only.
   ============================================================================================================ */
#fast-toggle { color: var(--cd-muted-1); border-color: var(--cd-line-3); } /* OFF — quiet neutral in the chip */
#fast-toggle:hover { color: var(--cd-text); border-color: var(--cd-approval); }
#fast-toggle[data-on="true"] { color: var(--cd-approval-chip-text); border-color: var(--cd-approval);
  background: color-mix(in oklch, var(--cd-approval) 18%, transparent); } /* ON — the selection-blue active signal */
/* ==================================== end Slice N/56 fast-mode toggle ==================================== */

/* ============================================================================================================
   SLICE O/57 — the DETERMINISTIC command SUMMARY line on the proposal card. Sits ABOVE the raw command (which
   always stays shown). Colour is driven by the daemon's gravity classification (never softened): safe = a quiet
   neutral reading aid; danger = the established GOLD wall/caution gravity (⚠, so danger reads in plain terms);
   unknown ("review carefully") = muted, distinct — an unrecognized command is flagged, never fabricated. Tokens
   only; no animation (reduced-motion inherited).
   ============================================================================================================ */
.prop-summary { margin: 0; font-size: var(--cd-type-lead); line-height: 1.4; padding: var(--cd-space-3) var(--cd-space-5); border-radius: 8px;
  border: 1px solid var(--cd-line-2); background: var(--cd-surface-1); color: var(--cd-text-2); } /* safe — neutral aid */
.prop-summary[data-gravity="danger"] { color: var(--cd-wall); border-color: var(--cd-wall-btn-border);
  background: color-mix(in oklch, var(--cd-wall) 10%, transparent); font-weight: 600; } /* danger — the gold warning gravity */
.prop-summary[data-gravity="unknown"] { color: var(--cd-muted-2); border-style: dashed; } /* unrecognized — muted "review carefully" */
/* ==================================== end Slice O/57 command summary ==================================== */

/* ============================================================================================================
   SLICE P/58 (Tier 1) — the RESULT PREVIEW on the completion card: the screenshots the crew captured this run,
   shown WHEN THEY EXIST (else hidden — the text summary stands; honesty). A quiet strip of real result frames in
   the completion vocabulary — the run ends by showing what it built. Tokens only; no animation (reduced-motion
   inherited; the completed card is steady by design).
   ============================================================================================================ */
.completed-preview { display: flex; flex-wrap: wrap; gap: var(--cd-space-4); padding: var(--cd-space-1) 0; }
.completed-preview[hidden] { display: none; }
.completed-shot { margin: 0; flex: 1 1 220px; min-width: 0; max-width: 100%; display: flex; flex-direction: column; gap: var(--cd-space-2); }
.completed-shot-img { display: block; width: 100%; max-height: 46vh; object-fit: contain; border-radius: 10px;
  border: 1px solid var(--cd-line-2); background: var(--cd-bg-void); }
.completed-shot-cap { font-size: var(--cd-type-micro); color: var(--cd-muted-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Slice M47 — a SUSPECTED-BLANK capture (byte-size heuristic): KEPT and shown, marked suspect — caution weight
   (--cd-wall guardrail gold, a hedged "may have failed", NOT the destructive red of a wall block/death). Applies to
   the completion-card shot and the inline transcript shot. No hardcoded colors. The caption wraps so the hedge reads. */
.completed-shot[data-suspect] .completed-shot-img { border-color: var(--cd-wall); border-style: dashed; }
.completed-shot[data-suspect] .completed-shot-cap { color: var(--cd-wall); white-space: normal; overflow-wrap: anywhere; }
.turn.shot[data-suspect] .shot-img { border-color: var(--cd-wall); border-style: dashed; }
.turn.shot[data-suspect] figcaption { color: var(--cd-wall); }
/* ==================================== end Slice P/58 completion preview ==================================== */

/* ============================================================================================================
   SLICE M2 — the DemoForge HANDOFFS inbox + the staged-handoff marker, in the Command Deck language. The rail
   panel lists pending client handoffs (read-only, GET /api/queue over the operator session); picking a row
   STAGES the client identity (approval-blue selection, same language as .project-row[data-active]) and shows
   the marker in the compose deck. Presentation only — no run, no pull. Tokens only; both widths; reduced-motion
   carries state by colour + inset bar, not motion.
   ============================================================================================================ */
.queue-panel { display: flex; flex-direction: column; gap: var(--cd-space-3); }
.queue-head { display: flex; align-items: baseline; gap: var(--cd-space-4); }
.queue-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-kicker); color: var(--cd-muted-4); }
.queue-rows { display: flex; flex-direction: column; gap: var(--cd-space-2); }
.queue-empty { font-size: var(--cd-type-meta); color: var(--cd-muted-3); margin: 0; padding: var(--cd-space-1) var(--cd-space-1) 0; }

/* one handoff = one selectable row (name / url / meta), in the deck language; the picked one lit approval-blue. */
.queue-row { width: 100%; text-align: left; display: flex; flex-direction: column; gap: var(--cd-space-1);
  font-family: var(--cd-font-sans, var(--sans)); color: var(--cd-muted-1); background: var(--cd-bg-void);
  border: 1px solid var(--cd-line-2); border-radius: 9px; padding: var(--cd-space-4) var(--cd-space-5); cursor: pointer; overflow: hidden;
  transition: border-color .15s ease, color .15s ease, background .15s ease; }
.queue-row:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.queue-row[data-active] { color: var(--cd-approval-chip-text); border-color: var(--cd-approval);
  background: color-mix(in oklch, var(--cd-approval) 12%, transparent); box-shadow: inset 2px 0 0 var(--cd-approval); }
.queue-row-name { font-size: var(--cd-type-lead); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-row-url { font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-row-meta { font-size: var(--cd-type-kicker); color: var(--cd-muted-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* the STAGED marker in the compose deck — a quiet approval-blue banner naming the client the run will build for,
   with the M4 scrape pull/attach status below it. */
.queue-staged { display: flex; flex-direction: column; gap: var(--cd-space-3); padding: var(--cd-space-4) var(--cd-space-5); border-radius: 10px;
  border: 1px solid var(--cd-approval-chip-border); background: var(--cd-approval-chip-bg); }
/* Slice M56 — the boot-sweep recovery notice: orphaned run-branch work committed on restart. Attention tint (the
   operator should register that a kill happened + work was recovered), persistent + dismissible. --cd-* tokens only. */
.sweep-notice { display: flex; flex-direction: column; gap: var(--cd-space-3); padding: var(--cd-space-4) var(--cd-space-5); border-radius: 10px; margin-bottom: var(--cd-space-4);
  border: 1px solid var(--cd-prod-cmd-border); background: var(--cd-surface-1); }
.sweep-notice[hidden] { display: none; }
.sweep-notice-row { display: flex; align-items: center; gap: var(--cd-space-4); }
.sweep-notice-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-micro); color: var(--cd-prod-label); flex: 1 1 auto; }
.sweep-notice-row .ghost { color: var(--cd-muted-1); border: 1px solid var(--cd-line-2); border-radius: 6px; padding: var(--cd-space-1) var(--cd-space-4); font-size: var(--cd-type-meta); background: transparent; cursor: pointer; }
.sweep-notice-row .ghost:hover { color: var(--cd-text-body); border-color: var(--cd-line-3); }
.sweep-notice-body { display: flex; flex-direction: column; gap: 3px; }
.sweep-notice-head { margin: 0; font-size: var(--cd-type-meta); line-height: 1.5; color: var(--cd-text-body); }
.sweep-notice-item { margin: 0; font-size: var(--cd-type-meta); line-height: 1.5; color: var(--cd-prod-label); overflow-wrap: anywhere; }
.queue-staged-row { display: flex; align-items: center; gap: var(--cd-space-4); }
.queue-staged-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-micro); color: var(--cd-approval-label); }
.queue-staged-label { font-size: var(--cd-type-body); font-weight: 600; color: var(--cd-approval-chip-text); flex: 1 1 auto;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-staged #queue-staged-clear, .queue-staged .ghost { color: var(--cd-muted-1); border: 1px solid var(--cd-line-2);
  background: transparent; border-radius: 8px; font-size: var(--cd-type-meta); padding: 3px 9px; }
.queue-staged .ghost:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
/* the scrape status — muted while pulling, approval-blue when attached, wall-gold when it failed (honest, calm). */
.queue-staged-status { font-size: var(--cd-type-meta); color: var(--cd-muted-2); }
.queue-staged-status[data-state="pulling"] { color: var(--cd-muted-2); }
.queue-staged-status[data-state="attached"] { color: var(--cd-approval-chip-text); }
.queue-staged-status[data-state="error"] { color: var(--cd-wall); }

@media (prefers-reduced-motion: reduce) {
  .queue-row { transition: none; }
}
/* ==================================== end Slice M2 handoffs inbox ==================================== */

/* ============================================================================================================
   SLICE M6 — the "allow for this run" opt-in, in the Command Deck language. An honest up-front control at run
   kickoff: auto-approve the run's RECOVERABLE actions; irreversible ones still ask. Tokens only; both widths;
   reduced-motion (state is carried by the checkbox + text, no animation).
   ============================================================================================================ */
.allow-run { display: flex; align-items: flex-start; gap: 9px; padding: 9px 11px; margin: 0 0 var(--cd-space-2); border-radius: 11px;
  border: 1px solid var(--cd-line-2); background: var(--cd-bg-void); cursor: pointer; }
.allow-run:hover { border-color: var(--cd-line-3); }
.allow-run input[type="checkbox"] { margin-top: var(--cd-space-1); accent-color: var(--cd-approval); }
.allow-run-text { display: flex; flex-direction: column; gap: var(--cd-space-1); min-width: 0; }
.allow-run-title { font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-lead); font-weight: 600; color: var(--cd-text-2); }
.allow-run-note { font-size: var(--cd-type-kicker); color: var(--cd-muted-3); line-height: 1.35; }
/* when checked, the row lights in the approval-blue selection language (same as a picked handoff/directory). */
.allow-run:has(#allow-run:checked) { border-color: var(--cd-approval); background: color-mix(in oklch, var(--cd-approval) 10%, transparent); }
.allow-run:has(#allow-run:checked) .allow-run-title { color: var(--cd-approval-chip-text); }
/* ==================================== end Slice M6 allow-for-run ==================================== */

/* Slice M68 — RUN MODE: the segmented Implement/Design toggle on the run-start surface + the header Design chip.
   --cd-* only, matching the allow-run / seq-chip vocabulary. Design is a caught-intent label (approval accent),
   never an error color. The note wraps to its own row so the toggle stays clean at 360px. */
.run-mode { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cd-space-3); margin: 0 0 var(--cd-space-2); }
.run-mode-opt { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); padding: var(--cd-space-2) var(--cd-space-6); border-radius: 999px;
  border: 1px solid var(--cd-line-3); background: transparent; color: var(--cd-muted-3); cursor: pointer; }
.run-mode-opt:hover { border-color: var(--cd-approval); }
.run-mode-opt[aria-checked="true"] { border-color: var(--cd-approval); background: color-mix(in oklch, var(--cd-approval) 12%, transparent); color: var(--cd-approval-chip-text); font-weight: 600; }
.run-mode-note { flex-basis: 100%; font-size: var(--cd-type-kicker); color: var(--cd-muted-3); line-height: 1.35; }
.mode-chip { font-size: var(--cd-type-body); padding: var(--cd-space-2) var(--cd-space-5);
  border: 1px solid var(--cd-approval); color: var(--cd-approval-label); }
.mode-chip[hidden] { display: none; }
/* ==================================== end Slice M68 run-mode ==================================== */

/* Slice M72 — the per-run work-ceiling toggle (Default / 20 min / 30 min), matching the run-mode vocabulary. The
   label + note wrap to their own rows so the segmented options stay clean at 360px. --cd-* only. */
.run-ceiling { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cd-space-3); margin: 0 0 var(--cd-space-2); }
.run-ceiling-label { flex-basis: 100%; font-size: var(--cd-type-kicker); color: var(--cd-muted-3); text-transform: uppercase; letter-spacing: 0.06em; }
.run-ceiling-opt { font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-body); padding: var(--cd-space-2) var(--cd-space-6); border-radius: 999px;
  border: 1px solid var(--cd-line-3); background: transparent; color: var(--cd-muted-3); cursor: pointer; }
.run-ceiling-opt:hover { border-color: var(--cd-approval); }
.run-ceiling-opt[aria-checked="true"] { border-color: var(--cd-approval); background: color-mix(in oklch, var(--cd-approval) 12%, transparent); color: var(--cd-approval-chip-text); font-weight: 600; }
.run-ceiling-note { flex-basis: 100%; font-size: var(--cd-type-kicker); color: var(--cd-muted-3); line-height: 1.35; }
/* ==================================== end Slice M72 run-ceiling ==================================== */

/* Slice M73 — the "auto-approve safe Bash" toggle reuses .allow-run; when the run carries scraped/attached input it is
   not armable, so it is dimmed + non-interactive (the trusted-input guardrail, made visible). --cd-* only. */
#auto-bash-row.is-disabled { opacity: 0.5; }
#auto-bash-row.is-disabled input[type="checkbox"] { cursor: not-allowed; }
/* ==================================== end Slice M73 auto-safe-bash ==================================== */

/* ============================================================================================================
   SLICE M8 — the DEPLOY PREVIEW panel, in the Command Deck language. Populated at run completion ONLY when the
   run produced a real Vercel deploy URL (captured structurally). Sticky within the sticky workspace rail.
   Tokens only; both widths; reduced-motion honored (no animation — a static link).
   ============================================================================================================ */
.preview-panel { display: flex; flex-direction: column; gap: var(--cd-space-3); padding: 9px 11px; border-radius: 11px;
  border: 1px solid var(--cd-approval-chip-border); background: var(--cd-approval-chip-bg); }
.preview-head { display: flex; align-items: baseline; gap: var(--cd-space-4); }
.preview-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-kicker); color: var(--cd-approval-label); }
.preview-link { font-size: var(--cd-type-body); color: var(--cd-approval-chip-text); text-decoration: underline; word-break: break-all;
  overflow-wrap: anywhere; }
.preview-link:hover { color: var(--cd-text-hi); }
.preview-empty { font-size: var(--cd-type-meta); color: var(--cd-muted-3); margin: 0; }
/* Slice M30 — the SOURCE label. "deployed this run" reads as a live result (approval-label gravity); "current
   live URL · this run didn't deploy" is visually distinct (muted/gold) so a stale link never reads as this run's
   output. The two states must never look the same. */
.preview-label { font-size: var(--cd-type-kicker); letter-spacing: 0.06em; text-transform: uppercase; margin: 0; font-weight: 600; }
.preview-label[data-src="this-run"] { color: var(--cd-approval-label); }
.preview-label[data-src="existing"] { color: var(--cd-wall); }
/* ==================================== end Slice M8 deploy preview ==================================== */

/* ============================================================================================================
   SLICE M9 — the PROMPTS tab grouped into collapsible last-word categories. Mirrors the Slice-49 collapse
   pattern (data-open + a head button + a rotating chevron; CSS-only show/hide so items stay in the DOM and
   selection is never touched). Tokens only; both widths; reduced-motion disables the chevron transition.
   ============================================================================================================ */
.lib-cat { list-style: none; display: flex; flex-direction: column; gap: 3px; }
.lib-cat + .lib-cat { margin-top: var(--cd-space-3); }
.lib-cat-head { width: 100%; display: flex; align-items: center; gap: var(--cd-space-4); text-align: left; cursor: pointer;
  background: var(--cd-surface-1); border: 1px solid var(--cd-line-2); border-radius: 8px; padding: 6px 9px; }
.lib-cat-head:hover { border-color: var(--cd-line-3); }
.lib-cat-chev { flex: 0 0 auto; color: var(--cd-muted-3); font-size: var(--cd-type-kicker); transition: transform 0.15s ease; }
.lib-cat[data-open="true"] .lib-cat-chev { transform: rotate(180deg); }
.lib-cat-name { flex: 1 1 auto; font-family: var(--cd-font-sans, var(--sans)); font-size: var(--cd-type-body); font-weight: 600;
  color: var(--cd-text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lib-cat-count { flex: 0 0 auto; font-size: var(--cd-type-kicker); color: var(--cd-muted-3); }
.lib-cat-list { list-style: none; margin: 0; padding: var(--cd-space-1) 0 0 var(--cd-space-2); display: flex; flex-direction: column; gap: var(--cd-space-1); }
.lib-cat[data-open="false"] .lib-cat-list { display: none; } /* collapsed — items stay in the DOM, selection untouched */

@media (prefers-reduced-motion: reduce) {
  .lib-cat-chev { transition: none; }
}
/* ==================================== end Slice M9 prompt categories ==================================== */

/* ============================================================================================================
   SLICE M14 — directory legibility. Two-line rows (folder name primary + full path secondary) so same-prefix
   projects are distinguishable; a pinned READ-ONLY armed-directory bar at the top of the command deck (folder
   name, full path on hover, honest empty when unpicked). Tokens only; both widths; reduced-motion honored.
   ============================================================================================================ */
.project-row { align-items: flex-start !important; } /* the row now stacks two lines */
.project-row-name { display: block; font-size: var(--cd-type-body); font-weight: 600; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 100%; }
.project-row-path { display: block; font-size: var(--cd-type-kicker); color: var(--cd-muted-3); overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; max-width: 100%; }
.project-row[data-active] .project-row-path { color: var(--cd-approval-chip-text); opacity: 0.7; }

/* the pinned armed-directory bar — a quiet, read-only display of what the run is aimed at. */
.armed-dir { display: flex; align-items: baseline; gap: var(--cd-space-4); padding: var(--cd-space-3) var(--cd-space-5); margin: 0 0 var(--cd-space-4); border-radius: 9px;
  border: 1px solid var(--cd-line-2); background: var(--cd-bg-void); }
.armed-dir-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-micro); color: var(--cd-muted-4); flex: 0 0 auto; }
.armed-dir-name { font-size: var(--cd-type-body); color: var(--cd-muted-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* armed → the folder name lit in the approval-blue selection language (matches a picked row). */
.armed-dir[data-armed="true"] { border-color: var(--cd-approval-chip-border); background: var(--cd-approval-chip-bg); }
.armed-dir[data-armed="true"] .armed-dir-name { color: var(--cd-approval-chip-text); font-weight: 600; }
/* ==================================== end Slice M14 directory legibility ==================================== */

/* ==================================== Slice S3a — prompt CARD gallery ==================================== */
/* The prompts tab renders as cards grouped by S1 section (renderPromptGroups/buildPromptCard). --cd-* tokens only;
   responsive auto-fill grid; theme-aware via the tokens; reduced-motion honored. Selection state is is-selected. */
.prompt-sec { margin: 0 0 14px; }
.prompt-sec-head { display: flex; align-items: baseline; gap: var(--cd-space-4); margin: 0 0 var(--cd-space-4); padding: 0 var(--cd-space-1); font-size: var(--cd-type-lead); font-weight: 600; }
.prompt-sec-name { color: var(--cd-text-2); letter-spacing: 0.02em; }
.prompt-sec-count { color: var(--cd-muted); font-size: var(--cd-type-meta); }
.prompt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--cd-space-5); }
.prompt-card { display: flex; flex-direction: column; text-align: left; padding: 0; overflow: hidden; width: 100%;
  background: var(--cd-surface-1); border: 1px solid var(--cd-line); border-radius: 10px; cursor: pointer; color: inherit;
  transition: border-color 0.12s ease, background 0.12s ease; }
.prompt-card:hover { border-color: var(--cd-line-3); }
.prompt-card.is-selected { border-color: var(--cd-ok); background: var(--cd-surface-2); }
.prompt-card-media { position: relative; aspect-ratio: 16 / 10; background: var(--cd-bg-void); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.prompt-card-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.prompt-card-media.is-titleonly { padding: var(--cd-space-5); }
.prompt-card-titleonly { color: var(--cd-text-2); font-size: var(--cd-type-body); font-weight: 600; text-align: center; word-break: break-word; line-height: 1.3; }
.prompt-card-check { position: absolute; top: 6px; right: 6px; width: 20px; height: 20px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: var(--cd-type-meta); opacity: 0;
  background: var(--cd-ok); color: var(--cd-bg-void); transition: opacity 0.12s ease; }
.prompt-card.is-selected .prompt-card-check { opacity: 1; }
.prompt-card-body { padding: 7px 9px 9px; display: flex; flex-direction: column; gap: var(--cd-space-2); }
.prompt-card-title { color: var(--cd-text-hi); font-size: var(--cd-type-lead); font-weight: 600; word-break: break-word; line-height: 1.25; }
.prompt-card-meta { display: flex; align-items: center; justify-content: space-between; gap: var(--cd-space-4); }
.prompt-card-subtype { color: var(--cd-muted); font-size: var(--cd-type-meta); text-transform: capitalize; }
.prompt-card-slots { color: var(--cd-muted); font-size: var(--cd-type-meta); flex: 0 0 auto; }
@media (prefers-reduced-motion: reduce) { .prompt-card { transition: none; } .prompt-card-check { transition: none; } }
/* ==================================== end Slice S3a prompt card gallery ==================================== */
/* Slice S8 — per-card delete control (a role="button" span cluster; the card is a <button>, so no nested button) */
.prompt-card { position: relative; } /* anchor for the absolute delete control (S3a block left byte-unchanged) */
.prompt-card-del { position: absolute; top: 6px; left: 6px; z-index: 2; display: flex; align-items: center; gap: var(--cd-space-2); }
.pcd-btn { display: inline-flex; align-items: center; justify-content: center; min-width: 22px; height: 22px; padding: 0 5px;
  border-radius: 6px; font-size: var(--cd-type-meta); line-height: 1; cursor: pointer; background: var(--cd-surface-2);
  border: 1px solid var(--cd-line); color: var(--cd-muted); opacity: 0.5; transition: opacity 0.12s ease, color 0.12s ease, border-color 0.12s ease; }
.prompt-card:hover .pcd-btn, .prompt-card:focus-within .pcd-btn { opacity: 1; } /* subtle by default (still tappable on touch), full on hover/focus */
.pcd-btn:hover, .pcd-btn:focus-visible { color: var(--cd-text-hi); border-color: var(--cd-line-3); outline: none; }
.pcd-trash:hover, .pcd-trash:focus-visible { color: var(--cd-prod); border-color: var(--cd-prod); }
.pcd-yes { color: var(--cd-prod); border-color: var(--cd-prod); opacity: 1; } /* destructive confirm reads red */
.pcd-no { opacity: 1; }
.pcd-q { font-size: var(--cd-type-meta); color: var(--cd-text-2); background: var(--cd-surface-2); border: 1px solid var(--cd-line); border-radius: 6px; padding: var(--cd-space-1) var(--cd-space-3); }
.pcd-err { font-size: var(--cd-type-meta); color: var(--cd-prod); background: var(--cd-surface-2); border: 1px solid var(--cd-prod); border-radius: 6px; padding: var(--cd-space-1) var(--cd-space-3); }
@media (prefers-reduced-motion: reduce) { .pcd-btn { transition: none; } }
/* end Slice S8 per-card delete control */

/* Slice S16 — the "use demo for all" card modifier. Same form as the S8 trashcan (reuses .pcd-btn), placed BOTTOM-RIGHT
   of the media so it never collides with the trashcan (top-left) or the select-check (top-right). Rendered only on a
   selected card that has a demo-capable slot. Distinct from the (red) trashcan: it reads in the blue "use demo" language
   (--cd-approval, matching the slot stepper's demo-choice ON state), and goes fully opaque when demo-for-all is applied. */
.prompt-card-demo { position: absolute; bottom: 6px; right: 6px; z-index: 2; }
.pcd-demo:hover, .pcd-demo:focus-visible { color: var(--cd-approval-overlay); border-color: var(--cd-approval); }
.pcd-demo.is-on { opacity: 1; color: var(--cd-approval-chip-text); border-color: var(--cd-approval); background: var(--cd-approval-chip-bg); }
@media (prefers-reduced-motion: reduce) { .pcd-demo { transition: none; } }
/* Slice S24 — the copy-composed-prompt card control. Same form as the S8 trashcan (reuses .pcd-btn), placed BOTTOM-LEFT
   of the media — the free corner (trash top-left, select-check top-right, S16 demo bottom-right). Copies THIS prompt's
   composed text; the icon briefly flips to ✓ (copied) / ✕ (failed) as the affordance via [data-state]. */
.prompt-card-copy { position: absolute; bottom: 6px; left: 6px; z-index: 2; }
.pcd-copy:hover, .pcd-copy:focus-visible { color: var(--cd-approval-overlay); border-color: var(--cd-approval); }
.pcd-copy[data-state="copied"] { opacity: 1; color: var(--cd-approval-chip-text); border-color: var(--cd-approval); background: var(--cd-approval-chip-bg); }
.pcd-copy[data-state="failed"] { opacity: 1; color: var(--cd-prod); border-color: var(--cd-prod); }
@media (prefers-reduced-motion: reduce) { .pcd-copy { transition: none; } }
/* end Slice S16 use-demo-for-all card modifier */
/* Slice S12 — hover-play video preview: fills the media like .prompt-card-img; pointer-events:none so the card's
   select click is never swallowed (clicks bubble to the card <button>; hover handlers are on the card). */
/* Slice S22 — the transient hover <video> OVERLAYS the static poster <img> (absolute, inset 0), so tearing it down on
   leave simply reveals the poster again. pointer-events:none so the card's select click always bubbles through. */
.prompt-card-video { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; background: var(--cd-bg-void); }
/* end Slice S12 hover-play video preview */

/* ==================================== Slice S3b — guided section flow ==================================== */
/* Wraps the S3a card grid (.prompt-grid) in ordered steps: active (expanded), completed (summary), upcoming (dimmed).
   Presentation + navigation ONLY — selecting a card is the S3a behavior, unchanged. --cd-* tokens; reduced-motion honored. */
.flow-progress { color: var(--cd-muted); font-size: var(--cd-type-meta); margin: 0 var(--cd-space-1) var(--cd-space-5); letter-spacing: 0.02em; }
.flow-step { border: 1px solid var(--cd-line); border-radius: 9px; margin: 0 0 var(--cd-space-4); overflow: hidden; background: var(--cd-surface-1); }
.flow-step[data-state="active"] { border-color: var(--cd-line-strong); }
.flow-step[data-state="upcoming"] { opacity: 0.55; }
.flow-step-head { width: 100%; display: flex; align-items: center; gap: 9px; text-align: left; cursor: pointer;
  padding: 9px 11px; background: transparent; border: 0; color: inherit; transition: background 0.12s ease; }
.flow-step-head:hover { background: var(--cd-surface-2); }
.flow-step-idx { flex: 0 0 auto; width: 20px; height: 20px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: var(--cd-type-meta); background: var(--cd-surface-2); color: var(--cd-muted); border: 1px solid var(--cd-line); }
.flow-step[data-state="active"] .flow-step-idx { background: var(--cd-link); color: var(--cd-bg-void); border-color: var(--cd-link); }
.flow-step[data-state="completed"] .flow-step-idx { background: var(--cd-ok); color: var(--cd-bg-void); border-color: var(--cd-ok); }
.flow-step-name { flex: 1 1 auto; color: var(--cd-text-hi); font-size: var(--cd-type-lead); font-weight: 600; }
.flow-step-sum { flex: 0 0 auto; color: var(--cd-muted); font-size: var(--cd-type-meta); }
.flow-step-body { padding: 4px 11px 12px; }
.flow-step-acts { display: flex; gap: var(--cd-space-4); margin-top: var(--cd-space-5); }
.flow-skip, .flow-next, .flow-native-btn { font-size: var(--cd-type-body); padding: 5px 12px; border-radius: 6px; cursor: pointer;
  border: 1px solid var(--cd-line); background: var(--cd-surface-2); color: var(--cd-text-body); transition: border-color 0.12s ease; }
.flow-skip:hover, .flow-next:hover, .flow-native-btn:hover { border-color: var(--cd-line-3); }
.flow-next { margin-left: auto; color: var(--cd-text-hi); }
.flow-native { padding: var(--cd-space-2) 0 var(--cd-space-1); }
.flow-native-note { color: var(--cd-text-2); font-size: var(--cd-type-body); line-height: 1.4; margin: 0 0 var(--cd-space-5); }
.flow-native-acts { display: flex; gap: var(--cd-space-4); }
@media (prefers-reduced-motion: reduce) { .flow-step-head, .flow-skip, .flow-next, .flow-native-btn { transition: none; } }
/* ==================================== end Slice S3b guided section flow ==================================== */

/* ==================================== Slice S5 — manual section collapse ==================================== */
/* A chevron on each step header manually folds/unfolds that section (override over the flow default). The body is
   DOM-absent when collapsed (consistent with S3b); the chevron rotates to signal state. --cd-* only; reduced-motion. */
.flow-step-headrow { display: flex; align-items: stretch; }
.flow-step-headrow .flow-step-head { width: auto; flex: 1 1 auto; padding-left: var(--cd-space-2); }
.flow-step-chev { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; width: 30px;
  background: transparent; border: 0; border-right: 1px solid var(--cd-line); color: var(--cd-muted); cursor: pointer;
  font-size: var(--cd-type-meta); transition: transform 0.14s ease, color 0.12s ease; }
.flow-step-chev:hover { color: var(--cd-text-hi); }
.flow-step-chev[aria-expanded="false"] { transform: rotate(-90deg); } /* collapsed → chevron points right */
@media (prefers-reduced-motion: reduce) { .flow-step-chev { transition: color 0.12s ease; } }
/* ==================================== end Slice S5 manual section collapse ==================================== */
/* Slice AR6 — asset/ref rows render as CARDS (buildPromptCard's shape), so a reference is pickable by eye. The base
   .lib-thumb rule is deliberately LEFT ALONE at 28×28: it is shared with the studio/Agent-Runs ref strips, and the
   two-class selector below (0,2,0) outranks it only inside a card. That is why this slice needed no repoint of
   slice33's fixed-box assertion — the box is still fixed, just fixed to a ratio instead of 28px. */
.lib-cat-list:has(.lib-card) { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--cd-space-5); }
.lib-item.lib-card { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.lib-item.lib-card.attached { border-color: var(--cd-ok); }
.lib-card-media { position: relative; width: 100%; aspect-ratio: 16 / 10; background: var(--cd-bg-void); overflow: hidden; display: flex; align-items: center; justify-content: center; }
/* the fixed RATIO is what keeps layout-shift at zero as previews resolve — the measured property this slice preserves */
.lib-card-media .lib-thumb { width: 100%; height: 100%; border: 0; border-radius: 0; object-fit: cover; display: block; }
.lib-item.lib-card .lib-main { padding: var(--cd-space-3) var(--cd-space-4); }
.lib-item.lib-card .lib-name { font-size: var(--cd-type-meta); }
/* Slice AR7 — the liveness tick on a running stage. Muted on purpose: it is a reassurance, not an alert. */
/* Slice AR9 — the crew executing inside the build stage, and the gate reason when one stops. */

/* ============================================================================================================
   SLICE AL2 — THE ALIVE SPACE: the catalog grid + one alive panel. --cd-* tokens only (no hex), phone-first,
   reduced-motion honoured. The overlay uses the SAME hidden-toggle idiom as every other overlay and offsets
   below --topbar-h (4.10), so the topbar's home/run-chip stay reachable from inside it.
   Division colour comes from the SHIPPED --cd-div-* set. That set covers 6 of the catalog's 18 real divisions
   (142 of 262 agents); the other 12 fall back to the neutral line token rather than being given invented hues
   — a colour that means nothing is worse than no colour. Extending the set is a token decision, not AL2's.
   ============================================================================================================ */
#alive-overlay { position: fixed; inset: var(--topbar-h, 48px) 0 0 0; display: flex; flex-direction: column;
  background: var(--cd-bg-app); overflow: hidden; }
#alive-bar { display: flex; align-items: center; gap: var(--cd-space-5); padding: 10px 14px; border-bottom: 1px solid var(--cd-line-2);
  background: var(--cd-surface-sheet); flex: 0 0 auto; }
#alive-title { color: var(--cd-text-hi); font-weight: 600; }
.alive-count { color: var(--cd-muted-3); font-size: var(--cd-type-meta); }
#alive-close { margin-left: auto; }

/* ---- catalog ---- */
#alive-grid-view { flex: 1 1 auto; overflow-y: auto; padding: 12px 14px 28px; }
.alive-searchrow { margin: 0 0 var(--cd-space-5); }
.alive-search { width: 100%; background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); border-radius: 9px;
  color: var(--cd-text); padding: 9px 11px; font-size: var(--cd-type-lead); }
.alive-search:focus { outline: none; border-color: var(--cd-approval); }
.alive-divisions { display: flex; flex-wrap: wrap; gap: var(--cd-space-3); margin: 0 0 var(--cd-space-6); }
.alive-div-chip { background: var(--cd-surface-1); border: 1px solid var(--cd-line-2); color: var(--cd-muted-1);
  padding: var(--cd-space-2) var(--cd-space-5); font-size: var(--cd-type-meta); cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease; }
.alive-div-chip:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.alive-div-chip.is-on { color: var(--cd-text-hi); border-color: var(--cd-approval); background: var(--cd-approval-chip-bg); }
.alive-empty { color: var(--cd-muted-3); font-size: var(--cd-type-body); padding: 18px 2px; }
.alive-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--cd-space-5); }
.alive-card { display: flex; flex-direction: column; gap: var(--cd-space-3); text-align: left; padding: 11px 12px; width: 100%;
  background: var(--cd-surface-1); border: 1px solid var(--cd-line-2); border-left-width: 3px; border-radius: 10px;
  color: inherit; cursor: pointer; transition: border-color 0.12s ease, background 0.12s ease; }
.alive-card:hover { border-color: var(--cd-line-3); background: var(--cd-surface-2); }
.alive-card:focus-visible { outline: none; border-color: var(--cd-approval); }
.alive-card-head { display: flex; align-items: baseline; gap: var(--cd-space-4); }
.alive-card-name { color: var(--cd-text-hi); font-size: var(--cd-type-lead); font-weight: 600; line-height: 1.25; word-break: break-word; }
.alive-card-div { margin-left: auto; color: var(--cd-muted-4); letter-spacing: 0.08em; flex: 0 0 auto; }
.alive-card-desc { color: var(--cd-muted-2); font-size: var(--cd-type-meta); line-height: 1.4; margin: 0;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.alive-card-foot { display: flex; align-items: center; gap: var(--cd-space-4); font-size: var(--cd-type-kicker); color: var(--cd-muted-4); }
.alive-card-tier { margin-left: auto; }
/* the six divisions the shipped token set names; every other division keeps the neutral left edge above */
.alive-card[data-div="engineering"] { border-left-color: var(--cd-div-engineering); }
.alive-card[data-div="design"] { border-left-color: var(--cd-div-design); }
.alive-card[data-div="security"] { border-left-color: var(--cd-div-security); }
.alive-card[data-div="testing"] { border-left-color: var(--cd-div-testing); }
.alive-card[data-div="specialized"] { border-left-color: var(--cd-div-specialized); }
.alive-card[data-div="product"] { border-left-color: var(--cd-div-product); }

/* ---- the alive panel ---- */
#alive-panel-view { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; padding: 12px 14px 14px; }
/* Slice UI3 §4 — the head is IDENTITY + STATE, not three peers in one unbreakable row. At 320px the old single
   row could not fit name + division + state, so the agent name wrapped mid-word and the state label wrapped with
   it — the panel announced itself worse the narrower the screen got. The identity group holds together and the
   state is free to drop to its own line, which is the one thing in the head that can be read on a second line. */
.alive-panel-head { display: flex; align-items: baseline; gap: var(--cd-space-4); flex: 0 0 auto; flex-wrap: wrap; }
.alive-panel-id { display: flex; align-items: baseline; gap: var(--cd-space-4); min-width: 0; flex: 1 1 auto; }
.alive-panel-id .alive-panel-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Slice UI2 — mapped by ROLE, not by rounding. Its old size rounded to the display step, but a panel head is a
   title: at 320px the display step pushed the agent name onto a second line and shoved the state label with it. */
.alive-panel-name { color: var(--cd-text-hi); font-size: var(--cd-type-title); font-weight: 600; }
.alive-panel-div { color: var(--cd-muted-4); letter-spacing: 0.08em; }
.alive-panel-state { margin-left: auto; font-size: var(--cd-type-meta); color: var(--cd-muted-2); }
.alive-panel-desc { color: var(--cd-muted-2); font-size: var(--cd-type-meta); line-height: 1.4; margin: var(--cd-space-3) 0 var(--cd-space-5); flex: 0 0 auto; }
.alive-out { flex: 1 1 auto; min-height: 0; overflow-y: auto; background: var(--cd-bg-void);
  border: 1px solid var(--cd-line-2); border-radius: 10px; padding: var(--cd-space-5) var(--cd-space-6); display: flex; flex-direction: column; gap: var(--cd-space-5); }
.alive-turn { display: flex; flex-direction: column; gap: 3px; }
.alive-turn-who { font-size: var(--cd-type-kicker); text-transform: uppercase; letter-spacing: 0.08em; color: var(--cd-muted-4); }
.alive-turn-body { font-size: var(--cd-type-body); line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.alive-you .alive-turn-who { color: var(--cd-tag-you); }
.alive-you .alive-turn-body { color: var(--cd-text); }
.alive-agent .alive-turn-body { color: var(--cd-text-body); font-family: var(--cd-font-mono, var(--mono)); }
.alive-composer { flex: 0 0 auto; margin-top: var(--cd-space-5); display: flex; flex-direction: column; gap: var(--cd-space-4); }
.alive-prompt { width: 100%; background: var(--cd-bg-void); border: 1px solid var(--cd-line-2); border-radius: 9px;
  color: var(--cd-text); padding: 9px 11px; font-size: var(--cd-type-lead); resize: vertical; }
.alive-prompt:focus { outline: none; border-color: var(--cd-approval); }
.alive-composer-actions { display: flex; align-items: center; gap: var(--cd-space-4); }
#alive-end { margin-left: auto; }

/* ---- the crew-run refusal, on the compose screen ---- */
.alive-blocked { margin-top: var(--cd-space-4); padding: var(--cd-space-5) var(--cd-space-6); border: 1px solid var(--cd-approval);
  border-left-width: 3px; border-radius: 9px; background: var(--cd-approval-chip-bg); }
.alive-blocked-msg { display: block; color: var(--cd-approval-chip-text); font-size: var(--cd-type-body); line-height: 1.45; }
.alive-blocked-acts { display: flex; gap: var(--cd-space-4); margin-top: var(--cd-space-4); }

@media (min-width: 900px) {
  /* the bar shares the body's measure, or the title floats at the window edge while the grid sits centred */
  #alive-bar { padding-left: max(14px, calc((100% - 1120px) / 2)); padding-right: max(14px, calc((100% - 1120px) / 2)); }
  #alive-grid-view, #alive-panel-view { max-width: 1120px; width: 100%; margin: 0 auto; }
  .alive-grid { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
}
@media (prefers-reduced-motion: reduce) {
  .alive-card, .alive-div-chip { transition: none; }
}
/* ==================================== end Slice AL2 alive space ==================================== */

/* ============================================================================================================
   SLICE UI1 — THE TAB SHELL. Sits ABOVE showView, below the topbar. --cd-* tokens only.
   It owns its OWN height token (--tabbar-h) rather than growing --topbar-h: that variable is a layout API used
   23 times (every overlay offsets below it), so changing it would move 23 rules to buy nothing. Only body's
   padding-top learns about the second strip, and nothing pins that rule.
   ============================================================================================================ */
:root { --tabbar-h: 44px; }
body { padding-top: calc(var(--topbar-h, 48px) + var(--tabbar-h, 44px)); } /* topbar + tab strip, both fixed */

.tabbar { position: fixed; top: var(--topbar-h, 48px); left: 0; right: 0; height: var(--tabbar-h, 44px);
  z-index: var(--cd-z-nav); display: flex; align-items: center; gap: var(--cd-space-5); padding: 0 14px;
  background: var(--cd-bg-app); border-bottom: 1px solid var(--cd-line-2); box-sizing: border-box; }
.tabbar-tabs { display: flex; align-items: center; gap: var(--cd-space-2); }
.tab-btn { position: relative; display: inline-flex; align-items: center; gap: var(--cd-space-3); cursor: pointer;
  background: transparent; border: 1px solid transparent; border-radius: 9px; padding: 5px 12px;
  color: var(--cd-muted-2); font-size: var(--cd-type-body); font-weight: 600;
  white-space: nowrap; flex: 0 0 auto;   /* at 390 the labels wrapped to two lines inside a fixed-height bar */
  transition: color 0.12s ease, background 0.12s ease, border-color 0.12s ease; }
.tab-btn:hover { color: var(--cd-text); }
.tab-btn.is-on { color: var(--cd-text-hi); background: var(--cd-surface-1); border-color: var(--cd-line-2); }
.tab-btn:focus-visible { outline: none; border-color: var(--cd-approval); }
/* the other surface holds the slot: legible BEFORE the tap, not as a refusal after */
.tab-btn[data-blocked="true"] .tab-btn-label { opacity: 0.62; }
.tab-badge { display: inline-flex; align-items: center; border-radius: 999px; padding: 1px 7px;
  font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-micro); letter-spacing: 0.04em;
  background: var(--cd-approval-chip-bg); color: var(--cd-approval-chip-text);
  border: 1px solid var(--cd-approval-chip-border); }
/* min-width:0 + ellipsis: at 320 this ran off the right edge and was hard-clipped mid-word. Degrading to
   "slot held · cr…" is honest; a sentence sliced by the viewport is not. */
.run-slot { margin-left: auto; font-size: var(--cd-type-meta); color: var(--cd-muted-3); white-space: nowrap;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.run-slot[data-slot="alive"], .run-slot[data-slot="crew"] { color: var(--cd-approval-chip-text); }
.run-slot::before { content: ""; display: inline-block; width: 6px; height: 6px; border-radius: 50%;
  margin-right: var(--cd-space-3); vertical-align: middle; background: var(--cd-line-3); }
.run-slot[data-slot="alive"]::before, .run-slot[data-slot="crew"]::before { background: var(--cd-approval); }

/* the two mounted surfaces. Both occupy the grid's center column at >=900; only one is ever shown. The rail
   stays a DOM SIBLING of both — which is why slice44 #9, slice49 #3 and slice51 #2 stay literally true: their
   claim is persistence across showView (idle <-> run), an axis this shell does not touch.
   Slice AL3c — the rail is no longer hidden on Alive Space (its capabilities have to be reachable from the
   surface the operator actually works on), so both tracks are occupied on both tabs. Scoping moved to the
   section: only .rail-crew-only sections hide there. */
.tab-surface { min-width: 0; }
#alive-overlay { position: static; inset: auto; z-index: auto; height: 100%; }

@media (min-width: 900px) {
  #tab-alive, #tab-crew { grid-area: center; min-width: 0; }
}
/* ── Slice AL3c — WHAT IS LIVE COMES FIRST, ON THE STACKED LAYOUT TOO ──────────────────────────────
   Below the breakpoint #app stacks in DOM order, which put the whole rail above the canvas: Alive Space
   opened on the working-directory selector with the live sessions a full viewport down. Moving the canvas
   above the catalog fixed the wrong half of that scroll. The rail is REORDERED, not moved and not hidden —
   the DOM is untouched (it stays a sibling of both tab surfaces) and every rail capability is still one
   short scroll away, below the sessions that are actually talking to you. Alive only; Crew is untouched. */
@media (max-width: 899px) {
  #app:has(#tab-alive:not([hidden])) { display: flex; flex-direction: column; }
  #app:has(#tab-alive:not([hidden])) > #workspace-rail { order: 2; }
  /* Slice UI10 — the Flows surface takes the same treatment, and for the same reason rather than for symmetry:
     the composer IS the tab, and in DOM order it began a full viewport down with its controls off-screen. Hit
     testing at these widths is what showed that — the surface rendered correctly the whole time. Added INSIDE
     this block rather than as another one: the breakpoints in this sheet are counted, and a new block would
     have moved that count without adding a width. The two lines above are untouched; Crew keeps DOM order. */
  #app:has(#tab-flows:not([hidden])) { display: flex; flex-direction: column; }
  #app:has(#tab-flows:not([hidden])) > #workspace-rail { order: 2; }
}
/* phone: buy the slot indicator its room back from the bar's own padding rather than from the labels */
@media (max-width: 420px) {
  .tabbar { padding: 0 var(--cd-space-4); gap: var(--cd-space-3); }
  .tab-btn { padding: 5px 9px; font-size: var(--cd-type-body); }
  .tab-badge { font-size: var(--cd-type-micro); padding: 1px 5px; }
}
@media (prefers-reduced-motion: reduce) { .tab-btn { transition: none; } }
/* ==================================== end Slice UI1 tab shell ==================================== */

/* ============================================================================================================
   SLICE AL3b — THE CANVAS: N live sessions, one card each, beside the catalog rather than replacing it.
   --cd-* tokens only, phone-first (one column below 900), reduced-motion honoured.
   ============================================================================================================ */
.alive-ceiling { margin: 0 0 var(--cd-space-4); font-size: var(--cd-type-meta); color: var(--cd-muted-3); }
.alive-ceiling[data-full="true"] { color: var(--cd-wall); }
/* Slice AL16 — the Alive surface's status line. STICKY inside the pane that scrolls, so a refusal stays on
   screen however far down the operator had scrolled to reach the row they tapped. It names no stacking level
   and needs none: the rows are static, and a positioned element paints above static siblings whatever the DOM
   order — so there is no number here to drift out of step with the ladder. It carries the WALL role, because
   every message it shows is something that did not happen; a refusal that reads like ordinary chrome is a
   refusal the operator scrolls past. The background is the pane's own, so the rows scrolling under it do not
   read through the text. */
.alive-status { position: sticky; top: 0; margin: 0 0 var(--cd-space-4); padding: var(--cd-space-4) var(--cd-space-5);
  font-size: var(--cd-type-meta); color: var(--cd-wall); background: var(--cd-bg-app);
  border: 1px solid var(--cd-wall); border-radius: 8px; }
/* No [hidden] rule here on purpose: the sheet already carries a global `[hidden] { display: none !important }`,
   so a local one could not change the outcome and would be a rule that never decides anything — which is exactly
   what CLEAN2 spent a slice counting. The check asserts the resolved value, so it is testing that global rule. */
/* Slice AL7 — ROUTING NEEDS BOTH ENDS VISIBLE. The canvas ran one column until the desktop breakpoint, so at
   tablet widths a hand-off had one panel on screen and the other a viewport below — and the operator is the
   medium here, so a medium that can only see one end is guessing. Measured at 768 the single column made panels
   660px wide, twice what a transcript needs, and two would not fit only because the track floor was set higher
   than the panels require. A floor the panels actually need needs no breakpoint of its own: it yields one column
   wherever two will not fit, which is the phone, and two as soon as they will.
   THE CLAMP IS LOAD-BEARING. Without it the floor exceeds a 320px canvas and the panel overflows it by 27px —
   the panel, not the page, so nothing scrolls sideways and it reads as a crop rather than as a fault. */
.alive-canvas { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); gap: var(--cd-space-6); padding: 0 14px 20px; }
/* A HELD CELL — the session is over, the space is not yet reclaimed. Receded, so it never competes with a live
   panel for attention, and visibly finished rather than idle. */
.alive-panel[data-ended="true"] { opacity: 0.62; border-style: dashed; }
.alive-ended-foot { display: flex; align-items: baseline; gap: var(--cd-space-4); flex-wrap: wrap; }
.alive-ended-msg { flex: 1 1 auto; min-width: 0; font-size: var(--cd-type-meta); color: var(--cd-muted-2); margin: 0; }
.alive-dismiss-btn { flex: 0 0 auto; }
.alive-canvas:empty { display: none; }
.alive-panel { display: flex; flex-direction: column; min-height: 0; gap: var(--cd-space-4); padding: 11px 12px;
  background: var(--cd-surface-1); border: 1px solid var(--cd-line-2); border-left-width: 3px;
  border-radius: 10px; }
.alive-panel[data-div="engineering"] { border-left-color: var(--cd-div-engineering); }
.alive-panel[data-div="design"] { border-left-color: var(--cd-div-design); }
.alive-panel[data-div="security"] { border-left-color: var(--cd-div-security); }
.alive-panel[data-div="testing"] { border-left-color: var(--cd-div-testing); }
.alive-panel[data-div="specialized"] { border-left-color: var(--cd-div-specialized); }
.alive-panel[data-div="product"] { border-left-color: var(--cd-div-product); }
.alive-panel .alive-out { max-height: 260px; min-height: 90px; }
.alive-panel .alive-prompt { rows: 2; }
.alive-end-btn { margin-left: auto; }
/* a catalog card at the ceiling says so in place, before the tap */
.alive-card[data-blocked="true"] { opacity: 0.55; }
.alive-card[data-blocked="true"] .alive-card-name { text-decoration: none; }

@media (min-width: 900px) {
  .alive-canvas { grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); max-width: 1120px; margin: 0 auto; width: 100%; }
  /* Slice AL10 — comfortable's desktop floor, joining this block rather than opening another. Clamped like the
     narrow one: a floor is a width a panel needs, never a width its container has to find. */
  .alive-canvas[data-density="comfortable"] { grid-template-columns: repeat(auto-fill, minmax(min(380px, 100%), 1fr)); }
}
/* Slice AL8 joins this query rather than opening another, and opts each animation out INDIVIDUALLY rather than
   with one blanket duration override. A blanket override does not stop a loop, it only makes it fast — the frames
   keep being painted — and it flattens a distinction that matters here: an entrance reduced to nothing should
   simply not happen, but a looping indicator reduced to nothing must still SAY what it was saying. So the caret
   settles opaque instead of vanishing, the sweep band settles visible at the head of its bar, and the two dots
   stay their state's colour. Motion goes; meaning does not. */
@media (prefers-reduced-motion: reduce) {
  .alive-panel { transition: none; animation: none; }
  .alive-panel[data-handoff], .alive-panel[data-dragging="true"] { transition: none; transform: none; }
  .alive-turn.alive-you { animation: none; }
  .alive-toast { animation: none; }
  .alive-turn-body[data-streaming="true"]::after { animation: none; opacity: 1; }
  .alive-panel[data-astate="working"] .alive-state-dot,
  .alive-panel[data-astate="needs-you"] .alive-state-dot { animation: none; }
  .alive-panel[data-astate="working"] .alive-statusbar-sweep { animation: none; transform: none; }
  /* Slice AL9 joins the same query. The dashes stop travelling and the route stays drawn; the count's dot stops
     pulsing and stays gold. Neither says less standing still than it did moving. */
  .alive-link { animation: none; }
  .alive-needs-chip .alive-state-dot { animation: none; }
  /* Slice AL11 joins the same query. The drop answer appears without arriving and the ghost stops tilting; both
     still say exactly what they said, which is what the setting asks for and all it asks for. */
  .alive-drop-overlay { animation: none; }
  .alive-drop-word { animation: none; }
  .alive-drag-ghost { transform: none; }
  /* Slice AI6 joins the same query rather than opening one of its own. The number of reduced-motion queries in
     this sheet is a document-wide figure: 38 verifies name the query and 17 pin the COUNT — measured, by opening
     one and reading the board, which turned 17 slices red at once. A new query is a change to all of them. The
     caret still turns to say open; it simply stops animating the turn. */
  .seq-deliv > summary::before { transition: none; }
}
/* ============================== Slice AL4 — the hand-off ==============================
   Additive: every rule here is scoped to the hand-off's own class or to a data-attribute that only exists while a
   hand-off is in flight, so a panel at rest renders exactly as it did before this slice. */
.handoff-chip { display: none; align-self: flex-start; }
/* The composer action row was built for two buttons and does not wrap. This slice puts up to four in it, which
   overflowed the panel by 125px at 320 and 59px at 390 — the tap path, which is the REQUIRED path, was the part
   that fell off the edge. Declared here rather than by editing the original rule, so the row is unchanged
   wherever two buttons still fit and only wraps when it must. */
.alive-composer-actions { flex-wrap: wrap; row-gap: var(--cd-space-3); }
.alive-handoff-btn, .alive-receive-btn { flex: 0 0 auto; }
/* DRAGGING — the transcript collapses to the chip so what is being moved reads as one object, and the panel
   lifts off the canvas rather than merely tinting. */
/* align-self is load-bearing, not polish: the panel is a grid item stretched by its tallest sibling, so hiding
   the transcript alone left a full-height empty box with a chip in the corner — the opposite of collapsing. */
.alive-panel[data-dragging="true"] { opacity: 0.92; transform: scale(0.97); box-shadow: 0 10px 26px rgba(var(--cd-shadow-rgb), 0.45);
  align-self: start; min-height: 0; }
.alive-panel[data-dragging="true"] .alive-out,
.alive-panel[data-dragging="true"] .alive-composer { display: none; }
.alive-panel[data-dragging="true"] .handoff-chip { display: inline-flex; }
/* VALID / INVALID targets, both announced on approach rather than after the drop. */
.alive-panel[data-handoff="valid"] { border-color: var(--cd-approval); box-shadow: 0 0 0 2px var(--cd-approval) inset; }
.alive-panel[data-handoff="busy"], .alive-panel[data-handoff="self"] { opacity: 0.55; }
.alive-panel[data-handoff="self"] { border-style: dashed; }
.alive-panel[data-handoff] { transition: border-color 100ms ease, box-shadow 100ms ease, transform 100ms ease, opacity 100ms ease; }
/* The reduced-motion opt-out for these two states is folded into the canvas's EXISTING query below rather than
   declared as a new one: a verify counts the reduced-motion queries in this stylesheet, and a slice that adds
   motion should join the existing opt-out rather than grow that count. */
/* ==================================== end Slice AL3b canvas ==================================== */

/* ============================================================================================================
   SLICE AL3c — the rail is GLOBAL chrome; only the sections that must not cross are hidden per tab, by class.
   Separate from [hidden] on purpose: those sections own their own show/hide (sweep-notice ships hidden), so the
   tab shell must not fight them for the attribute.
   ============================================================================================================ */
/* Slice CLEAN2 — the hiding class this rule styled went with the loop that applied it. AL3c had already retired
   the class that loop queried, so it toggled this onto nothing; UI15 replaced the behaviour with containment. */
/* the canvas leads the Alive tab (AL3c); it collapses to nothing when no session is live, so an empty canvas
   never pushes the catalog down. */
.alive-canvas:empty { display: none; }
/* ==================================== end Slice AL3c rail scope ==================================== */
.alive-bindrow { display: flex; align-items: center; gap: var(--cd-space-4); margin: 0 0 var(--cd-space-5); }
.alive-bind-label { font-size: var(--cd-type-kicker); text-transform: uppercase; letter-spacing: 0.08em; color: var(--cd-muted-4); flex: 0 0 auto; }
.alive-bind { flex: 1 1 auto; min-width: 0; background: var(--cd-bg-void); border: 1px solid var(--cd-line-2);
  border-radius: 8px; color: var(--cd-text); padding: 5px 8px; font-size: var(--cd-type-meta); }
.alive-bind:focus { outline: none; border-color: var(--cd-approval); }

/* ============================== Slice UI9 — clearing the tab strip ==============================
   THE DEFECT. UI1 added a second fixed bar under the header and gave it its own height token, but the surfaces
   that float over the app still start where the header ends. The strip stacks above almost all of them, so it
   paints over their first rows — which is exactly where these surfaces keep their close, cancel and search
   controls. Measured by hit-testing the centre of each surface's topmost control: ten of them returned the strip
   rather than the control, at every width. Two more had a control whose top edge was under the strip and whose
   centre happened to fall below it, and one escaped only by tying the strip's stacking level and being later in
   the document — none of those three were safe, they were lucky.

   WHY THIS IS A SEPARATE DECLARATION RATHER THAN AN EDIT. Each surface's own positioning is asserted, by id and
   by exact text, across eight checks in five verifies — a deliberate choice recorded when the overlay registry
   was built, which kept positioning per-alias so surfaces could not be moved as a group by accident. Editing
   those values would break every one of those assertions and require repointing checks that belong to other
   slices. Setting only the top offset here leaves each of those declarations untouched and still true: the
   shorthand they pin still says what it said, and this overrides one component of it by cascade order. No check
   was repointed to land this.

   The offset is COMPOSED FROM BOTH TOKENS and redefines neither: they stay layout APIs owned by the bars
   themselves, so a bar that changes height moves these surfaces with it instead of stranding them. */
/* Slice AUTH3 — the library joins this list. It was the sheet's only overlay starting at viewport top, so it
   covered the brand and the strip at every width; correcting its LEVEL alone would have left it doing that,
   because out-ranking is one of two ways to cover and starting above is the other. Clearing the topbar is not
   clearing navigation either — navigation is two bars, and this is the offset that composes both. */
#settings-overlay, #author-overlay, #agent-config-overlay, #vendor-overlay,
#asset-modal-overlay, #studio-modal-overlay, #naming-modal-overlay, #library-modal-overlay,
#history-overlay, #history-detail-overlay, #plan-overlay, #sequence-overlay,
#picker-overlay, #preview-overlay.fullscreen {
  top: calc(var(--topbar-h) + var(--tabbar-h));
}

/* ============================== Slice UI10 — Flows as a surface, not a sheet ==============================
   The composer stops floating over the app and becomes the content of a tab. Its own element, ids and internal
   view state are untouched; only the layer it lives on changes. Declared last so it wins over the positioning
   the surface carried while it was a sheet, without editing that declaration — the same reason the offsets in
   the block above are set from here rather than in place.

   This is why it also leaves the offset list above: a surface that no longer floats cannot be painted over by
   the strip, and the enumeration that watches for that derives what floats from this stylesheet on every run. */
#tab-flows { min-height: 0; }

/* ============================== Slice AL8 — the aliveness layer ==============================
   PRESENTATION ONLY. Every rule below is driven by an attribute the panel already knew how to be in: the state
   the head has printed as a word since this surface existed. Nothing new is tracked, nothing is asked of the
   daemon, and a panel whose state never changes renders exactly the sequence of words it did before.

   WHY A STATE DRIVES FIVE SURFACES AND NOT ONE. The word alone was the whole signal, in the same muted grey in
   every state, in a head that also carries the agent's name and division — so a panel that needed the operator
   looked exactly like a panel that was busy, and both looked like one that had failed. Colour on the word alone
   would have been legible only to whoever was already reading it. So the bar, the dot, the chip, the border and
   the lift all move together: at a glance across a canvas of panels the state is the shape of the panel, and up
   close it is still the word.

   COLOUR COMES FROM THE TOKEN LAYER. No value here is written as a colour; the roles this needed and the layer
   lacked were added there, by role, and are noted where they are declared.

   MOTION IS PAIRED. Every animation this slice introduces has its opt-out, and they are folded into the canvas's
   existing reduced-motion query rather than declared as a new one — the same reason the hand-off's was. */

/* The bar. A full-width rule across the top of the panel, the state's colour, with a lighter band sweeping it
   while there is work happening. The band is a child so the bar keeps its colour underneath it. */
.alive-statusbar { flex: 0 0 auto; position: relative; overflow: hidden; height: 2px; border-radius: 2px;
  margin: 0 0 var(--cd-space-3); background: var(--cd-line-2); }
.alive-statusbar-sweep { position: absolute; inset: 0 auto 0 0; width: 30%; border-radius: 2px;
  background: var(--cd-text-hi); opacity: 0; }
/* The dot, inside the chip rather than beside it, so the two can never disagree about what state this is. */
.alive-state-dot { width: 6px; height: 6px; border-radius: 50%; flex: 0 0 auto; background: var(--cd-muted-3); }
/* The word becomes a chip. Its layout is state-independent — only its fill, text and border move — so a longer
   state word never re-lays the head out. */
.alive-panel-state { display: inline-flex; align-items: center; gap: var(--cd-space-3); flex: 0 0 auto;
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--cd-line-2);
  background: var(--cd-surface-2); color: var(--cd-muted-2); }

/* WORKING — the agent has the turn. */
.alive-panel[data-astate="working"] { border-color: var(--cd-approval-chip-border); box-shadow: 0 6px 18px -12px var(--cd-shadow-panel); }
/* the bar takes the state's ANCHOR, not its chip fill: rendered at 320 the chip fill was invisible against the
   panel, so the only thing on screen was the travelling band — and with motion off there was nothing at all */
.alive-panel[data-astate="working"] .alive-statusbar { background: var(--cd-approval); }
.alive-panel[data-astate="working"] .alive-statusbar-sweep { background: var(--cd-text-hi); opacity: 0.75; animation: cd-sweep 1.1s linear infinite; }
.alive-panel[data-astate="working"] .alive-panel-state { background: var(--cd-approval-chip-bg); color: var(--cd-approval-chip-text); border-color: var(--cd-approval-chip-border); }
.alive-panel[data-astate="working"] .alive-state-dot { background: var(--cd-approval-chip-dot); animation: cd-pulse 1s ease-in-out infinite; }

/* NEEDS YOU — the agent has stopped and the turn is the operator's. The heaviest of the four on purpose: it is
   the only state where nothing happens until somebody does something. */
.alive-panel[data-astate="needs-you"] { border-color: var(--cd-wall); box-shadow: 0 0 0 1px var(--cd-wall-glow), 0 6px 18px -12px var(--cd-shadow-panel); }
.alive-panel[data-astate="needs-you"] .alive-statusbar { background: var(--cd-wall); }
.alive-panel[data-astate="needs-you"] .alive-panel-state { background: var(--cd-wall-chip-bg); color: var(--cd-wall-chip-text); border-color: var(--cd-wall-btn-border); }
.alive-panel[data-astate="needs-you"] .alive-state-dot { background: var(--cd-wall-chip-dot); animation: cd-pulse 1.2s ease-in-out infinite; }

/* ERROR — something went wrong on this session. Still, not pulsing: a failure is a fact, not an activity, and a
   panel that throbs after it has failed reads as though it is still trying. */
.alive-panel[data-astate="error"] { border-color: var(--cd-error); box-shadow: 0 6px 18px -12px var(--cd-shadow-panel); }
.alive-panel[data-astate="error"] .alive-statusbar { background: var(--cd-error); }
.alive-panel[data-astate="error"] .alive-panel-state { background: var(--cd-error-chip-bg); color: var(--cd-error-chip-text); border-color: var(--cd-error-chip-border); }
.alive-panel[data-astate="error"] .alive-state-dot { background: var(--cd-error-chip-dot); }

/* WAITING — nothing is owed in either direction. The quietest of the four, and the state a held cell settles into
   so a finished panel stops competing with the live ones beside it. */
.alive-panel[data-astate="waiting"] { border-color: var(--cd-line-2); box-shadow: 0 2px 10px -8px var(--cd-shadow-panel); }
.alive-panel[data-astate="waiting"] .alive-statusbar { background: var(--cd-line-2); }
.alive-panel[data-astate="waiting"] .alive-panel-state { background: var(--cd-surface-2); color: var(--cd-muted-2); border-color: var(--cd-line-2); }
.alive-panel[data-astate="waiting"] .alive-state-dot { background: var(--cd-muted-3); }

/* THE CARET — output is still arriving on this line. Bound to an attribute the stream sets and the turn's end
   clears, so it is never a decoration that outlives the thing it describes. */
.alive-turn-body[data-streaming="true"]::after { content: '\2588'; margin-left: 1px; color: var(--cd-muted-1);
  animation: cd-caret 0.9s steps(1) infinite; }

/* ENTRANCES. A panel arriving and a message you just sent landing — the two moments where something appears that
   the operator did not already have on screen. */
.alive-panel { animation: cd-rise 0.16s ease-out; }
.alive-turn.alive-you { animation: cd-pop 0.18s cubic-bezier(0.2, 0.9, 0.3, 1); }

/* THE TOAST. Bottom-anchored and centred by the box model rather than by a transform, which keeps the entrance
   animation free to move it and keeps it away from the top strip entirely — a floating surface that starts under
   the strip is exactly what the shell's enumeration refuses, and the way not to fail that is not to float there. */
.alive-toast { position: fixed; left: 0; right: 0; bottom: 18px; margin: 0 auto; width: max-content;
  max-width: calc(100% - 32px); z-index: var(--cd-z-float); pointer-events: none;
  padding: 7px 13px; border-radius: 999px; border: 1px solid var(--cd-line-3);
  background: var(--cd-surface-sheet); color: var(--cd-text); font-size: var(--cd-type-meta);
  box-shadow: 0 8px 24px -12px var(--cd-shadow-panel); animation: cd-rise 0.18s cubic-bezier(0.2, 0.9, 0.3, 1); }
/* ==================================== end Slice AL8 aliveness layer ==================================== */

/* ============================== Slice AL9 — connectors and needs-you navigation ==============================
   TWO SURFACES, ONE SUBJECT: where output went, and where the operator is needed. Both are routing, and both
   were invisible — a hand-off left a sentence on two panels and nothing between them, and with the ceiling full
   the one panel waiting on a directive was somewhere in six.

   THE LAYER OVERLAYS; IT DOES NOT PARTICIPATE. The canvas is a grid whose track floor is load-bearing, so the
   connectors are painted on an absolutely-positioned layer inside it rather than added to it as a cell. That
   layer takes no pointer events at all: it spans every panel on the canvas, and a surface that covers the
   controls must not be able to receive anything aimed at them.

   IT ALSO DOES NOT FLOAT. The layer is positioned against the canvas, not the viewport, and names neither bar
   height — so it cannot come to rest beneath the strip, and it is not something the shell has to know about. */
.alive-canvas { position: relative; }
.alive-connectors { position: absolute; inset: 0; z-index: 0; pointer-events: none; overflow: visible; }
/* the panels sit above the lines, so a connector reads as passing behind them rather than across them */
.alive-panel { position: relative; z-index: 1; }
.alive-link { fill: none; stroke: var(--cd-approval); stroke-width: 1.5; stroke-dasharray: 4 4; opacity: 0.75;
  animation: cd-dash 1.6s linear infinite; }
/* a link whose sender has ended keeps the record and stops claiming to be live traffic */
.alive-link[data-held="true"] { stroke: var(--cd-muted-4); opacity: 0.5; animation: none; }

/* THE NEEDS-YOU COUNT. Gold, because it names the same state the panels do, and a button because the whole
   point of the number is that it takes you to the first one. Hidden at zero rather than reading "0 needs you",
   which is a sentence about nothing. */
.alive-needs-chip { border: 1px solid var(--cd-wall-btn-border); background: var(--cd-wall-chip-bg);
  color: var(--cd-wall-chip-text); font-size: var(--cd-type-meta); padding: 3px 10px; cursor: pointer;
  gap: var(--cd-space-3); }
.alive-needs-chip:hover { border-color: var(--cd-wall); }
.alive-needs-chip:focus-visible { outline: none; border-color: var(--cd-wall); }
.alive-needs-chip .alive-state-dot { background: var(--cd-wall-chip-dot); animation: cd-pulse 1.2s ease-in-out infinite; }
/* ==================================== end Slice AL9 connectors ==================================== */

/* ============================== Slice AL10 — the canvas controls ==============================
   DENSITY, AND WHY BOTH FORMS KEEP THE CLAMP. The canvas's track floor is the width a panel actually needs, and
   it is written `min(floor, 100%)` because a bare floor wider than the narrowest canvas does not scroll — it
   crops, silently, inside the panel. Comfortable raises the floor; it does not get to raise it past the
   container. So both modes are clamped and neither can overflow the narrowest canvas, which is the property,
   not the number. Compact is what this surface already was, so nothing moves unless the operator asks. */
.alive-canvas[data-density="comfortable"] { grid-template-columns: repeat(auto-fill, minmax(min(360px, 100%), 1fr)); }
.alive-canvas[data-density="comfortable"] .alive-panel .alive-out { max-height: 340px; }
/* its desktop floor is declared in the canvas's OWN min-900 block above rather than in one of this slice's own:
   the sheet's breakpoint blocks are counted, and a slice that needs a band should join the block that band
   already has — the same reason the reduced-motion opt-outs join theirs. */
/* the header's own controls: quiet, in a row that wraps, so a phone header never pushes the canvas off screen */
.alive-canvas-ctls { display: flex; align-items: center; gap: var(--cd-space-3); flex-wrap: wrap; margin-left: auto; }
.alive-canvas-ctls .ghost { flex: 0 0 auto; }

/* THE EMPTY CANVAS. Not a blank area with a heading — the ceiling stated, and one control that does the thing
   the sentence is about. It replaces nothing: the catalog is still directly below it. */
.alive-canvas-empty { display: flex; flex-direction: column; gap: var(--cd-space-4); align-items: flex-start;
  margin: 0 14px var(--cd-space-6); padding: var(--cd-space-6); border: 1px dashed var(--cd-line-2);
  border-radius: 10px; background: var(--cd-surface-1); }
.alive-canvas-empty-title { color: var(--cd-text-hi); font-size: var(--cd-type-lead); font-weight: 600; }
.alive-canvas-empty-note { color: var(--cd-muted-2); font-size: var(--cd-type-meta); line-height: 1.45; margin: 0; }

/* THE DIRECTORY PICKER. One control for one filter. Its left edge carries the selected division's hue where the
   token layer has one and a neutral edge where it does not — the six that are coloured are coloured because
   something else on this surface already colours them, and inventing eleven more would be inventing meaning. */
.alive-div-picker { flex: 1 1 auto; min-width: 0; background: var(--cd-bg-void); border: 1px solid var(--cd-line-2);
  border-left-width: 3px; border-left-color: var(--cd-line-3); border-radius: 8px; color: var(--cd-text);
  padding: 5px 8px; font-size: var(--cd-type-meta); font-family: var(--cd-font-mono, var(--mono)); }
.alive-div-picker:focus { outline: none; border-color: var(--cd-approval); }
.alive-div-picker[data-div="engineering"] { border-left-color: var(--cd-div-engineering); }
.alive-div-picker[data-div="design"] { border-left-color: var(--cd-div-design); }
.alive-div-picker[data-div="security"] { border-left-color: var(--cd-div-security); }
.alive-div-picker[data-div="testing"] { border-left-color: var(--cd-div-testing); }
.alive-div-picker[data-div="specialized"] { border-left-color: var(--cd-div-specialized); }
.alive-div-picker[data-div="product"] { border-left-color: var(--cd-div-product); }

/* THE RAIL TOGGLE. It hides and shows the rail that is already there; it never moves it, and it is scoped to the
   band where the rail competes with the canvas for width. Above that band there is room for both and the control
   has nothing to do, so it is not shown.
   Its two narrow-band rules are folded into the stacked block this sheet already declares rather than opening a
   sixth: a verify counts those, and a slice that needs the band should join it the way the hand-off's opt-out
   joined the canvas's.

   Slice AL14 — THIS COMMENT USED TO CLOSE ON THE LINE ABOVE. A stray terminator after "not shown" ended it three
   lines early, so the prose below became a selector prelude and the browser dropped the rule it swallowed: the
   toggle was visible at every width while AL10's VERIFY, which matched the rule's text in a comment-STRIPPED
   copy of the sheet, stayed green on a rule no parser ever kept. The band rule below is now written to win on
   SPECIFICITY rather than on source order — see the note beside it. */
.alive-rail-toggle { display: none; }
/* ==================================== end Slice AL10 canvas controls ==================================== */

/* ============================== Slice AL11 — the hand-off's interaction states ==============================
   AL4 shipped the mechanism and made TAP the required path with drag as an enhancement. Everything here dresses
   that mechanism: what the pointer carries, what a target says before the drop, and how the operator says what
   they want done with what arrived. None of it is a second way to hand anything off.

   THE GHOST IS FIXED, AND ABOVE THE STRIP ON PURPOSE. It follows the pointer, so it is positioned against the
   viewport; and it stacks over the persistent bars rather than under them, because a token under the operator's
   finger that the chrome paints over is worse than no token at all. That is the branch the shell's own
   enumeration allows for — a surface above the strip cannot be covered by it — and it is asserted rather than
   assumed. It takes no pointer events: it is under the cursor by definition, and a thing under the cursor that
   can receive events is a thing that eats the drop. */
.alive-drag-ghost { position: fixed; top: 0; left: 0; z-index: var(--cd-z-float); pointer-events: none; will-change: transform;
  display: flex; align-items: baseline; gap: var(--cd-space-4); max-width: 260px;
  padding: 7px 11px; border-radius: 10px; border: 1px solid var(--cd-approval-chip-border);
  background: var(--cd-surface-sheet); box-shadow: 0 10px 26px -12px var(--cd-shadow-panel);
  transform: rotate(-1.5deg) scale(1.03); }
.alive-ghost-kind { color: var(--cd-approval-chip-text); background: var(--cd-approval-chip-bg);
  border-radius: 999px; padding: 1px 7px; font-size: var(--cd-type-kicker); letter-spacing: 0.08em;
  text-transform: uppercase; flex: 0 0 auto; }
.alive-ghost-title { color: var(--cd-text-hi); font-size: var(--cd-type-meta); overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.alive-ghost-from { color: var(--cd-muted-3); font-size: var(--cd-type-kicker); flex: 0 0 auto; }
/* the source recedes while its output is in flight, so the thing being moved is the ghost and not the panel */
.alive-panel[data-dragging="true"] .handoff-chip { opacity: 0.4; }

/* THE DROP OVERLAY. A target says whether it can take this before the drop rather than after, over its whole
   face so the answer is unmissable, and it never takes a pointer event — the panel under it is what the browser
   must still see. */
.alive-drop-overlay { position: absolute; inset: 0; z-index: 2; pointer-events: none; display: flex;
  align-items: center; justify-content: center; text-align: center; padding: var(--cd-space-5);
  border-radius: 10px; font-size: var(--cd-type-body); animation: cd-rise 0.14s ease-out; }
.alive-drop-overlay[data-drop="valid"] { background: var(--cd-approval-chip-bg); color: var(--cd-approval-chip-text);
  box-shadow: 0 0 0 2px var(--cd-approval) inset; }
.alive-drop-overlay[data-drop="invalid"] { background: var(--cd-wall-chip-bg); color: var(--cd-wall-chip-text);
  box-shadow: 0 0 0 2px var(--cd-wall-btn-border) inset; }
.alive-drop-word { animation: cd-pop 0.18s cubic-bezier(0.2, 0.9, 0.3, 1); }

/* THE DIRECTIVE. Chips are a shortcut for typing into the box beside them and nothing more: both write the same
   value, and one function sends it. They are generic on purpose — see the slice's verify for why a chip derived
   from the receiver's division would be a claim about that agent this surface cannot back. */
.alive-directive { display: none; flex-direction: column; gap: var(--cd-space-3); margin-top: var(--cd-space-4); }
.alive-panel[data-handoff-source="true"] .alive-directive { display: flex; }
.alive-directive-row { display: flex; flex-wrap: wrap; gap: var(--cd-space-3); }
.alive-directive-chip { background: var(--cd-surface-2); border: 1px solid var(--cd-line-2); color: var(--cd-muted-1);
  font-size: var(--cd-type-kicker); padding: 3px 9px; cursor: pointer; }
.alive-directive-chip:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.alive-directive-chip.is-on { color: var(--cd-text-hi); border-color: var(--cd-approval); background: var(--cd-approval-chip-bg); }
.alive-directive-input { width: 100%; background: var(--cd-bg-void); border: 1px solid var(--cd-line-2);
  border-radius: 8px; color: var(--cd-text); padding: 5px 8px; font-size: var(--cd-type-meta);
  font-family: var(--cd-font-mono, var(--mono)); }
.alive-directive-input:focus { outline: none; border-color: var(--cd-approval); }
/* Declining what arrived. Quiet: it is an ordinary reply, not an undo. */
.alive-discard-btn { flex: 0 0 auto; }
/* ==================================== end Slice AL11 handoff states ==================================== */

/* ============================== Slice AL12 — typed output, from attributed paths ==============================
   WHAT IS REAL HERE AND WHAT IS NOT. The path is real: the daemon wrote it, attributed it to a stage and an agent,
   and AL12a made it name its run. So the file ROW is real — its name, its extension, and the fact that this
   session produced it are all things the daemon proved. What is not on the wire is CONTENT: an image's bytes and
   a table's rows were never sent, and the download surface is gated to output-artifact types under output areas,
   so it will not serve an arbitrary project file either.

   SO THE PLATE AND THE TABLE ARE FRAMES AROUND SOMETHING ABSENT, AND THEY SAY SO. They carry the sentence, not a
   blank area: an empty-looking plate is indistinguishable from a real artifact that returned nothing, which makes
   a missing wire look like a working feature with no result. The frame states which it is, in the panel, every
   time. That is the whole difference between a placeholder and a lie. */
.alive-artifacts { display: flex; flex-direction: column; gap: var(--cd-space-3); margin-top: var(--cd-space-4); }
.alive-artifact { border: 1px solid var(--cd-line-2); border-left-width: 3px; border-radius: 9px;
  background: var(--cd-kind-fill); padding: var(--cd-space-4) var(--cd-space-5); min-width: 0; overflow: hidden; }
.alive-artifact[data-kind="image"] { border-left-color: var(--cd-kind-image); }
.alive-artifact[data-kind="data"] { border-left-color: var(--cd-kind-data); }
.alive-artifact[data-kind="file"] { border-left-color: var(--cd-kind-file); }
.alive-art-head { display: flex; align-items: baseline; gap: var(--cd-space-4); min-width: 0; }
.alive-art-kind { flex: 0 0 auto; font-size: var(--cd-type-kicker); letter-spacing: 0.08em; text-transform: uppercase; }
.alive-artifact[data-kind="image"] .alive-art-kind { color: var(--cd-kind-image); }
.alive-artifact[data-kind="data"] .alive-art-kind { color: var(--cd-kind-data); }
.alive-artifact[data-kind="file"] .alive-art-kind { color: var(--cd-kind-file); }
/* the name is the thing that is real, so it gets the room and ellipsises rather than wrapping into the meta */
.alive-art-name { flex: 1 1 auto; min-width: 0; color: var(--cd-text-hi); font-size: var(--cd-type-meta);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alive-art-meta { flex: 0 0 auto; color: var(--cd-muted-4); font-size: var(--cd-type-kicker); }
/* THE FRAME AROUND ABSENT CONTENT. Dashed and unfilled on purpose — it reads as an outline waiting for something
   rather than as a surface that holds nothing — and it always carries its own explanation. */
.alive-art-frame { margin-top: var(--cd-space-3); border: 1px dashed var(--cd-line-3); border-radius: 8px;
  padding: var(--cd-space-5); display: flex; flex-direction: column; gap: var(--cd-space-3); }
.alive-art-frame[data-frame="image"] { min-height: 64px; }
.alive-art-frame[data-frame="data"] { min-height: 52px; }
.alive-art-unwired { color: var(--cd-muted-2); font-size: var(--cd-type-kicker); line-height: 1.45; margin: 0; }
.alive-art-unwired b { color: var(--cd-muted-1); font-weight: 500; }
/* ==================================== end Slice AL12 typed output ==================================== */

/* ============================== Slice AL13 — the preview screen ==============================
   AN OVERLAY AT EVERY WIDTH, AND THAT IS THE POINT. A side-by-side column would have bought a sixth breakpoint
   and repointed the canvas's clamp and both densities onto a canvas that is suddenly narrower at one width and
   not at another. Floating over it costs the canvas nothing: not one rule below names .alive-canvas or
   .alive-panel, so the surface underneath is the same surface open or closed, in either density, at any count.

   IT CLEARS THE STRIP — Slice AL15. It used to stack ABOVE the tab bar, which is a branch the shell's enumeration
   allows and which does keep its own close control reachable, but it bought that by painting out the tab strip:
   a surface that blocks nothing, holds no unanswered question and closes on navigation was nonetheless hiding
   the way to the other two surfaces. So it begins BELOW both persistent bars, composed from their two tokens so
   a bar that changes height carries it, and it stacks UNDER the strip as well — the offset is what keeps them
   apart and the layer is what makes that true even if the offset ever regressed. It costs 44px of height, which
   is the right trade for a screen the operator is meant to be able to leave.

   LAYERS, NOT PAGES. Nothing here styles a first block differently from a fifth, and there is no heading, kicker
   or lead anywhere in this section — the type is one size for every block of agent output, because a rule that
   made the opening sentence bigger would be this surface asserting that the output is a document with a title.
   It is a stack of attributed text, and it looks like one. */
/* the offset is a LONGHAND on purpose: the shell's enumeration reads a shorthand's first component by splitting
   it on whitespace, which cuts a calc() in half and leaves the surface unresolvable to the check that guards it */
#alive-preview-overlay { position: fixed; top: calc(var(--topbar-h) + var(--tabbar-h)); left: 0; right: 0;
  bottom: 0; z-index: var(--cd-z-modal); display: flex; flex-direction: column; background: var(--cd-bg-app); overflow-y: auto; }
/* the bar wraps, so at 320 the controls fall onto a second line instead of off the edge */
.alive-preview-bar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--cd-space-4);
  padding: var(--cd-space-5) 14px; border-bottom: 1px solid var(--cd-line-2); }
.alive-preview-title { flex: 0 0 auto; color: var(--cd-text-hi); font-size: var(--cd-type-body); }
.alive-preview-devices { display: flex; flex-wrap: wrap; gap: var(--cd-space-2); margin-left: auto; }
/* sized like the rest of this surface's controls rather than like a page-level button: rendered at 320 the six of
   them inherited the 16px base control and stacked into a 197px bar — a quarter of a phone spent on chrome before
   a single line of what the operator opened this to read */
.alive-device-btn, .alive-preview-attrib, .alive-preview-close { flex: 0 0 auto; border-radius: 8px;
  padding: var(--cd-space-3) var(--cd-space-5); font-size: var(--cd-type-meta); }
.alive-device-btn[data-on="true"] { color: var(--cd-text-hi); border-color: var(--cd-approval);
  background: var(--cd-approval-chip-bg); }
/* who is streaming, through the same status-line primitive every other line on this surface uses */
.alive-preview-status { margin: 0; padding: var(--cd-space-4) 14px 0; color: var(--cd-muted-2);
  font-size: var(--cd-type-meta); }
.alive-preview-layers { display: flex; flex-wrap: wrap; gap: var(--cd-space-3); padding: var(--cd-space-4) 14px; }
.alive-layer-toggle { max-width: 100%; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  border: 1px solid var(--cd-line-2); border-radius: 999px; background: var(--cd-surface-2);
  color: var(--cd-muted-2); padding: 3px 9px; font-size: var(--cd-type-kicker); cursor: pointer; }
.alive-layer-toggle:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.alive-layer-toggle:focus-visible { outline: none; border-color: var(--cd-approval); }
.alive-layer-toggle[data-on="true"] { color: var(--cd-text-hi); border-color: var(--cd-approval);
  background: var(--cd-approval-chip-bg); }
.alive-preview-body { flex: 1 1 auto; min-width: 0; padding: 0 14px 20px; }
/* THE DEVICE TOGGLES SIZE THIS COLUMN AND NOTHING ELSE. Each width is clamped against the container for the same
   reason both densities are: a floor wider than the surface it sits in does not scroll, it crops. */
.alive-preview-column { display: flex; flex-direction: column; gap: var(--cd-space-6);
  width: 100%; min-width: 0; margin: 0 auto; }
.alive-preview-column[data-device="desktop"] { max-width: 100%; }
.alive-preview-column[data-device="tablet"] { max-width: min(744px, 100%); }
.alive-preview-column[data-device="mobile"] { max-width: min(360px, 100%); }
.alive-layer { min-width: 0; overflow: hidden; border: 1px solid var(--cd-line-2); border-radius: 10px;
  background: var(--cd-surface-1); padding: var(--cd-space-6); }
.alive-layer-who { display: flex; align-items: baseline; gap: var(--cd-space-4); min-width: 0;
  margin-bottom: var(--cd-space-4); }
.alive-preview-column[data-attribution="off"] .alive-layer-who { display: none; }
/* the name does not GROW — rendered wide, a growing name pushed the division to the far edge of the column and it
   read as a right-aligned heading rather than as a label beside the name — but it still shrinks and ellipsises */
.alive-layer-agent { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--cd-text-hi); font-size: var(--cd-type-meta); }
.alive-layer-div { flex: 0 0 auto; color: var(--cd-muted-4); font-size: var(--cd-type-kicker); }
.alive-layer-text { display: flex; flex-direction: column; gap: var(--cd-space-5); min-width: 0; }
/* the agent's own bytes, wrapped and no more: one size for every block, and a token with no space in it breaks
   rather than pushing the layer past the column it is in */
.alive-layer-block { min-width: 0; color: var(--cd-text-body); font-size: var(--cd-type-body); line-height: 1.5;
  white-space: pre-wrap; overflow-wrap: anywhere; }
.alive-layer-none { margin: 0; color: var(--cd-muted-2); font-size: var(--cd-type-kicker); line-height: 1.45; }
/* ==================================== end Slice AL13 preview screen ==================================== */

/* ============================== Slice AL14 — the header row ==============================
   WHY IT STACKED. #alive-bar is a flex row that does NOT wrap, so the control row inside it was a flex item that
   could shrink — all the way to its min-content, which is its widest single button. Every button therefore went
   on its own line, and the row was four lines tall on a phone regardless of how much width was actually free.
   Letting the BAR wrap is what gives the control row a whole line to lay out on; the row's own wrap then does
   the rest, and above the width where everything fits the bar has nothing to wrap and this changes nothing.

   AND THE BUTTONS ARE SIZED LIKE THIS SURFACE'S OTHER CONTROLS. They were inheriting the 16px page-level button,
   which is what made four of them 340px wide in a header that gets ~292 on a phone. Same treatment the preview's
   own bar takes, for the same reason. */
#alive-bar { flex-wrap: wrap; }
.alive-canvas-ctls .ghost { border-radius: 8px; padding: var(--cd-space-3) var(--cd-space-5);
  font-size: var(--cd-type-meta); }
/* ==================================== end Slice AL14 header row ==================================== */

/* ============================== Slice UI13 — every colour through a token ==============================
   WHAT THIS IS. Sixty-four colour literals lived outside :root — 39 written bare, 21 as stale fallbacks inside
   var() that no browser could ever reach, and 4 inside keyframes. Each is now a NAMED ROLE. No theme, no visual
   change: every value below is byte-identical to the literal it replaces, so this slice moves no pixel. It is
   the prerequisite that makes a second theme a value swap instead of a rewrite.

   WHY SOME ROLES SHARE A VALUE. A colour used for two meanings gets TWO tokens, not one. One amber served as the
   run chip's attention text, the overwrite marker's text and the abandoned outcome's text; those are three
   surfaces with three futures, and in dark they happen to agree. Collapsing them is exactly what would make a
   light theme impossible without redoing this slice — a light theme will want the outcome word darker than the
   chip label, and a shared token cannot give it that. Three roles at one value; the agreement is the accident.

   WHY THREE OF THEM ARE CHANNEL TRIPLETS. Shadows are one colour at many alphas — five uses at four alphas here,
   hairline borders four at four, the loud chip's pulse two at two. Twelve shadow tokens would be twelve names
   for one decision. The colour is tokened once and the alpha is composed at the use site, which also keeps the
   computed value identical: substituting the triplet into the colour function reproduces the declaration exactly.

   AND WHY THIS BLOCK IS NOT IN THE SLICE-A LAYER. That layer is asserted to DEFINE and never CONSUME — it reads
   no var(--cd-*) of its own. @keyframes cd-gold lived inside it and hardcoded its two gold stops, so the only
   way to give them names was to move the keyframe out. It is moved verbatim below, one definition still, and
   the rule that animates it is untouched. */
:root {
  /* the mat behind a thumbnail's image — not a surface and not the app background: it is what shows where a
     letterboxed image does not reach its box, and it is pure black on purpose */
  --cd-media-mat: #000;
  /* verbatim machine output: the live transcript and the command insets on the proposal and blocked cards */
  --cd-bg-transcript: #0a0b0d;
  /* the guest page's own backdrop behind the preview iframe — a document colour, not a UI one */
  --cd-preview-paper: #fff;
  /* text on a filled accent control. THREE values for one role today, one per surface that invented its own —
     see this slice's verify for why they are not collapsed here (it would move three computed colours) */
  /* Slice UI14 — ONE role now. Three surfaces had each invented their own near-black for text on a filled
     accent; collapsing them was not free in UI13 because it moved three computed colours, and it is free here
     because this slice restates values anyway. In light the accent darkens, so this role inverts to white. */
  --cd-on-accent: #08101f;
  /* the run chip, by state. Its fill and its label are separate roles because a theme can move one without the
     other, and its pulse ring is the same colour at two alphas */
  --cd-chip-quiet-bg: rgba(139,143,150,0.16);
  --cd-chip-attention-bg: rgba(240,180,41,0.18);
  --cd-chip-attention-text: #f0b429;
  --cd-chip-loud-bg: #f0603f;
  --cd-chip-loud-text: #fff;
  --cd-chip-loud-ring-rgb: 240, 96, 63;
  /* what a proposal's file rows say will happen to each file */
  --cd-row-create-text: #7fd08a;
  --cd-row-create-bg: rgba(127,208,138,0.12);
  --cd-row-overwrite-text: #f0b429;
  --cd-row-overwrite-bg: rgba(240,180,41,0.18);
  /* the advisory Bash flag's fill — guardrail amber, a prompt to read rather than a block */
  --cd-flag-bg: rgba(214,161,58,0.10);
  /* one colour, many alphas: composed at the use site rather than named once per alpha */
  /* ── Slice AUTH3 — THE STACKING LADDER, AS RULES ────────────────────────────────────────────────────────────
     Five levels, each a rule. Two defects came from a number that sorted correctly until its neighbours moved:
     the auth banner's base was right while every card was a bottom sheet and put a security ceremony under the
     catalog drawer the moment it moved to the top, and the same banner then tied with four surfaces it can be
     open beside, winning only because its rule is written late in this file. A level is now something a surface
     IS, not a number it holds, so arriving neighbours cannot change what it means.

     THE RULES, top to bottom:
       float — cannot receive a pointer, so it covers nothing. Above navigation DELIBERATELY, and admissible
               only for that reason: the drag ghost must follow the cursor over everything, and a toast must not
               steal a tap. Anything here without pointer-events:none is a bug, and the check says so.
       nav   — the way out. Nothing that can take a pointer may sit above it. AL15's rule, stated once here
               instead of per surface.
       auth  — the one surface that DEMANDS an answer rather than offering one. Below navigation so it cannot
               hide the way out, above every content surface so nothing can hide it.
       modal — overlays and modals. Dismissable; they offer, they do not demand.
       panel — rails, drawers, panels, cards. The furniture the content sits in.

     THE GAPS ARE DELIBERATE. A surface that opens OVER another at its own level says so as an offset from its
     own token — `calc(var(--cd-z-modal) + 1)` — never as a second number. That keeps the relation true under
     any renumbering, which is the property the whole design exists for: change these five values however you
     like and every surface moves with them. Twenty leaves room for the offsets without crowding the next rule. */
  --cd-z-panel: 20;
  --cd-z-modal: 40;
  --cd-z-auth: 60;
  --cd-z-nav: 80;
  --cd-z-float: 100;
  --cd-shadow-rgb: 0, 0, 0;
  /* Slice UI14 — the hairline was a channel triplet composed at four alphas, and a triplet cannot state a
     DIRECTION: on dark a border is lighter than its surface, on light it must be darker. Four of its five uses
     turned out to be dead, so what survives is one role holding one colour, and each theme states its own. */
  --cd-border: rgba(128, 128, 128, 0.28);
  /* the wall glow's resting stop; its peak is --cd-wall-glow, which already existed */
  --cd-wall-glow-off: oklch(0.8 0.13 85 / 0);
}
/* Moved out of the Slice-A layer verbatim so its two stops can be named. Same single definition, same name, and
   #blocked-card still animates it — a keyframe is resolved by name, not by where it sits. */
@keyframes cd-gold { 0%,100% { box-shadow: 0 0 0 0 var(--cd-wall-glow-off); } 50% { box-shadow: 0 0 26px 1px var(--cd-wall-glow); } }
/* ==================================== end Slice UI13 colour roles ==================================== */

/* ============================== Slice UI14 — the theme layer ==============================
   ONE BLOCK, AND NOTHING ELSE IN THE SHEET KNOWS A THEME EXISTS. Dark is `:root` and stays exactly what it was:
   it is the default, the fallback, and what an unknown or absent attribute renders. Light is the block below,
   restating the SAME role names — no new roles, no theme-specific selector anywhere outside this block. That is
   the property UI13 was built to make possible, and it is asserted rather than intended: a rule elsewhere that
   mentions a theme fails this slice's verify.

   WHY THE ATTRIBUTE AND NOT A MEDIA QUERY. The operator's choice has to beat the operating system's, and a media
   query cannot be overridden by a preference without duplicating every value in a second block. So the shell
   resolves the choice once, before first paint, and writes it here; the media query never appears in the sheet
   at all, which is also why the system preference can never win over an explicit choice.

   DIRECTION, NOT JUST VALUE. Half these roles are not a value swap but a REVERSAL. A border is lighter than its
   surface on dark and must be darker on light. Text on a filled accent is near-black on dark, because the accent
   is a pale blue there, and must be white on light, because the accent darkens to carry white. Those are the
   roles that make a theme more than a palette, and each is checked by luminance rather than by eye. */
:root[data-theme="light"] {
  color-scheme: light;        /* the browser's own controls follow the page, not the desktop — see :root above */
  /* ── neutral surfaces. The scale inverts: what was the deepest inset is now the faintest fill, because on
     light a recessed surface is greyer than the page rather than blacker than it. ── */
  --cd-bg-void: #f4f6f7;
  --cd-bg-app: #f4f5f7;
  --cd-bg-app-2: #eef0f3;
  --cd-surface-sheet: #ffffff;
  --cd-surface-1: #fafbfc;
  --cd-surface-2: #f6f7f9;
  /* ── lines. Every one of these is DARKER than the surface it divides, which is the reversal a value swap on a
     channel triplet could not express — see this slice's verify, which measures the direction. ── */
  --cd-line-1: #eef0f3;
  --cd-line-2: #e3e6ea;
  --cd-line-3: #cfd4da;
  --cd-line-strong: #b9c0c8;
  /* ── text. The ladder runs the other way: high-emphasis is the darkest, not the lightest. ── */
  --cd-text-hi: #14171a;
  --cd-text: #1b1f23;
  --cd-text-2: #2b3138;
  --cd-text-body: #3a4149;
  /* The design artifact's three muted greys measure 3.11:1, 2.58:1 and 2.32:1 on white against a 4.5:1 body-text
     threshold, so that ladder is decorative rather than readable and is not what ships. Holding the threshold
     compresses four steps into the narrow band below, which is the honest cost: on light there is very little
     room between "muted" and "the lightest grey a small label is still allowed to be". */
  --cd-muted-1: #4f5762;
  --cd-muted-2: #5b6470;
  --cd-muted-3: #646c76;
  --cd-muted-4: #6c7078;
  --cd-tag-you: #14171a;
  --cd-tag-system: #646c76;
  /* ── approval blue. The anchor darkens so it can carry white; the chip inverts to a pale fill with dark text. ── */
  /* rendered, the approve button put its own page-grey label on this fill and measured 4.49:1 — the single
     most consequential control in the product, a hundredth under the line. The anchor darkens until it carries
     that label as well as white. */
  --cd-approval: oklch(0.52 0.15 253);
  --cd-approval-btn: oklch(0.52 0.15 253);
  --cd-approval-btn-hover: oklch(0.45 0.15 253);
  --cd-approval-label: oklch(0.45 0.13 253);
  --cd-approval-chip-bg: oklch(0.96 0.02 253);
  --cd-approval-chip-border: oklch(0.52 0.15 253 / 0.35);
  --cd-approval-chip-dot: oklch(0.52 0.15 253);
  --cd-approval-chip-text: oklch(0.45 0.13 253);
  --cd-approval-overlay: oklch(0.45 0.13 253);
  /* ── wall gold. Rendered, this was the role that caught the slice out: the anchor is a border and a dot on
     dark, but SEVEN sites read it as TEXT — the refused command, its kind line, its dismiss control and the
     vendor notes — and a gold bright enough to sit on black measures 3.4:1 as text on white. The anchor is
     therefore darkened until it carries text, and the borders it also draws are darker for it, which on light
     is the direction they wanted anyway. ── */
  --cd-wall: oklch(0.52 0.14 75);
  --cd-wall-cmd-border: oklch(0.62 0.14 75 / 0.4);
  --cd-wall-glow: oklch(0.72 0.16 75 / 0.35);
  --cd-wall-btn-border: oklch(0.62 0.14 75 / 0.5);
  --cd-wall-btn-hover: oklch(0.96 0.05 85 / 0.7);
  --cd-wall-chip-bg: oklch(0.96 0.05 85);
  --cd-wall-chip-text: oklch(0.45 0.12 62);
  --cd-wall-chip-dot: oklch(0.62 0.14 75);
  /* ── production red, and the error family that must not read as it. ── */
  --cd-prod: oklch(0.53 0.19 25);
  --cd-prod-btn-hover: oklch(0.47 0.19 25);
  --cd-prod-label: oklch(0.45 0.15 25);
  --cd-prod-ring: oklch(0.53 0.19 25 / 0.5);
  --cd-prod-domain: oklch(0.45 0.15 25);
  --cd-prod-cmd: oklch(0.45 0.15 25);
  --cd-prod-cmd-border: oklch(0.53 0.19 25 / 0.35);
  --cd-prod-overlay: oklch(0.5 0.18 25);
  --cd-error: oklch(0.53 0.19 25);
  --cd-error-chip-bg: oklch(0.96 0.03 25);
  --cd-error-chip-border: oklch(0.53 0.19 25 / 0.35);
  --cd-error-chip-text: oklch(0.45 0.15 25);
  --cd-error-chip-dot: oklch(0.53 0.19 25);
  /* ── the rest of the semantic set ── */
  --cd-ok: oklch(0.48 0.13 155);
  --cd-link: oklch(0.48 0.12 233);
  --cd-link-hover: oklch(0.4 0.12 233);
  --cd-kind-image: oklch(0.5 0.16 320);
  --cd-kind-data: oklch(0.48 0.14 285);
  --cd-kind-file: oklch(0.45 0.12 150);
  --cd-kind-fill: #eef1f4;
  /* ── shadow. Still one colour at many alphas; on light it is a warm near-black rather than pure black, which
     is what keeps a lifted surface from looking like a hole. ── */
  --cd-shadow-rgb: 20, 23, 26;
  --cd-shadow-panel: rgba(20, 23, 26, 0.16);
  /* ── the live palette the older surfaces still read ── */
  --bg: #f4f5f7;
  --surface: #ffffff;
  --surface-2: #fafbfc;
  --fg: #14171a;
  --muted: #555e69;
  --line: #e3e6ea;
  --accent: oklch(0.52 0.15 253);
  --success: oklch(0.48 0.13 155);
  --danger: oklch(0.53 0.19 25);
  --guardrail: oklch(0.45 0.12 62);
  --ok: oklch(0.48 0.13 155);
  --card: #ffffff;
  /* ── the UI13 roles ── */
  --cd-bg-transcript: #f4f6f7;
  /* the reversal named above: the accent darkens on light, so its foreground goes the other way */
  --cd-on-accent: #ffffff;
  --cd-border: #e3e6ea;
  --cd-chip-quiet-bg: rgba(91, 100, 112, 0.10);
  --cd-chip-attention-bg: oklch(0.96 0.05 85);
  --cd-chip-attention-text: oklch(0.45 0.12 62);
  --cd-chip-loud-bg: oklch(0.53 0.19 25);
  --cd-chip-loud-ring-rgb: 200, 62, 48;
  --cd-row-create-text: oklch(0.45 0.13 150);
  --cd-row-create-bg: oklch(0.95 0.04 150);
  --cd-row-overwrite-text: oklch(0.45 0.12 62);
  --cd-row-overwrite-bg: oklch(0.96 0.05 85);
  --cd-flag-bg: oklch(0.96 0.05 85);
}
/* ==================================== end Slice UI14 theme layer ==================================== */

/* ============================== Slice UI15 — the rail swap ==============================
   THE RAIL IS NOT RETIRED; ITS CONTENTS ARE SWAPPED. The workspace controls moved out and the agent catalog
   moved in, so the grid's rail column has an occupant at every moment — which is why the claim that the rail is
   PLACED in that column never became false, and no guarantee had to be surrendered. That was the finding the
   slice was rebuilt around, and it is why the column widens here rather than disappearing.

   THE CATALOG IS A LIST, NOT A GRID. In a 360px column a card grid is one card per row with the padding of
   three, so the rows are rows: an identity tile, the name, its division beneath, and the controls at the end.
   The six divisions the token layer gives a hue keep it; the rest take the neutral edge rather than twelve
   invented colours — the hue formula for all eighteen is its own slice and has to be decided in both themes.

   BELOW THE STACKED BREAKPOINT IT IS A DRAWER. The column does not exist there, so the catalog leaves the flow
   entirely rather than pushing the surface down, and the control that opens it is the one the canvas already
   had. It clears both persistent bars, because a drawer that starts under them hides its own first row. */
#workspace-rail { --catalog-w: 360px; }
/* Slice UI15c — both controls belong to the drawer, so they exist only in the band where the drawer does. The
   band's own block turns them on; here they are off, which is what keeps a column from carrying a close button
   for something that cannot be closed. */
.catalog-close, .catalog-open { display: none; }
.catalog-close { margin-left: auto; padding: var(--cd-space-1) var(--cd-space-4); font-size: var(--cd-type-kicker);
  border: 1px solid var(--cd-line-2); border-radius: 7px; color: var(--cd-muted-2); }
.catalog-close:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.workspace-rail .rail-head { align-items: center; }
.catalog-count { margin: var(--cd-space-4) 0 0; color: var(--cd-muted-2); font-size: var(--cd-type-kicker);
  border-top: 1px solid var(--cd-line-1); padding-top: var(--cd-space-4); }
.alive-searchrow { margin-bottom: var(--cd-space-4); }
/* the rows. One per agent, and every part of one is allowed to shrink except the tile and the controls. */
.alive-grid { display: flex; flex-direction: column; gap: var(--cd-space-2); }
/* flex-direction is stated because the card rule this supersedes sets `column`, and a rule that only re-declares
   `display: flex` inherits that — rendered, the tile, the name, the division and the control stacked into four
   lines per agent. Restating the axis is what makes this a row rather than a narrower card. */
.alive-card { display: flex; flex-direction: row; align-items: center; gap: var(--cd-space-5); width: 100%; min-width: 0;
  text-align: left; padding: var(--cd-space-4); border-radius: 9px; border: 1px solid transparent;
  background: transparent; cursor: pointer; }
.alive-card:hover { background: var(--cd-surface-1); border-color: var(--cd-line-2); }
.alive-card:focus-visible { outline: none; border-color: var(--cd-approval); }
.alive-card[data-blocked="true"] { opacity: 0.55; }
.alive-card-head { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1 1 auto; }
.alive-card-name { color: var(--cd-text-hi); font-size: var(--cd-type-meta); font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.alive-card-div { color: var(--cd-muted-2); font-size: var(--cd-type-kicker);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the description and the id row are what a 360px column cannot afford; the name and division carry the row */
.alive-card-desc, .alive-card-foot { display: none; }
/* the identity tile: two letters on the division's own hue where the token layer has one, neutral where it does not */
.alive-card-tile { flex: 0 0 auto; width: 30px; height: 30px; border-radius: 8px; display: flex;
  align-items: center; justify-content: center; font-family: var(--cd-font-mono, var(--mono));
  font-size: var(--cd-type-kicker); font-weight: 600; text-transform: uppercase;
  background: var(--cd-surface-2); color: var(--cd-muted-1); border: 1px solid var(--cd-line-2); }
.alive-card[data-div="engineering"] .alive-card-tile { color: var(--cd-div-engineering); border-color: var(--cd-div-engineering); }
.alive-card[data-div="design"] .alive-card-tile { color: var(--cd-div-design); border-color: var(--cd-div-design); }
.alive-card[data-div="security"] .alive-card-tile { color: var(--cd-div-security); border-color: var(--cd-div-security); }
.alive-card[data-div="testing"] .alive-card-tile { color: var(--cd-div-testing); border-color: var(--cd-div-testing); }
.alive-card[data-div="specialized"] .alive-card-tile { color: var(--cd-div-specialized); border-color: var(--cd-div-specialized); }
.alive-card[data-div="product"] .alive-card-tile { color: var(--cd-div-product); border-color: var(--cd-div-product); }
/* the per-row config control reaches the SAME surface the panel's own control does — one config path, two doors */
.alive-card-cfg { flex: 0 0 auto; border: 1px solid var(--cd-line-2); background: transparent;
  color: var(--cd-muted-2); border-radius: 7px; padding: 2px 7px; font-size: var(--cd-type-kicker); cursor: pointer; }
.alive-card-cfg:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.alive-card-live { flex: 0 0 auto; color: var(--cd-wall-chip-text); background: var(--cd-wall-chip-bg);
  border-radius: 999px; padding: 1px 7px; font-size: var(--cd-type-micro); letter-spacing: 0.04em; }
/* Slice UI16 — the two things the row gained. PROVENANCE rides in the foot beside the id and the tier, because it
   is the same kind of fact and reads at the same weight. THE SELECT CONTROL matches the config control's box
   exactly: they sit side by side, and two adjacent controls at two sizes would read as two ranks. */
.alive-card-src { color: var(--cd-muted-2); border: 1px solid var(--cd-line-2); border-radius: 4px;
  padding: 0 4px; font-size: var(--cd-type-micro); letter-spacing: 0.04em; }
.alive-card-pick { flex: 0 0 auto; border: 1px solid var(--cd-line-2); background: transparent;
  color: var(--cd-muted-2); border-radius: 7px; padding: 2px 7px; font-size: var(--cd-type-kicker); cursor: pointer; }
.alive-card-pick:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
/* the way into curation, in the rail head beside the drawer's own close */
/* Slice UI17 — the pane selector. It leads the head because it is what the head is FOR now; manage and close
   keep their place at the end. The selected tab carries the approval blue every persistent selection in this
   product carries, which is the same role slice49 asserts is universal. */
.rail-panes { display: flex; align-items: center; gap: var(--cd-space-2); }
.rail-pane-tab { font-size: var(--cd-type-kicker); letter-spacing: 0.04em; text-transform: uppercase;
  padding: var(--cd-space-1) var(--cd-space-4); border: 1px solid var(--cd-line-2); border-radius: 7px;
  background: transparent; color: var(--cd-muted-2); cursor: pointer; }
.rail-pane-tab:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
.rail-pane-tab.is-on { color: var(--cd-approval-chip-text); border-color: var(--cd-approval);
  background: color-mix(in oklch, var(--cd-approval) 18%, transparent); }
.catalog-manage { margin-left: auto; padding: var(--cd-space-1) var(--cd-space-4); font-size: var(--cd-type-kicker);
  border: 1px solid var(--cd-line-2); border-radius: 7px; color: var(--cd-muted-2); }
.catalog-manage:hover { color: var(--cd-text); border-color: var(--cd-line-3); }
/* the curation surface says what it is; the bar was a search box and two buttons with no name on it */
.picker-kicker { text-transform: uppercase; letter-spacing: 0.12em; font-size: var(--cd-type-kicker); color: var(--cd-muted-2); }

/* THE CREW HEADER — step one, and the two surfaces that stage into a run, above the toggled pair and outside it */
.crew-header { display: flex; flex-direction: column; gap: var(--cd-space-5); margin-bottom: var(--cd-space-6);
  padding-bottom: var(--cd-space-6); border-bottom: 1px solid var(--cd-line-2); }
/* Slice AI8 — AND IT COLLAPSES WHEN IT HOLDS NOTHING. The directory group left for the bar's popover, so at rest
   this box's two remaining sections — the handoff inbox and the sweep notice — are both absent, and what was
   left behind was its own frame: a gap, a padding and a rule drawn across the surface between the bar and the
   directive entry, announcing a section with no content.
   THE `hidden` ATTRIBUTE, not a selector. The first draft wrote this as
   `.crew-header:not(:has(> *:not([hidden])))`, which is correct CSS and unverifiable here: the suite's shared
   resolver splits a selector on its combinators before tokenising, so a `>` inside :has() tears the selector in
   half, and its tokeniser cannot express nested parentheses at all. A rule the resolver cannot model is a rule
   no check can pin — and pinning it by matching its text is exactly what _css.mjs exists to stop. So the
   condition moved to syncCrewHeader(), where it is DERIVED from the two sections' own `hidden` (never a third
   opinion about whether they are there) and where a check can drive it both ways. */
.crew-header[hidden] { display: none; }

/* THE WORKSPACE SHEET — a registered overlay, so navigation closes it and the shell's enumeration accounts for
   it. It clears both bars for the reason every other floating surface does: its own close control is in its
   first row, and a row the strip paints over is a row the operator cannot reach. */
/* Slice UI17 — the sheet stops floating. It is the rail's other pane now, so it is part of the column rather
   than a surface over the app: no fixed position, no offset to compose, and no level at all — a thing that does
   not float cannot be covered, and giving it one would be a rule about a thing that cannot obey it, which is
   what AUTH3 deleted two of. It OWNS ITS SCROLL because the measurement put its content above the rail's whole
   usable height even alone; leaning on the rail's scroll would leave its own foot unreachable where the margin
   is thinnest. min-height:0 is what lets a flex child actually scroll rather than grow past its parent. */
#workspace-sheet { display: flex; flex-direction: column; min-height: 0; flex: 1 1 auto;
  overflow-y: auto; background: var(--cd-bg-app);
  /* NO ARITHMETIC HERE. The pane fills whatever its parent leaves it — the rail is bounded above, so this is
     correct however tall the head is. The first attempt subtracted the two bars from the viewport, which was
     right about the bars and wrong about the head that also sits above this pane: the cap overshot by the head's
     height, the box ran past the fold, and the internal scroll had six pixels to give. A cap that names one of
     the things above it is a cap that is wrong about the others. */ }
#workspace-sheet-bar { display: flex; align-items: center; justify-content: space-between; flex: 0 0 auto;
  gap: var(--cd-space-5); padding: var(--cd-space-5) 14px; border-bottom: 1px solid var(--cd-line-2);
  color: var(--cd-text-hi); }
#workspace-sheet-body { flex: 1 1 auto; min-width: 0; padding: var(--cd-space-6) 14px 20px;
  display: flex; flex-direction: column; gap: var(--cd-space-6); max-width: 720px; margin: 0 auto; width: 100%;
  box-sizing: border-box; }

/* ── Slice AI12 — the pane's two new members. Both borrow rules that already exist, which is the point:
   #studio-trigger carries .runbar-trigger and #pop-studio carries .runbar-pop, so neither draws a colour, a
   size or a level of its own and both themes answer them exactly as they answer the bar. What is added here is
   only what a COLUMN needs that a ROW did not — a trigger in a flex column would otherwise stretch to the full
   width and stop reading as a chip. The slot adds no box at all, so the queue lands in the pane's own column
   rather than inside a wrapper with its own spacing. */
.workspace-queue-slot { display: contents; }
.workspace-trigger { align-self: flex-start; }

/* Slice UI18 — the import panel, made ORDINARY inside this pane.
   It arrived carrying two positioning identities, one per band: a sticky panel with its own viewport-relative
   cap above 900, and a fixed slide-over drawer with a transform and a modal stacking level below. Both are
   wrong here for the same reason — the pane already owns a scroll, and a box that caps itself against the
   viewport inside a scroller puts its own foot out of reach, which is the defect UI17 fixed one level up.
   This wins by SPECIFICITY, two ids against one, so it holds in BOTH bands without adding a band block or
   depending on where it sits in the file. The .open form is listed too: that class is what the drawer was
   toggled by, it outranks a plain id, and a stale one must not be able to re-float this panel. */
#workspace-sheet #motion-store,
#workspace-sheet #motion-store.open {
  position: static; inset: auto; top: auto; transform: none; transition: none;
  width: auto; max-width: none; max-height: none;
  /* LONGHANDS, deliberately. What this overrides is a longhand pair, and `overflow: visible` would beat it in a
     browser but is invisible to a resolver reading declarations by name — which reported a scroller that is not
     there. Saying it the way the rule it replaces says it keeps the claim assertable as well as true. */
  overflow-x: hidden; overflow-y: visible;
  z-index: auto; box-shadow: none; }
/* ==================================== end Slice UI15 rail swap ==================================== */

/* ============================== Slice AUTH2 — the auth banner and its queue ==============================
   THE POSITION, and it is one mechanism at every width. A request you must act on belongs at the top of the
   content area and BELOW both bars: AL15 settled that when the preview covered the tab strip — a surface you
   have to answer must not hide the way out, because understanding what an agent is asking can require going
   somewhere else first. The card component itself is untouched; only where this one instance sits moves, so
   every other card keeps the bottom sheet it has always had and no gravity is forked.

   The offset is a `top:` LONGHAND. UI9's and UI11's strip guards split a shorthand on whitespace, which cuts a
   calc() in half and leaves them asserting something that is not the rule. */
#proposal-card {
  top: calc(var(--topbar-h) + var(--tabbar-h));
  bottom: auto;
  /* ABOVE THE DRAWER, BELOW THE STRIP. The card base stacks at a level chosen when every card was a bottom
     sheet under everything; moved to the top of the content area this one lands under the catalog drawer, and
     the hit-test found all five controls needed to answer a request covered by it at stacked widths whenever
     the drawer was open — the request unanswerable behind a list. It clears the drawer and the workspace sheet
     and still passes beneath the strip, so AL15's rule holds: the way out is never hidden. */
  z-index: var(--cd-z-auth);
  max-height: calc(100vh - var(--topbar-h) - var(--tabbar-h) - 24px);
  overflow-y: auto;
}
/* what is waiting behind this one, stated beside the kind rather than as a second surface */
.prop-queue { margin-left: auto; font-size: var(--cd-type-kicker); letter-spacing: 0.04em;
  color: var(--cd-approval); border: 1px solid var(--cd-approval); border-radius: 999px; padding: 1px 8px; }
#proposal-card .card-kind { display: inline-flex; align-items: center; }
/* the kind and the depth share a row, so the depth reads as part of this card's own header */
#proposal-card > .card-kind { flex: 0 1 auto; }

/* THE CONTROLS AT THE THUMB, and the banner does not move. Below the stacked breakpoint the actions sit at the
   banner's bottom edge; on a phone the reachable part of a fixed top surface is its lower edge, and moving the
   BANNER instead would put it back over the strip AL15 cleared. Compound on purpose: `.card-actions` is styled
   ~2600 lines above this, a media query buys no specificity, and at equal weight the later rule would win only
   by accident of position — which has now bitten three times and has only ever been caught by rendering. */
@media (max-width: 599px) {
  #proposal-card > .card-actions { order: 99; margin-top: var(--cd-space-4); }
  #proposal-card > #prop-timer { order: 98; }
}
/* ============================== end Slice AUTH2 auth banner ============================== */

/* ══ Slice AI1 — THE RUN BAR ═══════════════════════════════════════════════════════════════════════════════
   IN-SURFACE, NOT CHROME. Nothing here is `position: fixed`, which is deliberate and is what keeps the chrome
   at exactly two top-anchored bands: this scrolls with the surface it configures and reserves no height from
   --topbar-h or --tabbar-h, so a phone loses no row to it when a run is not being composed.
   Roles only — no literal colour, no literal size — so both themes answer it from the token layer. */
.runbar-mount { display: contents; }   /* the mount adds no box; the bar is the child the surface lays out */
.runbar {
  display: flex; flex-direction: column; gap: var(--cd-space-3);
  margin: 0 0 var(--cd-space-6);
  padding: var(--cd-space-4) var(--cd-space-5);
  border: 1px solid var(--cd-line-2); border-radius: 10px;
  background: var(--cd-surface-1);
}
/* ONE ROW AT REST. The row wraps rather than scrolls: the topbar scrolls because its height is a layout API
   with 23+ consumers and could not grow, and neither constraint applies to content — so at 320 this becomes two
   short rows the operator can read instead of one they must swipe. */
.runbar-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cd-space-3) var(--cd-space-4); }
.runbar-trigger {
  display: inline-flex; align-items: center; gap: var(--cd-space-2);
  min-height: 30px; padding: var(--cd-space-2) var(--cd-space-4);
  border: 1px solid var(--cd-line-2); border-radius: 999px;
  background: none; color: var(--cd-text); font: inherit; font-size: var(--cd-type-body); cursor: pointer;
}
.runbar-trigger:hover { border-color: var(--cd-line-3); color: var(--cd-text-hi); }
.runbar-trigger[aria-expanded="true"] { border-color: var(--cd-approval); color: var(--cd-text-hi); }
.runbar-trigger-quiet { color: var(--cd-muted-2); }
.runbar-kicker {
  font-family: var(--cd-font-mono, var(--mono));
  font-size: var(--cd-type-kicker); text-transform: uppercase; letter-spacing: 0.06em; color: var(--cd-muted-3);
}
.runbar-val { font-size: var(--cd-type-meta); color: var(--cd-text-2); }
.runbar-dir-slot { display: inline-flex; align-items: center; min-width: 0; }
/* the withheld note is a statement, not a control — it never takes a pointer */
.runbar-withheld { font-size: var(--cd-type-meta); color: var(--cd-muted-3); pointer-events: none; }
/* THE ATTACHED STRIP — hidden entirely at rest by the `hidden` attribute; this only styles it when it is there. */
.runbar-attached { display: flex; align-items: baseline; gap: var(--cd-space-4); flex-wrap: wrap; }
.runbar-attached-list { display: flex; flex-wrap: wrap; gap: var(--cd-space-2) var(--cd-space-3); margin: 0; padding: 0; list-style: none; }
.runbar-attached-item {
  display: inline-flex; align-items: baseline; gap: var(--cd-space-2);
  padding: 2px var(--cd-space-3); border: 1px solid var(--cd-line-2); border-radius: 999px;
  font-size: var(--cd-type-meta); color: var(--cd-text-2); max-width: 100%;
}
.runbar-attached-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.runbar-attached-prov { font-size: var(--cd-type-kicker); color: var(--cd-muted-3); text-transform: uppercase; letter-spacing: 0.04em; flex: none; }
/* ── Slice ATT1 — the remove affordance. Roles only, both themes answer it. A chip is small and a control
   inside one smaller, so the HIT AREA is grown past the glyph with padding and a min size, while a negative
   margin keeps it from inflating the pill — the tappable rectangle is larger than the × looks. It is quiet
   until hovered/focused, where it takes the same attention role the untrusted class badge already uses, so
   removing an attachment reads as the mildly-consequential thing it is without a new colour. It aligns to the
   centre of the baseline row rather than the text baseline, because a glyph button on a baseline sits low. */
.runbar-attached-remove {
  flex: none; align-self: center; margin: -4px -6px -4px 0;
  /* 24×24 is the WCAG 2.5.8 minimum target; the chip is ~23px tall, so the control is allowed to exceed it by
     a pixel (the negative margin absorbs it) rather than shrink below the floor — a control too small to hit is
     worse than a chip a hair taller. Measured at 320 at 24×24. */
  min-width: 24px; min-height: 24px; padding: 0 var(--cd-space-2);
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: var(--cd-type-body); line-height: 1; color: var(--cd-muted-3);
}
.runbar-attached-remove:hover, .runbar-attached-remove:focus-visible {
  color: var(--cd-chip-attention-text); outline: none;
}
/* THE POPOVERS. Inline, not floating: they push the surface down rather than covering it, so a control the
   operator is reading is never hidden behind the panel that changes it — and there is no offset to keep in step
   with a band height. They carry no z-index for the same reason; nothing here enters the stacking ladder. */
.runbar-pop {
  display: flex; flex-direction: column; gap: var(--cd-space-5);
  margin-top: var(--cd-space-2); padding: var(--cd-space-5);
  border: 1px solid var(--cd-line-2); border-radius: 8px; background: var(--cd-surface-2);
}
/* ── Slice AI8 — TWO IDS FOR ONE JOB, RECONCILED. #armed-dir and #project-head-label both render
   folderName() of the same selected option with the same full path as their title — syncProjectHead ends by
   calling renderArmedDir precisely to keep them agreeing, which is the tell. With the picker inside the bar
   they became visible together, and the render showed them disagreeing in wording about one state: the trigger
   row read "no directory armed" while the head six rows down read "select a working directory".
   THE HEAD IS THE ONE THAT GOES, and only here. Both of its jobs are already done in this context: the armed
   directory is stated by the trigger row above it — permanently, on both tabs and in both views, which is the
   rule that put it there — and collapsing the list is what the popover itself does, so a disclosure inside a
   disclosure is a second gesture for a decision the operator has already made.
   HIDDEN, NOT DROPPED. The element, its id, its label and #project-head→toggleProjectList all stay exactly as
   slice49 pins them, syncProjectHead goes on writing to it, and outside this popover it is untouched. */
#pop-dir #project-head { display: none; }

/* ── Slice PROV1 — provenance on the attached strip, and the flags trigger when its toggles are moot ────────
   The class badge is quiet by default and takes the ATTENTION role only when the entry is NOT the operator's
   own authorship — the state that costs the run three capabilities, so the state worth seeing. The role is the
   existing --cd-chip-attention-text rather than a new token: both themes already answer it (a warm amber on
   dark, a darker amber on light), and inventing a caution role for one badge would be a second name for a
   meaning the layer already carries. */
.runbar-attached-class {
  font-size: var(--cd-type-kicker); letter-spacing: 0.04em; flex: none;
  color: var(--cd-muted-3); border-left: 1px solid var(--cd-line-2); padding-left: var(--cd-space-2);
}
.runbar-attached-class[data-trusted="false"] { color: var(--cd-chip-attention-text); }
/* A trigger whose toggles the daemon will ignore reads as withheld rather than available. Not disabled: the
   operator may still want to see what is in there, and a control that cannot be opened cannot explain itself. */
.runbar-trigger[data-moot="true"] { border-color: var(--cd-chip-attention-text); color: var(--cd-chip-attention-text); }
.runbar-why {
  margin: 0; font-size: var(--cd-type-meta); color: var(--cd-chip-attention-text);
  border-left: 2px solid var(--cd-chip-attention-text); padding-left: var(--cd-space-4);
}

/* ── Slice AI2 — the plan's step actions and its order guard ────────────────────────────────────────────────
   Roles only, both themes answered from the token layer. The broken states reuse the existing attention role
   rather than inventing a second name for "this needs your eye". */
.plan-st-acts { display: flex; gap: var(--cd-space-2); margin-top: var(--cd-space-3); }
.plan-st-act {
  min-width: 28px; min-height: 28px; padding: 0 var(--cd-space-3);
  border: 1px solid var(--cd-line-2); border-radius: 6px;
  background: none; color: var(--cd-muted-2); font: inherit; font-size: var(--cd-type-body); cursor: pointer;
}
.plan-st-act:hover:not(:disabled) { border-color: var(--cd-line-3); color: var(--cd-text-hi); }
.plan-st-act:disabled { opacity: 0.35; cursor: default; }
.plan-foot { display: flex; flex-direction: column; gap: var(--cd-space-3); align-items: flex-start; margin-top: var(--cd-space-4); }
/* the guard's reason, beside the edit that caused it */
.plan-order-problem {
  margin: 0; font-size: var(--cd-type-meta); color: var(--cd-chip-attention-text);
  border-left: 2px solid var(--cd-chip-attention-text); padding-left: var(--cd-space-4);
}
.plan-st-deps.is-broken { color: var(--cd-chip-attention-text); }
/* Slice AI2 — the editable title/scope. Styled as the text they replace, not as form furniture: the row still
   reads as a plan step, and the field is where the operator types rather than a box bolted beside it. */
.plan-st-edit {
  width: 100%; box-sizing: border-box; background: none; border: 1px solid transparent;
  border-radius: 6px; padding: var(--cd-space-2) var(--cd-space-3); font: inherit; color: inherit;
}
.plan-st-edit:hover { border-color: var(--cd-line-2); }
.plan-st-edit:focus { outline: none; border-color: var(--cd-approval); }
/* Slice AI9 — the fields are textareas now, so a long title WRAPS instead of being clipped at the edge of a
   one-line box (the render caught it at 390). They must not look like form furniture and must not scroll:
   the height is set to the content by autoGrow, so an inner scrollbar would only ever appear mid-keystroke,
   and a drag handle in a plan row is a control that does nothing the row needs. */
/* min-height is overridden, and it is the whole reason this looked broken. The global `textarea` rule at the
   top of this sheet sets `min-height: 88px` — right for the task box and the reply box, and fatal here: a
   one-line step title rendered as an 88px slab with the scope stranded below it, and autoGrow could never
   shrink past a floor it does not control. The render measured it (line-height 19.5px, content 86px, min-height
   88px) after the first fix addressed only the other half of the cause. Both halves were real; this is the one
   that was visible. */
textarea.plan-st-edit { resize: none; overflow: hidden; display: block; min-height: 0; }
textarea.plan-st-title, input.plan-st-title { font-size: var(--cd-type-lead); font-weight: 600; color: var(--cd-text-hi); }
textarea.plan-st-scope, input.plan-st-scope { font-size: var(--cd-type-body); color: var(--cd-text-2); }
/* Slice AI2 — the step number as an ELEMENT for editable rows. The read-only row still takes its number from
   the .plan-st-title::before counter; a replaced element cannot render generated content, so the editable row
   carries it explicitly and the field opts out of the counter so the two cannot both increment it.
   Slice AI9 — the opt-out now names the TEXTAREA as well. It was scoped to `input.plan-st-title`, so swapping
   the element would have left the field silently incrementing `pst` again: invisible, because ::before does not
   render on a textarea either, and wrong the moment a read-only row is drawn beside an edited one.
   ALIGNED TO THE TOP, not the centre: a title that now wraps to two lines would otherwise push its own number
   to the middle of the block, and the number belongs beside the first line it labels. */
.plan-st-head { display: flex; align-items: flex-start; gap: var(--cd-space-3); }
.plan-st-num { flex: none; font-size: var(--cd-type-lead); font-weight: 600; color: var(--cd-muted-3);
  padding-top: var(--cd-space-2); }
textarea.plan-st-title, input.plan-st-title { counter-increment: none; }
textarea.plan-st-title::before, input.plan-st-title::before { content: none; }
/* Slice AI3 — the step's chosen agent. Quiet, because an override is a statement of fact rather than a
   warning: it is the operator exercising a choice, not a problem to fix. */
.plan-st-agent { display: flex; align-items: center; gap: var(--cd-space-3); flex-wrap: wrap; }
.plan-st-agent-kicker {
  font-family: var(--cd-font-mono, var(--mono)); font-size: var(--cd-type-kicker);
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--cd-muted-3);
}
.plan-st-agent-id { font-size: var(--cd-type-meta); color: var(--cd-text-2); }
/* the catalog row while a step is waiting for one — the verb is the difference, not a second list */
.alive-card[data-verb="pick"] { border-color: var(--cd-approval); }

/* ── Slice AI4 / Slice AI9 — the QUESTION band ──────────────────────────────────────────────────────────────
   IN-SURFACE CONTENT, not chrome: nothing here is fixed, so the two top-anchored bands stay two, and nothing
   takes a stacking level — the auth ladder is untouched. Roles only; both themes answer it from the token layer.
   Slice AI9 — RENAMED with the surface. The approval variant went to the card, which is the only surface that
   was ever visible for one; the class names stay anchored to the frozen #blocker-band id, because three names
   for one element is worse than one name that has narrowed.
   THE APPROVAL RULE IS RETAINED DELIBERATELY. `[data-kind="approval"]` can no longer match — showBlocker's
   table has one entry and nothing writes that value — and it is kept as the honest record that this band's
   approval styling is DEAD rather than missing. It costs one declaration and it is what a reader checks when
   asking whether the approval ever had a look of its own. */
.blocker-band {
  display: flex; flex-direction: column; gap: var(--cd-space-3);
  margin: 0 0 var(--cd-space-5); padding: var(--cd-space-5) var(--cd-space-6);
  border: 1px solid var(--cd-line-2); border-left-width: 3px; border-radius: 10px;
  background: var(--cd-surface-1);
}
.blocker-band[data-kind="approval"] { border-left-color: var(--cd-approval); }
.blocker-band[data-kind="clarification"] { border-left-color: var(--cd-chip-attention-text); }
.blocker-head { display: flex; align-items: center; gap: var(--cd-space-4); flex-wrap: wrap; }
.blocker-kind {
  font-size: var(--cd-type-kicker); text-transform: uppercase; letter-spacing: 0.08em;
  padding: 2px var(--cd-space-3); border-radius: 999px;
}
.blocker-band[data-kind="approval"] .blocker-kind { background: var(--cd-approval-chip-bg); color: var(--cd-approval-chip-text); }
.blocker-band[data-kind="clarification"] .blocker-kind { background: var(--cd-chip-attention-bg); color: var(--cd-chip-attention-text); }
.blocker-agent { font-size: var(--cd-type-meta); color: var(--cd-text-2); }
.blocker-depth, .blocker-remaining { font-size: var(--cd-type-kicker); color: var(--cd-muted-3); margin-left: auto; }
.blocker-what { margin: 0; font-size: var(--cd-type-body); color: var(--cd-text-hi); }
/* the command is never truncated — §5's rule, and a band is no different from a card about that */
.blocker-command {
  margin: 0; padding: var(--cd-space-4); border-radius: 8px; background: var(--cd-surface-2);
  font-size: var(--cd-type-meta); color: var(--cd-text); white-space: pre-wrap; overflow-wrap: anywhere; max-height: 40vh; overflow: auto;
}
.blocker-why { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-muted-2); }
/* ── Slice AI11 — the question, and the field that answers it. Roles only, so both themes answer from the
   token layer and nothing here names a colour, a level or a width of its own. The question takes the READING
   treatment the transcript uses (it is agent prose, and it wraps); the choices reuse the existing chip row
   idiom; the field borrows the reply textarea's shape rather than inventing a second one. */
.blocker-question { display: flex; flex-direction: column; gap: var(--cd-space-3); }
.blocker-q { margin: 0; font-size: var(--cd-type-body); color: var(--cd-text); white-space: pre-wrap; overflow-wrap: anywhere; }
.blocker-choices { display: flex; flex-wrap: wrap; gap: var(--cd-space-3); }
.blocker-choices:empty { display: none; }
.blocker-reply-field { display: flex; flex-direction: column; gap: var(--cd-space-2); }
.blocker-reply { width: 100%; box-sizing: border-box; resize: vertical; }
.blocker-reason { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-chip-attention-text); }
.blocker-reason[hidden] { display: none; }
.blocker-acts { display: flex; gap: var(--cd-space-4); flex-wrap: wrap; }
/* Slice AI5 — a step already run, and the pause that named itself. Roles only; both themes answer them. */
.plan-subtask[data-locked="true"] { opacity: 0.72; border-style: dashed; }
.plan-st-locked { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-muted-3); }
.plan-paused { display: flex; flex-direction: column; gap: var(--cd-space-3); align-items: flex-start; }
.plan-paused-what {
  margin: 0; font-size: var(--cd-type-meta); color: var(--cd-chip-attention-text);
  border-left: 2px solid var(--cd-chip-attention-text); padding-left: var(--cd-space-4);
}

/* ── Slice AI6 — deliverables. Roles only; both themes answer them. Nothing here is fixed or takes a level. */
.seq-deliv { margin-top: var(--cd-space-2); }
.seq-deliv > summary { cursor: pointer; font-size: var(--cd-type-meta); color: var(--cd-muted-2); gap: var(--cd-space-2); align-items: center; }
.seq-deliv > summary:hover { color: var(--cd-text-2); }
/* THE RENDER CAUGHT THIS. The global `details summary` rule hides the disclosure marker, so collapsed the row
   read as a static label at the same weight as the state line above it — the file count was there and nothing
   said it could be opened. A caret that turns is the affordance; it rotates rather than swapping glyphs so the
   open and closed states are the same mark in two positions. */
.seq-deliv > summary::before {
  content: '\25B8'; display: inline-block; flex: 0 0 auto;
  transition: transform 120ms ease;
}
.seq-deliv[open] > summary::before { transform: rotate(90deg); }
.seq-deliv-list {
  margin: var(--cd-space-2) 0 0; padding: 0 0 0 var(--cd-space-6); list-style: none;
  display: flex; flex-direction: column; gap: var(--cd-space-1);
  font-size: var(--cd-type-meta); color: var(--cd-text-2); overflow-wrap: anywhere;
}
.seq-deliv-acts { display: flex; flex-direction: column; gap: var(--cd-space-3); align-items: flex-start; margin-top: var(--cd-space-5); }
.seq-deliv-status { margin: 0; font-size: var(--cd-type-meta); color: var(--cd-muted-2); overflow-wrap: anywhere; }
