/* ==========================================================================
   Volar design tokens — the single source of truth for the visual language.
   ==========================================================================

   Every colour, size, and rhythm in the product resolves to a value in this
   file. Nothing else may declare a raw hex; `tests/design/test_design_tokens.py`
   enforces that.

   Why this file exists at all: before it, the design language was copy-pasted
   across landing/index.html, base.html and base_public.html, plus six page-level
   <style> blocks. That is how the same product came to advertise three
   different prices (€99 / €149 / €199) on three surfaces at once. A shared
   token file makes that class of drift structurally impossible rather than
   something a person has to remember.

   Direction: evidence-forward. Volar sells market data to quantitative
   researchers who evaluate a vendor by reading schemas, null rates and coverage
   gaps. The visual language is therefore built for dense tabular data and long
   numeric reading, not for editorial prose.

   Colour decisions are computed, not eyeballed:
     - text tokens verified for WCAG contrast against --ground
     - the sequential ramp verified monotonic in OKLab lightness
     - status hues taken unmodified from the validated reference palette,
       and deliberately NOT used as thin data marks (see the note there)
   ========================================================================== */

:root {
  /* ---------------------------------------------------------------------
     Surfaces

     Cool paper rather than cream. Cream (#f6f1e7, the previous ground) reads
     literary/editorial — a magazine. A faint blue cast reads instrument,
     lab, screen, which is what a data product should feel like.
     --------------------------------------------------------------------- */
  --ground:        #F4F7F9;  /* page background */
  --surface:       #FFFFFF;  /* raised: cards, table bodies */
  --surface-sunk:  #E9EFF3;  /* recessed: code wells, inputs */

  /* ---------------------------------------------------------------------
     Ink — blue-black, never pure black. Contrast vs --ground:
       ink 17.15 · ink-2 9.53 · ink-3 5.21   (all clear WCAG AA for text)
     --------------------------------------------------------------------- */
  --ink:           #0D1519;  /* headings, primary text, data */
  --ink-2:         #33434C;  /* body prose */
  --ink-3:         #5A6A73;  /* labels, captions, table headers */

  /* Rules are decorative (contrast ~1.2) and must never carry meaning alone. */
  --rule:          #D7E1E7;
  --rule-soft:     #E8EEF2;

  /* ---------------------------------------------------------------------
     Signal — indigo. Links and primary actions.

     Not navy (Databento, Massive), not terracotta, not acid green: those are
     respectively the category convention and two of the three looks that read
     as machine-generated. Indigo is uncommon here and reads technical.
     Contrast 7.80 on --ground, 8.40 on white.
     --------------------------------------------------------------------- */
  --signal:        #3F37BE;
  --signal-hover:  #2E278F;
  --signal-wash:   #EEEDF9;  /* tinted backgrounds, selected rows */

  /* ---------------------------------------------------------------------
     Sequential ramp — magnitude. One hue, light → dark.

     Used for the coverage strip and, later, IV surfaces. A single hue is
     colour-vision-safe by construction: there are no adjacent-pair confusions
     to validate away. Verified strictly monotonic in OKLab lightness
     (0.932 → 0.335); contrast vs --ground runs 1.14 → 11.74.

     For data marks use --seq-400 and darker: below that the mark falls under
     3:1 against the ground and cannot be read on its own.
     --------------------------------------------------------------------- */
  --seq-100: #E8E6F9;
  --seq-200: #CBC7F1;
  --seq-300: #ADA6E8;
  --seq-400: #8C83DD;   /* 3.05 — lightest usable mark */
  --seq-500: #6B61D0;   /* 4.60 */
  --seq-600: #5148BE;   /* 6.46 */
  --seq-700: #3B33A6;   /* 8.83 */
  --seq-800: #2A2480;   /* 11.74 */

  /* ---------------------------------------------------------------------
     Status — state, never series, never magnitude.

     Taken unmodified from the validated reference palette. Two of these sit
     below 3:1 on a light surface *by design*; the mitigation is that a status
     colour never travels alone — it always ships with an icon and a text
     label. Running the categorical validator against these on our surface
     correctly FAILs (warning measures 1.71), which is exactly why they are
     not used as thin marks. Coverage bars use the sequential ramp instead.
     --------------------------------------------------------------------- */
  --status-good:     #0CA30C;
  --status-warning:  #FAB219;
  --status-serious:  #EC835A;
  --status-critical: #D03B3B;

  /* Readable text equivalents, for when the state must be written out. */
  --status-good-ink:     #076B07;
  --status-warning-ink:  #7A5300;
  --status-serious-ink:  #9A4620;
  --status-critical-ink: #96201F;

  /* ---------------------------------------------------------------------
     Type

     Three roles, deliberately chosen against the brief:
       display — Space Grotesk: technical, geometric with a little grit.
                 Explicitly not a high-contrast serif; that is the single
                 most common machine-generated editorial look.
       body    — IBM Plex Sans: engineered heritage, good tabular figures.
       mono    — JetBrains Mono: designed for long code reading. In an
                 evidence-forward product the data IS the content, so the
                 monospace is a lead voice, not a caption font.
     --------------------------------------------------------------------- */
  --font-display: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
  --font-body:    'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Dense-data scale: more usable steps at small sizes than a typical
     marketing scale, because tables and schema listings live down there. */
  --text-2xs:  0.6875rem;  /* 11px — table micro-labels, units */
  --text-xs:   0.75rem;    /* 12px — captions, eyebrows */
  --text-sm:   0.8125rem;  /* 13px — table cells, code */
  --text-base: 0.9375rem;  /* 15px — body */
  --text-lg:   1.125rem;   /* 18px — lead paragraphs */
  --text-xl:   1.375rem;   /* 22px — card titles */
  --text-2xl:  1.75rem;    /* 28px — section headings */
  --text-3xl:  2.25rem;    /* 36px */
  --text-4xl:  3rem;       /* 48px */
  --text-5xl:  4rem;       /* 64px — hero */

  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  --leading-tight:  1.15;  /* display */
  --leading-snug:   1.35;  /* headings, table cells */
  --leading-normal: 1.6;   /* prose */

  --tracking-tight: -0.02em;  /* large display sizes */
  --tracking-normal: 0;
  --tracking-wide:  0.08em;   /* eyebrows, small caps labels */

  /* ---------------------------------------------------------------------
     Space — 4px base
     --------------------------------------------------------------------- */
  --space-1:  0.25rem;
  --space-2:  0.5rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.5rem;
  --space-6:  2rem;
  --space-7:  3rem;
  --space-8:  4rem;
  --space-9:  6rem;
  --space-10: 8rem;

  /* ---------------------------------------------------------------------
     Radius — small and consistent. Zero radius everywhere is one of the
     machine-generated tells; so is pill-shaped everything. A modest,
     consistent curve reads as a considered product.
     --------------------------------------------------------------------- */
  --radius-sm:   3px;
  --radius:      5px;
  --radius-lg:   8px;
  --radius-full: 999px;

  --border:       1px;
  --border-thick: 2px;

  /* ---------------------------------------------------------------------
     Elevation — restrained. Data surfaces should sit flat and legible.
     --------------------------------------------------------------------- */
  --shadow-sm: 0 1px 2px rgba(13, 21, 25, 0.06);
  --shadow:    0 2px 8px rgba(13, 21, 25, 0.08);

  /* ---------------------------------------------------------------------
     Motion — quick and unobtrusive. Excess animation is itself a tell.
     --------------------------------------------------------------------- */
  --duration-fast: 90ms;
  --duration:      160ms;
  --ease:          cubic-bezier(0.2, 0, 0.2, 1);

  /* ---------------------------------------------------------------------
     Layout measures
     --------------------------------------------------------------------- */
  /* Prose line length. ABSOLUTE, deliberately — `ch` resolves against the
     font size of the element it is set on, so this same token produced 418,
     480, 494, 510, 525, 540, 578 and 628px on different pages, and no two
     sections shared a right edge. A line-length measure is a layout constant,
     not a typographic one. ~80 characters at the 15px body size. */
  --measure-text: 600px;   /* prose line length */
  --measure:      1060px;  /* default content column */
  --measure-wide: 1320px;  /* tables and coverage strips need the room */
}

/* Motion is opt-out at the token level, so no component has to remember. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: 0ms;
    --duration:      0ms;
  }
}

/* --------------------------------------------------------------------------
   Dark mode is deliberately NOT defined yet.

   Per the visualization guidance, a dark theme is *selected* — each ramp step
   re-chosen and re-validated against the dark surface — not an automatic
   inversion. Half a dark mode is worse than none, so it is scoped as its own
   piece of work. Every consumer already reads semantic tokens
   (--ground, --ink, --surface), so adding it later is a change to this file
   alone and touches no component.
   -------------------------------------------------------------------------- */
