/* ============================================================================
   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) var(--ease); z-index:40;
}
.sidebar.collapsed { width:var(--sidebar-collapsed); }
.sb-logo { display:flex; align-items:center; gap:10px; padding:0 18px; height:var(--topbar-h); border-bottom:1px solid var(--border); }
.sb-logo .mark { width:30px; height:30px; border-radius:9px; background:linear-gradient(150deg,var(--accent),var(--accent-hover)); display:flex; align-items:center; justify-content:center; color:#fff; flex-shrink:0; box-shadow:var(--shadow-sm); }
.sb-logo .mark svg { width:18px; height:18px; }
.sb-logo .wm { font-weight:600; font-size:15px; letter-spacing:-.02em; white-space:nowrap; }
.sb-logo .wm small { display:block; font-size:var(--fs-micro); font-weight:400; color:var(--text-faint); letter-spacing:0; }
.sidebar.collapsed .wm { display:none; }

.sb-nav { padding:12px 12px; overflow-y:auto; flex:1; }
.nav-section { font-size:var(--fs-micro); font-weight:600; text-transform:uppercase; letter-spacing:.09em; color:var(--text-faint); padding:14px 10px 6px; }
.sidebar.collapsed .nav-section { opacity:0; height:14px; padding:0; }
.nav-item {
  display:flex; align-items:center; gap:11px; padding:8px 10px; border-radius:var(--r-sm); color:var(--text-muted);
  cursor:pointer; margin:1px 0; position:relative; transition:background var(--dur) var(--ease),color var(--dur) var(--ease); white-space:nowrap;
}
.nav-item:hover { background:var(--sunken); color:var(--text); }
.nav-item.active { background:var(--accent-soft); color:var(--accent-text); font-weight:600; }
.nav-item.active::before { content:""; position:absolute; left:-12px; top:50%; transform:translateY(-50%); width:3px; height:18px; border-radius:0 3px 3px 0; background:var(--accent); }
.nav-item .nav-ic { width:18px; height:18px; flex-shrink:0; }
.nav-item .nav-txt { flex:1; font-size:var(--fs-ui); overflow:hidden; text-overflow:ellipsis; }
.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); }
.sidebar.collapsed .nav-txt, .sidebar.collapsed .nav-badge { display:none; }
.sidebar.collapsed .nav-item { justify-content:center; padding:9px; }
.sidebar.collapsed .nav-item.active::before { left:0; }

.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; }
.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); }
.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 ============================ */
.tabs { display:flex; gap:2px; border-bottom:1px solid var(--border); margin-bottom:18px; }
.tab { padding:10px 16px; font-size:var(--fs-ui); font-weight:600; color:var(--text-muted); border-bottom:2px solid transparent; margin-bottom:-1px; cursor:pointer; transition:var(--dur); }
.tab:hover { color:var(--text); }
.tab.active { color:var(--accent-text); border-bottom-color:var(--accent); }
.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; }
input[type=text],input[type=number],input[type=date],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); }
.dialog-header h3 { font-size:var(--fs-prose); font-weight:600; flex:1; }
.dialog-body { padding:20px; overflow-y:auto; }

/* 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); }

/* ============================ Funnel rows (page) ============================ */
.funnel-list { display:flex; flex-direction:column; }
.frow { display:grid; grid-template-columns:30px 1fr auto; align-items:center; gap:14px; padding:12px 0; border-bottom:1px solid var(--border); }
.frow:last-child { border-bottom:0; }
.frow .fnum { width:26px; height:26px; border-radius:7px; background:var(--accent-soft); color:var(--accent-text); display:flex; align-items:center; justify-content:center; font-size:var(--fs-caption); font-weight:600; }
.frow .fmid .fname { font-weight:600; font-size:var(--fs-ui); }
.frow .fmid .fsub { font-size:var(--fs-caption); color:var(--text-faint); }
.frow .fmid .ftrack { height:6px; background:var(--sunken); border-radius:99px; overflow:hidden; margin-top:6px; max-width:520px; }
.frow .fmid .ffill { height:100%; background:var(--accent); border-radius:99px; }
.frow .fright { display:flex; align-items:center; gap:12px; }
.frow .fcount { font-size:var(--fs-title); font-weight:600; font-variant-numeric:tabular-nums; min-width:48px; text-align:right; }

/* ============================ 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 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; }

/* 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); }
.kv:last-child{ border-bottom:0; }
.kv .k { color:var(--text-faint); min-width:130px; }
.kv .v { color:var(--text); flex:1; }
.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) var(--ease); }
  .sidebar.open { left:0; box-shadow:var(--shadow-lg); }
  .hamburger { display:inline-flex; }
  .cmdk-trigger .cmdk-label { display:none; }
}

/* 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:64px; 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; }

/* ---- 分析台 + 预测记录 (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 { border-bottom:0; 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 td { font-size:var(--fs-data); }
.vault-table .vault-path { word-break:break-all; max-width:280px; }
.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; }
.vault-upload-file input[type=file] { font-size:var(--fs-data); color:var(--text-muted); }
.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); }
/* §J's judgment convention, identical to the Director's and the almanac's:
   inference is set off in --purple so a reader can never mistake it for a
   cited fact. */
.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; }

/* ==== app.js SHELL_CSS ==== */
/* SIDEBAR — the navigation goes quiet. The active item is INK, not a green
   fill block: the one working accent is spent on actions, and a filled row for
   "you are here" was the loudest object on every screen. */
/* SPECIFICITY, NOT ORDER (lane:hygiene). These two rules used to win because
   app.js injected them into <head> AFTER styles.css loaded; inside one
   stylesheet that guarantee is gone, so the `.sidebar` ancestor is added to
   out-specify the base `.nav-item.active` rules in the App shell section
   above (0,3,0 beats 0,2,0). Match set is unchanged: `.nav-item` is emitted
   only by renderSidebar(), inside `.sidebar`. Declarations are byte-identical.
   `.sidebar.collapsed .nav-item.active::before { left:0; }` is NOT repeated
   here — it is literally the App shell section's own rule. */
.sidebar .nav-item.active { background:transparent; color:var(--ink); font-weight:600; }
.sidebar .nav-item.active::before { left:0; width:2px; height:20px; border-radius:0; background:var(--ink); }
.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. */
@media (max-width: 1520px) { .chain-rail .cr-step:not(.current) .cr-txt { display:none; } }
.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; }
/* STANDING TYPE Wave 3 (§3.4) — judgment colour UNIFIED: repointed --info →
   --purple so the app ships ONE judgment colour (.vault-judgment, the Director,
   the almanac and this chip now agree). PRINT_CSS repoints the same three. */
.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; }
/* 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-withheld { font-family:var(--font); color:var(--danger-text); font-style:italic; }

/* ============================================================
   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); }

/* ============================================================
   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); }
}

/* ==== 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); }
.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; }

/* 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-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 { font-family:var(--font-serif); font-size:var(--fs-data); color:var(--ink); 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-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; max-height:56vh; overflow:auto; border:1px solid var(--border);
  border-radius:var(--r-md); background:var(--surface-2); padding:4px 12px; }
.rlz-msg { display:flex; gap:12px; padding:10px 0; border-bottom:1px solid var(--border); }
.rlz-msg:last-child { border-bottom:0; }
.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-data); color:var(--text); overflow-wrap:anywhere; }
.rlz-body .report-md > :first-child { margin-top:0; }
.rlz-body .report-md p { margin:0 0 6px; }
.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-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); }
/* §J — the D12 judgment convention, in the app's ONE inference colour
   (--purple, shared with .vault-judgment and the almanac). COLOUR IS THE
   SECOND CHANNEL, never the only one: the dotted underline carries the
   distinction in greyscale and in print, and the tag carries it in words for
   a screen reader. A reader must never mistake an inference for a cited fact. */
.rlz-judgment { color:var(--purple-text); border-bottom:1px dotted var(--purple); }
.rlz-judgment-tag { display:inline-block; margin-right:5px; padding:0 5px; font-size:var(--fs-micro);
  font-weight:600; letter-spacing:var(--track-caps); text-transform:uppercase; vertical-align:1px;
  border:1px solid var(--purple); border-radius:var(--r-pill);
  color:var(--purple-text); background:var(--purple-soft); }
:lang(zh-CN) .rlz-judgment-tag { text-transform:none; letter-spacing:.02em; }
/* 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); }
.rlz-cites { display:flex; flex-wrap:wrap; gap:6px; 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; }
/* 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; }
.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 - depth, scope, and the ceiling read BEFORE the
   send. Native <select> and native checkboxes: nothing here needs a widget,
   and a custom one would be a second keyboard and screen-reader contract to
   maintain. No new colour - the ceiling is .spend (the copper --spend-ink the
   armed strip and every other money figure already use), the labels are the
   same uppercase micro-caps key as .rlz-armed-k. */
.dir-controls { display:flex; align-items:center; flex-wrap:wrap; gap:var(--sp-2) var(--sp-3);
  margin-top:var(--sp-3); padding-top:var(--sp-3); border-top:1px solid var(--border);
  font-size:var(--fs-caption); }
.dir-ctl-k { font:600 var(--fs-micro)/1.4 var(--font); letter-spacing:var(--track-caps);
  text-transform:uppercase; color:var(--ink-faint); }
.dir-depth { font:inherit; padding:4px 8px; border:1px solid var(--border-strong);
  border-radius:var(--r-sm); background:var(--surface); color:var(--ink); }
.dir-depth:focus-visible { outline:2px solid var(--armed-ring); outline-offset:2px; }
/* 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 { display:inline-flex; align-items:center; gap:5px; color:var(--text-muted); cursor:pointer; }
.dir-scope input { accent-color:var(--spend-ink); margin:0; }
.dir-scope input:focus-visible { outline:2px solid var(--armed-ring); outline-offset:2px; }
/* 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); }

.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; }
.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; }
.pipeline-readiness { border-left: 4px solid var(--accent); }
.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; }
}
