/* Design tokens — the single source for every value the public site repeats.
 *
 * This is the file rail.css was written against ("this file deliberately does
 * NOT redeclare those tokens, it consumes them"). Before it existed, seven
 * templates each carried their own copy-pasted :root and drifted: 23 distinct
 * font sizes across 69 type combinations, 49 of them crammed into the 9-13.5px
 * band where nobody can tell 11px from 11.5px.
 *
 * LOAD ORDER: linked from _styles.html, which every template includes BEFORE
 * its own <style>. That makes this the base layer — a template rule still wins
 * at equal specificity, which is what lets templates migrate one at a time.
 *
 * The ONLY custom property a template may still declare is --colw (its own
 * column width). Everything else belongs here.
 */
:root {
  /* ---- type scale ----------------------------------------------------
   * FIVE steps on ONE ratio — 1.4, a real modular scale rather than eleven
   * hand-set numbers:
   *
   *     12 · 17 · 24 · 33 · 46        (12 × 1.4ⁿ, rounded)
   *
   * plus one label step below the scale:  10
   *
   * Until 2026-08-22 there were eleven sizes, and four of them (10/11/12/13)
   * sat inside a 3px band on 1px increments — a gradient, not a scale — while
   * carrying 73% of the site's type. Every old size was re-keyed to its
   * nearest step off the COMMITTED value, rounding UP on a tie so the scale
   * could only ever get more legible. 615 call sites moved.
   *
   * Two consequences worth knowing before you reach for a sixth step:
   *
   * 1. Hierarchy now comes from WEIGHT, COLOUR and SPACE, not from size.
   *    Three weights and the duck/cuck/bill palette were always doing that
   *    job better than a 1px difference nobody could see. If two things need
   *    to look different and they share a step, change the weight.
   * 2. The phone-only override that lifted the smallest step is gone. 11px
   *    is the floor on every screen now, which is all that override wanted.
   *
   * --fs-0 IS OFF THE RATIO ON PURPOSE and is not a sixth text size. It is a
   * LABEL step: uppercase, tracked, no descenders — a column header or a
   * stamp, never a sentence. It exists because those labels sit in 70-95px
   * columns on /lab and wrap to three lines at 12px, and because a header
   * that matches its own data size stops reading as a header. Do not reach
   * for it to make a paragraph fit; that is what --fs-1 is for.
   *
   * ⚠ THE BASE IS 12, NOT 11, AND THAT IS LOAD-BEARING. It puts --fs-2 at
   * 17px, and iOS Safari zooms the page whenever a focused form field is
   * under 16px. The search inputs and screener pickers carry --fs-2 for
   * exactly that reason (tests/test_web/test_mobile_audit_0821.py, and the
   * 07-28 mobile audit before it). An 11-based scale lands that step on
   * 15px and silently brings the zoom bug back.
   *
   * The old 52px display numeral folded into 46px. If the desk-closed
   * countdown wants its size back, that is a SIXTH step and it should be
   * 46 × 1.4 = 64px, not 52 — stay on the ratio. */
  --fs-0: 10px;   /* LABEL — uppercase tracked headers, tape keys, stamps */
  --fs-1: 12px;   /* micro — chips, meta, table cells, dense data */
  --fs-2: 17px;   /* the workhorse — UI text, letter prose, form fields */
  --fs-3: 24px;   /* section headings, big stat figures */
  --fs-4: 33px;   /* hero and panel titles */
  --fs-5: 46px;   /* page titles, the letter headline, the countdown */

  /* ---- weights -------------------------------------------------------
   * Three, down from six. 500 and 800 read as noise next to 600 and 700;
   * 900 appeared exactly twice and was certainly accidental. */
  --w-body: 400;
  --w-mid:  600;
  --w-bold: 700;

  /* ---- spacing -------------------------------------------------------- */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;   /* the rhythm INSIDE a section */
  --sp-7: 48px;
  /* --sp-8 is the SECTION step, and it is not just "one more size". Until
   * 2026-09-02 --sp-6 carried two different jobs: the gap between elements
   * inside a section AND the gap between one major section of a page and the
   * next. A --fs-4 headline followed 32px later by its own body copy reads
   * cramped, and a page whose major joints measure the same as its minor ones
   * has no structure the eye can find without reading every word.
   *
   * Reach for it ONLY where one whole section of a page ends and another
   * begins — the board after the hero, Activity after the cards. Inside a
   * section, --sp-6 is still the answer. Using it between two elements of one
   * component undoes the distinction it exists to draw. */
  --sp-8: 72px;   /* the step BETWEEN sections */

  /* ---- radii ---------------------------------------------------------
   * Four, down from eleven. Literal 50% stays for circles (avatars). */
  --r-xs:   4px;    /* chips, marks */
  --r-sm:   10px;   /* buttons, small cards */
  --r-md:   14px;   /* cards, panels */
  --r-pill: 999px;

  /* ---- measure & column ----------------------------------------------
   * --measure is the READING width: the letter's headline and its prose
   * share it, so a headline can no longer span the full column while its
   * own body stops 40% short. --colw is the PAGE column — 1400px seats the
   * rail and is the SITE-WIDE width, so the shared topbar never resizes
   * between pages. A template may still override it deliberately; none do. */
  /* ⚠ A `ch` CAP IS NOT A CHARACTER COUNT. `ch` is the width of "0", and in
   * DM Sans that is ~1.37x the average character — measured on the live page:
   * max-width:78ch renders 630px and fits ~107 characters. The site's caps
   * are 52ch for that reason, which lands near 72 characters, inside the
   * 45-75 that reads comfortably. Do not "fix" 52ch up to 70ch. */
  --measure: 680px;
  --colw: 1400px;

  /* ---- ink & paper ---------------------------------------------------- */
  --ink:   #111827;
  --paper: #ffffff;
  --dim:   #6b7280;
  --faint: #9ca3af;
  --panel: #fafbfc;

  /* ---- separators -----------------------------------------------------
   * ONE rule colour on light surfaces. --soft is a FILL only: it must never
   * appear inside a border declaration, which is how the site ended up with
   * three near-identical greys drawing the same hairline. */
  --hair: #e5e7eb;
  --soft: #eef0f2;

  /* ---- stance ---------------------------------------------------------
   * duck = bullish, cuck = bearish, sit = no edge. Per-symbol views stay
   * RAW; only market-direction aggregates flip for inverse ETFs. */
  --duck:        #10b981;
  --duck-deep:   #047857;
  --duck-bg:     #d1fae5;
  --duck-bright: #34d399;
  --cuck:        #dc2626;
  --cuck-deep:   #b91c1c;
  --cuck-bg:     #fee2e2;
  --sit-bg:      #f3f4f6;

  /* ---- the bill IS the terminal amber: data labels and eyebrows, dark
   * surfaces only. */
  --bill:      #f59e0b;
  --bill-deep: #d97706;

  /* ---- caution, as a colour a state can hold -------------------------
   * Aliases of the bill, named for the MEANING rather than the mascot, the
   * same way --up/--down alias the stance pair above. /portfolio referenced
   * --warn-deep on its paused account rows and NOTHING defined it, so that
   * state fell through to a hardcoded #b45309 while the lamp meaning the
   * same thing drew --bill (#f59e0b): one state, two ambers. Aliases, not
   * new colours — caution must never drift from the bill. */
  --warn:      var(--bill);
  --warn-deep: var(--bill-deep);

  /* ---- AI Intelligence & Catalyst Accent ------------------------------ */
  --ai-violet: #8b5cf6;
  --ai-glow:   rgba(139, 92, 246, 0.18);
  --ai-border: rgba(139, 92, 246, 0.35);

  /* ---- terminal band: dark instrument surfaces cutting the white page -- */
  --term:      #0a0f1c;
  --term-2:    #0f172a;
  --term-edge: rgba(148, 163, 184, 0.16);
  --term-ink:  #e2e8f0;
  --term-dim:  rgba(226, 232, 240, 0.62);

  /* ---- inline auth messages -------------------------------------------
   * _topbar.html reads these with fallbacks. No page ever defined them, and
   * error.html defined neither them nor --cuck-deep, so its error text fell
   * through to no colour at all. */
  --ok-msg:  var(--duck-deep);
  --err-msg: var(--cuck-deep);

  /* ---- direction, as a colour a chart can hold ------------------------
   * Same duck/cuck pair, named for the axis rather than the mascot, because
   * an SVG stroke reads "up/down" and not "bullish/bearish". lab.html used
   * both names and NOTHING defined them, so every .pos/.neg/.up/.down on the
   * board computed to plain ink and all 60 sparklines drew stroke:none — a
   * whole page of green/red that silently rendered black. Aliases, not new
   * colours: direction must never drift from the stance palette above. */
  --up:   var(--duck-deep);
  --down: var(--cuck-deep);

  /* ---- families --------------------------------------------------------
   * Three faces for the three things this site is: a paper, an interface,
   * and an instrument.
   *
   * --display is DM Sans (2026-08-22, replacing Space Grotesk). A geometric
   * next to Inter's neo-grotesque is a real pairing; Space Grotesk was a
   * second grotesque and never separated. It was named in 72 places and 54
   * of them sat at 20px or below, where it and Inter are the same font to a
   * reader — a webfont request buying a difference nobody could see. DM Sans
   * carries an optical-size axis (9-40), which is why the font links ask for
   * a RANGE and not a list of weights.
   *
   * ⚠ DM SANS HAS NO TABULAR FIGURES. It ships no `tnum` feature, so
   * `font-variant-numeric: tabular-nums` against it is a silent no-op and
   * columns of figures drift. Nothing numeric may be set in --display:
   * .meterbig .kv and .lb .idx were moved to --mono on the swap for exactly
   * this reason. Pinned by test_display_face_never_carries_tabular_figures.
   *
   * --body is ALSO DM Sans as of this pass. The site is now a two-family
   * system: one voice for everything that is words, one for everything that
   * is figures. --display and --body stay separate TOKENS so the roles can
   * be split again without touching 600 call sites; today they resolve to
   * the same family and the display/body distinction is carried by size,
   * weight and the optical-size axis instead.
   *
   * Retiring Inter is what makes the tnum rule above absolute: there is no
   * longer a sans on the page with tabular figures, so EVERY figure that
   * has to line up now belongs in --mono. That is not a workaround, it is
   * the data-layer convention in base.css finally applied everywhere.
   *
   * --mono is Space Mono (same date, replacing JetBrains Mono). Colophon
   * drew it alongside DM Sans, so the two agree; it reads as an instrument
   * where JetBrains reads as a code editor.
   *
   * ⚠ SPACE MONO SHIPS TWO WEIGHTS, 400 AND 700 — there is no 600. The 37
   * mono rules that ask for --w-mid resolve UP to 700 (CSS matches weights
   * >500 ascending first). They are all micro-labels and table headers where
   * bold reads fine, so this is accepted rather than worked around — but the
   * three-weight scale below is three weights in sans and two in mono, and
   * chasing a missing semibold in the mono layer is chasing nothing.
   *
   * ⚠ CHANGING A FAMILY HERE IS HALF THE CHANGE. The other half is every
   * template's own fonts.googleapis.com <link> — miss one and that page
   * renders in system sans with no error and no console warning. Run
   * `pytest tests/test_web/test_design_system.py -k font` after any edit. */
  --display: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --body:    'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono:    'Space Mono', 'SFMono-Regular', Menlo, Consolas, monospace;
}

/* Phones: the LABEL step lifts to 11px. ~300 stamps / tape keys / column
 * headers per page sit at 10px, which reads fine on a 1400px column at arm's
 * length and does not on a 390px screen. Lifting the token moves all of them
 * at once and keeps the scale's shape; the text steps are untouched. */
@media (max-width: 720px) {
  :root { --fs-0: 11px; }
  /* The SECTION step scales; the rhythm inside a section does not. 72px is a
   * joint on a 1400px column and roughly a fifth of the viewport on a 390px
   * phone, where it reads as the page having ended. 48px still clears --sp-6
   * by enough to say "something else starts here", which is the whole job. */
  :root { --sp-8: 48px; }
}
