/* ============================================================================
   FStea AI Cockpit — STANDING TYPE design system
   (docs/module5/STANDING-TYPE-DESIGN.md — the token authority)
   A typeset intelligence dossier: serif = what the machine claims, sans = the
   interface's own voice, mono ledger = what was measured or spent. One working
   accent (steeped-leaf green), cinnabar ONLY for refusals/hard limits, copper
   for money. All pre-existing token NAMES are preserved so every page keeps
   rendering; new namespaces are additive (--ev-*, --spend-*, --armed-*,
   --vintage-*, --seal-*, --fs-*, --sp-*, serif). Light + dark.
   ========================================================================== */

/* Three vendored faces (OFL; latin subsets — zh text deliberately falls to system
   PingFang/YaHei: LLM output has an unbounded glyph repertoire, so a vendored
   CJK subset would silently drop glyphs). Served from public/fonts/. */
@font-face { font-family:"IBM Plex Sans"; src:url("/fonts/IBMPlexSans-Variable.woff2") format("woff2"); font-weight:100 700; font-display:swap; }
@font-face { font-family:"IBM Plex Mono"; src:url("/fonts/IBMPlexMono-Regular.woff2") format("woff2"); font-weight:400; font-display:swap; }
@font-face { font-family:"IBM Plex Mono"; src:url("/fonts/IBMPlexMono-Medium.woff2") format("woff2"); font-weight:500 600; font-display:swap; }

:root {
  /* ---- paper: celadon-leaning neutral ramp ---- */
  --n-0:#FDFDFB; --n-25:#FAFBF7; --n-50:#F5F7F1; --n-100:#EEF1E9; --n-150:#E3E8DE;
  --n-200:#D6DCD0; --n-300:#C2CABB; --n-400:#97A294; --n-500:#6E7A70; --n-600:#535E55;
  --n-700:#3B453E; --n-800:#272E29; --n-900:#1C231E; --n-950:#12170F;

  --bg:var(--n-50); --surface:var(--n-0); --surface-2:var(--n-25); --sunken:var(--n-100);
  --border:var(--n-150); --border-strong:var(--n-200);
  --text:var(--n-900); --text-muted:#46514A; --text-faint:#59645B; /* darkened: AA with margin */
  --ink:var(--n-900); --ink-muted:#46514A; --ink-faint:#59645B;
  --hairline:var(--n-150);
  --rule-strong:var(--n-900); /* the ONE full-ink rule under each page masthead */

  /* ---- working accent: steeped-leaf green — actions only ---- */
  --accent:#2E5C48; --accent-hover:#264D3C; --accent-press:#1F4032;
  --accent-soft:#E4EEE6; --accent-soft-2:#D3E3D7; --accent-text:#2A523F;
  --accent-ring:rgba(46,92,72,.30); --on-accent:#F5F7F1; --accent-2:#4E7D6B;

  /* ---- the seal: cinnabar — refusals, quarantine, hard limits ONLY ---- */
  --seal:#B2402C; --seal-soft:#F7E8E2; --seal-text:#9A3421;

  /* ---- evidence ladder: shape primary, ink density secondary ---- */
  --ev-observed:#1C4A35;   --ev-observed-soft:#DFEBE2;
  --ev-supported:#4E7A63;  --ev-supported-soft:#E6EFE7;
  --ev-hypothesis:#68746C; --ev-hypothesis-soft:#ECEFEA;
  --ev-assumption:#8A857A; --ev-assumption-border:#A9A499; /* dashed outline, NEVER filled */
  --ev-refused:var(--seal); --ev-refused-soft:var(--seal-soft);

  /* ---- judgment/inference: ONE purple app-wide (matches .vault-judgment) ---- */
  --purple:#6E5794; --purple-soft:#EEEAF4; --purple-text:#59446E;

  /* ---- money: one copper family, two intensities ---- */
  --spend-ink:#8A5230; --spend-soft:#F5EBE1;              /* calm ledger: disclosed + spent  */
  --armed:#B4511C; --armed-hover:#9E4617; --armed-press:#8A3D13;
  --armed-soft:#F8EADF; --armed-text:#93400F; --armed-ring:rgba(180,81,28,.32);

  /* ---- vintage (data age) ---- */
  --vintage-ink:var(--ink-faint); --vintage-stale:#A06F1F; --vintage-stale-soft:#F6EDD8;

  /* ---- semantic (kept for existing call sites, re-quieted) ---- */
  --ok:#2E6B4F; --ok-soft:#E2EEE5; --ok-text:#27573F;
  --warn:#A06F1F; --warn-soft:#F6EDD8; --warn-text:#7F5714;
  --danger:var(--seal); --danger-soft:var(--seal-soft); --danger-text:var(--seal-text);
  --info:#3E5F8A; --info-soft:#E7EDF4; --info-text:#35507A;
  --chart-grid:var(--n-150);

  /* ---- elevation: paper sits flat; hairlines divide ---- */
  --shadow-sm:0 1px 2px rgba(28,35,30,.04);
  --shadow:0 1px 2px rgba(28,35,30,.05);
  --shadow-md:0 1px 0 rgba(28,35,30,.05), 0 6px 20px rgba(28,35,30,.07); /* menus/popovers */
  --shadow-lg:0 24px 60px rgba(18,23,15,.22);                            /* modals only   */

  /* ---- radii: square is a reading, round is a control ---- */
  --r-xs:3px; --r-sm:5px; --r-md:7px; --r-lg:10px; --r-xl:12px; --r-pill:999px;

  /* ---- type: the three voices ---- */
  /* One family (operator ruling 2026-08-24): claims wear the interface face.
     The token survives as an alias so every usage site keeps its role name. */
  --font-serif:var(--font);
  --font:"IBM Plex Sans","SF Pro Text",-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",system-ui,sans-serif;
  --mono:"IBM Plex Mono","SF Mono",ui-monospace,Menlo,"PingFang SC","Microsoft YaHei",monospace;

  --fs-hero:30px; --fs-title:22px; --fs-section:17px;
  --fs-prose:15px; --fs-ui:13.5px; --fs-data:12.5px; --fs-caption:11.5px; --fs-micro:10px;
  --lh-prose:1.68; --lh-ui:1.5; --lh-caption:1.45; --lh-zh:1.78;
  --track-caps:.08em; --track-caps-wide:.14em;
  --measure:68ch;       /* dossier prose column */
  --measure-note:44ch;  /* footings and marginal notes */

  /* ---- spacing rhythm ---- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:20px; --sp-6:24px; --sp-7:32px; --sp-8:48px;

  /* ---- layout + z ladder (topbar 30, sidebar 40, toast 200 are existing facts) ---- */
  --sidebar-w:250px; --sidebar-collapsed:68px; --topbar-h:58px; --container:1280px;
  --footing-indent:24px;
  --z-armed:20; /* armed strip sits under the topbar, over content, under toasts */

  /* ---- motion: print doesn't fidget ---- */
  --ease:cubic-bezier(.4,0,.2,1); --ease-out:cubic-bezier(.16,1,.3,1);
  --dur:120ms; --dur-2:220ms;
}

[data-theme="dark"] { /* the reading room at night: green-black paper, warm ink, no neon */
  --n-0:#171C15; --n-25:#1B211A; --n-100:#20261F; --n-150:#2A3128; --n-200:#363E34;
  --n-300:#434C41; --n-400:#5F695C;
  --bg:#10140F; --surface:#171C15; --surface-2:#1B211A; --sunken:#20261F;
  --border:#2A3128; --border-strong:#363E34;
  --text:#E8ECE3; --text-muted:#A8B2A4; --text-faint:#8A958A;
  --ink:#E8ECE3; --ink-muted:#A8B2A4; --ink-faint:#8A958A;
  --hairline:#2A3128; --rule-strong:#E8ECE3;
  --accent:#7FB899; --accent-hover:#8FC5A7; --accent-press:#6FA98A;
  --accent-soft:#1E2B23; --accent-soft-2:#26382D; --accent-text:#93C7AB;
  --accent-ring:rgba(127,184,153,.32); --on-accent:#10140F; --accent-2:#6FA98C;
  --seal:#D96A50; --seal-soft:#33201A; --seal-text:#E68D74;
  --ev-observed:#93C7AB;  --ev-observed-soft:#1E2B23;
  --ev-supported:#74A88C; --ev-supported-soft:#1C271F;
  --ev-hypothesis:#8B958D; --ev-hypothesis-soft:#222823;
  --ev-assumption:#9A9486; --ev-assumption-border:#6A655B;
  --ev-refused:var(--seal); --ev-refused-soft:var(--seal-soft);
  --purple:#9C86BF; --purple-soft:#262031; --purple-text:#B3A2D1;
  --spend-ink:#D89A6A; --spend-soft:#2E2318;
  --armed:#E07B3C; --armed-hover:#EA8A50; --armed-press:#D06E30;
  --armed-soft:#332215; --armed-text:#F0A374; --armed-ring:rgba(224,123,60,.35);
  --vintage-stale:#C49A58; --vintage-stale-soft:#2E271A;
  --ok:#74A88C; --ok-soft:#1C271F; --ok-text:#93C7AB;
  --warn:#C49A58; --warn-soft:#2E271A; --warn-text:#D9B379;
  --danger:var(--seal); --danger-soft:var(--seal-soft); --danger-text:var(--seal-text);
  --info:#7C99C4; --info-soft:#1D2430; --info-text:#9DB4D9;
  --chart-grid:#2A3128;
  --shadow-sm:0 1px 2px rgba(0,0,0,.3); --shadow:0 1px 3px rgba(0,0,0,.35);
  --shadow-md:0 6px 20px rgba(0,0,0,.5); --shadow-lg:0 24px 60px rgba(0,0,0,.6);
}

/* Bilingual guard: caps-tracking is a Latin device. i18n.js already sets
   document.documentElement.lang, so these are additive and land today.
   Mono ID/ledger spans must carry lang="en" so machine text keeps its tracking. */
:lang(zh-CN) { letter-spacing:0; }
:lang(zh-CN) body, :lang(zh-CN) p, :lang(zh-CN) .pv-val { line-height:var(--lh-zh); }
:lang(zh-CN) h1, :lang(zh-CN) .page-header h1, :lang(zh-CN) .panel-title,
:lang(zh-CN) .stat .stat-value, :lang(zh-CN) .concept .c-top h3 { letter-spacing:normal; }
:lang(zh-CN) .caps-label, :lang(zh-CN) .tag { text-transform:none; letter-spacing:.02em; font-weight:650; }

* { box-sizing:border-box; margin:0; padding:0; }
html,body { height:100%; }
body {
  font-family:var(--font); font-size:var(--fs-ui); line-height:1.55; color:var(--text);
  background:var(--bg); -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  font-feature-settings:"cv05","ss01","tnum" 0;
}
body.no-scroll { overflow:hidden; }
::selection { background:var(--accent-soft-2); }
a { color:var(--accent-text); text-decoration:none; }
button { font-family:inherit; cursor:pointer; color:inherit; }
.ic { flex-shrink:0; vertical-align:middle; }

/* universal keyboard focus ring (premium tell: visible on :focus-visible only) */
:focus-visible { outline:none; box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); border-radius:var(--r-xs); }
.nav-item:focus-visible, .chip:focus-visible, .tab:focus-visible, .seg:focus-visible, .model-card:focus-visible, .cmdk-item:focus-visible { box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
a:focus-visible, button:focus-visible { outline:none; }
.tnum { font-variant-numeric:tabular-nums; }
.mono { font-family:var(--mono); }
.muted { color:var(--text-muted); }
.faint { color:var(--text-faint); }

/* scrollbars */
*::-webkit-scrollbar { width:10px; height:10px; }
*::-webkit-scrollbar-thumb { background:var(--border-strong); border-radius:99px; border:3px solid var(--bg); }
*::-webkit-scrollbar-thumb:hover { background:var(--n-400); }

/* ============================ App shell ============================ */
#app, .app { display:flex; min-height:100vh; }

.sidebar {
  width:var(--sidebar-w); flex-shrink:0; background:var(--surface); border-right:1px solid var(--border);
  position:sticky; top:0; height:100vh; display:flex; flex-direction:column; transition:width var(--dur-2) var(--ease-out); z-index:40;
}
.sidebar.collapsed { width:var(--sidebar-collapsed); }
/* THE RAIL'S ONE MOTION. Collapse and expand are the width transition above,
   and .main is a flex sibling, so the content shift is that same 220ms — one
   curve, not two. The labels ride BEHIND it: on expand they fade in only
   once the rail has most of its width back, on collapse they are gone before
   the rail is narrow enough to clip a word. The icon column never moves
   (see .nav-item below), so a pill collapses to its mark without a jump.
   Reduced motion makes every one of these an instant switch — the rule sits
   after the phone drawer below, which is the same rail sliding on `left`. */
.sb-logo { display:flex; align-items:center; gap:10px; padding:0 14px; height:var(--topbar-h); border-bottom:1px solid var(--border); position:relative; }
/* ---- THE VESSEL: the shell's generation mark ----------------------------- */
/* The same steeping bowl THE STEEP draws on every Module 5 page (.m5-vessel),
   quoted at 32×32: an open-top bowl, an HTML fill rising from the foot, SVG
   steam above the rim. Two bits from generationBus: steam = the Director
   answering (--accent); liquid = Module 5 steeping (--armed, the second armed
   moment LINE-AND-STEEP §2 already named). The fill is an HTML box so the
   existing m5-steep keyframes actually rise, and the meniscus rule carries
   the state in grayscale; colour is redundant. Idle is a designed state: a
   dashed, empty bowl. No new tokens. */
.sidebar, .sb-logo { overflow:visible; }
.v-well { display:inline-flex; align-items:center; gap:10px; min-width:44px; min-height:44px; padding:5px 6px; width:100%; background:none; border:0; font:inherit; color:inherit; text-align:left; cursor:pointer; }
.v-mark { width:32px; height:32px; flex:none; display:grid; grid-template-rows:10px 22px; place-items:center; }
.v-steam { display:block; width:32px; height:10px; }
.v-bowl { position:relative; display:block; width:20px; height:22px; border:1.5px solid var(--border-strong); border-top-width:0; border-radius:0 0 var(--r-sm) var(--r-sm); background:var(--surface-2); overflow:hidden; }
.v-fill { position:absolute; left:0; right:0; bottom:0; height:0; }
.v-well[data-gen="idle"] .v-steam { visibility:hidden; }
.v-well[data-gen="idle"] .v-bowl { border-style:dashed; border-color:var(--ev-assumption-border); }
.v-well[data-gen="idle"] .v-fill { height:0; }
.v-well[data-gen="director"] .v-steam { visibility:visible; }
.v-well[data-gen="director"] .v-bowl { border-style:solid; border-color:var(--accent); }
.v-well[data-gen="director"] .v-fill { height:0; }
.v-well[data-gen="director"] .v-steam path { animation:v-steam 2.4s var(--ease) infinite; }
.v-well[data-gen="m5"] .v-steam { visibility:hidden; }
.v-well[data-gen="m5"] .v-bowl { border-style:solid; border-color:var(--armed); }
.v-well[data-gen="m5"] .v-fill,
.v-well[data-gen="both"] .v-fill { height:52%; border-top:1.5px solid var(--armed); background-image:repeating-linear-gradient(135deg, var(--armed-soft) 0 3px, transparent 3px 6px); animation:m5-steep 2.4s var(--ease) infinite; }
.v-well[data-gen="both"] .v-steam { visibility:visible; }
.v-well[data-gen="both"] .v-bowl { border-style:solid; border-color:var(--armed); }
.v-well[data-gen="both"] .v-steam path { animation:v-steam 2.4s var(--ease) infinite; }
@keyframes v-steam { 0%,100% { opacity:.45; } 50% { opacity:1; } }
/* Reduced motion freezes the drawing; it never empties the bowl. */
@media (prefers-reduced-motion: reduce) {
  /* Same specificity as the state rules above and later in the sheet, so the
     freeze wins; a bare .v-well .v-fill would lose to .v-well[data-gen] .v-fill. */
  .v-well[data-gen] .v-fill, .v-well[data-gen] .v-steam path { animation:none; }
  .v-well[data-gen="m5"] .v-fill, .v-well[data-gen="both"] .v-fill { height:52%; }
}
.v-copy { min-width:0; }
.v-k { display:block; font-size:var(--fs-micro); font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--text-faint); }
.v-v { display:block; font-size:var(--fs-caption); font-weight:600; color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.v-well[data-gen="idle"] .v-v { color:var(--text-muted); font-weight:500; }
/* Collapsed: mark only, the 44px target centred in the 68px rail. The box is
   stated as 44×44 outright rather than left to the min-height above: the
   32px mark is what the eye sees, the 44px button is what the finger hits. */
.sidebar.collapsed .sb-logo { padding:0 12px; }
.sidebar.collapsed .v-well { width:44px; height:44px; justify-content:center; padding:5px 0; gap:0; }
.sidebar.collapsed .v-copy { display:none; }
/* The panel sits inside the rail's width so a 250px rail never spills it into
   the page title; from the collapsed rail it may extend into main. */
.v-pop { position:absolute; top:calc(100% + 6px); left:10px; z-index:60; width:calc(var(--sidebar-w) - 20px); background:var(--surface); border:1px solid var(--border-strong); border-radius:var(--r-md); box-shadow:var(--shadow-md); padding:10px 12px; }
.v-pop[hidden] { display:none; }
.v-pop h4 { font-size:var(--fs-micro); letter-spacing:.08em; text-transform:uppercase; color:var(--text-faint); margin:0 0 8px; }
/* Standing Type law 9: caps-tracking is a Latin device. The shell kicker, the
   popover heading and its status readouts, and the nav section labels are
   micro-caps like every other label here, so under zh they take the same
   .02em / no-transform reset the .caps-label and .ter-* labels already take. */
:lang(zh-CN) .v-k, :lang(zh-CN) .v-pop h4, :lang(zh-CN) .v-pop .st, :lang(zh-CN) .nav-section { text-transform:none; letter-spacing:.02em; }
.v-row { display:flex; justify-content:space-between; gap:8px; padding:6px 0; border-top:1px solid var(--border); font-size:var(--fs-data); }
.v-row:first-of-type { border-top:0; }
.v-row .st { font-size:var(--fs-micro); font-weight:600; letter-spacing:.06em; text-transform:uppercase; }
.v-row .st.live { color:var(--ok-text); }
.v-row .st.idle { color:var(--text-faint); }
.v-pop .btn { width:100%; margin-top:8px; justify-content:center; }

/* ---- THE NAV: wide pills, stacked from the top ------------------------- */
/* Groups stack under the vessel with one fixed 12px gap between them and the
   slack falls to the bottom above the footer — never spread between groups,
   which is what made four groups look like four islands. Each destination is
   one full-width pill: 40px tall, an 8px inset off the rail's edges, the mark
   on a fixed 16px column 22px in from the rail so the label starts on one
   line down the whole rail, and the group heading sits on that same line. */
.sb-nav { padding:10px 0 16px; overflow-y:auto; overflow-x:hidden; flex:1; min-height:0; display:flex; flex-direction:column; gap:12px; }
.nav-group { display:flex; flex-direction:column; gap:2px; }
.nav-section { box-sizing:border-box; height:24px; padding:6px 22px 4px; font-size:var(--fs-micro); line-height:14px; font-weight:600; text-transform:uppercase; letter-spacing:.09em; color:var(--text-faint); white-space:nowrap; overflow:hidden;
  transition:height var(--dur-2) var(--ease-out), padding var(--dur-2) var(--ease-out), opacity 120ms var(--ease-out) 100ms; }
.nav-item {
  display:grid; grid-template-columns:16px minmax(0,1fr); grid-template-rows:18px; column-gap:10px; align-items:center;
  margin:0 8px; padding:11px 14px; border-radius:var(--r-pill); color:var(--text-muted);
  cursor:pointer; position:relative; overflow:hidden; white-space:nowrap;
  transition:background var(--dur) var(--ease), color var(--dur) var(--ease), column-gap var(--dur-2) var(--ease-out);
}
/* Hover is the active ground at reduced strength, so the two read as one
   family; the neutral fill is the fallback for a browser without color-mix. */
.nav-item:hover { background:var(--sunken); background:color-mix(in srgb, var(--accent-soft) 55%, transparent); color:var(--text); }
.nav-item.active { background:var(--accent-soft); color:var(--ink); font-weight:600; }
.nav-item .nav-ic { grid-row:1; grid-column:1; width:16px; height:16px; display:inline-flex; }
.nav-item .nav-txt { grid-row:1; grid-column:2; min-width:0; font-size:var(--fs-ui); line-height:18px; overflow:hidden; text-overflow:ellipsis; transition:opacity 120ms var(--ease-out) 100ms, transform 180ms var(--ease-out); }
.nav-item .nav-badge { font-size:var(--fs-micro); font-weight:600; letter-spacing:.04em; padding:1px 5px; border-radius:5px; background:var(--accent-soft-2); color:var(--accent-text); }
/* THE PILL OPENS — INSIDE ITS OWN 40px. The description is an absolutely
   positioned layer at the foot of the pill, on the label's column, hidden
   at rest (opacity 0, 4px low) and slid up into place under the pointer or
   keyboard focus on one 180ms ease-out while the label lifts 7px to make the
   room: a 4px + 18px label + 14px description + 4px stack, all of it inside
   the pill's own box. The pill's height never changes, so NO SIBLING MOVES —
   the earlier build grew the pill 40 → 58px and pushed every pill beneath it
   down while the pointer was mid-scan, so the target under the cursor kept
   changing. And because the layer never leaves the pill, it cannot clip at
   the rail's bottom edge or run under the footer. The description is a
   single line — caption size, muted, ellipsized past the label column — and
   it is the link's accessible description whether or not it is showing. */
.nav-item .nav-desc { position:absolute; left:40px; right:14px; bottom:4px; overflow:hidden; text-overflow:ellipsis;
  font-size:var(--fs-caption); line-height:14px; font-weight:400; color:var(--text-muted); pointer-events:none;
  opacity:0; transform:translateY(4px); transition:opacity 120ms var(--ease-out), transform 180ms var(--ease-out); }
.nav-item:hover .nav-txt, .nav-item:focus-visible .nav-txt { transform:translateY(-7px); }
.nav-item:hover .nav-desc, .nav-item:focus-visible .nav-desc { opacity:1; transform:none; transition-delay:40ms, 0ms; }
/* A screen whose primary input cannot hover gets no open-on-hover — a tap
   would leave the pill stuck open on its way to the page — and reads the
   description in the pill's title instead. Keyboard focus still opens it:
   :focus-visible is a keyboard signal wherever it fires. */
@media (hover: none) {
  .nav-item:hover .nav-txt { transform:none; }
  .nav-item:hover .nav-desc { opacity:0; transform:translateY(4px); }
  .nav-item:focus-visible .nav-txt { transform:translateY(-7px); }
  .nav-item:focus-visible .nav-desc { opacity:1; transform:none; }
}
/* Collapsed: the 52px pill that is left inside the 68px rail is exactly the
   mark's 16px plus its 14px padding either side, so the mark stays on the
   column it had. The label keeps its box (a display switch cannot fade) and
   goes to zero width behind the shrinking rail; the heading folds to a 12px
   gap so the groups still read as groups. The description layer stays shut
   in the icon-only rail — there is no label for it to sit under — and the
   pill's title carries it as the tooltip. */
.sidebar.collapsed .nav-section { height:12px; padding:0 22px; opacity:0; transition:height var(--dur-2) var(--ease-out), padding var(--dur-2) var(--ease-out), opacity 80ms var(--ease-out); }
.sidebar.collapsed .nav-item { column-gap:0; }
.sidebar.collapsed .nav-txt { opacity:0; transform:none; transition:opacity 80ms var(--ease-out); }
.sidebar.collapsed .nav-desc { opacity:0; transform:translateY(4px); }
.sidebar.collapsed .nav-badge { display:none; }

.ter-steps { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:6px; margin:0 0 14px; padding:0; list-style:none; }
.ter-steps li { margin:0; padding:8px 10px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--surface); font-size:var(--fs-caption); color:var(--text-muted); }
.ter-steps li b { display:block; font-size:var(--fs-micro); letter-spacing:.08em; text-transform:uppercase; color:var(--text-faint); }
.ter-help summary, .ter-var-summary { cursor:pointer; padding:12px 14px; font-weight:600; }
@media (max-width: 1100px) { .ter-steps { grid-template-columns:1fr 1fr; } }
.fbk-pick { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:8px; margin:0 0 14px; }
/* The date field's own error, shown on blur/change (pages/feedback.js). */
.fbk-field-error { margin-top:6px; font-size:var(--fs-caption); color:var(--danger-text); }
.fbk-field-error[hidden] { display:none; }
.field input[aria-invalid="true"] { border-color:var(--danger); }
.fbk-pick-card { text-align:left; font:inherit; color:inherit; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md); padding:10px 12px; cursor:pointer;
  min-width:0; overflow-wrap:anywhere; display:flex; flex-direction:column; gap:2px; }
.fbk-pick-name { font-weight:600; line-height:1.35; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.fbk-pick-meta { font-size:var(--fs-caption); color:var(--text-faint); }
.fbk-target { margin-bottom:6px; min-width:0; }
.fbk-rec-id { display:block; font-size:var(--fs-caption); font-weight:400; color:var(--text-faint); }
.fbk-pick-card.sel { border-color:var(--ink); box-shadow:inset 0 0 0 1px var(--ink); }
@media (max-width: 900px) { .fbk-pick { grid-template-columns:1fr 1fr; } }
@media (max-width: 520px) { .fbk-pick { grid-template-columns:1fr; } }
.sb-footer { border-top:1px solid var(--border); padding:12px 14px; }
.sb-user { display:flex; align-items:center; gap:10px; }
.sb-user .avatar { width:32px; height:32px; border-radius:50%; background:var(--accent-soft); color:var(--accent-text); display:flex; align-items:center; justify-content:center; font-weight:600; font-size:var(--fs-caption); flex-shrink:0; }
.sb-user .uinfo { overflow:hidden; }
.sb-user .uinfo b { font-size:var(--fs-data); display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sb-user .uinfo span { font-size:var(--fs-caption); color:var(--text-faint); display:flex; align-items:center; gap:4px; }
.sb-user .uinfo .dot { width:6px; height:6px; border-radius:50%; background:var(--ok); box-shadow:0 0 0 3px var(--ok-soft); }
.sidebar.collapsed .uinfo { display:none; }

.main { flex:1; min-width:0; display:flex; flex-direction:column; }

.topbar { height:var(--topbar-h); display:flex; align-items:center; gap:12px; padding:0 22px; background:color-mix(in srgb,var(--surface) 86%,transparent); backdrop-filter:saturate(1.4) blur(10px); border-bottom:1px solid var(--border); position:sticky; top:0; z-index:30; }
.crumbs { display:flex; align-items:center; gap:7px; font-size:var(--fs-ui); min-width:0; }
.crumbs .c-root { color:var(--text-faint); }
.crumbs .c-sep { color:var(--text-faint); display:flex; }
.crumbs .c-cur { font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.topbar .spacer { flex:1; }
.tb-actions { display:flex; align-items:center; gap:8px; }

.icon-btn { width:34px; height:34px; border-radius:var(--r-sm); border:1px solid transparent; background:transparent; color:var(--text-muted); display:inline-flex; align-items:center; justify-content:center; transition:var(--dur); }
.icon-btn:hover { background:var(--sunken); color:var(--text); }
/* Operator sign-in state on the top-bar lock. Accent-on means a key is held, so
   the cockpit's ONE credential is visible at a glance rather than only
   discoverable by clicking. */
.icon-btn.is-on { color:var(--accent-text); border-color:var(--accent); background:var(--accent-soft); }
.cmdk-trigger { display:inline-flex; align-items:center; gap:8px; height:34px; padding:0 10px 0 12px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--surface-2); color:var(--text-faint); font-size:var(--fs-data); transition:var(--dur); }
.cmdk-trigger:hover { border-color:var(--border-strong); color:var(--text-muted); }
.cmdk-trigger .kbd { display:inline-flex; gap:1px; }
.kbd kbd, .kbd-key { font-family:var(--mono); font-size:var(--fs-micro); background:var(--surface); border:1px solid var(--border); border-bottom-width:2px; border-radius:5px; padding:1px 5px; color:var(--text-muted); }
.seg-tb { display:inline-flex; background:var(--sunken); border-radius:var(--r-sm); padding:3px; }
.seg-tb button { border:0; background:transparent; padding:5px 11px; font-size:var(--fs-data); font-weight:600; color:var(--text-muted); border-radius:6px; transition:var(--dur); }
.seg-tb button.active { background:var(--surface); color:var(--text); box-shadow:var(--shadow-sm); }

.content { padding:26px 28px 80px; width:100%; max-width:var(--container); margin:0 auto; }

/* ============================ Page header ============================ */
.page-header { display:flex; align-items:flex-end; gap:16px; margin-bottom:22px; }
.page-header .ph-text { flex:1; min-width:0; }
.page-header h1 { font:600 var(--fs-hero)/1.2 var(--font-serif); letter-spacing:-.015em; }
.page-header .subtitle { color:var(--text-muted); font-size:var(--fs-ui); margin-top:3px; }
.page-actions { display:flex; gap:8px; align-items:center; flex-wrap:wrap; }

/* ============================ Panels / cards ============================ */
.panel { background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); box-shadow:var(--shadow-sm); margin-bottom:18px; }
.panel-header { display:flex; align-items:center; gap:12px; padding:15px 18px; border-bottom:1px solid var(--border); }
.panel-header .panel-title { font-size:var(--fs-ui); font-weight:600; letter-spacing:-.01em; }
.panel-header .panel-sub { font-size:var(--fs-caption); color:var(--text-faint); }
.panel-header .spacer { flex:1; }
.panel-body { padding:18px; }
.panel-body.flush { padding:0; }
.panel-note { font-size:var(--fs-caption); color:var(--text-faint); padding:12px 18px; border-top:1px solid var(--border); display:flex; gap:7px; align-items:flex-start; }

.grid { display:grid; gap:16px; margin-bottom:18px; }
.cols-2{grid-template-columns:repeat(2,1fr);} .cols-3{grid-template-columns:repeat(3,1fr);}
.cols-4{grid-template-columns:repeat(4,1fr);} .cols-5{grid-template-columns:repeat(5,1fr);}
.span-2{grid-column:span 2;} .span-3{grid-column:span 3;}
.grid.align-start{ align-items:start; }
.model-grid{ display:grid; grid-template-columns:repeat(auto-fill,minmax(186px,1fr)); gap:12px; }
@media (max-width:680px){ .model-grid{grid-template-columns:1fr 1fr;} }
@media (max-width:1100px){ .cols-4,.cols-5{grid-template-columns:repeat(2,1fr);} .cols-3{grid-template-columns:repeat(2,1fr);} .span-2,.span-3{grid-column:span 2;} }
@media (max-width:680px){ .grid[class*="cols-"]{grid-template-columns:1fr;} .span-2,.span-3{grid-column:span 1;} }

/* ============================ Stat cards ============================ */
.stat { background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); padding:16px 18px; box-shadow:var(--shadow-sm); position:relative; overflow:hidden; }
.stat .stat-top { display:flex; align-items:center; gap:8px; }
.stat .stat-ic { width:30px; height:30px; border-radius:8px; background:var(--accent-soft); color:var(--accent-text); display:flex; align-items:center; justify-content:center; }
.stat .stat-label { font-size:var(--fs-caption); color:var(--text-muted); font-weight:600; letter-spacing:.01em; }
.stat .stat-value { font-size:var(--fs-title); font-weight:600; letter-spacing:-.02em; margin-top:10px; font-variant-numeric:tabular-nums; line-height:1.05; }
.stat .stat-foot { display:flex; align-items:center; justify-content:space-between; margin-top:6px; }
.delta { display:inline-flex; align-items:center; gap:3px; font-size:var(--fs-caption); font-weight:600; font-variant-numeric:tabular-nums; }
.delta.up{ color:var(--ok-text); } .delta.down{ color:var(--danger-text); } .delta.flat{ color:var(--text-faint); }
.stat .stat-spark { position:absolute; right:14px; bottom:12px; opacity:.9; }

/* ============================ Tables ============================ */
.table-wrap { overflow-x:auto; }
table.table { width:100%; border-collapse:collapse; font-size:var(--fs-data); }
.table thead th { text-align:left; font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:.06em; color:var(--text-faint); padding:10px 14px; background:var(--surface-2); border-bottom:1px solid var(--border); white-space:nowrap; position:sticky; top:0; z-index:1; }
.table thead th.sortable { cursor:pointer; user-select:none; }
.table thead th.sortable:hover { color:var(--text-muted); }
.table thead th .sort-ar { opacity:.5; margin-left:3px; }
.table tbody td { padding:11px 14px; border-bottom:1px solid var(--border); vertical-align:middle; }
.table tbody tr:last-child td { border-bottom:0; }
.table tbody tr { transition:background var(--dur); }
.table tbody tr:hover td { background:var(--surface-2); }
.table td.num, .table th.num { text-align:right; font-variant-numeric:tabular-nums; }
.table td.tnum { white-space:nowrap; }
.table .row-link { cursor:pointer; }
.table .t-strong { font-weight:600; }
.table .t-sub { font-size:var(--fs-caption); color:var(--text-muted); margin-top:1px; }
.cell-id { font-family:var(--mono); font-size:var(--fs-caption); color:var(--text-faint); white-space:nowrap; }

/* ============================ Badges / pills / dots ============================ */
.badge { display:inline-flex; align-items:center; gap:5px; padding:2px 9px; border-radius:var(--r-pill); font-size:var(--fs-caption); font-weight:600; line-height:1.5; background:var(--sunken); color:var(--text-muted); white-space:nowrap; }
.badge.ok{background:var(--ok-soft);color:var(--ok-text);} .badge.warn{background:var(--warn-soft);color:var(--warn-text);}
.badge.danger,.badge.no{background:var(--danger-soft);color:var(--danger-text);} .badge.info{background:var(--info-soft);color:var(--info-text);}
.badge.purple,.badge.pu{background:var(--purple-soft);color:var(--purple-text);} .badge.accent{background:var(--accent-soft);color:var(--accent-text);}
.badge.neutral,.badge.muted{background:var(--sunken);color:var(--text-muted);}
.badge .bdot{ width:6px; height:6px; border-radius:50%; background:currentColor; }
.badge.outline{ background:transparent; box-shadow:inset 0 0 0 1px var(--border-strong); color:var(--text-muted); }
.grade { font-weight:600; letter-spacing:.02em; }

/* ============================ Buttons ============================ */
.btn { display:inline-flex; align-items:center; justify-content:center; gap:7px; height:36px; padding:0 14px; border-radius:var(--r-sm); font-size:var(--fs-ui); font-weight:600; border:1px solid transparent; transition:var(--dur); white-space:nowrap; }
.btn:focus-visible { outline:none; box-shadow:0 0 0 3px var(--accent-ring); }
.btn .ic { width:16px; height:16px; }
.btn-primary { background:var(--accent); color:var(--on-accent); border-color:var(--accent); }
.btn-primary:hover { background:var(--accent-hover); border-color:var(--accent-hover); }
.btn-primary:active { background:var(--accent-press); }
.btn-secondary { background:var(--surface); color:var(--text); border-color:var(--border-strong); box-shadow:var(--shadow-sm); }
.btn-secondary:hover { background:var(--surface-2); border-color:var(--n-300); }
.btn-ghost { background:transparent; color:var(--text-muted); }
.btn-ghost:hover { background:var(--sunken); color:var(--text); }
.btn-ghost.is-on { color:var(--accent-text); }
.btn-subtle { background:var(--accent-soft); color:var(--accent-text); }
.btn-subtle:hover { background:var(--accent-soft-2); }
.btn-danger { background:var(--surface); color:var(--danger-text); border-color:var(--border-strong); }
.btn-danger:hover { background:var(--danger-soft); border-color:var(--danger); }
.btn-sm { height:30px; padding:0 11px; font-size:var(--fs-data); border-radius:var(--r-xs); }
.btn-sm .ic { width:14px; height:14px; }
.btn:disabled { opacity:.5; cursor:not-allowed; }
.btn-row { display:flex; gap:8px; flex-wrap:wrap; }
.btn-row.nowrap { flex-wrap:nowrap; gap:6px; }
.btn.btn-icon { padding:0; width:30px; flex-shrink:0; }
.btn-icon-only { width:36px; padding:0; }

/* ============================ Chips ============================ */
.chip-group { display:flex; flex-wrap:wrap; gap:7px; min-width:0; }
.chip { display:inline-flex; align-items:center; gap:6px; padding:5px 11px; border-radius:var(--r-pill); font-size:var(--fs-data); font-weight:600; background:var(--surface); border:1px solid var(--border-strong); color:var(--text-muted); cursor:pointer; user-select:none; transition:var(--dur); max-width:100%; min-width:0; overflow-wrap:anywhere; text-align:left; }
.chip:hover { border-color:var(--n-300); color:var(--text); }
.chip.active { background:var(--accent); border-color:var(--accent); color:var(--on-accent); }
.chip .chip-count { font-size:var(--fs-micro); font-weight:600; padding:0 6px; border-radius:99px; background:var(--sunken); color:var(--text-muted); }
.chip.active .chip-count { background:rgba(255,255,255,.22); color:#fff; }

/* ============================ Tabs / segmented ============================ */
/* ONE tab primitive for every element that wears it — <div>, <span> AND
   <button>. The reset below is load-bearing: a <button class="tab"> without it
   arrives in the UA's own grey chrome, so every tab in the bar reads as
   pressed and none of them as the active one (the Feedback tab bar, FS
   Improvement Notes 2026-09-22). The bar's rule is an inset shadow rather than
   a border so it can scroll sideways on a phone without clipping the active
   underline. Regression: test/uiPrimitives.test.js. */
.tabs { display:flex; gap:2px; box-shadow:inset 0 -1px 0 var(--border); margin-bottom:18px; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; max-width:100%; }
.tabs::-webkit-scrollbar { display:none; }
.tab { appearance:none; -webkit-appearance:none; background:none; border:0; border-radius:0; border-bottom:2px solid transparent; font-family:inherit; line-height:1.4;
  display:inline-flex; align-items:center; gap:5px; flex-shrink:0; white-space:nowrap;
  padding:10px 16px; font-size:var(--fs-ui); font-weight:600; color:var(--text-muted); cursor:pointer; transition:var(--dur); }
.tab:hover { color:var(--text); background:none; }
.tab.active { color:var(--accent-text); border-bottom-color:var(--accent); }
/* At phone width a tab bar WRAPS rather than scrolling out of sight (QA D1:
   "Launch Feedback" was clipped at 390px with no scroll affordance). Tabs
   share each row, and every label stays whole. */
@media (max-width:600px) {
  .tabs { flex-wrap:wrap; overflow-x:visible; }
  .tab { flex:1 1 auto; justify-content:center; padding:8px 8px; font-size:var(--fs-caption); }
}
.segmented { display:inline-flex; background:var(--sunken); border-radius:var(--r-sm); padding:3px; gap:2px; }
.segmented .seg { border:0; background:transparent; padding:6px 13px; font-size:var(--fs-data); font-weight:600; color:var(--text-muted); border-radius:6px; transition:var(--dur); }
.segmented .seg.active { background:var(--surface); color:var(--text); box-shadow:var(--shadow-sm); }

/* ============================ Forms ============================ */
.form-grid { display:grid; grid-template-columns:1fr 1fr; gap:0 16px; }
@media (max-width:640px){ .form-grid{grid-template-columns:1fr;} }
.field { margin-bottom:14px; }
.field-label { display:block; font-size:var(--fs-caption); font-weight:600; color:var(--text-muted); margin-bottom:6px; }
/* CAPS-LABEL — the one small-caps eyebrow voice for form/field labels on
   Standing Type surfaces; the :lang(zh-CN) guard above already covers it. */
.caps-label { display:block; font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); margin-bottom:6px; }
/* Every text-like control the cockpit draws, INCLUDING an <input> with no
   type attribute (the Trends search, the Desk run id, the Pipeline fields) and
   the month kind. The list used to name four types only, so every other input
   fell to the browser's own white box — invisible in the light theme, a white
   hole in the dark one. */
input:not([type]),input[type=text],input[type=search],input[type=number],input[type=date],input[type=month],input[type=password],select,textarea {
  width:100%; height:38px; padding:0 12px; border:1px solid var(--border-strong); border-radius:var(--r-sm);
  font-size:var(--fs-ui); font-family:inherit; background:var(--surface); color:var(--text); transition:var(--dur);
}
textarea { height:auto; min-height:80px; padding:10px 12px; resize:vertical; line-height:1.5; }
select { appearance:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2376817b' stroke-width='2.2' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 11px center; padding-right:32px; }
input:hover,select:hover,textarea:hover { border-color:var(--n-300); }
input:focus,select:focus,textarea:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-ring); }
::placeholder { color:var(--text-faint); }
input[type=date]::-webkit-calendar-picker-indicator { opacity:.55; cursor:pointer; }
input[type=date]::-webkit-calendar-picker-indicator:hover { opacity:.85; }
input[type=date] { font-variant-numeric:tabular-nums; }

/* ============================ Modal / drawer ============================ */
.scrim { position:fixed; inset:0; background:rgba(13,18,16,.42); backdrop-filter:blur(2px); display:flex; align-items:center; justify-content:center; padding:24px; z-index:100; animation:fade var(--dur) var(--ease); }
@keyframes fade { from{opacity:0;} }
.dialog { background:var(--surface); border:1px solid var(--border); border-radius:var(--r-xl); width:560px; max-width:100%; max-height:88vh; display:flex; flex-direction:column; box-shadow:var(--shadow-lg); overflow:hidden; animation:pop 180ms var(--ease); }
@keyframes pop { from{opacity:0; transform:translateY(8px) scale(.98);} }
.dialog.wide { width:880px; }
.dialog.drawer { margin-left:auto; align-self:stretch; height:100vh; max-height:100vh; border-radius:0; width:520px; animation:slide 200ms var(--ease); }
@keyframes slide { from{transform:translateX(24px); opacity:.6;} }
.dialog-header { display:flex; align-items:center; gap:10px; padding:16px 20px; border-bottom:1px solid var(--border); }
/* Long titles, unbroken ids and knowledge paths WRAP inside a dialog; they
   never widen it. Without min-width:0 a long word sets the flex item's floor,
   the body scrolls sideways and the label column is cut (the citation record,
   FS Improvement Notes 2026-09-22). Regression: test/uiPrimitives.test.js. */
.dialog-header h3 { font-size:var(--fs-prose); font-weight:600; flex:1; min-width:0; overflow-wrap:anywhere; }
.dialog-body { padding:20px; overflow-y:auto; overflow-x:hidden; min-width:0; overflow-wrap:anywhere; }

/* Operator sign-in dialog (operator.js) — the cockpit's only credential form. */
.op-signin .op-lab { display:block; font-size:var(--fs-caption); font-weight:600; text-transform:uppercase; letter-spacing:.07em; color:var(--text-faint); margin-bottom:6px; }
.op-signin .op-err { background:var(--danger-soft); border:1px solid var(--danger); color:var(--danger-text); border-radius:var(--r-sm); padding:9px 12px; font-size:var(--fs-data); margin-bottom:14px; }
.op-signin input[type=password] { font-family:var(--mono); letter-spacing:.08em; }

/* ============================ Command palette ============================ */
.cmdk-scrim { position:fixed; inset:0; background:rgba(13,18,16,.45); backdrop-filter:blur(3px); display:flex; align-items:flex-start; justify-content:center; padding-top:14vh; z-index:120; animation:fade var(--dur) var(--ease); }
.cmdk { width:560px; max-width:92vw; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-lg); box-shadow:var(--shadow-lg); overflow:hidden; animation:pop 160ms var(--ease); }
.cmdk-search { display:flex; align-items:center; gap:10px; padding:14px 16px; border-bottom:1px solid var(--border); }
.cmdk-search input { border:0; height:auto; padding:0; font-size:15px; background:transparent; }
.cmdk-search input:focus { box-shadow:none; }
.cmdk-list { max-height:52vh; overflow-y:auto; padding:6px; }
.cmdk-group-label { font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:.08em; color:var(--text-faint); padding:10px 10px 4px; }
.cmdk-item { display:flex; align-items:center; gap:11px; padding:9px 11px; border-radius:var(--r-sm); cursor:pointer; font-size:var(--fs-ui); }
.cmdk-item .ic { color:var(--text-faint); width:17px; height:17px; }
.cmdk-item.active { background:var(--accent-soft); color:var(--accent-text); }
.cmdk-item.active .ic { color:var(--accent-text); }
.cmdk-item .ci-badge { margin-left:auto; font-size:var(--fs-micro); color:var(--text-faint); font-family:var(--mono); }

/* ============================ Toast ============================ */
#toast-host { position:fixed; bottom:24px; left:50%; transform:translateX(-50%); z-index:200; display:flex; flex-direction:column; gap:8px; align-items:center; }
.toast { display:flex; align-items:center; gap:9px; background:var(--surface); border:1px solid var(--border); color:var(--text); padding:10px 16px; border-radius:var(--r-pill); font-size:var(--fs-ui); font-weight:600; box-shadow:var(--shadow-md); opacity:0; transform:translateY(10px); transition:var(--dur); }
.toast.show { opacity:1; transform:translateY(0); }
.toast .ic { width:17px; height:17px; }
.toast.ok .ic{ color:var(--ok); } .toast.danger .ic,.toast.no .ic{ color:var(--danger); } .toast.warn .ic{ color:var(--warn); }

/* ============================ Charts ============================ */
.spark { display:block; }
.ring { display:block; }
.hbars { display:flex; flex-direction:column; gap:9px; --hbar-label-w:130px; }
.hbar-row { display:grid; grid-template-columns:var(--hbar-label-w) 1fr 52px; align-items:center; gap:12px; }
.hbar-label { font-size:var(--fs-caption); color:var(--text-muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.hbar-track { height:8px; background:var(--sunken); border-radius:99px; overflow:hidden; }
.hbar-fill { height:100%; border-radius:99px; transition:width .5s var(--ease); }
.hbar-val { font-size:var(--fs-data); font-weight:600; text-align:right; font-variant-numeric:tabular-nums; }
.donut-wrap { display:flex; align-items:center; gap:20px; flex-wrap:wrap; }
.donut-legend { display:flex; flex-direction:column; gap:7px; }
.dl-row { display:flex; align-items:center; gap:8px; font-size:var(--fs-data); color:var(--text-muted); }
.dl-row b { margin-left:auto; color:var(--text); font-variant-numeric:tabular-nums; padding-left:18px; }
.dl-dot { width:9px; height:9px; border-radius:3px; }
.meter { height:7px; background:var(--sunken); border-radius:99px; overflow:hidden; min-width:54px; }
.meter-fill { height:100%; border-radius:99px; background:var(--accent); transition:width .5s var(--ease); }

/* score pill / gauge */
.score { display:inline-flex; align-items:center; justify-content:center; min-width:36px; height:24px; padding:0 8px; border-radius:7px; font-weight:600; font-size:var(--fs-data); font-variant-numeric:tabular-nums; background:var(--accent-soft); color:var(--accent-text); }
.score.hi{ background:var(--ok-soft); color:var(--ok-text); } .score.mid{ background:var(--warn-soft); color:var(--warn-text); } .score.lo{ background:var(--sunken); color:var(--text-faint); }

/* ============================ Concept / detail ============================ */
.concept { border:1px solid var(--border); border-radius:var(--r-lg); padding:18px; background:var(--surface); margin-bottom:14px; box-shadow:var(--shadow-sm); }
.concept .c-top { display:flex; align-items:flex-start; gap:12px; margin-bottom:4px; }
.concept .c-top h3 { font:600 var(--fs-section)/1.3 var(--font-serif); flex:1; }
.concept .c-meta { font-size:var(--fs-caption); color:var(--text-faint); display:flex; flex-wrap:wrap; gap:6px 10px; margin:6px 0 12px; align-items:center; }
.concept .c-field { font:400 var(--fs-prose)/var(--lh-prose) var(--font-serif); margin:6px 0; }
.concept .c-field b { color:var(--text); font-weight:600; }
.concept .c-rtb { display:flex; flex-wrap:wrap; gap:5px; margin-top:4px; }
.concept .kv .v-claim { font-family:var(--font-serif); }
.evidence-list { list-style:none; margin:8px 0 0; padding:0; display:flex; flex-direction:column; gap:5px; }
.evidence-list li { font-size:var(--fs-data); padding:8px 11px; background:var(--surface-2); border:1px solid var(--border); border-left:2px solid var(--accent); border-radius:0 var(--r-sm) var(--r-sm) 0; color:var(--text-muted); }
.evidence-list li .ek { font-weight:600; color:var(--accent-text); text-transform:capitalize; }
.evidence-list li .src { float:right; font-size:var(--fs-micro); font-family:var(--mono); background:var(--sunken); color:var(--text-faint); padding:1px 5px; border-radius:4px; }
.fit-grid { display:grid; grid-template-columns:repeat(5,1fr); gap:8px; margin-top:10px; }
.fit-cell { text-align:center; background:var(--surface-2); border:1px solid var(--border); border-radius:var(--r-sm); padding:8px 4px; }
.fit-cell .v { font-weight:600; font-size:15px; font-variant-numeric:tabular-nums; }
.fit-cell .k { font-size:var(--fs-micro); color:var(--text-faint); text-transform:uppercase; letter-spacing:.04em; margin-top:2px; }

/* drink design (Nano Banana Pro) */
.design-block { margin-top:12px; padding-top:12px; border-top:1px dashed var(--border); display:flex; flex-direction:column; gap:8px; align-items:flex-start; }
.design-img { width:100%; max-width:300px; aspect-ratio:1/1; object-fit:cover; border-radius:var(--r-md); border:1px solid var(--border); background:var(--surface-2); box-shadow:var(--shadow-sm); }
.design-cap { font-size:var(--fs-caption); color:var(--text-faint); display:flex; align-items:center; gap:5px; }
.design-loading { display:flex; align-items:center; gap:9px; font-size:var(--fs-data); color:var(--text-muted); padding:8px 0; }
.report-md { font-size:var(--fs-ui); line-height:1.6; color:var(--text); }
.report-md h1 { font-size:var(--fs-section); margin:4px 0 10px; }
.report-md h2 { font-size:15px; margin:16px 0 7px; color:var(--accent-text); border-bottom:1px solid var(--border); padding-bottom:4px; }
.report-md h3 { font-size:var(--fs-ui); margin:12px 0 5px; }
.report-md ul,.report-md ol { padding-left:20px; margin:6px 0; }
.report-md li { margin:3px 0; }
.report-md p { margin:7px 0; }
.report-md blockquote { margin:var(--fs-prose) 0 var(--fs-prose) var(--fs-section); }
.report-md strong { color:var(--text); font-weight:600; }
.report-md code { font-family:var(--mono); font-size:var(--fs-data); background:var(--sunken); padding:1px 5px; border-radius:5px; }
.report-md p, .report-md li { overflow-wrap: anywhere; }
.report-md pre { white-space:pre-wrap; word-break:break-word; }

/* The client view keeps setup mechanics out of the primary navigation. They
   remain one explicit switch away in Operations. */
html[data-user-role="standard"] #settingsBtn { display:none; }
html[data-user-role="standard"] .operations-only { display:none; }

.explorer-review-tools > summary { padding:12px 16px; cursor:pointer; font-weight:600; }
.explorer-record { margin-top:8px; }
.explorer-record code { overflow-wrap:anywhere; }

/* model cards */
.model-card { border:1px solid var(--border-strong); border-radius:var(--r-md); padding:13px 14px; cursor:pointer; display:flex; align-items:center; gap:12px; background:var(--surface); transition:var(--dur); }
.model-card:hover { border-color:var(--n-300); }
.model-card.active { border-color:var(--accent); background:var(--accent-soft); }
.model-card .m-info { flex:1; min-width:0; }
.model-card .m-name { font-weight:600; font-size:var(--fs-ui); display:flex; align-items:center; gap:7px; }
.model-card .m-prov { font-size:var(--fs-caption); color:var(--text-faint); margin-top:1px; }
.model-card .m-check { width:20px; height:20px; border-radius:6px; border:1.5px solid var(--border-strong); display:flex; align-items:center; justify-content:center; color:transparent; flex-shrink:0; }
.model-card.active .m-check { background:var(--accent); border-color:var(--accent); color:#fff; }
.live-pill { display:inline-flex; align-items:center; gap:4px; font-size:var(--fs-micro); font-weight:600; color:var(--ok-text); background:var(--ok-soft); padding:1px 6px; border-radius:99px; }
.live-pill::before { content:""; width:5px; height:5px; border-radius:50%; background:var(--ok); }

/* ============================ Pipeline layers ============================ */
.layer { border:1px solid var(--border); border-radius:var(--r-md); margin:7px 0; overflow:hidden; background:var(--surface); }
.layer-head { display:flex; align-items:center; gap:11px; padding:11px 14px; cursor:pointer; transition:var(--dur); }
.layer-head:hover { background:var(--surface-2); }
.layer-head .lcode { font-family:var(--mono); font-size:var(--fs-caption); font-weight:600; color:var(--accent-text); background:var(--accent-soft); padding:2px 7px; border-radius:5px; }
.layer-head .ltitle { font-weight:600; font-size:var(--fs-ui); flex:1; }
.layer-head .lcaret { color:var(--text-faint); transition:transform var(--dur) var(--ease); display:flex; }
.layer.open .lcaret { transform:rotate(90deg); }
.layer-body { max-height:0; overflow:hidden; transition:max-height var(--dur) var(--ease); font-size:var(--fs-data); color:var(--text-muted); }
.layer.open .layer-body { max-height:200px; }
.layer-body .lb-inner { padding:0 14px 13px 39px; }

/* ============================ Empty / skeleton / misc ============================ */
.empty { text-align:center; padding:48px 20px; color:var(--text-faint); }
.empty .empty-ic { width:48px; height:48px; border-radius:50%; background:var(--sunken); display:inline-flex; align-items:center; justify-content:center; margin-bottom:12px; color:var(--text-faint); }
.empty .empty-title { font-size:var(--fs-ui); font-weight:600; color:var(--text-muted); }
.empty .empty-hint { font-size:var(--fs-data); margin-top:4px; max-width:380px; margin-left:auto; margin-right:auto; }
.skeleton { background:linear-gradient(90deg,var(--sunken) 25%,var(--surface-2) 37%,var(--sunken) 63%); background-size:400% 100%; animation:shimmer 1.3s ease infinite; border-radius:var(--r-sm); }
@keyframes shimmer { from{background-position:100% 0;} to{background-position:0 0;} }
.page-loading { display:flex; flex-direction:column; gap:16px; }
.spinner { width:18px; height:18px; border:2.5px solid var(--accent-soft-2); border-top-color:var(--accent); border-radius:50%; animation:spin .7s linear infinite; display:inline-block; }
@keyframes spin { to{transform:rotate(360deg);} }
.kv { display:flex; gap:10px; font-size:var(--fs-data); padding:5px 0; border-bottom:1px solid var(--border); min-width:0; }
.kv:last-child{ border-bottom:0; }
.kv .k { color:var(--text-faint); min-width:130px; max-width:40%; flex-shrink:0; overflow-wrap:anywhere; }
.kv .v { color:var(--text); flex:1; min-width:0; overflow-wrap:anywhere; }
@media (max-width:520px){ .kv { flex-direction:column; gap:1px; } .kv .k { min-width:0; max-width:none; } }
.sep { border:0; border-top:1px solid var(--border); margin:16px 0; }
.section-label { font-size:var(--fs-data); font-weight:600; color:var(--text); letter-spacing:-.01em; margin:4px 0 10px; display:flex; align-items:center; gap:7px; }
.section-label .ic { color:var(--accent); width:15px; height:15px; }
.tag-dim { font-size:var(--fs-micro); color:var(--text-muted); }
.inline-ic { display:inline-flex; vertical-align:-2px; margin-right:5px; color:var(--text-faint); }
.legend-row { display:flex; gap:16px; flex-wrap:wrap; font-size:var(--fs-caption); color:var(--text-faint); align-items:center; }
.legend-row .lg { display:inline-flex; align-items:center; gap:5px; }
.legend-row .lg::before { content:""; width:9px; height:3px; border-radius:2px; background:var(--accent); }

/* hamburger / responsive */
.hamburger { display:none; }
@media (max-width:920px){
  .sidebar { position:fixed; left:-260px; transition:left var(--dur-2) var(--ease-out); }
  .sidebar.open { left:0; box-shadow:var(--shadow-lg); }
  .hamburger { display:inline-flex; }
  .cmdk-trigger .cmdk-label { display:none; }
}
@media (prefers-reduced-motion: reduce) {
  .sidebar, .nav-item, .nav-item .nav-ic, .nav-item .nav-txt, .nav-item .nav-desc, .nav-section { transition:none; }
}
/* Phone widths. The top bar's row of controls has a minimum width near
   560px; below that a phone did not overflow, it ZOOMED OUT to fit the row —
   the whole cockpit rendered at ~560 CSS px and the page title wrapped one
   word per line beside its header chips. Let the bar wrap onto a second row,
   let the page header stack, and give the content the width back. */
@media (max-width:760px){
  .topbar { flex-wrap:wrap; height:auto; min-height:var(--topbar-h); padding:6px 12px; gap:8px; row-gap:4px; }
  .topbar .spacer { flex:1 1 auto; }
  .topbar .tb-actions { flex:1 1 100%; flex-wrap:wrap; justify-content:flex-end; gap:6px; }
  .cmdk-trigger .kbd { display:none; }
  .content { padding:18px 14px 80px; }
  .page-header { flex-wrap:wrap; align-items:flex-start; gap:10px; }
  .page-header .ph-text { flex:1 1 100%; }
}
/* The role switch carries a short form for phones. At 390px the full row of
   controls (search, role, sign-in, settings, theme, EN/中文) used to push the
   language switch onto a third row; with the short labels, an icon-only
   search and 32px icon buttons it fits one row. Guard: the capture loop at
   390x844 (docs/verification/ui-overhaul). */
.seg .seg-short { display:none; }
@media (max-width:520px){
  .seg .seg-long { display:none; }
  .seg .seg-short { display:inline; }
  .topbar #collapseBtn { display:none; }
  .topbar .cmdk-trigger .cmdk-label { display:none; }
  .topbar .cmdk-trigger { padding:0 9px; }
  .topbar .tb-actions { gap:4px; flex-wrap:nowrap; }
  .topbar .tb-actions .icon-btn { width:32px; height:32px; }
  .topbar .segmented .seg { padding:6px 9px; }
}

/* Market Almanac cockpit reader (Phase 2 Task 7) */
.almanac-toolbar { display:flex; align-items:flex-end; gap:18px; flex-wrap:wrap; }
.almanac-toolbar .field { margin-bottom:0; }
.almanac-select { min-width:150px; }
.almanac-scope-fixed { font-size:var(--fs-ui); font-weight:600; padding-bottom:9px; display:inline-block; }
.almanac-meta { border-top:1px solid var(--border); padding-top:12px; }
.almanac-nav { display:flex; flex-direction:column; padding:8px; gap:2px; max-height:520px; overflow-y:auto; }
.almanac-nav-item {
  display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:var(--r-sm);
  border:0; background:transparent; color:var(--text-muted); text-align:left; width:100%; cursor:pointer; transition:var(--dur);
}
.almanac-nav-item:hover { background:var(--sunken); color:var(--text); }
.almanac-nav-item.active { background:var(--accent-soft); color:var(--accent-text); font-weight:600; }
.almanac-nav-id { font-family:var(--mono); font-size:var(--fs-micro); color:var(--text-faint); flex-shrink:0; }
.almanac-nav-item.active .almanac-nav-id { color:var(--accent-text); }
.almanac-nav-title { flex:1; font-size:var(--fs-data); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.almanac-chapter { font-size:var(--fs-ui); }
.almanac-stale-banner {
  display:flex; align-items:center; gap:8px; background:var(--warn-soft); color:var(--warn-text);
  border-radius:var(--r-sm); padding:9px 12px; font-size:var(--fs-data); margin-bottom:14px;
}
.almanac-sources { border-top:1px solid var(--border); margin-top:16px; padding-top:12px; }
.almanac-sources-title { font-size:var(--fs-caption); font-weight:600; text-transform:uppercase; letter-spacing:.05em; color:var(--text-faint); margin-bottom:6px; }
.almanac-citations { list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:4px; }
.almanac-citations a { font-size:var(--fs-caption); word-break:break-all; }

/* ---- 经验库 (Task C5) ---- */
.instinct-toolbar { display:flex; align-items:flex-end; gap:14px; flex-wrap:wrap; }
.instinct-toolbar .field { margin-bottom:0; }
.instinct-cards { display:flex; flex-direction:column; gap:14px; }
.instinct-card {
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-md);
  padding:16px 18px; display:flex; flex-direction:column; gap:10px;
}
/* The whole point of the basis field: a world-knowledge rule must LOOK
   different from a cited one — tinted edge + background, not just a badge. */
.instinct-card-world { border-left:3px solid var(--warn-text); background:color-mix(in srgb, var(--warn-soft) 24%, var(--surface)); }
.instinct-card-head { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.instinct-card-head .spacer { flex:1; }
.instinct-id { font-family:var(--mono); font-size:var(--fs-caption); color:var(--text-faint); }
.instinct-pattern { font-size:var(--fs-ui); font-weight:600; line-height:1.55; }
.instinct-basis { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.instinct-citation { font-family:var(--mono); font-size:var(--fs-caption); background:var(--sunken); padding:2px 7px; border-radius:var(--r-sm); word-break:break-all; }
.instinct-no-citation { font-size:var(--fs-caption); color:var(--warn-text); }
.instinct-fields { display:flex; flex-direction:column; gap:6px; }
.instinct-field { display:flex; gap:10px; font-size:var(--fs-data); line-height:1.6; }
.instinct-field-label { flex-shrink:0; width:96px; font-size:var(--fs-caption); font-weight:600; color:var(--text-faint); padding-top:2px; }
/* D18 — the attributed approval. The picker sits with the decision buttons so
   "who is approving" is read in the same glance as "approve". */
.instinct-approver { display:flex; align-items:center; gap:7px; }
.instinct-approver-label { font-size:var(--fs-caption); font-weight:600; color:var(--text-faint); white-space:nowrap; }
.instinct-approver-select { max-width:180px; }
/* Status carries WORDS and a mark; the colour is the third signal, never the
   only one. */
.instinct-status { text-transform:none; }
/* A principle is only a principle while what would disprove it is on screen
   (§3.8 rule 2) — so it gets a block, not a label row. */
.instinct-card-principle { border-left:3px solid var(--info-text); background:color-mix(in srgb, var(--info-soft) 20%, var(--surface)); }
/* min-width: inside the approved table this block sits in a cell that would
   otherwise collapse to one character per line and hide the very thing it
   exists to show. The table already scrolls in .table-wrap. */
.instinct-counter-case {
  display:flex; flex-direction:column; gap:3px; background:var(--sunken);
  border-left:3px solid var(--info-text); border-radius:var(--r-sm); padding:9px 12px;
  min-width:200px; margin-top:6px;
}
.instinct-card > .instinct-counter-case { margin-top:0; }
.instinct-counter-case-label { font-size:var(--fs-caption); font-weight:600; letter-spacing:.03em; color:var(--text-faint); }
.instinct-counter-case-text { font-size:var(--fs-data); line-height:1.6; }
.instinct-counter-missing {
  display:flex; align-items:flex-start; gap:8px; background:var(--danger-soft); color:var(--danger-text);
  border-radius:var(--r-sm); padding:9px 12px; font-size:var(--fs-data); line-height:1.6;
}
/* A refused approval STAYS on the card — a toast that fades is not an answer
   to "why did nothing happen". */
.instinct-card-error {
  display:flex; align-items:flex-start; gap:8px; flex-wrap:wrap; background:var(--danger-soft);
  color:var(--danger-text); border-radius:var(--r-sm); padding:9px 12px; font-size:var(--fs-data); line-height:1.6;
}
.instinct-card-error-reason { font-family:var(--mono); font-size:var(--fs-caption); word-break:break-word; }
.instinct-counts { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:12px; }
.instinct-integrity-failed {
  display:flex; flex-direction:column; gap:6px; background:var(--danger-soft); color:var(--danger-text);
  border-radius:var(--r-sm); padding:12px 14px; font-size:var(--fs-data);
}
.instinct-report { font-family:var(--mono); font-size:var(--fs-caption); white-space:pre-wrap; word-break:break-word; background:var(--sunken); border-radius:var(--r-sm); padding:12px; margin:6px 0 0; max-height:260px; overflow-y:auto; }
.instinct-report-title { text-transform:uppercase; letter-spacing:.05em; font-weight:600; }
.instinct-progress { display:flex; flex-direction:column; gap:6px; }
.instinct-progress-track { height:6px; border-radius:3px; background:var(--sunken); overflow:hidden; }
.instinct-progress-fill { height:100%; background:var(--accent); transition:width .3s ease; }
/* No count yet: a moving stripe that cannot be read as a percentage. */
.instinct-progress-track[data-indeterminate] .instinct-progress-fill { width:30% !important; animation:instinct-progress-slide 1.4s ease-in-out infinite; }
@keyframes instinct-progress-slide { from { transform:translateX(-100%); } to { transform:translateX(340%); } }
@media (prefers-reduced-motion: reduce) { .instinct-progress-track[data-indeterminate] .instinct-progress-fill { animation:none; width:100% !important; opacity:.4; } }
.instinct-distill-outcome { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }

/* ---- 分析台 + 预测记录 (Task D6) ---- */
.desk-honesty { display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
.desk-steps { display:grid; grid-template-columns:repeat(auto-fit, minmax(130px, 1fr)); gap:10px; }
.desk-step { background:var(--sunken); border-radius:var(--r-sm); padding:9px 11px; }
.desk-step-name { font-size:var(--fs-caption); font-weight:600; }
.desk-step-detail { margin-top:3px; }
.desk-delta-up { color:var(--ok); font-weight:600; }
.desk-delta-down { color:var(--danger); font-weight:600; }
.desk-move { border-top:1px solid var(--border); padding:10px 0; display:flex; flex-direction:column; gap:8px; }
.desk-field { display:flex; gap:10px; font-size:var(--fs-data); line-height:1.6; }
.desk-field-label { flex-shrink:0; width:72px; font-size:var(--fs-caption); font-weight:600; color:var(--text-faint); padding-top:2px; }
.desk-citations { list-style:none; padding:0; margin:0; display:flex; flex-direction:column; gap:4px; }
.desk-refused-title { font-size:var(--fs-caption); font-weight:600; text-transform:uppercase; letter-spacing:.05em; color:var(--text-faint); margin:12px 0 6px; }
.desk-refusal-reason { color:var(--danger-text); }
.desk-attack { border-top:1px solid var(--border); padding:9px 0; display:flex; flex-direction:column; gap:5px; font-size:var(--fs-data); line-height:1.55; }
.desk-attack:first-child { border-top:0; }
.desk-attack-head { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.desk-attack-quarantined { opacity:.85; }
.desk-source { border-top:1px solid var(--border); padding:9px 0; display:flex; flex-direction:column; gap:4px; }
.desk-source:first-child { border-top:0; }
/* The §6.5 loudness for an unparseable challenger reply — a banner, not a
   footnote: its scrutiny was NOT obtained and the page must say so. */
.desk-loud {
  display:flex; flex-direction:column; gap:6px; background:var(--danger-soft); color:var(--danger-text);
  border-left:3px solid var(--danger-text); border-radius:var(--r-sm); padding:12px 14px; font-size:var(--fs-data); margin-bottom:10px;
}
.desk-quarantined-raw { margin:4px 0 0; padding:8px 10px; background:var(--sunken); color:var(--text); border-radius:var(--r-sm); font-size:var(--fs-data); }
/* §6.1 weight sliders (Task W1) — the left "what you value" rail, and the
   LOUD informal-preview banner the moment a slider leaves Ben's defaults. */
.desk-rail-grid { display:grid; grid-template-columns:280px minmax(0,1fr); gap:16px; align-items:start; margin-bottom:18px; }
.desk-rail-grid .panel { margin-bottom:0; }
@media (max-width:980px){ .desk-rail-grid { grid-template-columns:1fr; } }
.desk-weights { display:flex; flex-direction:column; gap:10px; }
.desk-weight { border-top:1px solid var(--border); padding-top:8px; }
.desk-weight:first-child { border-top:0; padding-top:0; }
.desk-weight-head { display:flex; justify-content:space-between; align-items:center; gap:8px; font-size:var(--fs-data); font-weight:600; margin-bottom:4px; }
.desk-weight-slider { width:100%; accent-color:var(--accent); }
.desk-preview-banner {
  display:flex; flex-direction:column; gap:6px; background:var(--warn-soft); color:var(--warn-text);
  border-left:3px solid var(--warn-text); border-radius:var(--r-sm); padding:10px 12px; font-size:var(--fs-data);
}
.desk-preview-banner .btn { align-self:flex-start; }
.desk-trigger { display:flex; flex-direction:column; gap:10px; }
.desk-trigger .field { margin-bottom:0; }
.desk-gate {
  display:flex; align-items:center; gap:8px; background:var(--warn-soft); color:var(--warn-text);
  border-radius:var(--r-sm); padding:9px 12px; font-size:var(--fs-data);
}
.instinct-gate { display:flex; align-items:center; gap:8px; padding:8px 2px; }
.track-downgrade { display:inline-flex; align-items:center; gap:6px; white-space:nowrap; }
.track-downgrade s { color:var(--text-faint); }

/* --- 知识库 / the vault page (lane 2 Task 6) -----------------------------
   Existing tokens only: the semantic pairs carry every state, so a refusal, a
   pending handoff and a finished ingestion are told apart by the same colours
   the rest of the cockpit already uses. No new hues, no new shadows. */
.vault-split { grid-template-columns:minmax(0,1.05fr) minmax(0,1fr); }
@media (max-width:1180px){ .vault-split { grid-template-columns:1fr; } }
.vault-tabs { box-shadow:none; margin-bottom:0; }
.vault-filters { display:flex; flex-direction:column; gap:10px; margin-bottom:14px; }
.vault-search input { width:100%; }
.vault-search .faint { margin-top:5px; }
.vault-count { align-self:flex-end; }
.vault-table { table-layout:fixed; }
.vault-table th:nth-child(1) { width:40%; }
.vault-table th:nth-child(2) { width:16%; }
.vault-table th:nth-child(3) { width:22%; }
.vault-table th:nth-child(4) { width:12%; }
.vault-table th:nth-child(5) { width:10%; }
.vault-table td { font-size:var(--fs-data); }
.vault-table .vault-path { overflow-wrap:anywhere; word-break:normal; }
.vault-row-active td { background:var(--accent-soft); }
.vault-kinds { margin-bottom:14px; }
.vault-entity-list { display:flex; flex-direction:column; gap:2px; }
.vault-entity {
  display:flex; align-items:center; justify-content:space-between; gap:12px; width:100%;
  text-align:left; background:none; border:0; border-radius:var(--r-sm); padding:9px 11px;
  cursor:pointer; color:var(--text); font-size:var(--fs-ui); transition:var(--dur);
}
.vault-entity:hover { background:var(--surface-2); }
.vault-entity-name { font-weight:600; }

/* A stated failure. It carries the server's own words and never stands in for
   an empty list — the whole point is that "unknown" reads differently. */
.vault-failed {
  background:var(--danger-soft); border-radius:var(--r-sm); padding:12px 14px;
  display:flex; flex-direction:column; gap:5px;
}
.vault-failed-head { display:flex; align-items:center; gap:8px; color:var(--danger-text); font-size:var(--fs-ui); }
.vault-failed-reason { font-family:var(--mono); font-size:var(--fs-caption); color:var(--danger-text); word-break:break-word; }
.vault-notice { display:flex; align-items:flex-start; gap:10px; border-radius:var(--r-sm); padding:12px 14px; font-size:var(--fs-data); }
.vault-notice-info { background:var(--info-soft); color:var(--info-text); }
.vault-notice-warn { background:var(--warn-soft); color:var(--warn-text); }
.vault-notice-ok { background:var(--ok-soft); color:var(--ok-text); }
.vault-notice .muted { margin-top:3px; }
.vault-report {
  font-family:var(--mono); font-size:var(--fs-caption); line-height:1.55; white-space:pre-wrap;
  background:var(--sunken); color:var(--text-muted); border-radius:var(--r-sm);
  padding:10px 12px; margin-top:8px; max-height:220px; overflow:auto;
}
.vault-upload .chip-group { max-width:640px; }
.warn-text { color:var(--warn-text); }

.vault-page-head { display:flex; align-items:flex-start; gap:14px; margin-bottom:10px; }
.vault-page-head h2 { font-size:var(--fs-section); font-weight:600; letter-spacing:-.01em; }
.vault-page-chips { margin-left:auto; display:flex; flex-wrap:wrap; gap:6px; justify-content:flex-end; }
.vault-citable-note { margin-bottom:6px; }
.vault-source { display:flex; align-items:center; flex-wrap:wrap; gap:7px; font-size:var(--fs-caption); color:var(--text-muted); }
.vault-source .k { color:var(--text-faint); }
.vault-source code { font-family:var(--mono); font-size:var(--fs-caption); background:var(--sunken); padding:1px 6px; border-radius:5px; }
.vault-facts .kv .k { min-width:0; flex:1; }
.vault-facts .kv .v { flex:0 0 auto; font-weight:600; }
.vault-conflicts { margin:0; padding-left:20px; font-size:var(--fs-data); color:var(--warn-text); }
.vault-section { margin-bottom:14px; }
.vault-prose { font-size:var(--fs-ui); line-height:1.65; white-space:pre-wrap; color:var(--text); }
/* Vault judgment styling follows 04-ui-design.md §L2. */
.vault-judgment { border-left:3px solid var(--purple); padding-left:12px; }
.vault-judgment .vault-prose { color:var(--purple-text); }

/* ============================================================================
   STANDING TYPE core primitives (STANDING-TYPE-DESIGN.md §2.1)
   ========================================================================== */

/* SIGILS — the evidence ladder as drawn shapes, never glyph characters
   (grayscale-safe, EN/中-identical, print-safe). Shape carries the ladder;
   color is redundant. Assumption is dashed and NEVER filled. */
.sigil{display:inline-block;width:9px;height:9px;border-radius:50%;flex:none;vertical-align:-.5px}
.sigil.ev-observed{background:var(--ev-observed)}
.sigil.ev-supported{border:1.5px solid var(--ev-supported);background:linear-gradient(90deg,var(--ev-supported) 0 50%,transparent 50%)}
.sigil.ev-hypothesis{border:1.5px solid var(--ev-hypothesis)}
.sigil.ev-assumption{border:1.5px dashed var(--ev-assumption-border)}
.sigil.ev-refused{background:var(--ev-refused);position:relative}
.sigil.ev-refused::after{content:"";position:absolute;left:-1px;right:-1px;top:50%;height:1.5px;background:var(--on-accent);transform:rotate(45deg)}

/* TAG — a READING: near-square, bordered in its own ink, no pointer. A value
   never promises a click it can't honor. (.chip stays --r-pill + pointer and
   is reserved for PRESSABLE things.) */
.tag{display:inline-flex;align-items:center;gap:6px;padding:2px 8px;border-radius:var(--r-xs);
  border:1px solid color-mix(in srgb,currentColor 28%,transparent);
  font:600 var(--fs-micro)/1.4 var(--font);text-transform:uppercase;letter-spacing:var(--track-caps);
  cursor:default;user-select:text;white-space:nowrap}
/* tag status colors mirror the badge vocabulary — the border tracks currentColor */
.tag.ok{color:var(--ok-text)} .tag.warn{color:var(--warn-text)}
.tag.danger,.tag.no{color:var(--danger-text)} .tag.info{color:var(--info-text)}
.tag.purple,.tag.pu{color:var(--purple-text)} .tag.accent{color:var(--accent-text)}
.tag.neutral,.tag.muted{color:var(--ink-muted)}
/* an id-bearing reading keeps the id's own case — raw ids ride small mono and
   are never shouted into tracked caps (Law 6) */
.tag.tag-id{text-transform:none;letter-spacing:normal;font-weight:400}
.tag.tag-id .ref{font-family:var(--mono);font-size:var(--fs-micro);color:inherit}

/* FOOTING — the signature: what this sentence stands on. Always visible,
   never a tooltip. Set in --ink-muted (not faint): footings are read, not
   decoration. */
.footing{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:4px;
  max-width:var(--measure-note);font-size:var(--fs-caption);color:var(--ink-muted)}
.footing::before{content:"";width:var(--footing-indent);height:1px;background:var(--hairline);flex:none}
.footing .ref{font-family:var(--mono);font-size:var(--fs-micro);color:var(--ink-faint)}

/* VINTAGE STAMP — data age, worn openly. */
.stamp-vintage{font-family:var(--mono);font-size:var(--fs-micro);color:var(--vintage-ink);
  border:1px solid color-mix(in srgb,var(--vintage-ink) 35%,transparent);
  padding:1px 6px;border-radius:var(--r-xs);white-space:nowrap}
.stamp-vintage.stale{color:var(--vintage-stale);background:var(--vintage-stale-soft)}

/* LEDGER — money is always mono tabular in calm copper. The saturated armed
   family appears only at the moment before spend (the armed strip). */
.spend{font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--spend-ink)}
/* on a filled control the copper fails contrast — the figure re-inks, mono stays */
.btn-primary .spend{color:inherit}

/* NOTICE — the five-kind provenance grammar for disclosure blocks. */
.notice{border-left:2px solid var(--border-strong);padding:8px 12px;font-size:var(--fs-data)}
.notice.measured{border-color:var(--ev-observed)}   /* measured facts               */
.notice.judged{border-color:var(--purple)}          /* inference/heuristic injected */
.notice.absent{border-color:var(--warn)}            /* disclosed-absent / starved   */
.notice.refused{border-color:var(--seal)}           /* refusals — reason VERBATIM   */
.notice.degraded{border-color:var(--warn)}          /* reduced effort (a choice, not a failure) */
.notice.vintage{border-color:var(--border-strong)}  /* data-age disclosures         */
/* raw ids inside disclosure prose keep the ledger's mono, never the UA default */
.notice code,.dsn-sub code{font-family:var(--mono);font-size:var(--fs-micro);color:var(--ink-faint)}

/* READOUT — a number's only legal rendering: label + value + optional scale.
   Consumed by readoutHtml() (realize.js); an unlabeled decimal is
   unrenderable, not merely discouraged. */
.readout{display:inline-flex;align-items:baseline;gap:8px}
.readout .readout-l{font:600 var(--fs-micro)/1 var(--font);letter-spacing:.1em;text-transform:uppercase;color:var(--ink-faint)}
.readout .readout-v{font:600 20px/1 var(--font-serif);font-variant-numeric:tabular-nums;color:var(--ink)}
.readout.compact .readout-v{font:500 var(--fs-data)/1 var(--mono)}
.readout .readout-meter{display:inline-block;width:96px;height:3px;background:var(--sunken);border-radius:2px;position:relative;top:-3px}
.readout .readout-meter i{display:block;height:100%;background:var(--accent);border-radius:2px}

/* ============================================================================
   CONSOLIDATED PAGE STYLESHEETS (STANDING-TYPE-DESIGN.md §6 Wave 8 item 1;
   §5.19 deferred this merge to now, it was never dropped)
   ----------------------------------------------------------------------------
   Until this wave every page module carried its own <style> block and ui.js /
   app.js injected theirs into <head> at runtime, under the rule "styles.css is
   not this unit's file". Eight blocks — realize.js's BRIEF_CSS, CHAT_CSS,
   SHARED_RLZ_CSS and WAVE_CSS, territory.js's TER_CSS, design.js's DESIGN_CSS,
   ui.js's EXPLAIN_CSS and app.js's SHELL_CSS — now live here, one labelled
   section each, rules preserved byte-for-byte except where a banner says
   otherwise. Every selector is still namespaced (.rlz- / .ter- / .dsn- /
   .dossier-brief / .popover / the shell's own), so nothing reaches a page it
   could not reach before; what changed is that the rules load once with the
   document instead of being re-parsed on every paint.

   realizePrint.js's PRINT_CSS is DELIBERATELY NOT HERE: the print route builds a
   separate document with its own <head>, so its stylesheet is not the cockpit's
   stylesheet. test/styleOwnership.test.js is the gate that keeps the rest out of
   the JS — it allowlists that one file, and it fails the wall if a new <style>
   block or a fat *_CSS constant appears in public/js.
   ========================================================================== */

/* ==== stage tracker (merged: realize.js WAVE_CSS + territory.js TER_CSS) ==== */
/* ONE stage-tracker family, where there were two.
   Spec §6 Wave 4.2 already called the run rail "a shared component, replaces
   rlz-/ter-stage trackers"; §5.19 deferred the merge to Wave 8, which is here.
   The STANDING TYPE §3.5 rail — realize.js's values — is the surviving look, so
   the Territory Lab's strip gains the hairline border, the square caps chips and
   the mono elapsed column it never had. One row per stage; a deterministic stage
   gets a dashed chip and NEVER an animated in-flight state — inventing
   intermediate progress is the UI equivalent of inventing a number. The row
   leads with the evidence sigil (done=filled, active=outlined and pulsing,
   pending=dashed) so the rail reads as the same ladder every claim on these
   pages is footed on. Two pulses (rlz-pulse 1.8s/.3, ter-breathe 1.6s/.35)
   become one: a single ambient motion, killed by prefers-reduced-motion. */
.stage-tracker { border:1px solid var(--hairline); border-radius:var(--r-md); background:var(--surface); padding:var(--sp-3) var(--sp-4); }
.stage-row { display:flex; align-items:center; gap:10px; padding:5px 0; border-bottom:1px solid var(--hairline); font-size:var(--fs-caption); }
.stage-row:last-of-type { border-bottom:0; }
.stage-row > .sigil { flex:0 0 9px; }
/* The pages' ONE ambient motion, and it dies under prefers-reduced-motion. */
.stage-row[data-state="running"] > .sigil { animation:stage-pulse 1.8s var(--ease) infinite; }
@keyframes stage-pulse { 0%,100% { opacity:1; } 50% { opacity:.3; } }
@media (prefers-reduced-motion: reduce) { .stage-row[data-state="running"] > .sigil { animation:none; } }
/* The Lab's ordinal column: its steps ARE a numbered sequence (§5.16 bans
   ordinals on choices, not on sequences), so the column travels with it. */
.stage-ord { flex:0 0 18px; color:var(--text-faint); font-variant-numeric:tabular-nums; }
.stage-label { flex:1; font:600 var(--fs-caption)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink); }
/* A step the wave walked past is dimmed AND labelled, never silently counted. */
.stage-row[data-state="skipped"] .stage-label { color:var(--text-faint); }
.stage-zh { color:var(--ink-faint); margin-left:6px; text-transform:none; letter-spacing:0; font-weight:400; }
.stage-chip { flex:0 0 auto; padding:0 8px; border-radius:var(--r-xs); border:1px solid var(--border-strong);
  font:600 var(--fs-micro)/17px var(--font); letter-spacing:var(--track-caps); text-transform:uppercase;
  color:var(--ink-muted); background:var(--surface); }
.stage-chip.st-running { border-color:var(--accent); color:var(--accent-text); }
.stage-chip.st-done { border-color:var(--ok); color:var(--ok-text); background:var(--ok-soft); }
.stage-chip.st-deterministic { border-style:dashed; }
.stage-chip.st-failed { border-color:var(--danger); color:var(--danger-text); background:var(--danger-soft); }
.stage-chip.st-skipped, .stage-chip.st-timeout { border-color:var(--warn); color:var(--warn-text); background:var(--warn-soft); }
.stage-el { flex:0 0 52px; text-align:right; color:var(--ink-faint); font-family:var(--mono);
  font-variant-numeric:tabular-nums; font-size:var(--fs-micro); }
.stage-spend { flex:0 0 auto; font-size:var(--fs-micro); }
.stage-foot { display:flex; align-items:center; gap:8px; margin-top:8px; font-size:var(--fs-caption); color:var(--text-muted); }
/* The reduced-effort stamp sits on the row it touched, never as a global lamp. */
.stage-stamp { display:flex; align-items:flex-start; gap:8px; margin:0 0 5px 19px; padding-left:10px;
  border-left:1px dashed var(--warn); font-size:var(--fs-caption); color:var(--warn-text); }
.stage-stamp .stage-stamp-l { font:600 var(--fs-micro)/1.5 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; flex:none; }
.stage-sub { margin:0 0 6px 19px; }
/* Task J review — a substage that has a WORD is prose, not a machine id: it
   drops the `.ek` mono face the raw ids wear, so the two are distinguishable
   at a glance and an undecoded id still reads as the token it is. Tokens only. */
.stage-subword { font:500 var(--fs-micro)/1.5 var(--font); color:var(--ink); }

/* ==== app.js SHELL_CSS ==== */
/* SIDEBAR — the active pill is the soft accent ground under INK text (the
   operator's 2026-09-16 ruling: wide pills, the mark on a fixed column). The
   quiet 2px ink left rule this section used to carry is retired with the row
   it sat beside; the pill's ground is drawn once, in the App shell section's
   `.nav-item.active`, and nothing here overrides it. `.nav-item` is emitted
   only by renderSidebar(), inside `.sidebar`, so no other `.active` is touched. */
.nav-item .nav-ord { flex:none; width:14px; font-size:var(--fs-micro); color:var(--ink-faint);
  font-variant-numeric:tabular-nums; text-align:center; }
.nav-item.active .nav-ord { color:var(--ink); }
.sidebar.collapsed .nav-ord { display:none; }
/* PIPELINE RAIL — the five NPD routes, as the sequence they are. Every step is
   a real href: a stepper that only reported position would be a picture of
   navigation instead of navigation. */
.chain-rail { display:flex; align-items:center; gap:4px; min-width:0; overflow:hidden; }
.chain-rail .cr-step { display:inline-flex; align-items:center; gap:5px; padding:3px 8px;
  border-radius:var(--r-xs); font-size:var(--fs-caption); color:var(--ink-faint);
  text-decoration:none; white-space:nowrap; }
.chain-rail .cr-step:hover { background:var(--sunken); color:var(--ink); }
.chain-rail .cr-step .cr-dot { width:7px; height:7px; border-radius:50%; flex:none;
  border:1.5px solid var(--border-strong); background:transparent; }
.chain-rail .cr-step.touched .cr-dot { border-style:dashed; border-color:var(--ink-faint); }
.chain-rail .cr-step.current { color:var(--ink); font-weight:600; }
.chain-rail .cr-step.current .cr-dot { background:var(--ink); border-color:var(--ink); border-style:solid; }
.chain-rail .cr-sep { color:var(--text-faint); display:flex; flex:none; }
/* The topbar holds rail + search + role toggle + four icons + language seg:
   below ~1520px the five dual-script labels overflow it, so non-current steps
   collapse to their dots early — the current stage always keeps its name. */
/* Every step is labelled where the bar has room; where it does not, the rail
   collapses to the current step and its place ("Design 4/5") instead of a
   row of unlabelled circles. */
.chain-rail .cr-count { display:none; font-weight:400; color:var(--text-faint); font-variant-numeric:tabular-nums; }
@media (max-width: 1280px) {
  .chain-rail .cr-step:not(.current), .chain-rail .cr-sep { display:none; }
  .chain-rail .cr-count { display:inline; }
}
.cmdk-trigger { white-space:nowrap; }
.seg-tb button { white-space:nowrap; }

/* ==== ui.js EXPLAIN_CSS ==== */
/* THE POPOVER — a one-line peek, not a modal. WCAG 1.4.13: hoverable (the
   pointer may travel into it), dismissible (Esc and outside click), persistent
   (it does not vanish on its own), and tap-openable, which is what kills the
   title=-only dead ends this replaces. */
.popover { position:absolute; z-index:120; max-width:min(360px, calc(100vw - 24px));
  background:var(--surface); color:var(--text); border:1px solid var(--border-strong);
  border-radius:var(--r-md); box-shadow:var(--shadow-md); padding:12px 14px;
  font-size:var(--fs-data); line-height:var(--lh-caption); }
.popover .pop-term { font-weight:600; font-size:var(--fs-ui); margin-bottom:7px; color:var(--text); }
.popover .pop-sec { margin-top:8px; }
.popover .pop-sec:first-of-type { margin-top:0; }
.popover .pop-h { font-size:var(--fs-micro); font-weight:600; text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--text-faint); margin-bottom:2px; }
.popover .pop-b { color:var(--text-muted); }
.popover .pop-verbatim { white-space:pre-wrap; color:var(--text); }
.popover .pop-x { position:absolute; top:4px; right:4px; }
/* THE AFFORDANCE — quiet, square (it is a reading's companion, not a chip),
   and a real button so a keyboard and a screen reader can both reach it. */
.explain-tag { display:inline-flex; align-items:center; justify-content:center; vertical-align:baseline;
  width:15px; height:15px; margin-left:4px; padding:0; border:0; background:transparent;
  color:var(--text-faint); cursor:pointer; border-radius:var(--r-xs); line-height:0; }
.explain-tag:hover, .explain-tag[aria-expanded="true"] { color:var(--accent-text); background:var(--sunken); }
.explain-tag svg { width:12px; height:12px; }
/* THE MARKED-TRANSLATION ATOM — after a translated or data-borne value. */
.i18n-orig { display:inline-flex; align-items:center; justify-content:center; vertical-align:baseline;
  margin-left:3px; padding:0 1px; border:0; background:transparent; color:var(--text-faint);
  font-size:var(--fs-micro); line-height:1; cursor:pointer; }
.i18n-orig:hover { color:var(--accent-text); }
/* PRINT PARITY — on paper a popover cannot be opened, so the definition is
   already on the page as bracketed text and the affordance itself disappears.
   A dead ? on a printed dossier is worse than no ? at all. */
.explain-print { display:none; }
@media print {
  .explain-tag, .i18n-orig { display:none; }
  .explain-print { display:inline; font-style:italic; color:var(--text-muted); }
  .popover { display:none; }
}
/* The empty state's provenance strip — a designed statement of the limit, set
   apart from the hint rather than whispered in faint text under it. */
.empty-status { margin-top:14px; text-align:left; max-width:var(--measure-note);
  margin-left:auto; margin-right:auto; }

/* ==== realize.js BRIEF_CSS ==== */
.dossier-brief .pv-sec { margin-bottom: 18px; }
.dossier-brief .pv-h { display:flex; align-items:baseline; gap:8px; font-size:var(--fs-ui); font-weight:600;
  margin:0 0 8px; padding-bottom:6px; border-bottom:1px solid var(--border); }
.dossier-brief .pv-ord { color:var(--text-faint); font-variant-numeric:tabular-nums; min-width:16px; }
.dossier-brief .pv-row { display:flex; gap:12px; padding:6px 0; border-bottom:1px solid var(--border); font-size:var(--fs-data); }
.dossier-brief .pv-row:last-child { border-bottom:0; }
.dossier-brief .pv-k { flex:0 0 210px; color:var(--text-faint); }
.dossier-brief .pv-val { flex:1; color:var(--text); }
.dossier-brief .pv-bi { display:flex; flex-direction:column; }
.dossier-brief .pv-primary { font-weight:600; }
.dossier-brief .pv-secondary { color:var(--text-muted); }
.dossier-brief .pv-list { margin:0; padding-left:18px; }
.dossier-brief .pv-chips { display:inline-flex; gap:4px; margin-left:6px; }
.dossier-brief .pv-chip { display:inline-block; padding:0 6px; border:1px solid var(--border); border-radius:var(--r-pill);
  font-size:var(--fs-micro); line-height:16px; color:var(--text-muted); background:var(--surface); }
.dossier-brief .pv-directive { border-color:var(--purple); color:var(--purple-text); background:var(--purple-soft); }
/* OWNER RULING R1 — the short on-screen commercial rationale, rendered by the
   SAME realizePrint.js function the PDF's long form comes from (depth:'screen').
   R2's judgment chip is a third disclosure beside the neutral basis chip and
   §7A's directive chip, so it gets its own colour rather than reusing either. */
.dossier-brief .pv-rationale { margin-bottom: 18px; }
/* E3b — the advisor panel, between the rationale and the brief sections. */
.dossier-brief .pv-panel { margin-bottom: 18px; }
.dossier-brief .pv-panelrow { padding:8px 0; border-bottom:1px solid var(--border); font-size:var(--fs-data); }
.dossier-brief .pv-panelrow:last-child { border-bottom:0; }
.dossier-brief .pv-panelname { font-weight:600; display:flex; align-items:baseline; gap:6px; margin-bottom:3px; }
.dossier-brief .pv-sub { color:var(--text-faint); font-size:var(--fs-caption); margin:0 0 8px; }
/* Dossier judgment styling follows STANDING-TYPE-DESIGN.md §3.4. */
.dossier-brief .pv-judgment { border-color:var(--purple); color:var(--purple-text); background:var(--purple-soft); }
/* judgment-layer.md §B.2.6 — the domain chip and the stated mechanism, styled on
   the SCREEN surface too. A judgment rendered without its mechanism is the
   "assertion wearing a chip" the lane exists to prevent, so this is not
   print-only decoration. Same class names as realizePrint.js's own stylesheet. */
.dossier-brief .pv-jdomain { border-style:dashed; border-color:var(--purple); color:var(--purple-text); }
.dossier-brief .pv-jreason { margin-top:3px; font-size:var(--fs-data); color:var(--text-muted);
  border-left:2px solid var(--purple); padding-left:7px; }
.dossier-brief .pv-jlabel { font-family:var(--font); font-weight:600; margin-right:5px; }

/* W4.T6 (brief D10) — THE EXPERT REVIEW STRIP, under the section it judges.
   Tokens only: dark mode is defined at token level in this file, so the strip
   follows the theme without a second palette of its own.
   THE OBJECTION IS NEVER SIGNALLED BY COLOUR ALONE. It carries its own word
   ("Objection" · "反对意见"), a heavier rule down its edge and a bordered chip,
   so a greyscale print and a colour-blind reader get the same signal a colour
   display does. */
.dossier-brief .pv-review { margin:8px 0 4px; padding-left:10px; border-left:2px solid var(--border-strong); }
.dossier-brief .pv-reviewlabel { font-size:var(--fs-caption); letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--text-faint); margin-bottom:4px; }
.dossier-brief .pv-reviewrow { padding:5px 0; font-size:var(--fs-data); }
.dossier-brief .pv-reviewrow[data-verdict="object"] { border-left:3px solid var(--seal); margin-left:-10px; padding-left:8px; background:var(--seal-soft); }
.dossier-brief .pv-reviewhead { font-weight:600; display:flex; align-items:baseline; gap:6px; margin-bottom:2px; }
.dossier-brief .pv-reviewverdict { font-weight:400; font-style:italic; color:var(--text-muted); }
.dossier-brief .pv-objection { font-weight:700; text-transform:uppercase; letter-spacing:var(--track-caps); font-size:var(--fs-micro);
  color:var(--seal-text); border:1px solid var(--seal); border-radius:var(--r-xs); padding:0 4px; }
.dossier-brief .pv-reviewedit { margin-top:3px; font-size:var(--fs-caption); color:var(--text-muted); }
.dossier-brief .pv-reviewedit > summary { cursor:pointer; }
/* WS-B (NPD Deepening §3) — the per-field "Why" line. Danni asked what each line
   stands on and Diego asked to see it "under each box", so it is VISIBLE BY
   DEFAULT and never a fold-out; "typographically secondary" is what keeps the
   claim the thing you read first. Muted and smaller like .pv-jreason, and
   deliberately a NEUTRAL rule rather than that block's --info border: the
   judgment lane's blue means "this is the engine's own labelled call", and a
   basis is carried by every field, so borrowing the colour would say every
   field was a professional judgment. */
.dossier-brief .pv-basis-why { margin-top:3px; font-size:var(--fs-data); color:var(--text-muted);
  border-left:2px solid var(--border); padding-left:7px; }
.dossier-brief .pv-why-label { font-weight:600; margin-right:5px; color:var(--text-faint); }
.dossier-brief .pv-decision { margin:7px 0; padding-left:7px; border-left:2px solid var(--border); font-size:var(--fs-data); color:var(--text); }
.dossier-brief .pv-decision-chosen { font-weight:600; }
.dossier-brief .pv-decision-why, .dossier-brief .pv-decision-lever { margin-top:3px; }
.dossier-brief .pv-decision-alternatives { margin-top:5px; color:var(--text-muted); }
.dossier-brief .pv-decision-alternative { margin-top:4px; }
.dossier-brief .pv-decision-unresolved { color:var(--text-muted); font-style:italic; }
.dossier-brief .pv-withheld { font-family:var(--font); color:var(--danger-text); font-style:italic; }
/* D16 (controller ruling, 2026-09-11) — the judgment-by-nature disclosure. It
   sits with the judgment lane's own vocabulary (--purple, the same rule
   .pv-jreason uses) because that is what it is: a judgment. What it must NOT
   read as is a passing grade — the leaf is scoped out of the density ratio,
   not promoted — so it keeps the muted secondary weight every disclosure line
   on this card has, and the chip is dashed like .pv-jdomain rather than solid
   like a resolved citation. Tokens only, so dark mode is defined once. */
.dossier-brief .pv-bynature { margin-top:3px; font-size:var(--fs-data); color:var(--text-muted);
  border-left:2px solid var(--purple); padding-left:7px; }
.dossier-brief .pv-bynature-chip { border-style:dashed; border-color:var(--purple); color:var(--purple-text);
  margin-right:5px; }

/* ============================================================
   lane:folio — STANDING TYPE Wave 3 (§3.4): the folio frame and
   the footing apparatus, SCREEN half. The print half of every
   rule here lives in realizePrint.js's PRINT_CSS. The sigil/
   tag/footing/stamp primitives themselves are styles.css's
   (Wave 1); this block carries only what is folio-specific.
   ============================================================ */
/* The reading frame: the dossier announces itself as the deliverable.
   lane:cardsplit — WIDENED 800 → 880px, and the measure is the reason. The
   verdict rail costs 240px + a 24px gutter; inside an 800px frame that leaves
   the serif column ~458px, under --measure (68ch ≈ 510px at --fs-prose), so the
   card would have broken its own measure rule to make room for the rail. 880
   restores it (~538px) and is still one column of paper, not a dashboard. */
.dossier-brief { max-width:880px; margin:0 auto; background:var(--surface);
  border-radius:var(--r-md); padding:var(--sp-6) var(--sp-7); }
/* The masthead: kicker h2, serif concept title, mono ids, ONE strong rule. */
.dossier-brief .folio-kicker { font:600 var(--fs-caption)/1 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps-wide); color:var(--ink-muted); margin:0 0 8px; }
.dossier-brief .folio-mast { display:flex; align-items:baseline; gap:12px; flex-wrap:wrap;
  padding-bottom:10px; border-bottom:1px solid var(--rule-strong); margin-bottom:var(--sp-5); }
.dossier-brief .folio-title { flex:1; font:600 var(--fs-title)/1.3 var(--font-serif);
  color:var(--ink); letter-spacing:-.01em; }
.dossier-brief .folio-ids { font:400 var(--fs-micro)/1.6 var(--mono); color:var(--ink-faint);
  text-align:right; display:flex; align-items:center; gap:8px; }
/* Section identity: dual-script museum heads + a quiet 2px left tick keyed off
   data-section — hairline and running head between sections, never new boxes. */
.dossier-brief .pv-card-sec { border-left:2px solid transparent; padding-left:12px; margin-bottom:var(--sp-6); }
.dossier-brief .pv-card-sec[data-section="card:opportunity"] { border-left-color:var(--info); }
.dossier-brief .pv-card-sec[data-section="card:proposition"] { border-left-color:var(--purple); }
.dossier-brief .pv-card-sec[data-section="card:evidence"] { border-left-color:var(--ev-observed); }
.dossier-brief .pv-card-sec[data-section="card:challenge"] { border-left-color:var(--warn); }
.dossier-brief .pv-card-sec[data-section="card:identity"] { border-left-color:var(--accent); }
.dossier-brief .pv-card-h { border-bottom:1px solid var(--hairline); }
.dossier-brief .pv-card-h .pv-h-en { font:600 var(--fs-caption)/1 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps-wide); color:var(--ink-muted); }
.dossier-brief .pv-card-h .pv-h-zh { font-weight:650; margin-left:8px; color:var(--ink); letter-spacing:normal; }
/* Fields: small-caps eyebrow labels; serif prose values at measure, FULL ink
   for every status — the sigil carries the ladder, never a faded sentence. */
.dossier-brief .pv-card-sec .pv-row { border-bottom:0; padding:8px 0; }
.dossier-brief .pv-card-sec .pv-k { font:600 var(--fs-micro)/1.6 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps-wide); color:var(--text-faint); }
.dossier-brief .pv-card-sec .pv-val { font:400 var(--fs-prose)/var(--lh-prose) var(--font-serif);
  color:var(--text); max-width:var(--measure); font-feature-settings:'onum'; }
.dossier-brief .pv-card-sec .pv-chips { font-family:var(--font); }
.dossier-brief .pv-card-sec .pv-ref-chip { font-family:var(--mono); }
/* THE FOOTING (screen specifics over styles.css's primitive). */
.dossier-brief .ft-status { font:600 var(--fs-micro)/1 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--ink-muted); }
.dossier-brief .ft-zh { text-transform:none; letter-spacing:0; font-weight:400; }
.dossier-brief .ft-zh::before { content:"· "; }
.dossier-brief .sigil.ev-unfooted { border:1.5px dashed var(--ev-assumption-border); }
.dossier-brief .ft-kind { font-size:var(--fs-micro); color:var(--ink-muted); }
.dossier-brief .pv-footing { margin-top:2px; }
.dossier-brief .pv-fold { margin-top:2px; }
.dossier-brief .pv-fold > summary { list-style:none; cursor:pointer; }
.dossier-brief .pv-fold > summary::-webkit-details-marker { display:none; }
.dossier-brief .pv-apparatus { margin:8px 0 4px var(--footing-indent); padding-left:12px;
  border-left:1px solid var(--hairline); }
.dossier-brief .pv-appmeta { margin:4px 0; }
.dossier-brief .pv-appmeta .pv-chips { margin-left:0; }
/* Cited passages: hanging-indent serif quotations with mono source tags. */
.dossier-brief .pv-quote { margin:8px 0; padding-left:16px; text-indent:-16px;
  font-family:var(--font-serif); font-style:italic; color:var(--text); }
.dossier-brief .pv-quote-src { font:400 var(--fs-micro)/1 var(--mono); font-style:normal;
  color:var(--ink-faint); margin-left:8px; }
/* Coherence failure reasons in the apparatus (warn, never red — red is refusal's). */
.dossier-brief .pv-cohfail { font-size:var(--fs-caption); color:var(--warn-text); margin-bottom:3px; }
.dossier-brief .pv-cohtest { font-weight:600; text-transform:uppercase; letter-spacing:var(--track-caps); margin-right:6px; }
/* The Why-line, restyled (§3.4): the analyst's voice — italic serif at data
   size in muted ink behind the NEUTRAL 2px hairline rule (this override is
   card-only in practice, since only card leaves carry basis_reasoning). */
.dossier-brief .pv-card-sec .pv-basis-why { font-family:var(--font-serif); font-style:italic;
  font-size:var(--fs-data); color:var(--ink-muted); border-left:2px solid var(--hairline); padding-left:12px; }
.dossier-brief .pv-card-sec .pv-why-label { font-family:var(--font); font-style:normal;
  font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:var(--track-caps); }
/* Confidence levels + the ten §6.7 basis classes — quiet border hues only. */
.dossier-brief .pv-conf-high { border-color:var(--ev-observed); color:var(--ev-observed); }
.dossier-brief .pv-conf-medium { border-color:var(--ev-supported); color:var(--ev-supported); }
.dossier-brief .pv-conf-low { border-color:var(--warn); color:var(--warn-text); background:var(--warn-soft); }
.dossier-brief .pv-conf-stated { border-color:var(--warn); color:var(--warn-text); }
.dossier-brief .pv-conf-judged { border-color:var(--purple); color:var(--purple-text); }
.dossier-brief .pv-conf-research-pending { border-color:var(--warn); color:var(--warn-text); border-style:dashed; }
.dossier-brief .pv-basis-trend { border-color:var(--info); }
.dossier-brief .pv-basis-chain_constraint { border-color:var(--info-text); }
.dossier-brief .pv-basis-regulatory { border-color:var(--warn-text); }
.dossier-brief .pv-basis-world_knowledge { border-color:var(--border-strong); }
.dossier-brief .pv-basis-research_pack { border-color:var(--ok); }
.dossier-brief .pv-basis-observed_market { border-color:var(--ev-observed); }
.dossier-brief .pv-basis-fs_capability { border-color:var(--border-strong); }
.dossier-brief .pv-basis-derived { border-color:var(--ev-hypothesis); }
.dossier-brief .pv-basis-user_directive { border-color:var(--warn); }
.dossier-brief .pv-basis-professional_judgment { border-color:var(--purple); }
.dossier-brief .pv-refchips { display:flex; gap:4px; flex-wrap:wrap; }
/* lane:folio — the coherence strip in the card header. Page-namespaced (.rlz-)
   like WAVE_CSS's rules: it sits in the header row, outside .dossier-brief. */
.rlz-coh { display:inline-flex; gap:4px; align-items:center; flex-wrap:wrap; }
.rlz-coh .tag.ok { color:var(--ok-text); border-color:var(--ok); }
.rlz-coh .tag.fail { color:var(--warn-text); background:var(--warn-soft); border-color:var(--warn); }
.rlz-coh .tag.refused { color:var(--seal-text); background:var(--seal-soft); border-color:var(--seal); }
/* F-50 — the refusal SENTENCE beside the needs-review tag, and the entailment
   judge's unjudged-claim line above the gate failures. Both are disclosures,
   so they read as the apparatus does: muted, small, never copper (no money
   moves here). Tokens only — dark mode follows --text-muted and --seal-text. */
.rlz-coh-refusal { color:var(--text-muted); font-size:var(--fs-micro); line-height:1.4; }
.rlz-judge-unavailable { color:var(--text-muted); font-size:var(--fs-micro); line-height:1.5; margin:0 0 6px; }
.rlz-judge-unavailable .ek { margin-right:4px; }

/* ============================================================
   lane:cardsplit — SPLIT VERDICT (owner pick B, 2026-08-17).
   The concept card's SCREEN arrangement: the claim on the left,
   the footing's own content standing beside it as a verdict
   rail on the right, so "what is this sentence standing on?"
   costs no eye travel. The FIELDS are untouched (Danni's locked
   dimensions) — this rearranges presentation and nothing else.

   SCREEN ONLY. realizePrint.js emits these classes solely under
   `opts.split`, which only the cockpit call site passes, so the
   PDF keeps the stacked footing form and PRINT_CSS never sees a
   selector below. The whole geometry lives here rather than in
   the renderer, which is what makes that separation structural.
   ============================================================ */
/* The container is the FOLIO ITSELF, not the viewport: the frame sits beside a
   260px sidebar, so a viewport rule would hold the split open at ~1000px wide
   where the frame is only ~690px and the measure collapses. The row responds to
   the width it actually has. */
.dossier-brief { container-type:inline-size; container-name:folio; }
/* THE ROW. Claim column | 240px verdict rail; the apparatus is a THIRD grid
   item spanning both columns, which is what lets a fold open FULL-WIDTH beneath
   the row instead of inside a 240px column. */
.dossier-brief .pv-splitrow { display:grid; grid-template-columns:minmax(0,1fr) 240px;
  column-gap:24px; row-gap:0; align-items:start; }
.dossier-brief .pv-splitrow > .pv-claimcol { grid-column:1; grid-row:1; min-width:0; }
.dossier-brief .pv-splitrow > .pv-railcell { grid-column:2; grid-row:1; margin-top:0; }
.dossier-brief .pv-splitrow > .pv-apparatus { grid-column:1 / -1; grid-row:2; margin-left:0; }
/* The fold's state, read from OUTSIDE the <details> — the apparatus is a
   sibling of the fold, not a child, because a <details> hides every non-summary
   child and that would have forced the claim prose inside <summary>. Written as
   "hide when CLOSED" on purpose: a browser without :has() renders the apparatus
   OPEN. This surface may show more than asked; it may never swallow disclosure. */
.dossier-brief .pv-splitrow:has(> .pv-railcell:not([open])) > .pv-apparatus { display:none; }
/* THE CLAIM COLUMN. The eyebrow now sits ABOVE the serif value (the under-field
   form ran them side by side); the Why-line stays WITH the prose, visible by
   default and never folded — the analyst's voice belongs beside the sentence. */
.dossier-brief .pv-splitrow > .pv-claimcol > .pv-k { margin-bottom:3px; }
/* THE RAIL. The same footing parts — the renderer builds them once — stacked
   instead of strung out: sigil + bilingual status word on the first line, then
   the grounding kind, the mono ref, the vintage stamp, each on its own. A GRID
   rather than a wrapping flex line, because wrapping is what the rail must not
   do: a 240px column would break "Hypothesis · 假设 · seasonal-regional" at
   whatever width the words happened to reach, and the reading order of a
   verdict is not negotiable. Each item keeps its own intrinsic width
   (justify-items:start) — a tag stretched to the column would read as a band.
   The 24px hairline lead-in belongs to the under-field form; here the rail's
   own left hairline does that work. */
.dossier-brief .pv-splitrow .pv-rail { display:grid; grid-template-columns:auto minmax(0,1fr);
  align-items:center; justify-items:start; column-gap:6px; row-gap:6px;
  margin-top:0; max-width:none;
  border-left:1px solid var(--hairline); padding-left:14px; }
.dossier-brief .pv-splitrow .pv-rail::before { content:none; }
.dossier-brief .pv-splitrow .pv-rail > .sigil { grid-column:1; grid-row:1; }
.dossier-brief .pv-splitrow .pv-rail > .ft-status { grid-column:2; grid-row:1; }
/* CHOICE is the one state with no sigil (Law 3 — a choice is not a claim, and
   never wears a claim's mark), so its word takes the whole first line rather
   than sitting indented past an empty sigil column. */
.dossier-brief .pv-splitrow .pv-rail.ft-choice > .ft-status { grid-column:1 / -1; }
.dossier-brief .pv-splitrow .pv-rail > .ft-kind,
.dossier-brief .pv-splitrow .pv-rail > .ref,
.dossier-brief .pv-splitrow .pv-rail > .stamp-vintage { grid-column:1 / -1; }
/* The rail IS the trigger, and it already reads as one: .pv-railcell carries
   .pv-fold, so the folio's existing `.pv-fold > summary` rule (no marker,
   cursor:pointer) dresses it. The claim column stays outside the <summary>,
   so its prose is selectable and clicking a sentence toggles nothing. */
/* THE FALLBACK. Below ~760px of folio width the two columns cannot both hold a
   readable measure, so the grid collapses to one column and the rail restyles
   back into the horizontal footing line under the field — the same form the PDF
   keeps. CSS only: the markup does not change with the width. */
@container folio (max-width: 760px) {
  .dossier-brief .pv-splitrow { display:block; }
  .dossier-brief .pv-splitrow > .pv-railcell { margin-top:2px; }
  /* back to the footing line: one flex row that wraps. The grid placements
     above need no undoing — a flex item ignores grid-column outright. */
  .dossier-brief .pv-splitrow .pv-rail { display:flex; margin-top:4px;
    column-gap:8px; row-gap:8px; max-width:var(--measure-note);
    border-left:0; padding-left:0; }
  .dossier-brief .pv-splitrow .pv-rail::before { content:""; }
  .dossier-brief .pv-splitrow > .pv-apparatus { margin-left:var(--footing-indent); }
}

/* ============================================================
   lane:deepen — W4.T7, THE DEEPENING ON THE GLASS. Two surfaces
   in one block because they are one gesture: the SELECTION
   (a checkbox per deepenable field, the live count, the armed
   verb) and the DEPTH FOLDS the run writes under those fields.
   The print half of every `.pv-depth*` rule here lives in
   realizePrint.js's PRINT_CSS — that document has its own
   <head>, which is the one allowlisted exemption of the
   style-ownership gate. Every colour is a TOKEN, so dark mode
   is defined where every other colour is and this block has no
   opinion about it.
   ============================================================ */
/* The checkbox rides the field's own eyebrow label — the operator chooses on
   the artifact, not in a side list that would make him match names by eye.
   ABSENT on a leaf this build cannot deepen (see realizePrint.deepenBoxHtml);
   there is nothing to style for that case, which is the point. */
.dossier-brief .pv-deepen-box { display:inline-flex; align-items:center; margin-right:7px; vertical-align:baseline; cursor:pointer; }
.dossier-brief .pv-deepen-box input { --check:var(--armed); width:14px; height:14px; margin:0; cursor:pointer; }
.dossier-brief .pv-deepen-secbox { margin:4px 0 6px; }
/* THE ARMED STRIP. Copper (`--armed`) is the app's money colour and it is worn
   here because this strip is a paid click with a disclosed estimate on it —
   and only then: the LOCKED form below drops back to the neutral surface,
   because a control that cannot spend must not look like one that can. */
.rlz-deepen { margin-top:12px; padding:10px 12px; border-radius:var(--r-md);
  border:1px solid var(--border); background:var(--surface-2); }
.rlz-deepen.armed { border-color:var(--armed); background:var(--armed-soft); }
.rlz-deepen-head { display:flex; align-items:baseline; flex-wrap:wrap; gap:10px; }
.rlz-deepen-title { font:600 var(--fs-caption)/1.4 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps-wide); color:var(--ink-muted); }
.rlz-deepen-count { font-size:var(--fs-data); color:var(--text-muted); }
.rlz-deepen-row { display:flex; align-items:center; flex-wrap:wrap; gap:10px; margin-top:8px; }
.rlz-deepen-est { font:400 var(--fs-data)/1 var(--mono); color:var(--spend-ink); }
.rlz-deepen-est.pending { color:var(--text-faint); font-family:var(--font); }
.rlz-deepen-why { margin-top:6px; font-size:var(--fs-caption); color:var(--text-muted); max-width:var(--measure-note); }
.rlz-deepen-targets { margin-top:6px; font-size:var(--fs-micro); color:var(--text-faint); overflow-wrap:anywhere; }
/* The run's own disclosures, under the strip: research, the deepening, and
   (Task I) the expert review when one is present. */
.rlz-deepen-report { margin-top:8px; font-size:var(--fs-caption); color:var(--text-muted); }
.rlz-deepen-report dl { display:grid; grid-template-columns:max-content 1fr; gap:2px 10px; margin:4px 0 0; }
.rlz-deepen-report dt { color:var(--text-faint); }
.rlz-deepen-report dd { margin:0; color:var(--text); }

/* W6.T5 — WHICH CARDS A BATCH VERB IS OVER. Above the tabs, never inside one:
   a checkbox inside a tab is a click that means two things, and the one
   pressed by accident is the one that costs money. Tokens only. */
.rlz-batch-cards { display:flex; align-items:baseline; flex-wrap:wrap; gap:6px 12px;
  margin-bottom:10px; padding:8px 10px; border:1px solid var(--hairline);
  border-radius:var(--r-md); background:var(--surface-2); }
.rlz-batch-card { display:inline-flex; align-items:baseline; gap:5px;
  font-size:var(--fs-data); color:var(--text-muted); cursor:pointer; }
.rlz-batch-card input { --check:var(--armed); width:14px; height:14px; margin:0; cursor:pointer; }
.rlz-batch-dropped { margin-top:6px; font-size:var(--fs-micro); color:var(--text-faint);
  max-width:var(--measure-note); overflow-wrap:anywhere; }
.ter-var-modes { display:flex; align-items:baseline; flex-wrap:wrap; gap:6px 14px; margin:8px 0; }
.ter-var-mode-opt { display:inline-flex; align-items:baseline; gap:5px;
  font-size:var(--fs-data); color:var(--text-muted); cursor:pointer; }
.ter-var-mode-opt input { --check:var(--armed); width:14px; height:14px; margin:0; cursor:pointer; }
/* THE DEPTH FOLDS, screen half. Same class names as realizePrint.js's own
   stylesheet, the idiom the decision block and the apparatus already use. */
.dossier-brief .pv-depth { margin:8px 0 10px var(--footing-indent); padding-left:12px;
  border-left:2px solid var(--border-strong); }
.dossier-brief .pv-depth > summary { font:600 var(--fs-caption)/1.5 var(--font); color:var(--ink-muted); }
.dossier-brief .pv-depth-body { margin-top:6px; }
.dossier-brief .pv-depth-group { margin:10px 0; }
.dossier-brief .pv-depth-grouplabel { font:600 var(--fs-micro)/1.6 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps-wide); color:var(--text-faint); margin-bottom:4px; }
/* Wide content scrolls INSIDE its own box; the folio never scrolls sideways. */
.dossier-brief .pv-depth-scroll { overflow-x:auto; }
.dossier-brief .pv-depth-table { width:100%; border-collapse:collapse; font:400 var(--fs-data)/1.5 var(--font); }
.dossier-brief .pv-depth-table th { text-align:left; font-weight:600; color:var(--text-faint);
  border-bottom:1px solid var(--hairline); padding:3px 8px 3px 0; vertical-align:bottom; }
.dossier-brief .pv-depth-table td { padding:5px 8px 5px 0; vertical-align:top; border-bottom:1px solid var(--hairline); color:var(--text); }
/* A components depth is eight columns wide and every cell is bilingual, so the
   cells must be allowed to WRAP before the table resorts to its scroller — a
   column that scrolled out of sight by default would hide the D5 range, which
   is the one cell that carries a disclosure. */
.dossier-brief .pv-depth-table th, .dossier-brief .pv-depth-table td { overflow-wrap:break-word; }
.dossier-brief .pv-depth-table .pv-bi { font-family:var(--font); }
/* The fold is a TABLE under a field, not prose beside it: it is allowed the
   folio's whole width rather than the claim column's measure. */
.dossier-brief .pv-depth .pv-bi { max-width:none; }
.dossier-brief .pv-depth-why { padding-bottom:9px; }
.dossier-brief .pv-depth-why .pv-decision { margin:2px 0 0; }
.dossier-brief .pv-depth-ground { display:block; margin-bottom:5px; }
.dossier-brief .pv-depth-from { margin-right:4px; }
.dossier-brief .pv-depth-range { white-space:nowrap; font-family:var(--mono); }
/* A HEADER THAT READS VERTICALLY IS A HEADER NOBODY READS. "Order of
   addition" is the last and narrowest column, so the Chinese header
   stacked one character per line and the English value jammed against
   the proportion range beside it. The table already scrolls inside
   `.pv-depth-scroll`, so the column is simply allowed to be wide. */
.dossier-brief .pv-depth-table th { white-space:nowrap; }
.dossier-brief .pv-depth-order { white-space:nowrap; min-width:4.5em; }
.dossier-brief .pv-depth-rangeto { color:var(--text-faint); font-family:var(--font); }
/* The D5 tag beside a range, and the disclosure that governs every one of them.
   Warn-toned, never copper: no money moves here, and never danger-toned, which
   is refusal's colour — an unvalidated starting point is neither. */
.dossier-brief .pv-depth-rdtag { display:block; white-space:normal; font:600 var(--fs-micro)/1.4 var(--font);
  text-transform:uppercase; letter-spacing:var(--track-caps); color:var(--warn-text); }
.dossier-brief .pv-depth-rd { margin:0 0 14px; padding:7px 11px; border:1px solid var(--warn);
  background:var(--warn-soft); color:var(--warn-text); border-radius:var(--r-xs); font-size:var(--fs-caption); }
.dossier-brief .pv-depth-rd span { display:block; }
.dossier-brief .pv-depth-refused { margin:4px 0 6px var(--footing-indent); font-size:var(--fs-caption);
  color:var(--text-muted); font-style:italic; }
/* A figure the calculator could not produce, said in words. Never a blank and
   never a zero: a nutrient nobody priced is a fact, and a zero would be a
   measurement this engine never made. */
.dossier-brief .pv-depth-absent { color:var(--text-faint); font-style:italic; }
/* An enum token this build has no word for renders as the token, visibly
   undressed. It is a defect made legible, never a state to hide. */
.dossier-brief .pv-enumword-unlabelled { font-family:var(--mono); color:var(--warn-text); }

/* ============================================================
   lane:art — W7.T4, THE ART DIRECTION ON THE GLASS. The fold
   that says what a picture was decided to be before it was
   drawn, the critique checklist of what came back, and the
   steered re-render pair. The print half of every `.pv-art*`
   rule here lives in realizePrint.js's PRINT_CSS, exactly as
   the depth folds' does.

   WHY THIS BLOCK REDECLARES A FEW `pv-*` BASE RULES. Every
   other `pv-*` rule in this stylesheet is scoped under
   `.dossier-brief`, and this block renders on TWO surfaces
   that are not inside it: the dossier panel above the brief,
   and the Design Suite's concept card, which has no brief at
   all. So the shared sub-elements the fold emits (the chips,
   the bilingual pair, the D2 record) are dressed again under
   `.pv-art-block`. Hoisting the base rules out of
   `.dossier-brief` would be the better fix and is a pass of
   its own — it would restyle every surface that borrows them.
   TASK S REVIEW, 2026-09-11: reviewed and LEFT AS IS on
   purpose — the hoisting is a separate pass with its own
   regression surface, and folding it into a fix commit would
   restyle pages this commit never looked at.

   Every colour is a TOKEN, so dark mode is defined where every
   other colour is and this block has no opinion about it.
   ============================================================ */
.pv-art-block { margin-top:12px; }
.pv-art-record { margin:10px 0; }
.pv-art-shot { font:600 var(--fs-micro)/1.6 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--text-faint); }
.pv-art-block .pv-art { margin:6px 0 10px; padding-left:12px; border-left:2px solid var(--border-strong); }
.pv-art-block .pv-art > summary { font:600 var(--fs-caption)/1.5 var(--font); color:var(--ink-muted); cursor:pointer; }
.pv-art-body { margin-top:6px; }
/* Wide content scrolls INSIDE its own box; neither page scrolls sideways. */
.pv-art-scroll { overflow-x:auto; }
.pv-art-table { width:100%; border-collapse:collapse; font:400 var(--fs-data)/1.5 var(--font); }
.pv-art-table th { text-align:left; font-weight:600; color:var(--text-faint);
  border-bottom:1px solid var(--hairline); padding:3px 8px 3px 0; vertical-align:bottom; }
.pv-art-table td { padding:5px 8px 5px 0; vertical-align:top; border-bottom:1px solid var(--hairline); color:var(--text); }
.pv-art-table th, .pv-art-table td { overflow-wrap:break-word; }
.pv-art-table .pv-art-tr > td { border-bottom:0; }
.pv-art-tr-why > td { padding-bottom:9px; }
.pv-art-why { padding-bottom:0; }
/* The shared sub-elements, dressed for the two surfaces that are not the
   brief. Same declarations as their `.dossier-brief` twins above. */
.pv-art-block .pv-bi { display:flex; flex-direction:column; }
.pv-art-block .pv-primary { font-weight:600; }
.pv-art-block .pv-secondary { color:var(--text-muted); }
.pv-art-block .pv-chips { display:inline-flex; flex-wrap:wrap; gap:4px; }
.pv-art-block .pv-chip { display:inline-block; padding:0 6px; border:1px solid var(--border); border-radius:var(--r-pill);
  font-size:var(--fs-micro); line-height:16px; color:var(--text-muted); background:var(--surface); }
.pv-art-block .pv-why-label { font-weight:600; margin-right:5px; color:var(--text-faint); }
.pv-art-block .pv-decision { margin:2px 0 0; padding-left:7px; border-left:2px solid var(--border);
  font-size:var(--fs-data); color:var(--text); }
.pv-art-block .pv-decision-chosen { font-weight:600; }
.pv-art-block .pv-decision-why, .pv-art-block .pv-decision-lever { margin-top:3px; }
.pv-art-block .pv-decision-alternatives { margin-top:5px; color:var(--text-muted); }
.pv-art-block .pv-decision-alternative { margin-top:4px; }
.pv-art-block .pv-decision-unresolved { color:var(--text-muted); font-style:italic; }
.pv-art-block .pv-withheld { font-family:var(--font); color:var(--danger-text); font-style:italic; }
/* An element or a checklist item this build has no word for renders as the
   token, visibly undressed. A defect made legible, never a state to hide. */
.pv-art-block .pv-enumword-unlabelled { font-family:var(--mono); color:var(--warn-text); }
/* THE POINTER CHIP. On the glass a dossier leaf is a BUTTON — it scrolls to
   the row that decided the picture — and every other pointer is the same chip
   without the affordance, because a control that goes nowhere is worse than
   no control. */
.pv-art-from { margin-right:4px; }
button.pv-art-jump { cursor:pointer; font-family:inherit; }
button.pv-art-jump:hover { border-color:var(--accent); color:var(--text); }
/* The artifact moved under this picture. Warn-toned, never copper (no money
   moves in saying so) and never danger-toned (a stale render is not a refusal). */
.pv-art-stale { margin:0 0 8px; padding:7px 11px; border:1px solid var(--warn); background:var(--warn-soft);
  color:var(--warn-text); border-radius:var(--r-xs); font-size:var(--fs-caption); }
.pv-art-stale span { display:block; }
.pv-art-refused { margin:5px 0; font-size:var(--fs-micro); color:var(--text-faint); }
/* THE CRITIQUE CHECKLIST. */
.pv-art-crit { margin:8px 0; }
.pv-art-crit-head { margin-bottom:4px; }
.pv-art-note { margin:5px 0; font-size:var(--fs-caption); color:var(--text-muted); max-width:var(--measure-note); }
.pv-art-failed { color:var(--text); }
/* WHICH RENDER A CRITIQUE IS ABOUT, and what the steer carried. Both are
   captions on a verdict, not verdicts — quieter than the note they sit above,
   and never a colour that would read as a pass or a fail. */
.pv-art-crit-of { margin:0 0 5px; font-style:italic; color:var(--text-faint); }
.pv-art-steer-applied { color:var(--text-muted); }
/* The verdict carries a GLYPH as well as a word, so it never rides colour
   alone: a reader who cannot tell the two hues apart still reads the verdict. */
.pv-art-verdict { white-space:nowrap; font-weight:600; }
.pv-art-glyph { margin-right:4px; }
.pv-art-pass { color:var(--ok-text); }
.pv-art-fail { color:var(--danger-text); }
.pv-art-unstated { color:var(--text-muted); }
.pv-art-meta { margin-top:5px; }
/* COPPER ONLY WHERE MONEY MOVED: a critique is a paid vision call, and this is
   the one chip in the block that reports spend. */
.pv-art-block .pv-art-usd { color:var(--spend-ink); font-family:var(--mono); }
/* THE PAIR — the render that failed, the steer, and the one re-render it
   bought. Three columns on a wide screen, stacked when there is no room. */
.pv-art-rerender { margin:10px 0; }
.pv-art-pair { display:grid; grid-template-columns:1fr minmax(0,220px) 1fr; gap:12px; align-items:start; margin-top:6px; }
.pv-art-side, .pv-art-steer { min-width:0; }
.pv-art-sidelabel { font:600 var(--fs-micro)/1.5 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--text-faint); margin-bottom:4px; }
@media (max-width: 880px) { .pv-art-pair { grid-template-columns:1fr; } }

/* ============================================================
   lane:recipe — W5.T6, THE RECIPE ON THE GLASS. The door beside
   "Realize the spec" and the view the run writes beneath it.
   The strip REUSES lane:deepen's `.rlz-deepen*` rules (the two
   doors are one gesture over two questions and should not look
   like two products), so only the option-count chooser is new;
   the view REUSES `.pv-depth*` for its tables, so only what a
   recipe has and a depth does not is declared here. The print
   half of every `.pv-recipe*` rule lives in realizePrint.js's
   PRINT_CSS. Every colour is a TOKEN, so dark mode is defined
   where every other colour is and this block has no opinion
   about it.
   ============================================================ */
.rlz-recipe-k { display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-caption); color:var(--text-muted); }
.rlz-recipe-klabel { color:var(--text-faint); }
.rlz-recipe-k select { font:400 var(--fs-data)/1.4 var(--font); color:var(--text);
  background:var(--surface); border:1px solid var(--border); border-radius:var(--r-xs); padding:3px 6px; }
/* THE OPTION TABS. Screen only by CODE PATH (renderPrintView passes no
   `tabs`), so there is deliberately no print counterpart for these rules. */
.dossier-brief .pv-recipe-tabs { display:flex; flex-wrap:wrap; gap:6px; margin:6px 0 10px; }
.dossier-brief .pv-recipe-tab { font:400 var(--fs-data)/1.4 var(--font); color:var(--text-muted);
  background:var(--surface-2); border:1px solid var(--border); border-radius:var(--r-xs);
  padding:4px 10px; cursor:pointer; }
.dossier-brief .pv-recipe-tab.on { color:var(--text); border-color:var(--border-strong); background:var(--surface); font-weight:600; }
.dossier-brief .pv-recipe-optname { font:600 var(--fs-ui)/1.4 var(--font); margin:12px 0 4px; }
.dossier-brief .pv-recipe-option, .dossier-brief .pv-recipe-process { margin-bottom:14px; }
.dossier-brief .pv-recipe-note { font-size:var(--fs-micro); color:var(--text-faint); margin:3px 0; max-width:var(--measure-note); }
.dossier-brief .pv-recipe-missing { margin:3px 0 6px; padding-left:18px; font-size:var(--fs-data); color:var(--text); }
.dossier-brief .pv-recipe-missing li { margin-bottom:3px; }
.dossier-brief .pv-recipe-disclosure { margin-top:6px; }
.dossier-brief .pv-recipe-dl { display:grid; grid-template-columns:max-content 1fr; gap:2px 10px;
  margin:4px 0 0; font-size:var(--fs-data); }
.dossier-brief .pv-recipe-dl dt { color:var(--text-faint); }
.dossier-brief .pv-recipe-dl dd { margin:0; color:var(--text); }
/* A unit symbol this build has no word for. `parameter_range.unit` is an OPEN
   symbol by schema, so an unfamiliar one is DATA and wears the mono face —
   never the warn tone `.pv-enumword-unlabelled` gives a closed enum that
   should have had a label. */
.dossier-brief .pv-recipe-unitsym { font-family:var(--mono); }

/* ==== realize.js CHAT_CSS ==== */
.rlz-flash { outline:2px solid var(--accent); outline-offset:3px; border-radius:var(--r-md); }

/* ==== realize.js SHARED_RLZ_CSS ==== */
.rlz-note { margin-top:8px; padding:6px 9px; border-radius:var(--r-xs); font-size:var(--fs-caption); }
.rlz-note.warn { border-left:2px solid var(--warn); background:var(--warn-soft); color:var(--warn-text); }
.rlz-note.plain { border-left:2px solid var(--border-strong); background:var(--surface-2); color:var(--text-muted); }
.rlz-advanced { margin-top:10px; }
.rlz-advanced > summary { cursor:pointer; font-size:var(--fs-caption); color:var(--text-muted); }
.rlz-preflight { display:flex; align-items:center; flex-wrap:wrap; gap:4px; margin-top:8px; }
/* WAVE D — imagery. A render is additive: if nothing renders, nothing here
   occupies the page, and a non-render is never styled like a product shot. */
.rlz-shots { display:grid; grid-template-columns:repeat(auto-fill, minmax(190px, 1fr)); gap:12px; margin-top:10px; }
.rlz-shot { border:1px solid var(--border); border-radius:var(--r-md); padding:8px; background:var(--surface-2); }
.rlz-shot img { width:100%; height:auto; display:block; border-radius:var(--r-xs); background:var(--surface); }
.rlz-shot.not-a-shot { border-style:dashed; border-color:var(--warn); background:var(--warn-soft); }
.rlz-shot .rlz-shotlabel { font-size:var(--fs-caption); font-weight:600; margin-top:6px; }
.rlz-shot .rlz-shotmeta { font-size:var(--fs-micro); color:var(--text-faint); overflow-wrap:anywhere; margin-top:3px; }
.rlz-shot .rlz-shotwarn { font-size:var(--fs-caption); color:var(--warn-text); margin-top:5px; }

/* ==== realize.js WAVE_CSS ==== */
.rlz-dir-echo { font-size:var(--fs-caption); color:var(--text-muted); margin-top:6px; }
.rlz-thumb { width:100%; max-width:180px; border-radius:var(--r-xs); display:block; margin-bottom:8px; }
.rlz-thumb-note { font-size:var(--fs-micro); color:var(--warn-text); margin-bottom:8px; }
/* WAVE E — the chain evidence meter replaces the binary research-pending flag. */
.rlz-meter { display:flex; gap:2px; margin:5px 0 3px; }
.rlz-seg { flex:1; height:5px; border-radius:1px; background:var(--surface); border:1px solid var(--border); }
.rlz-seg.t-filed_document, .rlz-seg.t-public_primary { background:var(--ok); border-color:var(--ok); }
.rlz-seg.t-peer_reviewed, .rlz-seg.t-trade_press { background:var(--accent); border-color:var(--accent); }
.rlz-seg.t-sector_default { background:var(--text-faint); border-color:var(--text-faint); }
/* fetched but below the admission bar — warmer than never-attempted, still not evidence */
.rlz-seg.t-sourced_untierable { background:var(--warn); border-color:var(--warn); opacity:.55; }
.rlz-seg.t-research_pending { background:var(--warn); border-color:var(--warn); }
.rlz-tierline { font-size:var(--fs-micro); color:var(--text-muted); }

/* USABILITY WAVE — trend board and run target. The pre-flight strip's own rule
   moved to SHARED_RLZ_CSS above: two pages paint that strip now.

   STANDING TYPE §1.2 Law 8 / §3.2 — THE SCROLL TRAP IS DEAD. The board used to
   be max-height:420px + overflow-y:auto, an inner-scrolling widget that trapped
   the wheel on the one surface where a buyer compares before paying. The rows
   now flow in the PAGE, and the length is governed by progressive disclosure
   ("Show all N") rather than by a cage.

   THE CARD GRID IS GONE with the INDEX LEDGER (owner's pick F) — `.rlz-tb-grid`
   and the macro-theme group heads went with it, and the rules below are what the
   ledger still paints: the Auto-select row (the one surviving card), the shared
   confidence meter, the two quiet text actions and the ghost "Show all N" row. */
.rlz-trend-board { display:flex; flex-direction:column; gap:var(--sp-3); }
.rlz-tb-more { display:flex; justify-content:center; }
.rlz-tb-more button { background:none; border:1px dashed var(--border-strong); border-radius:var(--r-sm);
  color:var(--ink-muted); font:600 var(--fs-caption)/1 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; padding:9px 18px; cursor:pointer; width:100%; }
.rlz-tb-more button:hover { background:var(--surface-2); color:var(--ink); }
.rlz-tb-more button:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }

/* THE AUTO-SELECT ROW — the one card the ledger keeps, and the reason it keeps
   its own look: it is not a trend, so it has no rank, no momentum and no quote,
   and a table row of em-dashes would claim it were a trend with nothing measured. */
.rlz-trend-card { display:flex; gap:var(--sp-3); border:1px solid var(--hairline); border-radius:var(--r-md);
  border-left:2px solid transparent; padding:var(--sp-3) var(--sp-4); background:var(--surface); }
.rlz-trend-card:hover { background:var(--surface-2); }
/* Selected = 2px ink left rule + surface-2, never a green fill. */
.rlz-trend-card.pinned { border-left-color:var(--ink); background:var(--surface-2); }
.rlz-tc-folio { flex:0 0 34px; font:500 20px/1.1 var(--font-serif); color:var(--text-faint);
  font-variant-numeric:tabular-nums; }
.rlz-tc-body { flex:1; min-width:0; }
.rlz-tc-name { font:600 var(--fs-ui)/1.35 var(--font); color:var(--ink); }
.rlz-tc-alt { color:var(--text-muted); font-weight:400; margin-left:6px; }
/* The raw group id is a CITATION, never a headline (§1.2 Law 6). */
.rlz-tc-ref { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint); margin-top:2px; }
/* Confidence is its OWN vocabulary: a labelled tag plus a three-step ink meter.
   §5.15 — never remapped onto the evidence sigils, and never through
   statusClass()'s risk colours (high=danger would read a strong trend as a
   hazard). */
.rlz-conf { display:inline-flex; align-items:center; gap:6px; }
.rlz-conf .rlz-conf-meter { display:inline-flex; gap:2px; }
.rlz-conf .rlz-conf-meter i { width:9px; height:4px; border:1px solid var(--border-strong); border-radius:1px; }
.rlz-conf .rlz-conf-meter i.on { background:var(--ink-muted); border-color:var(--ink-muted); }
.rlz-tc-actions { display:flex; align-items:center; gap:var(--sp-4); margin-top:var(--sp-2); }
/* The ~20 green buttons die: one quiet text action per entry. */
.rlz-tc-source { background:none; border:0; padding:0; cursor:pointer; font:600 var(--fs-caption)/1.4 var(--font);
  color:var(--accent-text); }
.rlz-tc-source:hover { text-decoration:underline; }
.rlz-tc-source:focus-visible { outline:2px solid var(--accent); outline-offset:3px; border-radius:2px; }
.rlz-tc-pin { background:none; border:0; padding:0; cursor:pointer; font:400 var(--fs-caption)/1.4 var(--font);
  color:var(--ink-faint); }
.rlz-tc-pin:hover { color:var(--ink); text-decoration:underline; }
.rlz-tc-pin:focus-visible { outline:2px solid var(--accent); outline-offset:3px; border-radius:2px; }
.rlz-tb-prov { font-size:var(--fs-caption); margin-top:4px; }
.rlz-run-target { margin:0; display:flex; gap:6px; align-items:center; flex-wrap:wrap; font-size:var(--fs-caption); }
.rlz-run-target .chip.active { border-color:var(--accent, var(--info)); font-weight:600; }
#runBtn.rlz-flash { box-shadow:0 0 0 3px var(--accent, var(--info)); transition:box-shadow .3s; }

/* ==========================================================================
   STANDING TYPE wave 2 — the doorway plates, the armed strip, the disclosure
   ========================================================================== */

/* THE SHARED DISCLOSURE. Replaces the two bare <details>: a chevron, a real
   focus ring, and routine mechanism prose folded away WITHOUT ever folding a
   honesty-critical sentence (those stay in the flow, by rule). */
.rlz-disc { border-top:1px solid var(--hairline); margin-top:var(--sp-3); }
.rlz-disc > summary { list-style:none; cursor:pointer; display:flex; align-items:center; gap:8px;
  padding:8px 0; font:600 var(--fs-caption)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-muted); }
.rlz-disc > summary::-webkit-details-marker { display:none; }
.rlz-disc > summary::before { content:""; flex:none; width:0; height:0; border-left:5px solid currentColor;
  border-top:4px solid transparent; border-bottom:4px solid transparent; transition:transform var(--dur) var(--ease); }
.rlz-disc[open] > summary::before { transform:rotate(90deg); }
.rlz-disc > summary:hover { color:var(--ink); }
.rlz-disc > summary:focus-visible { outline:2px solid var(--accent); outline-offset:2px; border-radius:2px; }
.rlz-disc .rlz-disc-body { padding:0 0 var(--sp-3) 13px; }
/* The receipt is a LEDGER line, so its summary is set in the ledger's voice. */
.rlz-disc.mono > summary { font-family:var(--mono); text-transform:none; letter-spacing:0; font-weight:400; }

/* THE SERIAL SECTIONS (operator directive 2026-08-27, replacing the one-row
   doorway plates). Sections read top-to-bottom in work order but stay
   UNNUMBERED (§5.16) — reading order, not a mandatory sequence. Selection
   rides the BORDER and a small tag only — every section keeps the one shared
   ground, so no section ever reads as a different-colored segment. */
.rlz-sec { display:block; border-top:1px solid var(--hairline); border-left:2px solid transparent;
  margin-top:var(--sp-4); padding:var(--sp-4) 0 var(--sp-2) var(--sp-3); }
/* Since ONE MANIFEST (2026-09-02) the sections follow the pot, the footing, the
   add-chain control, the floors strip and the run target, so no section is the
   panel body's first child any more: the hairline above THE ROOT is the wanted
   divider between the pot area and the sections, not a leak of this rule. */
.rlz-sec:first-child { border-top:0; margin-top:0; padding-top:0; }
.rlz-sec.selected { border-left-color:var(--ink); }
.rlz-sec .rlz-sec-head { display:flex; align-items:center; gap:var(--sp-2); }
.rlz-sec .rlz-sec-line { font:400 var(--fs-prose)/var(--lh-prose) var(--font-serif); color:var(--ink-muted);
  margin:var(--sp-2) 0 var(--sp-3); max-width:var(--measure); }
/* The SELECTED tag: hidden until its section is the armed root — one painter
   (paintArmedStrip) owns the toggle, so the tag and the manifest agree. */
.rlz-sel-tag { display:none; font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--on-accent); background:var(--ink); border-radius:var(--r-sm);
  padding:1px 6px; }
.rlz-sec.selected > .rlz-sec-head .rlz-sel-tag { display:inline-block; }

/* ONE MANIFEST (operator directive 2026-09-02). Under the pot: the territory
   footing with its Lab door, the add-chain button, and THE CHAIN FLOORS —
   each chain's evidence floor stated where the chain is read. The
   retail-customer grid that carried this meter is gone; the honesty is not. */
.rlz-pot-footing { display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-2); margin-top:var(--sp-3); }
.rlz-addchain-box { margin-top:var(--sp-2); }
.rlz-floors { display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:var(--sp-2) var(--sp-4);
  margin:var(--sp-3) 0 0; }
.rlz-floor { display:block; font-size:var(--fs-caption); line-height:var(--lh-caption); }
.rlz-floor-name { display:block; font-weight:600; margin-bottom:2px; }
.rlz-floor-prov { display:block; margin-top:2px; }

/* THE ARMED STRIP — the manifest, and the only place the armed copper appears.
   Sticky at the viewport FOOT since the serial restructure (operator directive
   2026-08-27). The sticky seat is the #armedStrip MOUNT, not the inner
   .rlz-armed: sticky is confined to its containing block, and the inner strip's
   block is the mount's own zero-slack box (the exact no-op the 2026-08-27
   review caught — twice: the old top seat had it too). The mount is the panel
   body's last direct child, so its block spans the whole panel and the pin is
   real: while the directed-run panel is in view, the request and its price ride
   the viewport foot — the same "read before money moves" duty, one screen edge
   down. z-index below the topbar (30) and far below the toast host (200): §5.6. */
#armedStrip { position:sticky; bottom:var(--sp-3); z-index:var(--z-armed); }
.rlz-armed { margin:var(--sp-3) 0;
  border:1px solid var(--border-strong); border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4);
  background:var(--surface); }
.rlz-armed.ghost { border-style:dashed; color:var(--ink-muted); }
.rlz-armed.armed { border-color:var(--border-strong); border-top:3px solid var(--armed); }
.rlz-armed.armed .spend { color:var(--armed-text); }
.rlz-armed-line { display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2) var(--sp-4);
  font-size:var(--fs-caption); }
.rlz-armed-k { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-faint); margin-right:5px; }
.rlz-armed-line .rlz-armed-v { color:inherit; }
.rlz-armed-go { margin-left:auto; }
.rlz-armed-go button { background:var(--armed); color:var(--on-accent); border:0; border-radius:var(--r-sm);
  padding:9px 20px; cursor:pointer; font:600 var(--fs-ui)/1 var(--font); }
.rlz-armed-go button:hover { background:var(--armed-hover); }
.rlz-armed-go button:active { background:var(--armed-press); }
.rlz-armed-go button:focus-visible { outline:2px solid var(--armed-ring); outline-offset:3px; }
/* A blocked arming STATES ITS REASON. It is never a dead button. */
.rlz-armed .rlz-armed-why { margin-top:6px; font-size:var(--fs-caption); }

/* THE TERRITORY BANNER — one paint target, .notice.judged, fusion stated
   BEFORE the click rather than discovered on the card. */
#stalenessBanner .notice { margin-bottom:14px; }
#territoryBanner .rlz-terbanner { display:flex; flex-direction:column; gap:5px; }
#territoryBanner .rlz-terbanner .rlz-terhead { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; }
#territoryBanner .rlz-terbanner .rlz-tername { font:600 var(--fs-section)/1.3 var(--font-serif); color:var(--ink); }
#territoryBanner .rlz-terbanner .rlz-terfuse { font:italic 400 var(--fs-caption)/1.5 var(--font-serif); color:var(--ink-muted); }

/* EDITORIAL EMPTY STATE — 24px hairline rule, kicker, one serif sentence, a
   ghost action, and a provenance strip that states the session scoping. */
.rlz-empty { padding-top:var(--sp-5); }
.rlz-empty::before { content:""; display:block; width:24px; height:1px; background:var(--rule-strong); margin-bottom:var(--sp-4); }
.rlz-empty .rlz-empty-kicker { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); }
.rlz-empty .rlz-empty-lead { font:400 var(--fs-prose)/var(--lh-prose) var(--font-serif); color:var(--ink);
  max-width:var(--measure); margin-top:var(--sp-2); }
.rlz-empty ol.rlz-steps { list-style:none; margin:var(--sp-4) 0 0; padding:0; }
.rlz-empty ol.rlz-steps li { padding:5px 0; border-bottom:1px solid var(--hairline); }
.rlz-empty ol.rlz-steps li:last-child { border-bottom:0; }
.rlz-steplink { background:none; border:0; padding:0; cursor:pointer; text-align:left;
  font:400 var(--fs-caption)/1.5 var(--font); color:var(--accent-text); }
.rlz-steplink:hover { text-decoration:underline; }
.rlz-steplink:focus-visible { outline:2px solid var(--accent); outline-offset:3px; border-radius:2px; }
.rlz-empty .rlz-empty-act { margin-top:var(--sp-4); }
.rlz-empty .rlz-empty-prov { margin-top:var(--sp-4); font-size:var(--fs-caption); color:var(--ink-muted);
  border-top:1px solid var(--hairline); padding-top:var(--sp-2); max-width:var(--measure); }

/* ==========================================================================
   STANDING TYPE wave 4 — the run rail, the odometer, the receipt, the Colophon
   ========================================================================== */
/* THE SPEND ODOMETER — a climbing figure over a track carrying the DISCLOSED
   band as bracket marks. Above band is --warn, NEVER red: an overrun is a
   disclosure, not a refusal (red is reserved for refusals). */
.rlz-odo { margin-top:var(--sp-3); padding-top:var(--sp-3); border-top:1px solid var(--hairline); }
.rlz-odo-head { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; font-size:var(--fs-caption); color:var(--ink-muted); }
.rlz-odo-v { font-family:var(--mono); font-variant-numeric:tabular-nums; font-size:var(--fs-section); color:var(--spend-ink); }
.rlz-odo[data-band="over"] .rlz-odo-v { color:var(--warn-text); }
.rlz-odo-track { position:relative; height:6px; margin-top:6px; background:var(--sunken); border-radius:2px; }
.rlz-odo-fill { position:absolute; left:0; top:0; bottom:0; background:var(--spend-ink); border-radius:2px; }
.rlz-odo[data-band="over"] .rlz-odo-fill { background:var(--warn); }
.rlz-odo-mark { position:absolute; top:-3px; bottom:-3px; width:1px; background:var(--ink-muted); }
.rlz-odo-mark::before { content:""; position:absolute; left:0; top:0; width:4px; height:2px; background:var(--ink-muted); }
.rlz-odo-mark.hi::before { left:-3px; }
.rlz-odo-mark::after { content:""; position:absolute; left:0; bottom:0; width:4px; height:2px; background:var(--ink-muted); }
.rlz-odo-mark.hi::after { left:-3px; }

/* THE RECEIPT — one mono line the rail collapses into, opening the Colophon. */
.rlz-receipt { font-family:var(--mono); font-size:var(--fs-data); color:var(--ink-muted); }
.rlz-colophon { margin-top:var(--sp-5); padding-top:var(--sp-4); border-top:1px solid var(--hairline); }
.rlz-colophon .rlz-colo-h { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); }
.rlz-colophon .rlz-colo-note { font:400 var(--fs-prose)/var(--lh-prose) var(--font-serif); color:var(--ink);
  max-width:var(--measure); margin-top:var(--sp-2); }
.rlz-ledger { margin-top:var(--sp-4); font-family:var(--mono); font-size:var(--fs-data); }
.rlz-ledger .rlz-lrow { display:flex; align-items:baseline; gap:6px; padding:3px 0; }
.rlz-ledger .rlz-lname { color:var(--ink); white-space:nowrap; }
.rlz-ledger .rlz-lleader { flex:1; border-bottom:1px dotted var(--border-strong); transform:translateY(-3px); }
.rlz-ledger .rlz-lval { color:var(--ink-muted); font-variant-numeric:tabular-nums; white-space:nowrap; }
.rlz-ledger .rlz-lrow.total { margin-top:5px; padding-top:6px; border-top:1px solid var(--rule-strong); }
.rlz-ledger .rlz-lrow.absent .rlz-lval { color:var(--warn-text); }

/* THE TASTING NOTE — score_detail as a ledger, opened beside a ranked card. */
.rlz-taste { margin-top:var(--sp-3); }
.rlz-taste .rlz-trow { display:flex; align-items:center; gap:8px; padding:4px 0; border-bottom:1px solid var(--hairline);
  font-size:var(--fs-caption); }
.rlz-taste .rlz-trow:last-child { border-bottom:0; }
.rlz-taste .rlz-tname { flex:0 0 9.5em; color:var(--ink); }
.rlz-taste .rlz-tw { font-family:var(--mono); color:var(--ink-faint); font-variant-numeric:tabular-nums; }
.rlz-taste .rlz-tmeter { flex:1; min-width:60px; height:3px; background:var(--sunken); border-radius:2px; }
.rlz-taste .rlz-tmeter i { display:block; height:100%; background:var(--accent); border-radius:2px; }
.rlz-taste .rlz-trow.excluded { color:var(--ink-faint); }
.rlz-taste .rlz-trow.excluded .rlz-tname { text-decoration:line-through; }
.rlz-taste .rlz-tfoot { font:italic 400 var(--fs-caption)/1.5 var(--font-serif); color:var(--ink-muted); margin-top:var(--sp-2); }
.rlz-tag-judged { color:var(--purple-text); }
.rlz-tag-measured { color:var(--info-text); }
/* Spend-vs-band, beside a figure rather than in place of it. */
.rlz-bandmeter { display:inline-flex; align-items:center; gap:5px; }
.rlz-bandmeter .rlz-bm-track { position:relative; width:64px; height:4px; background:var(--sunken); border-radius:2px; }
.rlz-bandmeter .rlz-bm-in { position:absolute; top:0; bottom:0; background:var(--ok); opacity:.35; }
.rlz-bandmeter .rlz-bm-at { position:absolute; top:-2px; bottom:-2px; width:2px; background:var(--spend-ink); }
.rlz-bandmeter[data-ok="false"] .rlz-bm-at { background:var(--warn); }

/* ==========================================================================
   THE INDEX LEDGER — the trend board's table (owner's pick F, 2026-08-17)
   ==========================================================================
   The card grid could not be compared: three figures at three heights in every
   card meant reading 148 cards to answer "which is strongest". One column per
   figure, and the eye ranks them. */

/* The toolbar that drives the table. The search box is NOT here — it sits above,
   outside the container the board repaints, so the field being typed into
   survives a repaint. */
.rlz-lg-tools { display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap; }
.rlz-lg-toollabel { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); }
.rlz-lg-tools .chip.active { border-color:var(--ink); color:var(--ink); font-weight:600; }

/* SIDEWAYS ONLY, and only here: the wrap owns any horizontal overflow so the
   PAGE never scrolls sideways, and it takes no max-height — the scroll cage
   §1.2 Law 8 killed does not come back as a table. */
.rlz-lg-wrap { border:1px solid var(--hairline); border-radius:var(--r-md); background:var(--surface); }
/* NO second sticky at the top of the page. §5 resolved the running-head vs
   armed-strip collision in the strip's favour; `.table thead th` is sticky by
   default, so the ledger opts out rather than re-open it. */
.rlz-index thead th { position:static; }
.rlz-index th.rlz-lg-rank { text-align:right; }
.rlz-index tbody td { vertical-align:top; padding:10px 14px; }
/* The folio: a rank IN THE CURRENT SORT, serif and faint — never mistakable for
   a rank the engine assigned, because re-sorting renumbers it. */
.rlz-index .rlz-lg-rank { width:44px; text-align:right; font:500 var(--fs-ui)/1.45 var(--font-serif);
  color:var(--text-faint); font-variant-numeric:tabular-nums; }
.rlz-index .rlz-lg-trend { min-width:13em; }
.rlz-index .rlz-lg-name { font:600 var(--fs-ui)/1.35 var(--font); color:var(--ink); }
.rlz-index .rlz-lg-flag { margin-top:5px; }
/* MOMENTUM keeps its readout LABEL in the markup — that is the enforcement that
   makes a bare decimal unrenderable — and spends the ink once, in the column
   header. Hidden from the glass, still read aloud. */
.rlz-index .rlz-lg-mom .readout { justify-content:flex-end; }
.rlz-index .rlz-lg-mom .readout-meter { width:56px; }
.rlz-index .rlz-lg-mom .readout-l, .rlz-lg-hide { position:absolute; width:1px; height:1px; margin:-1px;
  padding:0; overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; }
.rlz-index .rlz-lg-mentions { font-variant-numeric:tabular-nums; }
/* VOICE — one verbatim quote, truncated by CSS so the source text stays whole in
   the atom's `data-original` instead of being cut to 120 characters in JS. */
/* 22ch (was 26) keeps both row actions inside a 1400px viewport's container —
   a half-clipped "Pin" read as a defect on the walk; the wrap still scrolls
   for narrower windows and the full quote rides the ⊕ original affordance. */
.rlz-index .rlz-lg-voice { max-width:22ch; }
.rlz-index td:last-child { white-space:nowrap; }
.rlz-index .rlz-lg-voice .ter-src { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  font:italic 400 var(--fs-caption)/1.5 var(--font-serif); color:var(--ink-muted); }
.rlz-index .rlz-lg-act { white-space:nowrap; text-align:right; }
.rlz-index .rlz-lg-act .rlz-tc-pin { margin-left:var(--sp-3); }
/* SELECTED/ARMED — the same vocabulary the card carried: a 2px ink left rule and
   surface-2, never a green fill. */
.rlz-index tbody tr.pinned > td { background:var(--surface-2); }
.rlz-index tbody tr.pinned > td:first-child { box-shadow:inset 2px 0 0 var(--ink); }
.rlz-index tbody tr.pinned:hover > td { background:var(--surface-2); }
/* The ghost row that opens the rest — a row of the table, not a control beside it. */
.rlz-index .rlz-lg-morerow > td { padding:0; }
.rlz-index .rlz-lg-morerow:hover > td { background:none; }
.rlz-index .rlz-lg-morerow .rlz-tb-more button { border:0; border-radius:0; }
.rlz-lg-empty { padding-top:var(--sp-4); }

/* ==== territory.js TER_CSS ==== */
/* ---- THE CARD (STANDING-TYPE-DESIGN.md §3.3) -----------------------------
   Same seven dimensions, restructured: headline, footing bar, tension, the
   claim-bearing leaves with their footings, the quiet tier as a definition
   grid, key uncertainty last and set apart. */
.ter-head { display:flex; align-items:baseline; gap:8px; flex-wrap:wrap; margin-bottom:6px; }
.ter-card { margin-bottom:12px; border-left:2px solid transparent; }
/* the decision, made permanent on the card itself: approved reads in the
   observed ink, rejected keeps the seal AND keeps its reason on screen —
   refusal is data, never deletion. */
.ter-card[data-status="approved"] { border-left-color:var(--ev-observed); }
.ter-card[data-status="rejected"] { border-left-color:var(--seal); }
.ter-name { font-family:var(--font-serif); font-weight:600; font-size:var(--fs-section); line-height:1.3; color:var(--ink); }

/* THE FOOTING BAR — one square per cited item, so eight cards compare at a
   glance. Assumption (and unrated) is dashed and NEVER filled. */
.ter-footbar { display:flex; gap:2px; flex-wrap:wrap; margin:0 0 10px; }
.ter-fsq { width:8px; height:8px; border-radius:1px; flex:none; }
.ter-fsq.ev-observed { background:var(--ev-observed); }
.ter-fsq.ev-supported { background:linear-gradient(90deg,var(--ev-supported) 0 50%,transparent 50%); border:1px solid var(--ev-supported); }
.ter-fsq.ev-hypothesis { border:1px solid var(--ev-hypothesis); }
.ter-fsq.ev-assumption { border:1px dashed var(--ev-assumption-border); }

.ter-opportunity { font-family:var(--font-serif); font-size:var(--fs-prose); line-height:var(--lh-prose);
  color:var(--ink); max-width:var(--measure); margin-bottom:10px; }
.ter-claim { margin-top:10px; }
.ter-flabel { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); display:flex; align-items:center; gap:6px; }
:lang(zh-CN) .ter-flabel { text-transform:none; letter-spacing:.02em; font-weight:650; }
.ter-fval { font-family:var(--font-serif); font-size:var(--fs-prose); line-height:1.6;
  color:var(--ink); max-width:var(--measure); }
.ter-status { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps); text-transform:uppercase; }
:lang(zh-CN) .ter-status { text-transform:none; letter-spacing:.02em; }
.ter-status.ev-observed { color:var(--ev-observed); }
.ter-status.ev-supported { color:var(--ev-supported); }
.ter-status.ev-hypothesis { color:var(--ev-hypothesis); }
.ter-status.ev-assumption { color:var(--ev-assumption); }
.footing .ter-clamp { color:var(--warn-text); font-size:var(--fs-micro); }

/* the quiet tier, as a definition grid */
.ter-defs { display:grid; grid-template-columns:9.5em 1fr; row-gap:7px; column-gap:10px; margin:12px 0 0; }
.ter-dt { font:600 var(--fs-micro)/1.6 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); }
:lang(zh-CN) .ter-dt { text-transform:none; letter-spacing:.02em; font-weight:650; }
.ter-dd { margin:0; font-family:var(--font-serif); font-size:14px; line-height:1.6; color:var(--ink); }
.ter-none { color:var(--ink-faint); }
/* (ALIGN's three rules are gone with the Align mode — the REGISTRY MATRIX at
   the foot of this section is the aligned comparison, done as a matrix.) */
.ter-unknown { margin-top:14px; padding-top:10px; border-top:1px solid var(--hairline); }

/* the apparatus, and the family strip beside its trigger */
.ter-apparatus-bar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin-top:12px; }
.ter-fams { display:inline-flex; gap:10px; flex-wrap:wrap; align-items:center; }
.ter-fam { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--ink-muted); }
.ter-fam b { font-family:var(--mono); font-weight:500; margin-left:3px; }
.ter-fam.is-zero { color:var(--ink-faint); opacity:.5; }
:lang(zh-CN) .ter-fam { text-transform:none; letter-spacing:.02em; }
.ter-apparatus { list-style:none; margin:10px 0 0; padding:0; }
.ter-cite { padding:8px 0 8px 18px; text-indent:-18px; border-top:1px solid var(--hairline); font-size:var(--fs-data); }
.ter-cite-head { display:flex; align-items:center; gap:8px; text-indent:0; }
.ter-cite-tag { margin-left:auto; display:inline-flex; align-items:center; gap:6px; }
.ter-cite-body { margin-top:3px; text-indent:0; padding-left:18px; font-family:var(--font-serif); }
/* the credibility marker and M4's facet tags, LEADING the excerpt — the same
   bytes evidenceCardText puts in front of every prompt and gate line. It borrows
   .tag whole (this is a reading of the row, not a control) and changes only what
   a machine-composed string needs: its own case, and permission to wrap. A
   marker that overran the card would be a marker the approver cannot read. */
.ter-cite-dec { margin-right:6px; text-transform:none; letter-spacing:normal; white-space:normal; }
.ter-cite-limit { margin-top:3px; text-indent:0; padding-left:18px; color:var(--ink-faint); font-size:var(--fs-micro); }

/* the ladder, spelled once above the board */
.ter-legend { display:flex; align-items:center; gap:14px; flex-wrap:wrap; margin:10px 0; font-size:var(--fs-micro); color:var(--ink-muted); }
.ter-legend-l { font-weight:600; letter-spacing:var(--track-caps); text-transform:uppercase; }
:lang(zh-CN) .ter-legend-l { text-transform:none; letter-spacing:.02em; }
.ter-legend-i { display:inline-flex; align-items:center; gap:5px; }

/* HLH — one set-level stamp, three axes, THREE states each */
.ter-matrix { margin:10px 0; }
.ter-matrix-head { display:flex; align-items:baseline; gap:8px; }
.ter-matrix-t { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide); text-transform:uppercase; }
:lang(zh-CN) .ter-matrix-t { text-transform:none; letter-spacing:.02em; }
.ter-matrix-raw { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint); }
.ter-gauges { display:flex; gap:22px; flex-wrap:wrap; margin-top:8px; }
.ter-gauge { display:flex; flex-direction:column; gap:3px; min-width:120px; }
.ter-gauge-l { font-size:var(--fs-micro); color:var(--ink-faint); }
.ter-gauge-t { display:block; height:3px; background:var(--sunken); border-radius:2px; position:relative; }
.ter-gauge-t i { display:block; height:100%; border-radius:2px; background:var(--ink-muted); width:0; }
.ter-gauge[data-state="high"] .ter-gauge-t i { width:100%; }
.ter-gauge[data-state="low"] .ter-gauge-t i { width:34%; }
.ter-gauge[data-state="absent"] .ter-gauge-t { background:transparent; border:1px dashed var(--border-strong); height:5px; }
.ter-gauge-v { font-size:var(--fs-micro); color:var(--ink); font-weight:600; }
.ter-gauge[data-state="absent"] .ter-gauge-v { color:var(--warn-text); }
.ter-matrix-say { font-family:var(--font-serif); font-size:var(--fs-data); margin-top:8px; color:var(--ink); }
.ter-matrix-note { font-size:var(--fs-micro); color:var(--ink-faint); margin-top:5px; max-width:var(--measure); }

/* the toolbar */
.ter-toolbar { display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:10px 0; }
.ter-sort-l { font-size:var(--fs-micro); color:var(--ink-faint); letter-spacing:var(--track-caps); text-transform:uppercase; }
:lang(zh-CN) .ter-sort-l { text-transform:none; letter-spacing:.02em; }

/* refusals, rendered — the reason is the engine's own, word for word */
.ter-refused { margin:10px 0; }
.ter-refused-h { display:flex; align-items:center; gap:7px; }
.ter-refused-hint { font-size:var(--fs-micro); color:var(--ink-muted); margin-top:3px; max-width:var(--measure); }
.ter-refused-l { list-style:none; margin:7px 0 0; padding:0; }
.ter-refused-l li { padding:5px 0; border-top:1px solid var(--hairline); }
.ter-refused-n { font-family:var(--font-serif); font-weight:600; margin-right:8px; }
.ter-refused-w { color:var(--ink-muted); font-family:var(--font-serif); }

.ter-missing { color:var(--warn-text); }
.ter-undated { color:var(--warn-text); }

/* the decision */
.ter-review { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-top:12px;
  padding-top:10px; border-top:1px solid var(--border); }
.ter-review .ter-rationale { flex:1 1 220px; min-width:180px; }
.ter-btn-reject { color:var(--seal-text); }
.ter-btn-reject:hover { background:var(--seal-soft); }
.btn.is-armed { outline:2px solid var(--accent-ring); outline-offset:1px; }
.ter-arm-hint { flex-basis:100%; font-size:var(--fs-micro); color:var(--ink-muted); }
.ter-decided { display:block; }
.ter-decision { display:flex; align-items:center; gap:7px; }
.ter-decision-l { font:600 var(--fs-caption)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink); }
:lang(zh-CN) .ter-decision-l { text-transform:none; letter-spacing:.02em; }
.ter-record { margin-top:5px; padding-left:16px; border-left:2px solid var(--hairline);
  font-family:var(--font-serif); font-style:italic; font-size:var(--fs-data); color:var(--ink-muted); }
.ter-record-l { display:block; font-family:var(--font); font-style:normal; font-weight:600;
  font-size:var(--fs-micro); letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--ink-faint); }
:lang(zh-CN) .ter-record-l { text-transform:none; letter-spacing:.02em; }
.ter-decided .ter-gen { margin-top:8px; }

/* the saved-set LIBRARY (was a <select>, which showed no vintage at all) */
.ter-sets { margin-bottom:12px; }
.ter-sets-head { display:flex; align-items:center; gap:10px; margin-bottom:8px; }
.ter-sets-t { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide); text-transform:uppercase; color:var(--ink-faint); }
:lang(zh-CN) .ter-sets-t { text-transform:none; letter-spacing:.02em; }
.ter-setlist { list-style:none; margin:0; padding:0; }
.ter-set { display:flex; align-items:flex-start; gap:12px; padding:9px 0; border-top:1px solid var(--hairline); }
.ter-set.is-active { border-left:2px solid var(--ink); padding-left:10px; }
.ter-set-l { flex:1 1 auto; min-width:0; }
.ter-set-top { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ter-set-vintage { min-width:0; max-width:100%; white-space:normal; overflow-wrap:anywhere; }
.ter-set-when { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint); }
.ter-set-n { font-size:var(--fs-micro); color:var(--ink-muted); }
.ter-set-mandate { display:block; overflow-wrap:anywhere; font-family:var(--font-serif); font-size:var(--fs-data); color:var(--ink); margin-top:3px; }
.ter-set-note { font-size:var(--fs-caption); color:var(--ink-muted); margin-top:3px; }
.ter-set-mandate.is-none { color:var(--ink-faint); font-style:italic; }
.ter-set-diff { font-size:var(--fs-micro); color:var(--vintage-stale); margin-top:3px; }
.ter-set-a { display:flex; gap:6px; flex-wrap:wrap; flex:none; }
.ter-set-a .btn.is-armed { height:auto; min-height:30px; max-width:420px; padding:6px 10px; line-height:1.25; text-align:left; white-space:normal; }
.ter-set-none { font-size:var(--fs-data); color:var(--ink-faint); }
.ter-sets > .muted { margin-top:6px; }
/* WS-D — the data-borne atom. The original is one GESTURE away: hover on a
   pointer, focus on a touch screen (the span is focusable for that reason), and
   the native title for everything else. It is display:none rather than absent
   so the verbatim source text is always IN the document — a page that shows a
   translation and keeps no original is evidence rewritten. */
.ter-src { position:relative; }
.ter-srcmark { margin-left:5px; padding:0 5px; border-radius:var(--r-pill); border:1px solid var(--border-strong);
  font-size:var(--fs-micro); line-height:15px; color:var(--text-muted); background:var(--surface-2); white-space:nowrap; }
.ter-srcorig { display:none; margin-top:3px; padding:5px 7px; border:1px solid var(--border-strong);
  border-radius:var(--r-sm); background:var(--surface); color:var(--text-muted); font-size:var(--fs-caption); }
.ter-src:hover > .ter-srcorig, .ter-src:focus > .ter-srcorig, .ter-src:focus-within > .ter-srcorig { display:block; }

/* ---- REGISTRY MATRIX (the owner's pick D: the Lab's default view) ---------
   Territories are COLUMNS, dimensions are ROWS. The only thing that scrolls is
   the matrix, and it scrolls SIDEWAYS. §1.2 law 8 forbids a widget that traps
   the wheel, and this one cannot: the wrap is given no height at all, so it
   grows to its content and the y axis has nothing to scroll no matter what the
   computed overflow says. The page keeps its one vertical scroll, and the body
   never scrolls horizontally because the columns are trapped in here.

   The dimension column is STICKY at the left edge. That is not the sticky
   compare rail §5.13 dropped — the rail was a floating strip of pinned CARDS
   duplicating card content; this is the row header of a table staying beside
   the row it names, which is what makes reading across possible at all once the
   fourth column is scrolled into view. */
.ter-registry-wrap { overflow-x:auto; overflow-y:visible; margin:10px 0;
  border-top:1px solid var(--rule-strong); border-bottom:1px solid var(--hairline); }
.ter-registry { border-collapse:collapse; width:max-content; min-width:100%; font-size:var(--fs-data); }
.ter-registry th, .ter-registry td { text-align:left; vertical-align:top; padding:10px 14px 12px;
  border-bottom:1px solid var(--hairline); }
/* ~260px columns: three to four hold at desktop and the rest scroll within the
   container — a serif sentence needs the width, and a matrix that fits eight
   columns on a laptop is eight columns nobody can read. */
.ter-registry .ter-rg-col, .ter-registry .ter-rg-cell { min-width:260px; max-width:320px; }
.ter-registry thead th { border-bottom:1px solid var(--rule-strong); vertical-align:bottom; }
/* the row head, and the corner it hangs under */
.ter-rg-dim, .ter-rg-corner { position:sticky; left:0; z-index:1; background:var(--surface);
  min-width:9.5em; width:9.5em; border-right:1px solid var(--hairline);
  font:600 var(--fs-micro)/1.5 var(--font); letter-spacing:var(--track-caps-wide);
  text-transform:uppercase; color:var(--ink-faint); }
:lang(zh-CN) .ter-rg-dim, :lang(zh-CN) .ter-rg-corner { text-transform:none; letter-spacing:.02em; font-weight:650; }
/* the column head: serif name, the footing bar, then the review mark */
.ter-rg-col > .ter-name { display:block; margin-bottom:7px; }
.ter-rg-col .ter-footbar { margin-bottom:6px; }
.ter-rg-marks { display:inline-flex; gap:6px; align-items:center; flex-wrap:wrap; }
/* THE DECISION, adapted from the card's 2px LEFT rule to a 2px TOP rule on the
   column head — the same rule, the same two inks, rotated onto the column's
   leading edge. A header TINT was the other option and is refused: flooding a
   head with color spends the one accent (§1.2 law 5) on a status that a 2px rule
   already states, and it would put approved and rejected on the same footing as
   the page's one primary verb. */
.ter-rg-col { border-top:2px solid transparent; }
.ter-rg-col[data-status="approved"] { border-top-color:var(--ev-observed); }
.ter-rg-col[data-status="rejected"] { border-top-color:var(--seal); }
/* the cells, by kind — the card's own type, in a narrower measure */
.ter-rg-cell { font-family:var(--font-serif); line-height:1.6; color:var(--ink); }
.ter-rg-prose { font-size:var(--fs-prose); }
.ter-rg-claim, .ter-rg-unknown { font-size:var(--fs-prose); }
.ter-rg-field { font-size:14px; } /* the card's quiet tier (.ter-dd) */
.ter-rg-cell .footing { margin-top:5px; }
.ter-rg-apparatus, .ter-rg-decision { font-family:var(--font); }
.ter-rg-cell .ter-apparatus-bar { margin-top:0; }
.ter-rg-cell .ter-review { margin-top:0; padding-top:0; border-top:0; }
/* a 260px column cannot hold the card's one-line decision row — it stacks */
.ter-rg-decision .ter-review { flex-direction:column; align-items:stretch; }
.ter-rg-decision .ter-review .ter-rationale { flex:none; width:100%; min-width:0; }
/* THE OPEN APPARATUS is a full-width row under the apparatus row, not a drawer
   inside a 260px cell: the citations are set as a bibliography (hanging indent,
   mono source tag at the right margin) and that needs the width. */
.ter-rg-drawer > td { background:var(--sunken); }
.ter-rg-drawer .ter-apparatus { max-width:var(--measure); }
.ter-rg-drawer-h { display:flex; align-items:baseline; gap:8px; }
.ter-rg-drawer-n { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-faint); }
:lang(zh-CN) .ter-rg-drawer-n { text-transform:none; letter-spacing:.02em; }
/* the view toggle that replaced Align */
.ter-views { display:inline-flex; gap:4px; }

/* ==== design.js DESIGN_CSS ==== */
.dsn-list { display:grid; grid-template-columns:repeat(auto-fill, minmax(280px, 1fr)); gap:12px; }
.dsn-card { border:1px solid var(--border); border-radius:var(--r-md); padding:12px; background:var(--surface-2); }
.dsn-card .dsn-name { font-weight:600; font-size:var(--fs-ui); margin-bottom:2px; font-family:var(--font-serif); }
.dsn-card .dsn-name-2 { color:var(--text-muted); font-size:var(--fs-data); margin-bottom:8px; font-family:var(--font-serif); }
.dsn-meta { display:flex; flex-wrap:wrap; gap:6px; align-items:center; margin-bottom:10px; }
.dsn-head { display:flex; flex-wrap:wrap; gap:10px; align-items:center; margin-bottom:6px; }
.dsn-head-main { flex:1 1 280px; min-width:0; }
.dsn-head-main .dsn-name { overflow-wrap:anywhere; word-break:break-word; }
.dsn-sec { margin-top:18px; }
.dsn-note { margin-top:8px; padding:7px 10px; border-radius:var(--r-xs); font-size:var(--fs-caption); }
.dsn-note.plain { border-left:2px solid var(--border-strong); background:var(--surface-2); color:var(--text-muted); }
.dsn-note.warn { border-left:2px solid var(--warn); background:var(--warn-soft); color:var(--warn-text); }
.dsn-note.bad { border-left:2px solid var(--danger); background:var(--danger-soft); color:var(--danger-text); }
.dsn-note.ok { border-left:2px solid var(--ok); background:var(--ok-soft); color:var(--ok-text); }
.dsn-concept { border:1px solid var(--border); border-radius:var(--r-md); padding:14px; background:var(--surface-2); margin-bottom:14px; }
.dsn-concept .dsn-title { font:600 var(--fs-section)/1.3 var(--font-serif); }
.dsn-concept .dsn-title-2 { color:var(--text-muted); font-size:var(--fs-data); margin-bottom:6px; font-family:var(--font-serif); }
.dsn-dir { font:400 var(--fs-data)/1.6 var(--font-serif); color:var(--text); margin:8px 0; }
.dsn-dir-2 { font:400 var(--fs-data)/1.6 var(--font-serif); color:var(--text-muted); margin-bottom:8px; }
.dsn-ovr { width:100%; border-collapse:collapse; font-size:var(--fs-data); margin-top:6px; }
.dsn-ovr th { text-align:left; font-weight:600; color:var(--text-faint); font-size:var(--fs-micro);
  text-transform:uppercase; letter-spacing:.05em; padding:4px 8px 4px 0; border-bottom:1px solid var(--border); }
.dsn-ovr td { padding:5px 8px 5px 0; border-bottom:1px solid var(--border); vertical-align:top; overflow-wrap:anywhere; }
.dsn-ovr tr:last-child td { border-bottom:0; }
.dsn-was { color:var(--text-muted); font-family:var(--font-serif); }
.dsn-now { color:var(--purple-text); font-weight:600; font-family:var(--font-serif); }
.dsn-sub { font-size:var(--fs-caption); color:var(--text-faint); margin-top:3px; }
.dsn-fb { margin-top:12px; }
.dsn-fb textarea { width:100%; resize:vertical; }
.dsn-adv { margin-top:10px; }
.dsn-adv > summary { cursor:pointer; font-size:var(--fs-caption); color:var(--text-muted); }
.dsn-preflight-box { margin-top:6px; }
.dsn-rej { font-size:var(--fs-data); padding:6px 0; border-bottom:1px solid var(--border); }
.dsn-rej:last-child { border-bottom:0; }
.dsn-rej code { font-family:var(--mono); font-size:var(--fs-caption); color:var(--text-faint); }

/* ==== director.js DIRECTOR_CSS ==== */
/* THE DEBT, PAID. styleOwnership.test.js shipped with a second allowlist entry
   because this block fell outside the consolidation lane's file grant and could
   not move with the other eight. It moves here now, rules byte-for-byte, and
   the gate keeps ONE exemption (realizePrint.js, by design). The `.rlz-`
   namespace on the moved markup is HISTORICAL and kept for the same reason the
   page's own header states: the shared builders emit it.

   WHAT THE MOVE FIXES, beyond the ledger. Three of these rules dress markup
   that is NOT the Director's alone — realize.js's exported citationChipHtml
   (`.rlz-cite`), its modeBadgeHtml (`.rlz-mode`) and its own counsel strip
   (`.rlz-warns`). While the rules lived in a page-mounted <style>, a chip
   borrowed onto the Realization Engine painted raw and the Director's copy was
   the only styled one. In the stylesheet the renderer and its rules travel
   together, which is the defect the gate exists to prevent.

   INJECTION ORDER. The block used to be a <style> the page wrote into its own
   markup, i.e. after styles.css, so it won every equal-specificity tie against
   this file. Nothing in styles.css declares `.rlz-transcript`, `.rlz-msg`,
   `.rlz-who`, `.rlz-body`, `.rlz-toollog`, `.rlz-tool`, `.rlz-warns`,
   `.rlz-mode`, `.rlz-fail`, `.rlz-cites`, `.rlz-cite`, `.rlz-brief*` or
   `.dir-*`, and the only rules that reach INSIDE these blocks are the
   `.report-md` element rules (0,1,1), which the `.rlz-body .report-md …`
   selectors below outrank on SPECIFICITY rather than on order. So no rule here
   needed its specificity raised — checked, not assumed. */
.rlz-transcript { min-height:260px; overflow:auto; border:1px solid var(--border);
  border-radius:var(--r-md); background:var(--surface); padding:8px 18px; }
.main:has(.dir-page) > .topbar { flex-shrink:0; }
.content:has(.dir-page), .content > :has(> .dir-page) { flex:1; min-height:0; display:flex; flex-direction:column; }
.dir-page { --dir-transcript-min:max(160px, 30dvh); flex:1; min-height:0; display:flex; flex-direction:column; }
.dir-page > .page-header { flex-shrink:0; }
.dir-chat-panel { flex:1; min-height:0; display:flex; flex-direction:column; margin-bottom:0; }
.dir-chat-body { flex:1; min-height:0; display:flex; flex-direction:column; }
.dir-chat { flex:1; min-height:0; display:flex; flex-direction:column; gap:10px; container-type:size; }
.dir-chat > .rlz-transcript { flex:1; min-height:0; }
@media (min-width: 801px) {
  html:has(.dir-page), body:has(.dir-page) { height:100%; overflow:hidden; }
  #app:has(.dir-page), .app:has(.dir-page) { height:100dvh; min-height:0; overflow:hidden; }
  .main:has(.dir-page) { height:100dvh; min-height:0; overflow:hidden; }
  .content:has(.dir-page) { max-width:none; margin:0; padding:16px 18px; overflow:hidden; flex:1; min-height:0; }
}
@media (max-width: 800px) {
  html:has(.dir-page), body:has(.dir-page) { height:auto; overflow:visible; }
  #app:has(.dir-page), .app:has(.dir-page), .main:has(.dir-page) { height:auto; min-height:100dvh; overflow:visible; }
  .content:has(.dir-page) { overflow:visible; height:auto; max-width:none; margin:0; padding:16px 14px 28px; }
  .dir-page, .dir-chat-panel, .dir-chat-body, .dir-chat { height:auto; min-height:0; }
  .dir-chat > .rlz-transcript { min-height:200px; }
  .dir-history { height:auto; }
}
.dir-chat-body > :not(.dir-chat) { flex-shrink:0; }
/* The missing-secret badge above the brief (directorConfigNoticeHtml): the
   Trend Radar's warn badge, allowed to wrap because it names an env var. */
.dir-config-notice { margin-bottom:10px; }
.dir-config-notice .badge { white-space:normal; text-align:left; }
.dir-input-row { display:flex; flex-shrink:0; gap:8px; align-items:flex-end; }
.dir-input { flex:1; min-width:0; min-height:38px; max-height:30cqh; padding:8px 12px; resize:none; overflow-y:auto; }
@media (max-width: 800px) {
  .dir-chat-panel, .dir-chat-body, .dir-chat { flex:none; height:auto; }
  .dir-chat { container-type:normal; }
  .dir-chat > .rlz-transcript { flex:none; min-height:180px; }
  .dir-input { max-height:none; }
  .dir-input-row { flex-wrap:wrap; justify-content:flex-end; }
  .dir-input-row > .dir-input { flex-basis:100%; }
}
.dir-dossier-run .dsr-readback { margin-top:12px; }
.rlz-msg { display:flex; gap:16px; padding:18px 0; border-bottom:1px solid var(--border); }
.rlz-msg:last-child { border-bottom:0; }
.rlz-msg-user { margin:10px 0; padding:12px 14px; border:0; border-radius:var(--r-md); background:var(--accent-soft); }
.rlz-who { flex:0 0 68px; color:var(--text-faint); font-size:var(--fs-micro); letter-spacing:.05em;
  text-transform:uppercase; padding-top:2px; }
.rlz-body { flex:1; min-width:0; font-size:var(--fs-ui); line-height:1.68; color:var(--text); overflow-wrap:anywhere; }
.rlz-msg-assistant .rlz-body { max-width:82ch; }
.rlz-body .report-md > :first-child { margin-top:0; }
.rlz-body .report-md p { margin:0 0 11px; }
.rlz-msg-assistant .report-md > p:first-of-type { margin-bottom:18px; padding-left:14px; border-left:3px solid var(--accent); font-size:15px; line-height:1.72; }
.rlz-body .report-md h2 { margin-top:26px; padding-bottom:7px; font-size:17px; }
.rlz-body .report-md h3 { margin-top:20px; font-size:15px; }
.rlz-body .report-md .table-wrap { margin:14px 0 20px; }
.rlz-pending .rlz-body { display:flex; align-items:center; gap:9px; color:var(--text-muted); }
.rlz-toollog { display:flex; flex-wrap:wrap; gap:5px; margin-top:8px; }
.rlz-answer-details { margin-top:10px; color:var(--text-muted); font-size:var(--fs-caption); }
.rlz-answer-details > summary { cursor:pointer; width:max-content; color:var(--accent-text); }
.dir-session-details { margin:-10px 0 14px; width:max-content; max-width:100%; color:var(--text-muted); font-size:var(--fs-caption); }
.dir-session-details > summary { cursor:pointer; color:var(--accent-text); }
.dir-session-details > div { margin-top:6px; }
.dir-session-details p { max-width:68ch; margin:4px 0 0; }
.dir-answer-versions { display:flex; flex-wrap:wrap; gap:6px; margin:0 0 14px; }
.dir-translation-estimate { flex-basis:100%; color:var(--text-muted); font-size:var(--fs-caption); }
.dir-translation-state { display:flex; align-items:center; gap:8px; margin:0 0 14px; }
.dir-examples { max-width:650px; margin:-26px auto 34px; padding:0 18px; text-align:center; color:var(--text-muted); font-size:var(--fs-caption); }
.dir-examples > div { margin-bottom:8px; font-weight:600; }
.dir-examples .btn { height:auto; margin:4px; padding:7px 11px; white-space:normal; }
.rlz-actions { display:flex; flex-wrap:wrap; gap:5px; margin-top:8px; }
.rlz-tool { font-size:var(--fs-micro); line-height:17px; padding:0 7px; border-radius:var(--r-pill);
  border:1px solid var(--border-strong); color:var(--text-muted); background:var(--surface); }
.rlz-tool.bad { border-color:var(--danger); color:var(--danger-text); background:var(--danger-soft); }
.rlz-warns { margin-top:8px; padding:6px 9px; border-left:2px solid var(--warn); background:var(--warn-soft);
  border-radius:var(--r-xs); font-size:var(--fs-caption); color:var(--warn-text); }
/* One row per warning CLASS, collapsed. The per-sentence findings live inside,
   so ten identical reason paragraphs read as one line until an operator opens
   it (see warningsHtml in pages/director.js). */
.rlz-warn-group { margin-top:5px; border:1px solid var(--border); border-radius:var(--r-xs);
  background:var(--surface); }
.rlz-warn-group > summary { cursor:pointer; padding:4px 8px; display:flex; align-items:center; gap:6px;
  list-style:none; color:var(--text-muted); }
.rlz-warn-group > summary::-webkit-details-marker { display:none; }
.rlz-warn-group > summary::before { content:"\25B8"; color:var(--text-faint); font-size:var(--fs-micro); }
.rlz-warn-group[open] > summary::before { content:"\25BE"; }
.rlz-warn-n { font-family:var(--mono); font-size:var(--fs-micro); padding:0 5px; border-radius:var(--r-pill);
  border:1px solid var(--border); background:var(--sunken); color:var(--text-faint); }
.rlz-warn-one { padding:4px 8px; display:flex; align-items:baseline; gap:6px; color:var(--text-muted); }
.rlz-warn-one .rlz-warn-why { padding:0; }
.rlz-warn-why { margin:0; padding:0 8px 6px 22px; color:var(--text-muted); }
.rlz-warn-lines { margin:0; padding:0 8px 6px 34px; color:var(--text-faint); }
.rlz-warn-lines li { margin-bottom:2px; }
/* Task E2 — the mode badge: which of §5.5's two modes served this reply. */
.rlz-mode { display:inline-block; margin:0 0 6px; padding:1px 8px; font-size:var(--fs-micro); font-weight:600;
  letter-spacing:.03em; border-radius:var(--r-pill); border:1px solid var(--border-strong);
  color:var(--text-muted); background:var(--surface); }
.rlz-mode.full { border-color:var(--ok); color:var(--ok-text); background:var(--ok-soft); }
.rlz-fail { padding:6px 9px; border-left:2px solid var(--danger); background:var(--danger-soft);
  border-radius:var(--r-xs); font-size:var(--fs-data); color:var(--danger-text); }
/* Sources/tool-call strips hide as a set (the #provToggle preference). ONLY the
   standalone strips: inline citation chips are part of the sentence they ground
   and stay, and validation warnings are actionable rather than provenance. */
.rlz-prov-hidden .rlz-cites, .rlz-prov-hidden .rlz-toollog { display:none; }
/* The mode line joins that set in a rule of its OWN, deliberately: the
   selector above is pinned verbatim by directorChatPage.test.js, and growing
   a pinned line to add a member is how a pin quietly stops meaning what it
   said. Same behaviour, and both pins keep their subject. */
.rlz-prov-hidden .rlz-modeline { display:none; }
/* §5.5 — the mode DERIVATION, read as a footnote to the tool log it was
   derived from, so it hides and returns with that strip. The badge above the
   reply is the standing statement and never hides. */
.rlz-modeline { margin-top:5px; font-size:var(--fs-micro); line-height:1.5; color:var(--text-faint); }

@media print {
  body:has(.dir-page) { background:#fff; }
  body:has(.dir-page) .sidebar, body:has(.dir-page) .topbar, body:has(.dir-page) .page-actions,
  body:has(.dir-page) .dir-history, body:has(.dir-page) .dir-chat-panel > .panel-header,
  body:has(.dir-page) .dir-input-row, body:has(.dir-page) .dir-controls,
  body:has(.dir-page) .dir-chat-body > .muted, body:has(.dir-page) #briefCard,
  body:has(.dir-page) .rlz-answer-details, body:has(.dir-page) .dir-answer-versions,
  body:has(.dir-page) .dir-translation-state, body:has(.dir-page) .rlz-source-additional { display:none !important; }
  body:has(.dir-page), body:has(.dir-page) .app, body:has(.dir-page) .main,
  body:has(.dir-page) .content, body:has(.dir-page) .dir-page, body:has(.dir-page) .dir-shell,
  body:has(.dir-page) .dir-chat-panel, body:has(.dir-page) .dir-chat-body,
  body:has(.dir-page) .dir-chat { display:block; height:auto; min-height:0; overflow:visible; margin:0; padding:0; max-width:none; }
  body:has(.dir-page) .dir-page > .page-header { margin-bottom:10mm; }
  body:has(.dir-page) .dir-session-details { display:block; width:auto; margin:0 0 10mm; }
  body:has(.dir-page) .dir-session-details > :not(summary) { display:block; }
  body:has(.dir-page) .dir-chat-panel, body:has(.dir-page) .rlz-transcript { border:0; box-shadow:none; background:#fff; }
  body:has(.dir-page) .rlz-transcript { padding:0; overflow:visible; }
  body:has(.dir-page) .rlz-msg { break-inside:auto; padding:8mm 0; }
  body:has(.dir-page) .rlz-msg-user { padding:5mm; border:1px solid #d9ded8; }
  body:has(.dir-page) .rlz-body { font-size:10pt; line-height:1.55; max-width:none; }
  body:has(.dir-page) .report-md h1, body:has(.dir-page) .report-md h2,
  body:has(.dir-page) .report-md h3, body:has(.dir-page) .report-md table tr { break-inside:avoid; break-after:avoid; }
  body:has(.dir-page) .report-md .table-wrap { overflow:visible; }
}
/* Base judgment styles; the .dir-page overrides below implement the
   Director presentation contract in Interface/README.md#cockpit-surfaces. */
.rlz-judgment { color:var(--purple-text); border-bottom:1px dotted var(--purple); }
/* Visible reference warnings retain their hover and accessible labels. */
.rlz-tag-mark { display:inline-block; margin-right:3px; padding:0; border:0; background:none;
  font-size:var(--fs-micro); font-weight:600; letter-spacing:0; text-transform:none;
  vertical-align:super; line-height:1; opacity:.72; cursor:help; }
.rlz-judgment-tag { color:var(--purple-text); }
.rlz-engine-tag { color:var(--info-text); }
/* The engine LINE, not just its tag. Execution metadata is bookkeeping — a
   verdict id, a call count, a cost — and it was rendering as ordinary body
   text beside its chip, so a raw "[engine] verdict=conditional; usd=0.0199"
   could open an answer and read as its headline. It gets the muted register
   the warnings strip uses, so it sits where the eye skips unless looked for. */
.rlz-engine { display:inline-block; color:var(--text-muted); font-size:var(--fs-caption); }
/* An answer that cites nothing SAYS so. The strip above it renders only the
   citations the reply carried; this is what an empty one means, in words,
   because silence reads the same as a grounded answer scrolled out of view. */
.rlz-uncited { display:flex; align-items:center; gap:6px; margin-top:8px; padding:5px 9px;
  border-left:2px solid var(--warn); background:var(--warn-soft); border-radius:var(--r-xs);
  font-size:var(--fs-caption); color:var(--warn-text); }
/* The sources block, no longer a wrap-flex row of pills: it is a numbered list
   whose rows line up with the markers in the prose above. */
.rlz-cites { margin-top:8px; }
.rlz-cite { padding:2px 9px; font-size:var(--fs-caption); font-weight:600; border-radius:var(--r-pill);
  border:1px solid var(--border-strong); background:var(--surface); color:var(--text-muted); cursor:pointer; }
.rlz-cite:hover { color:var(--text); border-color:var(--n-300); }
.rlz-cite.cite-ok { border-color:var(--ok); color:var(--ok-text); background:var(--ok-soft); }
.rlz-cite.cite-unv { border-style:dashed; border-color:var(--warn); color:var(--warn-text); background:var(--warn-soft); }
.rlz-cite.cite-bad { border-color:var(--danger); color:var(--danger-text); background:var(--danger-soft);
  text-decoration:line-through; }
.rlz-cite-state { margin-left:5px; font-weight:500; }
html[data-user-role="standard"] .rlz-source-additional { display:none; }
/* provenance, stated on the chip so the run inside a trend_id is never the
   only signal a reader has (cluster ids are stable across runs) */
.rlz-cite .rlz-cite-prov { margin-left:6px; opacity:.72; font-weight:450; }
/* ONE INLINE CITATION MARKER: a small superscript number, in the app's one
   informational blue. A full pill inside a sentence runs ~80 characters, and
   .rlz-body's `overflow-wrap:anywhere` is inherited into it, so it shrink-wraps
   into a multi-line box that shoves the rest of the sentence onto its own line.
   A number has no width to wrap. The record's class, its verification state and
   its provenance are READ — in the tooltip and in the numbered block below —
   rather than glanced at from a colour, which is why the marker does not repeat
   the chips' green/orange/cinnabar scale. cite-bad is the one exception: a
   citation proved unresolvable must not read as a live one, and the strike is
   a shape, not a colour. */
/* A real box, raised by an offset rather than `vertical-align:super` with
   `line-height:0`: that pair kept the line box still but left the button 0px
   tall, so a pointer or a test driver could not hit it (staging round 2). The
   offset moves the glyph without growing the line, and ::after widens the
   target for a finger without moving anything. */
.rlz-refmark { display:inline-block; position:relative; top:-.55em; padding:0 1px; margin-left:1px; border:0;
  background:none; cursor:pointer; font-family:var(--mono); font-size:var(--fs-micro); font-weight:600;
  line-height:1; vertical-align:baseline; color:var(--info-text); }
.rlz-refmark::after { content:''; position:absolute; inset:-.45em -.4em; }
.rlz-refmark:hover, .rlz-refmark:focus-visible { text-decoration:underline; }
.rlz-refmark.cite-bad { color:var(--danger-text); text-decoration:line-through; }
/* the numbered sources block: first-appearance order, numbers matching the
   markers, a reader-facing source name on the glass, and the exact ref kept
   whole for Operations */
.rlz-sources-h { font-size:var(--fs-micro); letter-spacing:var(--track-caps); text-transform:uppercase;
  color:var(--text-faint); margin-bottom:4px; }
:lang(zh-CN) .rlz-sources-h { text-transform:none; letter-spacing:.02em; }
.rlz-source { display:flex; align-items:baseline; gap:6px; margin-bottom:3px; }
.rlz-source-n { font-family:var(--mono); font-size:var(--fs-micro); color:var(--info-text); min-width:1.2em; }
.rlz-source-note { margin:3px 0 8px; color:var(--text-muted); overflow-wrap:anywhere; }
.rlz-source-id { margin:2px 0 8px; color:var(--text-faint); font-size:var(--fs-micro); }
.rlz-source-id > summary { cursor:pointer; width:max-content; }
.rlz-source-id code { display:block; margin-top:3px; overflow-wrap:anywhere; }
.rlz-source > div { min-width:0; }
.rlz-source-additional > summary { cursor:pointer; margin:8px 0; color:var(--text-muted); }
.rlz-brief { border:1px solid var(--border); border-left:3px solid var(--accent); border-radius:var(--r-md);
  padding:11px 13px; background:var(--surface-2); margin-bottom:12px; font-size:var(--fs-data); }
.rlz-brief .rlz-brief-h { display:flex; align-items:center; gap:8px; margin-bottom:6px; }
.rlz-brief .rlz-brief-t { font-weight:600; font-size:var(--fs-data); }
/* read-only chat-minted artifacts */
.dir-card { border:1px solid var(--border); border-radius:var(--r-md); padding:10px 12px;
  background:var(--surface-2); margin-top:8px; font-size:var(--fs-data); }
.dir-card h3 { margin:0 0 4px; font-size:var(--fs-ui); }
/* .dir-card-alt is GONE with the dual print it existed to set: the card now
   prints the reading language and hangs the other half on the marked-original
   atom, so there is no second line of the same sentence left to style. */
.dir-card .dir-card-meta { display:flex; flex-wrap:wrap; gap:6px; margin-top:6px;
  font-size:var(--fs-micro); color:var(--text-faint); }
.dir-note { margin-top:8px; padding:6px 9px; border-left:2px solid var(--border-strong);
  background:var(--surface-2); border-radius:var(--r-xs); font-size:var(--fs-caption); color:var(--text-muted); }

/* THE PER-QUESTION CONTROLS - the ceiling and the source belt, read BEFORE
   the send. A <details> folded by default: the transcript is the page, and
   the six sources default to on, so the belt earns one summary line - the
   ceiling and "SOURCES · 6 of 6" - until a question needs a narrower belt.

   NOT display:flex on .dir-controls. Flex on a <details> flattens <summary>
   and its siblings into one wrapping row, which is exactly the always-open
   appearance the fold exists to remove; the summary is the flex row, the
   chips wrap inside their own .dir-scope-row.

   Each source is ONE chip: a real <input type="checkbox"> kept in the tab
   order and in [data-scope] for scopeFrom(), visually hidden with the same
   recipe as .rlz-lg-hide, beside a drawn 14px box. Native accent-color was
   how the row left the theme: the UA box parked itself on the wrapped word,
   and it wore --spend-ink, which is ledger copper and belongs to money, not
   to a source toggle. The check is --accent on the box only; the chip's
   ground stays --surface whether ticked or not, because six accent-soft
   pills is a state display, not six controls. No new colour - the ceiling
   is .spend (the copper --spend-ink every money figure uses), the key is the
   same uppercase micro-caps as .rlz-armed-k. */
.dir-controls { margin-top:var(--sp-3); padding-top:var(--sp-3); border-top:1px solid var(--border);
  font-size:var(--fs-caption); }
.dir-controls > summary { display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3);
  list-style:none; cursor:pointer; min-height:22px; }
.dir-controls > summary::-webkit-details-marker { display:none; }
/* The same drawn chevron as .rlz-disc, so the two folds on this page read as
   one widget; the native marker is UA chrome and stays off. */
.dir-controls > summary::before { content:""; flex:none; width:0; height:0; border-left:5px solid var(--ink-faint);
  border-top:4px solid transparent; border-bottom:4px solid transparent; transition:transform var(--dur) var(--ease); }
.dir-controls[open] > summary::before { transform:rotate(90deg); }
.dir-controls > summary:hover .dir-ctl-k { color:var(--ink); }
/* "SOURCES · 6 of 6" is ONE item on the summary row: key, interpunct and
   count in a nowrap group pushed right, so at 390 the count can only wrap
   as a whole line under the ceiling, never alone under the chevron. The dot
   is the same interpunct the ceiling string carries, spaced 4px either side
   like it. */
.dir-ctl-src { display:inline-flex; align-items:baseline; gap:var(--sp-1); margin-left:auto; white-space:nowrap; }
.dir-ctl-k { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-faint); }
:lang(zh-CN) .dir-ctl-k { text-transform:none; letter-spacing:.02em; }
.dir-ctl-n { font-size:var(--fs-caption); color:var(--ink-muted); font-variant-numeric:tabular-nums; }
.dir-ctl-n::before { content:"·"; color:var(--ink-faint); margin-right:var(--sp-1); }
/* The ceiling sits in the ledger copper, not the armed copper: it is a figure
   being READ, not a button being armed. */
.dir-ceiling { font-size:var(--fs-caption); margin-right:var(--sp-2); }
.dir-scope-row { display:flex; flex-wrap:wrap; gap:var(--sp-2); margin-top:var(--sp-3); }
.dir-scope { position:relative; display:inline-flex; align-items:center; gap:var(--sp-2); flex:0 0 auto;
  max-width:100%; white-space:nowrap; padding:4px 10px 4px 8px; border:1px solid var(--border);
  border-radius:var(--r-pill); background:var(--surface); color:var(--ink-muted); cursor:pointer;
  font-size:var(--fs-caption); line-height:1.4; user-select:none; transition:background var(--dur), border-color var(--dur); }
.dir-scope-input { position:absolute; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden;
  clip-path:inset(50%); white-space:nowrap; border:0; }
.dir-scope-box { position:relative; flex:none; width:14px; height:14px; box-sizing:border-box;
  border:1.5px solid var(--border-strong); border-radius:var(--r-xs); background:var(--surface);
  transition:background var(--dur), border-color var(--dur); }
.dir-scope-box::after { content:""; position:absolute; left:3.5px; top:0.5px; width:4px; height:8px;
  border:solid var(--on-accent); border-width:0 2px 2px 0; transform:rotate(45deg) scale(0); transform-origin:center; }
.dir-scope-txt { overflow:hidden; text-overflow:ellipsis; }
.dir-scope:has(input:checked) { border-color:var(--border-strong); background:var(--surface); color:var(--ink-muted); }
.dir-scope:has(input:checked) .dir-scope-box { background:var(--accent); border-color:var(--accent); }
.dir-scope:has(input:checked) .dir-scope-box::after { transform:rotate(45deg) scale(1); }
.dir-scope:hover, .dir-scope:has(input:focus-visible) { background:var(--accent-soft); }
.dir-scope:has(input:focus-visible) { box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
@media (max-width:800px) { .dir-scope { flex:1 1 calc(50% - var(--sp-2)); } }
.dir-shell { display:grid; grid-template-columns:minmax(200px,260px) minmax(0,1fr); gap:var(--sp-3); align-items:stretch; }
.dir-page > .dir-shell { flex:1; min-height:0; }
.dir-shell > .dir-chat-panel { display:flex; flex-direction:column; min-height:0; }
@media (min-width:801px) { .dir-shell:has(> .dir-history:not([open])) { grid-template-columns:auto minmax(0,1fr); } }
@media (max-width:800px) { .dir-shell { grid-template-columns:minmax(0,1fr); grid-template-rows:auto 1fr; } }
.dir-history { align-self:stretch; min-height:0; height:100%; display:flex; flex-direction:column; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface-2); padding:8px; }
@media (max-width: 800px) { .dir-history { height:auto; } }
.dir-history > summary, .dsr-history > summary { cursor:pointer; font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--text-faint); padding:2px 4px; }
.dir-history-new { width:100%; margin:8px 0; }
/* THE FLEX CHAIN, unbroken from the <details> to the list: the wrapper that
   holds the list and its "Show older" button is itself a flex column with
   min-height:0, so the LIST scrolls and the button stays in view. When the
   wrapper was a plain block the list grew past the panel and clipped every
   older conversation (FS Improvement Notes 2026-09-22). The max-height is the
   floor for a browser that cannot flex a <details>' content slot.
   Regression: test/uiPrimitives.test.js. */
.dir-history-scroll { display:flex; flex-direction:column; gap:6px; flex:1 1 0; min-height:0; max-height:calc(100dvh - 300px); }
/* Chromium lays a <details>' content out in a ::details-content box; without
   this the box is a plain block and the flex chain above breaks there. */
@media (min-width:801px) { .dir-history::details-content { display:flex; flex-direction:column; flex:1 1 0; min-height:0; } }
/* On the two-column layout the rail must not size the row: height 0 plus
   min-height 100% makes it exactly as tall as the chat panel beside it, so
   the list scrolls inside and "Show older" stays on screen. */
@media (min-width:801px) { .dir-shell > .dir-history[open] { height:0; min-height:100%; } }
.dir-history-scroll > .btn { flex-shrink:0; }
@media (max-width: 800px) { .dir-history-scroll { max-height:40vh; } }
.dir-history-list { display:flex; flex-direction:column; gap:2px; flex:1 1 auto; min-height:0; max-height:none; overflow:auto; overscroll-behavior:contain; }
.dir-history-item { display:block; width:100%; text-align:left; background:none; border:0; border-radius:var(--r-sm);
  padding:6px 8px; color:var(--text); cursor:pointer; font:inherit; }
.dir-history-item:hover, .dir-history-item[aria-current="true"] { background:var(--surface); }
.dir-history-item:focus-visible { outline:2px solid var(--armed-ring); outline-offset:1px; }
.dir-history-title { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.dir-history-meta { display:block; font-size:var(--fs-micro); color:var(--text-faint); }
/* The two sentences that keep the numbers honest - a ceiling is not a price,
   and a source switched off is genuinely gone. They wrap to their own row. */
.dir-ctl-hint { flex-basis:100%; font-size:var(--fs-micro); color:var(--text-faint); line-height:1.5; }

/* ==== glossary.js page (moved from the page's GLOSSARY_CSS at merge —
   the hygiene lane deleted injectStyle in the same wave this page was born) ==== */
/* The reading column: definitions are prose, and prose is measured. */
.gl-page { max-width:var(--measure); }
.gl-lead { font-size:var(--fs-data); color:var(--text-muted); max-width:var(--measure);
  line-height:var(--lh-caption); }
.gl-search { display:flex; align-items:center; gap:8px; margin:0 0 4px; }
.gl-search input { flex:1; }
.gl-count { font-size:var(--fs-caption); color:var(--text-faint); white-space:nowrap;
  font-variant-numeric:tabular-nums; }
.gl-grp { font-size:var(--fs-micro); font-weight:600; text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--text-faint); margin:22px 0 8px; }
.gl-grp:first-child { margin-top:4px; }
:lang(zh-CN) .gl-grp { text-transform:none; letter-spacing:.02em; }
/* One entry = one hairline-separated block. No card, no shadow: this is a
   reference page, and fifteen boxes down a column is a list pretending to be
   objects. */
.gl-entry { border-top:1px solid var(--hairline); padding:14px 0 4px; scroll-margin-top:76px; }
/* The rule under a group heading would be a second line saying the same thing. */
.gl-grp + .gl-entry { border-top:0; }
/* The entry a deep link addressed, marked with the same full-ink left rule the
   sidebar uses for "you are here" — never a highlight fill. */
.gl-entry.gl-targeted { border-left:2px solid var(--ink); padding-left:12px; }
.gl-head { display:flex; align-items:baseline; flex-wrap:wrap; gap:8px; }
.gl-term { font:600 var(--fs-section)/1.3 var(--font-serif); color:var(--ink); }
.gl-term-2 { font-size:var(--fs-data); color:var(--text-muted); font-family:var(--font-serif); }
/* The decoded-ID law: human headline, raw mono beside. The id is the handle
   the palette and the deep link both use, so it is printed, not hidden. */
.gl-id { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint);
  text-decoration:none; border:1px solid var(--hairline); border-radius:var(--r-xs);
  padding:1px 6px; white-space:nowrap; }
.gl-id:hover { color:var(--accent-text); border-color:var(--border-strong); }
.gl-mark { margin:8px 0 0; }
.gl-sec { margin-top:10px; max-width:var(--measure-note); }
.gl-sec-wide { max-width:var(--measure); }
.gl-h { font-size:var(--fs-micro); font-weight:600; text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--text-faint); margin-bottom:2px; }
:lang(zh-CN) .gl-h { text-transform:none; letter-spacing:.02em; }
.gl-b { font-size:var(--fs-data); line-height:var(--lh-caption); color:var(--text-muted); }
/* The evidence family illustrates itself with the primitives it is defining —
   the same .sigil shapes and .tag reading the boards print, never a picture
   drawn for this page. */
.gl-tag.ev-observed { color:var(--ev-observed); }
.gl-tag.ev-supported { color:var(--ev-supported); }
.gl-tag.ev-hypothesis { color:var(--ev-hypothesis); }
.gl-tag.ev-assumption { color:var(--ev-assumption); }
.gl-tag.ev-refused { color:var(--seal-text); }

/* Respect users who ask the OS to reduce motion: neutralize the infinite
   skeleton/spinner loops and entrance transitions, keep opacity fades. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ==== presentation density ====================================================
   STANDING TYPE §6, wave 8.3. `data-density="present"` on the root, set by
   app.js's setDensity() and persisted beside the theme.

   THE PROBLEM IT SOLVES. This cockpit is read at 60cm by two people who chose
   its type. It is also PROJECTED, at the front of a room, to people six metres
   from the glass — and at six metres a 10px caption, faint ink and a frosted
   topbar are not quiet, they are absent. Everything the design says about
   quietness is a claim about a reading distance, and this attribute states the
   other distance rather than pretending there is only one.

   TOKEN-LEVEL ONLY, and that is the whole discipline: the three sub-12px steps
   and the two faintest inks are retuned where they are DEFINED, so every
   surface in the cockpit — including the pages written after this — moves
   together and nothing is restyled twice. Type gains ~+2px; the faint inks step
   up one rung to the muted ones (which is "darker" on paper and "lighter" on
   the night theme — one step toward full ink in both, since a projector washes
   out contrast in whichever direction the theme runs).

   `:root[data-density="present"]` outranks `[data-theme="dark"]`, so the two
   compose instead of racing, and the faint inks are expressed as the theme's
   OWN muted token rather than as literals — a hard-coded grey here would paint
   the light ramp's ink onto the dark theme.

   THE ONE COMPONENT RULE below is deliberate and is the only one: the topbar's
   backdrop blur is written as a literal in .topbar (not as a token), so it
   cannot be turned off from the token block. A frosted bar over scrolling text
   is the single worst artifact on a projector — it smears rather than
   separates — and the opaque background travels with it, because a bar that
   stopped blurring while staying 86% transparent would be strictly worse than
   before.
   ============================================================================ */
:root[data-density="present"] {
  --fs-data:14.5px;      /* 12.5 */
  --fs-caption:13.5px;   /* 11.5 */
  --fs-micro:12px;       /* 10   */
  --text-faint:var(--text-muted);
  --ink-faint:var(--ink-muted);
}
:root[data-density="present"] .topbar { backdrop-filter:none; background:var(--surface); }

/* ==== audit.js AUDIT_CSS ==== */
/* W9 — the curation audit surface. Scoped to .aud-; everything shared
   (panels, tables, badges, inputs) comes from the house classes above. */
.aud-filters {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
}
.aud-filter-select { width: auto; min-width: 120px; }
.aud-filter-date { font-size: var(--fs-caption); color: var(--text-muted); }
/* The house input is width:100%; in a flex filter bar that pushed each date
   field onto its own full-width row with its label stranded above it. */
.aud-filters input[type=date] { width: auto; min-width: 160px; }

.aud-table td { vertical-align: top; }
.aud-table .instinct-id { white-space: nowrap; }

.aud-chains { display: grid; gap: 14px; }
.aud-chain-head-panel {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding-bottom: 6px; border-bottom: 1px solid var(--border);
}
.aud-chain-rows { display: grid; }
.aud-chain-row {
  padding: 10px 0; border-bottom: 1px dashed var(--border);
  display: grid; gap: 4px;
}
.aud-chain-row:last-child { border-bottom: none; }
/* The row whose verdict still governs reads first-class; superseded rows
   recede but stay fully legible — an audit never whispers. */
.aud-chain-latest { border-bottom: 1px solid var(--border); }
.aud-chain-head { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.aud-chain-note { font-size: var(--fs-data); line-height: 1.45; }
.aud-chain-extras { display: flex; gap: 12px; flex-wrap: wrap; font-size: var(--fs-caption); color: var(--text-muted); }
.aud-overturn-hint { margin-bottom: 10px; display: flex; gap: 6px; align-items: center; }
.ov-error { color: var(--danger); font-size: var(--fs-caption); min-height: 18px; margin: 4px 0; }
.ov-notice { color: var(--warn-text); font-size: var(--fs-caption); margin: 4px 0; }
.ov-notice:empty { display: none; }
.aud-row-caveat { margin-top: 4px; }
/* Task 8 P4 — exact-run Explorer and local collection controls */
.explorer-page { min-width: 0; }
/* Module 1 run button + progress bar on the radar (pages/trends.js) */
.m1-run .panel-header { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.m1-run-line { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 6px; }
.m1-run-bar { height: 10px; border-radius: 999px; background: var(--accent-soft); overflow: hidden; }
.m1-run-fill { height: 100%; background: var(--accent); border-radius: inherit; transition: width .6s ease; }
.m1-run-bar.is-busy .m1-run-fill { background-image: linear-gradient(90deg, var(--accent) 0 60%, var(--accent-2) 60% 100%); background-size: 24px 100%; animation: m1-run-busy 1.2s linear infinite; }
@keyframes m1-run-busy { from { background-position: 0 0; } to { background-position: 24px 0; } }
.m1-run-detail { margin-top: 6px; }
/* Runs › Collectors "Collect data" (components/collectData.js); bars reuse .m1-run-bar. */
.collect-data .panel-body > .btn { margin: 4px 0 12px; }
.collect-rows { display: grid; gap: 12px; }
.collect-row { display: grid; gap: 6px; padding-top: 10px; border-top: 1px solid var(--border); }
.collect-choice { display: flex; align-items: flex-start; gap: 10px; cursor: pointer; }
.collect-choice input { margin-top: 3px; }
.collect-choice > span { display: grid; gap: 2px; }
.collect-choice.is-disabled { cursor: not-allowed; opacity: .75; }
.collect-progress { display: grid; gap: 4px; margin-left: 26px; }
.sub-settings .sub-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.explorer-ledger { position: sticky; top: 8px; z-index: 4; border-left: 4px solid var(--accent); background: var(--surface); }
.explorer-ledger-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.analyst-id { font-family: var(--mono, "IBM Plex Mono", monospace); overflow-wrap: anywhere; }
.explorer-filter-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; align-items: end; }
.explorer-row-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; border-top: 1px solid var(--border); }
.explorer-handoff { border-color: var(--purple, #6d4ca1); }
.explorer-audit { max-height: 65vh; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }
.explorer-pagination { display: flex; justify-content: center; align-items: center; gap: 12px; margin-block: 18px; }
.explorer-review-form, .pipeline-control-form { display: grid; gap: 12px; }
.analyst-trend-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 270px), 1fr)); gap:12px; margin-bottom:18px; }
.analyst-trend-card { margin:0; min-width:0; box-shadow:none; }
.analyst-card-heading { display:flex; align-items:stretch; border-bottom:1px solid var(--hairline); background:var(--surface-2); }
.analyst-card-rank { display:inline-flex; align-items:center; padding:10px 12px; color:var(--ink); font-size:var(--fs-section); font-weight:600; letter-spacing:-.03em; }
.analyst-bucket { display:inline-flex; align-items:center; margin-left:auto; padding:0 12px; border:0; border-left:1px solid var(--hairline); background:transparent; color:var(--accent-text); font:600 var(--fs-caption)/1.4 var(--font); text-align:left; }
button.analyst-bucket:hover { background:var(--surface); color:var(--ink); text-decoration:underline; }
.analyst-card-label, .analyst-detail-label { color:var(--ink); font-size:var(--fs-ui); font-weight:600; line-height:1.4; }
.analyst-card-brief { min-height:2.9em; margin-top:6px; color:var(--ink-muted); font-size:var(--fs-data); line-height:1.45; }
.analyst-card-brief--one-line { min-height:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.analyst-card-counts { display:flex; gap:10px; flex-wrap:wrap; margin-top:12px; padding-top:8px; border-top:1px solid var(--hairline); }
.analyst-card-count { display:inline-flex; align-items:baseline; gap:3px; color:var(--ink-muted); font-size:var(--fs-caption); }
.analyst-card-count strong { color:var(--ink); font-weight:600; }
.analyst-trend-card .explorer-row-actions { margin:12px -18px -18px; padding:10px 18px; }
.analyst-trend-detail { max-width:var(--measure); }
.analyst-detail-rationale { margin-top:12px; }
.analyst-detail-rationale p + p { margin-top:10px; }
.analyst-rank-reason, .analyst-sentiment-penalty { color:var(--ink-muted); font-size:var(--fs-data); }
.analyst-sentiment-penalty { color:var(--ink); }
.analyst-details { margin-top:14px; border-top:1px solid var(--hairline); }
.analyst-details > summary { padding:9px 0; cursor:pointer; color:var(--ink-muted); font:600 var(--fs-caption)/1.4 var(--font); }
.analyst-details-body { display:grid; gap:8px; padding:0 0 12px; color:var(--ink-muted); font-size:var(--fs-caption); overflow-wrap:anywhere; }
.analyst-details pre { margin-top:4px; padding:8px; overflow:auto; background:var(--surface-2); border:1px solid var(--hairline); color:var(--ink); font:400 var(--fs-caption)/1.45 var(--mono); white-space:pre-wrap; }
/* Grouped choices (the Pipeline page's artifact list and run mode) were the
   browser's default fieldset: a grey inset border and an unpadded legend that
   read as unstyled. Dressed like every other house field. */
.pipeline-control-form fieldset { border: 1px solid var(--border); border-radius: var(--r-sm); padding: 10px 12px; margin: 0; min-width: 0; }
.pipeline-control-form legend { padding: 0 6px; margin-bottom: 0; }
.pipeline-control-form fieldset > label { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: var(--fs-ui); }
.pipeline-readiness { border-left: 4px solid var(--accent); }
.pipeline-readiness .badge { white-space: normal; }
.pipeline-catalog { display: grid; gap: 8px; }
.pipeline-artifact { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 8px; align-items: start; padding: 8px; border: 1px solid var(--border); background: var(--surface); }
.pipeline-artifact span { display: grid; gap: 3px; }
.pipeline-log { max-height: 280px; overflow: auto; font-size: var(--fs-caption); white-space: pre-wrap; overflow-wrap: anywhere; margin: 12px 0 0; }
@media (max-width: 760px) {
  .explorer-filter-grid { grid-template-columns: 1fr; }
  .explorer-ledger { position: static; }
  .explorer-row-actions .spacer { display: none; }
  .explorer-row-actions .btn { flex: 1 1 auto; }
}

/* ==== components/m5Line.js — THE LINE & THE STEEP ============================
   Governing contract: docs/module5/LINE-AND-STEEP-DESIGN.md (operator-approved
   2026-08-31), subordinate to STANDING-TYPE-DESIGN.md.

   ONE drawing, three pages. Module 5's three tabs are a single production line
   and the cockpit never said so, so the spine is a SHARED COMPONENT
   (public/js/components/m5Line.js) rather than three strips that agree by
   habit. These rules dress that one renderer and nothing else; every selector
   is `.m5-` namespaced and nothing here reaches a class another page owns.

   NO NEW COLOR EXISTS IN THIS SECTION. Every value is an existing token from
   the block at the top of this file, so the night theme is carried by the
   token flip that is already there — a literal here would have painted the day
   ramp's ink onto the dark reading room, and a color defined only inside
   `[data-theme="dark"]` would have had no light half at all.

   THE FOUR STATES SURVIVE A GRAYSCALE SCREENSHOT WITH MOTION OFF, which is the
   acceptance gate (§6) and the reason the drawing is what it is:

     waiting   dashed border, empty       (--ev-assumption-border)
     steeping  solid border, HATCHED fill at ~52%   (--armed — copper)
     sealed    solid border, FLAT fill at 82%       (--accent)
     refused   solid border, empty, cross-stroke    (--seal)

   Border STYLE separates waiting from the other three; fill HEIGHT separates
   steeping from sealed; fill TEXTURE separates them a second time (hatch vs
   flat) so the pair stays distinct even where a screenshot crops the vessel;
   the cross-stroke separates refused from waiting. Color is redundant in every
   one of those four readings — which is Law 2, applied to a vessel instead of
   a sigil.

   COPPER IS ONLY EVER `steeping` (Law 5). The belt's slats go copper for the
   same reason and at the same moment: when the operator sees copper on this
   instrument, paid work is in flight. The spend readout is LEDGER copper
   (`.spend`, already declared above) — calm, historical, never the armed
   intensity, which belongs to the armed strip alone.

   MOTION. Two ambient animations, both conditional and both dead under
   `prefers-reduced-motion`: the belt runs only while a station is steeping
   (`.m5-line[data-steeping="1"]`), so an idle line is a STILL picture rather
   than a screensaver, and the steeping fill breathes around the height it
   holds when it is stopped. The global reduce block near the top of this file
   already clamps every duration; these rules say `animation:none` anyway,
   because a 0.01ms infinite loop is still a running animation and the contract
   asks for the motion to be gone, not fast.
   ========================================================================== */

/* ---- THE LINE: the belt strip, the same drawing on all three pages -------- */
.m5-line { border:1px solid var(--hairline); border-radius:var(--r-md); background:var(--surface);
  padding:var(--sp-3) var(--sp-4) var(--sp-4); }
.m5-line-head { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-2) var(--sp-4);
  padding-bottom:var(--sp-2); }
.m5-line-name { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink); }
.m5-line-name .m5-han { margin-left:6px; font-weight:400; letter-spacing:0; text-transform:none;
  color:var(--ink-muted); }
.m5-batch { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint);
  font-variant-numeric:tabular-nums; }
/* The eyebrow keeps the interface face — only the id itself is ledger text. */
.m5-batch .m5-k { font-family:var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps); margin-right:5px; }
:lang(zh-CN) .m5-batch .m5-k, :lang(zh-CN) .m5-spend .m5-k { text-transform:none; letter-spacing:.02em; }
/* Ledger copper, and the label travels with the figure — a decimal with no
   label and no unit is unrenderable by rule (Law 6). */
.m5-spend { display:inline-flex; align-items:baseline; gap:var(--sp-3); margin-left:auto;
  font-size:var(--fs-micro); }
.m5-spend .m5-k { text-transform:uppercase; letter-spacing:var(--track-caps); color:var(--ink-faint);
  margin-right:5px; }

/* ---- the conveyor. Still when idle; copper and moving when work is paid ---- */
/* Slats, not a dashed rule: short marks on a quiet track, so the belt reads as
   texture under the stations rather than as a second masthead over them. */
.m5-belt { position:relative; height:3px; overflow:hidden; border-radius:var(--r-xs);
  background:var(--sunken); margin:0 0 var(--sp-3); }
.m5-belt::before { content:""; position:absolute; inset:0;
  background-image:repeating-linear-gradient(90deg, var(--border-strong) 0 5px, transparent 5px 12px);
  background-size:12px 100%; }
.m5-line[data-steeping="1"] .m5-belt::before {
  background-image:repeating-linear-gradient(90deg, var(--armed) 0 5px, transparent 5px 12px);
  animation:m5-belt 1.6s linear infinite; }
@keyframes m5-belt { from { background-position:0 0; } to { background-position:12px 0; } }

/* ---- THE STEEP: one vessel per station, four states ---------------------- */
.m5-vessel { position:relative; display:block; flex:none; width:20px; height:24px;
  border:1.5px solid var(--border-strong); border-top-width:0;
  border-radius:0 0 var(--r-sm) var(--r-sm); background:var(--surface-2); overflow:hidden; }
/* The large vessel: the station whose work is in flight, on the page that owns
   it (§4.2). Same four states, same drawing, read at arm's length. */
.m5-vessel.lg { width:44px; height:54px; border-width:2px; border-top-width:0; }
.m5-fill { position:absolute; left:0; right:0; bottom:0; height:0; }
.m5-vessel[data-state="waiting"] { border-style:dashed; border-color:var(--ev-assumption-border); }
.m5-vessel[data-state="steeping"] { border-color:var(--armed); }
/* THE MENISCUS — the liquid's own surface, drawn as a full-ink copper rule.
   The hatch alone could not carry this state: `--armed-soft` on `--surface` is
   about five points of luminance apart in the light theme, and the gap stripe
   was painting `--surface` OVER the vessel's slightly darker `--surface-2`, so
   the "full" half read lighter than the empty one. A LINE survives what a tint
   does not — a grayscale screenshot, a 20px vessel, a crop, a bad projector —
   and it is the same mark the eye already reads as a fill level. The gap is
   `transparent` now so the vessel's own ground shows through it and the fill can
   never be brighter than the vessel it sits in. Motion moves the line; killing
   the animation leaves it exactly where 52% puts it. */
.m5-vessel[data-state="steeping"] > .m5-fill { height:52%;
  border-top:1.5px solid var(--armed);
  background-image:repeating-linear-gradient(135deg, var(--armed-soft) 0 3px, transparent 3px 6px);
  animation:m5-steep 2.4s var(--ease) infinite; }
.m5-vessel[data-state="sealed"] { border-color:var(--accent); }
.m5-vessel[data-state="sealed"] > .m5-fill { height:82%; background:var(--accent-soft-2); }
.m5-vessel[data-state="refused"] { border-color:var(--seal); }
/* The cross-stroke — the same refusal mark the ⊘ sigil wears, at vessel scale. */
.m5-vessel[data-state="refused"]::after { content:""; position:absolute; left:-2px; right:-2px; top:50%;
  height:1.5px; background:var(--seal); transform:rotate(-38deg); }
@keyframes m5-steep { 0%,100% { height:44%; } 50% { height:62%; } }

/* ---- the six stations: name + 中文 + one mono note line ------------------ */
.m5-stations { display:grid; grid-template-columns:repeat(6, minmax(0, 1fr)); gap:var(--sp-3);
  list-style:none; margin:0; padding:0; }
.m5-stn { display:grid; grid-template-columns:auto 1fr; grid-template-rows:auto auto auto;
  align-items:start; column-gap:var(--sp-2); row-gap:2px; min-width:0; }
.m5-stn > .m5-vessel { grid-column:1; grid-row:1 / span 2; }
.m5-stn-name { grid-column:2; font:600 var(--fs-caption)/1.4 var(--font);
  letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--ink); }
.m5-stn-zh { grid-column:2; font-size:var(--fs-caption); line-height:1.4; color:var(--ink-muted); }
/* The note is the stage's own words, in the ledger voice: a count, an elapsed
   pair, a refusal's reason. It wraps rather than truncating — a note the
   operator cannot finish reading is a note the machine did not really state. */
.m5-stn-note { grid-column:1 / -1; font-family:var(--mono); font-size:var(--fs-micro);
  line-height:var(--lh-caption); color:var(--ink-faint); overflow-wrap:anywhere; }
.m5-stn[data-state="steeping"] .m5-stn-note { color:var(--spend-ink); }
.m5-stn[data-state="refused"] .m5-stn-note { color:var(--seal-text); }
/* A stage that has not said anything says so, in its own line, in the reading
   language — so it is visibly an absence and not an empty cell. */
.m5-stn-note.m5-absent { font-family:var(--font); font-style:italic; }

/* ---- the three tab anchors, beneath the belt ----------------------------- */
.m5-anchors { display:flex; flex-wrap:wrap; gap:var(--sp-2) var(--sp-5); list-style:none;
  margin:var(--sp-4) 0 0; padding:var(--sp-3) 0 0; border-top:1px solid var(--hairline); }
.m5-anch-item { min-width:0; }
.m5-anch { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-1) var(--sp-2);
  min-width:0; font-size:var(--fs-caption); color:var(--ink-muted); text-decoration:none;
  border-left:2px solid transparent; padding-left:var(--sp-2); }
a.m5-anch:hover .m5-anch-name { color:var(--ink); text-decoration:underline; }
.m5-anch-name { font:600 var(--fs-caption)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-muted); }
.m5-anch-zh { color:var(--ink-muted); }
/* The state word, square: it is a reading, not a control (Law 4). */
.m5-anch-state { padding:0 6px; border:1px solid var(--border-strong); border-radius:var(--r-xs);
  font:600 var(--fs-micro)/16px var(--font); letter-spacing:var(--track-caps); text-transform:uppercase;
  color:var(--ink-faint); background:var(--surface); cursor:default; }
.m5-anch[data-state="done"] { border-left-color:var(--accent); }
.m5-anch[data-state="done"] .m5-anch-name { color:var(--ink); }
.m5-anch[data-state="done"] .m5-anch-state { border-color:var(--accent); color:var(--accent-text);
  background:var(--accent-soft); }
.m5-anch[data-state="live"] { border-left-color:var(--ink); }
.m5-anch[data-state="live"] .m5-anch-name { color:var(--ink); }
.m5-anch[data-state="live"] .m5-anch-state { border-color:var(--ink); color:var(--ink); }
.m5-anch[data-state="locked"] { border-left-color:var(--ev-assumption-border); }
.m5-anch[data-state="locked"] .m5-anch-state { border-style:dashed; }
/* WHERE THE READER IS STANDING. Deliberately the quietest thing on the anchor:
   no box, no rule, no colour of its own — because the state chip beside it is
   the reading that matters, and the line is a picture of the RUN. It is set in
   the interface face rather than the caps-tracked state voice so the eye reads
   it as an aside, and it sits after the state so it can never be mistaken for
   one. The slant is Latin-only — a synthesized oblique is not a 中文 register
   (Law 9), so zh carries the aside by ink alone. */
.m5-anch-here { font-size:var(--fs-micro); line-height:16px; font-style:italic;
  color:var(--ink-faint); cursor:default; }
:lang(zh-CN) .m5-anch-here { font-style:normal; }
/* THE KEY THAT OPENS IT. Always present on a locked anchor, never a bare
   disabled state: the reader is told the prerequisite, not that the door is
   shut. Full width of its own row so a real sentence fits. */
.m5-anch-key { flex-basis:100%; font-size:var(--fs-micro); line-height:var(--lh-caption);
  color:var(--ink-faint); max-width:var(--measure-note); }

/* ---- THE POT and THE SHELF: the manifest, and free browsing -------------- */
/* Shared section head for the pot, the shelf, the steep log and the register —
   one label treatment, so the four instruments read as one family. */
.m5-h { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-2);
  font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink); margin-bottom:var(--sp-2); }
.m5-h .m5-han { font-weight:400; letter-spacing:0; text-transform:none; color:var(--ink-muted); }
:lang(zh-CN) .m5-h, :lang(zh-CN) .m5-stn-name, :lang(zh-CN) .m5-anch-name,
:lang(zh-CN) .m5-line-name { text-transform:none; letter-spacing:.02em; }
.m5-lead { font-size:var(--fs-caption); line-height:var(--lh-caption); color:var(--ink-muted);
  max-width:var(--measure-note); margin-bottom:var(--sp-3); }
.m5-pot, .m5-shelf { border:1px solid var(--hairline); border-radius:var(--r-md);
  background:var(--surface); padding:var(--sp-3) var(--sp-4); }
/* The two-up the pot and the shelf sit in. Declared HERE, once, because the
   pair is the instrument — three pages laying it out by hand is how one of the
   three ends up with the shelf above the pot on a narrow screen. auto-fit
   rather than a fixed pair: below ~600px of column the two stack, and neither
   ever scrolls sideways (Law 8). */
.m5-pair { display:grid; grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));
  gap:var(--sp-3); align-items:start; }
/* The pot is the contractual half, so it carries the heavier rule; the shelf is
   reversible and free, and is drawn as the lighter object it is. */
.m5-pot { border-left:2px solid var(--ink); }
.m5-shelf { border-left:2px dashed var(--border-strong); background:var(--surface-2); }
/* THE LAW, stated on the instrument rather than in a doc nobody opens. */
.m5-pot-law { font-size:var(--fs-caption); line-height:var(--lh-caption); color:var(--ink);
  border-top:1px solid var(--hairline); margin-top:var(--sp-3); padding-top:var(--sp-2); }
.m5-pot-sealed { font-size:var(--fs-caption); line-height:var(--lh-caption); color:var(--warn-text);
  border-left:2px solid var(--warn); background:var(--warn-soft); border-radius:var(--r-xs);
  padding:6px 9px; margin-bottom:var(--sp-3); }
.m5-abs { display:flex; flex-direction:column; gap:var(--sp-2); list-style:none; margin:0; padding:0; }
.m5-empty { font-size:var(--fs-caption); line-height:var(--lh-caption); color:var(--ink-muted); }
/* The attached item. Square (a reading) with its id and its attach time in the
   ledger voice, and one named button to move it to the other side. */
.m5-ab { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-1) var(--sp-2);
  border:1px solid var(--border); border-radius:var(--r-xs); background:var(--surface-2);
  padding:5px 8px; font-size:var(--fs-caption); }
.m5-ab-name { color:var(--ink); overflow-wrap:anywhere; }
.m5-ab-id, .m5-ab-at { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint);
  font-variant-numeric:tabular-nums; }
.m5-ab-act { margin-left:auto; }
/* THE ARRIVAL. The flash is a courtesy; the LEFT RULE and the "just attached"
   words are the fact, so an arrival is still visible with motion off and in a
   grayscale screenshot. */
.m5-ab.new { border-left:2px solid var(--accent); animation:m5-arrive var(--dur-2) var(--ease-out); }
.m5-ab-new { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--accent-text); }
:lang(zh-CN) .m5-ab-new { text-transform:none; letter-spacing:.02em; }
@keyframes m5-arrive { from { background:var(--accent-soft); } to { background:var(--surface-2); } }

/* ---- THE STEEP LOG and THE REGISTER ------------------------------------- */
/* Both are narration rows: a mono timestamp column, then the text. No inner
   scroll (Law 8) — a long log grows the page, it never traps the wheel. */
.m5-steeplog, .m5-register { border:1px solid var(--hairline); border-radius:var(--r-md);
  background:var(--surface); padding:var(--sp-3) var(--sp-4); }
.m5-slog-row, .m5-reg-row { display:grid; grid-template-columns:auto 1fr; gap:var(--sp-3);
  padding:4px 0; border-bottom:1px solid var(--hairline); font-size:var(--fs-caption); }
.m5-slog-row:last-child, .m5-reg-row:last-child { border-bottom:0; }
.m5-slog-ts, .m5-reg-ts { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint);
  font-variant-numeric:tabular-nums; white-space:nowrap; }
.m5-slog-tx, .m5-reg-tx { color:var(--ink-muted); line-height:var(--lh-caption); overflow-wrap:anywhere; }
/* THE LIVE ROW — the stage is still talking. Copper, because this row is the
   paid work narrating itself, and it says "in flight" in words beside the dot
   so the state is never carried by the animation alone. */
.m5-slog-row.live .m5-slog-tx { color:var(--ink); }
.m5-slog-live { display:inline-flex; align-items:center; gap:5px; margin-left:6px;
  font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--armed-text); }
:lang(zh-CN) .m5-slog-live { text-transform:none; letter-spacing:.02em; }
.m5-slog-live::before { content:""; width:6px; height:6px; border-radius:50%; flex:none;
  background:var(--armed); animation:m5-live 1.8s var(--ease) infinite; }
@keyframes m5-live { 0%,100% { opacity:1; } 50% { opacity:.3; } }

/* ---- reduced motion: every one of the four loops above, gone ------------- */
@media (prefers-reduced-motion: reduce) {
  .m5-line[data-steeping="1"] .m5-belt::before { animation:none; }
  .m5-vessel[data-state="steeping"] > .m5-fill { animation:none; height:52%; }
  .m5-ab.new { animation:none; }
  .m5-slog-live::before { animation:none; }
}

/* ---- narrow glass: the line wraps, it never scrolls sideways ------------- */
@media (max-width: 1100px) { .m5-stations { grid-template-columns:repeat(3, minmax(0, 1fr)); } }
@media (max-width: 640px) { .m5-stations { grid-template-columns:repeat(2, minmax(0, 1fr)); } }

/* ---- print: the line is a SCREEN instrument (contract §5.6) -------------- */
/* The printed dossier is built by realizePrint.js in its own document, so the
   line cannot reach it. This covers the other way in — a browser print of the
   cockpit page itself — because a conveyor belt and a breathing vessel on
   paper are a picture of a machine, not a record of one. The pot, the log and
   the register DO print: they are the run's ledger.

   THE STEEP HEAD GOES WITH IT. `.m5-steep` is the large vessel Realize mounts
   over the station in flight — the same instrument at arm's length, elapsed
   included, and an elapsed on paper is a stopwatch frozen at the moment
   somebody hit print. Any vessel that DOES print (Design's per-render rows are
   a record of what was made) prints still: an animation is motion, and print
   doesn't fidget (Law 11).

   AND THE MOVE BUTTONS COME OFF. The pot and the shelf print because they are
   the run's manifest, but `.m5-ab-act` is a live control — "Into the pot" on
   paper is an offer the page cannot honor, and the sheet reads as an interface
   somebody photographed rather than the record it is. */
@media print {
  .m5-line, .m5-steep { display:none; }
  .m5-slog-live::before { display:none; }
  .m5-ab-act { display:none; }
  .m5-vessel[data-state="steeping"] > .m5-fill { animation:none; }
}

/* ==== pages/runs.js — THE RUNS BOARD =========================================
   N runs on THE LINE. Nothing here restyles a vessel, a station or a belt: the
   board's rows ARE the component, and the only thing this section does to the
   drawing is set its scale. A board that repainted the line would be a second
   opinion about what `steeping` looks like.

   The LINE STATE chip is the one new mark, and it is deliberately not a vessel:
   the four vessel states are closed (integration ruling R16), and `queued` /
   `interrupted` are facts about the RUN, not about any stage of it. It reads as
   a status word, square, because it is a reading and not a control (Law 4).
   ============================================================================ */
.brd { display:flex; flex-direction:column; gap:var(--sp-3); }
.brd-summary { font-family:var(--mono); font-size:var(--fs-caption); color:var(--ink-muted); }
.brd-lines { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:var(--sp-3); }
.brd-line { border:1px solid var(--hairline); border-radius:var(--r-md); background:var(--surface);
  padding:var(--sp-3) var(--sp-4); border-left:3px solid var(--border-strong); }
.brd-line-head { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3);
  margin-bottom:var(--sp-2); }
.brd-line-id { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint); }
.brd-kind { font-size:var(--fs-micro); text-transform:uppercase; letter-spacing:var(--track-caps);
  color:var(--ink-muted); }
:lang(zh-CN) .brd-kind { text-transform:none; letter-spacing:.02em; }
.brd-clock { font-family:var(--mono); font-size:var(--fs-caption); color:var(--ink-muted); }
/* Issue #6 (cockpit UX eval round 1): a healthy live run states its last
   step plainly, in muted ink; past the quiet threshold the SAME line takes
   the warn ink — never the refusal cinnabar, since a stuck run has not
   failed and may still recover on its own. */
.brd-stuck { font-family:var(--mono); font-size:var(--fs-caption); color:var(--ink-muted); }
.brd-stuck[data-stuck="true"] { color:var(--warn-text); }
.brd-spend { font-size:var(--fs-caption); color:var(--ink-faint); margin-left:auto; }
.brd-open { flex:none; }
.brd-detail, .brd-note { font-size:var(--fs-caption); line-height:var(--lh-caption);
  color:var(--ink-muted); max-width:var(--measure-note); margin-bottom:var(--sp-2); }
.brd-note { color:var(--ink-faint); }

/* THE LOOP-YIELD STRIP (issue: the funnel-rollup gap, cockpit UX eval round
   1) — numbers only, no charts: one row of labeled figures, the same
   small-caps-label-over-mono-number the armed strip already uses for money. */
.yld-strip { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-2) var(--sp-4);
  border:1px solid var(--border-strong); border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4);
  background:var(--surface); margin-bottom:var(--sp-3); }
.yld-title { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-faint); margin-right:var(--sp-2); }
:lang(zh-CN) .yld-title { letter-spacing:.02em; }
.yld-figure { display:flex; flex-direction:column; gap:2px; }
.yld-k { font-size:var(--fs-micro); color:var(--ink-muted); }
.yld-v { font-family:var(--mono); font-size:var(--fs-ui); font-weight:600; color:var(--ink); }
.yld-strip[data-state="unavailable"] { color:var(--ink-muted); border-style:dashed; }
.yld-note { font-size:var(--fs-caption); color:var(--ink-faint); }

/* THE PRECONDITION NOTICE (components/m5Precondition.js, cockpit UX eval
   round 3). One drawing for every "you cannot do this yet": the sentence,
   the cost line when the action spends, the in-place PRIMARY action, and
   the cross-page door demoted to a text link. Tone inks are the app's own —
   warn for a precondition, the seal for a refusal, the accent for done — so
   nothing here teaches a new colour. */
.m5-pre { margin-top:10px; padding:10px 12px; border-radius:var(--r-xs); font-size:var(--fs-data);
  line-height:var(--lh-caption); }
.m5-pre-msg, .m5-pre-detail, .m5-pre-cost, .m5-pre-blocked, .m5-pre-refusal { max-width:92ch; }
.m5-pre-warn { border-left:2px solid var(--warn); background:var(--warn-soft); color:var(--warn-text); }
.m5-pre-plain { border-left:2px solid var(--border-strong); background:var(--surface-2); color:var(--text-muted); }
.m5-pre-bad { border-left:2px solid var(--seal); background:var(--seal-soft); color:var(--seal-text); }
.m5-pre-ok { border-left:2px solid var(--accent); background:var(--accent-soft); color:var(--accent-text); }
.m5-pre-title { display:block; margin-bottom:4px; }
.m5-pre-msg { margin:0; }
.m5-pre-detail { margin:4px 0 0; color:inherit; opacity:.85; }
.m5-pre-cost { margin-top:6px; font-size:var(--fs-caption); color:inherit; }
.m5-pre-cost-k { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps); text-transform:uppercase; }
:lang(zh-CN) .m5-pre-cost-k { text-transform:none; letter-spacing:.02em; }
.m5-pre-cost .spend { font-family:var(--mono); }
.m5-pre-blocked { margin-top:6px; font-size:var(--fs-caption); }
.m5-pre-refusal { margin-top:6px; font-size:var(--fs-caption); color:var(--seal-text); overflow-wrap:anywhere; }
.m5-pre-actions { display:flex; align-items:center; flex-wrap:wrap; gap:8px 10px; margin-top:10px; }
.m5-pre-or { font-size:var(--fs-caption); }
.m5-pre-link { font-size:var(--fs-caption); text-decoration:underline; text-underline-offset:2px; color:var(--accent-text); }
.m5-pre-status { margin-top:8px; font-size:var(--fs-caption); }
.m5-pre-body { margin-top:8px; }
.m5-pre-body .rlz-preflight { margin-top:0; }
/* On a board line the notice sits between the detail and THE LINE. */
.brd-line .m5-pre { margin:6px 0 var(--sp-3); }
/* The in-place carry (the armed strip, the dossier entry): a picker and one
   button on one row, the picker taking the width and wrapping under the
   label at phone width. */
.m5-pre-pick { display:flex; flex-direction:column; gap:4px; flex:1 1 260px; min-width:0;
  font-size:var(--fs-caption); }
.m5-pre-pick select { width:100%; min-width:0; }

/* The line state, square: a reading, never a control. Each state takes the ink
   its meaning already owns elsewhere on this instrument — copper only while
   money is moving (Law 5), the seal only for a refusal, the accent for sealed —
   so a reader who has learned the vessels has already learned these. */
.brd-state { padding:0 6px; border:1px solid var(--border-strong); border-radius:var(--r-xs);
  font:600 var(--fs-micro)/18px var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-faint); background:var(--surface); cursor:default; }
:lang(zh-CN) .brd-state { text-transform:none; letter-spacing:.02em; }
.brd-state[data-state="running"] { border-color:var(--armed); color:var(--armed-text); background:var(--armed-soft); }
.brd-state[data-state="completed"] { border-color:var(--accent); color:var(--accent-text); background:var(--accent-soft); }
.brd-state[data-state="failed"] { border-color:var(--seal); color:var(--seal-text); background:var(--seal-soft); }
/* Queued, interrupted and stale share the ASSUMPTION dash — the mark this
   design already uses for "not established": a queued run has not begun, and an
   interrupted one no longer knows where it is. Dashed, never filled. */
.brd-state[data-state="queued"],
.brd-state[data-state="interrupted"],
.brd-state[data-state="stale"],
.brd-state[data-state="unknown"] { border-style:dashed; border-color:var(--ev-assumption-border); }
.brd-line[data-state="running"] { border-left-color:var(--armed); }
.brd-line[data-state="completed"] { border-left-color:var(--accent); }
.brd-line[data-state="failed"] { border-left-color:var(--seal); }

/* ---------------------------------------------------------------------------
   W6.T5 — THE BATCH ON THE BOARD. A batch is one decision, so it is one line
   with its runs indented beneath it. No new colour: the roll-up wears the same
   `.brd-state` square the individual lines wear (so a reader who has learned
   the line states has already learned this one), and the only copper on the
   whole group is the batch total, which is the money the decision moved.
   Tokens only — no literal colour anywhere in this block.
   --------------------------------------------------------------------------- */
.brd-batch { list-style:none; border:1px solid var(--border-strong); border-radius:var(--r-md);
  background:var(--surface-2); padding:var(--sp-3); display:flex; flex-direction:column; gap:var(--sp-3); }
.brd-batch-head { display:flex; flex-direction:column; gap:var(--sp-2); }
.brd-batch-line { display:flex; align-items:baseline; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3); }
.brd-batch-label { font:600 var(--fs-micro)/18px var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--ink-muted); }
:lang(zh-CN) .brd-batch-label { text-transform:none; letter-spacing:.02em; }
.brd-batch-id { font-family:var(--mono); font-size:var(--fs-micro); color:var(--ink-faint); }
.brd-batch-count { font-size:var(--fs-caption); color:var(--ink-muted); }
.brd-batch-spend { font-size:var(--fs-caption); color:var(--ink-faint); margin-left:auto; }
.brd-batch-tally { font-family:var(--mono); font-size:var(--fs-caption); color:var(--ink-muted); }
.brd-batch-verbs { display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.brd-batch-why { font-size:var(--fs-caption); color:var(--ink-muted); }
/* The members are the same lines the board draws everywhere else, set in one
   step so the grouping is legible without redrawing a run. */
.brd-batch-members { padding-left:var(--sp-3); border-left:2px solid var(--hairline); }

/* ---------------------------------------------------------------------------
   THE ARMED BATCH STRIP (components/m5Batch.js). The same copper the single
   deepening's strip wears (`.rlz-deepen.armed`), for the same reason and under
   the same rule: copper only when money moves. On this strip exactly one
   figure is that money — `.m5-bat-total .spend`. The per-run band beside it is
   the arithmetic behind the total and takes the ordinary reading ink.
   --------------------------------------------------------------------------- */
.m5-bat { margin-top:12px; padding:10px 12px; border-radius:var(--r-md);
  border:1px solid var(--hairline); background:var(--surface-2); }
.m5-bat.armed { border-color:var(--armed); background:var(--armed-soft); }
.m5-bat-head { display:flex; align-items:baseline; flex-wrap:wrap; gap:10px; }
.m5-bat-title { font:600 var(--fs-caption)/1.4 var(--font); text-transform:uppercase;
  letter-spacing:var(--track-caps); color:var(--ink-muted); }
:lang(zh-CN) .m5-bat-title { text-transform:none; letter-spacing:.02em; }
.m5-bat-count { font-size:var(--fs-data); color:var(--text-muted); }
.m5-bat-row { display:flex; align-items:center; flex-wrap:wrap; gap:10px; margin-top:8px; }
.m5-bat-per { font:400 var(--fs-data)/1 var(--mono); color:var(--text-muted); }
.m5-bat-total { font:400 var(--fs-data)/1 var(--mono); color:var(--text-muted); }
.m5-bat-est.pending { font-size:var(--fs-data); color:var(--text-faint); }
.m5-bat-why { margin-top:6px; font-size:var(--fs-caption); color:var(--text-muted); max-width:var(--measure-note); }
.m5-bat-law { margin-top:6px; font-size:var(--fs-caption); color:var(--text-muted); max-width:var(--measure-note); }
.m5-bat-note { margin-top:6px; font-size:var(--fs-micro); color:var(--text-faint); max-width:var(--measure-note); }
.m5-bat-items { margin-top:6px; font-size:var(--fs-micro); color:var(--text-faint); overflow-wrap:anywhere; }
.m5-bat-refused-who { font-size:var(--fs-caption); color:var(--text-muted); margin-top:4px; }
.m5-bat-refused-why { font-size:var(--fs-caption); color:var(--text); max-width:var(--measure-note); margin-top:2px; }

/* The compact line: the SAME drawing, smaller. Only scale and the dropped
   anchors differ — every rule below is a size, never a colour or a shape. */
.m5-line.compact { border:0; border-radius:0; padding:0; background:transparent; }
.m5-line.compact .m5-line-head { margin-bottom:var(--sp-2); }
.m5-line.compact .m5-vessel { width:14px; height:17px; }
.m5-line.compact .m5-stations { gap:var(--sp-2); }
.m5-line.compact .m5-stn-note { font-size:var(--fs-micro); }

/* THE TRAY. Filling costs nothing; one commit spends. */
.brd-tray { border:1px solid var(--hairline); border-radius:var(--r-md); background:var(--surface);
  padding:var(--sp-3) var(--sp-4); }
.brd-pots { list-style:none; margin:var(--sp-2) 0; padding:0; display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.brd-pots li { font-size:var(--fs-caption); border:1px solid var(--border); border-radius:var(--r-xs);
  padding:2px 8px; color:var(--ink-muted); }
.brd-tray-sum { font-family:var(--mono); font-size:var(--fs-caption); color:var(--ink-muted);
  margin:var(--sp-2) 0; }

/* Print: the board is a SCREEN instrument for the same reason the line is —
   a page of runs in flight is a photograph of a machine, not a record of one. */
@media print { .brd, .brd-tray, .m5-bat { display:none; } }

/* Module 5 decision dossier (pages/dossier.js): entry form, run progress, reader. */
.dsr-entry .panel-header { display:flex; align-items:center; justify-content:space-between; gap:10px; flex-wrap:wrap; }
.dsr-modes, .dsr-efforts { border:0; padding:0; margin:0; display:flex; flex-direction:column; gap:4px; }
.dsr-visuals { display:flex; flex-wrap:wrap; align-items:baseline; gap:6px; margin:4px 0 12px; }
.dsr-visuals[hidden] { display:none; }
.dsr-concepts { display:flex; flex-direction:column; gap:10px; }
.dsr-concept-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(240px, 1fr)); gap:12px; }
.dsr-concept { display:flex; flex-direction:column; gap:8px; padding:14px 16px; border:1px solid var(--border); border-radius:var(--radius, 8px); background:var(--surface, transparent); }
.dsr-concept.is-recommended { border-color:var(--ok, var(--accent)); box-shadow:0 0 0 1px var(--ok, var(--accent)); }
.dsr-concept-head { display:flex; justify-content:space-between; align-items:center; gap:8px; }
.dsr-concept p, .dsr-concept dl { margin:0; }
.dsr-concept dd { margin:0 0 6px; }
.dsr-concept .btn { align-self:flex-start; margin-top:auto; }
.dsr-progress { margin-top:var(--sp-3); }
/* The dossier run's own panel (dossierProgressHtml): padded, wrapping, and a
   stage bar from components/liveRuns.js — no longer Module 1's .m1-run rules
   borrowed without their panel. */
.dsr-run { display:flex; flex-direction:column; gap:8px; padding:14px 16px; border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface); min-width:0; overflow-wrap:anywhere; }
.dsr-run[data-status="running"], .dsr-run[data-status="queued"] { border-color:var(--accent); }
.dsr-run-head { display:flex; flex-wrap:wrap; justify-content:space-between; align-items:baseline; gap:4px 12px; }
.dsr-run-count { font-size:var(--fs-caption); color:var(--text-muted); font-variant-numeric:tabular-nums; }
.dsr-run-meta { display:flex; flex-wrap:wrap; justify-content:space-between; gap:4px 12px; font-size:var(--fs-caption); color:var(--text-faint); }
.dsr-run-note { font-size:var(--fs-caption); color:var(--text-muted); }
.dsr-run .btn-row { display:flex; flex-wrap:wrap; gap:8px; }
.dsr-failure-reasons summary { cursor:pointer; font-weight:600; }
.dsr-failure-reasons ul { margin:6px 0 0; padding-left:1.25em; max-height:24em; overflow:auto; overflow-wrap:anywhere; }
.dsr-failure-reasons li { margin:4px 0; }
.dsr-blocking-reasons { border-left:4px solid var(--danger); background:var(--danger-soft); padding:8px 12px; }
.dsr-blocking-reasons summary { color:var(--danger); }
.dsr-failure-reasons code { font-size:.85em; }
.dsr-toolbar { position:sticky; top:0; z-index:2; background:var(--surface); padding-block:8px; align-items:center; }
.dsr-deepen summary { cursor:pointer; }
.dsr-toolbar, .dsr-page .dsr-deepen { max-width:840px; margin-inline:auto; }

/* The reader is a document: a sheet of paper set like a professional report, the
   same markup on screen and on A4. It keeps its own paper palette (a dark cockpit
   still shows paper) and ONE accent, in FS's own house palette (docs/module5/fs-design/):
   warm paper, dark tea-brown ink, a deep osmanthus-gold accent, serif display type.
   Rules divide; nothing inside the sheet is a box. */
.dsr-doc {
  /* The dossier wears its label's family (pages/dossier.js dossierTheme): --theme-* come from the reader, and the
     斐素 house values are the fallback. */
  --dsr-accent:var(--theme-accent, #8F6326); --dsr-rule:var(--theme-rule, #E6DCCB); --dsr-pad:64px;
  --dsr-serif:var(--theme-display, "Noto Serif SC","Noto Serif CJK SC","Source Han Serif SC","Songti SC","STSong",serif);
  --dsr-fs-title:34px; --dsr-fs-h2:19px; --dsr-fs-body:13.5px; --dsr-fs-label:11px;
  --dsr-gap-label:6px; --dsr-gap-para:8px; --dsr-gap-block:24px;
  --text:var(--theme-ink, #2B2118); --ink:var(--theme-ink, #2B2118); --text-muted:var(--theme-muted, #5E5244); --ink-muted:var(--theme-muted, #5E5244); --text-faint:var(--theme-faint, #6F6353); --ink-faint:var(--theme-faint, #6F6353);
  --border:var(--dsr-rule);
  max-width:840px; margin:var(--sp-2) auto var(--sp-6); padding:0 0 var(--dsr-pad);
  background:var(--theme-paper, #FFFDF8); color:var(--text); border:1px solid var(--theme-rule, #E2D8C6); box-shadow:0 1px 3px rgba(43,33,24,.08);
  font-size:var(--dsr-fs-body); line-height:1.6;
}
.dsr-doc:lang(zh-CN) { line-height:1.78; }
.dsr-doc p { margin:0 0 var(--dsr-gap-para); }
.dsr-doc p:last-child { margin-bottom:0; }
.dsr-doc strong { font-weight:600; }
.dsr-thesis { font-weight:600; }
.dsr-prose + .dsr-prose { margin-top:var(--dsr-gap-para); }
.dsr-callout { border-left:2px solid var(--dsr-accent); padding-left:14px; }
.dsr-num { color:var(--dsr-accent); font-weight:600; font-variant-numeric:tabular-nums; min-width:2ch; }
.dsr-label { font-weight:600; color:var(--dsr-accent); margin-bottom:8px; }
.dsr-note { color:var(--text-muted); font-style:italic; }
.dsr-doc > .dsr-note { padding:0 var(--dsr-pad); margin:40px 0 0; }

.dsr-cover { padding:0 var(--dsr-pad); }
.dsr-band { display:flex; justify-content:space-between; gap:var(--sp-4); margin:0 calc(-1 * var(--dsr-pad)) 40px;
  padding:14px var(--dsr-pad); background:var(--dsr-accent); color:#FFFFFF; font-weight:600;
  letter-spacing:var(--track-caps-wide); text-transform:uppercase; -webkit-print-color-adjust:exact; print-color-adjust:exact; }
.dsr-doc:lang(zh-CN) .dsr-band { letter-spacing:.12em; }
.dsr-cover h1 { font-family:var(--dsr-serif); font-size:var(--dsr-fs-title); font-weight:700; line-height:1.2; letter-spacing:-.015em; margin:0 0 28px; }
.dsr-cover h1::after { content:""; display:block; width:56px; height:3px; margin-top:24px; background:var(--dsr-accent);
  -webkit-print-color-adjust:exact; print-color-adjust:exact; }
.dsr-cover-call { max-width:62ch; margin:0 0 24px; }
.dsr-doc .dsr-cover-call .badge { display:block; margin-bottom:4px; color:var(--dsr-accent); letter-spacing:var(--track-caps); text-transform:uppercase; }
.dsr-meta { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:0 32px; margin:0 0 48px; border-top:1px solid var(--text); }
.dsr-meta > div { padding:9px 0; border-bottom:1px solid var(--dsr-rule); }
.dsr-meta dt { color:var(--text-muted); }
.dsr-meta dd { margin:0; }
.dsr-exec { margin:0 0 26px; padding:14px 16px; border:1px solid var(--dsr-rule); background:var(--theme-tint, #FBF6EA); }
.dsr-exec dl { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:14px 20px; margin:0; }
.dsr-exec dl > div:last-child { grid-column:1/-1; padding-top:10px; border-top:1px solid var(--dsr-rule); }
.dsr-exec dt { color:var(--text-muted); font-size:.88em; }
.dsr-exec dd { margin:2px 0 0; font-weight:600; }
.dsr-document-details { margin:-28px 0 34px; color:var(--text-muted); font-size:.9em; }
.dsr-document-details > summary { cursor:pointer; color:var(--dsr-accent); }
.dsr-document-details code { font-family:var(--mono); font-size:.86em; overflow-wrap:anywhere; }
.dsr-contents ol { list-style:none; margin:0; padding:0; columns:2; column-gap:32px; }
.dsr-contents li { break-inside:avoid; }
.dsr-toc { display:flex; gap:12px; width:100%; padding:6px 0; border:0; border-bottom:1px solid var(--dsr-rule);
  background:none; color:var(--text); font:inherit; text-align:left; cursor:pointer; }
.dsr-toc:hover { color:var(--dsr-accent); }
.dsr-toc:focus-visible, .dsr-doc .dsr-test-ref:focus-visible { outline:2px solid var(--dsr-accent); outline-offset:2px; }

.dsr-doc .dsr-sec { padding:0 var(--dsr-pad); margin-top:56px; }
.dsr-h2 { display:flex; gap:14px; align-items:baseline; margin:0 0 20px; padding-bottom:10px; border-bottom:1px solid var(--text);
  font-family:var(--dsr-serif); font-size:var(--dsr-fs-h2); font-weight:700; line-height:1.3; }
.dsr-doc .caps-label { font:600 var(--dsr-fs-label)/1.5 var(--font); letter-spacing:var(--track-caps); text-transform:uppercase;
  color:var(--dsr-accent); margin:0 0 var(--dsr-gap-label); }
.dsr-doc:lang(zh-CN) .caps-label { letter-spacing:.04em; }
.dsr-field { margin:0 0 var(--dsr-gap-block); }
.dsr-call { margin-bottom:var(--dsr-gap-label); }
.dsr-doc .dsr-call .badge { color:var(--dsr-accent); }
/* A grid of fields reads as a ruled fact sheet: label column, value column. */
.dsr-grid { margin:0 0 var(--dsr-gap-block); border-top:1px solid var(--dsr-rule); }
.dsr-grid > .dsr-field { display:grid; grid-template-columns:minmax(120px, 26%) minmax(0, 1fr); gap:0 24px; margin:0; padding:12px 0; border-bottom:1px solid var(--dsr-rule); }
.dsr-doc .dsr-grid > .dsr-field > .caps-label { color:var(--text-faint); margin:0; padding-top:.2em; }
.dsr-list { margin:0; padding-left:1.1em; } .dsr-list li + li { margin-top:4px; }
.dsr-chain { margin:0 0 20px; padding-left:1.6em; } .dsr-chain li { margin-bottom:10px; padding-left:4px; }
.dsr-chain li::marker { color:var(--dsr-accent); font-weight:600; }
.dsr-facts { display:flex; flex-wrap:wrap; margin:0; font-weight:600; }
.dsr-fact + .dsr-fact::before { content:"·"; margin:0 10px; color:var(--text-faint); font-weight:400; }
.dsr-en, .dsr-zh { display:block; } .dsr-zh { color:var(--ink-muted); }
.dsr-doc .notice { border-left:2px solid var(--dsr-accent); padding:2px 0 2px 14px; margin:0 0 var(--dsr-gap-block); font-size:inherit; }
/* Tables: booktabs rules, no fills, no header caps. */
.dsr-doc table.table { font-size:inherit; border-top:1.5px solid var(--text); border-bottom:1.5px solid var(--text); }
.dsr-doc .table thead th { position:static; background:none; color:var(--text); font-size:inherit; font-weight:600; letter-spacing:0;
  text-transform:none; white-space:normal; padding:8px 16px 8px 0; border-bottom:1px solid var(--text); }
.dsr-doc .table tbody td { padding:8px 16px 8px 0; border-bottom:1px solid var(--dsr-rule); vertical-align:top; }
.dsr-doc .table th:last-child, .dsr-doc .table td:last-child { padding-right:0; }
.dsr-doc .table tbody tr:last-child td { border-bottom:0; }
.dsr-doc .table tbody tr:hover td { background:none; }
/* Sources: a short citation with a superscript number; the raw ids sit in References. */
.dsr-cite-n { font-size:.72em; line-height:0; vertical-align:super; margin-left:1px; color:var(--dsr-accent); font-weight:600; }
/* The one-page decision brief: the packet's highlights as a two-column list (captain, 2026-10-08). */
.dsr-brief-grid { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr)); gap:16px 28px; margin:0; }
.dsr-brief-grid > div { min-width:0; break-inside:avoid; }
.dsr-brief-grid dt { margin-bottom:4px; }
.dsr-brief-grid dd { margin:0; }
.dsr-brief-grid .dsr-list { margin:0; padding-left:1.2em; }
.dsr-decision-brief > .dsr-note { margin-top:20px; }
@media (max-width:720px) { .dsr-brief-grid { grid-template-columns:minmax(0, 1fr); } }
.dsr-flagged { margin:24px var(--dsr-pad) 0; padding:12px 16px; border-left:3px solid var(--warn); background:var(--warn-soft); }
.dsr-must-fix { border-left-color:var(--danger); background:var(--danger-soft); }
.dsr-blocking { margin:0 var(--dsr-pad) 24px; border:2px solid var(--danger); border-left-width:6px; background:var(--danger-soft); -webkit-print-color-adjust:exact; print-color-adjust:exact; }
.dsr-blocking .caps-label { color:var(--danger); font-weight:700; }
.dsr-unverified { color:var(--danger); }
.dsr-flag-source { display:block; font-weight:600; }
.dsr-flagged ol { margin:6px 0 0; padding-left:1.6em; }
.dsr-flagged li { margin-bottom:6px; }
.dsr-flagged code { font-family:var(--mono); font-size:.8em; color:var(--text-faint); word-break:break-all; margin-left:6px; }
.dsr-refs { padding:0 var(--dsr-pad); margin-top:40px; }
.dsr-refs ol { margin:0; padding-left:1.6em; }
.dsr-refs li { margin-bottom:4px; color:var(--text-muted); }
.dsr-refs li::marker { color:var(--dsr-accent); font-weight:600; }
.dsr-refs code { font-family:var(--mono); font-size:.85em; color:var(--text-faint); word-break:break-all; margin-left:6px; }
/* Status words are words in a document, not pills. */
.dsr-doc .badge { display:inline; padding:0; border-radius:0; background:none; color:var(--text); font-size:inherit; font-weight:600; white-space:normal; }
.dsr-doc .dsr-test-ref { display:inline; height:auto; padding:0; border:0; background:none; box-shadow:none;
  color:var(--dsr-accent); font:inherit; font-weight:600; cursor:pointer; }
.dsr-doc .dsr-test-ref:hover { text-decoration:underline; }
.dsr-tests { list-style:none; margin:0; padding:0; }
.dsr-test { margin:0 0 calc(var(--dsr-gap-block) + 12px); }
.dsr-test-head { display:flex; gap:14px; align-items:baseline; padding-bottom:8px; }
.dsr-doc .dsr-test-head .badge { color:var(--dsr-accent); min-width:2.5ch; }
.dsr-test .dsr-grid { border-top:1.5px solid var(--text); }
.dsr-timeline { list-style:none; margin:0; padding:0; }
.dsr-value-basis { display:block; margin-top:2px; color:var(--text-muted); font-size:.82em; font-weight:400; }
.dsr-timeline-note { margin-bottom:10px; }
.dsr-timeline li { display:grid; grid-template-columns:minmax(180px,1.5fr) minmax(80px,1fr) minmax(130px,auto); align-items:center; gap:12px; margin:12px 0; break-inside:avoid; }
.dsr-timeline-label { min-width:0; }
.dsr-timeline-name { display:block; font-weight:600; }
.dsr-timeline-label small { display:block; margin-top:2px; color:var(--dsr-accent); font-weight:600; }
.dsr-timeline-track { height:6px; background:var(--dsr-rule); }
.dsr-timeline-track > span { display:block; height:100%; background:var(--dsr-accent); -webkit-print-color-adjust:exact; print-color-adjust:exact; }
.dsr-timeline strong { font-weight:500; }
.dsr-chart { margin:4px 0 8px; break-inside:avoid; }
.dsr-chart-svg { display:block; width:100%; height:auto; max-width:640px; -webkit-print-color-adjust:exact; print-color-adjust:exact; }
.dsr-print-only { display:none; }
/* The product-image and label sections follow the document: the same paper, serif section head and gold rule, no UI card. */
.dsr-images.panel, .dsr-label.panel { max-width:840px; margin:0 auto var(--sp-6); padding:40px 64px; background:var(--theme-paper, #FFFDF8); color:var(--theme-ink, #2B2118);
  border:1px solid var(--theme-rule, #E2D8C6); border-radius:0; box-shadow:0 1px 3px rgba(43,33,24,.08); }
.dsr-images > .panel-header, .dsr-label > .panel-header { padding:0 0 10px; margin:0 0 20px; border-bottom:1px solid var(--theme-ink, #2B2118); }
.dsr-images .panel-title, .dsr-label .panel-title { font-family:var(--theme-display, "Noto Serif SC","Noto Serif CJK SC","Source Han Serif SC","Songti SC","STSong",serif);
  font-size:19px; font-weight:700; color:var(--theme-ink, #2B2118); }
.dsr-images > .panel-body, .dsr-label > .panel-body { padding:0; }
.dsr-images .caps-label, .dsr-label .caps-label { color:var(--theme-accent, #8F6326); font-weight:600; }
.dsr-images .muted, .dsr-label .muted { color:var(--theme-faint, #6F6353); }
.dsr-image img, .dsr-label-art img { border-color:var(--theme-rule, #E6DCCB); }
/* Studio stills are shot on white: multiply lets the white become the page's paper instead of a box. */
.dsr-cover-image img, .dsr-image img, .dsr-turntable img { mix-blend-mode:multiply; border:0; }
.dsr-page .dsr-label { max-width:840px; margin-inline:auto; }
.dsr-label-art { margin:0 0 12px; }
.dsr-label-art img { width:100%; height:auto; border:1px solid var(--border, #ddd); background:#fff; }
.dsr-label-flags { margin:4px 0 12px; padding-left:18px; }
.dsr-label-flag-details { margin-top:4px; color:var(--text-muted); font-size:var(--fs-caption); }
.dsr-label-flag-details > summary { cursor:pointer; }
.dsr-label-flag-details code { white-space:normal; overflow-wrap:anywhere; }
.dsr-turntable video { display:block; max-width:360px; width:100%; margin:8px auto; background:#eee; }
.dsr-turntable img { width:100%; height:auto; }
.dsr-page .dsr-images { max-width:840px; margin-inline:auto; }
.dsr-image-grid { display:grid; grid-template-columns:repeat(auto-fit, minmax(220px, 1fr)); gap:16px; margin:0 0 12px; }
.dsr-image { margin:0; break-inside:avoid; }
.dsr-image img { display:block; width:100%; height:auto; border:1px solid var(--border, #ddd); background:#fff; }
.dsr-image figcaption { margin-top:6px; }
.dsr-cover-image { margin:0 0 32px; }
/* The label's own painting as the cover's header art: the dossier wears the product's FS artwork, not a UI band. */
.dsr-cover-art { margin:-40px calc(-1 * var(--dsr-pad)) 32px; height:150px; overflow:hidden; -webkit-print-color-adjust:exact; print-color-adjust:exact; }
.dsr-cover-art img { display:block; width:100%; height:100%; object-fit:cover; object-position:left 40%; }
.dsr-cover-image img { display:block; max-width:100%; max-height:280px; height:auto; }
@media print {
  .dsr-cover-image img { max-height:95mm; }
  .dsr-image-grid { grid-template-columns:repeat(2, minmax(0, 1fr)); }
  /* A deepening panel's heading stays with its first content rather than ending a page on its own. */
  .dsr-images > .panel-header, .dsr-label > .panel-header { break-after:avoid; }
  .dsr-images > .panel-header + .panel-body > :first-child, .dsr-label > .panel-header + .panel-body > :first-child { break-before:avoid; break-inside:avoid; }
}

@media (max-width:720px) {
  .dsr-doc { --dsr-pad:20px; --dsr-fs-title:26px; }
  .dsr-meta, .dsr-grid > .dsr-field { grid-template-columns:minmax(0, 1fr); }
  .dsr-exec dl { grid-template-columns:minmax(0,1fr); }
  .dsr-exec dl > div:last-child { grid-column:auto; }
  .dsr-contents ol { columns:1; }
  .dsr-timeline li { grid-template-columns:minmax(0,1fr) minmax(110px,auto); gap:6px 12px; }
  .dsr-timeline-track { grid-row:2; }
  .dsr-timeline strong { grid-column:2; grid-row:2; }
}

/* A4 pages. Sections 01–04 share a named page; 05–09 each start a new one.
   The reader supplies bilingual group headers as root custom properties.
   Every page keeps the same margins. Chrome drops comma-separated page selectors,
   so each named page repeats its geometry. */
@page dsr-en-cover { size:A4; margin:22mm 20.5mm 20mm 20mm; }
@page dsr-zh-cover { size:A4; margin:22mm 20.5mm 20mm 20mm; }
@page dsr-en-short { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-zh-short { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-en-brief { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-brief); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-zh-brief { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-brief); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-en-overview { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-overview); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-en-product_definition { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-product_definition); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-en-cost_economics { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-cost_economics); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-en-bench_tests { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-bench_tests); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-en-risks_alternatives { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-risks_alternatives); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-en-honesty_ledger { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-honesty_ledger); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-zh-overview { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-overview); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-zh-product_definition { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-product_definition); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-zh-cost_economics { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-cost_economics); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-zh-bench_tests { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-bench_tests); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-zh-risks_alternatives { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-risks_alternatives); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-zh-honesty_ledger { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-honesty_ledger); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-en-recipe { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-recipe); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-en-specification { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-en-name); } @top-right { content:var(--dsr-en-head-specification); } @bottom-left { content:var(--dsr-en-foot); } @bottom-right { content:var(--dsr-en-pages); } }
@page dsr-zh-recipe { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-recipe); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
@page dsr-zh-specification { size:A4; margin:22mm 20.5mm 20mm 20mm; font:8pt/1.3 "IBM Plex Sans","PingFang SC","Microsoft YaHei",sans-serif; color:#6F6353; @top-left { content:var(--dsr-zh-name); } @top-right { content:var(--dsr-zh-head-specification); } @bottom-left { content:var(--dsr-zh-foot); } @bottom-right { content:var(--dsr-zh-pages); } }
/* A recipe option or process option inside section 10: a lighter heading that stays with its first block. */
.dsr-h3 { margin:32px 0 14px; font-family:var(--dsr-serif); font-size:calc(var(--dsr-fs-h2) - 3px); font-weight:600; line-height:1.35; break-after:avoid; }
.dsr-nowrap { white-space:nowrap; }
@media print {
  body:has(.dsr-doc) { background:#FFFDF8; }
  body:has([data-dossier-theme="aldi"]) { background:#FFFCF3; }
  body:has(.dsr-doc) .sidebar, body:has(.dsr-doc) .topbar, .dsr-toolbar, .dsr-deepen, .dsr-screen-only, .dsr-turntable .dsr-screen-only { display:none; }
  body:has(.dsr-doc) .app, body:has(.dsr-doc) .main, body:has(.dsr-doc) .content { display:block; margin:0; padding:0; max-width:none; }
  .dsr-print-only { display:block; }
  .dsr-doc { --dsr-pad:0px; --dsr-fs-title:26pt; --dsr-fs-h2:14pt; --dsr-fs-body:9.5pt; --dsr-fs-label:7pt;
    max-width:none; margin:0; padding:0; border:0; box-shadow:none; }
  .dsr-band { margin:0 0 16mm; padding:6mm 7mm; }
  .dsr-doc .dsr-sec { margin-top:10mm; }
  .dsr-doc > .dsr-note, .dsr-refs { margin-top:8mm; }
  .dsr-doc .table-wrap { overflow:visible; }
  .dsr-doc .table thead { display:table-header-group; }
  /* References set a step smaller, so a long list does not strand its last line on a page of its own. */
  .dsr-refs { break-before:page; font-size:.86em; line-height:1.45; }
  .dsr-refs li { margin-bottom:2px; }
  /* The 360° poster stays with the label artwork on one page instead of starting a near-empty page. */
  .dsr-turntable { break-inside:avoid; break-before:avoid; }
  .dsr-turntable img { max-height:62mm; width:auto; max-width:100%; margin:0 auto; }
  .dsr-h2, .dsr-field > .caps-label, .dsr-test-head, .dsr-thesis, .dsr-chart { break-after:avoid; }
  .dsr-h2 + * { break-before:avoid; break-inside:avoid; }
  .dsr-doc tr, .dsr-grid > .dsr-field, .dsr-chain li, .dsr-meta > div, .dsr-refs li { break-inside:avoid; }
  .dsr-document-details > :not(summary) { display:block; }
  /* Both short versions start with the decision brief and let the remaining sections flow compactly. */
  .dsr-doc-short { --dsr-gap-block:8px; --dsr-gap-para:4px; line-height:1.4; }
  .dsr-doc-short:lang(zh-CN) { line-height:1.5; }
  .dsr-doc-short .dsr-cover { display:none; }
  .dsr-doc-short .dsr-sec { margin-top:4mm; }
  .dsr-doc-short .dsr-h2 { margin-bottom:2mm; padding-bottom:5px; }
  .dsr-doc-short .dsr-grid > .dsr-field { padding:4px 0; }
  .dsr-doc-short .table thead th, .dsr-doc-short .table tbody td { padding-top:4px; padding-bottom:4px; }
  .dsr-doc-short .dsr-refs { break-before:auto; margin-top:4mm; }
}

.dsr-gate-sequence { display:grid; gap:12px; padding-left:28px; border-left:2px solid var(--border); }
.dsr-gate-sequence > li { padding:8px 12px; break-inside:avoid; }

/* ==== Live runs (components/liveRuns.js, runTracker.js) ====================
   One look for a server run on every page: the shell popover's rows, the
   Design Suite's first card slot, the library, the dossier progress panel.
   The stage bar is one segment per stage ("stage i of n"); without a count it
   is an honest indeterminate sweep, never a still 4% sliver. */
.run-bar { position:relative; height:8px; border-radius:var(--r-pill); background:var(--accent-soft); overflow:hidden; width:100%; min-width:0; }
.run-bar.is-steps { display:grid; grid-template-columns:repeat(var(--run-steps), minmax(0,1fr)); gap:2px; background:none; }
.run-seg { height:100%; background:var(--accent-soft); border-radius:2px; }
.run-seg.done { background:var(--accent); }
.run-seg.now { background:var(--accent-2); animation:run-breathe 1.6s var(--ease) infinite; }
.run-bar.is-indeterminate .run-bar-sweep { position:absolute; top:0; bottom:0; width:35%; border-radius:inherit; background:var(--accent); animation:run-sweep 1.8s var(--ease) infinite; }
.run-bar.is-done .run-bar-fill { position:absolute; inset:0; background:var(--accent); }
.run-bar.is-failed { background:var(--danger-soft); }
@keyframes run-breathe { 50% { opacity:.45; } }
@keyframes run-sweep { from { left:-35%; } to { left:100%; } }
@media (prefers-reduced-motion: reduce) {
  .run-seg.now { animation:none; opacity:.7; }
  .run-bar.is-indeterminate .run-bar-sweep { animation:none; left:0; width:100%; opacity:.45; }
}
.run-elapsed { font-variant-numeric:tabular-nums; }
.lr-list { display:flex; flex-direction:column; gap:6px; margin:8px 0; max-height:50vh; overflow:auto; min-width:0; }
.lr-row { display:grid; gap:1px; padding:7px 9px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--surface); color:var(--text); min-width:0; overflow-wrap:anywhere; }
a.lr-row:hover { border-color:var(--border-strong); background:var(--surface-2); }
.lr-kind { font-size:var(--fs-micro); font-weight:600; letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--text-faint); }
.lr-title { font-size:var(--fs-data); font-weight:600; line-height:1.35; display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden; }
.lr-meta { font-size:var(--fs-caption); color:var(--text-muted); }
.lr-foot { display:flex; gap:10px; font-size:var(--fs-caption); color:var(--text-faint); }
.lr-card { display:flex; flex-direction:column; gap:8px; padding:14px 16px; border:1px solid var(--accent); border-radius:var(--r-lg); background:var(--accent-soft); min-width:0; overflow-wrap:anywhere; }
.lr-card-head { display:flex; align-items:center; gap:8px; }
.lr-dot { width:8px; height:8px; border-radius:50%; background:var(--accent); box-shadow:0 0 0 3px var(--accent-soft-2); animation:run-breathe 1.6s var(--ease) infinite; flex-shrink:0; }
.lr-card-title { font-size:var(--fs-prose); font-weight:600; line-height:1.35; margin:0; }
.lr-card-meta { display:flex; flex-wrap:wrap; justify-content:space-between; gap:4px 12px; font-size:var(--fs-caption); color:var(--text-muted); }
.lr-card-nums { color:var(--text-faint); }
.lr-card-actions { display:flex; flex-wrap:wrap; gap:8px; }
@media (prefers-reduced-motion: reduce) { .lr-dot { animation:none; } }
.v-pop .lr-list { max-height:40vh; }
.v-pop .v-note { font-size:var(--fs-caption); color:var(--text-faint); margin:6px 0 8px; }

/* ==== Director overhaul (FS Improvement Notes 2026-09-22) ================== */
/* History rows carry a delete control beside the link; the title keeps its
   ellipsis and the row never widens the rail. */
.dir-history-row { display:flex; align-items:stretch; gap:2px; min-width:0; }
.dir-history-row > .dir-history-item { flex:1; min-width:0; }
.dir-history-del { flex-shrink:0; align-self:center; width:28px; height:28px; color:var(--text-faint); opacity:.55; }
.dir-history-row:hover .dir-history-del, .dir-history-del:focus-visible { opacity:1; }
.dir-history-del:hover { color:var(--danger-text); background:var(--danger-soft); }
@media (hover: none) { .dir-history-del { opacity:.85; } }
/* Past dossiers on #/realize: the Conversations rail's look and rows, stacked under the New drink idea panel. */
.dsr-history { margin-top:var(--sp-3); border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface-2); padding:8px; }
.dsr-history-scroll { display:flex; flex-direction:column; gap:6px; margin-top:8px; max-height:50vh; overflow:auto; overscroll-behavior:contain; }
.dsr-history-scroll > .btn { align-self:flex-start; }
.dsr-history-row { flex-wrap:wrap; align-items:center; }
.dsr-history-pdf { flex-basis:100%; display:flex; flex-wrap:wrap; gap:8px; align-items:baseline; padding:0 8px 6px; font-size:var(--fs-micro); color:var(--text-faint); }
.dir-pending-body { display:flex; flex-direction:column; gap:4px; min-width:0; }
.dir-pending-line { display:inline-flex; align-items:center; gap:8px; }
.dir-remote-note { font-size:var(--fs-caption); color:var(--text-muted); }
/* The answer-mode switch: two options, each with its own ceiling. */
.dir-mode-switch { display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:8px; margin-top:8px; }
.dir-mode-opt { display:flex; align-items:flex-start; gap:8px; padding:8px 10px; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface); cursor:pointer; min-width:0; }
.dir-mode-opt.on { border-color:var(--accent); background:var(--accent-soft); }
.dir-mode-opt input { margin-top:2px; flex-shrink:0; }
.dir-mode-opt:has(input:disabled) { opacity:.6; cursor:not-allowed; }
.dir-mode-opt:has(input:focus-visible) { box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
.dir-mode-txt { display:flex; flex-direction:column; gap:1px; min-width:0; }
.dir-mode-name { font-weight:600; font-size:var(--fs-data); }
.dir-mode-desc, .dir-mode-ceil { font-size:var(--fs-caption); color:var(--text-muted); }
.dir-mode-ceil { color:var(--spend-ink); font-variant-numeric:tabular-nums; }
@media (max-width:520px) { .dir-mode-switch { grid-template-columns:1fr; } }
.dir-fast-badge { background:var(--info-soft); color:var(--info-text); }
/* "What changed": the dated baseline and the sources it covers. */
.rlz-brief-scope { font-size:var(--fs-caption); color:var(--text-muted); border-left:2px solid var(--border-strong); padding:4px 0 4px 10px; margin:6px 0 10px; }
.rlz-brief-covers { margin-top:4px; font-weight:600; color:var(--text-faint); }
.rlz-brief-sources { list-style:none; margin:2px 0 0; padding:0; display:flex; flex-wrap:wrap; gap:4px 14px; }
.rlz-brief-src { color:var(--text); }
/* The citation record: wide, wrapping, the path read file-first. */
.dialog.dir-record { width:760px; }
.rec-ref { font-family:var(--mono); font-size:var(--fs-caption); overflow-wrap:anywhere; white-space:normal; }
/* The machine ref is secondary: last, small and faint, still copyable. */
.rec-ref-row { margin-top:8px; padding-top:8px; border-top:1px solid var(--border); font-size:var(--fs-caption); color:var(--text-faint); }
.rec-ref-row .rec-ref { color:var(--text-faint); }
.rlz-warn-code { margin-left:6px; font-size:var(--fs-micro); color:var(--text-faint); }
.rec-path { display:flex; flex-direction:column; min-width:0; }
.rec-file { font-weight:600; overflow-wrap:anywhere; }
.rec-dir { font-family:var(--mono); font-size:var(--fs-micro); color:var(--text-faint); overflow-wrap:anywhere; }
.rec-subs { display:flex; flex-direction:column; gap:3px; min-width:0; }
.rec-sub { display:grid; grid-template-columns:minmax(80px, 30%) minmax(0,1fr); gap:8px; min-width:0; }
.rec-sub-k { color:var(--text-faint); overflow-wrap:anywhere; }
.rec-sub-v { overflow-wrap:anywhere; min-width:0; }
.rec-value { white-space:pre-wrap; }
@media (max-width:520px) { .rec-sub { grid-template-columns:1fr; gap:0; } }
/* Settings › Deleted items. */
.del-list { display:flex; flex-direction:column; gap:8px; }
.del-row { display:flex; flex-wrap:wrap; align-items:center; gap:6px 12px; padding:10px 12px; border:1px solid var(--border); border-radius:var(--r-md); min-width:0; }
.del-main { flex:1 1 240px; min-width:0; overflow-wrap:anywhere; }
.del-title { font-weight:600; }
.del-meta { font-size:var(--fs-caption); color:var(--text-faint); }
.del-row.purged { background:var(--surface-2); }

/* ==== components/flowLine.js — the linear flow ============================
   Brief → Decision dossier (deepened) → Design renders → Feedback. Four
   stations on one belt; the reader's station is inked, a live one breathes.
   At phone width the belt turns vertical. */
.flow { margin:0 0 var(--sp-5); min-width:0; }
.flow-title { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps-wide); text-transform:uppercase; color:var(--ink-faint); margin-bottom:8px; }
.flow-ol { list-style:none; margin:0; padding:0; display:grid; grid-template-columns:repeat(4, minmax(0,1fr)); gap:0; counter-reset:flow; }
.flow-st { position:relative; min-width:0; }
.flow-st + .flow-st::before { content:""; position:absolute; left:-1px; top:22px; width:14px; height:2px; background:var(--border-strong); transform:translateX(-50%); }
.flow-a { display:flex; gap:10px; align-items:flex-start; height:100%; padding:12px 14px; margin-right:12px; border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface); color:var(--text); min-width:0; }
.flow-st:last-child .flow-a { margin-right:0; }
a.flow-a:hover { border-color:var(--border-strong); background:var(--surface-2); }
.flow-st.here .flow-a { border-color:var(--ink); box-shadow:inset 0 0 0 1px var(--ink); }
.flow-st.live .flow-a { border-color:var(--accent); background:var(--accent-soft); }
.flow-n { flex-shrink:0; width:22px; height:22px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font:600 var(--fs-caption)/1 var(--font); background:var(--sunken); color:var(--text-muted); }
.flow-st.here .flow-n { background:var(--ink); color:var(--surface); }
.flow-txt { display:flex; flex-direction:column; gap:3px; min-width:0; overflow-wrap:anywhere; }
.flow-name { font-weight:600; font-size:var(--fs-data); display:inline-flex; align-items:center; gap:6px; }
.flow-d { font-size:var(--fs-caption); color:var(--text-muted); line-height:1.4; }
.flow-deep { display:flex; flex-wrap:wrap; gap:4px; margin-top:2px; }
.flow-deep-i { font-size:var(--fs-micro); padding:1px 6px; border:1px solid var(--border); border-radius:var(--r-pill); color:var(--text-muted); background:var(--surface-2); }
.flow-state { font-size:var(--fs-micro); font-weight:600; letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--accent-text); }
.flow-dot { width:7px; height:7px; border-radius:50%; background:var(--accent); animation:run-breathe 1.6s var(--ease) infinite; }
.flow.compact .flow-a { padding:6px 10px; margin-right:8px; }
.flow.compact .flow-st + .flow-st::before { top:15px; width:8px; }
@media (max-width:900px) {
  .flow-ol { grid-template-columns:1fr 1fr; gap:8px; }
  .flow-a { margin-right:0; }
  .flow-st + .flow-st::before { display:none; }
}
@media (max-width:520px) {
  .flow-ol { grid-template-columns:1fr 1fr; gap:6px; }
  .flow-a { padding:8px 10px; gap:8px; }
  .flow-d, .flow-deep { display:none; }
  .flow-title { margin-bottom:6px; }
}
@media (prefers-reduced-motion: reduce) { .flow-dot { animation:none; } }
@media print { .flow { display:none; } }

/* ==== pages/library.js — the Dossier Library ================================ */
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
.lib-tools { display:flex; flex-direction:column; gap:10px; margin-bottom:var(--sp-4); min-width:0; }
.lib-search { display:flex; align-items:center; gap:8px; padding:0 12px; border:1px solid var(--border-strong); border-radius:var(--r-sm); background:var(--surface); color:var(--text-faint); }
.lib-search:focus-within { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-ring); }
.lib-search input { border:0; padding:0; box-shadow:none !important; background:transparent; }
.lib-filters { display:grid; grid-template-columns:repeat(4, minmax(0,1fr)) auto; gap:8px; align-items:end; }
.lib-f { display:flex; flex-direction:column; gap:4px; min-width:0; font-size:var(--fs-caption); color:var(--text-muted); font-weight:600; }
.lib-clear { align-self:end; }
@media (max-width:900px) { .lib-filters { grid-template-columns:1fr 1fr; } }
@media (max-width:520px) { .lib-filters { grid-template-columns:1fr 1fr; gap:8px 8px; } .lib-f select { height:36px; padding:0 28px 0 10px; } }
.lib-grid { display:grid; grid-template-columns:repeat(auto-fill, minmax(280px, 1fr)); gap:12px; margin-bottom:var(--sp-5); }
@media (max-width:520px) { .lib-grid { grid-template-columns:1fr; } }
.lib-live { margin-bottom:var(--sp-4); }
.lib-group-h { font-size:var(--fs-section); font-weight:600; margin:var(--sp-3) 0 var(--sp-3); display:flex; gap:8px; align-items:baseline; flex-wrap:wrap; }
.lib-count, .lib-none { font-size:var(--fs-data); color:var(--text-muted); margin-bottom:var(--sp-3); }
.lib-batch { display:flex; flex-direction:column; gap:6px; text-align:left; font:inherit; color:inherit; padding:14px 16px; border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface); cursor:pointer; min-width:0; overflow-wrap:anywhere; }
.lib-batch:hover { border-color:var(--border-strong); box-shadow:var(--shadow-md); }
.lib-batch-kind, .lib-card-kind { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps); text-transform:uppercase; color:var(--text-faint); }
.lib-batch-title { font-size:var(--fs-prose); font-weight:600; line-height:1.35; }
.lib-batch-names { list-style:none; margin:0; padding:0; font-size:var(--fs-caption); color:var(--text-muted); display:flex; flex-direction:column; gap:2px; }
.lib-batch-names li { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.lib-batch-meta { font-size:var(--fs-caption); color:var(--text-faint); }
.lib-batch-chains { display:flex; flex-wrap:wrap; gap:4px; }
.lib-crumb { display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin-bottom:var(--sp-3); }
.lib-crumb-cur { font-weight:600; overflow-wrap:anywhere; min-width:0; }
.lib-card { display:flex; flex-direction:column; gap:8px; padding:14px 16px; border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface); min-width:0; overflow-wrap:anywhere; }
.lib-card-top { display:flex; justify-content:space-between; align-items:center; gap:8px; flex-wrap:wrap; }
.lib-card-title { font-size:var(--fs-prose); font-weight:600; line-height:1.35; margin:0; }
.lib-card-meta { display:flex; flex-wrap:wrap; gap:6px 10px; align-items:center; font-size:var(--fs-caption); }
.lib-card-facts { font-size:var(--fs-caption); color:var(--text-muted); }
.lib-card-sum { font-size:var(--fs-data); color:var(--text-muted); margin:0; display:-webkit-box; -webkit-line-clamp:3; -webkit-box-orient:vertical; overflow:hidden; }
.lib-card-legacy-note { margin:0; font-size:var(--fs-caption); color:var(--text-muted); }
.lib-card-actions { display:flex; flex-wrap:wrap; gap:6px; margin-top:auto; }
.lib-cs { display:flex; flex-wrap:wrap; gap:4px; }
.lib-c { display:inline-flex; align-items:center; gap:3px; font-size:var(--fs-micro); padding:1px 7px 1px 5px; border-radius:var(--r-pill); border:1px solid var(--border); color:var(--text-faint); }
.lib-c.on { border-color:var(--ok); color:var(--ok-text); background:var(--ok-soft); }
.lib-c.part { border-color:var(--warn); color:var(--warn-text); background:var(--warn-soft); }
.lib-c.off { border-style:dashed; }
.lib-archive { margin-top:var(--sp-5); }
.lib-archive > summary { cursor:pointer; list-style:none; }
.lib-arch-list { display:flex; flex-direction:column; gap:8px; }
.lib-arch-set { border:1px solid var(--border); border-radius:var(--r-md); padding:8px 12px; }
.lib-arch-set > summary { cursor:pointer; display:flex; flex-wrap:wrap; gap:4px 12px; align-items:baseline; }
.lib-arch-title { font-weight:600; overflow-wrap:anywhere; }
.lib-arch-ters { margin:8px 0 2px 18px; display:flex; flex-direction:column; gap:4px; font-size:var(--fs-data); }
.dialog.lib-dialog { width:1000px; }
.lib-facts { margin-bottom:var(--sp-4); }
.lib-expand-doc .page-header { margin-top:var(--sp-3); }

/* ==== design.js — the control center (FS Improvement Notes 2026-09-22) ==== */
.dsn-cc { margin-bottom:var(--sp-5); min-width:0; }
.dsn-cc-grid { display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:12px; align-items:stretch; }
@media (max-width:1100px) { .dsn-cc-grid { grid-template-columns:1fr 1fr; } }
@media (max-width:700px) { .dsn-cc-grid { grid-template-columns:1fr; } }
.dsn-cc-box { border:1px solid var(--border); border-radius:var(--r-lg); background:var(--surface); padding:12px 14px; min-width:0; overflow-wrap:anywhere; display:flex; flex-direction:column; gap:8px; }
.dsn-cc-h { font-size:var(--fs-data); font-weight:600; margin:0; display:flex; align-items:center; gap:6px; }
.dsn-cc-h2 { font-size:var(--fs-caption); font-weight:600; color:var(--text-muted); margin:6px 0 0; }
.dsn-cc-count { font-size:var(--fs-micro); font-weight:600; padding:0 7px; border-radius:var(--r-pill); background:var(--sunken); color:var(--text-muted); }
.dsn-cc-none { font-size:var(--fs-caption); color:var(--text-faint); margin:0; }
.dsn-cc-list { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:8px; }
.dsn-cc-item { display:flex; flex-direction:column; gap:3px; padding-bottom:8px; border-bottom:1px solid var(--border); min-width:0; }
.dsn-cc-item:last-child { border-bottom:0; padding-bottom:0; }
.dsn-cc-name { font-weight:600; font-size:var(--fs-data); color:var(--text); }
.dsn-cc-meta { font-size:var(--fs-caption); color:var(--text-muted); }
.dsn-cc-act { display:flex; flex-wrap:wrap; gap:6px; }
.dsn-cc-busy { display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-caption); color:var(--text-muted); }
.dsn-cc-more { font-size:var(--fs-caption); }
.dsn-cc-spend-n { font-size:var(--fs-data); font-variant-numeric:tabular-nums; }
.dsn-cc-meter { height:6px; border-radius:var(--r-pill); background:var(--sunken); overflow:hidden; margin-top:4px; }
.dsn-cc-meter span { display:block; height:100%; background:var(--spend-ink); }
.dsn-ws-live { margin-bottom:var(--sp-4); }
.dsn-id { font-family:var(--mono); font-size:var(--fs-micro); color:var(--text-faint); overflow-wrap:anywhere; }
.dsn-list > .lr-card, .dsn-live-slot > .lr-card { min-height:100%; }

/* ==== almanac.js — search (FS Improvement Notes 2026-09-22) ================ */
.almanac-search { display:flex; flex-wrap:wrap; gap:8px; align-items:center; border-top:1px solid var(--border); }
.almanac-search-box { flex:1 1 280px; display:flex; align-items:center; gap:8px; padding:0 12px; border:1px solid var(--border-strong); border-radius:var(--r-sm); background:var(--surface); color:var(--text-faint); min-width:0; }
.almanac-search-box:focus-within { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-ring); }
.almanac-search-box input { border:0; padding:0; box-shadow:none !important; background:transparent; }
.almanac-results-wrap { border-top:1px solid var(--border); }
.almanac-results-h { font-size:var(--fs-data); font-weight:600; margin-bottom:8px; }
.almanac-hits { display:flex; flex-direction:column; gap:6px; max-height:320px; overflow:auto; }
.almanac-hit { display:flex; flex-direction:column; gap:3px; text-align:left; font:inherit; color:inherit; background:var(--surface); border:1px solid var(--border); border-radius:var(--r-sm); padding:8px 10px; cursor:pointer; min-width:0; overflow-wrap:anywhere; }
.almanac-hit:hover { border-color:var(--border-strong); background:var(--surface-2); }
.almanac-hit-ch { font-size:var(--fs-caption); font-weight:600; color:var(--text-muted); display:flex; gap:6px; align-items:baseline; }
.almanac-hit-snip { font-size:var(--fs-data); color:var(--text); }
.almanac-hit mark, mark.alm-hit { background:var(--warn-soft); color:inherit; border-radius:2px; padding:0 1px; }
mark.alm-hit.current { background:var(--warn); color:var(--surface); box-shadow:0 0 0 2px var(--warn-soft); }
.alm-hit-block { background:var(--warn-soft); box-shadow:0 0 0 2px var(--warn-soft); border-radius:3px; }
.alm-hit-block.current { box-shadow:0 0 0 2px var(--warn); }
.almanac-match-nav { position:sticky; top:var(--topbar-h); z-index:5; display:flex; align-items:center; gap:6px; justify-content:flex-end; font-size:var(--fs-caption); color:var(--text-muted); background:var(--surface); padding:4px 0; margin-bottom:6px; border-bottom:1px solid var(--border); }

/* ==== components/feedbackDropIn.js — the Feedback drop-in ================= */
.fdi > summary { cursor:pointer; list-style:none; }
.fdi-grid { display:grid; grid-template-columns:minmax(0,1.3fr) minmax(0,1fr); gap:0 16px; }
@media (max-width:760px) { .fdi-grid { grid-template-columns:1fr; } }
.fdi-drop { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; min-height:96px; padding:12px; border:1.5px dashed var(--border-strong); border-radius:var(--r-md); color:var(--text-muted); text-align:center; cursor:pointer; background:var(--surface-2); }
.fdi-drop:hover, .fdi-drop.over, .fdi-drop:focus-visible { border-color:var(--accent); background:var(--accent-soft); color:var(--text); }
.fdi-files { list-style:none; margin:6px 0 0; padding:0; display:flex; flex-direction:column; gap:4px; }
.fdi-files li { display:flex; align-items:center; gap:6px; font-size:var(--fs-caption); min-width:0; }
.fdi-fname { overflow-wrap:anywhere; min-width:0; }
.fdi-row { display:flex; flex-wrap:wrap; align-items:flex-end; gap:10px; margin-bottom:8px; }
.fdi-kind { display:flex; flex-direction:column; gap:4px; font-size:var(--fs-caption); font-weight:600; color:var(--text-muted); min-width:200px; }
.fdi-preflight { display:flex; flex-wrap:wrap; align-items:center; gap:6px 10px; }
.fdi-pf-actions { display:inline-flex; gap:8px; }
.fdi-recs-h { font-weight:600; font-size:var(--fs-data); margin:10px 0 6px; }
.fdi-recs { display:grid; grid-template-columns:repeat(auto-fill, minmax(260px, 1fr)); gap:10px; }
.fdi-rec { display:flex; flex-direction:column; gap:6px; padding:10px 12px; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface); min-width:0; overflow-wrap:anywhere; }
.fdi-rec.done { opacity:.75; }
.fdi-rec-h { display:flex; flex-wrap:wrap; gap:6px; align-items:center; }
.fdi-rec-n { font-weight:600; font-size:var(--fs-data); }
.fdi-rec-t, .fdi-rec-src { font-size:var(--fs-caption); color:var(--text-muted); }
.fdi-rec-f { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px; font-size:var(--fs-caption); }
.fdi-rec-f .fdi-k { color:var(--text-faint); }
.fdi-rec-f li.unsure .fdi-v { background:var(--warn-soft); }
.fdi-unsure { font-size:var(--fs-micro); font-weight:600; color:var(--warn-text); text-transform:uppercase; letter-spacing:var(--track-caps); }
.fdi-rec > .btn { align-self:flex-start; margin-top:auto; }
.field.fbk-unsure input, .field.fbk-unsure select, .field.fbk-unsure textarea, .fbk-unsure .chip-group { border-color:var(--warn); box-shadow:0 0 0 3px var(--warn-soft); }
.fbk-unsure-note { margin-top:4px; font-size:var(--fs-caption); color:var(--warn-text); }
.fdi-row .btn { height:38px; }
/* The empty transcript fits its examples inside the chat box (no clipped buttons). */
.dir-chat .rlz-transcript > .empty { padding:20px 16px 32px; }
.dir-chat .rlz-transcript > .empty .empty-ic { width:40px; height:40px; margin-bottom:8px; }
.rec-md { max-height:40vh; overflow:auto; padding:8px 10px; border:1px solid var(--border); border-radius:var(--r-sm); background:var(--surface-2); font-size:var(--fs-data); }
.rec-md h1, .rec-md h2, .rec-md h3 { font-size:var(--fs-data); margin:6px 0 4px; }
.lib-cardview { display:flex; flex-direction:column; gap:14px; margin-bottom:12px; }
.lib-card-group h3 { font-size:var(--fs-data); font-weight:600; margin:0 0 4px; text-transform:none; }

/* ============================================================================
   THEMED CHOICE CONTROLS (captain ask U1, 2026-09-23). Every native radio and
   checkbox in the Interface wears the cockpit's own drawing instead of the
   browser's grey default. :where() keeps these at zero specificity, so a page
   rule that hides a native box behind its own drawing (.dir-scope-input) or
   sizes it still wins. --check is the fill; a control that arms paid work
   sets it to --armed.
   ============================================================================ */
:where(input[type="radio"], input[type="checkbox"]) {
  appearance:none; -webkit-appearance:none; flex:none; display:inline-grid; place-content:center;
  width:16px; height:16px; margin:0; vertical-align:-3px; cursor:pointer;
  border:1.5px solid var(--border-strong); background:var(--surface);
  transition:border-color var(--dur), background var(--dur), box-shadow var(--dur);
}
:where(input[type="radio"]) { border-radius:50%; }
:where(input[type="checkbox"]) { border-radius:4px; }
:where(input[type="radio"])::before { content:""; width:8px; height:8px; border-radius:50%; background:var(--check, var(--accent)); transform:scale(0); transition:transform var(--dur); }
:where(input[type="radio"]:checked) { border-color:var(--check, var(--accent)); }
:where(input[type="radio"]:checked)::before { transform:scale(1); }
:where(input[type="checkbox"])::before { content:""; width:4px; height:8px; margin-top:-2px; border:solid var(--on-accent); border-width:0 2px 2px 0; transform:rotate(45deg) scale(0); transition:transform var(--dur); }
:where(input[type="checkbox"]:checked) { background:var(--check, var(--accent)); border-color:var(--check, var(--accent)); }
:where(input[type="checkbox"]:checked)::before { transform:rotate(45deg) scale(1); }
:where(input[type="radio"], input[type="checkbox"]):hover { border-color:var(--check, var(--accent)); }
:where(input[type="radio"], input[type="checkbox"]):focus-visible { outline:none; box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
:where(input[type="radio"], input[type="checkbox"]):disabled { opacity:.5; cursor:not-allowed; }
/* Option cards: a radio choice drawn as the Director's Thorough/Fast cards. */
.opt-cards { display:grid; grid-template-columns:repeat(2, minmax(0,1fr)); gap:8px; }
.opt-card { display:flex; align-items:flex-start; gap:8px; padding:8px 10px; border:1px solid var(--border); border-radius:var(--r-md); background:var(--surface); cursor:pointer; min-width:0; transition:border-color var(--dur), background var(--dur); }
.opt-card:hover { border-color:var(--border-strong); }
.opt-card:has(input:checked) { border-color:var(--accent); background:var(--accent-soft); }
.opt-card:has(input:focus-visible) { box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
.opt-card:has(input:disabled) { opacity:.6; cursor:not-allowed; }
.opt-card input { margin-top:2px; }
.opt-txt { display:flex; flex-direction:column; gap:1px; min-width:0; overflow-wrap:anywhere; }
.opt-name { font-weight:600; font-size:var(--fs-data); }
.opt-desc { font-size:var(--fs-caption); color:var(--text-muted); }
@media (max-width:520px) { .opt-cards { grid-template-columns:1fr; } }
.dsr-modes .opt-cards, .dsr-efforts .opt-cards { margin-top:2px; }

/* A reading that is prose keeps sentence case (U3: "Needs review", never
   "GATE: NEEDS_REVIEW"). */
.tag.tag-plain { text-transform:none; letter-spacing:normal; font-size:var(--fs-caption); }

/* The Design Suite control center's folds (U2): a header row with its count,
   the list on expand. */
.dsn-live-slot { display:contents; }
.dsn-cc-fold { gap:0; }
.dsn-cc-fold > .dsn-cc-sum { list-style:none; display:flex; align-items:center; gap:6px; cursor:pointer; border-radius:var(--r-sm); min-height:24px; }
.dsn-cc-fold > .dsn-cc-sum::-webkit-details-marker { display:none; }
.dsn-cc-fold > .dsn-cc-sum .ic { margin-left:auto; color:var(--text-faint); transition:transform var(--dur); flex:none; }
.dsn-cc-fold[open] > .dsn-cc-sum .ic { transform:rotate(180deg); }
.dsn-cc-fold > .dsn-cc-sum:hover .dsn-cc-h { color:var(--accent-text); }
.dsn-cc-fold > .dsn-cc-sum:focus-visible { outline:none; box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
.dsn-cc-fold-body { display:flex; flex-direction:column; gap:8px; margin-top:8px; }
#ccPreflight:not(:empty) { margin-top:10px; }

/* U5 / U6 on a dossier card: the retired generator's note, and a remembered
   spec rejection with its paid Retry. */
.dsn-legacy { font-size:var(--fs-caption); color:var(--text-muted); padding:8px 10px; border-radius:var(--r-sm); background:var(--sunken); overflow-wrap:anywhere; }
.dsn-rejection { display:flex; flex-direction:column; align-items:flex-start; gap:6px; padding:8px 10px; border-radius:var(--r-sm); background:var(--danger-soft); color:var(--danger-text); overflow-wrap:anywhere; }
.dsn-rejection-line { display:flex; gap:6px; align-items:flex-start; font-size:var(--fs-caption); font-weight:600; }
.dsn-rejection-line .ic { flex:none; margin-top:2px; }
.dsn-rejection .btn { white-space:normal; height:auto; min-height:32px; text-align:left; }

/* The library's legacy section and its full-artifact expand (U5, review). */
.lib-legacy { margin-top:var(--sp-5); }
.lib-legacy > summary { list-style:none; cursor:pointer; }
.lib-legacy > summary::-webkit-details-marker { display:none; }
.lib-card-legacy { opacity:.92; }
.lib-card-more { font-size:var(--fs-data); font-weight:600; margin:8px 0 0; }
.lib-card-extra > summary { display:flex; align-items:baseline; gap:8px; cursor:pointer; list-style:none; }
.lib-card-extra > summary::-webkit-details-marker { display:none; }
.lib-card-extra > summary h3 { margin:0; }
.lib-card-extra[open] > summary { margin-bottom:4px; }
.lib-long-value > summary { cursor:pointer; color:var(--accent); font-size:var(--fs-caption); }
.lib-long-value[open] > summary { margin-bottom:4px; }
.lib-long-value .v { display:block; white-space:pre-wrap; overflow-wrap:anywhere; }

/* "What changed": the part of an interval counted by whole day is said, not hidden. */
.rlz-brief-partial { color:var(--warn-text); }

/* A history table stacks on a phone (QA D2): each record a block, each cell a
   labelled row, so no status pill is clipped by a squeezed column. */
@media (max-width:640px) {
  .table.table-stack thead { display:none; }
  .table.table-stack, .table.table-stack tbody, .table.table-stack tr, .table.table-stack td { display:block; width:100%; }
  .table.table-stack tr { padding:8px 0; border-bottom:1px solid var(--border); }
  .table.table-stack tbody tr:last-child { border-bottom:0; }
  .table.table-stack tbody td { display:flex; gap:12px; justify-content:space-between; align-items:flex-start; padding:4px 14px; border-bottom:0;
    max-width:none !important; white-space:normal; text-align:right; overflow-wrap:anywhere; }
  .table.table-stack tbody td::before { content:attr(data-label); flex:none; max-width:45%; text-align:left; font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:.06em; color:var(--text-faint); padding-top:2px; }
  .table.table-stack tbody td .badge { white-space:normal; }
  .table.table-stack tbody tr:hover td { background:none; }
}
/* Market Almanac: a chapter's open questions, read as a list (staging round 1). */
.almanac-oq { margin:18px 0; padding-top:12px; border-top:1px solid var(--border); }
.almanac-oq ol { padding-left:20px; display:flex; flex-direction:column; gap:10px; }
.almanac-oq-q { font-weight:600; margin:0 0 4px; }
.almanac-oq p { margin:2px 0; }
.almanac-oq-k { color:var(--text-muted); font-weight:600; }
.almanac-oq-tried { font-size:var(--fs-caption); color:var(--text-muted); overflow-wrap:anywhere; }

/* ==== Site feedback (pages/siteFeedback.js) + the Vault's file control ==== */
/* The drop zone is the Feedback drop-in's own .fdi-drop; these rules only
   size and lay it out. Tokens throughout, so light and dark follow the theme. */
.sfb-grid { display:grid; grid-template-columns:minmax(0,1.4fr) minmax(0,1fr); gap:16px; align-items:start; }
.sfb-drop { min-height:188px; }
.sfb-note { border:1px solid var(--border); border-radius:var(--r-md); padding:12px 14px; background:var(--surface); min-width:0; }
.sfb-notes { display:flex; flex-direction:column; gap:10px; }
.sfb-note-h { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin-bottom:6px; }
.sfb-note-text { white-space:pre-wrap; overflow-wrap:anywhere; margin:0 0 8px; font-size:var(--fs-data); line-height:1.5; }
.sfb-atts { display:flex; flex-wrap:wrap; align-items:flex-start; gap:8px; }
.sfb-thumb { display:block; width:168px; height:104px; border:1px solid var(--border-strong); border-radius:var(--r-sm); overflow:hidden; background:var(--surface-2); }
/* contain, not cover: a wide screenshot shows whole, never cropped to its middle */
.sfb-thumb img { display:block; width:100%; height:100%; object-fit:contain; }
.sfb-file { display:inline-flex; align-items:center; gap:6px; min-width:0; max-width:100%; padding:6px 10px; border:1px solid var(--border-strong); border-radius:var(--r-sm); background:var(--surface-2); color:var(--text); font-size:var(--fs-caption); text-decoration:none; }
.sfb-thumb:hover, .sfb-file:hover, .sfb-thumb:focus-visible, .sfb-file:focus-visible { border-color:var(--accent); }
.sfb-page [data-sfb-error] { opacity:.6; }
.vault-drop { flex-direction:row; flex-wrap:wrap; justify-content:flex-start; gap:6px 12px; min-height:60px; max-width:640px; text-align:left; }
.vault-drop .btn { pointer-events:none; }
.vault-drop-name { color:var(--text); font-weight:600; font-size:var(--fs-data); overflow-wrap:anywhere; min-width:0; }
.vault-drop-name.none { color:var(--text-muted); font-weight:400; }
@media (max-width: 820px) {
  .sfb-grid { grid-template-columns:minmax(0,1fr); }
  .sfb-drop { min-height:120px; }
}

.dir-chat-body > .muted:first-child { display:none; }
.dir-chat-panel > .panel-header { padding-top:6px; padding-bottom:6px; }
.dir-chat-body .rlz-brief { padding:6px 10px; margin-bottom:8px; }
.dir-chat-body .rlz-brief[data-e2e="brief-invite"] { display:flex; align-items:center; gap:10px; }
.dir-chat-body .rlz-brief[data-e2e="brief-invite"] > .rlz-brief-h { display:contents; }
.dir-chat-body .rlz-brief[data-e2e="brief-invite"] > .rlz-brief-h > span[style] { display:none; }
.dir-chat-body .rlz-brief[data-e2e="brief-invite"] > .muted { order:1; flex:1; min-width:0; }
.dir-chat-body .rlz-brief[data-e2e="brief-invite"] .btn { order:2; flex-shrink:0; }
.dir-chat-body .rlz-brief .rlz-brief-t { white-space:nowrap; }
.dir-chat .rlz-transcript { padding:8px max(16px, calc((100% - 860px) / 2)); }
.dir-chat .rlz-msg { flex-direction:column; gap:4px; padding:14px 0; border-bottom:0; }
.dir-chat .rlz-msg-user { width:fit-content; max-width:80%; margin:14px 0 6px auto; padding:10px 14px; border-radius:18px; }
.dir-chat .rlz-msg-user .rlz-who { display:none; }
.dir-chat .rlz-who { flex:none; padding:0; }
.dir-chat .rlz-msg-assistant .rlz-body { max-width:none; font-size:var(--fs-prose); line-height:1.72; }
.dir-chat .rlz-msg-assistant .report-md > p:first-of-type { padding-left:0; border-left:0; font-size:inherit; }
.dir-chat .rlz-body .report-md h2 { padding-bottom:0; border-bottom:0; }
.dir-chat .rlz-body .md-table td, .dir-chat .rlz-body .md-table th { padding:8px 10px; vertical-align:top; white-space:normal; }
.dir-chat .rlz-body .md-table tbody tr:hover td { background:none; }
.dir-page .rlz-judgment { color:inherit; border-bottom:0; }
/* Judgment, estimate and engine marks are lifted; a passage whose source did
   not resolve keeps its visible "(unverified ref)" mark. */
.dir-page .rlz-judgment-tag, .dir-page .rlz-engine-tag { display:none; }
.dir-answer-foot { margin-top:14px; font-size:var(--fs-data); }
.dir-answer-foot .rlz-cites { display:grid; grid-template-columns:repeat(auto-fill, minmax(210px, 1fr)); gap:2px 14px; }
.dir-answer-foot .rlz-cites > .rlz-sources-h, .dir-answer-foot .rlz-source-additional { grid-column:1 / -1; }
.dir-answer-foot .rlz-source { margin:0; }
.dir-answer-tags { display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin:10px 0 6px; }
.dir-answer-tags .rlz-mode { margin:0; }
.dir-web-badge { border-color:var(--accent); color:var(--accent-text); background:var(--accent-soft); }
.dir-input { min-height:64px; padding:12px 14px; font-size:var(--fs-prose); line-height:1.5; border-radius:14px; }
.dir-input-row { align-items:stretch; }
.dir-input-row > .btn { align-self:flex-end; }
.dir-composer-opts { display:flex; flex-wrap:wrap; align-items:stretch; gap:8px; }
.dir-composer-opts > .dir-mode-switch { flex:1 1 360px; margin-top:0; }
.dir-composer-opts .dir-mode-opt { align-items:center; padding:6px 10px; }
.dir-composer-opts .dir-mode-txt { flex-direction:row; flex-wrap:wrap; align-items:baseline; gap:2px 8px; }
.dir-composer-opts .dir-mode-desc { display:none; }
.dir-chat .rlz-body .md-table th:first-child, .dir-chat .rlz-body .md-table td:first-child { min-width:7em; }
.dir-web-switch { display:inline-flex; flex:0 1 auto; padding:3px; border:1px solid var(--border); border-radius:var(--r-pill); background:var(--surface-2); }
.dir-web-opt { position:relative; display:inline-flex; align-items:center; padding:5px 12px; border-radius:var(--r-pill);
  font-size:var(--fs-data); font-weight:600; color:var(--text-muted); cursor:pointer; white-space:nowrap; }
.dir-web-opt input { position:absolute; opacity:0; width:1px; height:1px; }
.dir-web-opt.on, .dir-web-opt:has(input:checked) { background:var(--surface); color:var(--text); box-shadow:0 0 0 1px var(--border-strong); }
.dir-web-opt:has(input:focus-visible) { box-shadow:0 0 0 2px var(--surface), 0 0 0 4px var(--accent-ring); }
@media (max-width:520px) {
  .dir-web-switch { display:flex; width:100%; }
  .dir-web-opt { flex:1; justify-content:center; white-space:normal; text-align:center; }
  .dir-chat .rlz-msg-user { max-width:92%; }
}
@media print { .dir-web-switch { display:none; } }
/* Bigger Director chat. The panel already frames the transcript, so the inner
   box goes; the sources belt rides the composer's option row instead of its
   own; the Conversations list starts folded and, folded, is a tab, not a
   full-height column; the page header drops its subtitle. On a phone the composer stays pinned to the bottom of
   the screen while the transcript takes most of it. */
.dir-chat .rlz-transcript { border:0; border-radius:0; background:none; }
.dir-composer-opts > .dir-controls { flex:1 1 auto; align-self:center; margin:0; padding:0; border:0; }
.dir-composer-opts > .dir-controls[open] { flex-basis:100%; }
.dir-history:not([open]) { align-self:start; height:auto; }
.dir-page > .page-header { margin-bottom:10px; }
.dir-page > .page-header .subtitle { display:none; }
.dir-page > .dir-session-details { margin:0 0 10px; }
@media (max-width: 800px) {
  .dir-chat > .rlz-transcript { min-height:60dvh; }
  .dir-input-row { position:sticky; bottom:0; z-index:2; padding:8px 0; background:var(--surface); }
  .dir-input { max-height:40dvh; }
  .dir-chat-body .rlz-brief[data-e2e="brief-invite"] { flex-wrap:wrap; }
  .dir-chat-body .rlz-brief[data-e2e="brief-invite"] > .muted { flex-basis:100%; }
}
