/* ============================================
   felt.md — Design tokens
   The single source of truth for colour, type, space, line, motion.
   style.css holds rules only, and reads every value from here.
   Load this file before style.css.
   ============================================ */

:root {
  /* ============ Palette — Norfair (default) ============
     Every text colour is tuned to an APCA (SAPC) lightness-contrast target
     against --bg-main, not to a WCAG 2 ratio: WCAG 2 badly overestimates
     contrast for light-on-dark, which is how the old palette shipped
     --text-dim at Lc 20 (invisible). Targets used:
       Lc 90+  body text at 16px/400        -> --text, --text-bright
       Lc 68   small secondary / mono meta  -> --text-dim, --cyan-mid
       Lc 60   dim links, dates, prefixes   -> --accent-dim, --green-dim
     check-contrast.py asserts these against the tokens below, so a palette
     edit here is checked by `python3 check-contrast.py`.

     The backgrounds are lifted off near-black on purpose. Pure black under
     bright text causes halation (the glow/smear around glyphs) which hits
     astigmatic readers hardest. */
  --bg-deep: #0a0e18;
  --bg-main: #0e1320;
  --bg-panel: #121828;
  --bg-panel-hover: #182036;
  --bg-sunken: #0c111d;
  --bg-raised: #161d2e;
  --cyan: #00e5ff;
  --cyan-mid: #49d1df;
  --cyan-dim: #3ea9bb;
  --teal: #00bcd4;
  --teal-rgb: 0 188 212;
  --green: #00ff41;
  --green-dim: #44c974;
  --orange: #ff6d00;
  --orange-rgb: 255 109 0;
  --orange-light: #ff9100;
  --orange-light-rgb: 255 145 0;
  --orange-glow: #f5a439;
  --red: #f55;
  --steel: #9fb4cc;
  --gold: #ffc24b;
  --gold-rgb: 255 194 75;

  /* Text */
  --text: #e2e8f3;
  --text-dim: #b7c1d1;
  --text-bright: #f0f4ff;

  /* Scrims: translucent panel and overlay backdrops, darker than --bg-deep so
     content sits clearly on top of the atmosphere layers. */
  --scrim: rgb(3 8 15 / 72%);
  --scrim-strong: rgb(8 13 23 / 92%);
  --scrim-full: rgb(4 6 11 / 96%);
  --scrim-panel: rgb(10 15 30 / 80%);        /* tail of a panel gradient */
  --scrim-panel-deep: rgb(10 15 30 / 85%);
  --scrim-panel-hover: rgb(14 21 40 / 80%);

  /* Planet identity colours. Used outside their own page scope too, by the
     map overlay and the planet indicators, so they live at the root. */
  --brinstar: #39ff14;
  --brinstar-rgb: 57 255 20;
  --tourian: #5a5a7a;
  --tourian-rgb: 90 90 122;

  /* Third-party brand colours. Fixed by their owners, never themed. */
  --brand-telegram: #2aabee;
  --brand-telegram-rgb: 42 171 238;
  --brand-signal: #3a76f0;
  --brand-signal-rgb: 58 118 240;

  /* Planet orbs on the map: a four-stop sphere ramp each, lit from 30%/30%.
     Artwork, not UI colour, which is why they do not reduce to the accent. */
  --orb-norfair: radial-gradient(circle at 30% 30%, #ffb74d, #ff6d00 35%, #bf360c 65%, #4a1500);
  --orb-brinstar: radial-gradient(circle at 30% 30%, #81c784, #39ff14 35%, #1b5e20 65%, #0a2e0a);
  --orb-tourian: radial-gradient(circle at 30% 30%, #616161, #424242 40%, #212121 70%, #0a0a0a);

  /* ============ Planet accent (overridden per page) ============ */
  --accent: var(--cyan);
  --accent-dim: var(--cyan-dim);
  --accent-mid: var(--cyan-mid);
  --accent-rgb: 0 229 255;

  /* ============ Lines, washes, glows ============
     Borders and panel tints are written inline as
     `rgb(var(--accent-rgb) / N%)`, so a planet theme retints the whole site
     by setting --accent-rgb alone. Only the weights that repeat get a name. */
  --line: rgb(var(--accent-rgb) / 18%);
  --line-locked: #2a2a3a;              /* reads as disabled: the locked map cell */

  /* Neutral washes, for lifts that must not take the planet tint. */
  --wash-1: rgb(255 255 255 / 3%);
  --wash-2: rgb(255 255 255 / 10%);
  --wash-3: rgb(255 255 255 / 15%);
  --sheen: rgb(255 255 255 / 2%);      /* the diagonal sweep across a panel */

  /* Glows */
  --glow-orange: 0 0 25px rgb(var(--orange-rgb) / 25%);

  /* ============ Type ============
     Chakra Petch stays on headers and short display strings, where its
     squared techno shapes are the point. Body text is Inter: larger
     x-height, open apertures and unambiguous l/I/1, which is what carries a
     paragraph at small sizes. */
  --font-pixel: "Press Start 2P", monospace;
  --font-display: "Chakra Petch", sans-serif;
  --font-body: inter, system-ui, sans-serif;
  --font-mono: "JetBrains Mono", "Fira Code", monospace;

  /* Eight steps, ~1.12 ratio. Every font-size in the site is one of these.
     3xs..2xs are mono labels and tags, xs..md carry prose, lg..xl are
     sub-headings, display is the locked-zone glyph. */
  --fs-3xs: 0.55rem;
  --fs-2xs: 0.65rem;
  --fs-xs: 0.75rem;
  --fs-sm: 0.85rem;
  --fs-md: 0.95rem;
  --fs-lg: 1.05rem;
  --fs-xl: 1.15rem;
  --fs-display: 3rem;

  /* Tracking. Small mono type is set wide on purpose: it reads as instrument
     labelling and it stops the uppercase runs from clotting. */
  --track-tight: 0.04em;
  --track: 0.08em;
  --track-wide: 0.12em;
  --track-wider: 0.15em;
  --track-widest: 0.2em;
  --track-display: 0.3em;   /* one step past widest: map header only */

  /* ============ Space ============
     Eight steps, ratio φ (1.618), base 1rem. The old scale was a linear
     0.25rem grid, which is the trap: perceived distance is not linear. At
     the small end a linear grid gives you 4/8/12/16, four values that read
     as one; at the large end it gives you 40/48/56, three values that read
     as one. An exponential ladder spends its steps where the eye can still
     tell them apart, so every step is a visible decision.

     Nothing outside this block picks a spacing value. Rules pick a
     RELATIONSHIP from the ladder below, and the relationship carries the
     number. `python3 check-spacing.py` fails the build if a rule writes a
     length instead.

     The eye reads distance as meaning: two things close together belong to
     each other, two things apart do not. So the name of a gap is the
     relationship it declares, not its size. Pick the rung that describes
     the tie, and take the number it comes with.

       bonded    two halves of one atom      a stat's value and its label
       tight     a label and what it labels  a list header and its list
       close     lines inside one block      paragraph to paragraph
       related   blocks inside one unit      prose to the stat row under it
       unit      one unit to the next        a heading to the group it opens
       group     one group to the next       card to card, block to block
       zone      one zone of a page to next  a section's inner padding
       page      the page's outer rhythm     the band around a section

     A gap is declared ONCE, by the dominant element of the pair: below a
     heading, never above the body it introduces; below a block, never above
     the label that trails it. Two owners means the rendered gap is
     max(a, b) through margin collapse, which is a number no one wrote. */
  --gap-bonded: 0.236rem;    /* φ⁻³ · 3.8px  */
  --gap-tight: 0.382rem;     /* φ⁻² · 6.1px  */
  --gap-close: 0.618rem;     /* φ⁻¹ · 9.9px  */
  --gap-related: 1rem;       /* 1    · 16px   */
  --gap-unit: 1.618rem;      /* φ    · 25.9px */
  --gap-group: 2.618rem;     /* φ²   · 41.9px */
  --gap-zone: 4.236rem;      /* φ³   · 67.8px */
  --gap-page: 6.854rem;      /* φ⁴   · 110px  */

  /* Optical correction lives in style.css, as one text-box rule. It needs
     no token: text-box reads the font's own cap height and baseline, so the
     correction is exact per font and per size instead of a tuned constant.
     The reason it belongs here anyway is that it is what makes the ladder
     above true — without it every gap silently carries about 0.7em of
     leading on top of the value it names. */

  /* ============ Shape ============ */
  --radius-sharp: 1px;
  --radius: 2px;
  --radius-md: 4px;
  --radius-lg: 6px;
  --radius-round: 50%;

  /* ============ Motion ============
     --ease is the standard decelerating curve; everything that travels a
     distance uses it. Durations step 0.2 / 0.35 / 0.7. */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 0.2s;
  --dur: 0.35s;
  --dur-slow: 0.7s;

  /* ============ Layout ============ */
  --section-max: 880px;
  --border-color: var(--line);
}

/* --- Brinstar palette --- */
.planet-brinstar {
  --accent: var(--brinstar);
  --accent-dim: #61c758;
  --accent-mid: #6bd75d;
  --accent-rgb: var(--brinstar-rgb);
  --bg-panel: #0d1810;
  --bg-panel-hover: #142418;
}

/* --- Tourian palette --- */
.planet-tourian {
  --accent: #d3d3df;
  --accent-dim: #adadc1;
  --accent-mid: #bfbfd0;
  --accent-rgb: 211 211 223;
}
