@import url('https://fonts.googleapis.com/css2?family=Libre+Caslon+Display&family=Libre+Caslon+Text:ital,wght@0,400;0,700;1,400&family=Libre+Franklin:wght@300;400;500;600;700&display=swap');

/*
  Numla Quant — "Financial Broadsheet"
  Warm ivory paper, sepia ink, hairline rules. Caslon for identity & hero
  figures; Libre Franklin (Franklin Gothic lineage) for all UI and data.
  Signal colour (green/amber/red) is rare and reserved for value/score bands.
*/

:root {
  /* ---- surfaces (OKLCH, tinted warm toward paper hue) ---- */
  --paper:     oklch(0.975 0.009 85);   /* page — warm ivory */
  --surface:   oklch(0.993 0.005 85);   /* raised — near-white sheet */
  --surface-2: oklch(0.948 0.011 82);   /* oat — inputs, hover fills */
  --surface-3: oklch(0.915 0.013 80);   /* deeper oat — pressed/segmented */

  /* legacy aliases (kept so JS reading these tokens still resolves) */
  --bg:      var(--paper);
  --panel:   var(--surface);
  --panel-2: var(--surface-2);
  --logo-bg: transparent;

  /* ---- ink / text ---- */
  --ink:    oklch(0.255 0.018 55);   /* deep sepia-black */
  --ink-2:  oklch(0.498 0.016 60);   /* muted */
  --ink-3:  oklch(0.635 0.013 65);   /* faint */
  --ink-4:  oklch(0.745 0.011 70);   /* empty / placeholder */
  --text:  var(--ink);
  --muted: var(--ink-2);
  --faint: var(--ink-3);
  --empty: var(--ink-4);

  /* ---- rules ---- */
  --rule:        oklch(0.876 0.010 78);
  --rule-strong: oklch(0.788 0.013 72);
  --line: var(--rule);

  /* ---- editorial accent (brand ink-blue) ---- */
  --accent:     #0f6d92;
  --on-accent:  #fbf8f1;
  --focus-ring: rgba(15, 109, 146, .20);
  --brand-blue:  #0d77a1;
  --brand-green: #1d6c37;

  /* ---- signal colours (hex: also fed to the charting lib) ---- */
  --good: #2f7d4e;   /* forest green — strong scores, gains, up candles */
  --mid:  #b07d23;   /* ochre — middling scores */
  --bad:  #b23a2e;   /* oxblood — weak scores, losses, down candles */

  /* score-band tags (tinted toward paper; not concatenated in JS) */
  --good-bg:  oklch(0.935 0.045 150);  --good-ink:  oklch(0.420 0.100 152);
  --mid-bg:   oklch(0.940 0.052 90);   --mid-ink:   oklch(0.455 0.090 78);
  --bad-bg:   oklch(0.932 0.052 33);   --bad-ink:   oklch(0.470 0.140 31);

  /* alerts badges */
  --good-soft:  color-mix(in srgb, var(--good) 13%, var(--paper));
  --muted-soft: color-mix(in srgb, var(--ink-2) 11%, var(--paper));

  /* pipeline verdicts — ink + tinted-paper background, reusing the score palette.
     Researching is a quiet neutral; Too Hard is a desaturated slate, kept distinct
     from Pass's oxblood. */
  --v-buy:        var(--good);
  --v-watchlist:  var(--mid);
  --v-pass:       var(--bad);
  --v-toohard:    oklch(0.470 0.012 250);
  --v-researching: var(--ink-2);
  --v-buy-soft:        color-mix(in srgb, var(--good) 14%, var(--paper));
  --v-watchlist-soft:  color-mix(in srgb, var(--mid) 16%, var(--paper));
  --v-pass-soft:       color-mix(in srgb, var(--bad) 13%, var(--paper));
  --v-toohard-soft:    color-mix(in srgb, var(--v-toohard) 12%, var(--paper));
  --v-researching-soft: color-mix(in srgb, var(--ink-2) 9%, var(--paper));

  /* ---- table ---- */
  --row-hover: oklch(0.952 0.014 82);
  --row-alt:   transparent;            /* ledger uses rules, not zebra */
  --star:      #c1851a;
  --star-off:  oklch(0.805 0.012 75);

  /* ---- chart + valuation overlays (resolved in JS via getComputedStyle) ---- */
  --chart-grid: oklch(0.908 0.010 80);
  /* equity-curve area fill — a soft accent wash fading to paper */
  --equity-fill-top:    color-mix(in srgb, var(--accent) 20%, transparent);
  --equity-fill-bottom: color-mix(in srgb, var(--accent) 2%, transparent);
  --ov-last:    oklch(0.430 0.012 60);   /* graphite */
  --ov-buy:     var(--good);
  --ov-mos:     #2b7fb0;
  --ov-sticker: var(--mid);
  --ov-pbt:     #7a52b3;
  --ov-10cap:   #c4663a;                 /* rust */
  /* margin-of-safety zone shaded between the Buy and Sticker price lines */
  --mos-band:   color-mix(in srgb, var(--good) 9%, transparent);
  --ma-10:      #c77d11;                 /* amber */
  --ma-50:      var(--accent);
  --ma-200:     var(--bad);
  --vol-up:     color-mix(in srgb, var(--good) 24%, transparent);
  --vol-down:   color-mix(in srgb, var(--bad) 24%, transparent);
  /* oscillator sub-panels (RSI / MACD) */
  --osc-rsi:       #6a4fb3;               /* violet */
  --osc-macd:      var(--accent);         /* teal — MACD line */
  --osc-signal:    #b07d23;               /* ochre — signal line */
  --osc-hist-up:   color-mix(in srgb, var(--good) 45%, transparent);
  --osc-hist-down: color-mix(in srgb, var(--bad) 45%, transparent);
  --osc-stoch-k:   #2f7ec2;               /* blue — %K line */
  --osc-stoch-d:   #c2502f;               /* rust — %D (trigger) line */

  /* ---- effects ---- */
  --shadow-card: 0 1px 2px rgba(72, 50, 22, .06), 0 18px 34px -22px rgba(72, 50, 22, .26);

  /* ---- spacing (4pt) ---- */
  --space-xs: 4px;  --space-sm: 8px;  --space-md: 12px;
  --space-lg: 16px; --space-xl: 24px; --space-2xl: 32px;

  /* ---- page gutter ---- the fluid inline padding on the pipeline content
     column (#main). The pipeline tabs run full-bleed inside this gutter, sharing
     one left/right edge that lines up with the masthead — matching the Scores
     ledger. */
  --gutter:  clamp(20px, 4vw, 44px);

  /* ---- type ---- */
  --font-display: "Libre Caslon Display", "Hoefler Text", Georgia, serif;
  --font-serif:   "Libre Caslon Text", Georgia, serif;
  --font-sans:    "Libre Franklin", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body {
  background: var(--paper);
  color: var(--ink);
  font: 400 14px/1.45 var(--font-sans);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "kern" 1, "liga" 1;
  display: flex;
  flex-direction: column;
  height: 100vh;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 2px; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* small-caps grotesque label, the workhorse editorial device */
.eyebrow, .meta, thead .label, nav.tabs a, .side h2,
.field label, table.alist th, thead .filter input::placeholder {
  font-family: var(--font-sans);
}

/* ====================================================================
   Masthead
   ==================================================================== */
header {
  padding: 11px 22px 9px;
  /* Pinned so the bar keeps one height across routes regardless of which
     controls a page mounts (Scores adds a taller search input than the
     brand/buttons on Watchlist/Alerts). Content is centered, so shorter
     pages just gain symmetric breathing room. */
  min-height: 60px;
  background: var(--surface);
  border-top: 1px solid var(--rule);
  border-bottom: 3px double var(--rule-strong);
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
header h1 { font-size: 16px; margin: 0; font-weight: 600; }
header h1 span { color: var(--ink-2); font-weight: 400; }

.brand { display: inline-flex; align-items: center; gap: 10px; text-decoration: none; }
.brand:hover { text-decoration: none; }
.brand-logo {
  height: 30px; width: 30px; border-radius: 0; background: var(--logo-bg);
  padding: 0; display: block; align-self: center;
}
.brand-name {
  font-family: var(--font-display);
  font-size: 22px; line-height: 1; font-weight: 400; color: var(--ink);
  letter-spacing: .1px; white-space: nowrap;
}
.brand-n { color: var(--brand-blue); }
.brand-q { color: var(--brand-green); }
.brand-sub {
  font-family: var(--font-sans);
  font-weight: 600; font-size: 9.5px; text-transform: uppercase; letter-spacing: .16em;
  color: var(--ink-2); margin-left: 2px;
}
nav.tabs {
  display: flex; gap: 18px; align-self: stretch; align-items: center;
  padding-left: 16px; margin-left: 2px;
}
nav.tabs a {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .11em;
  color: var(--ink-2); padding: 4px 0 5px; border-bottom: 2px solid transparent;
  transition: color .12s ease, border-color .12s ease;
}
nav.tabs a:hover { color: var(--ink); text-decoration: none; border-bottom-color: var(--rule-strong); }
nav.tabs a.active { color: var(--ink); border-bottom-color: var(--accent); }

/* vertical hairline divider between header control groups (e.g. after Horizons) */
.hsep {
  align-self: center; width: 1px; height: 20px; flex: none;
  background: var(--rule); margin: 0 -3px;
}
.hsep[hidden] { display: none; }

.grow { flex: 1; }
.meta {
  color: var(--ink-2); font-size: 10px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .12em; font-variant-numeric: tabular-nums;
}

.search {
  background: var(--surface-2); border: 1px solid var(--rule); color: var(--ink);
  border-radius: 4px; padding: 8px 12px; width: 240px; outline: none;
  font: 400 13px var(--font-sans);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.search:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.search::placeholder { color: var(--ink-3); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 30px; box-sizing: border-box;
  background: var(--surface); border: 1px solid var(--rule); color: var(--ink);
  border-radius: 4px; padding: 0 13px; cursor: pointer;
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .08em;
  transition: border-color .12s ease, background .12s ease;
}
.btn:hover { border-color: var(--rule-strong); background: var(--surface-2); }
.btn.primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent);
}
.btn.primary:hover { background: color-mix(in srgb, var(--accent) 88%, black); }

/* ---- Lucide icons (inline SVG, currentColor) ---- */
.ico { flex: none; display: inline-block; vertical-align: middle; }
@keyframes spin { to { transform: rotate(360deg); } }
.ico.spin { animation: spin .8s linear infinite; transform-origin: 50% 50%; }
/* A button mid-refresh spins its icon (e.g. the masthead "Refresh prices"). */
.btn.spin .ico { animation: spin .8s linear infinite; transform-origin: 50% 50%; }
.btn .ico { color: var(--ink-2); }            /* glyph a touch quieter than the label */
.btn:hover .ico { color: var(--ink); }
.btn.primary .ico { color: var(--on-accent); }

/* search field with a leading magnifier */
.search-wrap { position: relative; display: inline-flex; align-items: center; }
.search-wrap .search-ico { position: absolute; left: 10px; color: var(--ink-3); pointer-events: none; }
.search-wrap .search { padding-left: 32px; }

label.check {
  display: inline-flex; align-items: center; gap: 7px; color: var(--ink-2);
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .08em; cursor: pointer;
}
input[type="checkbox"] { accent-color: var(--accent); }

/* Toggle switch — checkbox semantics, broadsheet switch styling */
.check.toggle { gap: 9px; }
.check.toggle input[type="checkbox"] {
  -webkit-appearance: none; appearance: none; margin: 0; flex: none;
  position: relative; width: 32px; height: 18px; border-radius: 999px;
  background: var(--surface-3); border: 1px solid var(--rule-strong);
  cursor: pointer; outline: none;
  transition: background .14s ease, border-color .14s ease;
}
.check.toggle input[type="checkbox"]::after {
  content: ""; position: absolute; top: 1px; left: 1px;
  width: 14px; height: 14px; border-radius: 50%; background: var(--paper);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--ink) 22%, transparent);
  transition: transform .16s cubic-bezier(.2, .7, .3, 1);
}
.check.toggle input[type="checkbox"]:checked { background: var(--accent); border-color: var(--accent); }
.check.toggle input[type="checkbox"]:checked::after { transform: translateX(14px); }
.check.toggle input[type="checkbox"]:focus-visible { box-shadow: 0 0 0 3px var(--focus-ring); }

/* Edition picker — the ledger's sections, set as a run of broadsheet section heads */
.editions {
  display: inline-flex; align-items: center; gap: 16px;
  padding-left: 16px; margin-left: 2px; border-left: 1px solid var(--rule);
}
.editions .ed {
  background: none; border: 0; padding: 4px 0 5px; cursor: pointer;
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .11em;
  color: var(--ink-3); border-bottom: 2px solid transparent;
  transition: color .12s ease, border-color .12s ease;
}
.editions .ed:hover { color: var(--ink); border-bottom-color: var(--rule-strong); }
.editions .ed.active { color: var(--ink); border-bottom-color: var(--accent); }

/* Right-aligned action cluster: meta count + page buttons + Sign out. Pinned
   right so every masthead button stacks from the right edge. Wraps as one unit. */
.hdr-actions { display: inline-flex; align-items: center; gap: 16px; margin-left: auto; }

/* Top-right menu: page actions (e.g. Refresh prices) + Sign out collapse behind
   a hamburger button so the masthead stays uncluttered. */
.hdr-menu { position: relative; }
.hdr-menu-btn { padding: 0; width: 32px; }
.hdr-menu-btn.active { color: var(--ink); background: var(--surface-3); border-color: var(--rule-strong); }
.hdr-menu-pop {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 30; min-width: 212px; padding: 5px;
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 8px; box-shadow: var(--shadow-card);
}
.hdr-menu-pop[hidden] { display: none; }
.menu-group { display: flex; flex-direction: column; gap: 1px; }
/* Folio rule between groups — a full-bleed hairline, not a boxed divider. */
.menu-rule { height: 1px; background: var(--rule); margin: 5px -5px; }
/* Stack the buttons as full-width menu rows, left-aligned. */
.hdr-menu-pop .btn {
  width: 100%; justify-content: flex-start; min-height: 32px; gap: 9px;
  border-color: transparent; background: transparent; border-radius: 5px;
}
.hdr-menu-pop .btn:hover { background: var(--surface-2); border-color: transparent; }

/* A menu row that carries an inline control (the Trend window toggle) rather than
   being a button itself: label + icon on the left, control on the right. */
.menu-row {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  min-height: 32px; padding: 0 9px 0 11px;
}
.menu-row-label {
  display: inline-flex; align-items: center; gap: 9px; color: var(--ink);
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .08em;
}
.menu-row-label .ico { color: var(--ink-2); }

/* Segmented two-state toggle — broadsheet: hairline frame, ink-filled when active.
   The 1px inter-segment line is a divider, not a decorative accent stripe. */
.seg-toggle {
  display: inline-flex; flex: none; background: var(--surface);
  border: 1px solid var(--rule-strong); border-radius: 5px; overflow: hidden;
}
.seg-opt {
  -webkit-appearance: none; appearance: none; border: 0; background: transparent;
  cursor: pointer; padding: 4px 10px; color: var(--ink-3);
  /* Equal-width segments: the longest label ("TODAY") sets the floor so both
     halves match and the divider sits dead-center, regardless of label length. */
  min-width: 3.5rem; text-align: center;
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .07em;
  transition: color .12s ease, background .12s ease;
}
.seg-opt + .seg-opt { border-left: 1px solid var(--rule); }
.seg-opt[aria-pressed="false"]:hover { color: var(--ink); background: var(--surface-2); }
.seg-opt[aria-pressed="true"] { background: var(--accent); color: var(--on-accent); }
.seg-opt:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--focus-ring); }

/* Scores filter group — flows inline in the masthead on desktop; on phones it
   collapses behind the "Filters" disclosure button (see the mobile block). */
.hdr-tools { display: inline-flex; align-items: center; gap: 18px; }
.tools-toggle { display: none; }            /* disclosure trigger: phones only */
/* square icon-only button (Filters); pressed = the disclosure is open */
.icon-btn { padding: 0 9px; }
.tools-toggle.pressed { background: var(--surface-3); border-color: var(--rule-strong); }
.tools-toggle.pressed .ico { color: var(--ink); }

/* ====================================================================
   Ledger table
   ==================================================================== */
.table-wrap { flex: 1; overflow: auto; }
table { border-collapse: separate; border-spacing: 0; width: max-content; min-width: 100%; }

thead th {
  position: sticky; top: 0; z-index: 3; background: var(--surface);
  border-bottom: 2px solid var(--rule-strong); padding: 0; text-align: left; white-space: nowrap;
}
thead .label {
  padding: 11px 13px 5px; cursor: pointer; -webkit-user-select: none; user-select: none;
  font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink); display: flex; align-items: center; gap: 5px;
}
thead .label.right { flex-direction: row-reverse; }
thead .label:hover { color: var(--accent); }
thead .label .arrow { color: var(--accent); display: inline-flex; align-items: center; }
thead .label .arrow .ico { transition: transform .14s ease; }
thead .label .arrow.asc .ico { transform: rotate(180deg); }
thead .label .dim { color: var(--ink-3); font-weight: 400; letter-spacing: .02em; }
thead .filter { padding: 0 10px 9px; }
thead .filter input {
  width: 100%; min-width: 90px; background: var(--paper); border: 1px solid var(--rule);
  color: var(--ink); border-radius: 3px; padding: 4px 7px; font: 400 11px var(--font-sans); outline: none;
}
thead .filter input::placeholder { color: var(--ink-3); }
thead .filter input:focus { border-color: var(--accent); box-shadow: 0 0 0 2px var(--focus-ring); }

/* sticky ticker column — a true ledger column rule (1px, neutral) */
thead th.sticky, tbody td.sticky {
  position: sticky; left: 0; z-index: 2; background: var(--surface);
  border-right: 1px solid var(--rule);
}
thead th.sticky { z-index: 4; }
tbody td.sticky { background: var(--paper); }
tbody tr:hover td.sticky { background: var(--row-hover); }
tbody td.sticky a { color: var(--ink); font-weight: 600; letter-spacing: .02em; }
tbody td.sticky a:hover { color: var(--accent); }

tbody td {
  padding: 7px 13px; border-bottom: 1px solid var(--rule); white-space: nowrap;
  font-variant-numeric: tabular-nums; font-size: 13px; color: var(--ink);
}
td.num { text-align: right; }
tbody tr:hover td { background: var(--row-hover); }

.pill {
  display: inline-block; min-width: 2.6ch; text-align: center; padding: 1px 7px;
  border-radius: 3px; font-weight: 600; font-size: 12px; font-variant-numeric: tabular-nums;
}
/* Score pills (0–100) are fixed to a 3-digit width so a 2- and 3-digit score
   share one width — "88" and "100" line up in the column. Excludes the BUY/SELL
   signal capsules, which size to their text. */
.pill:not(.sig-pill) { min-width: calc(3ch + 16px); box-sizing: border-box; }
.pill[data-band="good"] { color: var(--good-ink); background: var(--good-bg); }
.pill[data-band="mid"]  { color: var(--mid-ink);  background: var(--mid-bg); }
.pill[data-band="bad"]  { color: var(--bad-ink);  background: var(--bad-bg); }
/* Neutral band for a combined signal whose three indicators disagree (MIXED) —
   deliberately quiet, distinct from the green/red of an actionable BUY/SELL. */
.pill[data-band="mixed"] { color: var(--ink-3); background: var(--muted-soft); }

/* MACD/STOCH/SMA/SIGNAL BUY/SELL pills (reuse the score-band palette) plus a
   "fresh" marker for a crossover that just happened, so a new flip stands out.
   Shaped as full capsules (rounded ends) to read distinctly from the squarer
   score pill — consistent across the roster, holdings table, and ticker chart. */
.sig-pill { letter-spacing: .04em; border-radius: 999px; padding: 3px 10px; }
/* Signal columns (MACD / STOCH / SMA 10 / SIGNAL) center their pill and header,
   distinct from right-aligned numeric columns and left-aligned text — so the
   roster and holdings tables read consistently. */
th.sig-col, td.sig-col { text-align: center; }
/* In a table cell, stack the small NEW / oversold-overbought tags on a line
   beneath the pill so the column stays narrow (instead of widening it inline). */
.sig-cell { display: inline-flex; flex-direction: column; align-items: center; line-height: 1.05; }
.sig-tags { display: flex; gap: 4px; margin-top: 1px; }
.sig-tags .sig-new, .sig-tags .sig-confirm { margin-left: 0; font-size: 8px; vertical-align: baseline; }
/* Subtle 20/80 confirmation tag for the stochastic signal (oversold/overbought).
   Quiet by design — secondary to the BUY/SELL pill. */
.sig-confirm {
  margin-left: 5px; font-size: 9px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; cursor: help; opacity: .8;
}
.sig-confirm.good { color: var(--good); }
.sig-confirm.bad  { color: var(--bad); }
/* Daily indicator badges (MACD, Stochastic) in the ticker toolbar, beside the
   last-price readout. */
.ind-signal { margin-left: 10px; display: inline-flex; align-items: center; gap: 6px; }
.ind-signal-label {
  font-size: 11px; font-weight: 600; letter-spacing: .02em; color: var(--ink-3);
  text-transform: none;
}
.sig-new {
  margin-left: 4px; font-size: 9px; font-weight: 700; letter-spacing: .06em;
  vertical-align: top; color: var(--brand-blue); cursor: help;
}

.empty { color: var(--ink-4); }
/* Scraped fallback shown when the live price is unavailable. */
.stale { color: var(--ink-3); font-style: italic; cursor: help; }

/* Last-price cell: the number with a trailing per-tick sparkline. */
.last-wrap { display: inline-flex; align-items: center; gap: 6px; justify-content: flex-end; }
.spark { display: block; overflow: visible; }
.spark polyline { fill: none; stroke: currentColor; stroke-width: 1.25; stroke-linejoin: round; stroke-linecap: round; }
.spark-up   { color: var(--good); }
.spark-down { color: var(--bad); }
.spark-flat { color: var(--ink-4); }


/* Next-earnings cell: the report date over a muted "days away" line. */
td.earn-cell { line-height: 1.25; }
.earn-date { display: block; font-variant-numeric: tabular-nums; }
.earn-days {
  display: block; font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.earn-days.earn-soon { color: var(--mid-ink); font-weight: 600; }   /* due within a week */
.earn-days.earn-past { color: var(--ink-4); font-style: italic; }   /* awaiting refresh */

/* Analyst Target cell: average target over an upside-vs-last · coverage line */
td.analyst-cell { line-height: 1.25; }
.analyst-target { display: block; font-variant-numeric: tabular-nums; }
.analyst-sub { display: block; font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.star {
  cursor: pointer; display: inline-block; line-height: 0; vertical-align: middle;
  color: var(--star-off);
  -webkit-user-select: none; user-select: none; transition: color .12s ease, transform .12s ease;
}
.star:hover { transform: scale(1.12); color: var(--star); }
.star.on { color: var(--star); }

#status, #pfstatus {
  padding: 56px 40px; text-align: center; color: var(--ink-2);
  font-size: 13px; letter-spacing: .01em;
}
#status.error, #pfstatus.error { color: var(--bad); }
code { background: var(--surface-2); padding: 2px 6px; border-radius: 3px; font-size: .9em; }

/* ====================================================================
   Ticker detail
   ==================================================================== */
.detail { flex: 1; display: flex; min-height: 0; }
.chart-col { flex: 1; display: flex; flex-direction: column; min-width: 0; padding: 18px 24px; gap: 14px; }
.chart-toolbar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

.ticker-title { display: flex; align-items: baseline; gap: 12px; }
/* Star is a flex item among baseline-aligned text; center it on the symbol. */
.ticker-title .star { align-self: center; }
.ticker-title .sym {
  font-family: var(--font-display); font-size: 30px; font-weight: 400; line-height: 1;
  color: var(--ink); letter-spacing: .2px;
}
.ticker-title .name {
  color: var(--ink); font-size: 16px; font-weight: 500; line-height: 1;
}
.ticker-title .name:empty { display: none; }
.ticker-title .sub {
  color: var(--ink-2); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .1em;
}

.seg { display: inline-flex; border: 1px solid var(--rule); border-radius: 5px; overflow: hidden; }
.seg button {
  background: var(--surface); color: var(--ink-2); border: none; padding: 7px 14px; cursor: pointer;
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .07em;
  border-left: 1px solid var(--rule);
}
.seg button:first-child { border-left: none; }
.seg button:hover { background: var(--surface-2); color: var(--ink); }
.seg button.active { background: var(--accent); color: var(--on-accent); }
.seg button:disabled { opacity: .35; cursor: not-allowed; }
.seg button:disabled:hover { background: var(--surface); color: var(--ink-2); }

/* interval row sits under the range row; big last price left, segment right */
.res-row, .overlay-row { margin-top: -4px; }
.res-label { font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-2); }
.last-price {
  font-family: var(--font-display); font-size: 28px; font-weight: 400; line-height: 1;
  color: var(--ink); letter-spacing: .2px; font-variant-numeric: tabular-nums;
}
.last-var {
  margin-left: 8px; font: 600 13px var(--font-sans); font-variant-numeric: tabular-nums;
}
.last-var.up { color: var(--good); }
.last-var.down { color: var(--bad); }

/* range picker — eight compact, evenly-spaced segments; scrolls if the toolbar
   gets too narrow rather than forcing the chart below the fold */
.seg-range { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
.seg-range::-webkit-scrollbar { display: none; }
.seg-range button { padding: 7px 11px; font-variant-numeric: tabular-nums; }

.overlay-toggles { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; }
.overlay-toggles > label {
  display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ink-2); cursor: pointer;
}
.swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; flex: none; }

/* Indicator dropdowns (SMA / MACD groups) */
.ind-dd { position: relative; }
.ind-dd-btn {
  display: inline-flex; align-items: center; gap: 5px; font-size: 12px; cursor: pointer;
  color: var(--ink-2); background: var(--surface-2); border: 1px solid var(--rule);
  border-radius: 6px; padding: 5px 9px;
}
.ind-dd-btn:hover { color: var(--ink); border-color: var(--rule-strong); }
.ind-dd-btn .ico { transition: transform .15s ease; }
.ind-dd.open .ind-dd-btn { color: var(--ink); background: var(--surface-3); border-color: var(--rule-strong); }
.ind-dd.open .ind-dd-btn .ico { transform: rotate(180deg); }
.ind-dd-menu {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 20; min-width: 196px; padding: 6px;
  display: flex; flex-direction: column; gap: 2px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 8px; box-shadow: var(--shadow-card);
}
.ind-dd-menu[hidden] { display: none; }
.ind-row {
  display: flex; align-items: center; gap: 8px; padding: 6px 8px;
  border-radius: 6px; cursor: pointer; font-size: 12px; color: var(--ink);
}
.ind-row:hover { background: var(--surface-2); }
.ind-row-label { flex: 1; }
/* toggle switch */
.tgl { position: relative; width: 30px; height: 16px; flex: none; }
.tgl input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.tgl-track {
  position: absolute; inset: 0; border-radius: 999px;
  background: var(--surface-3); border: 1px solid var(--rule-strong); transition: background .15s ease;
}
.tgl-track::after {
  content: ""; position: absolute; top: 1px; left: 1px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--surface); box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
  transition: transform .15s ease;
}
.tgl input:checked + .tgl-track { background: var(--accent); border-color: var(--accent); }
.tgl input:checked + .tgl-track::after { transform: translateX(14px); }

.chart-frame { position: relative; flex: 1; min-height: 320px; display: flex; }
#chart {
  flex: 1; min-height: 320px; border: 1px solid var(--rule); border-radius: 4px;
  overflow: hidden; background: var(--surface);
}
/* Crosshair OHLC legend overlaid top-left, tracking the hovered bar. */
.chart-legend {
  position: absolute; top: 8px; left: 10px; z-index: 4; pointer-events: none;
  font: 600 12px var(--font-sans); color: var(--ink-2); line-height: 1.55;
  font-variant-numeric: tabular-nums; max-width: calc(100% - 20px);
  text-shadow: 0 0 4px var(--surface), 0 0 4px var(--surface);
}
.chart-legend[hidden] { display: none; }
.chart-legend .lg-head { color: var(--ink); margin-right: 8px; }
.chart-legend .lg-k { color: var(--ink-3); margin-right: 1px; }
.chart-legend .lg-ohlc.up, .chart-legend .lg-chg.up { color: var(--good); }
.chart-legend .lg-ohlc.down, .chart-legend .lg-chg.down { color: var(--bad); }
.chart-legend .lg-chg { margin-left: 8px; }
.chart-legend .lg-vol { display: block; }
.chart-legend .lg-vol .lg-k { color: var(--ink-2); }

/* Shown centered over the chart when there are no bars to draw (failed/empty
   fetch), so the frame reads as an explained empty state, not a broken box. */
.chart-empty {
  position: absolute; inset: 0; z-index: 3; display: flex;
  align-items: center; justify-content: center; text-align: center;
  padding: 0 24px; color: var(--muted); font: 500 14px var(--font-sans);
  line-height: 1.5; pointer-events: none;
}
.chart-empty[hidden] { display: none; }

/* Price-scale toggles overlaid inside the chart, bottom-right against the price
   axis: A = auto-fit, L = logarithmic. Hidden until the chart is hovered (or a
   toggle is focused for keyboard users), like the native TradingView controls. */
.scale-toggles {
  position: absolute; right: 8px; bottom: 8px; z-index: 4; display: flex; gap: 3px;
  opacity: 0; transition: opacity .12s ease; pointer-events: none;
}
.chart-frame:hover .scale-toggles,
.scale-toggles:focus-within { opacity: 1; pointer-events: auto; }
.scale-toggles button {
  width: 22px; height: 22px; padding: 0; cursor: pointer; border-radius: 4px;
  font: 700 10px var(--font-sans); border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  color: var(--muted); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.scale-toggles button:hover { background: var(--surface-2); color: var(--ink); }
.scale-toggles button.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Export cluster overlaid top-right of the chart: copy-to-clipboard + PNG
   download. Same hover-reveal treatment as the scale toggles. */
.chart-export {
  position: absolute; right: 8px; top: 8px; z-index: 4; display: flex; gap: 3px;
  opacity: 0; transition: opacity .12s ease; pointer-events: none;
}
.chart-frame:hover .chart-export,
.chart-export:focus-within { opacity: 1; pointer-events: auto; }
.chart-export button {
  width: 24px; height: 24px; padding: 0; cursor: pointer; border-radius: 4px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--rule);
  background: color-mix(in srgb, var(--surface) 80%, transparent);
  color: var(--muted); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.chart-export button:hover { background: var(--surface-2); color: var(--ink); }
.chart-export button.ok  { color: var(--good); border-color: var(--good); }
.chart-export button.err { color: var(--bad);  border-color: var(--bad); }
.chart-export button[hidden] { display: none; }

.chart-note { color: var(--ink-2); font-size: 11px; letter-spacing: .01em; }

.side {
  width: 332px; border-left: 1px solid var(--rule); background: var(--surface);
  overflow: auto; padding: 22px 24px;
}
.side h2 {
  font-size: 10.5px; text-transform: uppercase; letter-spacing: .14em; color: var(--ink-2);
  margin: 26px 0 10px; padding-bottom: 6px; border-bottom: 1px solid var(--rule); font-weight: 600;
}
.side h2:first-child { margin-top: 0; }
.growth-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; margin: 26px 0 10px; }
.growth-head h2 { margin: 0; flex: 1; }
.seg.seg-sm button { padding: 3px 9px; font-size: 10px; }

.kv {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 6px 0; border-bottom: 1px solid var(--rule); font-size: 13px; gap: 12px;
}
.kv:last-child { border-bottom: none; }
.kv .k { color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.kv .v { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; flex: none; color: var(--ink); }

.bigscore {
  font-family: var(--font-display); font-size: 52px; font-weight: 400; line-height: .95;
  letter-spacing: -.5px;
}

/* Active-alerts + history in the ticker side panel (read-only). */
.side-manage {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  font-size: 11px; color: var(--ink-2); text-decoration: none; line-height: 0;
}
.side-manage:hover { color: var(--ink); }
.side-manage span { line-height: 1; }
.side-events { display: flex; flex-direction: column; }
.side-event { padding: 9px 0; border-bottom: 1px solid var(--rule); }
.side-event:first-child { padding-top: 2px; }
.side-event:last-child { border-bottom: none; padding-bottom: 0; }
.side-event-when {
  font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em;
}
.side-event-msg {
  margin-top: 3px; font-size: 12.5px; color: var(--ink-2); line-height: 1.45;
  font-variant-numeric: tabular-nums;
}
/* News panel (ticker side column, below alerts) */
/* The News heading is the first child of its own #sideNews wrapper, so the
   .side h2:first-child reset zeroes its top margin — restore it so the section
   gets the same gap as the others above it. */
#sideNews h2 { margin-top: 26px; }
.news-list { display: flex; flex-direction: column; }
.news-item {
  display: block; padding: 10px 0; border-bottom: 1px solid var(--rule);
  text-decoration: none;
}
.news-item:first-child { padding-top: 2px; }
.news-item:last-child { border-bottom: none; padding-bottom: 0; }
.news-title {
  font-size: 13px; line-height: 1.4; font-weight: 500; color: var(--ink);
}
.news-item:hover .news-title { color: var(--accent); }
.news-meta {
  margin-top: 4px; font-size: 11px; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: .04em;
}

/* Aggregated news on the Watchlist page: one tile per ticker */
/* Let the grid use the full page width (the default .panel caps at 1000px,
   which limits the tile grid to ~3 columns) so tiles flow to fit the screen. */
#view-news .panel { max-width: none; }
/* Active Alerts view stacks two panels (standing rules + recently fired) */
#view-active .panel + .panel { margin-top: 36px; }
.news-tiles {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.news-tile {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: 10px; padding: 14px 16px;
}
.news-tile-head {
  display: flex; align-items: baseline; gap: 8px;
  margin-bottom: 8px; padding-bottom: 8px; border-bottom: 1px solid var(--rule);
}
.news-tile-tkr {
  flex: none; font-family: var(--font-display); font-size: 16px; font-weight: 400;
  color: var(--ink); text-decoration: none; letter-spacing: .2px;
}
.news-tile-tkr:hover { color: var(--accent); text-decoration: none; }
.news-tile-co {
  font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .04em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.news-tile-list { display: flex; flex-direction: column; }
.news-link {
  display: block; padding: 8px 0; border-bottom: 1px solid var(--rule); text-decoration: none;
}
.news-link:first-child { padding-top: 0; }
.news-link:last-child { border-bottom: none; padding-bottom: 0; }
.news-link-title {
  display: block; font-size: 13px; line-height: 1.4; font-weight: 500; color: var(--ink);
}
.news-link:hover .news-link-title { color: var(--accent); }
.news-link-meta {
  display: block; margin-top: 3px; font-size: 11px; color: var(--ink-3);
  text-transform: uppercase; letter-spacing: .04em;
}

.bigscore span { font-family: var(--font-sans); }

/* ====================================================================
   Login — editorial two-panel gate
   ==================================================================== */
.login-page {
  background:
    radial-gradient(120% 90% at 50% -10%, oklch(0.99 0.006 85) 0%, var(--paper) 60%);
  color: var(--ink);
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.login-shell { width: 100%; max-width: 860px; }
.login-card {
  display: grid; grid-template-columns: 1.05fr .95fr;
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  border-radius: 6px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
}
.login-panel { padding: 56px 52px; }
.login-panel-form { display: flex; flex-direction: column; justify-content: center; background: var(--surface); }
.login-panel-logo {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 22px;
  background: var(--surface-2);
  border-left: 1px solid var(--rule);
}
.login-logo { width: 200px; max-width: 70%; height: auto; display: block; }
.login-panel-logo::after {
  content: "Signals";
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .2em; color: var(--ink-2);
}

.login-brand {
  text-align: left; font-family: var(--font-display); font-size: clamp(32px, 5vw, 40px);
  font-weight: 400; font-style: normal; margin: 0 0 4px; letter-spacing: 0; color: var(--brand-blue);
}
.login-brand span { color: var(--brand-green); font-style: normal; }
.login-sub {
  text-align: left; color: var(--ink-2); margin: 0 0 22px; font-size: 12px;
  font-weight: 600; text-transform: uppercase; letter-spacing: .14em;
}

.login-panel-form label {
  display: block; font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-2); margin: 16px 0 6px;
}
.login-panel-form input {
  width: 100%; background: var(--paper); border: 1px solid var(--rule); color: var(--ink);
  border-radius: 4px; padding: 11px 12px; font: 400 14px var(--font-sans); outline: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.login-panel-form input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.login-panel-form .btn {
  width: 100%; margin-top: 26px; padding: 13px; border-radius: 4px; border: 1px solid var(--accent);
  background: var(--accent); color: var(--on-accent); font-size: 12px; letter-spacing: .12em;
  cursor: pointer; transition: background .12s ease;
}
.login-panel-form .btn:hover { background: color-mix(in srgb, var(--accent) 88%, black); }
.login-err { color: var(--bad); font-size: 13px; margin-top: 14px; min-height: 16px; text-align: left; }

.login-foot {
  text-align: center; color: var(--ink-2); font-size: 10px; margin-top: 24px;
  text-transform: uppercase; letter-spacing: .1em;
}
.login-ver { color: var(--ink-3); }

@media (max-width: 680px) {
  .login-card { grid-template-columns: 1fr; }
  .login-panel { padding: 40px 30px; }
  .login-panel-logo { border-left: none; border-top: 1px solid var(--rule); order: -1; padding: 34px 0 30px; }
  .login-logo { width: 132px; }
}

/* --- 404 / error page (reuses login shell) --- */
.error-panel { justify-content: center; }
.error-code {
  font-family: var(--font-display); font-size: clamp(56px, 11vw, 84px); line-height: .9;
  font-weight: 400; color: var(--rule-strong); margin: 0 0 10px; letter-spacing: -.01em;
}
.error-msg {
  text-align: left; color: var(--ink-2); font-size: 14px; line-height: 1.55;
  margin: 0 0 26px; max-width: 34ch;
}
.error-home {
  display: inline-block; width: auto; text-decoration: none; text-align: center;
  padding: 13px 22px; border-radius: 4px; border: 1px solid var(--accent);
  background: var(--accent); color: var(--on-accent); font-size: 12px; letter-spacing: .12em;
  text-transform: uppercase; transition: background .12s ease;
}
.error-home:hover { background: color-mix(in srgb, var(--accent) 88%, black); }

/* ====================================================================
   Watchlist + Alerts — combined roster with embedded editions
   ==================================================================== */
/* The pipeline masthead is left untouched here so it inherits the shared
   `header` rule — the brand, nav tabs, and Sign Out land at the same x-positions
   as Dashboard/Scores/Ticker. (Previously this route insets the masthead to a
   1280px measure, which made it read as a different site.) */

/* #main spans the full width with NO padding, so the active tab's scroll
   container reaches the window's edges. */
#main { flex: 1; display: flex; min-height: 0; }

/* Each tab is its own scroll frame. Because the .view fills #main edge-to-edge,
   its vertical scrollbar rides the window's right edge — and the horizontal one,
   on the rare narrow window where a dense table overflows, rides the bottom —
   exactly like the Scores ledger. The gutter is INNER padding, so content stays
   inset and symmetric while the bars sit at the window edge. All four tabs
   (roster, portfolio + equity curve, alerts, news) share this one frame. */
.view {
  flex: 1; min-width: 0; min-height: 0; overflow: auto;
  padding: clamp(22px, 3vw, 34px) var(--gutter) 56px;
}
.view[hidden] { display: none; }

/* Alerts panels go full-bleed like News so all four tabs share one frame. */
#main .panel { max-width: none; }

.section-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
  margin-bottom: 18px; padding-bottom: 12px; border-bottom: 2px solid var(--rule-strong);
}
.section-title {
  font-family: var(--font-display); font-weight: 400; font-size: 23px; line-height: 1;
  margin: 0; color: var(--ink); letter-spacing: .2px;
}
.section-note {
  margin: 8px 0 0; color: var(--ink-2); font-size: 12.5px; line-height: 1.5; max-width: 62ch;
}
.section-note b { color: var(--ink); font-weight: 600; }
.section-head .btn { flex: none; }
/* "Check now" button stacked over its live "next check" readout. */
.check-col { display: flex; flex-direction: column; align-items: flex-end; gap: 5px; flex: none; }
.check-col .next-check { color: var(--ink-2); font-size: 11.5px; line-height: 1; white-space: nowrap; }
/* Equal-width figures so the ticking mm:ss countdown doesn't reflow each second. */
.next-check { font-variant-numeric: tabular-nums; }
.check-col .next-check:empty { display: none; }
.newsfront-note.next-check:empty { display: none; }

/* favorite = pin-to-top, marked with a bookmark (distinct from the watch-star) */
.pin-cell { width: 1%; }
.pin {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; padding: 2px; cursor: pointer; line-height: 0;
  color: var(--star-off);
  transition: color .12s ease, transform .12s ease;
}
.pin:hover { color: var(--star); transform: translateY(-1px); }
.pin.on { color: var(--star); }
.pin-head { display: inline-flex; color: var(--ink-3); line-height: 0; }

/* roster action column — Alerts disclosure button + quiet Remove */
td.row-acts { text-align: right; white-space: nowrap; }
.row-acts { display: flex; gap: 16px; align-items: center; justify-content: flex-end; }
/* Icon-only, fixed width so every Alerts/Documents button lines up with or
   without a count. Icon + count bubble sit left; the chevron is pushed right. */
.alerts-btn, .docs-btn { display: inline-flex; align-items: center; justify-content: flex-start; gap: 6px; width: 76px; padding: 0 11px; white-space: nowrap; }
/* Icon-only square — trash, no label. */
.icon-btn { width: 38px; padding: 0; }
.alerts-btn .chev, .docs-btn .chev {
  flex: none; margin-left: auto; color: var(--ink-3);
  transition: transform .2s cubic-bezier(.2, .7, .3, 1), color .12s ease;
}
.alerts-btn:hover .chev, .docs-btn:hover .chev { color: var(--ink-2); }
.alerts-btn.pressed, .docs-btn.pressed { background: var(--surface-3); border-color: var(--rule-strong); }
.alerts-btn.pressed .chev, .docs-btn.pressed .chev { transform: rotate(180deg); color: var(--ink-2); }
.alert-count {
  font-variant-numeric: tabular-nums; background: var(--accent); color: var(--on-accent);
  border-radius: 999px; min-width: 17px; height: 17px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; letter-spacing: 0;
}

/* the unfolded entry, and its annotation row */
tbody tr.row-open td { background: var(--row-hover); }
tbody tr.row-open td.sticky { background: var(--row-hover); }
.expand-row td { padding: 0; border-bottom: 2px solid var(--rule-strong); background: var(--surface-2); }
.expand-grid {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .28s cubic-bezier(.2, .7, .3, 1);
}
.expand-row.open .expand-grid { grid-template-rows: 1fr; }
.expand-inner { overflow: hidden; }
/* The roster table is wider than the screen, so a full-colspan expand cell would
   lay the research/alert editor out across the table's full width and push it
   off-screen. Pin the cell to the viewport's left edge and cap the fold to the
   viewport so it always fits the screen, however far the table is scrolled
   sideways. (Form-control fields shrank to fit on their own; the rich-text
   thesis, whose long lines set the auto-table width, made this bite on desktop
   too — hence applied at all widths, not just narrow screens.) */
.expand-row td.expand-cell { position: sticky; left: var(--gutter); }
/* Width is the frame's CONTENT width (viewport minus the .view gutter on each
   side), not 100vw — the fold sits inset by one gutter, so 100vw overran the
   right edge by exactly that much. The column track is minmax(0, 1fr), not the
   implicit `auto`: auto sizes to the editor's longest line (max-content) and
   overflows; the 0 minimum forces the fold's content to wrap within the width. */
.expand-grid {
  width: calc(100vw - 2 * var(--gutter)); max-width: calc(100vw - 2 * var(--gutter));
  grid-template-columns: minmax(0, 1fr);
}

/* shared list table for the two alert editions and rule lists */
table.alist { width: 100%; border-collapse: separate; border-spacing: 0; }
table.alist th, table.alist td {
  text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--rule);
  font-size: 13px; font-variant-numeric: tabular-nums; vertical-align: baseline;
}
table.alist th {
  color: var(--ink); font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: .08em;
  border-bottom: 2px solid var(--rule-strong); white-space: nowrap;
}
table.alist tr:last-child td { border-bottom: none; }
/* Numeric column (Last price) — right-align over the table's default left. */
table.alist th.num, table.alist td.num { text-align: right; }
table.alist td a { color: var(--ink); }
table.alist td a:hover { color: var(--accent); }
.col-when { width: 1%; white-space: nowrap; color: var(--ink-2); }
.col-act { text-align: right; white-space: nowrap; width: 1%; }
.muted-row td { color: var(--ink-3); }
.note-inline { color: var(--ink-3); }
.dispatch { color: var(--ink-2); }

.badge {
  display: inline-block; font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .08em;
  padding: 2px 8px; border-radius: 3px; white-space: nowrap;
}
.badge.on  { background: var(--good-soft); color: var(--good); }
.badge.off { background: var(--muted-soft); color: var(--ink-2); }

.linkbtn {
  display: inline-flex; align-items: center; gap: 5px; vertical-align: middle;
  background: none; border: none; color: var(--accent); cursor: pointer; padding: 0;
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .06em;
}
.linkbtn + .linkbtn { margin-left: 14px; }
.linkbtn:hover span { text-decoration: underline; text-underline-offset: 2px; }
.linkbtn.danger { color: var(--bad); }
.linkbtn.quiet { color: var(--ink-2); }
.linkbtn.quiet:hover { color: var(--bad); }

.formerr { color: var(--bad); font-size: 12px; }

/* empty state — teaches the interface rather than reporting a void */
.empty-state { padding: 72px 32px; text-align: center; }
.empty-mark { color: var(--ink-4); line-height: 0; margin-bottom: 16px; }
.empty-title {
  font-family: var(--font-display); font-size: 22px; font-weight: 400; color: var(--ink);
  margin: 0 0 8px;
}
.empty-sub { margin: 0 auto; color: var(--ink-2); font-size: 13px; line-height: 1.55; max-width: 46ch; }
.empty-sub b { color: var(--ink); font-weight: 600; }

/* ---- form fields (shared by the alert ticket) ---- */
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field label {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .1em; color: var(--ink-2);
}
.field label .opt { color: var(--ink-3); font-weight: 400; letter-spacing: .04em; }
.field input, .field select {
  background: var(--paper); border: 1px solid var(--rule); color: var(--ink);
  border-radius: 4px; height: 38px; padding: 0 10px; font: 400 13px var(--font-sans); outline: none;
  width: 100%; -webkit-appearance: none; appearance: none;
  transition: border-color .12s ease, box-shadow .12s ease;
}
/* native dropdown caret, drawn so selects match input height exactly */
.field select {
  padding-right: 30px;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%),
                    linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: right 13px center, right 9px center;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
  cursor: pointer;
}
.field input:focus, .field select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.field input { font-variant-numeric: tabular-nums; }
.field input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
.field input[type="number"]::-webkit-outer-spin-button,
.field input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* ====================================================================
   Alert editor — two broadsheet columns folded under the entry
   ==================================================================== */
.editor { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
.editor-col { padding: 22px clamp(18px, 3vw, 30px); min-width: 0; }
.editor-new { border-right: 1px solid var(--rule); }
@media (max-width: 860px) {
  .editor { grid-template-columns: 1fr; }
  .editor-new { border-right: none; border-bottom: 1px solid var(--rule); }
}

.editor-head {
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .12em; color: var(--ink-2);
  margin: 0 0 16px; padding-bottom: 9px; border-bottom: 1px solid var(--rule);
  display: flex; align-items: center; gap: 8px;
}
.block-count {
  font-variant-numeric: tabular-nums; color: var(--ink); background: var(--surface-3);
  border-radius: 999px; min-width: 18px; height: 18px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 10px; letter-spacing: 0;
}
.block-count:empty { display: none; }

/* the rule builder — two tight rows of equal-height controls */
.field-row { display: flex; gap: 14px; align-items: flex-end; }
.field-row + .field-row { margin-top: 14px; }
.field-row-1 .field-kind { flex: 1.4 1 0; }
.field-row-1 .field-op   { flex: 1 1 0; }
.field-row-1 .field-thr  { flex: 1 1 0; }
.field-row-2 .field-cd   { flex: 1 1 0; }
.field-row-2 .field-note { flex: 2.4 1 0; }
@media (max-width: 520px) {
  .field-row { flex-wrap: wrap; }
  .field-row-1 .field-kind { flex-basis: 100%; }
}

/* plain-language readout of the rule being composed */
.rule-plain {
  margin: 16px 0 0; padding: 11px 14px; background: var(--surface);
  border: 1px solid var(--rule); border-radius: 4px;
  font-size: 13px; line-height: 1.5; color: var(--ink-2);
}
.rule-plain b { color: var(--ink); font-weight: 600; }

.editor-actions { display: flex; align-items: center; justify-content: flex-end; gap: 16px; margin-top: 16px; }
.editor-actions .formerr { margin-right: auto; }
/* Cancel only appears while editing an existing rule */
.btn.ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn.ghost:hover { color: var(--ink); background: var(--surface-2); }
.e-cancel { display: none; }
.expand-row.is-editing .e-cancel { display: inline-flex; }

/* the ticker's standing rules */
.rule-list { display: flex; flex-direction: column; }
.rule { padding: 13px 0; border-bottom: 1px solid var(--rule); }
.rule:first-child { padding-top: 0; }
.rule:last-child { border-bottom: none; padding-bottom: 0; }
.rule.is-paused .rule-desc { color: var(--ink-2); }
.rule-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.rule-desc { font-size: 13.5px; font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }
.rule-note { margin-top: 4px; font-size: 12px; color: var(--ink-3); font-style: italic; }
.rule-foot { margin-top: 7px; display: flex; align-items: center; gap: 0; }
.rule-fired {
  margin-right: auto; font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.rule-empty { margin: 0; color: var(--ink-2); font-size: 13px; }

/* ====================================================================
   Pipeline — stage group headers, verdict badge button, research fold
   ==================================================================== */

/* a folio rule introducing each verdict section of the roster */
.grp-cell { padding: 0; background: var(--paper); border-bottom: 2px solid var(--rule-strong); }
.grp:not(:first-child) .grp-cell { border-top: 1px solid var(--rule); }
.grp-inner {
  display: flex; align-items: center; gap: 9px;
  padding: 14px 12px 9px;
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .1em; color: var(--ink-2);
}
.grp-collapsible .grp-inner { cursor: pointer; }
.grp-collapsible .grp-cell:hover .grp-name { color: var(--ink); }
.grp-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--v-researching); }
.grp-name { color: var(--ink); letter-spacing: .12em; }
.grp-count {
  font-variant-numeric: tabular-nums; color: var(--ink-2); background: var(--surface-3);
  border-radius: 999px; min-width: 18px; height: 17px; padding: 0 6px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 10px; letter-spacing: 0;
}
.grp-chev {
  flex: none; color: var(--ink-3);
  transition: transform .2s cubic-bezier(.2, .7, .3, 1);
}
.grp.is-collapsed .grp-chev { transform: rotate(-90deg); }

.grp-inner[data-verdict="buy"]       .grp-dot { background: var(--v-buy); }
.grp-inner[data-verdict="watchlist"] .grp-dot { background: var(--v-watchlist); }
.grp-inner[data-verdict="pass"]      .grp-dot { background: var(--v-pass); }
.grp-inner[data-verdict="too_hard"]  .grp-dot { background: var(--v-toohard); }

/* verdict button — the row's stage badge; opens the research fold. Fixed width
   so every stage badge lines up regardless of label length. */
.verdict-btn { display: inline-flex; align-items: center; justify-content: flex-start; gap: 7px; width: 152px; white-space: nowrap; }
.verdict-btn .chev {
  flex: none; margin-left: auto; color: var(--ink-3);
  transition: transform .2s cubic-bezier(.2, .7, .3, 1), color .12s ease;
}
.verdict-btn:hover .chev { color: var(--ink-2); }
.verdict-btn.pressed { border-color: var(--rule-strong); }
.verdict-btn.pressed .chev { transform: rotate(180deg); color: var(--ink-2); }
.verdict-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--v-researching); }
.verdict-btn[data-verdict=""]          { background: var(--v-researching-soft); color: var(--ink-2); }
.verdict-btn[data-verdict=""] .verdict-dot          { background: var(--v-researching); }
.verdict-btn[data-verdict="buy"]       { background: var(--v-buy-soft);       color: var(--v-buy); }
.verdict-btn[data-verdict="buy"] .verdict-dot       { background: var(--v-buy); }
.verdict-btn[data-verdict="watchlist"] { background: var(--v-watchlist-soft); color: var(--v-watchlist); }
.verdict-btn[data-verdict="watchlist"] .verdict-dot { background: var(--v-watchlist); }
.verdict-btn[data-verdict="pass"]      { background: var(--v-pass-soft);      color: var(--v-pass); }
.verdict-btn[data-verdict="pass"] .verdict-dot      { background: var(--v-pass); }
.verdict-btn[data-verdict="too_hard"]  { background: var(--v-toohard-soft);   color: var(--v-toohard); }
.verdict-btn[data-verdict="too_hard"] .verdict-dot  { background: var(--v-toohard); }

/* research fold — verdict picker + thesis, folded under the row */
.research { padding: 22px clamp(18px, 3vw, 30px); }
.research-head {
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .12em; color: var(--ink-2);
  margin: 0 0 14px; padding-bottom: 9px; border-bottom: 1px solid var(--rule);
}
.verdict-picker { display: flex; flex-wrap: wrap; gap: 8px; }
.vpick {
  display: inline-flex; align-items: center; cursor: pointer;
  background: var(--surface); border: 1px solid var(--rule); border-radius: 999px;
  padding: 7px 14px; font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-2); transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.vpick:hover { border-color: var(--rule-strong); color: var(--ink); }
.vpick:focus-visible { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.vpick.on { color: var(--paper); border-color: transparent; background: var(--ink); }
.vpick[data-verdict-key="buy"].on       { background: var(--v-buy); }
.vpick[data-verdict-key="watchlist"].on  { background: var(--v-watchlist); }
.vpick[data-verdict-key="pass"].on       { background: var(--v-pass); }
.vpick[data-verdict-key="too_hard"].on   { background: var(--v-toohard); }
.vpick[data-verdict-key="researching"].on { background: var(--v-researching); }

.verdict-crit {
  margin: 13px 0 18px; padding: 11px 14px; background: var(--surface);
  border: 1px solid var(--rule); border-radius: 4px;
  font-size: 12.5px; line-height: 1.5; color: var(--ink-2); min-height: 1em;
}
/* Thesis editor is Wysi (vendored). It ships its own toolbar/editor styling; a
   few overrides below align it to the app's surface, rule, and accent tokens. */
.field-thesis .wysi-wrapper {
  border: 1px solid var(--rule); border-radius: 4px; background: var(--surface);
}
.field-thesis .wysi-wrapper:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--focus-ring); }
.field-thesis .wysi-toolbar { border-bottom: 1px solid var(--rule); background: var(--paper); }
.field-thesis .wysi-editor {
  font: 400 13.5px/1.55 var(--font-sans); color: var(--ink); background: var(--surface);
  /* An ancestor (.field) sets white-space: nowrap for labels; reset it so long
     thesis sentences wrap instead of scrolling sideways. */
  white-space: normal; overflow-wrap: anywhere;
}
.field-thesis .wysi-editor:focus { outline: none; }
.research-actions { display: flex; align-items: center; gap: 16px; margin-top: 16px; }
.research-actions .r-save { margin-left: auto; }
.research-meta { font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); }

/* ====================================================================
   Portfolio — Schwab-style holdings + the position fold's lots
   ==================================================================== */
/* The holdings ledger sizes its columns to their content (the global table
   rule: width:max-content, min-width:100%). At the user's display widths the
   natural table is narrower than the content column, so min-width:100% stretches
   it to fill the frame — making it the exact same width as the equity chart
   above it, with no horizontal scroll. Only when a window is squeezed too narrow
   does its .view frame scroll sideways, like the Scores ledger — values are
   never truncated. */

/* Signed figures: gains green, losses oxblood (reusing the signal palette). */
.gain-up   { color: var(--good); }
.gain-down { color: var(--bad); }

/* Totals row pinned to the bottom of the holdings ledger. */
.pftbl tfoot td {
  position: sticky; bottom: 0; z-index: 2; background: var(--surface);
  border-top: 2px solid var(--rule-strong); border-bottom: none;
  padding: 9px 13px; font-weight: 700;
}
.pftbl tfoot td.sticky { z-index: 3; }
.pf-total td:first-child { text-transform: uppercase; letter-spacing: .07em; font-size: 11px; color: var(--ink-2); }

/* Portfolio splits into Buy and Watchlist sections, each chart + table. */
.pf-section { margin-bottom: clamp(28px, 5vw, 48px); }
.pf-section:last-child { margin-bottom: 0; }
/* A section with no holdings shows a quiet inline note, not the full empty hero. */
.pf-section-empty { padding: 22px 0 4px; text-align: left; }

/* Toolbar above the holdings ledger: the "Show tax lots" toggle. */
.pf-toolbar { display: flex; justify-content: flex-end; margin: 0 0 10px; }
.pf-lots-toggle { display: inline-flex; align-items: center; gap: 9px; cursor: pointer;
  font-size: 12.5px; color: var(--ink-2); -webkit-user-select: none; user-select: none; }
/* On/off switch: a styled track + sliding thumb over a visually-hidden checkbox. */
.pf-lots-toggle .switch-input { position: absolute; opacity: 0; width: 0; height: 0; }
.pf-lots-toggle .switch {
  position: relative; flex: none; width: 34px; height: 20px; border-radius: 999px;
  background: var(--rule-strong, #c9c4bb); transition: background .15s ease;
}
.pf-lots-toggle .switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25);
  transition: transform .15s ease;
}
.pf-lots-toggle .switch-input:checked + .switch { background: var(--accent, #2f5d7c); }
.pf-lots-toggle .switch-input:checked + .switch::after { transform: translateX(14px); }
.pf-lots-toggle .switch-input:focus-visible + .switch { outline: 2px solid var(--accent, #2f5d7c); outline-offset: 2px; }

/* Holdings rows fold open to reveal their lots on click. */
.pftbl tbody tr.pf-row { cursor: pointer; }
.pftbl tbody tr.pf-row:hover { background: var(--surface-2, rgba(0,0,0,.02)); }
.pftbl tbody tr.pf-row.open td.sticky { font-weight: 700; }
/* Name is capped so it never dominates the row; longer company names truncate
   with an ellipsis. */
.pftbl td.pf-name { color: var(--ink-2); white-space: nowrap; max-width: 220px;
  overflow: hidden; text-overflow: ellipsis; }

/* Lot sub-rows: quieter than the position row, with a lead-in rule on the left. */
.pftbl tbody tr.pf-lot-row td { background: var(--surface-2, rgba(0,0,0,.02));
  font-size: 12.5px; color: var(--ink-2); padding-top: 6px; padding-bottom: 6px; }
.pftbl tbody tr.pf-lot-row td.sticky { color: var(--ink-3); padding-left: 26px; }
.pftbl tbody tr.pf-lot-row td.pf-name { color: var(--ink-3); }
.pftbl tbody tr.pf-row.open + tr.pf-lot-row td { border-top: 1px solid var(--rule); }

/* Position lots inside the research fold. */
.position { margin-top: 22px; }
.lot-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.lot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 12px; background: var(--surface); border: 1px solid var(--rule); border-radius: 4px;
  font-size: 13px; color: var(--ink); font-variant-numeric: tabular-nums;
}
.lot-date { color: var(--ink-3); }
.lot-actions { display: inline-flex; align-items: center; gap: 14px; flex: none; }
/* A lot mid-edit: it grows to hold the fields, which wrap on a narrow fold. */
.lot.editing { flex-wrap: wrap; align-items: flex-end; }
.lot-edit { display: flex; gap: 12px; flex: 1 1 240px; flex-wrap: wrap; }
.lot-edit label {
  display: flex; flex-direction: column; gap: 4px; flex: 1 1 90px; min-width: 84px;
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .08em; color: var(--ink-2);
}
.lot-edit input {
  font: 400 13px var(--font-sans); color: var(--ink); padding: 6px 8px;
  border: 1px solid var(--rule); border-radius: 4px; background: var(--bg); font-variant-numeric: tabular-nums;
}
.lot-edit-err:not(:empty) { flex: 1 0 100%; margin-top: 8px; color: var(--bad); font-size: 12px; }
.lot-add { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; }
.lot-add .field-qty, .lot-add .field-cost { flex: 1 1 0; min-width: 110px; }
.lot-add .field-date { flex: 1 1 0; min-width: 130px; }
.lot-summary { margin: 12px 0 0; font-size: 12.5px; color: var(--ink-2); }
.lot-err:not(:empty) { display: block; margin-top: 10px; }

/* ====================================================================
   Documents fold — research PDFs attached to a ticker
   ==================================================================== */
.docs { padding: 22px clamp(18px, 3vw, 30px); }
.docs-count {
  font-variant-numeric: tabular-nums; color: var(--ink-3); font-weight: 600;
}
.doc-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 18px; }
.doc {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 9px 12px; background: var(--surface); border: 1px solid var(--rule); border-radius: 4px;
}
.doc-open {
  display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1 1 auto;
  background: none; border: none; padding: 0; cursor: pointer; text-align: left;
  color: var(--ink); font: inherit;
}
.doc-open .ico { color: var(--ink-2); flex: none; }
.doc-open:hover .doc-name { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.doc-name { font-size: 13.5px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.doc-meta { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; flex: none; font-variant-numeric: tabular-nums; }
.doc-acts { display: flex; align-items: center; flex: none; }
.doc-upload { display: flex; gap: 14px; align-items: flex-end; flex-wrap: wrap; }
.doc-upload .field-docfile { flex: 1 1 0; min-width: 200px; }
.doc-upload .field-doctitle { flex: 1.4 1 0; min-width: 180px; }
.doc-upload input[type="file"] {
  height: 38px; padding: 7px 10px; font-size: 12.5px; cursor: pointer;
}
.doc-upload input[type="file"]::file-selector-button {
  margin-right: 10px; padding: 5px 10px; border: 1px solid var(--rule); border-radius: 4px;
  background: var(--surface-2); color: var(--ink); font: 600 11px var(--font-sans);
  text-transform: uppercase; letter-spacing: .06em; cursor: pointer;
}
.doc-err:not(:empty) { display: block; margin-top: 12px; }

/* ---- document viewer modal ---- */
body.modal-open { overflow: hidden; }
.doc-modal { position: fixed; inset: 0; z-index: 100; display: flex; }
.doc-modal[hidden] { display: none; }
.doc-modal-backdrop {
  position: absolute; inset: 0; background: color-mix(in srgb, var(--ink) 55%, transparent);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
.doc-modal-panel {
  position: relative; margin: auto; width: min(960px, 94vw); height: min(92vh, 1100px);
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--rule-strong); border-radius: 8px;
  box-shadow: 0 24px 60px color-mix(in srgb, var(--ink) 30%, transparent); overflow: hidden;
}
.doc-modal-head {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px 12px 18px; border-bottom: 1px solid var(--rule); background: var(--surface);
}
.doc-modal-title {
  flex: 1 1 auto; min-width: 0; font-family: var(--font-display); font-size: 17px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.doc-modal-acts { display: flex; align-items: center; gap: 8px; flex: none; }
.doc-modal-body { flex: 1 1 auto; min-height: 0; background: var(--surface-3); }
.doc-frame { width: 100%; height: 100%; border: 0; display: block; }

@media (max-width: 600px) {
  .doc-modal-panel { width: 100vw; height: 100vh; border-radius: 0; border: none; }
}

/* ====================================================================
   Equity curve — portfolio value over time, above the holdings table
   ==================================================================== */
.equity { margin-bottom: clamp(20px, 3vw, 32px); }
.equity-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 18px;
  padding-bottom: 12px; margin-bottom: 16px; border-bottom: 2px solid var(--rule-strong);
}
.equity-lede { min-width: 0; }
.equity-head .section-title {
  font-family: var(--font-display); font-weight: 400; font-size: 23px; line-height: 1;
  margin: 0; color: var(--ink); letter-spacing: .2px;
}
.equity-head .section-note { margin: 6px 0 0; color: var(--ink-2); font-size: 12.5px; line-height: 1.5; }
/* One row: the metric switch on the left, the holding dropdown on the right.
   A dropdown (not a button strip) keeps the row stable as the list grows. */
.equity-controls { display: flex; flex-direction: row; align-items: center;
  justify-content: flex-end; gap: 12px; flex: none; flex-wrap: wrap; }
.eq-ticker { flex: none; }
.eq-select {
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink); background: var(--surface); cursor: pointer;
  border: 1px solid var(--rule); border-radius: 5px; padding: 7px 30px 7px 11px;
  -webkit-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23777' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center;
}
.eq-select:hover { border-color: var(--rule-strong); }
.eq-select:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.equity-chart {
  height: clamp(240px, 38vh, 380px); width: 100%;
  border: 1px solid var(--rule); border-radius: 6px; background: var(--surface);
  overflow: hidden;
}
.equity-note {
  margin: 10px 0 0; font: 600 10.5px var(--font-sans); text-transform: uppercase;
  letter-spacing: .08em; color: var(--ink-3); font-variant-numeric: tabular-nums;
}

@media (max-width: 720px) {
  .equity-head { flex-direction: column; align-items: stretch; gap: 12px; }
  .equity-controls { justify-content: flex-start; }
}

/* ====================================================================
   Phone-size screens — stack the desktop-first views, condense the
   masthead, and grow tap targets to a comfortable minimum.
   ==================================================================== */

/* --- Ticker detail: stack the chart over its stats panel --- */
@media (max-width: 720px) {
  .detail { flex-direction: column; overflow-y: auto; }
  .chart-col { flex: none; padding: 14px 16px; gap: 12px; }
  /* fixed viewport-relative height so the auto-sizing chart has room,
     then the stats panel flows beneath it as the page scrolls */
  .chart-frame { flex: none; height: 56vh; min-height: 280px; }
  #chart { flex: 1; min-height: 0; }
  .side {
    flex: none; width: auto; overflow: visible;
    border-left: none; border-top: 1px solid var(--rule);
    padding: 20px 16px 32px;
  }
  /* (The expand-cell viewport pin lives in the base styles now — it applies at
     all widths since the rich-text thesis can widen the table on desktop too.) */
}

/* --- Masthead + dense tables + touch targets --- */
@media (max-width: 600px) {
  /* condense the bar: drop the "Signals" kicker, tighten gaps */
  header { padding: 8px 14px; gap: 8px 12px; min-height: 0; }
  .brand-sub { display: none; }
  .brand-name { font-size: 19px; }
  nav.tabs { padding-left: 12px; margin-left: 0; gap: 16px; }
  .hsep { display: none; }

  /* editions become a single swipeable strip on their own full-width row,
     instead of wrapping across several lines and eating vertical space */
  .editions {
    order: 8; flex: 1 1 100%; gap: 18px;
    padding-left: 0; margin-left: 0; border-left: none;
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none;                 /* Firefox: hide the thin strip bar */
  }
  .editions::-webkit-scrollbar { display: none; }
  .editions .ed { flex: none; white-space: nowrap; }

  /* right cluster stays pinned right and wraps as a unit; tighten its gap so
     count + Filters + Sign out fit comfortably */
  .hdr-actions { gap: 10px; }

  /* the toggles + reset tuck behind the "Filters" icon (which lives in the
     right cluster); the group drops to its own full-width row when opened */
  .tools-toggle { display: inline-flex; }
  .hdr-tools { display: none; }
  .hdr-tools.open {
    display: flex; order: 11; flex: 1 1 100%; flex-wrap: wrap; gap: 12px 18px;
    padding-top: 4px;
  }

  /* search drops to its own full-width row beneath the nav */
  .search-wrap { order: 9; flex: 1 1 100%; }
  .search { width: 100%; }
  /* sign-out collapses to its glyph to reclaim width */
  #logoutBtn span { display: none; }
  #logoutBtn { padding: 0 10px; }

  /* comfortable tap targets (≥38px) for nav, controls, glyphs */
  nav.tabs a, .editions .ed { padding-top: 9px; padding-bottom: 10px; }
  .btn { min-height: 38px; }
  .seg button { padding: 10px 14px; }
  .star { padding: 5px; }
  .pin { padding: 6px; }
  .linkbtn { padding: 5px 0; }

  /* keep the dense ledger as a horizontal-scroll table (best for
     comparing/sorting many columns) but make it touch-friendly */
  thead .label { padding-left: 11px; padding-right: 11px; }
  tbody td { padding: 8px 11px; font-size: 12px; }
  /* let columns size to their data (esp. the ticker), not the filter field —
     pairs with the shrunk input intrinsic set in table.js */
  thead .filter input { min-width: 0; }

  /* tighter top/bottom padding on phones (the .view keeps its inline gutter) */
  #main .view { padding-block: 22px 48px; }
  .section-head { flex-wrap: wrap; gap: 12px; }
  table.alist th, table.alist td { padding: 9px 8px; }
}

/* ====================================================================
   Front page — the broadsheet cover. Three departments set as ruled
   columns over an aggregated newswire. No cards: column rules and the
   masthead's double rule do the dividing.
   ==================================================================== */
/* The cover scrolls as a full-width container so its vertical scrollbar rides
   the window's right edge (not the edge of a centered 1180px column). The
   content stays centered on that 1180px measure via symmetric inline padding:
   on wide screens the padding is the centering slack, collapsing to the gutter
   as the window narrows. */
.front {
  flex: 1; overflow: auto;
  width: 100%;
  padding: clamp(20px, 3.5vw, 40px)
           max(clamp(20px, 4vw, 44px), calc((100% - 1180px) / 2)) 64px;
}

/* Departments — a run of three front-page columns, divided by column rules */
.departments {
  display: grid; grid-template-columns: repeat(3, 1fr);
  margin-top: clamp(22px, 3vw, 36px);
}
.dept {
  position: relative;
  display: flex; flex-direction: column;
  padding: 4px clamp(18px, 2.4vw, 30px) 18px;
  color: var(--ink); text-decoration: none;
  border-radius: 5px;
  transition: background .14s ease;
}
/* Manual price-refresh on the Portfolio tile — corner icon button. The tile is a
   link, so its click handler stops navigation (see dashboard.js). */
.dept-refresh {
  position: absolute; top: 6px; right: 6px; z-index: 2;
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border-radius: 5px; cursor: pointer;
  border: 1px solid transparent; background: transparent; color: var(--ink-3);
  transition: background .12s ease, color .12s ease;
}
.dept-refresh:hover { background: var(--surface-2); color: var(--ink); }
.dept-refresh:disabled { cursor: default; opacity: .6; }
.dept + .dept { border-left: 1px solid var(--rule); }
.dept:last-child { padding-right: 0; }
.dept:hover { background: var(--row-hover); text-decoration: none; }

.dept-kicker {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .16em;
  color: var(--ink-3);
}
.dept-name {
  font-family: var(--font-display); font-weight: 400; font-size: 25px; line-height: 1.05;
  margin: 5px 0 0; color: var(--ink); letter-spacing: .2px;
}
.dept-figure {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(42px, 4.4vw, 56px); line-height: .96; letter-spacing: -.5px;
  margin: 18px 0 0; color: var(--ink); font-variant-numeric: tabular-nums;
}
.dept-figcap {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-2); margin: 7px 0 0;
}
.dept-lede {
  margin: 14px 0 0; font-size: 13px; line-height: 1.55; color: var(--ink-2);
  max-width: 34ch;
}
.dept-stats {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: flex; flex-direction: column; gap: 7px;
}
.dept-stats li {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 13px; color: var(--ink); font-variant-numeric: tabular-nums;
}
.dept-stats li.signal { font-weight: 600; }
.dept-stats li.signal.up { color: var(--good); }
.dept-stats li.signal.down { color: var(--bad); }
.dept-stats li.signal.flat { color: var(--ink-2); }
.dept-stat-alerts, .dept-stat-empty { color: var(--ink-2); }
.dept-stat-empty { font-size: 12.5px; line-height: 1.5; }
.vdot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  transform: translateY(1px); background: var(--v-researching);
}
.vdot[data-verdict="buy"]         { background: var(--v-buy); }
.vdot[data-verdict="watchlist"]   { background: var(--v-watchlist); }
.vdot[data-verdict="researching"] { background: var(--v-researching); }
.vdot[data-verdict="pass"]        { background: var(--v-pass); }
.vdot[data-verdict="too_hard"]    { background: var(--v-toohard); }

.dept-go {
  margin-top: auto; padding-top: 18px;
  font: 600 10.5px var(--font-sans); text-transform: uppercase; letter-spacing: .1em;
  color: var(--accent);
}
.dept:hover .dept-go { text-decoration: underline; text-underline-offset: 3px; }

/* Status tiles — left column stacks the Hour + the Ledger (economic calendar);
   the On Deck tile fills the whole right column (both rows). */
.front-tiles {
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2.4vw, 28px);
  margin-top: clamp(28px, 4vw, 46px); align-items: stretch;
}
/* The left column stacks the Hour + Ledger and is the ONLY thing that sets the
   row height. The right cell wraps the On Deck tile; the tile is absolutely
   positioned to fill that cell, so its (arbitrarily long) list is removed from
   flow and can never grow the grid row. The cell therefore stretches to exactly
   the left column's height and the tile scrolls inside it. */
.front-tiles-col { display: flex; flex-direction: column; gap: clamp(16px, 2.4vw, 28px); }
.front-tiles-right { position: relative; min-height: 0; }
.front-tiles-right > #oddTile { position: absolute; inset: 0; min-height: 0; overflow: hidden; }
.ftile {
  display: flex; flex-direction: column;
  padding: clamp(16px, 2vw, 22px) clamp(18px, 2.2vw, 24px);
  border: 1px solid var(--rule); border-radius: 6px; background: var(--card, transparent);
  color: var(--ink);
}
.ftile-link { text-decoration: none; transition: background .14s ease, border-color .14s ease; }
.ftile-link:hover { background: var(--row-hover); border-color: var(--rule-strong); text-decoration: none; }
.ftile-kicker {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .16em;
  color: var(--ink-3);
}
.ftile-name {
  font-family: var(--font-display); font-weight: 400; font-size: 22px; line-height: 1.05;
  margin: 5px 0 0; color: var(--ink);
}
.ftile-sub { margin: 6px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }

/* Clock tile */
.ftile-date {
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-2); margin: 6px 0 0;
}
/* A shared grid so the label column sizes once across both rows — the times
   then start at the same x and read as left-aligned. */
.clk-zones {
  display: grid; grid-template-columns: auto auto auto; justify-content: start;
  align-items: baseline; column-gap: 12px; row-gap: 8px; margin-top: 14px;
}
.clk-zone { display: contents; }
.clk-label {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-3); white-space: nowrap;
}
.clk-time {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(26px, 3vw, 34px); line-height: 1; letter-spacing: -.4px;
  color: var(--ink);
}
/* The display serif lacks tabular figures, so each digit gets a fixed-width,
   centered slot — the clock stays rock-steady as the seconds change. */
.clk-time .clk-d { display: inline-block; width: .58em; text-align: center; }
.clk-tz {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-3);
}
.ftile-market {
  display: flex; align-items: center; gap: 9px; margin-top: auto; padding-top: 16px;
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.clk-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--ink-3); }
.ftile-market[data-state="open"] .clk-dot { background: var(--good); }
.ftile-market[data-state="open"] .clk-mstat { color: var(--good); }
.clk-mtime { color: var(--ink-3); }

/* Tile bodies */
.ftile-body { margin-top: 12px; }
.ftile-empty { margin: 4px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }

/* On Deck tile: pipeline names, each a two-column row — ticker over its earnings
   date on the left, target · count over upside on the right. Fills the right
   column (two rows) and scrolls past a screenful so it stays contained. */
#oddBody { flex: 1; min-height: 0; overflow-y: auto; }
.oddlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.oddrow {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 8px 0; border-bottom: 1px solid var(--rule); font-variant-numeric: tabular-nums;
}
.oddrow:last-child { border-bottom: none; }
.odd-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.odd-fig { display: flex; flex-direction: column; gap: 2px; align-items: flex-end; text-align: right; white-space: nowrap; }
.odd-tkr { font-weight: 700; font-size: 13px; letter-spacing: .2px; color: var(--ink); }
.odd-earn { font-size: 12px; color: var(--ink-2); }
.odd-days { color: var(--ink-3); }
.odd-days.is-soon { color: var(--mid-ink); font-weight: 600; }
.odd-tgt { font-size: 12.5px; color: var(--ink-2); }
.odd-up { font-size: 12px; }
.odd-dim { color: var(--ink-4); }
/* Upside figure colours */
.tgt-up { color: var(--good); font-weight: 600; }
.tgt-down { color: var(--bad); font-weight: 600; }

/* Economic-calendar tile: a two-line row (event + region chip, then when · figures) */
.econlist { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.econrow {
  display: flex; flex-direction: column; gap: 2px;
  padding: 7px 0; border-bottom: 1px solid var(--rule); font-variant-numeric: tabular-nums;
}
.econrow:last-child { border-bottom: none; }
.econ-event { font-size: 13px; font-weight: 600; color: var(--ink); line-height: 1.35; }
.econ-region {
  margin-left: 6px; font-size: 10.5px; font-weight: 700; letter-spacing: .3px;
  color: var(--ink-3); border: 1px solid var(--rule); border-radius: 4px; padding: 0 4px;
}
.econ-meta { font-size: 12px; color: var(--ink-2); }
.econ-figs { color: var(--ink-3); }

/* Stack the status tiles on narrow screens */
@media (max-width: 720px) {
  .front-tiles { grid-template-columns: 1fr; }
  /* Single column: drop the absolute fill so the On Deck tile flows naturally
     under the left stack and sizes to its own content. */
  .front-tiles-right { position: static; }
  .front-tiles-right > #oddTile { position: static; overflow: visible; }
}

/* Newswire — the second fold */
.newsfront { margin-top: clamp(34px, 4.5vw, 52px); }
.newsfront-head {
  display: flex; align-items: flex-end; justify-content: space-between; gap: 24px;
  padding-bottom: 12px; border-bottom: 2px solid var(--rule-strong);
}
.newsfront-lede { display: flex; flex-direction: column; gap: 6px; }
.newsfront-lede .newsfront-note { text-align: left; }
.newsfront-title {
  font-family: var(--font-display); font-weight: 400; font-size: 23px; line-height: 1;
  margin: 0; color: var(--ink); letter-spacing: .2px;
}
.newsfront-aside {
  display: flex; flex-direction: column; align-items: flex-end; gap: 6px; flex: none;
}
.newsfront-note {
  margin: 0; color: var(--ink-2); font-size: 12.5px; line-height: 1.5;
  max-width: 48ch; text-align: right;
}
.newsfront-more {
  font: 600 10.5px var(--font-sans); text-transform: uppercase; letter-spacing: .1em;
  color: var(--accent); white-space: nowrap;
}
.newsfront-more:hover { text-decoration: underline; text-underline-offset: 3px; }
.newsfront-body { margin-top: 18px; }

/* Recent alerts — a ruled ledger of the latest rules that tripped */
.alertfeed { list-style: none; margin: 0; padding: 0; }
.alert-item {
  display: grid; grid-template-columns: auto 1fr auto; align-items: baseline; gap: 16px;
  padding: 11px 0; border-bottom: 1px solid var(--rule);
}
.alert-item:first-child { padding-top: 0; }
.alert-item:last-child { border-bottom: none; }
.alert-tkr {
  font: 600 11px var(--font-sans); text-transform: uppercase; letter-spacing: .1em;
  color: var(--accent); text-decoration: none; min-width: 5ch;
}
.alert-tkr:hover { text-decoration: underline; text-underline-offset: 3px; }
.alert-msg {
  font-family: var(--font-serif); font-size: 14px; line-height: 1.4; color: var(--ink);
  font-variant-numeric: tabular-nums; min-width: 0;
}
.alert-when {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums;
}

.newswire {
  list-style: none; padding: 0;
  /* pull the box up by one item's top padding so the first item of EACH column
     sits flush with the heading — :first-child only resets column one, leaving
     the second column a line lower, so compensate uniformly instead */
  margin: -13px 0 0;
  counter-reset: wire;
  columns: 2; column-gap: clamp(28px, 4vw, 52px);
}
.wire { break-inside: avoid; counter-increment: wire; }
.wire-link {
  display: grid;
  grid-template-columns: auto 1fr; grid-template-rows: auto auto auto;
  column-gap: 14px;
  padding: 13px 0; border-bottom: 1px solid var(--rule); text-decoration: none;
}
/* the ranking figure, set in Caslon down the left margin */
.wire-link::before {
  content: counter(wire);
  grid-row: 1 / 4; align-self: start;
  font-family: var(--font-display); font-weight: 400; font-size: 22px; line-height: 1;
  color: var(--ink-4); font-variant-numeric: tabular-nums; min-width: 1.4ch;
}
.wire-tkr {
  font: 600 10px var(--font-sans); text-transform: uppercase; letter-spacing: .12em;
  color: var(--accent);
}
.wire-title {
  font-family: var(--font-serif); font-size: 15px; line-height: 1.36; color: var(--ink);
  margin-top: 3px;
}
.wire-link:hover .wire-title { color: var(--accent); }
.wire-meta {
  margin-top: 5px; font: 600 10px var(--font-sans); text-transform: uppercase;
  letter-spacing: .07em; color: var(--ink-3); font-variant-numeric: tabular-nums;
}

.front-loading { color: var(--ink-2); font-size: 13px; padding: 8px 0; }
.front-empty { padding: 24px 0 8px; }
.front-empty-title {
  font-family: var(--font-display); font-size: 18px; font-weight: 400; color: var(--ink);
  margin: 0 0 6px;
}
.front-empty-sub { margin: 0; color: var(--ink-2); font-size: 13px; line-height: 1.55; max-width: 46ch; }

/* one orchestrated load-in: departments, then the wire */
@keyframes front-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
.front > * { animation: front-rise .5s cubic-bezier(.2, .7, .3, 1) both; }
.departments { animation-delay: .09s; }
.newsfront { animation-delay: .17s; }

@media (max-width: 860px) {
  /* departments stack; the column rule becomes a horizontal divider */
  .departments { grid-template-columns: 1fr; }
  .dept { padding: 20px 0; }
  .dept + .dept { border-left: none; border-top: 1px solid var(--rule); }
  .dept-figure { font-size: clamp(40px, 11vw, 52px); margin-top: 12px; }
  .dept-go { padding-top: 14px; }
  .newswire { columns: 1; }
  .newsfront-head { flex-direction: column; align-items: flex-start; gap: 8px; }
  .newsfront-aside { align-items: flex-start; gap: 8px; }
  .newsfront-note { text-align: left; }
}

/* ====================================================================
   Settings — the Specifications sheet (read-only colophon)
   A printed datasheet: a Caslon nameplate, folio-numbered departments, and
   spec rows where a dotted leader carries the eye from each term to its figure.
   ==================================================================== */
.spec {
  flex: 1;
  overflow-y: auto;
  padding: clamp(28px, 5vw, 64px) var(--gutter) 96px;
}
.spec-status { color: var(--ink-2); font-size: 13px; padding: 8px 0; }

/* ---- slim top strip: page label + release/build, no hero ---- */
.spec-topbar {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--space-md);
  padding-bottom: var(--space-sm);
  margin-bottom: var(--space-2xl);
  border-bottom: 1px solid var(--rule);
}
.spec-topbar-label {
  font-family: var(--font-sans);
  font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: .18em;
  color: var(--ink-3);
}
.spec-colophon {
  display: flex; flex-wrap: wrap; gap: var(--space-lg);
  margin: 0;
}
.spec-colophon div { display: flex; align-items: baseline; gap: var(--space-sm); }
.spec-colophon dt {
  font-family: var(--font-sans);
  font-weight: 600; font-size: 9px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--ink-3);
}
.spec-colophon dd {
  margin: 0; font-family: var(--font-sans); font-size: 12px; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* ---- department (section) ---- */
.spec-section { margin-bottom: var(--space-2xl); }
.spec-section + .spec-section { margin-top: var(--space-md); }
.spec-section-head {
  padding-bottom: var(--space-sm);
  border-bottom: 1px solid var(--rule-strong);
  margin-bottom: var(--space-xl);
}
.spec-section-title {
  font-family: var(--font-display);
  font-weight: 400; font-size: clamp(1.4rem, 2.6vw, 2rem); color: var(--ink);
  margin: 0; letter-spacing: .01em;
}

/* groups flow into self-adjusting columns; each group is a self-contained sheet */
.spec-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
  gap: clamp(28px, 3.5vw, 52px);
  align-items: start;
}

.spec-group-head { margin-bottom: var(--space-md); }
.spec-kicker {
  display: block;
  font-family: var(--font-sans);
  font-weight: 600; font-size: 9.5px; text-transform: uppercase; letter-spacing: .18em;
  color: var(--accent); margin-bottom: var(--space-xs);
}
.spec-group-titlerow {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-md);
}
.spec-group-title {
  font-family: var(--font-display);
  font-weight: 400; font-size: 1.32rem; color: var(--ink); margin: 0;
}
/* a quiet text-link edit affordance — no button chrome, in keeping with the sheet */
.spec-edit-btn {
  flex: none;
  font-family: var(--font-sans);
  font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--accent); background: none; border: 0; cursor: pointer;
  padding: 2px 0; border-bottom: 1px solid transparent; transition: border-color .12s ease;
}
.spec-edit-btn:hover { border-bottom-color: var(--accent); }
.spec-group-note {
  font-family: var(--font-serif);
  font-size: 13px; line-height: 1.5; color: var(--ink-2);
  max-width: 46ch; margin: 6px 0 0;
}

/* ---- the spec rows ---- */
.spec-list { margin: var(--space-lg) 0 0; }
.spec-row {
  padding: var(--space-md) 0;
  border-top: 1px solid var(--rule);
}
.spec-row:first-child { border-top: none; padding-top: var(--space-sm); }

.spec-line { display: flex; align-items: flex-end; gap: var(--space-sm); }
.spec-term {
  font-family: var(--font-sans);
  font-weight: 500; font-size: 13.5px; color: var(--ink);
  white-space: nowrap;
}
/* the dotted leader — a zero-height rule riding the baseline between term & figure */
.spec-leader {
  flex: 1 1 auto;
  height: 0;
  border-bottom: 1px dotted var(--rule-strong);
  margin-bottom: 5px;
  min-width: 16px;
}
.spec-val {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.18rem; line-height: 1.05; color: var(--ink);
  font-variant-numeric: tabular-nums;
  text-align: right; min-width: 0; word-break: break-word;
}
.spec-unit {
  display: block;
  font-family: var(--font-sans);
  font-weight: 500; font-size: 9.5px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-3); margin-top: 3px;
}
.spec-note {
  font-family: var(--font-serif);
  font-size: 12.5px; line-height: 1.5; color: var(--ink-2);
  max-width: 50ch; margin: var(--space-xs) 0 0;
}
.spec-cite {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-sm);
  margin-top: 7px;
}
.spec-via {
  font-family: var(--font-sans);
  font-weight: 600; font-size: 9px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-3);
}
.spec-via-env {
  color: var(--accent);
  padding: 1px 6px;
  background: color-mix(in srgb, var(--accent) 8%, var(--paper));
}
.spec-via-edit {
  color: var(--good);
  padding: 1px 6px;
  background: color-mix(in srgb, var(--good) 11%, var(--paper));
}
.spec-src {
  font-family: ui-monospace, "SF Mono", "Cascadia Code", Menlo, monospace;
  font-size: 10.5px; color: var(--ink-3);
}

/* ---- inline edit form (editable groups) ---- */
.spec-form { margin-top: var(--space-lg); display: flex; flex-direction: column; gap: var(--space-lg); }
.spec-field { display: flex; flex-direction: column; gap: 5px; }
.spec-field label {
  font-family: var(--font-sans);
  font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: .12em;
  color: var(--ink-2);
}
.spec-input-row { display: flex; align-items: baseline; gap: var(--space-sm); }
.spec-input {
  font-family: var(--font-display);
  font-size: 1.1rem; color: var(--ink); font-variant-numeric: tabular-nums;
  width: 7ch; padding: 6px 8px;
  background: var(--surface-2); border: 1px solid var(--rule-strong); border-radius: 0;
  transition: border-color .12s ease, box-shadow .12s ease;
}
.spec-input:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--focus-ring);
}
/* text/url values are longer than a number — give them a real field */
.spec-input-wide {
  width: 100%; max-width: 34ch;
  font-family: var(--font-sans); font-size: 13.5px;
}
.spec-input-row:has(.spec-input-wide) { width: 100%; }

/* composite field: several inputs folded onto one row (e.g. host · port · user).
   Text inputs flex to share the width; the number (port) stays compact. */
.spec-input-multi {
  flex-wrap: wrap; width: 100%; max-width: 44ch;
}
.spec-input-multi .spec-input-wide {
  flex: 1 1 11ch; min-width: 9ch; max-width: none;
}
.spec-input-multi .spec-input:not(.spec-input-wide) { flex: 0 0 auto; }
.spec-input-unit {
  font-family: var(--font-sans);
  font-weight: 500; font-size: 10px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--ink-3);
}
.spec-field-note {
  font-family: var(--font-serif);
  font-size: 12px; line-height: 1.45; color: var(--ink-2); max-width: 44ch; margin: 0;
}
.spec-form-help {
  font-family: var(--font-sans);
  font-size: 11.5px; line-height: 1.45; color: var(--ink-3); margin: 0;
}
.spec-form-actions {
  display: flex; align-items: center; gap: var(--space-sm);
  padding-top: var(--space-sm); border-top: 1px solid var(--rule);
}
.spec-form-err {
  flex: 1; min-width: 0;
  font-family: var(--font-sans); font-size: 12px; color: var(--bad);
}

@media (max-width: 600px) {
  .spec-colophon { gap: var(--space-lg); }
  .spec-line { flex-wrap: wrap; }
  .spec-leader { display: none; }
  .spec-val { text-align: left; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
