/* ==========================================================================
   QK CANONICAL DESIGN TOKENS  ·  qk-tokens.css
   --------------------------------------------------------------------------
   THE single source of typeface, colour, type scale, spacing and radius for
   every page on this site. Link it FIRST, before any page-specific stylesheet
   or <style> block, so a page can still override a token deliberately — but
   has to do so on purpose, in the open, after the floor is laid.

   WHY THIS FILE EXISTS
   The EV calculator (members/ev-calculator.html) was, on 2026-08-14, the only
   page of 36 holding the standard its own design spec sets. Its :root block is
   the standard. Those values are reproduced here VERBATIM so the calculator's
   own sheet is byte-identical to this one and its migration in P2e is a no-op.

   TOKEN NAMES ARE LOAD-BEARING. The EV calculator suite pins --t-hero and
   --t-label by name. Do not rename; add.

   NO CDN, NO EXTERNAL HOST. Fonts are self-hosted below and this is the only
   @font-face source in the tree — tests/site_audit.test.mjs pins both facts.

   Reference: QK_Lab\docs\design\EV_CALCULATOR_DESIGN_SPEC_2026-08-14.md
              QK_Lab\docs\design\HANDOFF_PROP_TOOLS_STALENESS_AND_ABSENCE_2026-08-14.md
   ========================================================================== */

/* ------------------------------------------------------------------ fonts
   The ONLY @font-face declarations on the site. Both faces are variable, so
   one file per family covers every weight the design uses (400/600/700).
   Previously duplicated in six places; deduplicated 2026-08-15. */
@font-face {
  font-family: "QK Inter";
  src: url("/assets/fonts/qk-inter-latin-variable.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
}

@font-face {
  font-family: "QK Mono";
  src: url("/assets/fonts/qk-jetbrains-mono-latin-variable.woff2") format("woff2");
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
}

:root {
  /* --------------------------------------------------------------- surfaces */
  --bg:#050807;--surface:#0b1210;--surface2:#101a16;--surface3:#16221c;
  --line:#1a3328;--line-hi:#245840;--hair:rgba(230,242,236,.07);
  --text:#e6f2ec;--muted:#9fb8ac;--dim:#6b8a7c;--faint:#4c6659;
  --up:#4fae8b;--up-hi:#00d99a;--down:#cf6a6e;--warn:#d9a03c;
  --info:#5aa7ff;--violet:#b59cff;--accent:#22c55e;--accent2:#4ade80;
  --font:"QK Inter",Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --mono:"QK Mono","JetBrains Mono","Cascadia Code",Consolas,monospace;
  --r:7px;--r-sm:5px;
  /* ONE exception to the 7/5 radius vocabulary: marketing hero cards, which
     sit at a scale where 7px reads as a rendering artefact rather than a
     corner. Not for instrument surfaces — cards, tables and inputs stay 7/5. */
  --r-lg:12px;

  /* ---------------------------------------------------------- type scale
     Retuned DOWN for a desk instrument: the page states numbers, it does
     not shout them. Token NAMES are load-bearing (the suite pins --t-hero
     and --t-label); values are free. */
  --t-hero:clamp(24px,2.6vw,30px);
  --t-stat:clamp(20px,2.2vw,25px);
  --t-mid:18px;--t-h1:clamp(20px,2.6vw,26px);--t-h2:15.5px;--t-h3:12px;
  --t-body:13.5px;--t-small:12px;--t-label:10.5px;
  --t-figure:15px;   /* the EV RATE numeral in a board cell */
  --t-chart:11px;    /* EVERY svg axis / tick label — single source */
  --t-annot:11.5px;  /* every in-plot annotation label */
  --t-code:11px;     /* basis / provenance / source lines */
  /* THE SECOND OF EXACTLY TWO BODY TIERS. --t-body 13.5px is the instrument
     tier: dense pages that state numbers. --t-prose is for pages that are
     READ — marketing, legal, learn articles, playbook narrative — where a
     13.5px measure over 70ch is a tax on the reader. Nothing else. The
     13/14/15/17px strays collapse onto one of these two. */
  --t-prose:16px;

  /* ------------------------------------------------------- spacing ramp
     Names the 13/14/18/22 magic numbers that were scattered before. */
  --s1:4px;--s2:8px;--s3:12px;--s4:18px;--s5:26px;--s6:38px;

  /* ------------------------------------------------------- colour roles
     ONE COLOUR, ONE MEANING. Published here so a future change has to
     argue with the table rather than pick a hue that looks nice:
       --up-hi  EV positive · passed · MEASURED/SOLID point
       --up     the same at fill weight
       --down   EV negative · blown · the cost bar
       --warn   a THRESHOLD (p*, N*, the member's own marker) AND staleness.
                NEVER an absence.
       --info   an INTERVAL (MC band, Wilson interval, seen band, composed
                ladder). NEVER a point estimate.
       --violet UNSEALED — the member's own input
       --dim    ALL axis and tick TEXT (5.02:1 on --surface — passes AA)
       --faint  NON-TEXT structure only: gridlines, hairlines, rules.
                2.95:1 — never used for text a member must read.
     Colour never carries a distinction alone: sign also reads as a leading
     minus and a bar direction against a pinned zero; absence also reads as
     a 45° hatch and a literal reason code; ladder basis also reads as
     filled vs hollow marks. */
  --chart-grid:var(--hair);
  --chart-axis:var(--dim);
  --plate:var(--surface3);
  --hatch-ink:var(--line-hi);
}

/* ============================================ ELEMENT FLOOR (P3 findings)
   Three UA defaults that no page overrides and that the DOM audit caught on
   2026-08-15. All three are element selectors in the FIRST sheet, so any rule
   a page already has still wins — these only reach what nothing else claims.

   1. EMPHASIS. <b>/<strong> default to `bolder`, which the UA resolves
      RELATIVE to the parent: inside a 600 label it lands on **900**. That is
      how a tree with almost no literal `font-weight:8xx` still rendered 284
      elements at 800+ across 24 pages. Bold marks a decision or a result, at
      one weight, everywhere.
   2. MONO. <code>/<kbd>/<samp>/<pre> otherwise render in the platform's
      default mono — not a QK face, and not tabular.
   3. LINKS. A link no rule has claimed keeps the UA's #0000EE, which is
      **2.14:1** on --bg. It was live in the playbook disclosure footers on
      six pages. Underline stays: colour must not be the only signal. */
b, strong { font-weight: 700; }
code, kbd, samp, pre { font-family: var(--mono); }
a { color: var(--text); }

/* 4. FORM CONTROLS do not inherit the font. Left alone they render in the
      platform UI face — the audit caught prop-test's primary "Run" button
      rendering in Arial. Family only: size stays with whatever rule owns the
      control, because the UA's 13.333px default is off the ramp either way. */
button, input, select, textarea, optgroup { font-family: inherit; }

/* 5. SUB/SUP carry the UA's `font-size: smaller` — 0.83x of WHATEVER they sit
      in, which landed on 10px, 11.25px, 12.92px and 13.33px on one page alone,
      three of them under the 10.5px floor. One token instead: a subscript is
      the same size wherever it appears, and it is never the smallest thing on
      the page by accident. */
sub, sup { font-size: var(--t-label); }

/* 5b. SMALL and CODE carry the same UA relativity. <small> is `font-size:
       smaller` (0.83x of its parent, landing on 11.25px inside the instrument
       tier), and an unstyled <code> inherits Chrome's separate monospace
       default, which measured 12.15px inside the legal pages' prose. Both are
       named sizes now, so a caption is the same size in every family. */
small { font-size: var(--t-small); }
code, kbd, samp, pre { font-size: var(--t-small); }

/* 6. CANVAS illustrations with a CSS height but no CSS width take their box
      from their own drawing buffer — and qk-motion writes that buffer back at
      devicePixelRatio, so the element grows by the DPR every time it is
      re-fitted. On epm.html it had pushed 170px of a sample chart outside its
      own clipped frame. */
canvas { max-width: 100%; }

/* ------------------------------------------------------------- numerals
   Every DATA numeral is mono and tabular so columns align and a changing
   figure does not reflow its own row. .num is the explicit opt-in; the
   blanket below catches tables and stat readouts, which are numeric by
   construction. font-variant-numeric only changes glyph WIDTH selection —
   it cannot change layout of non-numeric content. */
.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums lining-nums;
}

table, th, td,
.stat .v, .metric .v, .num, output, [data-num] {
  font-variant-numeric: tabular-nums lining-nums;
}

/* ============================================================== CHIPS
   FOUR TYPED FAMILIES, split by SHAPE as well as colour, because they say
   four different things and used to say them all in the same amber pill:
     1. .chip[.safe|.info|.warn|.bad|.unsealed|.plain]  STATUS   (pill)
     2. .chip.absent                                    ABSENCE  (dashed square)
     3. .chip.stale[data-status]                        STALENESS(pill, own scale)
     4. .chip.basis                                     PROVENANCE(mono, low chroma)
   Lifted verbatim from members/ev-calculator.html so the propagation in P2
   is a copy, not a re-derivation. Semantics are fixed by the HANDOFF brief
   (QK_Lab\docs\design\HANDOFF_PROP_TOOLS_STALENESS_AND_ABSENCE_2026-08-14.md):
   staleness follows the EVIDENCE date, never the effective date; a
   publishable=0 field renders .chip.absent IN the cell where the number
   would be, never beside a 0.
   ------------------------------------------------------------------- */
.chip{display:inline-flex;align-items:center;gap:5px;border:1px solid var(--line-hi);
  border-radius:99px;padding:3px 10px;font:600 var(--t-label)/1.5 var(--font);
  letter-spacing:.06em;text-transform:uppercase;color:var(--muted);white-space:nowrap}
.chip.safe{color:var(--up-hi);border-color:#1a6b4d;background:rgba(0,217,154,.07)}
.chip.info{color:var(--info);border-color:#28516f;background:rgba(90,167,255,.08)}
.chip.warn{color:var(--warn);border-color:#6b5220;background:rgba(217,160,60,.08)}
.chip.bad{color:var(--down);border-color:#6e2f33;background:rgba(207,106,110,.08)}
.chip.unsealed{color:var(--violet);border-color:#463571;background:rgba(181,156,255,.07)}
.chip.plain{color:var(--dim)}

/* 2. ABSENCE — deliberately NOT amber and deliberately not filled.
   A filled amber pill reads "something went wrong". An unfilled dashed
   square reads "there is nothing here", which is the truth. The reason
   code is visible TEXT, never hover-only, and it sits in the cell where
   the number would have been. */
.chip.absent{border-radius:2px;border:1px dashed var(--line-hi);background:none;
  color:var(--dim);font-family:var(--mono);font-weight:500;letter-spacing:.05em;
  text-transform:none;padding:2px 7px;font-size:var(--t-code);white-space:normal;
  text-align:left;line-height:1.35}
/* the ∅ is a meaningful glyph, not decoration — it carries the same
   statement as the code beside it, so it holds the same contrast floor */
.chip.absent .glyph{color:var(--dim);font-weight:700}

/* 3. STALENESS — its own scale. Amber is reclaimed for thresholds and
   for this. The day count is always printed. */
.chip.stale{font-family:var(--mono);letter-spacing:.05em;gap:4px}
.chip.stale[data-status="FRESH"]{color:var(--muted);border-color:var(--line);background:none}
.chip.stale[data-status="AGING"]{color:var(--info);border-color:#28516f;background:rgba(90,167,255,.10)}
.chip.stale[data-status="STALE"]{color:var(--warn);border-color:#6b5220;background:rgba(217,160,60,.14)}
.chip.stale[data-status="UNKNOWN"]{color:var(--dim);border-color:var(--line);background:none}
.chip.stale b{font-weight:700}

/* 4. PROVENANCE — what KIND of number this is. Always carries the engine's
   own source string in its title. */
.chip.basis{font-family:var(--mono);font-weight:500;font-size:var(--t-label);
  letter-spacing:.05em;color:var(--dim);border-color:var(--line);background:none;padding:2px 8px}
.chip.basis[data-basis="MEASURED"],.chip.basis[data-basis="QK MEASURED"],
.chip.basis[data-basis="SOLID"]{color:var(--up-hi);border-color:#1a6b4d}
.chip.basis[data-basis="COMPOSED"],.chip.basis[data-basis="MODELLED"]{color:var(--info);border-color:#28516f}
.chip.basis[data-basis="UNSEALED"]{color:var(--violet);border-color:#463571}
/* THIN is styled because the engine can emit it — it does not occur on
   today's payload, and it is never fabricated into a picture. */
.chip.basis[data-basis="THIN"]{color:var(--warn);border-color:#6b5220}
.chip.basis::before{content:"";width:6px;height:6px;border-radius:50%;flex:0 0 auto;
  border:1px solid currentColor}
.chip.basis[data-basis="MEASURED"]::before,
.chip.basis[data-basis="SOLID"]::before,
.chip.basis[data-basis="QK MEASURED"]::before{background:currentColor}
