/* ═══════════════════════════════════════════════════════════════════
   Coil — design system

   A light, analytical surface. Structure is carried by hairlines and
   whitespace, never by boxes and shadows: the only elevated things in
   the app are the ones that genuinely float (the command palette, the
   drawer). Everything else sits on the page.

   Colour means something. Green is pass, red is fail, amber is caution,
   grey is unknown — and nothing is coloured for decoration. The accent
   ink-blue marks interaction, never data.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  /* ── surface ─────────────────────────────────────────────────── */
  --paper:      #fbfbfa;   /* the page */
  --surface:    #ffffff;   /* raised reading surfaces */
  --sunken:     #f4f4f2;   /* wells, table headers, inert chips */
  --hairline:   rgba(18, 20, 24, 0.09);
  --hairline-2: rgba(18, 20, 24, 0.16);

  /* ── ink ─────────────────────────────────────────────────────── */
  --ink:        #121418;
  --ink-2:      #4a4f57;   /* secondary text */
  --ink-3:      #6b7178;   /* captions, units, muted — 4.8:1 on paper */
  --ink-4:      #888f96;   /* placeholder, disabled — 3.1:1, non-text only */

  /* ── accent: interaction only ────────────────────────────────── */
  --accent:     #1f3ad6;
  --accent-ink: #16299a;
  --accent-wash:#eef1fe;

  /* ── signal: meaning only ────────────────────────────────────── */
  --pass:       #0d7a4d;
  --pass-wash:  #e8f5ee;
  --fail:       #bf2f28;
  --fail-wash:  #fdecea;
  --warn:       #8a5804;
  --warn-wash:  #fdf3e2;
  --unknown:    #676c73;
  --unknown-wash:#f0f0ef;

  /* ── values that invert with the theme ───────────────────────── */
  --on-ink:      #fff;     /* text on an --ink fill */
  --on-accent:   #fff;     /* text on an --accent fill */
  --selected-bg: var(--ink);
  --selected-ink:#fff;
  --glass:       rgba(251, 251, 250, 0.86);   /* topbar */
  --glass-strong:rgba(251, 251, 250, 0.94);   /* sticky heads */
  --scrim:       rgba(18, 20, 24, 0.28);
  --shadow-float:0 16px 48px rgba(18, 20, 24, 0.16);
  --shadow-pop:  0 10px 32px rgba(18, 20, 24, 0.13);
  --shadow-edge: -12px 0 40px rgba(18, 20, 24, 0.08);
  --skeleton-hi: #ececeb;
  --mark-tile:   #121418;  /* the logo tile, which is dark in both themes */
  /* chart annotation + volume, read by chart.js and split.js */
  --mark-soft:   rgba(31, 58, 214, 0.08);
  --mark-edge:   rgba(31, 58, 214, 0.32);
  --vol-up:      rgba(13, 122, 77, 0.25);
  --vol-down:    rgba(191, 47, 40, 0.25);

  /* ── type ────────────────────────────────────────────────────── */
  --sans: "Space Grotesk", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── metrics ─────────────────────────────────────────────────── */
  --gut: 28px;             /* page gutter */
  --rail: 232px;           /* left rail */
  --topbar: 56px;
  --radius: 6px;
  --tap: 40px;             /* minimum comfortable hit target */

  /* ── motion ──────────────────────────────────────────────────────
     Motion is centralised the way colour is, and it means one thing:
     something arrived, something changed, or something is live. The
     signature is the product's own idea — elements enter compressed and
     settle, structures draw themselves in a contracting sequence. See
     docs/ALIVE.md, and web/motion-lab.html for the comparison sheet. */
  /* One dial for the whole system. 1 is the reference tempo. It ran at 2
     (half speed) for a while; that made every arrival something to wait
     through, and the app felt slow even when the data was instant. */
  --motion-scale: 1;
  /* Pointer feedback stays quick whatever the scale: a hover that takes
     180ms to answer reads as lag, not as grace. */
  --t-instant: 90ms;       /* hover, focus, press */
  --t-quick:   calc(180ms * var(--motion-scale));  /* state changes, chips */
  --t-settle:  calc(320ms * var(--motion-scale));  /* arrival, expansion */
  --t-draw:    calc(620ms * var(--motion-scale));  /* charts drawing themselves */
  --e-out:    cubic-bezier(.2, .7, .2, 1);      /* fast out, soft landing */
  --e-spring: cubic-bezier(.34, 1.32, .64, 1);  /* arrival, slight overshoot */
  --e-tight:  cubic-bezier(.7, 0, .3, 1);       /* compression: slow, then snap */
  --stagger:  calc(26ms * var(--motion-scale));  /* per-item delay */
}

/* ═══════════════════════════════════════════════════════════════════
   Dark: the same system after dark, not an inversion of it.

   The ground is the midnight slate of the logo tile and the accent is
   the logo's electric blue, lifted until it carries text contrast. Every
   ink and signal colour clears 4.5:1 on all three dark surfaces; --ink-4
   stays non-text, exactly as in light. The washes turn translucent so
   one value works on paper, surface and a hovered row alike.

   docs/DARK-THEME.md is the spec, with the measured contrast table.
   ═══════════════════════════════════════════════════════════════════ */

:root[data-theme="dark"] {
  color-scheme: dark;

  --paper:      #0c0e12;
  --surface:    #13161c;
  --sunken:     #1a1e26;
  --hairline:   rgba(226, 232, 255, 0.08);
  --hairline-2: rgba(226, 232, 255, 0.15);

  --ink:        #e9ecf2;
  --ink-2:      #b4bac5;
  --ink-3:      #8c93a0;   /* 5.4:1 on --sunken, the worst case */
  --ink-4:      #626975;   /* 3.0:1 — non-text only */

  --accent:     #7d8eff;
  --accent-ink: #a6b1ff;   /* hover goes lighter here, darker in light */
  --accent-wash:rgba(125, 142, 255, 0.14);

  --pass:       #3ecf8e;
  --pass-wash:  rgba(62, 207, 142, 0.12);
  --fail:       #ff6b63;
  --fail-wash:  rgba(255, 107, 99, 0.12);
  --warn:       #e8b04a;
  --warn-wash:  rgba(232, 176, 74, 0.12);
  --unknown:    #8c93a0;
  --unknown-wash:rgba(140, 147, 160, 0.12);

  /* White on the lifted accent is 2.9:1, so the ink inverts instead. */
  --on-ink:      #0c0e12;
  --on-accent:   #0c0e12;
  /* A selected segment is a raised chip, not a white slab: inverting to
     --ink would make the brightest thing on screen a control. */
  --selected-bg: #2a303b;
  --selected-ink:#e9ecf2;
  --glass:       rgba(12, 14, 18, 0.82);
  --glass-strong:rgba(12, 14, 18, 0.92);
  --scrim:       rgba(4, 5, 8, 0.60);
  /* Soft shadows vanish on a dark ground; these carry more opacity, and
     the hairline borders still do the real work of separating layers. */
  --shadow-float:0 16px 48px rgba(0, 0, 0, 0.55);
  --shadow-pop:  0 10px 32px rgba(0, 0, 0, 0.50);
  --shadow-edge: -12px 0 40px rgba(0, 0, 0, 0.45);
  --skeleton-hi: #232833;
  --mark-tile:   #1a1e26;  /* the tile would vanish into the topbar */
  --mark-soft:   rgba(125, 142, 255, 0.10);
  --mark-edge:   rgba(125, 142, 255, 0.40);
  --vol-up:      rgba(62, 207, 142, 0.30);
  --vol-down:    rgba(255, 107, 99, 0.30);
}

/* Switching theme must not animate: every hover transition would ripple
   across the page at once. app.js adds this for a single frame. */
html.theme-switching *, html.theme-switching *::before, html.theme-switching *::after {
  transition: none !important;
}

/* ─────────────────────────────────────────────────────── reset */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "tnum" 1, "cv05" 1;
}

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; padding: 0; }
a { color: inherit; text-decoration: none; }
[hidden] { display: none !important; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Respect a user who has asked the OS for less motion. */
/* ─────────────────────────────────────────────── chart split
   Click a stock in a list: the right half holds its weekly chart above its
   daily chart, and the list keeps the left half. */

.split { display: none; }
body.split-open .split {
  display: flex; flex-direction: column;
  position: fixed; z-index: 50; top: var(--topbar); right: 0; bottom: 0;
  width: 50vw; background: var(--paper);
  border-left: 1px solid var(--hairline-2);
}
body.split-open .page { margin-right: 50vw; max-width: none; }
/* The list keeps its columns and scrolls sideways within the left half. */
body.split-open .ledger:not(.compact) { overflow-x: auto; }
body.split-open .ledger:not(.compact) > * { min-width: max-content; }
/* The VCP table's structure glyphs would take their full natural width. */
body.split-open #vcp-out .ledger:not(.compact) > * { min-width: 1080px; }

.sp-head {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 10px 16px; border-bottom: 1px solid var(--hairline);
}
.sp-id { display: flex; align-items: baseline; gap: 12px; }
.sp-sym { font-size: 19.5px; font-weight: 700; letter-spacing: -0.02em; }
.sp-px { font-size: 14px; color: var(--ink-2); }
.sp-nav { margin-left: auto; display: flex; align-items: center; gap: 6px; }
.sp-pos { margin-right: 6px; }
.sp-step { width: 30px; padding: 0; justify-content: center; }

.sp-chart {
  position: relative; flex: 1; min-height: 0;
  display: flex; flex-direction: column; padding: 8px 8px 4px 16px;
}
.sp-chart + .sp-chart { border-top: 1px solid var(--hairline); }
.sp-label {
  display: flex; align-items: baseline; gap: 12px; padding-bottom: 4px;
  font-size: 12px; color: var(--ink-3); white-space: nowrap; overflow: hidden;
}
.sp-label .lbl { display: inline-flex; align-items: center; gap: 10px; font-weight: 600; color: var(--ink); }
.sp-ema { display: inline-flex; align-items: center; gap: 4px; font-weight: 400; color: var(--ink-3); }
.sp-ema i { display: inline-block; width: 10px; height: 2px; margin: 0 2px 0 6px; }
.sp-ema i:first-child { margin-left: 0; }
.sp-ro { margin-left: auto; font-size: 12px; }
.sp-mount { flex: 1; min-height: 0; }
.sp-msg {
  position: absolute; inset: 30px 0 0; display: grid; place-items: center;
  font-size: 14px; color: var(--ink-3); background: var(--paper); pointer-events: none;
}
.sp-msg[hidden] { display: none; }

.split-active, .lrow.split-active { background: var(--accent-wash) !important;
  box-shadow: inset 2px 0 0 var(--accent); }

@media (max-width: 860px) {
  body.split-open .split { width: 100vw; }
  body.split-open .page { margin-right: 0; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ────────────────────────────────────────────────── typography */

.display {
  font-size: clamp(35px, 4.4vw, 56px);
  font-weight: 500;
  letter-spacing: -0.035em;
  line-height: 1.02;
  margin: 0;
}
h1, .h1 {
  font-size: 26px; font-weight: 600; letter-spacing: -0.022em;
  line-height: 1.18; margin: 0;
}
h2, .h2 {
  font-size: 18.5px; font-weight: 600; letter-spacing: -0.014em;
  margin: 0;
}
h3, .h3 { font-size: 14px; font-weight: 600; margin: 0; }

/* A figure that is the answer to the section's question, rather than one
   number among many: display weight, tabular, tight. */
.figure {
  font-size: clamp(24px, 2.4vw, 32px); font-weight: 500;
  letter-spacing: -0.03em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.figure-sm { font-size: 20.5px; font-weight: 600; letter-spacing: -0.02em;
             font-variant-numeric: tabular-nums; }

.eyebrow {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-3);
}
.caption { font-size: 13px; color: var(--ink-3); line-height: 1.45; }

/* The way back out of a stock page, named after where you came from. */
.back-link {
  display: inline-block; margin-bottom: 14px;
  font-size: 13.5px; color: var(--ink-3); text-decoration: none;
}
.back-link:hover { color: var(--accent); }
.back-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
.muted   { color: var(--ink-3); }
.lede    { font-size: 16px; color: var(--ink-2); line-height: 1.55; max-width: 66ch; }
.prose   { font-size: 14.5px; color: var(--ink-2); line-height: 1.6; max-width: 72ch; }

/* Numbers are the point of this product: one face, tabular, aligned. */
.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}
.mono { font-family: var(--mono); font-size: 0.92em; letter-spacing: -0.01em; }

.up   { color: var(--pass); }
.down { color: var(--fail); }
.flat { color: var(--ink-3); }

/* ──────────────────────────────────────────────────── app shell */

.topbar {
  position: sticky; top: 0; z-index: 60;
  height: var(--topbar);
  display: flex; align-items: center; gap: 20px;
  padding: 0 var(--gut);
  background: var(--glass);
  backdrop-filter: saturate(1.6) blur(12px);
  border-bottom: 1px solid var(--hairline);
}

.wordmark {
  font-size: 18.5px; font-weight: 700; letter-spacing: -0.03em;
  display: inline-flex; align-items: center; gap: 8px;
}
/* The mark: a range tightening under a resistance line — web/brand/logo.svg */
.wordmark .mark { width: 22px; height: 22px; flex: none; display: block; }

.nav { display: flex; align-items: center; gap: 0; margin-left: 6px; }
/* The groups are the product's shape: discover, context, follow. A
   hairline between them is enough to show it; labelling them in the bar
   would turn navigation into a menu of itself. */
.nav-group { display: flex; gap: 2px; }
.nav-group + .nav-group {
  margin-left: 10px; padding-left: 10px;
  border-left: 1px solid var(--hairline);
}
.nav a {
  position: relative;
  padding: 7px 10px; border-radius: var(--radius);
  font-size: 14px; font-weight: 500; color: var(--ink-3);
  transition: color 0.12s;
}
.nav a:hover { color: var(--ink); }
.nav a.on { color: var(--ink); font-weight: 600; }
/* The active page is marked by a tick under it rather than a filled
   chip: one small solid mark in a bar of text reads as "you are here"
   without the bar turning into a row of buttons. */
.nav a.on::before {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: 1px;
  height: 2px; border-radius: 1px; background: var(--ink);
}

.topbar-end { margin-left: auto; display: flex; align-items: center; gap: 10px; }

.searchbtn {
  display: flex; align-items: center; gap: 8px;
  height: 32px; padding: 0 10px 0 11px;
  border: 1px solid var(--hairline); border-radius: var(--radius);
  background: var(--surface); color: var(--ink-3); font-size: 14px;
  min-width: 190px;
}
.searchbtn:hover { border-color: var(--hairline-2); color: var(--ink-2); }

/* The theme toggle shows the theme it will switch *to*: a sun while dark
   is on offer would read as "currently light", which is what the page
   already shows. */
.theme-toggle {
  display: grid; place-items: center; width: 32px; height: 32px; flex: none;
  border: 1px solid var(--hairline); border-radius: var(--radius);
  background: var(--surface); color: var(--ink-3);
  transition: color 0.12s, border-color 0.12s;
}
.theme-toggle:hover { border-color: var(--hairline-2); color: var(--ink); }
.theme-toggle svg { transition: transform 0.16s cubic-bezier(.2,.7,.2,1); }
.theme-toggle:hover svg { transform: rotate(15deg); }
.theme-toggle .moon { display: none; }
:root[data-theme="dark"] .theme-toggle .sun { display: none; }
:root[data-theme="dark"] .theme-toggle .moon { display: block; }
@media (prefers-reduced-motion: reduce) {
  .theme-toggle svg, .theme-toggle:hover svg { transition: none; transform: none; }
}
.searchbtn kbd {
  margin-left: auto; font-family: var(--mono); font-size: 11.5px;
  color: var(--ink-4); border: 1px solid var(--hairline);
  border-radius: 4px; padding: 1px 4px;
}

.page { padding: 26px var(--gut) 96px; max-width: 1560px; }

/* ════════════════════════════════════════════ editorial page head

   Every page opens the same way: what kind of page this is, what it is
   called, what it is for, and the facts behind it. The order is fixed so
   that moving between pages feels like turning a page, not switching
   tools. The rule underneath is the product's mark — see .tension. */

.page-head { margin-bottom: 30px; padding-bottom: 18px; position: relative; }
.page-head .display { margin-bottom: 10px; }
.page-head .eyebrow { display: block; margin-bottom: 12px; }
.page-head .lede { font-size: 17.5px; max-width: 62ch; }
.page-head-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 18px;
  margin-top: 16px; font-size: 12.5px; color: var(--ink-3);
  font-family: var(--mono); letter-spacing: -0.01em;
}
.page-head-meta b { color: var(--ink-2); font-weight: 500; }
.page-head-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }

/* The mark of the product, drawn rather than illustrated: a rule whose
   ticks tighten from left to right. Compression, stated once per page in
   the quietest way available — a hairline. */
.tension {
  /* An absolutely placed SVG takes its width from its viewBox ratio, not
     from left/right — 1,000px at this height, which made every page
     scroll sideways on a phone. */
  position: absolute; left: 0; right: 0; bottom: 0; height: 9px; width: 100%;
  display: block; color: var(--hairline-2);
}
.tension line { stroke: currentColor; stroke-width: 1; }
.tension .base { stroke: var(--hairline); }

/* ─────────────────────────────────────────────────────── sections */

.section { margin-top: 52px; }
/* Only the first section of a *page* loses its top margin. A section that
   happens to be the first child of a container the view painted into is
   still following something. */
.page > .section:first-child,
.page > div:first-child > .section:first-child { margin-top: 0; }
/* Title and its note stack on the left, the action sits right: a note set
   beside the title in a wide column drifts into the middle of the page and
   reads as a stray sentence. */
.section-head, .sec-head {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: end; gap: 4px 20px;
  padding-bottom: 12px; margin-bottom: 4px;
  border-bottom: 1px solid var(--hairline);
}
.section-head .h2, .sec-head .h2 { grid-column: 1; margin-right: auto; }
.section-head > .section-label, .sec-head > .section-label { grid-column: 1; }
.section-head > .btn, .sec-head > .btn,
.section-head > a.btn, .sec-head > a.btn,
.section-head > .seg-ctl, .sec-head > .seg-ctl,
.section-head > div > .seg-ctl, .sec-head > div > .seg-ctl,
.section-head > input, .sec-head > input {
  grid-column: 2; grid-row: span 1; justify-self: end; align-self: center;
}
/* The label sits above the title, so a section announces its role before
   its name — the same order the page head uses. */
.section-label {
  display: block; width: 100%;
  font-size: 11px; font-weight: 600; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-4);
  margin-bottom: 7px;
}
.section-note {
  grid-column: 1; margin-top: 2px;
  font-size: 13.5px; color: var(--ink-3); line-height: 1.5; max-width: 72ch;
}
.section-body { padding-top: 16px; }

/* ─────────────────────────────────────────── market pulse pill */

.pulse {
  display: inline-flex; align-items: center; gap: 8px;
  height: 32px; padding: 0 12px;
  border-radius: 999px; border: 1px solid var(--hairline);
  background: var(--surface);
  font-size: 13.5px; font-weight: 600; white-space: nowrap;
}
.pulse:hover { border-color: var(--hairline-2); }
.pulse .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.pulse[data-tone="positive"] { color: var(--pass);    background: var(--pass-wash);    border-color: transparent; }
.pulse[data-tone="positive"] .dot { background: var(--pass); }
.pulse[data-tone="caution"]  { color: var(--warn);    background: var(--warn-wash);    border-color: transparent; }
.pulse[data-tone="caution"] .dot  { background: var(--warn); }
.pulse[data-tone="negative"] { color: var(--fail);    background: var(--fail-wash);    border-color: transparent; }
.pulse[data-tone="negative"] .dot { background: var(--fail); }
.pulse[data-tone="unknown"]  { color: var(--ink-3);   background: var(--unknown-wash); border-color: transparent; }
.pulse[data-tone="unknown"] .dot  { background: var(--unknown); }

/* The market banner: context that changes what the results mean, so it
   sits above them rather than in a corner. */
/* The market state as a statement with a tone rule at its edge, not as a
   panel. It appears on most pages, and a bordered box repeated five times
   is what makes an application look like a dashboard. */
.market-banner {
  display: flex; gap: 16px; align-items: flex-start;
  padding: 2px 0; margin: 0 0 26px;
  max-width: 86ch;
}
.market-banner .bar { width: 2px; border-radius: 1px; align-self: stretch; flex: none; }
.market-banner[data-tone="positive"] .bar { background: var(--pass); }
.market-banner[data-tone="caution"]  .bar { background: var(--warn); }
.market-banner[data-tone="negative"] .bar { background: var(--fail); }
.market-banner[data-tone="unknown"]  .bar { background: var(--unknown); }
.market-banner .why { font-size: 13.5px; color: var(--ink-2); margin-top: 3px; }
.market-banner .why b { font-weight: 600; color: var(--ink); }

/* ═══════════════════════════════════════════════════ the runner

   The controls that start a scan. A quiet band rather than a panel: it is
   a setting, not a result, and it should not compete with the rows it
   produces. */

.runner { margin: 4px 0 22px; }
.runner-row {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px 18px;
}
.runner .field { display: inline-flex; flex-direction: column; gap: 5px; }
.runner .field .k {
  font-size: 11px; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-4);
}
.runner .caption { margin: 10px 0 0; max-width: 72ch; }

/* ══════════════════════════════════════════ the lead (Today's top)

   The market read at the size of its consequence. No box: the statement
   itself is the object, with a tone rule at its left edge and the
   evidence set as a list underneath. */

.lead { margin: 6px 0 12px; padding-left: 20px; position: relative; max-width: 74ch; }
.lead::before {
  content: ""; position: absolute; left: 0; top: 4px; bottom: 4px; width: 2px;
  border-radius: 1px; background: var(--unknown);
}
.lead[data-tone="positive"]::before { background: var(--pass); }
.lead[data-tone="caution"]::before  { background: var(--warn); }
.lead[data-tone="negative"]::before { background: var(--fail); }
.lead .eyebrow { display: block; margin-bottom: 8px; }
.lead-title {
  font-size: clamp(26px, 3vw, 37px); font-weight: 500;
  letter-spacing: -0.03em; line-height: 1.08; margin: 0;
}
.lead-say { font-size: 16px; color: var(--ink-2); line-height: 1.5;
            margin: 10px 0 0; max-width: 60ch; }
/* The evidence, as separate clauses rather than one run-on sentence: each
   is a separate test the read is standing on. */
.lead-why {
  list-style: none; margin: 14px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 6px 0;
}
.lead-why li {
  font-size: 13px; color: var(--ink-3); font-family: var(--mono);
  letter-spacing: -0.01em; padding-right: 14px; margin-right: 14px;
  border-right: 1px solid var(--hairline);
}
.lead-why li:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.lead-more { display: inline-block; margin-top: 18px; margin-bottom: 6px; font-size: 13.5px;
             color: var(--accent); }
.lead-more:hover { text-decoration: underline; text-underline-offset: 2px; }

/* ══════════════════════════════════════════════ featured setups

   Three rows, each carrying its own reason. Deliberately rows and not
   cards: a card would put a border around a sentence, and three bordered
   sentences is the card soup this product is trying not to be. */

.feature { border-top: 1px solid var(--hairline-2); }
.feature-row {
  display: grid; grid-template-columns: 210px minmax(0, 1fr) auto 160px;
  gap: 10px 26px; align-items: baseline;
  padding: 20px 4px 20px 0;
  border-bottom: 1px solid var(--hairline);
  transition: background 0.12s;
}
.feature-row:hover { background: var(--sunken); }
.feature-id { display: flex; flex-direction: column; gap: 7px; }
.feature-sym {
  font-size: 22.5px; font-weight: 600; letter-spacing: -0.02em;
  font-family: var(--mono);
}
.feature-state {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--ink-3);
}
.feature-state[data-s="BREAKOUT"],
.feature-state[data-s="BREAKOUT_CONFIRMED"] { color: var(--pass); }
.feature-state[data-s="NEAR_PIVOT"] { color: var(--warn); }
.feature-why {
  margin: 0; font-size: 15px; line-height: 1.55; color: var(--ink-2);
  max-width: 62ch;
}
.feature-why b { color: var(--ink); font-weight: 600; }
.feature-px {
  display: flex; flex-direction: column; align-items: flex-end; gap: 4px;
  font-size: 13.5px;
}
.feature-rest { margin: 16px 0 0; font-size: 13.5px; color: var(--ink-3); }
.feature-rest a { color: var(--accent); }

@media (max-width: 860px) {
  .feature-row { grid-template-columns: 1fr auto; gap: 8px 16px; padding: 16px 0; }
  .feature-why { grid-column: 1 / -1; font-size: 14px; }
  .feature-px { align-items: flex-end; }
  .lead { padding-left: 14px; }
}

/* ────────────────────────────────────────────── status vocabulary */

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  height: 20px; padding: 0 7px; border-radius: 4px;
  font-size: 12px; font-weight: 600; letter-spacing: 0.01em;
  white-space: nowrap;
}
.chip[data-s="PASS"]     { color: var(--pass);    background: var(--pass-wash); }
.chip[data-s="FAIL"]     { color: var(--fail);    background: var(--fail-wash); }
.chip[data-s="PARTIAL"]  { color: var(--warn);    background: var(--warn-wash); }
.chip[data-s="UNKNOWN"],
.chip[data-s="REQUIRES_ANALYSIS"] { color: var(--ink-3); background: var(--unknown-wash); }
.chip.ghost { background: none; border: 1px solid var(--hairline); color: var(--ink-2); font-weight: 500; }

/* Provenance badges — where a rule's authority comes from. Deliberately
   quiet: they inform, they don't decorate. */
.prov {
  display: inline-flex; align-items: center;
  font-size: 11px; font-weight: 600; letter-spacing: 0.04em;
  text-transform: uppercase; padding: 1px 5px; border-radius: 3px;
  border: 1px solid var(--hairline); color: var(--ink-3);
}
.prov[data-p="BOOK_EXPLICIT"]  { color: var(--accent-ink); border-color: color-mix(in srgb, var(--accent) 28%, transparent); }
.prov[data-p="IMPL_DEFINED"]   { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }
.prov[data-p="PROPRIETARY"]    { color: var(--fail); border-color: color-mix(in srgb, var(--fail) 28%, transparent); }

/* ═══════════════════════════════════════════════════════════════
   The spine — this product's signature mark.

   Seven letters, each carrying its own verdict as a weight underneath.
   The same object renders at three sizes: inline in a results row, at
   reading size in a stock header, and large on the strategy page. It is
   the one visual that says what this app is.
   ═══════════════════════════════════════════════════════════════ */

.spine { display: inline-flex; gap: 3px; align-items: flex-end; }

.spine .seg {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  min-width: 13px;
}
.spine .seg .l {
  font-size: 11px; font-weight: 700; letter-spacing: 0.02em;
  color: var(--ink-4); line-height: 1;
}
.spine .seg .b { height: 3px; width: 100%; border-radius: 1px; background: var(--unknown-wash); }
.spine .seg[data-s="PASS"]    .b { background: var(--pass); }
.spine .seg[data-s="PASS"]    .l { color: var(--ink-2); }
.spine .seg[data-s="FAIL"]    .b { background: var(--fail); }
.spine .seg[data-s="FAIL"]    .l { color: var(--ink-4); }
.spine .seg[data-s="PARTIAL"] .b { background: var(--warn); }
.spine .seg[data-s="PARTIAL"] .l { color: var(--ink-2); }

.spine.lg .seg { min-width: 34px; gap: 6px; }
.spine.lg .seg .l { font-size: 18.5px; }
.spine.lg .seg .b { height: 5px; border-radius: 2px; }
.spine.md .seg { min-width: 22px; gap: 5px; }
.spine.md .seg .l { font-size: 14px; }
.spine.md .seg .b { height: 4px; }

/* ═══════════════════════════════════ ledger — the list primitive

   Full-width rows on hairlines. No boxes, no cards, no shadows. A row
   expands in place rather than navigating away, because "why is this
   here?" should not cost a page load.
   ═══════════════════════════════════════════════════════════════ */

.ledger { border-top: 1px solid var(--hairline); }

.ledger-head,
.lrow {
  display: grid;
  grid-template-columns: var(--cols, 190px 92px 74px 148px 120px 92px 110px 128px 1fr);
  gap: 14px; align-items: center;
}

.ledger-head {
  position: sticky; top: var(--topbar); z-index: 20;
  padding: 8px var(--gut) 8px 4px; margin: 0 calc(var(--gut) * -1) 0 -4px;
  padding-left: calc(var(--gut) + 4px);
  background: var(--glass-strong);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--hairline);
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-3);
}
.ledger-head button {
  font: inherit; color: inherit; letter-spacing: inherit;
  text-transform: inherit; display: inline-flex; align-items: center; gap: 3px;
}
.ledger-head button:hover { color: var(--ink); }
.ledger-head .sorted { color: var(--ink); }

.lrow {
  padding: 11px 4px; border-bottom: 1px solid var(--hairline);
  cursor: pointer; transition: background 0.1s;
}
.lrow:hover { background: var(--surface); }
.lrow[aria-expanded="true"] { background: var(--surface); }

.lrow .sym { font-weight: 600; font-size: 15px; letter-spacing: -0.01em; }
.lrow .co {
  display: block; font-size: 12.5px; color: var(--ink-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.r { text-align: right; }
.tnum { font-variant-numeric: tabular-nums; }

.ind {
  font-size: 12.5px; color: var(--ink-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ind.derived { color: var(--ink-3); border-bottom: 1px dotted var(--hairline-2); }

/* Expanded detail lives inside the ledger, on the same hairline grid. */
.lrow-detail {
  padding: 4px 4px 26px; border-bottom: 1px solid var(--hairline);
  background: var(--surface);
}
.why-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 18px 30px; margin-top: 12px;
}

.why-list { list-style: none; margin: 6px 0 0; padding: 0; }
.why-list li {
  display: flex; gap: 8px; align-items: baseline;
  padding: 4px 0; font-size: 13.5px; line-height: 1.45;
  border-bottom: 1px solid var(--hairline);
}
.why-list li:last-child { border-bottom: 0; }
.why-list .mark { flex: none; width: 13px; font-weight: 700; font-size: 12px; }
.why-list li[data-s="PASS"] .mark { color: var(--pass); }
.why-list li[data-s="FAIL"] .mark { color: var(--fail); }
.why-list li[data-s="PARTIAL"] .mark { color: var(--warn); }
.why-list li[data-s="UNKNOWN"] .mark,
.why-list li[data-s="REQUIRES_ANALYSIS"] .mark { color: var(--ink-4); }
.why-list .txt { color: var(--ink-2); }
.why-list .txt b { color: var(--ink); font-weight: 600; }

/* ───────────────────────────────────────────────── rule ledger */

.rule {
  display: grid; grid-template-columns: 1fr 200px 80px;
  min-width: 0;
  gap: 16px; align-items: baseline;
  padding: 12px 4px; border-bottom: 1px solid var(--hairline);
}
.rule.rule-wide { grid-template-columns: 1fr 230px 120px; }
.rule > * { min-width: 0; }
.rule .name { font-size: 14.5px; font-weight: 500; }
.rule .desc { font-size: 13px; color: var(--ink-3); margin-top: 3px; line-height: 1.5; }
.rule .cite {
  font-size: 12.5px; color: var(--ink-3); margin-top: 5px;
  font-style: italic; padding-left: 9px; border-left: 2px solid var(--hairline);
}
.rule .meas { font-size: 13.5px; color: var(--ink-2); }
.rule .meas .k { color: var(--ink-3); }
.rule .meas .v { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.rule-meta { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; }

/* Pass-rate bar on the strategy page: how much each rule actually filters. */
.ratebar {
  height: 4px; border-radius: 2px; background: var(--sunken);
  overflow: hidden; margin-top: 6px;
}
.ratebar i { display: block; height: 100%; background: var(--accent); border-radius: 2px; }

/* ────────────────────────────────────────── growth spark (EPS/sales)

   The acceleration reading the brief asks for: four quarters side by
   side, so a rising series reads as a shape rather than a single number. */

/* Growth bars carry direction, so they take the signal colours. They used
   the accent, which is reserved for things you can click — on a chart it
   read as "this bar is interactive" and broke the one colour rule the
   design system has. */
.growth { display: flex; gap: 3px; align-items: flex-end; height: 52px; }
.growth .q { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; gap: 3px; min-width: 26px; }
.growth .q i { display: block; border-radius: 2px 2px 0 0; background: var(--pass); opacity: 0.45; }
.growth .q.neg i { background: var(--fail); opacity: 0.45; }
.growth .q.best i { opacity: 1; }
.growth-labels span.v { font-variant-numeric: tabular-nums; }
.growth-labels { display: flex; gap: 3px; margin-top: 4px; }
.growth-labels span {
  flex: 1; min-width: 26px; text-align: center;
  font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.growth-labels span.v { color: var(--ink-2); font-weight: 600; }

/* ─────────────────────────────────────────────── base card / glyph */

/* The schematic is drawn at a size you can actually read the shape at,
   and sits beside the numbers rather than under them. */
.base {
  display: grid; grid-template-columns: 190px 1fr;
  gap: 28px; align-items: start;
}
.base svg { width: 190px; height: 96px; overflow: visible; margin-top: 6px; }
.base .shape { fill: none; stroke: var(--ink-2); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.base .pivot { stroke: var(--accent); stroke-width: 1.2; stroke-dasharray: 3 3; }
.base .now   { fill: var(--accent); }

.base-facts { display: flex; flex-wrap: wrap; gap: 4px 26px; }
.fact { min-width: 92px; }
.fact .k { font-size: 11.5px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-3); }
.fact .v { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.fact .v small { font-size: 12px; font-weight: 500; color: var(--ink-3); }

/* ───────────────────────────────────────── distribution-day ribbon */

.ribbon { display: flex; gap: 2px; align-items: flex-end; height: 26px; }
.ribbon i {
  flex: 1; min-width: 2px; height: 8px; border-radius: 1px;
  background: var(--sunken);
}
.ribbon i.d { background: var(--fail); height: 22px; }
.ribbon i.f { background: var(--pass); height: 22px; }

/* ─────────────────────────────────────────────────── buttons */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  height: 32px; padding: 0 13px; border-radius: var(--radius);
  border: 1px solid var(--hairline); background: var(--surface);
  font-size: 14px; font-weight: 500; color: var(--ink);
  transition: background 0.12s, border-color 0.12s;
}
.btn:hover { background: var(--sunken); border-color: var(--hairline-2); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary {
  background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600;
}
.btn-primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.btn-sm { height: 27px; padding: 0 9px; font-size: 13px; }
.btn-ghost { border-color: transparent; background: none; color: var(--ink-2); }
.btn-ghost:hover { background: var(--sunken); }

.seg-ctl { display: inline-flex; border: 1px solid var(--hairline); border-radius: var(--radius); overflow: hidden; }
.seg-ctl button {
  height: 30px; padding: 0 11px; font-size: 13.5px; color: var(--ink-2);
  border-right: 1px solid var(--hairline); background: var(--surface);
}
.seg-ctl button:last-child { border-right: 0; }
.seg-ctl button:hover { background: var(--sunken); }
.seg-ctl button.on, .seg-ctl a.on { background: var(--selected-bg); color: var(--selected-ink); font-weight: 600; }

select, input[type="text"], input[type="number"], input[type="search"] {
  height: 32px; padding: 0 9px; border-radius: var(--radius);
  border: 1px solid var(--hairline); background: var(--surface); color: var(--ink);
  font-size: 14px; min-width: 0;
}
select:hover, input:hover { border-color: var(--hairline-2); }
select { padding-right: 26px; appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%2382888f' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 9px center; }

/* ──────────────────────────────────────────────── screen builder

   A layered workflow, not a wall of checkboxes: universe, then strategy,
   then optional refinements, then run. Each step states what it does. */

/* The builder reads as four numbered moves, not as a form: where to look,
   what to look for, your own refinements, then run. */
.steps { display: grid; gap: 0; border-top: 1px solid var(--hairline-2);
         margin-bottom: 8px; }
.step {
  display: grid; grid-template-columns: 26px 190px 1fr;
  gap: 18px; align-items: start;
  padding: 18px 4px; border-bottom: 1px solid var(--hairline);
}
.step .n {
  width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--hairline-2); color: var(--ink-3);
  display: grid; place-items: center; font-size: 12px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.step.done .n { background: var(--selected-bg); border-color: var(--selected-bg); color: var(--selected-ink); }
.step .label .h3 { margin-bottom: 3px; }
.step .body { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }

.pick {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 13px; border: 1px solid var(--hairline);
  border-radius: var(--radius); background: var(--surface);
  text-align: left; min-width: 230px;
}
.pick:hover { border-color: var(--hairline-2); }
.pick.on { border-color: var(--accent); background: var(--accent-wash); }
.pick .t { font-size: 14.5px; font-weight: 600; }
.pick .s { font-size: 12.5px; color: var(--ink-3); }

.chipset { display: flex; flex-wrap: wrap; gap: 6px; }
.tog {
  height: 27px; padding: 0 10px; border-radius: 999px;
  border: 1px solid var(--hairline); background: var(--surface);
  font-size: 13px; color: var(--ink-2);
}
.tog:hover { border-color: var(--hairline-2); }
.tog.on { background: var(--selected-bg); border-color: var(--selected-bg); color: var(--selected-ink); font-weight: 500; }

/* ─────────────────────────────────────────────────── progress */

.progress { padding: 14px 0 18px; }
.progress-head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 13.5px; margin-bottom: 8px;
}
.track { height: 2px; background: var(--sunken); border-radius: 1px; overflow: hidden; }
.track i {
  display: block; height: 100%; background: var(--accent);
  transition: width 0.3s ease;
}
.stages { display: flex; gap: 14px; margin-top: 10px; flex-wrap: wrap; }
.stages span { font-size: 12.5px; color: var(--ink-4); }
.stages span.on  { color: var(--accent); font-weight: 600; }
.stages span.was { color: var(--ink-3); }

/* funnel: where the universe went */
.funnel { display: flex; flex-wrap: wrap; gap: 0; margin: 20px 0 4px;
          border-top: 1px solid var(--hairline-2);
          border-bottom: 1px solid var(--hairline); }
.funnel .f {
  padding: 16px 20px 15px 0; margin-right: 0;
  display: grid; gap: 4px; align-content: start;
  border-right: 1px solid var(--hairline);
}
.funnel .f + .f { padding-left: 20px; }
.funnel .f:last-child { border-right: 0; }
.funnel .f .k { font-size: 11px; font-weight: 600; text-transform: uppercase;
                letter-spacing: 0.12em; color: var(--ink-4); }
.funnel .f .v { font-size: 29px; font-weight: 500; font-variant-numeric: tabular-nums;
                letter-spacing: -0.03em; line-height: 1; }

/* ────────────────────────────────────────── states: empty / error */

.state {
  padding: 44px 4px; max-width: 60ch;
}
.state .h2 { margin-bottom: 7px; }
.state p { font-size: 14.5px; color: var(--ink-2); line-height: 1.6; margin: 0 0 12px; }
.state ul { margin: 10px 0 16px; padding-left: 18px; font-size: 14px; color: var(--ink-2); line-height: 1.7; }

.skeleton {
  background: linear-gradient(90deg, var(--sunken) 25%, var(--skeleton-hi) 37%, var(--sunken) 63%);
  background-size: 400% 100%;
  animation: sheen 1.3s ease infinite;
  border-radius: 3px;
}
@keyframes sheen { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

/* ─────────────────────────────────────────── command palette */

.scrim {
  position: fixed; inset: 0; z-index: 90;
  background: var(--scrim);
  backdrop-filter: blur(2px);
}
.palette {
  position: fixed; z-index: 100; top: 14vh; left: 50%; transform: translateX(-50%);
  width: min(560px, calc(100vw - 32px));
  background: var(--surface); border: 1px solid var(--hairline-2);
  border-radius: 10px; box-shadow: var(--shadow-float);
  overflow: hidden;
}
.palette input {
  width: 100%; height: 48px; border: 0; border-bottom: 1px solid var(--hairline);
  border-radius: 0; padding: 0 16px; font-size: 16px;
}
.palette input:focus { outline: none; }
.palette-list { max-height: 52vh; overflow-y: auto; padding: 6px; }
.palette-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px 10px; border-radius: var(--radius); text-align: left;
}
.palette-row:hover, .palette-row.on { background: var(--sunken); }
.palette-row .t { font-weight: 600; font-size: 14.5px; }
.palette-row .s { font-size: 13px; color: var(--ink-3); margin-left: auto; }
.palette-group {
  padding: 9px 10px 4px; font-size: 11.5px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-4); font-weight: 600;
}

/* ──────────────────────────────────────────────────── drawer */

.drawer {
  position: fixed; z-index: 95; top: 0; right: 0; bottom: 0;
  width: min(760px, 94vw); background: var(--paper);
  border-left: 1px solid var(--hairline-2);
  box-shadow: var(--shadow-edge);
  display: flex; flex-direction: column;
}
.drawer-head {
  display: flex; align-items: flex-start; gap: 14px;
  padding: 16px 20px 13px; border-bottom: 1px solid var(--hairline);
}
.drawer-body { flex: 1; overflow-y: auto; padding: 18px 20px 60px; }

/* ────────────────────────────────────── stock page composition */

.stock-head {
  display: flex; flex-wrap: wrap; gap: 26px 44px; align-items: flex-end;
  padding-bottom: 22px; margin-bottom: 4px;
  border-bottom: 1px solid var(--hairline-2);
}
.price-now {
  font-size: clamp(32px, 3.4vw, 43px); font-weight: 500;
  letter-spacing: -0.035em; line-height: 1; font-variant-numeric: tabular-nums;
}

.cols-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 26px 40px; }
.cols-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px 34px; }

.kv { display: grid; grid-template-columns: 1fr auto; gap: 4px 14px; align-items: baseline; }
.kv dt { font-size: 13.5px; color: var(--ink-2); padding: 5px 0; border-bottom: 1px solid var(--hairline); }
.kv dd {
  margin: 0; padding: 5px 0; font-size: 14px; font-weight: 600;
  font-variant-numeric: tabular-nums; text-align: right;
  border-bottom: 1px solid var(--hairline);
}
.kv dd.unknown { color: var(--ink-4); font-weight: 500; }

/* A term the reader may not know, explained on hover and on focus. */
.term {
  border-bottom: 1px dotted var(--hairline-2); cursor: help;
}

/* ────────────────────────────────────────────── strategy cards */

.strategy-list { border-top: 1px solid var(--hairline); }
.strategy-row {
  display: grid; grid-template-columns: 1fr 280px 150px;
  gap: 30px; align-items: center; padding: 22px 4px;
  border-bottom: 1px solid var(--hairline); width: 100%; text-align: left;
}
.strategy-row:hover { background: var(--surface); }
.strategy-row .meta { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 9px; }
.strategy-row .meta span { font-size: 12.5px; color: var(--ink-3); }

/* ─────────────────────────────────────────────────── density */

body[data-density="analyst"] { font-size: 14px; }
body[data-density="analyst"] .lrow { padding: 7px 4px; }
body[data-density="analyst"] .rule { padding: 8px 4px; }

/* ─────────────────────────────────────────────── responsive

   Mobile is a different composition, not a squeezed desktop: the ledger
   stops being a grid and becomes a stack whose first line answers the
   question the row exists to answer. */

@media (max-width: 1180px) {
  .ledger-head, .lrow { --cols: 170px 84px 70px 1fr 100px 96px; }
  .lrow > .hide-lg, .ledger-head > .hide-lg { display: none; }
  .cols-3 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 860px) {
  :root { --gut: 16px; }

  .nav { display: none; }
  .searchbtn { min-width: 0; }
  .searchbtn span { display: none; }

  .cols-2, .cols-3 { grid-template-columns: 1fr; }
  .step { grid-template-columns: 22px 1fr; }
  .step .label { grid-column: 2; }
  .step .body { grid-column: 2; }
  .strategy-row { grid-template-columns: 1fr; gap: 14px; }
  .rule, .rule.rule-wide { grid-template-columns: 1fr; gap: 8px; }
  .rule .r { text-align: left; }
  .kv { grid-template-columns: 1fr auto; }
  .funnel .f { padding-right: 14px; margin-right: 14px; }
  .base { grid-template-columns: 1fr; }

  .ledger-head { display: none; }
  .lrow {
    display: grid; grid-template-columns: 1fr auto; gap: 3px 12px;
    padding: 13px 2px;
  }
  .lrow > * { grid-column: auto; }
  .lrow .cell-sym  { grid-column: 1; grid-row: 1; }
  .lrow .cell-px   { grid-column: 2; grid-row: 1; text-align: right; }
  .lrow .cell-spine{ grid-column: 1 / -1; grid-row: 2; margin-top: 5px; }
  .lrow .cell-mob  { grid-column: 1 / -1; grid-row: 3; font-size: 13px; color: var(--ink-3); }
  .lrow > .mob-hide { display: none; }

  /* A tap target on a phone has to be a real one. */
  .btn, .tog, .seg-ctl button { min-height: var(--tap); }
  .theme-toggle { width: var(--tap); height: var(--tap); }
  .nav-mobile {
    position: fixed; bottom: 0; left: 0; right: 0; z-index: 70;
    display: flex; background: var(--glass-strong);
    backdrop-filter: blur(12px); border-top: 1px solid var(--hairline);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .nav-mobile a {
    /* Sized to their labels, so eight entries fit a 375px phone. */
    flex: 1 1 auto; min-width: 0; text-align: center; padding: 10px 2px 11px;
    font-size: 11.5px; font-weight: 500; color: var(--ink-3); white-space: nowrap;
  }
  .nav-mobile a.on { color: var(--accent); font-weight: 600; }
  .page { padding-bottom: 90px; }
  .drawer { width: 100vw; }
}

@media (min-width: 861px) { .nav-mobile { display: none; } }

/* ═══════════════════════════════════════════════════ price chart

   The chart sits inside the stock page rather than on a page of its own:
   the question it answers — is this actionable right now — belongs next
   to the base and the scorecard, not one navigation step away. */

.chart-controls {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding-bottom: 10px; margin-bottom: 12px;
  border-bottom: 1px solid var(--hairline);
}
.chart-controls-right { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }

.chart-legend-inline {
  display: flex; gap: 14px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--ink-3);
}
.chart-legend-inline i {
  display: inline-block; width: 10px; height: 2px; border-radius: 1px;
  margin-right: 5px; vertical-align: middle;
}

/* chart.js emits `.seg`; the app's segmented control is `.seg-ctl`. Both
   are the same object, so they share one appearance. */
.seg { display: inline-flex; border: 1px solid var(--hairline);
       border-radius: var(--radius); overflow: hidden; }
.seg button {
  height: 28px; padding: 0 10px; font-size: 13px; color: var(--ink-2);
  border-right: 1px solid var(--hairline); background: var(--surface);
}
.seg button:last-child { border-right: 0; }
.seg button:hover { background: var(--sunken); }
.seg button.on { background: var(--selected-bg); color: var(--selected-ink); font-weight: 600; }

.chart-host { position: relative; }
.lwc-mount { height: 380px; }
/* On the stock page the chart is the page's primary object rather than
   one panel among many, so it gets real height and the full column. */
.chart-hero { margin-top: 18px; }
.chart-hero .lwc-mount { height: clamp(380px, 52vh, 620px); }
.vcp-overlay {
  position: absolute; inset: 0; pointer-events: none; overflow: visible;
}
.vo-depth { fill: none; stroke: var(--accent); stroke-width: 1;
            stroke-dasharray: 3 3; opacity: 0.55; }
.vo-num { font-size: 11px; fill: var(--accent); font-variant-numeric: tabular-nums; }

.chart-readout {
  display: flex; gap: 16px; flex-wrap: wrap;
  padding-top: 9px; margin-top: 4px; min-height: 26px;
  border-top: 1px solid var(--hairline);
  font-size: 13px; font-variant-numeric: tabular-nums; color: var(--ink-2);
}
.chart-readout .ro-empty { color: var(--ink-3); }
.chart-readout .ro-date { font-weight: 600; color: var(--ink); }
.chart-readout .ro-vol { color: var(--ink-3); }

.chart-empty {
  padding: 40px 4px; color: var(--ink-3); font-size: 14px;
  border: 1px dashed var(--hairline-2); border-radius: var(--radius);
  text-align: center;
}

.tgl {
  height: 28px; padding: 0 10px; border-radius: var(--radius);
  border: 1px solid var(--hairline); background: var(--surface);
  font-size: 13px; color: var(--ink-2);
}
.tgl.on { background: var(--accent-wash); border-color: var(--accent);
          color: var(--accent-ink); font-weight: 600; }

.ladder { display: inline-flex; gap: 2px; align-items: flex-end; }

@media (max-width: 860px) {
  .lwc-mount { height: 280px; }
  .chart-controls-right { margin-left: 0; width: 100%; }
}

/* ───────────────────────────── column filter menu (Base column)

   Anchored to its column header rather than parked in a toolbar, so the
   control sits where the thing it filters is. */

.col-filter button { display: inline-flex; align-items: center; gap: 4px; }

.colmenu {
  position: absolute; z-index: 80; width: 292px;
  background: var(--surface); border: 1px solid var(--hairline-2);
  border-radius: 8px; box-shadow: var(--shadow-pop);
  padding: 5px; overflow: hidden;
}
.colmenu-row {
  display: block; width: 100%; text-align: left;
  padding: 8px 10px; border-radius: var(--radius);
}
.colmenu-row:hover, .colmenu-row:focus-visible { background: var(--sunken); }
.colmenu-row .t {
  display: flex; align-items: baseline; gap: 8px;
  font-size: 14px; font-weight: 600; text-transform: none; letter-spacing: 0;
  color: var(--ink);
}
.colmenu-row .t .n {
  margin-left: auto; font-variant-numeric: tabular-nums;
  font-weight: 500; color: var(--ink-3); font-size: 13px;
}
.colmenu-row .s {
  display: block; margin-top: 2px; font-size: 12.5px; line-height: 1.45;
  color: var(--ink-3); text-transform: none; letter-spacing: 0; font-weight: 400;
}
.colmenu-row.on { background: var(--accent-wash); }
.colmenu-row.on .t { color: var(--accent-ink); }

/* ═══════════════════════════════════════════════════ sector flow

   A treemap and a scatter plot were the wrong instruments here: with 22
   industries whose names run to three words, both spend their pixels on
   labels that collide and clip, and neither can be read at a glance.

   What replaces them is one object — a ranked ledger where each row
   carries its own small charts. Nothing can overlap, it scales to any
   number of industries, and every visual is anchored to the same
   baseline so rows compare directly down the column. */

.flow-summary {
  display: flex; flex-wrap: wrap; gap: 0;
  padding: 16px 0 18px; border-bottom: 1px solid var(--hairline);
  margin-bottom: 4px;
}
.flow-summary .f { padding-right: 26px; margin-right: 26px;
                   border-right: 1px solid var(--hairline); }
.flow-summary .f:last-child { border-right: 0; }
.flow-summary .k {
  display: block; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: 0.07em; color: var(--ink-3);
}
.flow-summary .v {
  font-size: 22.5px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}

/* ── rotation phase: structure, not a scatter plot ───────────────
   The four quadrants of a rotation map become four groups of rows.
   Same information, no overlapping dots, and the names stay legible. */

.phase { margin-top: 26px; }
.phase-head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  padding-bottom: 7px; border-bottom: 1px solid var(--hairline);
}
.phase-mark {
  width: 7px; height: 7px; border-radius: 2px; flex: none;
  transform: translateY(-1px);
}
.phase[data-p="leading"]   .phase-mark { background: var(--pass); }
.phase[data-p="improving"] .phase-mark { background: var(--accent); }
.phase[data-p="weakening"] .phase-mark { background: var(--warn); }
.phase[data-p="lagging"]   .phase-mark { background: var(--fail); }
.phase-head .t { font-size: 14px; font-weight: 700; letter-spacing: 0.01em; }
.phase-head .n {
  font-size: 13px; color: var(--ink-3); font-variant-numeric: tabular-nums;
}
.phase-head .d { font-size: 13px; color: var(--ink-3); margin-left: auto; }

/* ── one industry ────────────────────────────────────────────── */

.frow {
  display: grid;
  grid-template-columns: 218px 190px 128px 118px 104px 1fr;
  gap: 20px; align-items: center;
  padding: 12px 4px; border-bottom: 1px solid var(--hairline);
  width: 100%; text-align: left;
}
.frow:hover { background: var(--surface); }
.frow .name { font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em; }
.frow .sub { font-size: 12.5px; color: var(--ink-3); }

/* Diverging bar — the market median is the axis, so a row's length
   answers "better or worse than everything else", not "up or down". */
.dbar-cell { display: grid; grid-template-columns: 1fr 52px; gap: 8px;
                 align-items: center; }
.dbar-cell .val {
  font-size: 13.5px; font-weight: 600; text-align: right;
  font-variant-numeric: tabular-nums;
}
.dbar-cell .val.pos { color: var(--pass); }
.dbar-cell .val.neg { color: var(--fail); }

.dbar { position: relative; height: 18px; }
.dbar .axis {
  position: absolute; left: 50%; top: 0; bottom: 0; width: 1px;
  background: var(--hairline-2);
}
.dbar i {
  position: absolute; top: 3px; height: 12px; border-radius: 2px;
  /* A deviation near the median is genuinely small, but below
     about three pixels it stops being visible at all rather
     than reading as small. */
  min-width: 3px;
}
.dbar i.pos { left: 50%; background: var(--pass); }
.dbar i.neg { right: 50%; background: var(--fail); }

/* Multi-timeframe strip — five cells, one per horizon. Reading left to
   right shows whether a move is building or fading, which a single
   period figure cannot say at all. */
.tstrip { display: flex; gap: 2px; }
.tstrip .c {
  flex: 1; height: 24px; border-radius: 2px; position: relative;
  background: var(--sunken); display: grid; place-items: center;
}
.tstrip .c b {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.03em;
  color: var(--ink-3); text-transform: uppercase;
}
.tstrip .c[data-d="up"]   { background: color-mix(in srgb, var(--pass) calc(var(--i) * 1%), var(--sunken)); }
.tstrip .c[data-d="down"] { background: color-mix(in srgb, var(--fail) calc(var(--i) * 1%), var(--sunken)); }
.tstrip .c[data-strong="1"] b { color: var(--on-ink); }
.tstrip-labels { display: flex; gap: 2px; margin-top: 4px; }
.tstrip-labels span {
  flex: 1; text-align: center; font-size: 10.5px; color: var(--ink-3);
  letter-spacing: 0.06em; font-weight: 600;
}

/* Breadth — participation behind the move. A 6% gain carried by two
   names is a different thing from one carried by twenty. */
.breadth { display: flex; align-items: center; gap: 8px; }
.breadth .meter {
  flex: 1; height: 6px; border-radius: 3px; background: var(--sunken);
  overflow: hidden; position: relative;
}
.breadth .meter i { display: block; height: 100%; background: var(--ink-4); }
.breadth .meter.hi i { background: var(--pass); }
.breadth .meter.lo i { background: var(--fail); }
.breadth .pv {
  font-size: 13px; font-variant-numeric: tabular-nums; color: var(--ink-2);
  min-width: 30px; text-align: right;
}

/* Turnover — share of the market's traded value, as a share. */
.flowbar { display: flex; align-items: center; gap: 8px; }
.flowbar .meter {
  flex: 1; height: 6px; border-radius: 3px; background: var(--sunken);
  overflow: hidden;
}
.flowbar .meter i { display: block; height: 100%; background: var(--accent);
                    opacity: 0.55; }
.flowbar .pv {
  font-size: 13px; font-variant-numeric: tabular-nums; color: var(--ink-2);
  min-width: 34px; text-align: right;
}

.leaders { display: flex; flex-wrap: wrap; gap: 4px 8px; min-width: 0; }
.leaders span {
  font-size: 12.5px; color: var(--ink-2); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.leaders span em { font-style: normal; color: var(--ink-3); }

.frow .colhead, .fhead {
  font-size: 11px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-3);
}
.fhead {
  display: grid;
  grid-template-columns: 218px 190px 128px 118px 104px 1fr;
  gap: 20px; padding: 0 4px 8px;
}

@media (max-width: 1240px) {
  .frow, .fhead { grid-template-columns: 180px 168px 112px 100px 1fr; }
  .frow > .drop-md, .fhead > .drop-md { display: none; }
}

@media (max-width: 860px) {
  .fhead { display: none; }
  .frow {
    grid-template-columns: 1fr auto; gap: 8px 12px; padding: 14px 2px;
  }
  .frow > .cell-name { grid-column: 1; grid-row: 1; }
  .frow > .cell-bar  { grid-column: 1 / -1; grid-row: 2; }
  .frow > .cell-strip{ grid-column: 1 / -1; grid-row: 3; }
  .frow > .cell-brd  { grid-column: 1; grid-row: 4; }
  .frow > .cell-flow { grid-column: 2; grid-row: 4; min-width: 110px; }
  .frow > .cell-lead { grid-column: 1 / -1; grid-row: 5; }
  .flow-summary .f { padding-right: 16px; margin-right: 16px; }
}

/* ═══════════════════════════════════════════════════════════════════
   Minervini VCP

   One idea, drawn many ways: wide on the left, narrow on the right.
   Colour still means only what it means everywhere else — pass, fail,
   caution, unknown — and the contraction bands borrow that vocabulary
   rather than inventing a second one.
   ═══════════════════════════════════════════════════════════════════ */

:root {
  --vcp-ink:   var(--ink-2);
  --vcp-rule:  var(--hairline-2);
  --vcp-pivot: var(--accent);
}

/* ── quality: a shape, not a score ─────────────────────────────── */

.vq { display: inline-flex; align-items: center; gap: 7px; }
.vq-dots { display: inline-flex; gap: 3px; }
.vq-dots i {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--hairline-2);
}
.vq[data-t="pass"]    .vq-dots i.on { background: var(--pass); }
.vq[data-t="warn"]    .vq-dots i.on { background: var(--warn); }
.vq[data-t="fail"]    .vq-dots i.on { background: var(--fail); }
.vq[data-t="unknown"] .vq-dots i.on { background: var(--unknown); }
.vq-word { font-size: 13px; color: var(--ink-2); letter-spacing: .01em; }

/* ── the contraction map ───────────────────────────────────────── */

.vcp-map { width: 100%; height: 84px; overflow: visible; }
.vcp-map.sm { height: 30px; }
/* The map stretches to its column (preserveAspectRatio="none") so the
   depth sequence uses the width it is given. Without this the strokes
   stretch with it and the glyph reads as smudged at ledger scale. */
.vcp-map line, .vcp-map circle { vector-effect: non-scaling-stroke; }
.vcp-map.sm .vt { stroke-width: 3; }
.vcp-map.sm .vcap { stroke-width: 1; }
.vcp-map .vt      { stroke: var(--ink-3); stroke-width: 2.2; }
.vcp-map .vt.strong   { stroke: var(--pass); }
.vcp-map .vt.moderate { stroke: var(--ink-2); }
.vcp-map .vt.weak     { stroke: var(--warn); }
.vcp-map .vt.none     { stroke: var(--fail); }
.vcp-map .vcap  { stroke: var(--hairline-2); stroke-width: .8; }
.vcp-map .vlink { stroke: var(--hairline-2); stroke-width: .7;
                  stroke-dasharray: 2 2; }
.vcp-map .vpivot { stroke: var(--vcp-pivot); stroke-width: 1; }
.vcp-map .vpoint { fill: var(--vcp-pivot); }
.vcp-map text { font-family: var(--mono); fill: var(--ink-3); }
.vcp-map .vd { font-size: 7.5px; text-anchor: middle; }
.vcp-map .vn { font-size: 6.5px; text-anchor: middle; fill: var(--ink-4); }
.vcp-map .vp { font-size: 6px; fill: var(--vcp-pivot); letter-spacing: .08em; }

/* ── technical footprint ───────────────────────────────────────── */

.fp-mark {
  display: inline-flex; align-items: baseline; gap: 10px;
  font-family: var(--mono); font-size: 20.5px; letter-spacing: .01em;
  color: var(--ink); padding: 6px 0;
}
.fp-mark i { color: var(--ink-4); font-style: normal; font-size: 14px; }
.fp-more summary {
  font-size: 13px; color: var(--ink-3); cursor: pointer;
  padding: 3px 0;
}
.fp-parts { display: grid; gap: 9px; margin: 9px 0; }
.fp-part { display: grid; grid-template-columns: 78px 1fr; gap: 10px;
           align-items: baseline; }
.fp-part .k { font-size: 12px; letter-spacing: .07em;
              text-transform: uppercase; color: var(--ink-4); }
.fp-part .v { font-size: 14px; color: var(--ink); }
.fp-part .caption { grid-column: 2; }
.fp-partial .fp-parts { margin-top: 0; }

/* ── tightness ─────────────────────────────────────────────────── */

.tw { display: grid; grid-template-columns: 58px 1fr 52px;
      gap: 10px; align-items: center; padding: 3px 0; }
.tw-k { font-size: 12px; color: var(--ink-3); }
.tw-bar { height: 9px; background: var(--sunken); border-radius: 2px; }
.tw-bar i { display: block; height: 100%; border-radius: 2px;
            background: var(--ink-3); }
.tightness[data-s="TIGHTENING"] .tw-bar i { background: var(--pass); }
.tightness[data-s="WIDENING"]   .tw-bar i { background: var(--fail); }
.tw-v { font-size: 12px; text-align: right; color: var(--ink-2); }
.tw-status { font-size: 13px; color: var(--ink-2); margin: 9px 0 0; }

/* ── volume ladder ─────────────────────────────────────────────── */

.vladder { position: relative; }
.vl-bars { position: relative; }
/* the 1.0x reference — the book's one hard number, drawn */
.vl-bars::after {
  content: ""; position: absolute; top: 0; bottom: 0;
  left: calc(48px + 10px + (100% - 48px - 10px - 52px - 10px) * var(--ref, 50%) / 100%);
  border-left: 1px dashed var(--hairline-2);
}
.vl-row { display: grid; grid-template-columns: 48px 1fr 52px;
          gap: 10px; align-items: center; padding: 3px 0; }
.vl-k { font-family: var(--mono); font-size: 12px; color: var(--ink-3); }
.vl-bar { height: 9px; background: var(--sunken); border-radius: 2px; }
.vl-bar i { display: block; height: 100%; border-radius: 2px;
            background: var(--ink-3); }
.vl-bar i.dry { background: var(--pass); }
.vl-v { font-size: 12px; text-align: right; color: var(--ink-2); }

/* ── final contraction ─────────────────────────────────────────── */

.fc-row { display: grid; grid-template-columns: 128px 1fr; gap: 12px;
          padding: 5px 0; border-bottom: 1px solid var(--hairline);
          align-items: baseline; }
.fc-row:last-of-type { border-bottom: 0; }
.fc-row .k { font-size: 12px; letter-spacing: .05em;
             text-transform: uppercase; color: var(--ink-4); }
.fc-row .v { font-size: 14px; color: var(--ink-2); }
.fc-row .v.ok { color: var(--pass); }
.fc-row .v.no { color: var(--warn); }

/* ── supply/demand lifecycle ───────────────────────────────────── */

.lifecycle { list-style: none; margin: 0; padding: 0; position: relative; }
.lifecycle::before {
  content: ""; position: absolute; left: 4px; top: 8px; bottom: 8px;
  border-left: 1px solid var(--hairline-2);
}
.lifecycle li { position: relative; padding: 0 0 12px 20px; }
.lifecycle li:last-child { padding-bottom: 0; }
.lc-dot { position: absolute; left: 0; top: 5px; width: 9px; height: 9px;
          border-radius: 50%; background: var(--paper);
          border: 1.5px solid var(--hairline-2); }
.lifecycle li.on .lc-dot { border-color: var(--pass); background: var(--pass); }
.lc-t { display: block; font-size: 13.5px; color: var(--ink-3); }
.lifecycle li.on .lc-t { color: var(--ink); }
.lc-d { display: block; font-size: 12.5px; color: var(--ink-4); }

/* ── pivot ─────────────────────────────────────────────────────── */

.pivot-panel { display: grid; gap: 10px; }
.pv-prices { display: grid; grid-template-columns: 1fr auto 1fr;
             gap: 10px; align-items: center; }
.pv-now, .pv-piv { display: grid; gap: 1px; }
.pv-piv { text-align: right; }
.pv-prices .k { font-size: 11.5px; letter-spacing: .07em;
                text-transform: uppercase; color: var(--ink-4); }
.pv-prices .v { font-size: 18.5px; color: var(--ink); }
.pv-gap { font-size: 13px; color: var(--ink-3);
          padding: 2px 8px; border: 1px solid var(--hairline-2);
          border-radius: 999px; }
.pv-gap.up { color: var(--pass); border-color: var(--pass); }
.pv-state { font-size: 13px; letter-spacing: .04em; text-transform: uppercase;
            color: var(--ink-2); }
.pivot-panel[data-t="pass"] .pv-state { color: var(--pass); }
.pivot-panel[data-t="warn"] .pv-state { color: var(--warn); }
.pv-meta { display: grid; grid-template-columns: 130px 1fr;
           gap: 3px 12px; margin: 0; font-size: 13px; }
.pv-meta dt { color: var(--ink-4); }
.pv-meta dd { margin: 0; color: var(--ink-2); }
.pv-wait { border-left: 2px solid var(--warn); padding-left: 9px; }

/* ── trend template ────────────────────────────────────────────── */

.tt-head { display: flex; align-items: baseline; gap: 10px;
           padding-bottom: 8px; border-bottom: 1px solid var(--hairline); }
.tt-count { font-size: 21.5px; color: var(--fail); }
.tt[data-ok="true"] .tt-count { color: var(--pass); }
.tt-lab { font-size: 13px; color: var(--ink-3); }
.tt-warn { font-size: 13.5px; color: var(--warn); margin: 9px 0 0;
           border-left: 2px solid var(--warn); padding-left: 9px; }
.tt-list { list-style: none; margin: 10px 0 0; padding: 0; }
.tt-list li { display: grid; grid-template-columns: 18px 1fr auto;
              gap: 8px; padding: 6px 0;
              border-bottom: 1px solid var(--hairline); align-items: baseline; }
.tt-list li:last-child { border-bottom: 0; }
.tt-list li.supp { opacity: .82; }
.tt-mark { font-size: 13px; color: var(--unknown); }
.tt-list li[data-s="PASS"] .tt-mark { color: var(--pass); }
.tt-list li[data-s="FAIL"] .tt-mark { color: var(--fail); }
.tt-text { font-size: 13.5px; color: var(--ink-2); }
.tt-val  { font-size: 13px; color: var(--ink-3); }
.tt-ver { display: inline-block; margin-left: 6px; font-size: 11px;
          letter-spacing: .05em; text-transform: uppercase;
          color: var(--ink-4); border: 1px solid var(--hairline-2);
          border-radius: 3px; padding: 0 4px; }
.tt-note { grid-column: 2 / -1; }

/* ── evidence, warnings, rejections ────────────────────────────── */

.evidence { margin-top: 18px; display: grid; gap: 6px; }
.ev-list { list-style: none; margin: 0 0 10px; padding: 0; }
.ev-list li { display: grid; grid-template-columns: 16px 1fr; gap: 8px;
              padding: 4px 0; align-items: baseline; }
.ev-m { font-size: 12px; }
.ev-list li.ok   .ev-m { color: var(--pass); }
.ev-list li.warn .ev-m { color: var(--warn); }
.ev-list li.no   .ev-m { color: var(--fail); }
.ev-t { font-size: 13.5px; color: var(--ink-2); }
.ev-t .caption { display: block; margin-top: 2px; }

/* ── state track ───────────────────────────────────────────────── */

.vstate { display: grid; gap: 6px; }
.vs-track { list-style: none; display: flex; gap: 4px; margin: 0; padding: 0;
            align-items: center; }
.vs-track li i { display: block; width: 100%; height: 3px; border-radius: 2px;
                 background: var(--hairline-2); }
.vs-track li { flex: 1; }
.vs-track li.past i { background: var(--ink-3); }
.vs-track li.now  i { background: var(--pass); height: 5px; }
.vs-now { font-size: 14px; color: var(--ink); }
.vstate.off[data-t="fail"] .vs-now { color: var(--fail); }
.vstate.off[data-t="warn"] .vs-now { color: var(--warn); }

/* ── the annotated chart ───────────────────────────────────────── */

.vcp-chart { margin: 20px 0; }
.vcp-chart svg { width: 100%; height: auto; display: block; }
.vcp-chart .cd.u, .vcp-chart .wk.u { fill: var(--ink-2); stroke: var(--ink-2); }
.vcp-chart .cd.d, .vcp-chart .wk.d { fill: var(--ink-4); stroke: var(--ink-4); }
.vcp-chart .wk { stroke-width: .8; }
.vcp-chart .vb { fill: var(--hairline-2); }
.vcp-chart .vb.dry { fill: var(--pass); opacity: .45; }
/* Clipped at the top of the scale — marked so an outlier still reads as
   one rather than looking like an ordinary heavy session. */
.vcp-chart .vb.over { fill: var(--ink-2); opacity: .8; }
.vcp-chart .vavg { fill: none; stroke: var(--ink-3); stroke-width: .9;
                   stroke-dasharray: 3 2; }
.vcp-chart .tzone { fill: var(--accent-wash); opacity: .5; }
.vcp-chart .tbr.pending .tzone { opacity: .28; }
.vcp-chart .thi, .vcp-chart .tlo { stroke: var(--accent); stroke-width: .9;
                                    stroke-dasharray: 4 3; }
.vcp-chart .tbr.weak .thi, .vcp-chart .tbr.weak .tlo,
.vcp-chart .tbr.none .thi, .vcp-chart .tbr.none .tlo { stroke: var(--warn); }
.vcp-chart .tlab { font-family: var(--mono); font-size: 9.5px;
                   fill: var(--accent-ink); text-anchor: middle; }
.vcp-chart .tpct { fill: var(--ink-3); }
.vcp-chart .tshake { font-family: var(--mono); font-size: 8px;
                     fill: var(--warn); text-anchor: middle; }
.vcp-chart .lvl.pivot { stroke: var(--vcp-pivot); stroke-width: 1.1; }
.vcp-chart .lvl.stop  { stroke: var(--fail); stroke-width: .9;
                        stroke-dasharray: 5 3; }
.vcp-chart .lvl-t { font-family: var(--mono); font-size: 9.5px;
                    text-anchor: end; letter-spacing: .06em; }
.vcp-chart .lvl-t.pivot { fill: var(--vcp-pivot); }
.vcp-chart .lvl-t.stop  { fill: var(--fail); }
.vcp-chart .basestart { stroke: var(--hairline-2); stroke-width: 1;
                        stroke-dasharray: 2 3; }
.vcp-chart .basestart-t { font-size: 9px; fill: var(--ink-4); }

/* ── overhead supply ───────────────────────────────────────────── */

.os-row { display: grid; grid-template-columns: 118px 1fr 58px;
          gap: 10px; align-items: center; padding: 3px 0; }
.os-bar { height: 8px; background: var(--sunken); border-radius: 2px; }
.os-bar i { display: block; height: 100%; border-radius: 2px;
            background: var(--warn); opacity: .55; }
.os-k, .os-v { font-size: 12px; color: var(--ink-3); }
.os-v { text-align: right; }

/* ── the workspace ─────────────────────────────────────────────── */

.vfunnel { list-style: none; display: flex; flex-wrap: wrap; gap: 0;
           margin: 22px 0; padding: 0;
           border-top: 1px solid var(--hairline-2);
           border-bottom: 1px solid var(--hairline); }
.vfunnel li { flex: 1 1 130px; padding: 16px 20px 15px 0;
              border-right: 1px solid var(--hairline); display: grid; gap: 4px; }
.vfunnel li:last-child { border-right: 0; }
.vfunnel li + li { padding-left: 20px; }
.vfunnel .n { font-size: 29px; font-weight: 500; letter-spacing: -0.03em;
              line-height: 1; color: var(--ink); }
.vfunnel .t { font-size: 11px; font-weight: 600; letter-spacing: .12em;
              text-transform: uppercase; color: var(--ink-4); }
.vfunnel .caption { font-size: 12.5px; }

.vfilters { display: flex; flex-wrap: wrap; gap: 6px; margin: 14px 0; }
.vfilters button {
  font: inherit; font-size: 13px; padding: 5px 11px; cursor: pointer;
  background: transparent; color: var(--ink-2);
  border: 1px solid var(--hairline-2); border-radius: 999px;
}
.vfilters button .mono { color: var(--ink-4); margin-left: 4px; }
.vfilters button[aria-selected="true"] {
  background: var(--accent-wash); border-color: var(--accent);
  color: var(--accent-ink);
}
.vfilters button[disabled] { opacity: .4; cursor: default; }

/* Ledger rows, per the house pattern — full-width entries on a hairline,
   never boxed cards. */
.vcp-ledger .lrow { display: grid; grid-template-columns: var(--grid);
                    gap: 12px; align-items: center; width: 100%;
                    padding: 9px 4px; text-align: left;
                    background: transparent; border: 0;
                    border-bottom: 1px solid var(--hairline);
                    cursor: pointer; font: inherit; }
.vcp-ledger .lhead { display: grid; grid-template-columns: var(--grid);
                     gap: 12px; padding: 0 4px 6px;
                     border-bottom: 1px solid var(--hairline-2); }
.vcp-ledger.compact .lrow {
  grid-template-columns: minmax(90px,1fr) 82px 130px 118px 52px 74px;
}
.vcp-ledger .lrow:hover { background: var(--sunken); }
.vcp-ledger .lrow-wrap.open .lrow { background: var(--sunken); }
.vcp-ledger .lc.n, .vcp-ledger .lh.n { text-align: right;
                                        justify-content: flex-end; }
.vcp-ledger .lh { font: inherit; font-size: 11.5px; letter-spacing: .06em;
                  text-transform: uppercase; color: var(--ink-4);
                  background: transparent; border: 0; cursor: pointer;
                  display: flex; gap: 4px; align-items: center; padding: 0; }
.vcp-ledger .c-sym { font-weight: 600; }
.vcp-ledger .c-fp { font-size: 12.5px; color: var(--ink-2); }
.vcp-ledger .c-state { font-size: 12.5px; }
.vcp-ledger .c-state[data-t="pass"]    { color: var(--pass); }
.vcp-ledger .c-state[data-t="warn"]    { color: var(--warn); }
.vcp-ledger .c-state[data-t="fail"]    { color: var(--fail); }
.vcp-ledger .c-state[data-t="unknown"] { color: var(--ink-3); }
.vcp-ledger .c-dry { font-family: var(--mono); font-size: 12.5px;
                     color: var(--ink-3); }
.vcp-ledger .c-dry.on { color: var(--pass); }
.vcp-ledger .c-tt.ok { color: var(--pass); }
.vcp-ledger .mono.up { color: var(--pass); }
.tag { font-style: normal; font-size: 10.5px; letter-spacing: .06em;
       text-transform: uppercase; padding: 1px 5px; border-radius: 3px;
       margin-left: 6px; vertical-align: 1px; }
.tag.strict { background: var(--pass-wash); color: var(--pass); }
.tag.cand   { background: var(--sunken); color: var(--ink-3); }

.lpanel { padding: 16px 4px 22px; border-bottom: 1px solid var(--hairline); }
.vp-grid { display: grid; gap: 26px 32px; margin-bottom: 22px;
           grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.vp-grid > section { min-width: 0; }
.vp-more { margin-top: 14px; }

/* Figures read as a measured row, not as a strip of boxes: the box was
   drawing a border around every number and making four counts look like
   four features. See .metrics — this is the same object. */
.vtiles { display: flex; flex-wrap: wrap; gap: 0; margin: 2px 0 20px;
          border-top: 1px solid var(--hairline-2);
          border-bottom: 1px solid var(--hairline); }
.vtile { flex: 1 1 110px; padding: 16px 20px 15px 0; display: grid; gap: 4px;
         border-right: 1px solid var(--hairline); }
.vtile:last-child { border-right: 0; }
.vtile + .vtile { padding-left: 20px; }
.vtile .n { font-size: 29px; font-weight: 500; letter-spacing: -0.03em;
            line-height: 1; color: var(--ink); }
.vtile.ok   .n { color: var(--pass); }
.vtile.warn .n { color: var(--warn); }
.vtile .t { font-size: 11px; font-weight: 600; letter-spacing: .12em;
            text-transform: uppercase; color: var(--ink-4); }

/* ── the stock page panel ──────────────────────────────────────── */

.vcp-head { display: flex; align-items: center; justify-content: space-between;
            gap: 14px; flex-wrap: wrap; }
.vcp-head-end { display: flex; align-items: center; gap: 12px; }
.vcp-summary { display: flex; gap: 32px; flex-wrap: wrap;
               align-items: flex-start; margin: 10px 0 4px; }
.vcp-summary > * { flex: 1 1 240px; min-width: 0; }
.vcp-fold { border-top: 1px solid var(--hairline); padding: 12px 0 4px; }
.vcp-fold > summary { font-size: 13px; letter-spacing: .05em;
                      text-transform: uppercase; color: var(--ink-3);
                      cursor: pointer; padding: 4px 0; }
.vcp-attr { margin-top: 22px; padding-top: 12px;
            border-top: 1px solid var(--hairline); max-width: 76ch; }

.ctable { width: 100%; border-collapse: collapse; margin-top: 12px;
          font-size: 13px; }
.ctable th { font-weight: 500; font-size: 11.5px; letter-spacing: .05em;
             text-transform: uppercase; color: var(--ink-4);
             text-align: left; padding: 0 8px 5px 0;
             border-bottom: 1px solid var(--hairline-2); }
.ctable td { padding: 5px 8px 5px 0; color: var(--ink-2);
             border-bottom: 1px solid var(--hairline); }
.ctable th.n, .ctable td.n { text-align: right; padding-right: 0; }

.kv { display: grid; grid-template-columns: 150px 1fr; gap: 4px 14px;
      margin: 0 0 10px; font-size: 13.5px; }
.kv dt { color: var(--ink-4); }
.kv dd { margin: 0; color: var(--ink-2); }
.kv dd .mono.no { color: var(--warn); }

.linkish { background: none; border: 0; padding: 0; font: inherit;
           font-size: inherit; color: var(--accent); cursor: pointer;
           text-decoration: underline; text-underline-offset: 2px; }

@media (max-width: 900px) {
  /* The wide ledger cannot usefully shrink to a phone. Below this width
     it becomes the five columns that carry the decision, and the rest
     moves into the expanded panel where there is room for it. */
  .vcp-ledger .lrow, .vcp-ledger .lhead {
    grid-template-columns: minmax(84px,1fr) 74px 112px 96px 70px;
  }
  .vcp-ledger .lc:nth-child(n+6), .vcp-ledger .lh:nth-child(n+6) { display: none; }
  .vcp-summary { gap: 18px; }
}

/* A rule whose threshold moved between editions of its source book. The
   later edition governs and screens; this is what the earlier one said.
   Set apart from the citation above it so the two are not misread as one
   quotation from the same place. */
.cite.edition {
  margin-top: 6px; padding-left: 9px;
  border-left: 2px solid var(--hairline-2);
  color: var(--ink-3);
}
.edition-tag {
  display: inline-block; margin-right: 6px; font-size: 10.5px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-4);
  border: 1px solid var(--hairline-2); border-radius: 3px; padding: 0 4px;
  vertical-align: 1px;
}

/* Coil grades. Ordering only — the letter is a shorthand for the columns
   beside it, never a verdict on the stock. */
.tag.g-A { background: var(--pass-wash); color: var(--pass); }
.tag.g-B { background: var(--accent-wash); color: var(--accent-ink); }
.tag.g-C { background: var(--sunken); color: var(--ink-3); }
.tag.g-D { background: var(--sunken); color: var(--ink-4); }

/* The coil chart: one level, the range beneath it, and the volume story.
   Deliberately sparser than the VCP chart — this setup reads at a glance
   and an overlay that needs a legend has lost the argument. */
.coil-chart .coil-band  { fill: var(--accent); opacity: .10; }
.coil-chart .coil-edge  { stroke: var(--accent); stroke-width: 1;
                          opacity: .45; stroke-dasharray: 3 3; }
.coil-chart .coil-level { stroke: var(--pass); stroke-width: 1.6; }
.coil-chart .coil-lt    { font-family: var(--mono); font-size: 13px;
                          font-weight: 500; fill: var(--pass); text-anchor: start; }
.coil-chart .coil-lk, .coil-chart .coil-sk {
  font-family: var(--mono); font-size: 9px; letter-spacing: .18em;
  fill: var(--ink-4); text-anchor: start;
}
.coil-chart .coil-stop  { stroke: var(--fail); stroke-width: 1;
                          stroke-dasharray: 4 3; }
.coil-chart .coil-st    { font-family: var(--mono); font-size: 12px;
                          fill: var(--fail); text-anchor: start; }
/* The distance still to travel, drawn as a measured gap rather than left
   as a percentage the reader has to map onto the chart themselves. */
.coil-chart .coil-gap line { stroke: var(--ink-3); stroke-width: 1;
                             stroke-dasharray: 2 3; }
.coil-chart .coil-gap text { font-family: var(--mono); font-size: 12px;
                             fill: var(--ink-2); text-anchor: end; }
/* Inside the range the candles carry direction; before it they are
   context and recede, so the coil is what the eye lands on. */
.coil-chart .cd, .coil-chart .wk { opacity: .38; }
.coil-chart .cd.u, .coil-chart .wk.u { fill: var(--ink-3); stroke: var(--ink-3); }
.coil-chart .cd.d, .coil-chart .wk.d { fill: var(--ink-4); stroke: var(--ink-4); }
.coil-chart .cd.in, .coil-chart .wk.in { opacity: 1; }
.coil-chart .cd.u.in, .coil-chart .wk.u.in { fill: var(--pass); stroke: var(--pass); }
.coil-chart .cd.d.in, .coil-chart .wk.d.in { fill: var(--fail); stroke: var(--fail); }
.coil-chart .vb { fill: var(--ink-4); opacity: .35; }
.coil-chart .vb.coil-dry   { fill: var(--pass); opacity: .75; }
.coil-chart .vb.coil-surge { fill: var(--accent); opacity: .9; }

/* ── server waking / background runs ─────────────────────────────── */

html[data-waking] body::after {
  content: "Waking the server — the free host sleeps when idle and takes about a minute to start.";
  position: fixed; left: 50%; bottom: 20px; transform: translateX(-50%);
  z-index: 300; max-width: calc(100vw - 32px);
  padding: 10px 14px; border-radius: var(--radius);
  background: var(--ink); color: var(--paper);
  font-size: 14px; line-height: 1.4; box-shadow: var(--shadow-pop);
}

.nav a[data-running]::after,
.nav-mobile a[data-running]::after {
  content: ""; display: inline-block; width: 6px; height: 6px;
  margin-left: 6px; vertical-align: middle; border-radius: 50%;
  background: var(--accent);
  animation: run-pulse 1.2s ease-in-out infinite;
}
@keyframes run-pulse { 50% { opacity: .25; } }
@media (prefers-reduced-motion: reduce) {
  .nav a[data-running]::after, .nav-mobile a[data-running]::after { animation: none; }
}

/* ─────────────────────────────────────────────── print
   Dark backgrounds don't print; app.js also flips the attribute around
   the print event so the charts redraw in light. */
@media print {
  :root { color-scheme: light; }
}

/* A row of controls that filters what follows. It sits above the content
   it acts on, not inside a section head, which is for naming things. */
.filterbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin: 0 0 10px;
}
.filterbar .btn { margin-left: auto; }

/* ══════════════════════════════════════════ watchlist: what changed */

.changed { list-style: none; margin: 0; padding: 0; }
.changed li {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 16px;
  padding: 13px 0 13px 16px; position: relative;
  border-bottom: 1px solid var(--hairline);
}
.changed li::before {
  content: ""; position: absolute; left: 0; top: 17px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--unknown);
}
.changed li[data-tone="positive"]::before { background: var(--pass); }
.changed li[data-tone="caution"]::before  { background: var(--warn); }
.changed li[data-tone="negative"]::before { background: var(--fail); }
.changed-t { font-size: 15.5px; color: var(--ink); }
.changed-s { font-size: 13.5px; color: var(--ink-3); font-family: var(--mono); }
.changed-s a { color: var(--ink-2); }
.changed-s a:hover { color: var(--accent); }

/* ══════════════════════════════════════════════ page transition

   One short, small movement when a view paints: enough to signal that the
   page changed rather than that the same page redrew, and short enough
   that it never delays reading. Nothing else on the page animates by
   itself — motion here means state, never decoration. */

@keyframes page-in {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}
.page[data-fresh] { animation: page-in 0.22s cubic-bezier(.2,.7,.2,1); }
@media (prefers-reduced-motion: reduce) {
  .page[data-fresh] { animation: none; }
}

/* ══════════════════════════════════════════ responsive refinement

   The hierarchy is the same on a phone: the page still opens with its
   role, its name and its purpose, and figures still read as figures. Only
   the amounts change — type steps down, the measured rows wrap to two
   across, and the wide ledgers hand their extra columns to the expanded
   panel (handled where those ledgers are defined). */

@media (max-width: 860px) {
  .base { grid-template-columns: 1fr; gap: 14px; }
  .base svg { width: 150px; height: 76px; }
  .page-head { margin-bottom: 24px; padding-bottom: 16px; }
  .page-head .lede { font-size: 16px; }
  .page-head-meta { gap: 4px 14px; font-size: 12px; }
  .section { margin-top: 38px; }
  .section-head, .sec-head { grid-template-columns: minmax(0, 1fr); }
  .section-head > .btn, .sec-head > .btn,
  .section-head > a.btn, .sec-head > a.btn,
  .section-head > .seg-ctl, .sec-head > .seg-ctl,
.section-head > div > .seg-ctl, .sec-head > div > .seg-ctl,
  .section-head > input, .sec-head > input {
    grid-column: 1; justify-self: start; margin-top: 10px;
  }
  .funnel .f, .vfunnel li, .vtile { flex: 1 1 44%; padding: 13px 14px 12px 0; }
  .funnel .f + .f, .vfunnel li + li, .vtile + .vtile { padding-left: 14px; }
  .funnel .f .v, .vfunnel .n, .vtile .n { font-size: 24px; }
  /* The banner's link follows the sentence it belongs to rather than
     being pushed to a right edge that no longer exists. */
  .market-banner a.caption { margin-left: 0 !important; }
  .lead-title { font-size: clamp(24px, 7vw, 30px); }
  .lead-say { font-size: 15.5px; }
  .changed li { padding-left: 14px; }
}

/* ══════════════════════════════════════════════════ the risk rail

   Where price sits between the level that invalidates the structure and
   the level that triggers the trade, drawn to scale. Two numbers and a
   position answer, in one glance, the question the whole page exists to
   inform: what does this cost if it fails, and how far is it from going. */

.rail { margin: 26px 0 4px; }
.rail-track {
  position: relative; height: 6px; border-radius: 3px;
  background: linear-gradient(90deg,
    var(--fail-wash) 0%, var(--sunken) 45%, var(--pass-wash) 100%);
  box-shadow: inset 0 0 0 1px var(--hairline);
}
.rail-fill {
  position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px;
  background: linear-gradient(90deg, var(--fail) 0%, var(--warn) 55%, var(--pass) 100%);
  opacity: .5;
}
/* The marker is a bar, not a dot: a dot on a 6px track reads as a bullet
   point, and this is a price — it belongs on an axis. */
.rail-now {
  position: absolute; top: -7px; bottom: -7px; width: 2px; margin-left: -1px;
  background: var(--ink); border-radius: 1px;
}
.rail[data-through="true"] .rail-now { background: var(--pass); }
.rail-ends {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px;
  margin-top: 12px;
}
.rail-end { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.rail-end .k {
  font-size: 11px; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-4);
}
.rail-end .v {
  font-size: 18.5px; font-weight: 600; letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.rail-end .s { font-size: 12.5px; color: var(--ink-3); font-family: var(--mono); }
.rail-mid { align-items: center; text-align: center; }
.rail-mid .v { font-size: 21.5px; }
.rail-right { align-items: flex-end; text-align: right; }
.rail-note { margin: 14px 0 0; max-width: 74ch; }

@media (max-width: 860px) {
  .rail-ends { grid-template-columns: 1fr 1fr; gap: 14px; }
  .rail-mid { grid-column: 1 / -1; order: -1; align-items: flex-start; text-align: left; }
  .rail-end .v { font-size: 17.5px; }
}

/* ══════════════════════════════════════════════ the verdict meter

   One segment per rule, grouped by the methodology's own letters. The
   widths are proportional to how many rules a group holds, so a group
   carrying seven tests looks like seven tests. */

.verdict { margin: 20px 0 6px; }
.verdict-bar { display: flex; gap: 10px; align-items: flex-end; }
.vg {
  flex: var(--n, 1) 1 0; display: grid; gap: 3px;
  grid-template-columns: repeat(var(--n, 1), minmax(0, 1fr));
}
.vg i { height: 10px; border-radius: 2px; background: var(--unknown-wash); }
.vg i[data-s="PASS"]    { background: var(--pass); }
.vg i[data-s="PARTIAL"] { background: var(--warn); }
.vg i[data-s="FAIL"]    { background: var(--fail); }
.vg i[data-s="UNKNOWN"],
.vg i[data-s="REQUIRES_ANALYSIS"] { background: var(--hairline-2); }
.vg b {
  grid-column: 1 / -1; margin-top: 7px;
  font-family: var(--mono); font-size: 12px; font-weight: 500;
  color: var(--ink-3); letter-spacing: .04em;
}
.verdict-key {
  display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 14px;
  font-size: 12.5px; color: var(--ink-3);
}
.vk { display: inline-flex; align-items: center; gap: 6px; }
.vk i { width: 8px; height: 8px; border-radius: 2px; background: var(--unknown-wash); }
.vk i[data-s="PASS"]    { background: var(--pass); }
.vk i[data-s="PARTIAL"] { background: var(--warn); }
.vk i[data-s="FAIL"]    { background: var(--fail); }
.vk i[data-s="UNKNOWN"],
.vk i[data-s="REQUIRES_ANALYSIS"] { background: var(--hairline-2); }
.vk-total { margin-left: auto; color: var(--ink-4); font-family: var(--mono); }

/* ═════════════════════════════════════ a rule with a threshold, drawn */

.rbars { display: grid; gap: 4px; }
.rbar {
  display: grid; grid-template-columns: minmax(0, 1fr) 96px;
  gap: 4px 14px; align-items: baseline;
  padding: 8px 0; border-bottom: 1px solid var(--hairline);
}
.rb-k { font-size: 13.5px; color: var(--ink-2); }
.rb-v {
  grid-column: 2; grid-row: 1; text-align: right;
  font-size: 14px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.rb-v small { display: block; font-size: 11.5px; font-weight: 400; color: var(--ink-4); }
.rb-v.unknown { color: var(--ink-4); font-weight: 500; }
.rb-track {
  grid-column: 1 / -1; grid-row: 2; position: relative;
  height: 6px; margin-top: 6px; border-radius: 3px; background: var(--sunken);
}
.rb-track i {
  position: absolute; left: 0; top: 0; bottom: 0; border-radius: 3px;
  background: var(--fail); opacity: .55;
}
.rbar[data-ok="true"] .rb-track i { background: var(--pass); opacity: .75; }
/* The threshold: the one number the book actually states. */
.rb-track b {
  position: absolute; top: -3px; bottom: -3px; width: 1px;
  background: var(--ink-3);
}
.rbar[data-ok="unknown"] .rb-track b { background: var(--hairline-2); }

/* ═══════════════════════════════════════════════════ the motion system

   Everything arrives by tightening and reveals by releasing: the one idea
   the whole app shares, and the product's own subject made temporal.

   Three rules hold it together. Content is legible at frame one — motion
   refines, it never gates reading. A sequence staggers at most ten items,
   so a 96-row ledger never takes two seconds to appear. And every effect
   here collapses to an instant state change under prefers-reduced-motion,
   at the end of this block. */

@keyframes coil-row-in {
  from { opacity: 0; transform: translateY(7px) scaleY(.975); }
  to   { opacity: 1; transform: none; }
}
@keyframes coil-rule-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes coil-fade-in   { from { opacity: 0; } to { opacity: 1; } }
@keyframes coil-draw      { to { stroke-dashoffset: 0; } }
@keyframes coil-pop {
  from { opacity: 0; transform: scale(.7); }
  to   { opacity: 1; transform: none; }
}

/* Applied by reveal() in ui.js, which sets --i per item and caps it. */
.reveal-item {
  animation: coil-row-in var(--t-settle) var(--e-spring) both;
  animation-delay: calc(var(--i, 0) * var(--stagger));
  transform-origin: top center;
}
.reveal-fade {
  animation: coil-fade-in var(--t-quick) var(--e-out) both;
  animation-delay: calc(var(--i, 0) * var(--stagger));
}

/* A section announces itself by drawing its own rule. Only the rule
   grows: scaling the head itself squashed its text while it played. */
@keyframes coil-rule-grow { from { background-size: 0 1px; } to { background-size: 100% 1px; } }
.page[data-fresh] .section-head,
.page[data-fresh] .sec-head {
  background-image: linear-gradient(var(--hairline), var(--hairline));
  background-repeat: no-repeat;
  background-position: left bottom;
  background-size: 100% 1px;
  animation: coil-rule-grow var(--t-draw) var(--e-out) both;
}

/* Skeletons hand over rather than swapping. */
.skeleton-out { animation: coil-fade-in var(--t-quick) var(--e-out) reverse both; }

/* Press feedback: the smallest acknowledgement an interface can give. */
.btn, .tog, .seg-ctl button, .vfilters button, .theme-toggle, .searchbtn {
  transition: background var(--t-instant) var(--e-out),
              border-color var(--t-instant) var(--e-out),
              color var(--t-instant) var(--e-out),
              transform 60ms var(--e-out);
}
.btn:active, .tog:active, .seg-ctl button:active,
.vfilters button:active, .theme-toggle:active { transform: scale(.985); }

@media (prefers-reduced-motion: reduce) {
  .reveal-item, .reveal-fade, .skeleton-out,
  .page[data-fresh] .section-head, .page[data-fresh] .sec-head {
    animation: none !important;
  }
  .btn:active, .tog:active, .seg-ctl button:active,
  .vfilters button:active, .theme-toggle:active { transform: none; }
}

/* ══════════════════════════════════════════════════ the plain read

   The sentence that goes in front of the numbers. Set at reading size,
   in the page's own voice, with the qualifier underneath at caption
   weight — so the first thing a newcomer meets is a claim they can
   understand and the second is the evidence for it. */

.readout { margin: 26px 0 4px; max-width: 78ch; }
.readout-lead {
  margin: 0; font-size: clamp(18px, 1.6vw, 23px); line-height: 1.45;
  letter-spacing: -0.015em; color: var(--ink);
}
.readout-sub {
  margin: 10px 0 0; font-size: 14.5px; line-height: 1.6; color: var(--ink-3);
  max-width: 72ch;
}

/* ══════════════════════════════════════════ a value that changed

   The one effect a market screen genuinely needs: when a polled number
   moves, it says so in the direction it moved and then gets out of the
   way. 1.2s decay, so a busy poll never leaves the page strobing. */

@keyframes coil-flash-up {
  from { background: color-mix(in srgb, var(--pass) 22%, transparent); }
  to   { background: transparent; }
}
@keyframes coil-flash-down {
  from { background: color-mix(in srgb, var(--fail) 22%, transparent); }
  to   { background: transparent; }
}
.flash-up   { animation: coil-flash-up 1.2s var(--e-out) both;
              border-radius: 3px; }
.flash-down { animation: coil-flash-down 1.2s var(--e-out) both;
              border-radius: 3px; }

/* The freshness dot breathes only while the data is actually fresh. */
@keyframes coil-breathe {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(.82); }
}
.pulse .dot { animation: coil-breathe 2.4s ease-in-out infinite; }
.pulse[data-tone="unknown"] .dot { animation: none; }

@media (prefers-reduced-motion: reduce) {
  .flash-up, .flash-down, .pulse .dot { animation: none !important; }
}

/* ═══════════════════════════════════════ depth, bloom, tension field

   The other half of "it feels dull", and the half motion cannot fix. The
   colour rule stands — nothing here carries meaning, and nothing is
   tinted to look lively — but a page needs tonal range to read as a
   surface rather than as a hole. Three devices, used sparingly:

   1. a 1px inner highlight, so a raised surface has an edge;
   2. one accent wash per page, behind the title, at the threshold of
      visibility — it is what separates "premium dark" from "black";
   3. the brand motif as a corner texture at ~4% opacity.

   If any of these becomes noticeable on its own, it is too strong. */

:root[data-theme="dark"] .palette,
:root[data-theme="dark"] .drawer,
:root[data-theme="dark"] .split {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .05), var(--shadow-float);
}
:root[data-theme="dark"] .searchbtn,
:root[data-theme="dark"] .theme-toggle,
:root[data-theme="dark"] .btn,
:root[data-theme="dark"] select,
:root[data-theme="dark"] input[type="text"],
:root[data-theme="dark"] input[type="number"],
:root[data-theme="dark"] input[type="search"] {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}

/* One wash per page, behind the head, anchored to the title's own corner.
   In light it is barely a tint; in dark it is what gives the ground air. */
.page-head::before {
  content: ""; position: absolute; z-index: -1;
  left: -12%; right: 30%; top: -60%; bottom: -10%;
  background: radial-gradient(60% 70% at 18% 40%,
    color-mix(in srgb, var(--accent) 12%, transparent), transparent 72%);
  opacity: .3; pointer-events: none;
}
:root[data-theme="dark"] .page-head::before { opacity: .8; }
.page { position: relative; isolation: isolate; }

/* The tension field: the mark's own geometry, as texture, in the corner
   the eye leaves alone. Static — it is a surface, not an animation. */
.page::after {
  content: ""; position: absolute; z-index: -1;
  top: 0; right: 0; width: min(460px, 38vw); height: 320px;
  pointer-events: none; opacity: .5;
  background-image: repeating-linear-gradient(
    76deg, transparent 0 22px, color-mix(in srgb, var(--ink) 9%, transparent) 22px 23px);
  -webkit-mask-image: radial-gradient(75% 85% at 100% 0%, #000, transparent 72%);
          mask-image: radial-gradient(75% 85% at 100% 0%, #000, transparent 72%);
}
@media (max-width: 860px) { .page::after { display: none; } }

/* One oversized element per page breaks the single-tempo problem: the
   figure a page is really about is allowed to be much larger than the
   rest, rather than one size up. */
.figure-hero {
  font-size: clamp(48px, 7vw, 93px); font-weight: 500;
  letter-spacing: -.045em; line-height: .95;
  font-variant-numeric: tabular-nums;
}

/* The screen's own sentence, before its figures. Prose takes a measure —
   a 21px line running the full width of a 1,500px page is a banner, not
   something anyone reads. */
.screen-read { margin: 20px 0 8px; max-width: 74ch; }

/* ══════════════════════════════════════════ the signature moments

   One per screen, and only one. Each is the page's own subject made
   temporal: a market read settling, sessions stamping in one at a time,
   industry bars growing out of the median they are measured against.

   All of them are entrance-only — they play when a view is painted and
   never again, so nothing on a page is perpetually in motion. */

/* Today and Market: the outlook settles out of a tightened state, which
   is the same gesture as the mark itself. */
@keyframes coil-settle {
  from { opacity: 0; letter-spacing: .04em; transform: translateY(3px); }
  to   { opacity: 1; letter-spacing: -.03em; transform: none; }
}
.page[data-fresh] .lead-title {
  animation: coil-settle calc(var(--t-settle) * 1.4) var(--e-out) both;
}

/* Market: 25 sessions stamp in, left to right, like the sessions they
   stand for. The flagged ones land last and hardest. */
@keyframes coil-stamp {
  from { opacity: 0; transform: scaleY(.3); }
  to   { opacity: 1; transform: none; }
}
.page[data-fresh] .ribbon i {
  transform-origin: bottom center;
  animation: coil-stamp calc(var(--t-quick) * .8) var(--e-out) both;
  animation-delay: calc(var(--i, 0) * 18ms * var(--motion-scale));
}

/* Sector flow: bars grow out of the median line — which is also the
   honest reading, since that is what they are measured against. */
@keyframes coil-grow-x { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.page[data-fresh] .dbar i,
.page[data-fresh] .meter i {
  animation: coil-grow-x var(--t-settle) var(--e-out) both;
  animation-delay: calc(var(--i, 0) * 12ms * var(--motion-scale));
}
.dbar i.pos { transform-origin: left center; }
.dbar i.neg { transform-origin: right center; }
.meter i { transform-origin: left center; }

/* Watchlist: a crossed pivot is the one event the app celebrates. */
@keyframes coil-release {
  0%   { transform: scaleY(1); }
  45%  { transform: scaleY(1.09); }
  100% { transform: scaleY(1); }
}
.released { animation: coil-release calc(var(--t-settle) * 1.3) var(--e-spring) both; }

@media (prefers-reduced-motion: reduce) {
  .page[data-fresh] .lead-title,
  .page[data-fresh] .ribbon i,
  .page[data-fresh] .dbar i,
  .page[data-fresh] .meter i,
  .released { animation: none !important; }
}

/* ══════════════════════════════════════════ interaction feedback

   Hovering a ledger dims its siblings a step and lifts the hovered row's
   own glyph. It is the cheapest way to make a dense list feel like an
   instrument: the row you are pointing at is the row the page is about. */

.ledger:hover .lrow:not(:hover),
.ledger:hover .crow:not(:hover),
.ledger:hover .vrow:not(:hover),
.feature:hover .feature-row:not(:hover) {
  opacity: .62;
}
.lrow, .crow, .vrow, .feature-row {
  transition: background var(--t-instant) var(--e-out),
              opacity var(--t-instant) var(--e-out);
}
.lrow svg, .crow svg, .vrow svg, .feature-row svg {
  transition: transform var(--t-instant) var(--e-out);
}
.lrow:hover svg, .crow:hover svg, .vrow:hover svg { transform: scale(1.05); }

/* The row that opened the chart keeps a lit rail, so the pane beside it
   is visibly *that row's* chart rather than a panel that appeared. */
.split-active, .lrow.split-active {
  background: var(--accent-wash) !important;
  box-shadow: inset 2px 0 0 var(--accent);
}
@keyframes coil-rail-in { from { box-shadow: inset 0 0 0 var(--accent); } }
.split-active { animation: coil-rail-in var(--t-quick) var(--e-out) both; }

@media (prefers-reduced-motion: reduce) {
  .ledger:hover .lrow:not(:hover), .ledger:hover .crow:not(:hover),
  .ledger:hover .vrow:not(:hover), .feature:hover .feature-row:not(:hover) { opacity: 1; }
  .split-active { animation: none; }
}

/* The setup's own shape, beside the sentence describing it: the
   contraction sequence as bars, and where price sits between its stop and
   its pivot. A row that reads and a row that is drawn, in one line. */
.feature-glyphs {
  display: flex; flex-direction: column; gap: 6px; align-items: flex-end;
  justify-self: end;
}
.feature-glyphs svg { display: block; }
@media (max-width: 1180px) {
  .feature-row { grid-template-columns: 200px minmax(0, 1fr) 150px; }
  .feature-glyphs { display: none; }
}

/* ═══════════════════════════════════════════════════ NSE Screens

   A query editor, a metric gallery and ready-made screens above a ledger.
   The signature is the sieve: the whole market as one bar, split into
   what matched, what could not be judged, and what failed — drawn in on
   every run, so the proportion reads before any number does. */

.nse-presets { margin: 4px 0 26px; }
.nse-fold { margin-top: 8px; color: var(--accent); }
.nav a { white-space: nowrap; }
.nse-cats {
  display: flex; gap: 2px; flex-wrap: wrap; margin-bottom: 10px;
  border-bottom: 1px solid var(--hairline);
}
.nse-cats button {
  height: 34px; padding: 0 12px; font-size: 13.5px; color: var(--ink-3);
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color .15s, border-color .2s var(--e-out);
}
.nse-cats button:hover { color: var(--ink); }
.nse-cats button.on { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }

.nse-plist {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr));
  column-gap: 28px;
}
.np {
  display: grid; grid-template-columns: 1fr auto; grid-template-areas:
    "cat n" "name n" "q q";
  gap: 1px 14px; align-items: center; text-align: left;
  padding: 11px 8px 12px; border-bottom: 1px solid var(--hairline);
  position: relative; transition: background .15s;
}
.np:hover { background: var(--surface); }
.np.on { background: var(--accent-wash); }
.np.on::before {
  content: ""; position: absolute; left: 0; top: 8px; bottom: 8px; width: 2px;
  background: var(--accent); border-radius: 2px;
  animation: coil-grow-x .3s var(--e-out) both; transform-origin: top;
}
.np-cat { grid-area: cat; font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase;
          color: var(--ink-3); font-weight: 600; }
.np-name { grid-area: name; font-size: 14.5px; font-weight: 600; color: var(--ink);
           line-height: 1.3; }
.np-q { grid-area: q; font-size: 11.5px; color: var(--ink-3); margin-top: 3px;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.np-n { grid-area: n; display: grid; justify-items: end; gap: 5px; font-size: 15px;
        font-weight: 600; color: var(--ink); }
.np-bar { display: block; width: 58px; height: 3px; border-radius: 2px;
          background: var(--hairline); overflow: hidden; }
.np-bar i { display: block; height: 100%; width: var(--w); background: var(--accent);
            border-radius: 2px; transform-origin: left;
            animation: coil-grow-x .7s var(--e-out) .15s both; }

/* ─────────────────────────────── editor + gallery */

.nse-build {
  display: grid; grid-template-columns: minmax(0, 1fr) 330px; gap: 22px;
  align-items: start; margin-bottom: 30px;
}
.qe, .gallery {
  border: 1px solid var(--hairline-2); border-radius: 10px; background: var(--surface);
  min-width: 0;
}
.qe { position: relative; transition: border-color .2s, box-shadow .2s; }
.qe:focus-within { border-color: color-mix(in srgb, var(--accent) 55%, var(--hairline-2));
  box-shadow: 0 0 0 4px var(--accent-wash); }
.qe-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
  padding: 10px 14px; border-bottom: 1px solid var(--hairline);
}
.qe-title { font-weight: 600; font-size: 14.5px; padding-left: 9px; position: relative; }
.qe-title::before { content: ""; position: absolute; left: 0; top: 3px; bottom: 3px;
  width: 3px; border-radius: 2px; background: var(--accent); }
.qe-grp { display: inline-flex; align-items: center; gap: 5px; }
.qe-lab { font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase;
          color: var(--ink-3); font-weight: 600; margin-right: 3px; }
.qe-tok {
  height: 26px; min-width: 34px; padding: 0 9px; border-radius: 6px;
  border: 1px solid var(--hairline); background: var(--paper); font-size: 12.5px;
  font-weight: 600; color: var(--ink-2); transition: all .12s;
}
.qe-tok:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-1px); }
.qe-tok:active { transform: none; }
.qe-kbd { margin-left: auto; }
.qe-kbd kbd, .gallery kbd {
  font-family: var(--mono); font-size: 11px; padding: 1px 5px; border-radius: 4px;
  border: 1px solid var(--hairline-2); background: var(--paper);
}
.qe-body { position: relative; display: grid; grid-template-columns: 38px 1fr;
           background: var(--paper); }
.qe-lines {
  padding: 12px 0; text-align: right; color: var(--ink-4); font-size: 13px;
  line-height: 24px; overflow: hidden; user-select: none; border-right: 1px solid var(--hairline);
}
.qe-lines span { display: block; padding-right: 9px; }
.qe-body textarea {
  width: 100%; resize: vertical; border: 0; outline: 0; background: transparent;
  color: var(--ink); font-size: 14px; line-height: 24px; padding: 12px 14px;
  min-height: 132px; caret-color: var(--accent);
}
.qe-body textarea::placeholder { color: var(--ink-4); }
.qe-ac {
  position: absolute; left: 46px; right: 14px; max-width: 460px; z-index: 30;
  background: var(--surface); border: 1px solid var(--hairline-2); border-radius: 8px;
  box-shadow: var(--shadow-pop); padding: 4px; animation: coil-fade-in .12s both;
}
.ac-i { display: flex; justify-content: space-between; gap: 12px; padding: 7px 10px;
        border-radius: 5px; cursor: pointer; font-size: 13.5px; }
.ac-i.on, .ac-i:hover { background: var(--accent-wash); }
.ac-i.on span:first-child { color: var(--accent-ink); font-weight: 600; }
.ac-c { color: var(--ink-3); font-size: 12px; white-space: nowrap; }
.ac-hint { font-size: 11px; color: var(--ink-3); padding: 5px 10px 3px;
           border-top: 1px solid var(--hairline); margin-top: 3px; }

.qe-foot {
  display: flex; gap: 14px; align-items: flex-start; padding: 9px 14px;
  border-top: 1px solid var(--hairline); min-height: 40px;
}
.qe-clear { font-size: 13px; color: var(--fail); font-weight: 500; white-space: nowrap;
            padding-top: 1px; }
.qe-clear:hover { text-decoration: underline; }
.qe-status { display: flex; gap: 8px; align-items: baseline; flex: 1; min-width: 0;
             font-size: 13px; line-height: 1.5; }
.qe-status .qs-mark {
  flex: none; width: 17px; height: 17px; border-radius: 50%; display: inline-grid;
  place-items: center; font-size: 11px; font-weight: 700; transform: translateY(3px);
  animation: coil-pop .3s var(--e-out) both;
}
.qe-status[data-s="ok"] .qs-mark { background: var(--pass-wash); color: var(--pass); }
.qe-status[data-s="err"] .qs-mark { background: var(--fail-wash); color: var(--fail); }
.qe-status[data-s="err"] .qs-read { color: var(--fail); }
.qs-read { min-width: 0; overflow-wrap: anywhere; color: var(--ink-2); }
.qs-read .mono { color: var(--ink); }
.qs-n { margin-left: auto; white-space: nowrap; color: var(--ink-3); }
.qs-where { margin-left: 6px; }
.qs-snip { display: block; margin-top: 4px; color: var(--ink-2); white-space: pre; overflow-x: auto; }
.qs-snip mark { background: var(--fail-wash); color: var(--fail);
  text-decoration: underline wavy var(--fail); text-underline-offset: 3px; border-radius: 2px; }

.qe-run { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 16px;
          padding: 12px 14px 14px; border-top: 1px solid var(--hairline); }
.qe-go { height: 38px; padding: 0 18px; font-size: 14.5px; border-radius: 8px; gap: 9px;
         box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 28%, transparent);
         transition: transform .12s, box-shadow .2s, background .12s; }
.qe-go:hover { transform: translateY(-1px);
  box-shadow: 0 10px 24px color-mix(in srgb, var(--accent) 34%, transparent); }
.qe-go.busy svg { animation: run-pulse .8s ease-in-out infinite; }

.gallery { padding: 12px 12px 10px; display: grid; gap: 10px; position: sticky;
           top: calc(var(--topbar) + 12px); }
.g-head { display: grid; gap: 9px; }
.g-head input { width: 100%; }
.g-cats { display: flex; flex-wrap: wrap; gap: 5px; }
.g-cats button {
  height: 25px; padding: 0 9px; border-radius: 999px; font-size: 12px; color: var(--ink-2);
  border: 1px solid var(--hairline); background: var(--paper); transition: all .12s;
}
.g-cats button:hover { border-color: var(--hairline-2); color: var(--ink); }
.g-cats button.on { background: var(--selected-bg); border-color: var(--selected-bg);
                    color: var(--selected-ink); font-weight: 600; }
.g-list { display: grid; gap: 2px; max-height: 300px; overflow-y: auto;
          margin: 0 -4px; padding: 0 4px; }
.gm {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px; text-align: left;
  padding: 7px 9px; border-radius: 6px; border-left: 2px solid var(--hairline-2);
  transition: background .12s, border-color .12s;
}
.gm:hover, .gm:focus-visible { background: var(--accent-wash); border-left-color: var(--accent); }
.gm-l { font-size: 13.5px; font-weight: 500; color: var(--ink); }
.gm-u { font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); }
.gm-cov { grid-column: 1 / -1; height: 2px; background: var(--hairline); border-radius: 2px;
          overflow: hidden; }
.gm-cov i { display: block; height: 100%; width: var(--w); background:
  color-mix(in srgb, var(--accent) 55%, transparent); }
.g-desc { min-height: 58px; border-top: 1px solid var(--hairline); padding-top: 9px;
          margin: 0; }
.g-desc b { color: var(--ink); }
.g-cov-note { color: var(--ink-2); }
.g-alias { display: inline-block; margin-top: 3px; }

/* ─────────────────────────────── results */

.nse-out { transition: opacity .2s; }
.nse-out.is-running { opacity: .45; pointer-events: none; }
.nse-sum { padding: 6px 0 16px; }
.nse-count { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.nse-big { font-family: var(--sans); font-size: 52px; font-weight: 700; letter-spacing: -0.03em;
           line-height: 1; color: var(--ink); }
.nse-of { font-size: 16px; color: var(--ink-2); }
.nse-of b { color: var(--ink); }

.sieve {
  display: flex; height: 10px; margin: 16px 0 9px; border-radius: 6px; overflow: hidden;
  background: var(--hairline); gap: 2px;
}
.sieve i { display: block; width: var(--w); flex: none; transform-origin: left; }
.sieve .sv-m { background: var(--accent);
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 55%, transparent); }
.sieve .sv-u { background: repeating-linear-gradient(135deg, var(--ink-4) 0 3px,
  transparent 3px 6px); opacity: .6; }
.sieve .sv-f { background: var(--hairline-2); }
.sieve.draw i { animation: coil-grow-x .8s var(--e-out) both; }
.sieve.draw .sv-u { animation-delay: .18s; }
.sieve.draw .sv-f { animation-delay: .3s; }
.sieve-key { display: flex; flex-wrap: wrap; gap: 6px 18px; align-items: center; }
.sieve-key i { display: inline-block; width: 9px; height: 9px; border-radius: 2px;
               margin-right: 6px; vertical-align: -1px; }
.k-m { background: var(--accent); }
.k-u { background: repeating-linear-gradient(135deg, var(--ink-3) 0 2px, transparent 2px 4px); }
.k-f { background: var(--hairline-2); }
.sieve-key .took { margin-left: auto; font-family: var(--mono); font-size: 11.5px; }
.nse-unknown, .nse-note { margin-top: 10px; max-width: 78ch; }
.nse-unknown b, .nse-note b { color: var(--ink-2); }
.nse-note { border-left: 2px solid var(--warn); padding-left: 10px; }

.nse-tools { display: flex; flex-wrap: wrap; gap: 10px 14px; align-items: center;
             margin: 6px 0 10px; }
.nse-tools input { width: min(320px, 100%); }
.nse-tools .btn { margin-left: auto; }
.nse-scroll { overflow-x: auto; margin: 0 calc(var(--gut) * -1); padding: 0 var(--gut); }
.nse-table { min-width: max-content; }
.nse-table .ledger-head { position: static; margin: 0; padding: 9px 4px; }
.nse-table .ledger-head, .nse-table .lrow { min-width: 900px; }
.nse-row { color: inherit; text-decoration: none; }
.nse-co { min-width: 0; }
.nse-co .sym { display: block; font-size: 14.5px; overflow: hidden; text-overflow: ellipsis;
               white-space: nowrap; }
.nse-co .co { font-size: 11.5px; letter-spacing: .02em; }
/* The query's own metrics: named in the accent, figures in full weight. */
.nse-table .lrow .qcol .tnum { font-weight: 600; }
.nse-table .ledger-head .qcol button { color: var(--accent-ink); }
.nse-more { padding: 16px 0 6px; display: flex; justify-content: center; }
.nse-credit { margin: 34px 0 10px; max-width: 86ch; border-top: 1px solid var(--hairline);
              padding-top: 14px; }

@media (max-width: 1100px) {
  .nse-build { grid-template-columns: 1fr; }
  .gallery { position: static; }
  .g-list { max-height: 220px; }
}
@media (max-width: 900px) {
  .lrow > .hide-md, .ledger-head > .hide-md { display: none; }
}
@media (max-width: 640px) {
  .nse-plist { grid-template-columns: 1fr; }
  .nse-big { font-size: 40px; }
  .qe-kbd { display: none; }
  .qe-bar { gap: 8px 10px; }
  .sieve-key .took { margin-left: 0; width: 100%; }
  .nse-tools .btn { margin-left: 0; }
  .nse-table .lrow > :first-child, .nse-table .ledger-head > :first-child {
    position: sticky; left: 0; z-index: 2; background: var(--paper);
    box-shadow: 8px 0 10px -8px var(--scrim);
  }
}
@media (prefers-reduced-motion: reduce) {
  .np-bar i, .sieve.draw i, .np.on::before { animation: none; }
}

/* On a phone the market pill gives way instead of pushing the top bar
   past the screen edge. */
@media (max-width: 480px) {
  .topbar-end { min-width: 0; }
  .pulse { min-width: 0; max-width: 150px; }
  .pulse .txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ═══════════════════════════════════════════ My scan — ML-ERT

   The one strategy on the site that is Shiv's own, so its entrance is
   the loudest thing on NSE Screens: a lit tile above the page head, with
   three bars tightening and breaking out — the setup, in miniature. */

.myscan {
  float: right; position: relative; z-index: 2; margin: 2px 0 12px 18px;
  display: flex; align-items: center; gap: 12px; padding: 11px 16px 11px 13px;
  border-radius: 12px; text-decoration: none; color: var(--on-accent);
  background:
    radial-gradient(120% 140% at 0% 0%, color-mix(in srgb, #fff 22%, transparent), transparent 55%),
    linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 62%, #7c3aed));
  box-shadow: 0 10px 30px color-mix(in srgb, var(--accent) 38%, transparent),
              inset 0 1px 0 color-mix(in srgb, #fff 30%, transparent);
  transition: transform .18s var(--e-out), box-shadow .25s;
  animation: coil-fade-in .5s var(--e-out) .1s both;
  overflow: hidden;
}
.myscan::after {                       /* a slow sheen, once per arrival */
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 35%, color-mix(in srgb, #fff 28%, transparent) 50%, transparent 65%);
  background-size: 250% 100%; background-position: 130% 0;
  animation: myscan-sheen 2.4s var(--e-out) .6s 1 both; pointer-events: none;
}
@keyframes myscan-sheen { to { background-position: -30% 0; } }
.myscan:hover { transform: translateY(-2px);
  box-shadow: 0 16px 38px color-mix(in srgb, var(--accent) 46%, transparent),
              inset 0 1px 0 color-mix(in srgb, #fff 30%, transparent); }
.myscan.on { background: var(--surface); color: var(--ink);
  border: 1px solid var(--hairline-2); box-shadow: none; }
.myscan.on::after { display: none; }
.myscan-glyph { display: flex; align-items: flex-end; gap: 3px; height: 22px; width: 26px; }
.myscan-glyph i { display: block; width: 6px; border-radius: 2px; background: currentColor;
  opacity: .9; animation: myscan-coil 2.8s var(--e-tight) infinite; }
.myscan-glyph i:nth-child(1) { height: 16px; opacity: .55; }
.myscan-glyph i:nth-child(2) { height: 11px; opacity: .75; animation-delay: .15s; }
.myscan-glyph i:nth-child(3) { height: 22px; animation-delay: .3s; }
@keyframes myscan-coil { 0%, 60%, 100% { transform: scaleY(1); } 30% { transform: scaleY(.6); } }
.myscan-txt { display: grid; line-height: 1.15; }
.myscan-k { font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; font-weight: 700;
            opacity: .85; }
.myscan-t { font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
.myscan-go { font-size: 18px; margin-left: 4px; transition: transform .2s var(--e-out); }
.myscan:hover .myscan-go { transform: translateX(3px); }

/* ─────────────────────────────── hero + pipeline */

.ml-hero { display: grid; gap: 10px; margin: 6px 0 22px; }
.ml-badge { display: inline-block; font-size: 10.5px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent-ink); background: var(--accent-wash);
  padding: 3px 8px; border-radius: 999px; }
.ml-h { font-size: 30px; font-weight: 700; letter-spacing: -.02em; margin: 8px 0 4px; }
.ml-h span { color: var(--ink-3); font-weight: 500; }
.ml-lede { max-width: 78ch; color: var(--ink-2); font-size: 14.5px; line-height: 1.55; margin: 0; }
.ml-today { font-size: 16px; margin: 4px 0 0; color: var(--ink-2); }
.ml-today b { color: var(--ink); font-size: 18px; }

/* Sized by the space it has, not the window: with the chart split open
   the page is half as wide. The 1px gap over a hairline ground draws the
   dividers at every column count. */
#mlRoot { container-type: inline-size; }
.ml-pipe {
  display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 1px;
  background: var(--hairline); border-top: 1px solid var(--hairline-2);
  border-bottom: 1px solid var(--hairline); margin-bottom: 20px;
}
.ml-step { display: grid; gap: 5px; align-content: start; padding: 14px 12px;
           background: var(--paper); min-width: 0; }
.ml-step:first-child { padding-left: 0; }
.ml-k { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
        color: var(--ink-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ml-v { font-size: 26px; font-weight: 600; letter-spacing: -.03em; line-height: 1; }
.ml-step:nth-last-child(2) .ml-v { color: var(--pass); }
.ml-bar { display: block; height: 4px; background: var(--hairline); border-radius: 2px; overflow: hidden; }
.ml-bar i { display: block; height: 100%; width: var(--w); border-radius: 2px;
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #7c3aed));
  transform-origin: left; }
.ml-pipe.draw .ml-bar i { animation: coil-grow-x .8s var(--e-out) both;
  animation-delay: calc(var(--i) * 70ms); }
.ml-note { font-size: 11.5px; color: var(--ink-3); line-height: 1.35;
  overflow-wrap: anywhere; }

/* ─────────────────────────────── controls, tabs, table */

.ml-controls { display: flex; flex-wrap: wrap; gap: 14px 34px; margin-bottom: 18px; }
.ml-ctl { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; }
.ml-lab { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
          color: var(--ink-3); }
.ml-cap { font-size: 13px; color: var(--ink-2); display: inline-flex; align-items: center; gap: 6px; }
.ml-cap input { width: 120px; }

.ml-tabs { display: flex; flex-wrap: wrap; gap: 2px; border-bottom: 1px solid var(--hairline); }
.ml-tabs button {
  display: inline-flex; align-items: center; gap: 7px; height: 38px; padding: 0 13px;
  font-size: 13.5px; color: var(--ink-3); border-bottom: 2px solid transparent; margin-bottom: -1px;
  transition: color .15s, border-color .2s var(--e-out);
}
.ml-tabs button:hover { color: var(--ink); }
.ml-tabs button.on { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }
.ml-tabs i { width: 7px; height: 7px; border-radius: 50%; background: var(--unknown); }
.ml-tabs i[data-tone="PASS"] { background: var(--pass); }
.ml-tabs i[data-tone="PARTIAL"] { background: var(--warn); }
.ml-tabs i[data-tone="FAIL"] { background: var(--fail); }
.ml-tabs .n { font-size: 12px; font-variant-numeric: tabular-nums; color: var(--ink-3);
  background: var(--sunken); border-radius: 999px; padding: 1px 7px; }
.ml-tabs button.on .n { background: var(--accent-wash); color: var(--accent-ink); }
.ml-stage-say { margin: 10px 0 8px; }

.ml-table .ledger-head, .ml-table .lrow { min-width: 1060px; }
.ml-table .ledger-head { position: static; margin: 0; padding: 9px 4px; }
.ml-table .lrow .r { display: grid; justify-items: end; gap: 1px; }
.ml-sub { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; }
.ml-sub.up { color: var(--pass); }
.ml-checks { display: inline-flex; gap: 3px; }
.ml-checks i { width: 12px; height: 12px; border-radius: 3px; background: var(--unknown-wash);
               border: 1px solid var(--hairline-2); }
.ml-checks i[data-s="PASS"] { background: var(--pass); border-color: var(--pass); }
.ml-checks i[data-s="PARTIAL"] { background: var(--warn); border-color: var(--warn); opacity: .8; }
.ml-checks i[data-s="FAIL"] { background: var(--fail-wash); border-color: var(--fail); }

/* ─────────────────────────────── rules */

.ml-rules { margin: 34px 0 10px; border-top: 1px solid var(--hairline-2); }
.ml-rules summary { cursor: pointer; display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 6px 14px; padding: 14px 0; list-style: none; }
.ml-rules summary::-webkit-details-marker { display: none; }
.ml-rules summary::before { content: "+"; font-family: var(--mono); color: var(--accent); width: 12px; }
.ml-rules[open] summary::before { content: "−"; }
.ml-rule { display: grid; grid-template-columns: 34px 1fr; gap: 14px; padding: 12px 0;
           border-top: 1px solid var(--hairline); }
.ml-step-n { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-weight: 700; font-size: 12.5px; background: var(--selected-bg); color: var(--selected-ink); }
.ml-pdf { margin: 0 0 5px; font-size: 14px; color: var(--ink); }
.ml-ours { margin: 0; font-size: 13px; color: var(--ink-2); line-height: 1.55; }
.ml-ours span { font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
                color: var(--accent-ink); margin-right: 6px; }

/* ─────────────────────────────── backtest */

.ml-bt { margin-top: 30px; }
.ml-verdict { max-width: 80ch; font-size: 15px; line-height: 1.55; color: var(--ink-2);
  border-left: 3px solid var(--warn); padding: 4px 0 4px 14px; margin: 12px 0 6px; }
.ml-verdict b { color: var(--ink); }
.ml-metrics .v.up { color: var(--pass); }
.ml-metrics .v.down { color: var(--fail); }
.ml-curve-wrap { margin: 22px 0 8px; }
.ml-curve-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px;
                 margin-bottom: 8px; }
.ml-curve { display: block; width: 100%; height: 170px; }
.ml-curve .zero { stroke: var(--hairline-2); stroke-dasharray: 3 4; vector-effect: non-scaling-stroke; }
.ml-curve .line { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; }
.ml-curve .line.pos { stroke: var(--pass); }
.ml-curve .line.neg { stroke: var(--fail); }
.ml-curve .area.pos { fill: color-mix(in srgb, var(--pass) 12%, transparent); }
.ml-curve .area.neg { fill: color-mix(in srgb, var(--fail) 10%, transparent); }
.ml-curve-axis { display: flex; justify-content: space-between; margin-top: 4px; }
.ml-splits { margin-top: 20px; gap: 28px; }
.ml-split { display: grid; gap: 4px; margin-bottom: 18px; }
.ml-sb { display: grid; grid-template-columns: minmax(170px, 1.3fr) 2fr 62px 52px;
         gap: 10px; align-items: center; font-size: 13px; }
.ml-sb-k { color: var(--ink-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ml-sb-bar { position: relative; height: 10px; background:
  linear-gradient(90deg, transparent calc(50% - .5px), var(--hairline-2) calc(50% - .5px),
                  var(--hairline-2) calc(50% + .5px), transparent calc(50% + .5px)); }
.ml-sb-bar i { position: absolute; top: 1px; bottom: 1px; width: var(--w); border-radius: 2px;
               animation: coil-grow-x .7s var(--e-out) both; }
.ml-sb-bar i.pos { background: var(--pass); transform-origin: left; }
.ml-sb-bar i.neg { background: var(--fail); transform-origin: right; }
.ml-sb-v { text-align: right; font-weight: 600; }
.ml-sb-n { text-align: right; }
.ml-caveats { margin: 8px 0 16px; }
.ml-caveats summary { cursor: pointer; }
.ml-caveats ul { margin: 8px 0 0; padding-left: 18px; display: grid; gap: 4px; max-width: 86ch; }
.ml-trades .ledger-head, .ml-trades .lrow { min-width: 820px; }
.ml-trades .ledger-head { position: static; margin: 0; padding: 9px 4px; }
.ml-foot { margin: 30px 0 10px; border-top: 1px solid var(--hairline); padding-top: 14px; }

@container (max-width: 900px) {
  .ml-pipe { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .ml-step:nth-child(5) { padding-left: 0; }
}
@container (max-width: 480px) {
  .ml-pipe { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ml-step:nth-child(odd) { padding-left: 0; }
  .ml-step:nth-child(even) { padding-left: 12px; }
  .ml-sb { grid-template-columns: 110px 1fr 56px 44px; }
}
@media (max-width: 640px) {
  .myscan { float: none; margin: 0 0 14px; }
  .ml-h { font-size: 24px; }
}
@media (prefers-reduced-motion: reduce) {
  .myscan, .myscan::after, .myscan-glyph i, .ml-pipe.draw .ml-bar i, .ml-sb-bar i { animation: none; }
}

/* ═══════════════════════════════════════════ sector picker

   NSE's four-level classification, from a whole macro sector down to one
   basic industry. A bar of chips on the page; the tree opens as the one
   popover on it. */

.nse-sectors { position: relative; z-index: 25; margin: 0 0 18px; }
.sp-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px;
  padding: 10px 0; border-top: 1px solid var(--hairline-2); border-bottom: 1px solid var(--hairline); }
.sp-lab { font-size: 10.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
          color: var(--ink-3); margin-right: 2px; }
.sp-open {
  display: inline-flex; align-items: center; gap: 8px; height: 32px; padding: 0 12px;
  border-radius: 8px; border: 1px solid var(--hairline-2); background: var(--surface);
  font-size: 13.5px; font-weight: 600; color: var(--ink); transition: border-color .15s, box-shadow .2s;
}
.sp-open:hover { border-color: var(--accent); }
.sp-bar.has .sp-open { border-color: var(--accent); color: var(--accent-ink);
  box-shadow: 0 0 0 3px var(--accent-wash); }
.sp-open[aria-expanded="true"] svg { transform: rotate(180deg); }
.sp-open svg { transition: transform .2s var(--e-out); }
.sp-chips { display: contents; }
.sp-chip {
  display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 6px 0 4px;
  border-radius: 999px; background: var(--accent-wash); color: var(--accent-ink);
  font-size: 12.5px; font-weight: 500; animation: coil-pop .25s var(--e-out) both;
}
.sp-chip i { font-style: normal; font-size: 9.5px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; background: var(--surface); color: var(--ink-3);
  padding: 2px 6px; border-radius: 999px; }
.sp-chip b { font-size: 10px; opacity: .6; padding: 0 3px; }
.sp-chip:hover b { opacity: 1; }
.sp-clear { font-size: 12.5px; color: var(--fail); }
.sp-clear:hover { text-decoration: underline; }
.sp-src { margin-left: auto; }

.sp-panel {
  position: absolute; left: 0; top: calc(100% + 6px); width: min(620px, 100%);
  background: var(--surface); border: 1px solid var(--hairline-2); border-radius: 12px;
  box-shadow: var(--shadow-float); padding: 10px; animation: coil-fade-in .15s both;
}
.sp-head { display: flex; gap: 8px; }
.sp-search { flex: 1; }
.sp-tree { max-height: min(460px, 60vh); overflow-y: auto; margin: 8px -4px 0; padding: 0 4px; }
.sp-node { display: grid; grid-template-columns: 22px 1fr; align-items: center;
  padding-left: calc(var(--d) * 18px); }
.sp-tw { width: 22px; height: 26px; display: grid; place-items: center; color: var(--ink-3); }
.sp-tw svg { transition: transform .18s var(--e-out); }
.sp-tw.open svg { transform: rotate(90deg); }
.sp-row { display: grid; grid-template-columns: 18px 1fr auto 44px; align-items: center; gap: 8px;
  padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 13.5px; }
.sp-row:hover { background: var(--sunken); }
.sp-row.on { background: var(--accent-wash); }
.sp-row.implied { opacity: .7; }
.sp-row input { accent-color: var(--accent); margin: 0; }
.sp-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); }
.sp-path { display: block; font-size: 11.5px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; }
.sp-lvl { font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3); }
.sp-n { text-align: right; color: var(--ink-3); font-size: 12.5px; }
.sp-foot { margin: 8px 4px 2px; }

@media (max-width: 640px) {
  .sp-src { margin-left: 0; width: 100%; }
  .sp-panel { position: fixed; left: 8px; right: 8px; top: 70px; width: auto; z-index: 90; }
}

/* ══════════════════════════════════════════════ route progress

   A hairline across the top while a view is being fetched: the app has
   heard the click before it has anything to paint. It waits 120ms before
   showing, so a view served from the read cache never flashes it. */

.route-progress {
  position: fixed; inset: 0 0 auto 0; height: 2px; z-index: 300;
  pointer-events: none; transform-origin: left center;
  background: linear-gradient(90deg, transparent, var(--accent) 30%, var(--accent));
  transform: scaleX(0); opacity: 0;
}
.route-progress[data-state="run"] {
  opacity: 1;
  animation: route-crawl 2.4s cubic-bezier(.1, .7, .2, 1) 120ms both;
}
.route-progress[data-state="done"] {
  opacity: 0; transform: scaleX(1);
  transition: transform 140ms var(--e-out), opacity 220ms 120ms var(--e-out);
}
@keyframes route-crawl {
  from { transform: scaleX(0); }
  to   { transform: scaleX(.86); }
}
@media (prefers-reduced-motion: reduce) {
  .route-progress[data-state="run"] { animation: none; transform: scaleX(.5); }
}
