/*
  ============================================================================
  DESIGN SYSTEM v2 — joseph-compound quantdev/operator portal
  MOBILE-FIRST (CTO 2026-08-25, BRIEF.md §7)
  ============================================================================
  DESIGN PLAN (read before editing — BRIEF.md is the full brief)

  ONE SENTENCE: Apple Stocks meets a private-bank statement, on a phone.
  Big, calm, confident numbers on quiet grey or true black; grouped inset
  lists instead of bordered cards; one accent used almost never; translucent
  chrome that defers to content; every number honest about its age.

  THE PHONE IS THE PRODUCT. This file is authored mobile-first: every base
  rule targets 390–430px and assumes NO pointer, NO hover, and NO width above
  430. Wider layouts are ADDITIONS:
      base            phone   — tab bar, grouped rows, sheets
      min-width:768   tablet  — icon rail replaces the tab bar
      min-width:1024  desktop — full 224px sidebar, tables become grids
  There is no `max-width` breakpoint anywhere in this file, on purpose. A
  max-width query means "desktop, shrunk", and shrinking desktop is what made
  v1 read as a generic admin template on a phone.

  TYPE. ONE family — the system stack (SF on Apple, Inter elsewhere). Numbers
  use the SAME family with tabular figures; there is NO monospace money here.
  --font-code (SF Mono → JetBrains Mono) is only for CLI snippets, client
  order ids and INV M29 reason codes. Scale = macOS text styles used
  literally (pt = px), plus ONE Display size for a screen's hero number.

  COLOUR IS MEANING, NOT BRAND. Label colours are opacity tiers of ink. One
  accent for interactivity. Semantics stay isolated from each other:
    --pos / --neg   money only
    --warn          attention that is not yet a loss
    --live          liveness — teal, NEVER green (a heartbeat is not profit)
    --stale         tertiary ink — grey, NEVER red (old is unknown, not loss)

  GROUPING BY SHAPE, NOT BORDERS. A block is a rounded filled surface on the
  canvas — no border, no shadow. Rows are separated by hairlines inset from
  the leading edge. Shadows exist only on floating surfaces (sheet, dialog,
  toast). Chrome (tab bar, toolbar, sidebar) is translucent material.

  TOUCH FIRST. Every target is ≥44px. Actions are pill buttons; a screen's
  primary actions live in a sticky bottom action bar above the tab bar.
  Destructive confirms are half-sheets on the phone and centred dialogs from
  768 up — same markup, no JS branch.

  CLASS CONTRACT: every class name from v1 still exists and still works (see
  CONTRACT.md); they were restyled, never renamed.
  ============================================================================
*/

/* ---------------------------------------------------------------------- */
/* 1. TOKENS                                                               */
/* ---------------------------------------------------------------------- */

:root {
  /* ---- type ---------------------------------------------------------- */
  --font-ui: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display",
    "Inter", "Segoe UI", system-ui, sans-serif;
  --font-code: ui-monospace, "SF Mono", SFMono-Regular, "JetBrains Mono",
    "IBM Plex Mono", Menlo, Consolas, monospace;
  /* Legacy aliases used by screen fragments. --font-mono is code-only now. */
  --font-sans: var(--font-ui);
  --font-mono: var(--font-code);

  /* macOS text styles, pt = px */
  --fs-display: 40px;      --lh-display: 44px;   /* phone; grows at 768 */
  --fs-large-title: 26px;  --lh-large-title: 32px;
  --fs-title1: 22px;       --lh-title1: 28px;
  --fs-title2: 17px;       --lh-title2: 22px;
  --fs-title3: 15px;       --lh-title3: 20px;
  --fs-headline: 13px;     --lh-headline: 16px;
  --fs-body: 13px;         --lh-body: 18px;
  --fs-callout: 12px;      --lh-callout: 16px;
  --fs-subheadline: 11px;  --lh-subheadline: 14px;
  --fs-footnote: 11px;     --lh-footnote: 14px;
  --fs-caption: 11px;      --lh-caption: 14px;

  /* Legacy numeric aliases, remapped onto the macOS scale. */
  --fs-12: var(--fs-callout);
  --fs-13: var(--fs-body);
  --fs-14: var(--fs-title3);
  --fs-16: var(--fs-title2);
  --fs-20: var(--fs-title1);
  --fs-24: var(--fs-large-title);
  --fs-32: var(--fs-display);

  /* ---- approved palette (W1.1, FRONTEND_EXECUTION_PLAN): Binance-inspired
     near-black canvas, charcoal surfaces, yellow actions/selection, green/red
     trading outcomes, blue information. ONE theme: the light palette and its
     colour-scheme / stored-theme overrides were removed, so no stored
     "jb-theme" value and no OS setting can paint a light surface. The canvas
     (canvas/canvas.css) reads the same values through its --qc-* tokens. */
  --canvas: #07090c;
  --surface: #181a20;
  --surface-2: #252930;
  --surface-3: rgba(176, 183, 194, 0.10);
  --material-bg: rgba(24, 26, 32, 0.94);
  --material-line: #353b45;

  --ink: #eaecef;
  --ink-dim: #b0b7c2;
  --ink-faint: #9aa5b5;
  --ink-quat: rgba(234, 236, 239, 0.24);
  --ink-on-accent: #181a20;
  --ink-on-neg: #181a20;
  --ink-on-pos: #07090c;

  --separator: #353b45;
  --border: var(--separator);
  --border-soft: #2a2f37;
  --border-strong: #505866;

  --accent: #f0b90b;
  --accent-hover: #ffd044;
  --accent-fill: rgba(240, 185, 11, 0.14);
  --accent-soft: var(--accent-fill);
  --accent-soft-border: rgba(240, 185, 11, 0.36);

  --pos: #2ed6a1;
  --pos-bg: rgba(46, 214, 161, 0.14);
  --pos-border: rgba(46, 214, 161, 0.32);
  --pos-line: #2ed6a1;
  --neg: #ff7084;
  --neg-bg: rgba(255, 112, 132, 0.14);
  --neg-border: rgba(255, 112, 132, 0.32);
  --neg-hover: #ff8f9f;
  --neg-line: #ff7084;
  --warn: #f5c76b;
  --warn-bg: rgba(245, 199, 107, 0.14);
  --warn-border: rgba(245, 199, 107, 0.32);

  --stale: var(--ink-faint);
  --stale-bg: rgba(154, 165, 181, 0.14);
  --stale-border: rgba(154, 165, 181, 0.28);

  /* Liveness stays teal, never green (a heartbeat is not profit). */
  --live: #7fd6e6;
  --live-bg: rgba(127, 214, 230, 0.14);
  --live-border: rgba(127, 214, 230, 0.32);
  --info: #a7c5ff;

  --fill: rgba(176, 183, 194, 0.12);
  --fill-hover: rgba(176, 183, 194, 0.20);

  /* ---- shape & space ------------------------------------------------- */
  --radius-pill: 999px;
  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 14px;
  --radius-sheet: 16px;
  --hairline: 1px;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;

  /* Touch: never below 44. */
  --row-h: 44px;
  --tap: 44px;
  --tabbar-h: 49px;
  /* Height a fixed .action-bar--sticky covers: 12 + 44 + 12. Screens that
     carry one reserve exactly this much at their end. */
  --action-bar-h: 68px;

  --shadow-elev: none;
  --shadow-overlay: 0 -8px 40px rgba(0, 0, 0, 0.7);
  --shadow-float: 0 8px 24px rgba(0, 0, 0, 0.6);

  --sidebar-w: 224px;
  --sidebar-rail-w: 68px;
  --topbar-h: 48px;

  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  color-scheme: dark;
}

@media (prefers-contrast: more) {
  :root {
    --ink-dim: #c8ced8;
    --ink-faint: #b5bfcc;
    --separator: #6b7685;
  }
}

/* ---------------------------------------------------------------------- */
/* 2. BASE                                                                 */
/* ---------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}

h1, h2, h3, h4, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; }

a { color: var(--accent); text-decoration: none; }

button, input, select, textarea { font: inherit; color: inherit; }

/* No hover styling is assumed anywhere in the base — it is added only
   inside the pointer query below, so a touch device never inherits a
   sticky :hover state after a tap. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

svg { display: block; }

.num, .stat-card-value, .hero-value, .kv-value, .pnl, .age-badge,
.row-value, td.num, th.num, .table td.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

.mono, .inline-code, .code-block {
  font-family: var(--font-code);
  font-variant-numeric: tabular-nums;
}
.mono { font-size: 0.92em; letter-spacing: -0.01em; }

.inline-code {
  background: var(--fill);
  border-radius: 5px;
  padding: 1px 5px;
  font-size: 0.88em;
}

.code-block {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-4);
  font-size: var(--fs-callout);
  line-height: 1.65;
  color: var(--ink-dim);
  white-space: pre;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.eyebrow, .group-header, .table-caption, .field-label, .sidebar-group-label {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* ---------------------------------------------------------------------- */
/* 3. MATERIALS                                                            */
/* ---------------------------------------------------------------------- */

.material {
  background: var(--material-bg);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
}

/* ---------------------------------------------------------------------- */
/* 4. APP SHELL — phone: toolbar on top, tab bar at the bottom             */
/* ---------------------------------------------------------------------- */

.app-shell {
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: auto 1fr;
  grid-template-areas: "topbar" "main";
  min-height: 100vh;
  min-height: 100dvh;
}

.main {
  grid-area: main;
  min-width: 0;
  width: 100%;
  padding: var(--space-4) var(--space-4)
           calc(var(--tabbar-h) + var(--safe-b) + var(--space-8));
  padding-left: max(var(--space-4), var(--safe-l));
  padding-right: max(var(--space-4), var(--safe-r));
}

/* The sidebar does not exist on a phone. It is introduced at 768. */
.sidebar { display: none; }

/* ---- toolbar: minimal on the phone ----------------------------------- */
/* One action, the liveness dot, and the tenant switcher in operator mode.
   The screen's identity is the Large Title in the content, not here. */
.topbar {
  grid-area: topbar;
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  min-width: 0;
  overflow: hidden;
  height: calc(var(--topbar-h) + var(--safe-t));
  padding: var(--safe-t) max(var(--space-4), var(--safe-r)) 0
           max(var(--space-4), var(--safe-l));
  background: var(--material-bg);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  box-shadow: inset 0 -1px 0 var(--material-line);
}
/* The leading slot exists on a phone ONLY to hold a back link. The
   breadcrumb stays hidden here (the Large Title in the content already
   says where you are); it returns at 768 where there is room for it. */
.topbar-left { display: flex; align-items: center; min-width: 0; flex: 1 1 auto; overflow: hidden; }
.topbar-left .breadcrumb { display: none; }

.topbar-back, .auth-back {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: var(--tap);
  margin-left: -8px;
  padding: 0 8px 0 4px;
  color: var(--accent);
  font-size: var(--fs-title3);
  font-weight: 500;
  white-space: nowrap;
  min-width: 0;
  -webkit-tap-highlight-color: transparent;
}
.topbar-back svg, .auth-back svg { width: 20px; height: 20px; flex: none; }
.topbar-back .label, .auth-back .label { overflow: hidden; text-overflow: ellipsis; }

/* The auth layout has no toolbar, so its back link sits at the top of the
   content column instead. */
.auth-back { display: none; }
html.layout-auth .auth-back { display: inline-flex; margin-bottom: var(--space-2); }
html.layout-auth .auth-back[hidden] { display: none; }
.topbar-right {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  margin-left: auto;
}

.breadcrumb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-callout);
  color: var(--ink-faint);
  min-width: 0;
}
.breadcrumb-item { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.breadcrumb-item:last-child { color: var(--ink); font-weight: 600; }
.breadcrumb-sep { color: var(--ink-quat); }


.tenant-switcher {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
  height: 30px;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--ink-dim);
  cursor: pointer;
}
.tenant-switcher .eyebrow { display: none; }
.tenant-switcher-select {
  border: 0;
  background: transparent;
  color: var(--ink);
  font-size: var(--fs-callout);
  font-weight: 600;
  padding: 0;
  min-width: 0;
  max-width: 108px;
  text-overflow: ellipsis;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}
.tenant-switcher svg { color: var(--ink-faint); flex: none; }

/* The liveness dot keeps its meaning; the word is read by assistive tech. */
.topbar .liveness { flex: none; }
.topbar .liveness-why {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.tenant-view-banner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 10px var(--space-4);
  margin-bottom: var(--space-4);
  border-radius: var(--radius);
  background: var(--accent-fill);
  color: var(--accent);
  font-size: var(--fs-callout);
}
.tenant-view-banner strong { font-weight: 600; }

body[data-mode="quantdev"] .operator-only { display: none !important; }

.screen { display: none; }
.screen.is-active { display: block; }

/* ---- data source switch: the ONE place that says where numbers come from */
/* Layout only — .segmented and .tag already carry the visual language.
   Folded in from the placeholder live.js left in shell.html's <head>. */
.data-mode-switch { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.data-mode-switch .segmented > * { min-height: 26px; padding: 5px 8px; }
/* The tag spells out WHICH world and whether the read lane is connected.
   Below 1024 that sentence has no room beside the segmented, and a clipped
   "Sam…" pill is worse than no pill — the segmented already says which
   source is selected. */
/* .tag.data-mode-tag, not .data-mode-tag: the element carries BOTH
   classes, so a single-class rule ties with .tag's own display and loses
   on source order — the pill stayed visible and the toolbar said Sample
   twice. */
.tag.data-mode-tag { display: none; max-width: 22ch; overflow: hidden; text-overflow: ellipsis; }
/* Signed out there is no data source to choose — there is a key to present. */
html.layout-auth .data-mode-switch { display: none !important; }

/* Exactly one voice for the data source. A screen that also prints its own
   "Sample data" pill in the page header is a second answer to a question
   the toolbar has already answered; when the switch is present, that pill
   stands down. Matched on the title text the four screens share, so no
   screen edit is needed to make this true. */
body:has(#data-mode-switch) .page-header-actions .tag[title^="Deterministic demo fixture"] { display: none; }

/* ---------------------------------------------------------------------- */
/* 5. TAB BAR — iOS, 49px + safe area, 5 items                             */
/* ---------------------------------------------------------------------- */

.bottom-nav {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  height: calc(var(--tabbar-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  background: var(--material-bg);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  box-shadow: inset 0 1px 0 var(--material-line);
}
.bottom-nav-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink-faint);
  font-family: inherit;
  font-size: 10px;
  line-height: 12px;
  font-weight: 500;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.bottom-nav-link .icon { width: 24px; height: 24px; }
.bottom-nav-link.is-active { color: var(--accent); }

/* ---------------------------------------------------------------------- */
/* 6. SHEETS — the phone's modal surface                                   */
/* ---------------------------------------------------------------------- */

/* .sheet is the standalone component; .dialog (what App.confirm renders)
   inherits the same shape at base so a confirm is a half-sheet on a phone
   with NO JS branch, and becomes a centred dialog from 768 up. */
.bottom-sheet-backdrop, .dialog-backdrop, .sheet-backdrop {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: flex-end;
  background: rgba(0, 0, 0, 0.4);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
.bottom-sheet-backdrop[hidden], .sheet-backdrop[hidden] { display: none; }
.dialog-backdrop { z-index: 100; }

.bottom-sheet, .sheet, .dialog {
  width: 100%;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--surface);
  color: var(--ink);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  box-shadow: var(--shadow-overlay);
  padding: var(--space-2) var(--space-4)
           calc(var(--space-5) + var(--safe-b));
  text-align: left;
}

/* Grabber. On .bottom-sheet it is an explicit element; on .sheet/.dialog it
   is drawn so no markup change is needed for App.confirm. */
.bottom-sheet-handle,
.sheet::before,
.dialog::before {
  content: "";
  display: block;
  width: 36px; height: 5px;
  border-radius: var(--radius-pill);
  background: var(--ink-quat);
  margin: var(--space-2) auto var(--space-4);
}

.bottom-sheet-link {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  color: var(--ink);
  font-size: var(--fs-title3);
  font-weight: 500;
}
.bottom-sheet-link + .bottom-sheet-link { box-shadow: inset 0 1px 0 var(--separator); }
.bottom-sheet-group { margin-top: var(--space-4); }
.bottom-sheet-group .sidebar-group-label { padding-bottom: var(--space-1); }

.sheet-title, .dialog-title {
  font-size: var(--fs-title2);
  line-height: var(--lh-title2);
  font-weight: 700;
  letter-spacing: -0.015em;
  color: var(--ink);
  margin-bottom: var(--space-3);
}
.dialog-step-label {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: var(--space-2);
}
.dialog-consequences {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  background: var(--fill);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: var(--fs-callout);
  line-height: var(--lh-body);
  color: var(--ink-dim);
}
.dialog-consequences li { position: relative; padding-left: 16px; }
.dialog-consequences li::before {
  content: "";
  position: absolute;
  left: 3px; top: 7px;
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--ink-quat);
}
/* Stacked full-width actions: the iOS sheet pattern, and it keeps a
   destructive confirm from sitting a thumb-width from Cancel. */
.dialog-footer, .sheet-footer {
  display: flex;
  flex-direction: column-reverse;
  gap: var(--space-2);
}
.dialog-footer .btn, .sheet-footer .btn { width: 100%; height: var(--tap); }

/* ---------------------------------------------------------------------- */
/* 7. STICKY ACTION BAR — a screen's primary actions, above the tab bar    */
/* ---------------------------------------------------------------------- */

.action-bar { display: flex; gap: var(--space-2); align-items: center; }

.action-bar--sticky {
  position: fixed;
  left: 0; right: 0;
  bottom: calc(var(--tabbar-h) + var(--safe-b));
  z-index: 35;
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3) max(var(--space-4), var(--safe-l))
           var(--space-3) max(var(--space-4), var(--safe-r));
  background: var(--material-bg);
  -webkit-backdrop-filter: blur(24px) saturate(180%);
  backdrop-filter: blur(24px) saturate(180%);
  box-shadow: inset 0 1px 0 var(--material-line);
}
.action-bar--sticky .btn { flex: 1; height: var(--tap); }

/* A fixed bar covers whatever is behind it, so the screen it belongs to
   MUST reserve that much room at its end — otherwise the last group can
   never be scrolled clear of the bar. Reserving it HERE, once, is the
   point: three screens each invented their own number (96px, 88px, 84px)
   and the one that forgot shipped a permanently-covered heading. */
/* :has() matches on EXISTENCE, not visibility — so a bar sitting in a
   hidden tab panel still reserved 68px, and Strategy's Ship / Indicators /
   New tabs each ended with a band of dead space below the last group.
   Two guards: the bar is not itself hidden, and it is not inside anything
   hidden. Both key off the `hidden` ATTRIBUTE, which is why a screen must
   hide an inactive panel with `hidden` rather than a display:none class —
   a class is invisible to this selector. */
.screen:has(.action-bar--sticky:not([hidden]):not([hidden] *)) { padding-bottom: var(--action-bar-h); }

/* Auth routes have no tab bar to clear, so the bar sits flush to the
   bottom edge. It is NOT hidden here — hiding it under layout-auth is
   what forced the signup flow to hand-roll a second sticky bar. */
html.layout-auth .action-bar--sticky {
  bottom: 0;
  padding-bottom: calc(var(--space-3) + var(--safe-b));
}

/* ---------------------------------------------------------------------- */
/* 8. PAGE HEADER + HERO                                                   */
/* ---------------------------------------------------------------------- */

.page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-4);
}
.page-header-title { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.page-header-title h1 {
  font-size: var(--fs-large-title);
  line-height: var(--lh-large-title);
  font-weight: 700;
  letter-spacing: -0.021em;
  color: var(--ink);
}
.page-header-title .eyebrow { color: var(--ink-faint); }
.page-header-actions { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }

.hero {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.hero-value {
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  font-weight: 700;
  letter-spacing: -0.028em;
  color: var(--ink);
}
.hero-value.is-stale { color: var(--stale); }
/* Unknown is not the same shape as known. A Display-size em-dash reads as a
   loading skeleton, so an unknown hero drops to Title 1 and carries its
   reason as words — the size at which "—" is punctuation again. */
.hero-value.is-unknown {
  font-size: var(--fs-title1);
  line-height: var(--lh-title1);
  letter-spacing: -0.02em;
  font-weight: 600;
  color: var(--ink-dim);
}
.hero-value.is-unknown .hero-why { font-weight: 400; color: var(--ink-faint); }
.hero-change {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: var(--space-2);
  font-size: var(--fs-title3);
  line-height: var(--lh-title3);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink-dim);
}
.hero-change .pos, .hero-change.pos { color: var(--pos); }
.hero-change .neg, .hero-change.neg { color: var(--neg); }
.hero-change .is-stale, .hero-change.is-stale { color: var(--stale); }
.hero-change .sep { color: var(--ink-quat); font-weight: 400; }
.hero-change .muted { color: var(--ink-dim); font-weight: 400; }

/* ---------------------------------------------------------------------- */
/* 9. SEGMENTED CONTROL + CHIPS                                            */
/* ---------------------------------------------------------------------- */

.segmented {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-sm);
  background: var(--fill);
  max-width: 100%;
}
.segmented > * {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--ink-dim);
  font-family: inherit;
  font-size: var(--fs-callout);
  font-weight: 600;
  line-height: 1;
  min-height: 32px;
  padding: 8px 14px;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
.segmented > .is-active {
  background: var(--surface-2);
  color: var(--ink);
  box-shadow: none;
}

/* Filters: one line of capsules that scrolls horizontally. Never wraps. */
.chips {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding-bottom: var(--space-1);
  margin-bottom: var(--space-3);
}
.chips::-webkit-scrollbar { display: none; }
.chips > * {
  flex: none;
  appearance: none;
  border: 0;
  background: var(--fill);
  color: var(--ink-dim);
  font-family: inherit;
  font-size: var(--fs-callout);
  font-weight: 600;
  min-height: 32px;
  padding: 0 14px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  cursor: pointer;
}
.chips > .is-active { background: var(--accent-fill); color: var(--accent); }

/* ---------------------------------------------------------------------- */
/* 10. GROUPED INSET LISTS — the primary container                         */
/* ---------------------------------------------------------------------- */

.group {
  background: var(--surface);
  border-radius: var(--radius);
  margin-bottom: var(--space-4);
  overflow: hidden;
}
.group-header {
  padding: var(--space-3) var(--space-4) 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.group-header--outside {
  padding: 0 var(--space-1) var(--space-2);
  background: transparent;
}

.row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--row-h);
  padding: 10px var(--space-4);
  position: relative;
}
.row + .row::before {
  content: "";
  position: absolute;
  left: var(--space-4);
  right: 0;
  top: 0;
  height: var(--hairline);
  background: var(--separator);
  transform: scaleY(0.5);
  transform-origin: top;
}
.row--stacked { align-items: flex-start; flex-direction: column; gap: var(--space-2); }
.row--link { cursor: pointer; }

.row-main { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.row-title {
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 500;
  color: var(--ink);
}
.row-sub {
  font-size: var(--fs-callout);
  line-height: var(--lh-callout);
  color: var(--ink-dim);
}
.row-value {
  margin-left: auto;
  text-align: right;
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}
.row-value.is-dim { color: var(--ink-dim); font-weight: 400; }
.row-aside { margin-left: auto; display: flex; align-items: center; gap: var(--space-2); }

/* ---- expandable row: secondary detail collapses behind a tap ---------- */
/* This is how dense data reaches the phone — one important number on the
   row, everything else in the detail. app.js toggles .is-open on tap. */
.row--expandable { cursor: pointer; padding-right: var(--space-8); }
.row--expandable::after {
  content: "";
  position: absolute;
  right: var(--space-4);
  top: 50%;
  width: 7px; height: 7px;
  border-right: 1.5px solid var(--ink-quat);
  border-bottom: 1.5px solid var(--ink-quat);
  transform: translateY(-70%) rotate(45deg);
  transition: transform 160ms ease;
}
/* Open: the chevron stays with the row's own line instead of drifting to the
   middle of the expanded detail. */
.row--expandable.is-open::after {
  top: 22px;
  transform: translateY(-50%) rotate(-135deg);
}
.row--expandable .row-detail { display: none; }
.row--expandable.is-open {
  flex-direction: column;
  align-items: stretch;
}
.row--expandable.is-open .row-detail {
  display: flex;
  flex-direction: column;
  width: 100%;
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  box-shadow: inset 0 1px 0 var(--separator);
}
/* .row-head must lay out the same whether the row is open or closed — when
   this was scoped to .is-open only, a CLOSED row dropped its value onto a
   second line because the wrapper fell back to a block. */
.row--expandable .row-head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
}
.row-detail .kv-row:first-child { padding-top: var(--space-2); }

/* ---------------------------------------------------------------------- */
/* 11. STAT TILES                                                          */
/* ---------------------------------------------------------------------- */

.stat-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.stat-card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}
.stat-card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.stat-card-value {
  font-size: var(--fs-title1);
  line-height: var(--lh-title1);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.stat-card-value.is-stale { color: var(--stale); }
.stat-card-value .pnl { font-size: inherit; font-weight: inherit; letter-spacing: inherit; }
.stat-card-foot {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: var(--fs-callout);
  line-height: var(--lh-callout);
  color: var(--ink-dim);
  margin-top: 2px;
}

/* ---------------------------------------------------------------------- */
/* 12. TABLES — grouped rows on the phone, a grid only from 1024           */
/* ---------------------------------------------------------------------- */

/* There are no tables in the base. A <table> renders as a stack of rows:
   the label from data-label on the left, the value on the right. What was
   .table--responsive in v1 is simply what .table does now. */
.table {
  background: var(--surface);
  border-radius: var(--radius);
  margin-bottom: var(--space-4);
  overflow: hidden;
}
.table thead { display: none; }
.table table, .table tbody, .table tr, .table td { display: block; width: 100%; }
.table tbody tr {
  padding: var(--space-3) 0;
  position: relative;
}
.table tbody tr + tr { box-shadow: inset 0 1px 0 var(--separator); }
.table td {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 26px;
  padding: 3px var(--space-4);
  font-size: var(--fs-body);
  color: var(--ink);
  text-align: right;
}
.table td::before {
  content: attr(data-label);
  flex: none;
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-align: left;
}
/* A cell with no data-label has nothing to announce — don't reserve a gap. */
.table td:not([data-label])::before { content: none; }
.table .cell-sub { display: block; font-size: var(--fs-callout); color: var(--ink-dim); }

.table-caption {
  padding: var(--space-3) var(--space-4);
  color: var(--ink-faint);
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
  font-size: var(--fs-callout);
  line-height: var(--lh-callout);
  box-shadow: inset 0 1px 0 var(--separator);
}

/* .table-scroll only means something once the grid exists (≥1024). */
.table-scroll { overflow-x: visible; }

/* ---------------------------------------------------------------------- */
/* 13. TAGS, PILLS, AGE CHIPS, LIVENESS, RUNGS                             */
/* ---------------------------------------------------------------------- */

.tag, .pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 9px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-caption);
  line-height: 1;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  background: var(--fill);
  color: var(--ink-dim);
}
.pill--neutral { background: var(--fill); color: var(--ink-dim); }
.pill--pos, .tag--pos { background: var(--pos-bg); color: var(--pos); }
.pill--neg, .tag--neg { background: var(--neg-bg); color: var(--neg); }
.pill--warn, .tag--warn { background: var(--warn-bg); color: var(--warn); }
.pill--accent, .tag--accent { background: var(--accent-fill); color: var(--accent); }
.pill--live, .tag--live { background: var(--live-bg); color: var(--live); }
.pill--stale, .tag--stale { background: var(--stale-bg); color: var(--stale); }

.age-badge {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  font-size: var(--fs-caption);
  line-height: 1;
  font-weight: 500;
  white-space: nowrap;
  background: transparent;
  color: var(--ink-faint);
}
.age-badge--fresh { color: var(--ink-faint); }
.age-badge--warn { background: var(--warn-bg); color: var(--warn); }
.age-badge--stale { background: var(--stale-bg); color: var(--stale); font-weight: 600; }

.liveness { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.liveness-dot {
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--ink-quat);
}
.liveness-why {
  font-size: var(--fs-callout);
  line-height: var(--lh-callout);
  color: var(--ink-dim);
  min-width: 0;
}
.liveness--live .liveness-dot { background: var(--live); box-shadow: 0 0 0 3px var(--live-bg); }
.liveness--warn .liveness-dot { background: var(--warn); box-shadow: 0 0 0 3px var(--warn-bg); }
.liveness--dead .liveness-dot { background: var(--ink-faint); box-shadow: 0 0 0 3px var(--stale-bg); }

.pnl { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }
.pnl.pos { color: var(--pos); }
.pnl.neg { color: var(--neg); }
.pnl.is-stale { color: var(--stale) !important; }
.pos { color: var(--pos); }
.neg { color: var(--neg); }
.is-stale { color: var(--stale); }
.is-unknown { color: var(--ink-faint); }

.rung-strip { display: flex; gap: 3px; align-items: center; width: 100%; }
.rung {
  flex: 1 1 0;
  min-width: 10px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--ink-quat);
}
.rung--waiting { background: var(--ink-quat); }
.rung--resting { background: var(--ink); }
.rung--holding-profit { background: var(--pos); }
.rung--holding-loss { background: var(--neg); }

/* ---------------------------------------------------------------------- */
/* 14. BUTTONS — capsules, ≥44px on touch                                  */
/* ---------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 0 20px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--ink);
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: background 120ms ease, color 120ms ease, opacity 120ms ease;
}
.btn:disabled, .btn[disabled] { opacity: 0.4; cursor: not-allowed; }
/* Still ≥36px: a "small" button on a phone is not a 26px target. */
.btn--sm { min-height: 36px; padding: 0 14px; font-size: var(--fs-callout); }

.btn--primary { background: var(--accent); color: var(--ink-on-accent); }
.btn--secondary { background: var(--fill); color: var(--ink); }
.btn--quiet { background: transparent; color: var(--accent); padding: 0 12px; }
.btn--danger { background: var(--neg); color: var(--ink-on-neg); }
.btn--danger-outline { background: var(--neg-bg); color: var(--neg); }

/* ---------------------------------------------------------------------- */
/* 15. FORMS                                                               */
/* ---------------------------------------------------------------------- */

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--space-4); }
.field-label { color: var(--ink-dim); }
.field-hint {
  font-size: var(--fs-callout);
  line-height: var(--lh-callout);
  color: var(--ink-dim);
}
.field-error { font-size: var(--fs-callout); color: var(--neg); }

/* 16px minimum on inputs or iOS Safari zooms the page on focus. */
.input, .select, textarea.input {
  min-height: var(--tap);
  padding: 0 12px;
  border: var(--hairline) solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font-size: 16px;
  width: 100%;
}
textarea.input { padding: 10px 12px; line-height: var(--lh-body); }
.input::placeholder { color: var(--ink-faint); }
.input:focus, .select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-fill); }
.input.is-invalid { border-color: var(--neg); }
.select {
  appearance: none;
  -webkit-appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 16px) calc(50% + 2px), calc(100% - 11px) calc(50% + 2px);
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 32px;
}

.toggle { display: inline-flex; align-items: center; gap: var(--space-3); cursor: pointer; font-size: var(--fs-body); min-height: var(--tap); }
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.toggle-track {
  flex: none;
  width: 51px; height: 31px;
  border-radius: var(--radius-pill);
  background: var(--fill-hover);
  position: relative;
  transition: background 160ms ease;
}
.toggle-track::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 27px; height: 27px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
  transition: transform 160ms ease;
}
.toggle input:checked + .toggle-track { background: var(--pos-line); }
.toggle input:checked + .toggle-track::after { transform: translateX(20px); }
.toggle input:focus-visible + .toggle-track { outline: 2px solid var(--accent); outline-offset: 2px; }

.radio-card-group { display: grid; gap: var(--space-2); }
.radio-card {
  display: block;
  min-height: var(--tap);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  background: var(--surface);
  cursor: pointer;
  box-shadow: inset 0 0 0 1px var(--separator);
}
.radio-card:has(input:checked) { box-shadow: inset 0 0 0 2px var(--accent); background: var(--accent-fill); }
.radio-card input { margin-right: var(--space-2); accent-color: var(--accent); }
.radio-card-title { font-size: var(--fs-body); font-weight: 600; color: var(--ink); display: inline; }
.radio-card-desc { font-size: var(--fs-callout); color: var(--ink-dim); margin-top: 2px; }

/* ---------------------------------------------------------------------- */
/* 16. CHART FRAME + SPARKLINE — full-bleed in its group on the phone      */
/* ---------------------------------------------------------------------- */

.chart-frame {
  background: var(--surface);
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-2);
  margin-bottom: var(--space-4);
}
.chart-frame--bare { background: transparent; padding: 0; }
.chart-frame-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  flex-wrap: wrap;
  padding: 0 var(--space-2);
  margin-bottom: var(--space-3);
}

.sparkline { width: 100%; height: 180px; overflow: visible; }
.sparkline .line { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.sparkline .area { fill: var(--fill); stroke: none; }
.sparkline.pos .line { stroke: var(--pos-line); }
.sparkline.pos .area { fill: var(--pos-bg); }
.sparkline.neg .line { stroke: var(--neg-line); }
.sparkline.neg .area { fill: var(--neg-bg); }
.sparkline .gridline { stroke: var(--separator); stroke-width: 1; stroke-dasharray: 2 4; vector-effect: non-scaling-stroke; }
.sparkline .baseline { stroke: var(--ink-quat); stroke-width: 1; stroke-dasharray: 4 4; vector-effect: non-scaling-stroke; }
.sparkline .axis { stroke: var(--separator); stroke-width: 1; vector-effect: non-scaling-stroke; }
.sparkline .tick-label {
  fill: var(--ink-faint);
  font-family: var(--font-ui);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  font-weight: 500;
}

/* ---------------------------------------------------------------------- */
/* 16b. LIVE HUD — ticker, candle chart, feed, ladder                      */
/* ---------------------------------------------------------------------- */

/* ---- ticker strip: the screen's pulse, one scrolling line ------------- */
/* Sits directly under the hero. Scrolls rather than wraps, because a HUD
   that reflows to two lines when a number gains a digit is not a HUD. */
.hud-ticker {
  display: flex;
  gap: var(--space-2);
  align-items: stretch;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin-bottom: var(--space-4);
  padding-bottom: 2px;
}
.hud-ticker::-webkit-scrollbar { display: none; }

.hud-cell {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.hud-label {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
}
.hud-value {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: var(--fs-title3);
  line-height: var(--lh-title3);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  white-space: nowrap;
}
.hud-value .pos { color: var(--pos); }
.hud-value .neg { color: var(--neg); }
.hud-delta { font-size: var(--fs-callout); font-weight: 600; }
.hud-foot { display: flex; align-items: center; gap: 4px; }

/* A value that just changed flashes its tint for one beat. Tiny, and the
   only motion on the page besides the heartbeat dot. */
.hud-value.is-bumped-up { animation: jb-bump-up 600ms ease-out; }
.hud-value.is-bumped-down { animation: jb-bump-down 600ms ease-out; }
@keyframes jb-bump-up { 0% { color: var(--pos); } 100% { color: var(--ink); } }
@keyframes jb-bump-down { 0% { color: var(--neg); } 100% { color: var(--ink); } }

/* ---- liveness pulse: one beat per heartbeat interval ------------------ */
.liveness--live .liveness-dot { animation: jb-pulse-ring 30s ease-out infinite; }
@keyframes jb-pulse-ring {
  0%   { box-shadow: 0 0 0 0 var(--live-bg); }
  4%   { box-shadow: 0 0 0 7px rgba(0, 0, 0, 0); }
  5%   { box-shadow: 0 0 0 0 var(--live-bg); }
  100% { box-shadow: 0 0 0 3px var(--live-bg); }
}

/* ---- candle chart ---------------------------------------------------- */
.chart { position: relative; width: 100%; }
.chart-svg {
  width: 100%;
  display: block;
  /* A finger inspecting a candle must not scroll the page underneath. */
  touch-action: none;
}

.chart-candle.is-up { stroke: var(--pos-line); fill: var(--pos-line); }
.chart-candle.is-down { stroke: var(--neg-line); fill: var(--neg-line); }
.chart-wick { stroke-width: 1; vector-effect: non-scaling-stroke; }
.chart-body { stroke: none; }

.chart-vol { opacity: 0.32; stroke: none; }
.chart-vol.is-up { fill: var(--pos-line); }
.chart-vol.is-down { fill: var(--neg-line); }

.chart-sma { fill: none; stroke: var(--accent); stroke-width: 1.5; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.chart-band { fill: var(--accent-fill); stroke: none; }

.chart-mark { stroke: var(--ink); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.chart-mark-label { fill: var(--ink); font-family: var(--font-ui); font-size: 10px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* Rung lines carry the rung's own state colour, and a label in the gutter
   so the line is never colour-only. */
.chart-rung { stroke-width: 1; stroke-dasharray: 2 4; vector-effect: non-scaling-stroke; stroke: var(--ink-quat); }
.chart-rung--resting { stroke: var(--ink); stroke-dasharray: none; }
.chart-rung--holding-profit { stroke: var(--pos); stroke-dasharray: none; }
.chart-rung--holding-loss { stroke: var(--neg); stroke-dasharray: none; }
.chart-rung-label { fill: var(--ink-faint); font-family: var(--font-ui); font-size: 9px; font-weight: 600; font-variant-numeric: tabular-nums; }
.chart-rung-label--resting { fill: var(--ink); }
.chart-rung-label--holding-loss { fill: var(--neg); }
.chart-rung-label--holding-profit { fill: var(--pos); }

.chart-cross { stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 2 3; vector-effect: non-scaling-stroke; }

.chart-tip {
  position: absolute;
  top: 4px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 6px 9px;
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow-float);
  font-size: var(--fs-caption);
  line-height: 14px;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  white-space: nowrap;
}
.chart-tip-time { font-weight: 700; color: var(--ink); margin-bottom: 2px; }
.chart-tip-row { display: flex; justify-content: space-between; gap: 10px; color: var(--ink-dim); }
.chart-tip-row b { font-weight: 600; color: var(--ink); }
.chart-tip-row b.pos { color: var(--pos); }
.chart-tip-row b.neg { color: var(--neg); }

.chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-2);
  font-size: var(--fs-caption);
  color: var(--ink-dim);
}
.chart-legend span { display: inline-flex; align-items: center; gap: 5px; }
.chart-legend i { width: 14px; height: 0; border-top: 2px solid currentColor; display: inline-block; }

/* ---- live feed ------------------------------------------------------- */
.feed { display: flex; flex-direction: column; }
.feed-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: var(--row-h);
  padding: 10px var(--space-4);
  position: relative;
}
.feed-row + .feed-row::before {
  content: "";
  position: absolute;
  left: calc(var(--space-4) + 15px);
  right: 0;
  top: 0;
  height: var(--hairline);
  background: var(--separator);
  transform: scaleY(0.5);
  transform-origin: top;
}
.feed-dot {
  flex: none;
  width: 7px; height: 7px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--ink-quat);
}
.feed-row--fill .feed-dot { background: var(--pos); }
.feed-row--refusal .feed-dot { background: var(--neg); }
/* Ink, matching .rung--resting: a resting order is a STATE, and the state
   ramp is quaternary ink → ink → pos/neg. .spinner-dot keeps accent on
   purpose — it marks the viewer's OWN action in flight, which is the one
   thing accent is for. */
.feed-row--order .feed-dot { background: var(--ink); }
.feed-row--heartbeat .feed-dot { background: var(--live); }
/* A cancel is not a refusal: nothing was denied, an order was withdrawn.
   Warn, not negative — the money colours stay for money. */
.feed-row--cancel .feed-dot { background: var(--warn); }

/* Verbatim machine strings inside a row or a sheet: the deny name an
   operator greps for, or the CLI they can copy. Set in the code font so
   they are visibly NOT prose. */
.feed-code, .dialog-code {
  font-family: var(--font-code);
  font-size: 0.92em;
  background: var(--fill);
  border-radius: 5px;
  padding: 1px 5px;
  color: var(--ink);
}
.dialog-code { display: inline-block; margin-top: 2px; word-break: break-all; }
.dialog-code-label {
  display: block;
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.feed-age { margin-left: auto; flex: none; padding-top: 2px; }
.feed .row-sub { overflow-wrap: anywhere; }

/* ---- rung ladder widget ---------------------------------------------- */
/* A vertical price axis: every rung at its own height, the mark price as a
   line across it, and the distance a price has to travel to reach each. */
.ladder { position: relative; padding: var(--space-2) 0; }
.ladder-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: 34px;
  padding: 0 var(--space-4);
  position: relative;
}
.ladder-tick {
  flex: none;
  width: 22px; height: 3px;
  border-radius: var(--radius-pill);
  background: var(--ink-quat);
}
/* Ink, not accent — same law as .rung--resting. A rung's state is DATA;
   accent means "you can touch this". I wrote the law and then missed this
   tick when fixing the strip. */
.ladder-row--resting .ladder-tick { background: var(--ink); }
.ladder-row--holding-profit .ladder-tick { background: var(--pos); }
.ladder-row--holding-loss .ladder-tick { background: var(--neg); }
.ladder-id { font-size: var(--fs-callout); font-weight: 600; color: var(--ink); white-space: nowrap; }
.ladder-px { margin-left: auto; font-size: var(--fs-body); font-weight: 500; font-variant-numeric: tabular-nums; color: var(--ink); }
.ladder-dist { flex: none; width: 62px; text-align: right; font-size: var(--fs-callout); font-variant-numeric: tabular-nums; color: var(--ink-dim); }

/* The mark row is the one thing in the ladder that is not a rung. */
.ladder-mark {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-1) 0;
  padding: 4px var(--space-4);
  background: var(--fill);
}
.ladder-mark .ladder-id { color: var(--ink-dim); }
.ladder-mark .ladder-px { font-weight: 700; }

@media (prefers-reduced-motion: reduce) {
  .hud-value.is-bumped-up, .hud-value.is-bumped-down { animation: none; }
  .liveness--live .liveness-dot { animation: none; }
}

/* ---------------------------------------------------------------------- */
/* 17. CALLOUTS, EMPTY STATE                                               */
/* ---------------------------------------------------------------------- */

.callout {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius);
  background: var(--fill);
  color: var(--ink);
  font-size: var(--fs-callout);
  line-height: var(--lh-body);
  margin-bottom: var(--space-3);
}
.callout-title {
  display: block;
  font-size: var(--fs-body);
  line-height: var(--lh-headline);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 3px;
}
.callout--info { background: var(--accent-fill); }
.callout--info .callout-title { color: var(--accent); }
.callout--warn { background: var(--warn-bg); }
.callout--warn .callout-title { color: var(--warn); }
.callout--neg { background: var(--neg-bg); }
.callout--neg .callout-title { color: var(--neg); }

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-6) var(--space-4);
  background: var(--surface);
  border-radius: var(--radius);
  color: var(--ink-dim);
}
.empty-state-headline {
  font-size: var(--fs-title3);
  line-height: var(--lh-title3);
  font-weight: 600;
  color: var(--ink);
}
.empty-state p { max-width: 46ch; font-size: var(--fs-callout); line-height: var(--lh-body); color: var(--ink-dim); }
.empty-state-action { margin-top: var(--space-2); }

/* ---------------------------------------------------------------------- */
/* 18. TABS                                                                */
/* ---------------------------------------------------------------------- */

/* Same capsule language as .segmented and .chips, and it scrolls rather
   than wrapping or widening the page. */
.tabs {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  border-radius: var(--radius-sm);
  background: var(--fill);
  margin-bottom: var(--space-4);
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex: none;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  padding: 0 14px;
  border-radius: 6px;
  font-size: var(--fs-callout);
  font-weight: 600;
  color: var(--ink-dim);
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}
.tab.is-active { background: var(--surface-2); color: var(--ink); box-shadow: none; }

/* ---------------------------------------------------------------------- */
/* 19. KEY-VALUE LIST                                                      */
/* ---------------------------------------------------------------------- */

.kv-list { display: flex; flex-direction: column; }
.kv-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 32px;
  padding: 6px 0;
}
.kv-row + .kv-row { box-shadow: inset 0 1px 0 var(--separator); }
.kv-key { font-size: var(--fs-callout); color: var(--ink-dim); }
.kv-value {
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ---------------------------------------------------------------------- */
/* 20. STEPPER, SKELETON, SPINNER, GHOST ROW                               */
/* ---------------------------------------------------------------------- */

.stepper { display: flex; align-items: center; gap: var(--space-2); margin-bottom: var(--space-4); flex-wrap: wrap; }
.stepper-step { display: inline-flex; align-items: center; gap: 6px; }
.stepper-num {
  width: 22px; height: 22px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--fill);
  color: var(--ink-dim);
  font-size: var(--fs-caption);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.stepper-step.is-active .stepper-num { background: var(--accent); color: var(--ink-on-accent); }
.stepper-step.is-done .stepper-num { background: var(--pos-bg); color: var(--pos); }
.stepper-label { font-size: var(--fs-callout); font-weight: 500; color: var(--ink-dim); }
.stepper-step.is-active .stepper-label { color: var(--ink); font-weight: 600; }
.stepper-connector { flex: 1 1 12px; min-width: 12px; height: 2px; border-radius: 2px; background: var(--fill); }

.skeleton {
  border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--fill) 25%, var(--fill-hover) 37%, var(--fill) 63%);
  background-size: 400% 100%;
  animation: jb-shimmer 1.4s ease infinite;
  min-height: 12px;
}
@keyframes jb-shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

.spinner-dot {
  display: inline-block;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--accent);
  animation: jb-pulse 1s ease-in-out infinite;
  margin-right: 6px;
  vertical-align: middle;
}
@keyframes jb-pulse { 0%, 100% { opacity: 0.25; } 50% { opacity: 1; } }

.ghost-row, .ghost-row-tr td {
  color: var(--ink-dim);
  font-size: var(--fs-callout);
  background: var(--accent-fill);
}
.ghost-row { padding: 10px var(--space-4); border-radius: var(--radius-sm); }

@media (prefers-reduced-motion: reduce) {
  .skeleton, .spinner-dot { animation: none; }
  .row--expandable::after { transition: none; }
}

/* ---------------------------------------------------------------------- */
/* 21. TOAST                                                               */
/* ---------------------------------------------------------------------- */

/* Above the tab bar, not under it. */
.toast-stack {
  position: fixed;
  left: var(--space-4);
  right: var(--space-4);
  bottom: calc(var(--tabbar-h) + var(--safe-b) + var(--space-3));
  z-index: 120;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.toast {
  padding: 12px var(--space-4);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font-size: var(--fs-callout);
  box-shadow: var(--shadow-float);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.toast--pos { box-shadow: var(--shadow-float), inset 3px 0 0 var(--pos); }
.toast--neg { box-shadow: var(--shadow-float), inset 3px 0 0 var(--neg); }
.toast--warn { box-shadow: var(--shadow-float), inset 3px 0 0 var(--warn); }

/* ---------------------------------------------------------------------- */
/* 22. AUTH LAYOUT                                                         */
/* ---------------------------------------------------------------------- */

.auth-brand, .auth-footer { display: none; }

html.layout-auth .sidebar,
html.layout-auth .topbar,
html.layout-auth .bottom-nav,
html.layout-auth .bottom-sheet-backdrop,
html.layout-auth .tenant-view-banner { display: none !important; }

html.layout-auth .app-shell {
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  grid-template-areas: "main";
}
html.layout-auth .main {
  grid-area: main;
  max-width: 560px;
  margin: 0 auto;
  padding: calc(var(--space-8) + var(--safe-t)) var(--space-4) var(--space-8);
}
html.layout-auth .auth-brand {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
  font-size: var(--fs-headline);
  font-weight: 600;
  color: var(--ink-dim);
}
html.layout-auth .auth-brand .mark {
  width: 26px; height: 26px;
  border-radius: 7px;
  background: var(--ink);
  color: var(--canvas);
  display: grid;
  place-items: center;
  font-size: var(--fs-caption);
  font-weight: 700;
}
html.layout-auth .auth-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  box-shadow: inset 0 1px 0 var(--separator);
  font-size: var(--fs-callout);
  color: var(--ink-dim);
}

/* ---------------------------------------------------------------------- */
/* 23. UTILITIES                                                           */
/* ---------------------------------------------------------------------- */

.icon { width: 20px; height: 20px; flex: none; }
[hidden] { display: none !important; }

/* Hover belongs to devices that have a pointer. Adding it here instead of
   in the base keeps a tapped control from staying "hovered" on a phone. */
@media (hover: hover) and (pointer: fine) {
  a:hover { color: var(--accent-hover); }
  .btn:hover { background: var(--fill-hover); }
  .btn--primary:hover { background: var(--accent-hover); color: var(--ink-on-accent); }
  .btn--secondary:hover { background: var(--fill-hover); }
  .btn--quiet:hover { background: var(--accent-fill); color: var(--accent); }
  .btn--danger:hover { background: var(--neg-hover); color: var(--ink-on-neg); }
  .btn--danger-outline:hover { background: var(--neg-border); color: var(--neg); }
  .row--link:hover, .row--expandable:hover { background: var(--surface-3); }
  .tab:hover, .segmented > *:hover { color: var(--ink); }
  .sidebar-link:hover { background: var(--fill); }
    .tenant-switcher:hover { background: var(--fill-hover); }
  .radio-card:hover { background: var(--surface-3); }
  .table th.sortable:hover { color: var(--ink); }
  .chips > *:hover { color: var(--ink); }
}

/* ====================================================================== */
/* 24. TABLET — from 768: an icon rail replaces the tab bar               */
/* ====================================================================== */

@media (min-width: 768px) {
  :root {
    --fs-display: 44px;
    --lh-display: 48px;
    --topbar-h: 52px;
  }

  .app-shell {
    grid-template-columns: var(--sidebar-rail-w) 1fr;
    grid-template-rows: var(--topbar-h) 1fr;
    grid-template-areas: "sidebar topbar" "sidebar main";
  }

  .bottom-nav, .bottom-sheet-backdrop { display: none !important; }

  .main {
    padding: var(--space-5) var(--space-6) var(--space-12);
    max-width: 1120px;
  }

  .sidebar {
    grid-area: sidebar;
    position: sticky;
    top: 0;
    align-self: start;
    height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-2) var(--space-3);
    background: var(--material-bg);
    -webkit-backdrop-filter: blur(24px) saturate(180%);
    backdrop-filter: blur(24px) saturate(180%);
    overflow-y: auto;
    overflow-x: hidden;
    z-index: 30;
  }
  .sidebar-brand { display: flex; align-items: center; justify-content: center; min-height: 32px; }
  .sidebar-brand .mark {
    flex: none;
    width: 28px; height: 28px;
    border-radius: 8px;
    background: var(--ink);
    color: var(--canvas);
    display: grid;
    place-items: center;
    font-size: var(--fs-caption);
    font-weight: 700;
    text-transform: none;
  }
  .sidebar-brand .label { display: none; }

  .sidebar-group { display: flex; flex-direction: column; align-items: center; gap: 2px; width: 100%; }
  .sidebar-group-label { display: none; }
  .sidebar-group ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; gap: 2px; width: 100%; }

  .sidebar-link {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px; height: 40px;
    padding: 0;
    border-radius: var(--radius-sm);
    color: var(--ink);
  }
  .sidebar-link .icon { width: 20px; height: 20px; color: var(--ink-dim); }
  .sidebar-link .label { display: none; }
  .sidebar-link.is-active { background: var(--accent-fill); }
  .sidebar-link.is-active .icon { color: var(--accent); }

  .sidebar-footer { margin-top: auto; display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
  .sidebar-mode-btn { width: 40px; min-height: 40px; padding: 0; overflow: hidden; }
  .sidebar-mode-btn .label {
    position: absolute;
    width: 1px; height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .sidebar-mode-btn::after {
    content: "OP";
    font-size: var(--fs-caption);
    font-weight: 700;
    color: var(--ink-dim);
  }
  .sidebar-collapse-btn { display: none; }

  /* Toolbar regains the breadcrumb and the full switcher. */
  .topbar {
    justify-content: space-between;
    height: var(--topbar-h);
    padding: 0 var(--space-6);
  }
  .topbar-left { display: flex; align-items: center; gap: var(--space-3); min-width: 0; flex: 1 1 auto; overflow: hidden; }
  /* From 768 the sidebar and the breadcrumb both say where you are, so the
     back link would be a third answer to the same question. */
  .topbar-left .breadcrumb { display: flex; }
  .topbar-back { display: none; }
  .screen:has(.action-bar--sticky:not([hidden]):not([hidden] *)) { padding-bottom: 0; }
  .topbar-right { flex: 0 0 auto; gap: var(--space-3); }
  .topbar .liveness-why {
    position: static;
    width: auto; height: auto;
    margin: 0;
    clip-path: none;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .tenant-switcher { height: 28px; gap: 6px; padding: 0 10px; }
  .data-mode-switch .segmented > * { padding: 5px 10px; }
  .tenant-switcher .eyebrow { display: inline; letter-spacing: 0.05em; }
  
  /* A confirm becomes a centred dialog once there is room for one. */
  .dialog-backdrop { align-items: center; justify-content: center; padding: var(--space-4); }
  .dialog {
    width: min(420px, 100%);
    max-height: none;
    border-radius: var(--radius-lg);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.18), 0 2px 8px rgba(0, 0, 0, 0.08);
    padding: var(--space-5);
    text-align: center;
  }
  .dialog::before { display: none; }
  .dialog-consequences { text-align: left; }
  .dialog-footer { flex-direction: row; }
  .dialog-footer .btn { min-height: 36px; }
  .dialog { box-shadow: 0 24px 64px rgba(0, 0, 0, 0.7), 0 2px 8px rgba(0, 0, 0, 0.5); }

  /* No tab bar to clear. */
  .action-bar--sticky { position: static; padding: 0; background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
  .action-bar--sticky .btn { flex: 0 0 auto; min-height: 36px; }
  .toast-stack { left: auto; right: var(--space-5); bottom: var(--space-5); }
  .toast { min-width: 240px; max-width: 360px; }

  .stat-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-3); }
  .btn { min-height: 36px; padding: 0 16px; }
  .btn--sm { min-height: 28px; padding: 0 12px; }
  .input, .select, textarea.input { min-height: 34px; font-size: var(--fs-body); }
  .toggle-track { width: 40px; height: 24px; }
  .toggle-track::after { width: 20px; height: 20px; }
  .toggle input:checked + .toggle-track::after { transform: translateX(16px); }
  .chart-frame { padding: var(--space-4); }
  .sparkline { height: 200px; }
}

/* ====================================================================== */
/* 25. DESKTOP — from 1024: full sidebar, and tables become grids again    */
/* ====================================================================== */

@media (min-width: 1024px) {
  /* The strip scrolls on a phone, where a half-visible next cell is the
     affordance that says "there is more". With a mouse there is no such
     hint, so a cell clipped 20px off the right edge just reads as a broken
     render. From 1024 the strip WRAPS instead of scrolling.

     Wrapping rather than shrinking-to-fit is deliberate: five cells will
     not fit one 1024 row without ellipsizing "$3,812.99 / $20,000.00" down
     to "$3,812.99 / …", and truncating the limit is losing the half of the
     sentence that says what 19% is 19% OF. A second row costs 40px; a
     hidden money number costs the reader the meaning. */
  .hud-ticker { overflow-x: visible; flex-wrap: wrap; }
  /* Content-sized, not stretched: a single cell wrapping to row two
     and spanning the full width reads as a different kind of element. */
  .hud-cell { flex: 0 1 auto; min-width: 0; }

  .tag.data-mode-tag { display: inline-flex; }

  .app-shell { grid-template-columns: var(--sidebar-w) 1fr; }
  .app-shell.is-collapsed { grid-template-columns: var(--sidebar-rail-w) 1fr; }

  .main { padding: var(--space-6) var(--space-8) var(--space-12); }

  .sidebar {
    align-items: stretch;
    gap: var(--space-5);
    padding: var(--space-4) var(--space-3) var(--space-3);
  }
  .sidebar-brand { justify-content: flex-start; gap: var(--space-2); padding: var(--space-1) var(--space-2) 0; }
  .sidebar-brand .mark { width: 26px; height: 26px; border-radius: 7px; }
  .sidebar-brand .label {
    display: block;
    font-size: var(--fs-headline);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--ink);
    white-space: nowrap;
  }
  .sidebar-group { align-items: stretch; }
  .sidebar-group-label { display: block; padding: 0 var(--space-2) var(--space-2); }
  .sidebar-group ul { align-items: stretch; gap: 1px; }

  .sidebar-link {
    justify-content: flex-start;
    gap: 10px;
    width: auto; height: 32px;
    padding: 0 10px;
    font-size: var(--fs-body);
    font-weight: 500;
  }
  .sidebar-link .icon { width: 17px; height: 17px; }
  .sidebar-link .label { display: block; white-space: nowrap; }
  .sidebar-link.is-active { color: var(--accent); font-weight: 600; }

  .sidebar-footer { flex-direction: row; align-items: center; gap: var(--space-2); padding-top: var(--space-3); }
  .sidebar-mode-btn { flex: 1; width: auto; min-height: 28px; padding: 0 12px; }
  .sidebar-mode-btn::after { display: none; }
  .sidebar-mode-btn .label {
    position: static;
    width: auto; height: auto;
    clip-path: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .sidebar-collapse-btn {
    display: grid;
    place-items: center;
    flex: none;
    width: 28px; height: 28px;
    border: 0;
    border-radius: var(--radius-pill);
    background: var(--fill);
    color: var(--ink-dim);
    cursor: pointer;
  }

  .app-shell.is-collapsed .sidebar { align-items: center; padding-left: var(--space-2); padding-right: var(--space-2); }
  .app-shell.is-collapsed .sidebar-brand .label,
  .app-shell.is-collapsed .sidebar-group-label,
  .app-shell.is-collapsed .sidebar-link .label,
  .app-shell.is-collapsed .sidebar-mode-btn { display: none; }
  .app-shell.is-collapsed .sidebar-link { justify-content: center; padding: 0; width: 44px; }
  .app-shell.is-collapsed .sidebar-collapse-btn { transform: rotate(180deg); }
  .app-shell.is-collapsed .sidebar-footer { justify-content: center; }

  .topbar { padding: 0 var(--space-8); }

  /* ---- tables become real grids again ---- */
  .table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .table thead { display: table-header-group; }
  .table table { display: table; width: 100%; border-collapse: collapse; }
  .table tbody { display: table-row-group; }
  .table tr { display: table-row; }
  .table td { display: table-cell; }
  .table th {
    display: table-cell;
    text-align: left;
    font-size: var(--fs-caption);
    line-height: var(--lh-caption);
    font-weight: 600;
    letter-spacing: 0.055em;
    text-transform: uppercase;
    color: var(--ink-dim);
    padding: var(--space-3) var(--space-4);
    white-space: nowrap;
    background: var(--surface);
    position: sticky;
    top: 0;
    z-index: 1;
    box-shadow: inset 0 -1px 0 var(--separator);
  }
  .table td {
    padding: 0 var(--space-4);
    height: var(--row-h);
    min-height: 0;
    font-size: var(--fs-body);
    vertical-align: middle;
    text-align: left;
  }
  .table td::before { content: none; }
  .table tbody tr { padding: 0; }
  .table tbody tr + tr { box-shadow: none; }
  .table tbody tr + tr td { box-shadow: inset 0 1px 0 var(--separator); }
  .table td.num, .table th.num { text-align: right; }
  .table th.sortable { cursor: pointer; }
  .table th.is-asc::after { content: " ↑"; color: var(--accent); }
  .table th.is-desc::after { content: " ↓"; color: var(--accent); }

}

/* --- screens/operator.html --- */

  .screen[data-route="tenants"] .op-tenant-actions { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); width: 100%; }
  .screen[data-route="tenants"] .op-tenant-buttons { display: flex; gap: var(--space-2); flex-wrap: wrap; }
  .screen[data-route="accounts"] .op-account-detail { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--space-2); width: 100%; }
  .screen[data-route="accounts"] .op-custody-tags { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
  .screen[data-route="health"] .op-freshness-bar { width: 120px; height: 4px; border-radius: var(--radius-pill); background: var(--fill); overflow: hidden; flex: none; }
  .screen[data-route="health"] .op-freshness-bar > div { height: 100%; }
  .op-drawer { background: var(--surface-2); margin-top: var(--space-2); }
  .op-drawer-actions { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
  /* Base (mobile): wrap "no session bound yet" to two short lines so its
     .row-value column doesn't force-shrink the title/subtitle next to it.
     From 768 up there's room for the phrase on one line, same as before. */
  .screen[data-route="accounts"] .op-no-session { white-space: normal; display: inline-block; max-width: 78px; text-align: right; }
  @media (min-width: 768px) {
    .screen[data-route="accounts"] .op-no-session { white-space: nowrap; display: inline; max-width: none; }
  }

  /* Mobile-first pass (BRIEF.md §7 / CONTRACT.md, CTO 2026-08-25). Tenant and
     Account rows now use the OFFICIAL .row--expandable/.row-detail — app.js
     owns the open/close toggle and the chevron is drawn by that component's
     own CSS, so nothing screen-local is needed for either. App.confirm is
     also a half-sheet on the phone by CSS alone now (Kill/Force-close/Save-
     limits included) — nothing to branch on here either. What's left as
     genuinely mine: the internal layout of the View as/Limits/Provision/Kill
     button cluster inside a tenant's .row-detail, and Health's tile/bar
     sizing. */
  @media (max-width: 430px) {
    .screen[data-route="registrations"] .op-drawer-actions,
    .screen[data-route="tenants"] .op-drawer-actions,
    .screen[data-route="accounts"] .op-drawer-actions {
      flex-direction: column;
    }
    .screen[data-route="registrations"] .op-drawer-actions .btn,
    .screen[data-route="tenants"] .op-drawer-actions .btn,
    .screen[data-route="accounts"] .op-drawer-actions .btn {
      width: 100%;
    }

    /* View as/Limits/Provision stay one horizontal row of small pills; Kill
       gets its own full-width line below them (flex-wrap + forced 100%
       width pushes it there without changing DOM order or introducing a
       second solid-red button stacked among normal rows). */
    .screen[data-route="tenants"] .op-tenant-actions { flex-direction: column; align-items: flex-start; }
    .screen[data-route="tenants"] .op-tenant-buttons [data-action="kill"] { width: 100%; }

    .screen[data-route="health"] .stat-grid { grid-template-columns: 1fr 1fr; }
    /* Wallet name + bar + age chip + FRESH/OVER tag all have to share one
       390px row — shrink the bar rather than drop it, so the shape (fresh
       vs. over the 180s bar) is still visible at a glance, per BRIEF.md §7. */
    .screen[data-route="health"] .op-freshness-bar { width: 40px; }
    .screen[data-route="health"] .row-aside { flex-wrap: wrap; justify-content: flex-end; }
  }

