/* ==========================================================================
   Outpush Trading Desk — design system
   --------------------------------------------------------------------------
   INSTITUTIONAL RE-THEME. The identity is money green; the discipline is that
   green is CHROME and nothing else.

   THE COLLISION, AND HOW IT IS RESOLVED
   Making the brand green would make "green" mean two things at once — house
   identity and profit — and the reader has no way to tell which one a green
   thing is. So the three colour families are separated by JOB and kept apart
   by measurement, not by taste:

     1. BRAND  (--brand*)  chrome only: nav, brand mark, primary button, focus,
        active state, the login card. It NEVER touches a data mark. Deep and
        low-chroma on purpose — BNY-Mellon restraint, not fintech neon.
     2. P&L POLARITY (--up / --down)  a validated DIVERGING PAIR: BLUE gains ↔
        RED losses. Green had to give up P&L when the brand took it; blue is
        the house diverging pole (see the dataviz standard) and — unlike
        green↔red — it survives protanopia and deuteranopia. Sign is ALSO
        carried by the +/− on the number and by bar direction from a zero
        baseline, so polarity never rests on hue alone.
     3. STATUS (--st-*)  the reserved good/warning/serious/critical scale.
        Fixed hexes, never themed, always shipped with a written label.

   THE RULE THAT MAKES CHROME UNMISTAKABLE: brand green lives OUTSIDE the
   lightness band that data marks are allowed to occupy. Light theme brand ink
   sits at OKLCH L 0.387, below the light mark band (0.43–0.77); dark theme
   brand tint sits at L 0.767, above the dark mark band (0.48–0.67). A mark is
   never that dark and never that pale, so "is this chrome or data?" is
   answered by value before hue is even considered.

   MEASURED (OKLab ΔE ×100, min of protan/deutan for CVD; floor 15 normal):
     brand fill ↔ P&L positive   18.2 light / 25.3 dark   (17.7 / 24.0 CVD)
     brand fill ↔ status good    27.6 light / 20.1 dark
     brand tint ↔ series aqua    29.1 light / 17.3 dark
     P&L positive ↔ negative     26.9 light / 27.7 dark   (21.6 / 19.4 CVD)
   Full validator output lives in the session report; re-run before changing a
   hex:  node validate_palette.js "<hexes>" --mode light --surface "#FFFFFF"
   ========================================================================== */

:root {
  /* ── Neutrals — dark ─────────────────────────────────────────
     Graphite with a whisper of green, not the old blue navy: the page plane
     should read as stone under the brand, never as a second accent. */
  --bg:          #0A0E0D;
  --bg-elev:     #0E1413;
  --surface:     #121817;   /* card surface — the validator's dark surface */
  --surface-2:   #171E1C;
  --surface-3:   #1E2624;
  --line:        rgba(159,187,174,.13);
  --line-strong: rgba(159,187,174,.24);

  /* Ink — every step clears WCAG AA as text on --surface
     (15.3 : 1, 7.9 : 1, 4.9 : 1). */
  --ink:      #E9EEEB;
  --ink-2:    #A3AFAA;
  --ink-3:    #7C8884;

  /* ── Brand — CHROME ONLY. Never on a data mark. ──────────────
     --brand      the fill (nav rail, brand mark, primary button)
     --brand-2    the deeper step the fill settles into
     --brand-ink  the ink that sits ON a brand fill
     --brand-tint the readable brand green for TEXT and hairlines */
  --brand:      #1F7458;   /* 3.16:1 on --surface, 5.68:1 under white ink */
  --brand-2:    #14503C;
  --brand-ink:  #F2F7F4;
  --brand-tint: #9FBBAE;   /* 8.7:1 on --surface; L 0.767, above the mark band */
  --brand-sf:   rgba(31,116,88,.16);
  --brand-ring: rgba(159,187,174,.30);

  /* The one signature treatment. Deliberately nearly flat — an institution
     does not glow. Kept as a gradient token so every existing caller works. */
  --grad-accent: linear-gradient(160deg, var(--brand), var(--brand-2));

  /* Legacy aliases. Everything that used to say "accent" meant "brand
     chrome", and still does. New code should say --brand*. */
  --accent:     var(--brand-tint);
  --accent-2:   var(--brand-2);
  --accent-sf:  var(--brand-sf);
  --accent-ink: var(--brand-ink);

  /* ── P&L polarity — the diverging pair ───────────────────────
     Gains BLUE, losses RED. Distinct from brand green at a glance and under
     CVD; both steps clear 4.5:1 on --surface because they are set as TEXT far
     more often than they are drawn as marks. */
  --up:        #4A93EA;
  --up-sf:     rgba(74,147,234,.14);
  --up-ring:   rgba(74,147,234,.32);
  --down:      #E66767;
  --down-sf:   rgba(230,103,103,.14);
  --down-ring: rgba(230,103,103,.32);
  --flat:      #7C8884;

  /* ── Status — reserved. Marks are FIXED in both themes. ──────
     A status colour never stands in for a series and never carries meaning
     without a written label beside it. The -tx steps are the themed variants
     used when the status has to be legible as TEXT. */
  --st-good:      #0ca30c;
  --st-warning:   #fab219;
  --st-serious:   #ec835a;
  --st-critical:  #d03b3b;
  --st-good-tx:   #0ca30c;   /* 5.4:1 on --surface */
  --st-warn-tx:   #fab219;   /* 9.8:1 */
  --st-bad-tx:    #E85D5D;   /* 5.3:1 */
  --st-good-sf:   rgba(12,163,12,.13);
  --st-good-ring: rgba(12,163,12,.30);
  --st-warn-sf:   rgba(250,178,25,.13);
  --st-warn-ring: rgba(250,178,25,.28);
  --st-bad-sf:    rgba(232,93,93,.13);
  --st-bad-ring:  rgba(232,93,93,.30);

  /* Legacy status aliases (desk.js writes var(--warn) inline). */
  --warn:    var(--st-warn-tx);
  --warn-sf: var(--st-warn-sf);
  --ok:      var(--st-good-tx);
  --bad:     var(--st-bad-tx);

  /* ── Stat-tile pips — HUELESS BY DESIGN ──────────────────────
     A pip beside a tile label encodes nothing; it used to spend four hues on
     decoration. Colour on this desk now appears only where it MEANS something
     (polarity, status), so the decorative slots are ink. A tile whose subject
     really is polarity or status still passes --up/--down/--warn instead. */
  --pip-1: var(--ink-3);
  --pip-2: var(--ink-3);
  --pip-3: var(--ink-3);
  --pip-4: var(--ink-3);
  /* Deprecated hue-named aliases kept so older call sites keep rendering. */
  --gold:   var(--pip-2);
  --teal:   var(--pip-3);
  --violet: var(--pip-4);

  /* ── Type ────────────────────────────────────────────────────
     One sans, a real scale, and restrained weights: 400/500/600, 700 only for
     a page title. Institutional pages are set, not styled. */
  --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;

  --fs-eyebrow: 10.5px;   /* uppercase section labels */
  --fs-cap:     11.5px;   /* captions, foot notes */
  --fs-sm:      12.5px;
  --fs-body:    13.5px;
  --fs-lead:    15px;     /* card titles */
  --fs-title:   20px;     /* view titles */
  --fs-figure:  26px;     /* stat values */
  --fs-hero:    32px;     /* the one big number on a report */

  --w-reg:  400;
  --w-med:  500;
  --w-semi: 600;
  --w-bold: 700;
  --track-eyebrow: .13em;

  /* ── Space + shape ───────────────────────────────────────────
     Tight radii and hairlines. Rounded pills read consumer; a ledger does not
     have rounded corners. */
  --r-sm: 4px;
  --r:    6px;
  --r-lg: 8px;
  --sidebar-w: 244px;
  --topbar-h:  58px;

  /* Elevation is carried by the hairline, not by a drop shadow. */
  --shadow-1: 0 1px 1px rgba(0,0,0,.22);
  --shadow-2: 0 4px 16px -8px rgba(0,0,0,.50);
  --shadow-3: 0 14px 36px -14px rgba(0,0,0,.60);
}

:root[data-theme="light"] {
  /* Paper, not a blue-white screen. */
  --bg:          #F3F5F3;
  --bg-elev:     #FFFFFF;
  --surface:     #FFFFFF;   /* card surface — the validator's light surface */
  --surface-2:   #F1F4F2;
  --surface-3:   #E7ECE9;
  --line:        rgba(16,26,22,.10);
  --line-strong: rgba(16,26,22,.18);

  --ink:      #101A16;   /* 17.8:1 */
  --ink-2:    #45524D;   /*  8.2:1 */
  --ink-3:    #67736F;   /*  4.9:1 — was 3.7:1, under AA */

  --brand:      #14503C;   /* 9.4:1 under white ink; L 0.387, below the mark band */
  --brand-2:    #0F4433;
  --brand-ink:  #F5F9F7;
  --brand-tint: #14503C;
  --brand-sf:   rgba(20,80,60,.09);
  --brand-ring: rgba(20,80,60,.24);

  --up:        #1C5CAB;   /* 6.6:1 */
  --up-sf:     rgba(28,92,171,.10);
  --up-ring:   rgba(28,92,171,.26);
  --down:      #9E2A24;   /* 7.5:1 */
  --down-sf:   rgba(158,42,36,.10);
  --down-ring: rgba(158,42,36,.26);
  --flat:      #67736F;

  /* Status marks stay fixed; only the TEXT steps re-step for paper, where
     #0ca30c (3.4:1) and #fab219 (1.8:1) are not legible as type. */
  --st-good-tx:   #0a7a0a;   /* 5.5:1 */
  --st-warn-tx:   #96650F;   /* 5.0:1 */
  --st-bad-tx:    #B22F2F;   /* 6.3:1 */
  --st-good-sf:   rgba(10,122,10,.10);
  --st-good-ring: rgba(10,122,10,.26);
  --st-warn-sf:   rgba(150,101,15,.11);
  --st-warn-ring: rgba(150,101,15,.26);
  --st-bad-sf:    rgba(178,47,47,.10);
  --st-bad-ring:  rgba(178,47,47,.26);

  --shadow-1: 0 1px 1px rgba(16,26,22,.05);
  --shadow-2: 0 4px 14px -8px rgba(16,26,22,.14);
  --shadow-3: 0 14px 32px -14px rgba(16,26,22,.18);
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: var(--w-reg);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; }

/* Every figure on the desk lines up. Applied at the top so a new component
   inherits it instead of remembering to ask — money that wobbles between rows
   is the fastest way to look amateur. Prose keeps proportional figures. */
.stat .v, .chip, .badge, .delta, .meter, table, .ticket .facts,
.charcount, .tagchip, .seg, .nav-item .tag, .ch-hero .v, .ch-hero .s,
pre.log, .mono { font-variant-numeric: tabular-nums; }

::selection { background: var(--brand-sf); }

/* Scrollbars — thin, unobtrusive */
* { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 99px; border: 3px solid transparent; background-clip: content-box; }
*::-webkit-scrollbar-track { background: transparent; }

/* ── App shell ─────────────────────────────────────────────── */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  min-height: 100vh;
}

/* Sidebar */

.sidebar {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 12px;
  background: var(--bg-elev);
  border-right: 1px solid var(--line);
  overflow-y: auto;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 16px;
}

.brand .mark {
  width: 32px; height: 32px;
  flex: none;
  border-radius: var(--r-sm);
  background: var(--grad-accent);
  display: grid; place-items: center;
  color: var(--brand-ink);
  font-weight: var(--w-semi);
  font-size: 15px;
}

.brand .name { font-weight: var(--w-semi); letter-spacing: -.005em; line-height: 1.2; }
.brand .sub  { font-size: 11px; color: var(--ink-3); font-weight: var(--w-reg); }

.nav-group { margin-top: 18px; }

.nav-label {
  padding: 0 10px 7px;
  font-size: var(--fs-eyebrow);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-3);
}

.nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  color: var(--ink-2);
  font-weight: var(--w-med);
  cursor: pointer;
  border: 1px solid transparent;
  transition: background .12s ease, color .12s ease;
}

.nav-item:hover { background: var(--surface-2); color: var(--ink); }

.nav-item.active {
  background: linear-gradient(90deg, var(--brand-sf), transparent 78%);
  color: var(--ink);
  border-color: var(--brand-ring);
  font-weight: var(--w-semi);
}

/* Brand chrome, as a hairline bar on the active tab. */
.nav-item.active::before {
  content: '';
  position: absolute;
  left: -1px; top: 6px; bottom: 6px;
  width: 2px;
  background: var(--brand-tint);
}

.nav-item .ico { width: 17px; text-align: center; flex: none; opacity: .8; font-size: 13px; }

.nav-item .tag {
  margin-left: auto;
  font-size: var(--fs-eyebrow);
  font-weight: var(--w-semi);
  padding: 1px 6px;
  border-radius: 3px;
  background: var(--surface-3);
  color: var(--ink-2);
}

.nav-item.active .tag { background: var(--brand-sf); color: var(--brand-tint); }

.sidebar-foot {
  margin-top: auto;
  padding: 12px 6px 4px;
  border-top: 1px solid var(--line);
  font-size: 11.5px;
  color: var(--ink-3);
}

/* Compact signed-in-as chip: avatar, name + role, sign out. */
.user-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 8px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--line);
}

.user-chip .avatar {
  width: 28px; height: 28px;
  flex: none;
  border-radius: var(--r-sm);
  background: var(--grad-accent);
  color: var(--brand-ink);
  font-weight: var(--w-semi);
  font-size: 12.5px;
  display: grid; place-items: center;
}

.user-chip .who { min-width: 0; flex: 1; line-height: 1.25; }
.user-chip .u {
  font-size: var(--fs-sm); font-weight: var(--w-semi); color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-chip .r {
  font-size: var(--fs-eyebrow); font-weight: var(--w-semi);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase; color: var(--ink-3);
}
.user-chip form { margin: 0; flex: none; }
.user-chip .btn.icon { width: 28px; height: 28px; font-size: 13px; }

.foot-note { margin-top: 9px; padding: 0 4px; line-height: 1.5; }
.foot-note b { color: var(--ink-2); }

/* Topbar */

.main { min-width: 0; display: flex; flex-direction: column; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 0 22px;
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}

.topbar h1 { margin: 0; font-size: var(--fs-lead); font-weight: var(--w-semi); letter-spacing: -.008em; }
.topbar .spacer { flex: 1; }

.status-strip { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 26px;
  padding: 0 9px;
  border-radius: var(--r-sm);
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 12px;
  font-weight: var(--w-med);
  color: var(--ink-2);
  white-space: nowrap;
}

.chip b { color: var(--ink); font-weight: var(--w-semi); }

/* Health dots are STATUS, not P&L — they wear the reserved scale and always
   sit beside a written label. */
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--flat); flex: none; }
.dot.ok   { background: var(--st-good);     box-shadow: 0 0 0 3px var(--st-good-sf); }
.dot.warn { background: var(--st-warning);  box-shadow: 0 0 0 3px var(--st-warn-sf); }
.dot.bad  { background: var(--st-critical); box-shadow: 0 0 0 3px var(--st-bad-sf); }
.dot.live { animation: pulse 3.2s infinite; }

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 var(--st-good-sf); }
  70%  { box-shadow: 0 0 0 6px rgba(12,163,12,0); }
  100% { box-shadow: 0 0 0 0 rgba(12,163,12,0); }
}

/* Content */

.content { padding: 26px 28px 40px; max-width: 1440px; width: 100%; }

.view { display: none; }
.view.active { display: block; animation: fade .18s ease; }

@keyframes fade { from { opacity: 0; transform: translateY(3px); } to { opacity: 1; transform: none; } }

/* Every view opens with its name and one line saying what it is FOR. */
.view-head { margin: 2px 0 20px; }

.view-head h1 {
  margin: 0;
  font-size: var(--fs-title);
  font-weight: var(--w-bold);
  letter-spacing: -.015em;
  line-height: 1.25;
}

.view-head p {
  margin: 6px 0 0;
  font-size: var(--fs-body);
  color: var(--ink-3);
  max-width: 74ch;
  line-height: 1.6;
}

.row {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 14px;
}

.row h2 {
  margin: 0;
  font-size: var(--fs-eyebrow);
  font-weight: var(--w-semi);
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--ink-3);
}

.row .spacer { flex: 1; }

/* ── Onboarding strip (Overview, until dismissed) ──────────── */

.onboard {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 13px 16px;
  margin: 0 0 18px;
  border-radius: var(--r);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-1);
}

.onboard::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--grad-accent);
}

.ob-title { font-size: 13px; font-weight: 650; white-space: nowrap; }

.ob-steps { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; flex: 1; }

.ob-step {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
}

.ob-step b {
  width: 20px; height: 20px;
  flex: none;
  border-radius: 50%;
  background: var(--grad-accent);
  color: var(--accent-ink);
  font-size: 11px;
  font-weight: 800;
  display: grid; place-items: center;
}

.ob-step span { color: var(--accent); font-weight: 650; }

a.ob-step { cursor: pointer; }
a.ob-step:hover { color: var(--ink); }

/* ── Buttons ───────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  height: 32px;
  padding: 0 13px;
  border-radius: var(--r-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 13px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s ease, border-color .12s ease, transform .06s ease;
}

.btn:hover  { background: var(--surface-2); border-color: var(--ink-3); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; transform: none; }

.btn.primary {
  background: var(--grad-accent);
  border-color: transparent;
  color: var(--accent-ink);
  font-weight: 650;
}
.btn.primary:hover { filter: brightness(1.07); }

.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn.ghost:hover { background: var(--surface-2); color: var(--ink); }

.btn.sm { height: 27px; padding: 0 10px; font-size: 12px; }
.btn.icon { width: 32px; padding: 0; }

/* ── Cards ─────────────────────────────────────────────────── */

.grid { display: grid; gap: 14px; }
.grid.k2 { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.grid.k3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid.k4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
  box-shadow: var(--shadow-1);
}

.card.pad { padding: 16px 18px; }

.card-h {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line);
}

.card-h h3 { margin: 0; font-size: 13.5px; font-weight: 650; }
.card-h .spacer { flex: 1; }
.card-h .hint { font-size: 12px; color: var(--ink-3); }

.card-b { padding: 16px 18px; }
.card-b.flush { padding: 0; }

/* Stat tile */

.stat .k {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  font-weight: 550;
  color: var(--ink-2);
}

.stat .k .pip { width: 8px; height: 8px; border-radius: 2.5px; flex: none; }

.stat .v {
  margin-top: 9px;
  font-size: 27px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
}

.stat .s {
  margin-top: 7px;
  font-size: 12px;
  color: var(--ink-3);
  display: flex;
  align-items: center;
  gap: 6px;
}

.stat .s b { font-weight: 650; font-variant-numeric: tabular-nums; }

.delta { font-weight: 650; font-variant-numeric: tabular-nums; }
.delta.up   { color: var(--up); }
.delta.down { color: var(--down); }
.delta.flat { color: var(--flat); }

/* ── Tables ────────────────────────────────────────────────── */

.t-wrap { overflow-x: auto; }

/* Numerals line up everywhere by default — money tables must never wobble. */
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

th, td {
  text-align: left;
  padding: 10px 18px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

thead th {
  position: sticky;
  top: 0;
  background: var(--surface);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
  z-index: 1;
}

tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: var(--surface-2); }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
td.sym { font-weight: 650; letter-spacing: -.01em; }
td.mono, .mono { font-family: var(--mono); font-size: 12px; }

/* ── Badges + pills ────────────────────────────────────────── */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 8px;
  border-radius: 6px;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: .01em;
  border: 1px solid transparent;
}

.badge.buy    { background: var(--up-sf);     color: var(--up);     border-color: rgba(61,220,151,.24); }
.badge.sell   { background: var(--down-sf);   color: var(--down);   border-color: rgba(255,107,107,.24); }
.badge.hold   { background: var(--surface-3); color: var(--ink-2); }
.badge.paper  { background: var(--accent-sf); color: var(--accent); border-color: rgba(255,107,44,.26); }
.badge.live   { background: var(--down-sf);   color: var(--down);   border-color: rgba(255,107,107,.30); }
.badge.warn   { background: var(--warn-sf);   color: var(--warn);   border-color: rgba(245,166,35,.26); }
.badge.ok     { background: var(--up-sf);     color: var(--up);     border-color: rgba(61,220,151,.24); }
.badge.muted  { background: var(--surface-3); color: var(--ink-3); }
.badge.info   { background: rgba(139,124,246,.13); color: var(--violet); border-color: rgba(139,124,246,.26); }

/* Conviction meter */

.meter { display: inline-flex; gap: 2.5px; vertical-align: middle; }
.meter i {
  width: 5px; height: 13px;
  border-radius: 1.5px;
  background: var(--surface-3);
  display: block;
}
.meter i.on { background: var(--accent); }
.meter.up i.on   { background: var(--up); }
.meter.down i.on { background: var(--down); }

/* ── Empty / loading ───────────────────────────────────────── */

.empty {
  padding: 36px 22px;
  text-align: center;
  color: var(--ink-3);
}

.empty .big {
  width: 44px; height: 44px;
  margin: 0 auto 10px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--line);
  display: grid; place-items: center;
  font-size: 19px;
  opacity: .85;
}

.empty p { margin: 0 0 4px; font-size: 13px; color: var(--ink-2); font-weight: 550; }
.empty .why { font-size: 12px; color: var(--ink-3); max-width: 52ch; margin: 0 auto; line-height: 1.55; }

.skel {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.3s ease infinite;
  border-radius: 5px;
  height: 11px;
}

@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* ── Sparkline / chart holder ──────────────────────────────── */

.spark { display: block; width: 100%; height: 44px; overflow: visible; }
.chart { display: block; width: 100%; height: 220px; overflow: visible; }

.axis-lbl { font-size: 10px; fill: var(--ink-3); font-family: var(--font); }

/* ── Ticket (proposed trade) ───────────────────────────────── */

.ticket {
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  background: var(--surface);
  padding: 14px 16px;
  display: grid;
  gap: 10px;
}

.ticket.buy  { border-left: 3px solid var(--up); }
.ticket.sell { border-left: 3px solid var(--down); }

.ticket .th { display: flex; align-items: center; gap: 9px; }
.ticket .th .s { font-size: 16px; font-weight: 750; letter-spacing: -.02em; }
.ticket .th .spacer { flex: 1; }

.ticket .facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 10px 14px;
  padding: 10px 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.ticket .facts div span { display: block; font-size: 10.5px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-3); font-weight: 650; }
.ticket .facts div b { font-size: 14px; font-weight: 650; font-variant-numeric: tabular-nums; }

.ticket .why { font-size: 12.5px; color: var(--ink-2); line-height: 1.55; }
.ticket .acts { display: flex; gap: 8px; }

/* Stale-data banner — these panels read files that stopped updating
   months ago, and the UI should say so rather than look current. */

.stale {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 10px 14px;
  margin-bottom: 14px;
  border-radius: var(--r-sm);
  background: var(--warn-sf);
  border: 1px solid rgba(245,166,35,.26);
  font-size: 12.5px;
  color: var(--ink-2);
}

.stale b { color: var(--warn); }

/* Red variant — the worker heartbeat is stale, which is an incident,
   not just old data. */
.stale.red {
  background: var(--down-sf);
  border-color: rgba(255,107,107,.32);
}

.stale.red b { color: var(--down); }

/* ── Publish (cross-posting engine) ────────────────────────── */

/* Compose-form fields — shared by the listing and social composers. */
.f-label {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
  font-weight: 650;
}

.f-input {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 11px;
  color: var(--ink);
  font-family: inherit;
  font-size: 13.5px;
  text-transform: none;
  letter-spacing: 0;
  resize: vertical;
}

/* One package field with its copy button. */
.copyrow {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px dashed var(--line);
}

.copyrow:last-child { border-bottom: none; }

.copyrow .lbl {
  flex: none;
  width: 92px;
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
  font-weight: 650;
  padding-top: 2px;
}

.copyrow .val {
  flex: 1;
  min-width: 0;
  font-size: 13px;
  white-space: pre-wrap;
  word-break: break-word;
}

.charcount { font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.charcount.over { color: var(--down); font-weight: 700; }

.tagchip {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  margin: 2px 3px 2px 0;
  border-radius: 99px;
  background: var(--surface-3);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 550;
}

.photo-thumbs { display: flex; flex-wrap: wrap; gap: 8px; }

.photo-thumbs img {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--surface-2);
}

/* The per-venue package/variant cards — the centerpiece of Publish.
   Every card leads with the venue name + state; the gradient hairline
   marks them as product, not just another data panel. */
.venue-card {
  position: relative;
  overflow: hidden;
  border-color: var(--line-strong);
}

.venue-card::before {
  content: '';
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: 2px;
  background: var(--grad-accent);
  opacity: .85;
}

.venue-name {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -.015em;
}

/* Copy-button confirmation state ("Copied ✓"). */
.btn.copied {
  color: var(--up);
  border-color: rgba(61,220,151,.42);
  background: var(--up-sf);
}

/* Venue/platform picker rows in the composers. */
.pickrow {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  cursor: pointer;
  font-size: 13px;
}

.pickrow:hover { background: var(--surface-2); }
.pickrow input { accent-color: var(--accent); }
.pickrow .spacer { flex: 1; }

/* The sold → delist-everywhere checklist. Loud on purpose. */
.delist-banner {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 13px 16px;
  margin-bottom: 12px;
  border-radius: var(--r-sm);
  background: var(--down-sf);
  border: 1px solid rgba(255,107,107,.40);
  border-left: 3px solid var(--down);
  font-size: 13.5px;
  box-shadow: var(--shadow-1);
}

.delist-banner b { color: var(--down); }
.delist-banner > span:first-child { font-size: 17px; line-height: 1; }

/* ── Log / pre ─────────────────────────────────────────────── */

pre.log {
  margin: 0;
  padding: 14px 18px;
  background: var(--bg);
  border-radius: var(--r-sm);
  font-family: var(--mono);
  font-size: 11.5px;
  line-height: 1.65;
  color: var(--ink-2);
  max-height: 340px;
  overflow: auto;
  white-space: pre-wrap;
  word-break: break-word;
}

/* ── Toast ─────────────────────────────────────────────────── */

.toasts {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 9px;
  max-width: 380px;
}

.toast {
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-sm);
  padding: 11px 14px;
  font-size: 13px;
  box-shadow: var(--shadow-3);
  animation: rise .18s ease;
}

.toast.ok  { border-left-color: var(--up); }
.toast.bad { border-left-color: var(--down); }

@keyframes rise { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ── Responsive ────────────────────────────────────────────── */

@media (max-width: 900px) {
  .app { grid-template-columns: 1fr; }
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--sidebar-w);
    z-index: 50;
    transform: translateX(-100%);
    transition: transform .2s ease;
    box-shadow: var(--shadow-3);
  }
  .sidebar.open { transform: none; }
  .content { padding: 16px; }
  .topbar { padding: 0 14px; }
  th, td { padding: 9px 13px; }
}

@media (min-width: 901px) { .menu-btn { display: none; } }

/* ── Motion accessibility ──────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}


/* ==========================================================================
   SIGNATURE LAYER — "scribe ledger"                       (self-contained)
   --------------------------------------------------------------------------
   Everything below is the polish pass: cursor-aware ink on cards, the ruled-
   paper hairline motif, entrance motion, and the ambient ink strip drawn into
   the topbar by static/ambient.js.

   Rules this block keeps to itself:
     · it only ADDS — no existing selector above is redefined except
       `.view.active` (easing) and `.view-head` (spacing for its rule);
     · every new token is prefixed --pp-* so it cannot collide;
     · every new class is prefixed .pp-* or is a state class (.is-inked);
     · animation is transform/opacity only, and dies under reduced motion.

   Companion file: static/ambient.js (one extra <script> in desk.html).
   ========================================================================== */

:root {
  /* Ink sheen — the light the cursor drags across the card. Dark theme reads
     as warm paper catching a lamp; deliberately weaker than the accent so it
     never competes with a number. */
  --pp-sheen-1: rgba(255,168,116,.085);
  --pp-sheen-2: rgba(255,255,255,.022);
  --pp-inked-line: rgba(255,107,44,.22);

  /* Hairline rules — the ledger motif. Fainter than --line on purpose:
     these are texture, not structure. */
  --pp-rule:   rgba(148,163,184,.10);
  --pp-rule-2: rgba(148,163,184,.055);

  /* The ink tick that marks the row your cursor is on. */
  --pp-tick: rgba(255,107,44,.55);

  /* Ambient strip (read by ambient.js via getComputedStyle — full rgba
     strings so the canvas never has to guess at a theme). */
  /* The rules are DASHED on the canvas (1 on, 4 off), so they need roughly
     twice the alpha of a solid hairline to carry the same weight. */
  --pp-amb-dot:   rgba(166,179,201,.34);
  --pp-amb-line:  rgba(148,163,184,.22);
  --pp-amb-trace: rgba(255,107,44,.22);

  /* One easing curve for the whole layer: quick out, settled landing. */
  --pp-ease: cubic-bezier(.2,.8,.2,1);
}

:root[data-theme="light"] {
  /* On white stock the "light" has to be a warm tint — a white sheen on white
     paper is invisible, which is exactly how this looked on the first pass. */
  --pp-sheen-1: rgba(255,107,44,.075);
  --pp-sheen-2: rgba(15,23,42,.016);
  --pp-inked-line: rgba(255,107,44,.30);

  --pp-rule:   rgba(15,23,42,.075);
  --pp-rule-2: rgba(15,23,42,.045);

  --pp-tick: rgba(255,107,44,.60);

  --pp-amb-dot:   rgba(100,116,139,.30);
  --pp-amb-line:  rgba(15,23,42,.17);
  --pp-amb-trace: rgba(255,107,44,.26);
}

/* ── 1 · Cursor ink ────────────────────────────────────────────
   One throttled pointermove listener on .app sets --pp-mx/--pp-my on the
   card under the cursor and tags it .is-inked; nothing else in the document
   changes. The sheen is a ::after at z-index -1, which lands above the card's
   own background and BELOW its content — so text contrast is untouched.
   .card/.ticket get `isolation:isolate` to guarantee that stacking order
   instead of relying on an ancestor. */

.card, .ticket {
  position: relative;
  isolation: isolate;
  transition: border-color .3s var(--pp-ease);
}

.card::after, .ticket::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  transition: opacity .32s var(--pp-ease);
  background: radial-gradient(300px circle at var(--pp-mx, 50%) var(--pp-my, -20%),
              var(--pp-sheen-1), var(--pp-sheen-2) 38%, transparent 72%);
}

.card.is-inked::after, .ticket.is-inked::after { opacity: 1; }
/* Only the three non-semantic sides: the shorthand `border-color` also
   repaints border-left, which .ticket.buy/.sell use to carry direction —
   same specificity, declared later, so the ink was erasing the buy/sell
   stripe. Never let a decorative hover overwrite an encoding. */
.card.is-inked, .ticket.is-inked {
  border-top-color: var(--pp-inked-line);
  border-right-color: var(--pp-inked-line);
  border-bottom-color: var(--pp-inked-line);
}
.card.is-inked { border-left-color: var(--pp-inked-line); }

/* ── 2 · Ruled-paper motif ─────────────────────────────────────
   Three placements, all hairlines, all texture-weight:
     a. a double rule under every view header (ledger stationery),
     b. faint ruled stock behind empty states — they are the biggest blank
        areas in the app and read as "unfinished" without it,
     c. a double rule under the topbar band. */

.view-head {
  position: relative;
  margin-bottom: 18px;
  padding-bottom: 13px;
}

.view-head::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  pointer-events: none;
  background:
    linear-gradient(90deg, var(--pp-rule), transparent 62%) top    /100% 1px no-repeat,
    linear-gradient(90deg, var(--pp-rule-2), transparent 44%) bottom /100% 1px no-repeat;
}

.empty { position: relative; isolation: isolate; }

.empty::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: repeating-linear-gradient(to bottom,
              transparent 0 25px, var(--pp-rule-2) 25px 26px);
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 34%, #000 66%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 34%, #000 66%, transparent);
}

.topbar { box-shadow: 0 2px 0 -1px var(--pp-rule); }

/* The row your cursor is on gets an ink tick in the margin — the one place
   the ledger idea becomes a pointer response inside dense data. */
tbody tr:hover td:first-child { box-shadow: inset 2px 0 0 var(--pp-tick); }

/* ── 3 · Motion ────────────────────────────────────────────────
   Short and confident: a 260ms view swap, cards riding in behind it on a
   24ms stagger. ambient.js owns .pp-rise and the --pp-d delay; it only ever
   applies them on a view change, never on a data poll, so a 30-second
   refresh does not re-animate the page under you. */

.view.active { animation: pp-view-in .26s var(--pp-ease); }

@keyframes pp-view-in {
  from { opacity: 0; transform: translate3d(0, 6px, 0); }
  to   { opacity: 1; transform: none; }
}

.pp-rise {
  animation: pp-rise .34s var(--pp-ease) both;
  animation-delay: var(--pp-d, 0ms);
}

@keyframes pp-rise {
  from { opacity: 0; transform: translate3d(0, 10px, 0); }
  to   { opacity: 1; transform: none; }
}

/* ── 4 · Ambient ink strip ─────────────────────────────────────
   A canvas injected by ambient.js as the first child of .topbar. The topbar
   is already a stacking context (sticky + z-index:20), so z-index:-1 paints
   the strip above the bar's frosted background and below its controls —
   the ink is never blurred and never sits on a label. */

.pp-ambient {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
  opacity: .8;
}

/* ── 5 · Reduced motion ────────────────────────────────────────
   The global guard above already flattens durations. This kills the parts
   that would still *move* or draw attention: the cursor sheen stops
   following (it would snap, which is worse than nothing) and the ambient
   strip holds a single static frame — ambient.js never starts its loop. */

@media (prefers-reduced-motion: reduce) {
  .card::after, .ticket::after { display: none; }
  .card.is-inked, .ticket.is-inked { border-color: var(--line-strong); }
  .pp-rise { animation: none !important; opacity: 1; transform: none; }
  .pp-ambient { opacity: .55; }
}


/* ══════════════════════════════════════════════════════════════
   REPORTS · charts  (owned by static/charts.js — keep it in this block)
   ══════════════════════════════════════════════════════════════

   Colour is assigned by the JOB it does, not by taste:

     · CATEGORICAL (identity) — --ch-1/2/3, a FIXED slot order. The entity
       owns its slot: market_baseline is always slot 1, the US cohort is
       always slot 1, whatever the sort order does. Both modes are stepped
       for their own surface (var(--surface): #141B2D dark, #FFF light) and
       validated as a set — worst all-pairs CVD ΔE 9.2 light / 9.4 dark,
       worst normal-vision ΔE 24.0 / 20.9. Light-mode --ch-3 sits at 2.82:1
       on white, under the 3:1 bar, so every chart that uses it ships a
       labelled legend and a CSV/table view (the relief rule).
     · STATUS (state) — --ch-good/warning/serious/critical. Reserved: these
       never stand in for "series 4", and every one of them ships with a
       written label, never colour alone.
     · POLARITY (P&L) — --ch-pos / --ch-neg, this app's money semantics.
       Sign is ALSO carried by bar direction from a zero baseline and by a
       signed number, so the red/green pair never has to be told apart.
   ────────────────────────────────────────────────────────────── */

:root {
  /* categorical — dark steps, for the dark card surface */
  --ch-1: #3987e5;
  --ch-2: #d95926;
  --ch-3: #199e70;
  /* status — fixed, never themed */
  --ch-good:     #0ca30c;
  --ch-warning:  #fab219;
  --ch-serious:  #ec835a;
  --ch-critical: #d03b3b;
  /* structure */
  --ch-grid:    rgba(148,163,184,.15);
  --ch-axis:    rgba(148,163,184,.45);
  --ch-surface: var(--surface);
  /* polarity */
  --ch-pos: var(--up);
  --ch-neg: var(--down);
}

:root[data-theme="light"] {
  --ch-1: #2a78d6;
  --ch-2: #eb6834;
  --ch-3: #1baf7a;
  --ch-grid: rgba(15,23,42,.11);
  --ch-axis: rgba(15,23,42,.34);
}

/* ── chart frame ───────────────────────────────────────────── */

.ch-host { position: relative; }
/* hidden, not visible: a long axis title must clip at the card edge rather
   than bleed into the panel next door. */
.ch { display: block; overflow: hidden; }

/* The shared stat tile lays its sub-line out as a flex row, which shreds a
   sentence with a <b> in the middle. Reports tiles write prose, so they get
   normal text flow. Scoped — every other view keeps the flex row. */
#rp-summary .stat .s,
#rp-cohorts .stat .s,
#rp-scatter-stats .stat .s,
/* Overview's autopilot card sets a whole sentence with a bold figure in the
   middle. .stat .s is a flex row, which turns each text node and the <b>
   into separate flex items and shreds the sentence across lines — so any
   sub-line that is PROSE rather than a couple of chips opts back into
   normal text flow. */
#ov-stats .stat .s { display: block; line-height: 1.65; }

.ch-lbl {
  font-family: var(--font);
  font-size: 11px;
  fill: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.ch-cat        { fill: var(--ink-2); }
.ch-val        { fill: var(--ink); font-weight: 620; }
.ch-end        { fill: var(--ink-2); font-weight: 620; }
.ch-ref        { fill: var(--ink-3); font-size: 10px; letter-spacing: .04em; }
.ch-axis-title { fill: var(--ink-3); font-size: 10px; letter-spacing: .07em;
                 text-transform: uppercase; }
.ch-mono       { font-family: var(--mono); font-size: 10.5px; }

/* ── hover layer ───────────────────────────────────────────── */

.ch-tip {
  position: absolute;
  z-index: 6;
  pointer-events: none;
  min-width: 156px;
  max-width: 290px;
  padding: 9px 11px;
  background: var(--bg-elev);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  box-shadow: var(--shadow-2);
  font-size: 12px;
  line-height: 1.5;
}
.ch-tip[hidden] { display: none; }
.ch-tip .h { font-weight: 650; color: var(--ink); margin-bottom: 5px;
             word-break: break-word; }
.ch-tip .r { display: flex; align-items: center; gap: 8px; line-height: 1.75; }
.ch-tip .r i { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.ch-tip .r span { color: var(--ink-3); flex: 1; }
.ch-tip .r b { color: var(--ink); font-weight: 650;
               font-variant-numeric: tabular-nums; }
.ch-tip .n { margin-top: 5px; color: var(--ink-3); font-size: 11px;
             word-break: break-word; }

/* ── legend + notes ────────────────────────────────────────── */

.ch-legend {
  display: flex; flex-wrap: wrap; gap: 7px 18px;
  margin: 0 0 13px; font-size: 12px; color: var(--ink-2);
}
.card-h .ch-legend { margin: 0; }
.ch-key { display: inline-flex; align-items: center; gap: 7px; }
.ch-key i { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.ch-key em { font-style: normal; color: var(--ink-3);
             font-variant-numeric: tabular-nums; }

.ch-note {
  margin: 12px 0 0; max-width: 84ch;
  font-size: 12px; line-height: 1.65; color: var(--ink-3);
}

/* ── honest empty / insufficient states ────────────────────── */

.ch-overlay {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: min(400px, 86%);
  padding: 14px 16px; text-align: center;
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r);
  box-shadow: var(--shadow-2);
}
.ch-overlay b { display: block; font-size: 13px; margin-bottom: 5px; }
.ch-overlay span { display: block; font-size: 12px; line-height: 1.6;
                   color: var(--ink-3); }

.ch-insufficient {
  display: flex; gap: 11px; align-items: flex-start;
  margin-top: 12px; padding: 11px 13px;
  background: var(--warn-sf);
  border: 1px solid rgba(245,166,35,.24);
  border-radius: var(--r-sm);
}
.ch-insufficient .badge { white-space: nowrap; flex: none; }
.ch-insufficient .txt b { display: block; font-size: 12.5px; }
.ch-insufficient .txt span { display: block; margin-top: 3px; font-size: 12px;
                             line-height: 1.6; color: var(--ink-2); }

.ch-hero { padding: 10px 0 4px; }
.ch-hero .k { font-size: 11.5px; letter-spacing: .05em; text-transform: uppercase;
              color: var(--ink-3); font-weight: 620; }
.ch-hero .v { margin-top: 6px; font-size: 34px; font-weight: 680;
              letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.ch-hero .s { margin-top: 4px; font-size: 12px; color: var(--ink-3);
              font-variant-numeric: tabular-nums; }

.ch-verdict {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 16px; border-radius: var(--r); border: 1px solid transparent;
}
.ch-verdict.warn { background: var(--warn-sf); border-color: rgba(245,166,35,.28); }
.ch-verdict.good { background: var(--up-sf);   border-color: rgba(61,220,151,.26); }
.ch-verdict .ic { font-size: 16px; font-weight: 800; line-height: 1.35; flex: none; }
.ch-verdict.warn .ic { color: var(--warn); }
.ch-verdict.good .ic { color: var(--up); }
.ch-verdict b { display: block; font-size: 13.5px; margin-bottom: 4px; }
.ch-verdict span { display: block; max-width: 100ch; font-size: 12.5px;
                   line-height: 1.65; color: var(--ink-2); }

/* ── segmented control (p_raw ↔ p_shrunk) ──────────────────── */

.seg-group {
  display: inline-flex; padding: 2px; gap: 2px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm);
}
.seg {
  height: 23px; padding: 0 11px;
  background: transparent; border: 0; border-radius: 6px;
  color: var(--ink-3); font: inherit; font-size: 12px; font-weight: 600;
  font-family: var(--mono); cursor: pointer;
}
.seg:hover { color: var(--ink); }
.seg.on { background: var(--surface); color: var(--ink); box-shadow: var(--shadow-1); }

/* ── print ─────────────────────────────────────────────────── */

@media print {
  /* Paper is a light surface, so print re-steps the tokens to the light
     ramp rather than printing dark-mode ink onto white. */
  :root, :root[data-theme="dark"], :root[data-theme="light"] {
    --bg: #fff; --bg-elev: #fff; --surface: #fff;
    --surface-2: #f4f5f7; --surface-3: #ecedf0;
    --ink: #111; --ink-2: #333; --ink-3: #555;
    --line: rgba(0,0,0,.16); --line-strong: rgba(0,0,0,.32);
    --up: #0F9D62; --down: #D64545; --warn: #B7791F;
    --ch-1: #2a78d6; --ch-2: #eb6834; --ch-3: #1baf7a;
    --ch-grid: rgba(0,0,0,.13); --ch-axis: rgba(0,0,0,.38);
  }
  .sidebar, .topbar, .toasts, .no-print, .onboard, .pp-ambient,
  .ch-tip { display: none !important; }
  .app { display: block; }
  .view { display: none !important; }
  .view.active { display: block !important; animation: none; }
  body { background: #fff; color: #111; }
  .card { border: 1px solid #ccc !important; box-shadow: none !important;
          break-inside: avoid; page-break-inside: avoid; }
  .card::after, .ticket::after { display: none !important; }
  .row h2, .view-head h1, .view-head h1 + p { break-after: avoid;
                                              page-break-after: avoid; }
  .grid.k2, .grid.k3, .grid.k4 { grid-template-columns: 1fr 1fr; }
  .content { padding: 0 !important; }
}

/* ==========================================================================
   SIMPLE ↔ ADVANCED — the two audiences
   --------------------------------------------------------------------------
   Appended by the audience-view pass. Two rules govern everything below:

     1. NOT ONE RAW HEX. Every colour is a token declared at the top of this
        file, so the institutional re-theme repaints this block for free and
        both themes stay correct without a second set of values to maintain.
     2. Status and polarity keep their jobs. The simple view's headline is a
        STATUS (good / needs-attention / broken), so it uses --st-*, never
        --up/--down, which mean money direction. And every coloured thing
        below ships with the word beside it — "Broken", "Waiting", "did not
        finish" — because a reader who cannot see the colour must get the
        same answer from the text.
   ========================================================================== */

/* The live region that announces an audience change. Present for assistive
   technology, invisible (but not display:none, which would silence it). */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

/* Chrome that belongs to one audience. The sidebar is filtered in desk.js
   from the same set the router uses (one definition of "who is this page
   for"); everything else is tagged in the template. */
:root[data-mode="simple"]   [data-mode-only="advanced"],
:root[data-mode="advanced"] [data-mode-only="simple"] { display: none; }
.nav-item[hidden], .nav-group[hidden] { display: none !important; }

/* Belt and braces against a flash of the wrong home: data-mode is set while
   desk.js parses, which is before first paint, so the home that does not
   belong to this audience is already hidden when the page draws. Routing
   itself still happens in desk.js. */
:root[data-mode="simple"]   .view[data-audience="advanced"],
:root[data-mode="advanced"] .view[data-audience="simple"] { display: none; }

/* The switch itself — the existing segmented control, plus the focus ring a
   keyboard radiogroup owes its user. */
.vm-group .seg { font-family: var(--font); letter-spacing: 0; }
.vm-group .seg:focus-visible {
  outline: 2px solid var(--brand-tint);
  outline-offset: 1px;
}

/* ── The simple view ──────────────────────────────────────────
   Prose, not a dashboard. A reading measure, generous leading, and figures
   that sit inside sentences instead of standing alone in tiles. */

.sv .view-head p, .sv .sv-prose, .sv .sv-head-s { max-width: 68ch; }

.sv-prose p, .sv-p {
  margin: 0 0 10px;
  font-size: var(--fs-lead);
  line-height: 1.62;
  color: var(--ink-2);
}
.sv-prose p:last-child, .sv-p:last-child { margin-bottom: 0; }
.sv-prose b, .sv-p b { color: var(--ink); font-weight: var(--w-semi); }
.sv-h {
  margin: 0 0 10px;
  font-size: var(--fs-lead);
  font-weight: var(--w-semi);
  color: var(--ink);
}
.sv-quiet { color: var(--ink-3); }

/* Headline: one sentence, sized so it is the first thing read. The left
   edge carries the status; the words carry it too. */
.sv-head { border-left: 3px solid var(--line-strong); }
.sv-head.ok   { border-left-color: var(--st-good-tx); }
.sv-head.warn { border-left-color: var(--st-warn-tx); }
.sv-head.bad  { border-left-color: var(--st-bad-tx); }
.sv-head-t {
  font-size: var(--fs-hero);
  font-weight: var(--w-semi);
  line-height: 1.2;
  letter-spacing: -.02em;
  color: var(--ink);
}
.sv-head-s {
  margin-top: 8px;
  font-size: var(--fs-lead);
  color: var(--ink-2);
}

/* "Does anything need you" — one row per thing, each a full sentence. */
.sv-list { display: grid; gap: 10px; }
.sv-item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r);
}
.sv-item-tag {
  flex: none; margin-top: 1px;
  padding: 2px 8px;
  border-radius: var(--r-sm);
  font-size: var(--fs-cap);
  font-weight: var(--w-semi);
  text-transform: uppercase;
  letter-spacing: var(--track-eyebrow);
  background: var(--surface-3);
  color: var(--ink-2);
}
.sv-item.broken { border-color: var(--st-bad-ring); }
.sv-item.broken .sv-item-tag { background: var(--st-bad-sf); color: var(--st-bad-tx); }
.sv-item.you    { border-color: var(--st-warn-ring); }
.sv-item.you .sv-item-tag { background: var(--st-warn-sf); color: var(--st-warn-tx); }
.sv-item.ok .sv-item-tag { background: var(--st-good-sf); color: var(--st-good-tx); }
.sv-item-t {
  flex: 1;
  font-size: var(--fs-lead);
  line-height: 1.55;
  color: var(--ink-2);
}
.sv-item .btn { flex: none; align-self: center; }

/* "What happened recently" — a plain log, no ids, no durations in seconds. */
.sv-log { display: grid; gap: 2px; }
.sv-log-row {
  display: grid;
  grid-template-columns: 168px 1fr auto;
  gap: 14px; align-items: baseline;
  padding: 9px 0;
  border-bottom: 1px solid var(--line);
}
.sv-log-row:last-child { border-bottom: 0; }
.sv-log-when { color: var(--ink-3); font-size: var(--fs-sm); }
.sv-log-what { color: var(--ink-2); font-size: var(--fs-lead); line-height: 1.5; }
.sv-log-tag {
  font-size: var(--fs-cap);
  color: var(--ink-3);
  white-space: nowrap;
}
.sv-log-tag.ok  { color: var(--st-good-tx); }
.sv-log-tag.bad { color: var(--st-bad-tx); font-weight: var(--w-semi); }

/* The way out to the instrument. */
.sv-switch {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin-top: 26px;
  background: var(--brand-sf);
  border-color: var(--brand-ring);
}
.sv-switch .spacer { flex: 1; }
.sv-switch-t { font-size: var(--fs-lead); font-weight: var(--w-semi); color: var(--ink); }
.sv-switch-s { margin-top: 3px; font-size: var(--fs-body); color: var(--ink-2); max-width: 60ch; }

/* ── Advanced: the model-detail key/value blocks ──────────── */

.kv-h {
  margin: 0 0 12px;
  font-size: 13.5px; font-weight: 650; color: var(--ink);
}
.kv {
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 4px 14px;
  padding: 8px 0;
  border-top: 1px solid var(--line);
}
.kv:first-of-type { border-top: 0; }
.kv-k { font-size: var(--fs-sm); color: var(--ink-3); }
.kv-v { font-size: var(--fs-body); color: var(--ink); overflow-wrap: anywhere; }
.kv-n { grid-column: 2; font-size: var(--fs-cap); color: var(--ink-3); }

@media (max-width: 900px) {
  /* The switch is the one control that must survive a narrow topbar, so the
     machine chips give up their room before it does. */
  .sv-head-t { font-size: var(--fs-figure); }
  .sv-log-row { grid-template-columns: 1fr auto; }
  .sv-log-when { grid-column: 1 / -1; }
  .sv-item { flex-wrap: wrap; }
  .sv-item .btn { align-self: flex-start; }
  .kv { grid-template-columns: 1fr; }
  .kv-n { grid-column: 1; }
}
