/**
 * File:          assets/css/tokens.css
 * Version:       0.4.0
 * Last Modified: 2026-08-11
 * Changes:       Rebuilt on the "Deep Field" design — dark canvas, cyan/violet
 *                accents, Unbounded + Space Grotesk. Token NAMES are unchanged
 *                so the four interactive demos re-skin without being rewritten.
 */

/* ==========================================================================
   FONTS — self-hosted, subset to latin, SIL OFL 1.1 (licences alongside).
   Unbounded 41KB (wght 200-900) for display, Space Grotesk 18KB (wght 300-700)
   for text. Same-origin: the page still makes zero external requests, which is
   why these are not the Google Fonts <link> the comp used.
   ========================================================================== */

@font-face {
  font-family: 'Unbounded';
  src: url('../fonts/unbounded-latin.woff2') format('woff2-variations');
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'SpaceGrotesk';
  src: url('../fonts/spacegrotesk-latin.woff2') format('woff2-variations');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   COLOUR — "Deep Field"

   The page is a dark canvas with a live WebGL field behind it. Everything in
   the foreground is either near-white text or a translucent panel over that
   field, so the palette is built around ONE question: does this stay readable
   when the scene behind it changes from a nebula to an aurora?

   The answer is the scrim. Panels are not tinted glass for decoration — they
   are an opacity floor that guarantees contrast no matter what the shader is
   doing underneath. --panel is deliberately opaque enough (0.82) that the
   worst-case bright frame still leaves text above AAA.

   60 / 30 / 10
   --------------------------------------------------------------------------
   60%  CANVAS     --void #04050a, and the shader field itself
   30%  STRUCTURE  --panel + --text/--text-2 (near-white on near-black)
   10%  ACCENT     --cyan #00E5FF and --violet #8B5CF6

   CONTRAST LEDGER (measured against the panel floor, not the raw canvas)
   --------------------------------------------------------------------------
   text     #EAF2FF on --void    #04050a   17.9 : 1  AAA
   text     #EAF2FF on panel-min #0A0C16   16.6 : 1  AAA
   text-2   #AEBBD0 on --void    #04050a   10.4 : 1  AAA
   text-2   #AEBBD0 on panel-min #0A0C16    9.7 : 1  AAA
   cyan     #00E5FF on --void    #04050a   12.9 : 1  AAA
   cyan     #00E5FF on panel-min #0A0C16   12.0 : 1  AAA
   void     #04050a on --cyan fill         12.9 : 1  AAA
   violet   #8B5CF6 on --void     4.2 : 1  — NON-TEXT ONLY (numerals, rules)
   violet-t #A78BFA on --void     6.7 : 1  — large text only (>=24px)

   HARD RULES, enforced everywhere:
     --violet is NEVER body-size text. It is a rule, a border, or a big numeral.
       For violet-coloured text at any size, use --violet-text and keep it large.
     --cyan IS legible as text here (12.9:1) — the inverse of the old light
       build, where amber was fill-only. Dark canvas flips which accent can
       carry type.
   ========================================================================== */

:root {
  /* --- 60% canvas ------------------------------------------------------- */
  --void:        #04050a;
  --void-2:      #0a0d1f;   /* radial lift behind the field */
  --panel:       rgba(6, 8, 18, 0.82);
  --panel-min:   #0A0C16;   /* the opaque equivalent — what contrast is measured on */
  --panel-2:     rgba(10, 13, 31, 0.6);

  /* --- 30% structure ---------------------------------------------------- */
  --text:        #EAF2FF;
  --text-2:      #AEBBD0;   /* lifted from the comp's 0.62 alpha, which fell under AAA */
  --hairline:    rgba(0, 229, 255, 0.14);
  --hairline-2:  rgba(234, 242, 255, 0.12);
  --edge:        rgba(139, 92, 246, 0.28);

  /* --- 10% accent ------------------------------------------------------- */
  --cyan:        #00E5FF;
  --cyan-dim:    #00B8CC;
  --violet:      #8B5CF6;   /* non-text: rules, borders, numerals */
  --violet-text: #A78BFA;   /* large text only — 6.7:1 */
  --glow-cyan:   rgba(0, 229, 255, 0.35);
  --glow-violet: rgba(139, 92, 246, 0.35);

  /* --- Compatibility aliases -------------------------------------------- */
  /* The four demo components were written against the previous light system.
     Re-pointing the old names here re-skins all of them for free, which is the
     entire payoff of having used semantic tokens rather than raw hex. */
  --paper:        var(--panel-min);
  --surface:      #10131F;
  --paper-sunk:   #0C0F1A;
  --ink:          var(--text);
  --ink-2:        var(--text-2);
  --rule:         var(--hairline-2);
  --rule-strong:  rgba(174, 187, 208, 0.42);
  --ember:        var(--cyan);      /* interactive text */
  --ember-deep:   #7FF3FF;
  --signal:       var(--cyan);      /* fill; ink-on-cyan measures 12.9:1 */
  --act-ink-bg:   var(--void);
  --ink-2-inv:    var(--text-2);
  --rule-inv:     var(--hairline-2);
  --rule-strong-inv: rgba(174, 187, 208, 0.42);
  --surface-inv:  #10131F;

  /* --- Typography ------------------------------------------------------- */
  --font-display: 'Unbounded', 'Segoe UI', system-ui, sans-serif;
  --font-body:    'SpaceGrotesk', 'Segoe UI', system-ui, sans-serif;
  --font-mono:    ui-monospace, 'SF Mono', 'Cascadia Mono', 'Segoe UI Mono',
                  Menlo, Consolas, monospace;

  --t-display: clamp(2.5rem, 6.6vw, 6rem);
  --t-h1:      clamp(2rem, 4.6vw, 4rem);
  --t-h2:      clamp(1.625rem, 3.2vw, 2.75rem);
  --t-h3:      clamp(1.125rem, 1.6vw, 1.25rem);
  --t-lead:    clamp(1rem, 1.3vw, 1.125rem);
  --t-body:    1rem;
  --t-sm:      0.9375rem;
  --t-meta:    0.75rem;

  --lh-display: 1.02;
  --lh-head:    1.15;
  --lh-body:    1.65;

  --track-display: -0.015em;
  --track-meta:     0.28em;

  /* --- Spacing — 8pt ---------------------------------------------------- */
  --s1: 0.5rem;  --s2: 1rem;   --s3: 1.5rem;  --s4: 2rem;   --s5: 3rem;
  --s6: 4rem;    --s7: 5rem;   --s8: 6.5rem;  --s9: 8rem;

  /* --- Grid ------------------------------------------------------------- */
  --grid-max:    1180px;
  --grid-gutter: var(--s3);
  --grid-margin: clamp(var(--s3), 4vw, 40px);

  /* --- Radii — the comp uses 3-6px; kept tight on purpose --------------- */
  --r-sm: 3px;
  --r-md: 4px;
  --r-lg: 6px;

  /* --- Elevation -------------------------------------------------------- */
  /* On a near-black canvas a drop shadow is invisible, so depth comes from a
     lit edge plus an accent glow — the same reasoning as the previous build,
     different palette. */
  --shadow-1: inset 0 1px 0 rgba(234, 242, 255, 0.06);
  --shadow-2: inset 0 1px 0 rgba(234, 242, 255, 0.09),
              0 0 24px rgba(0, 229, 255, 0.10);
  --edge-inv: inset 0 1px 0 rgba(234, 242, 255, 0.06);

  /* --- Motion ----------------------------------------------------------- */
  --ease:       cubic-bezier(0.2, 0.7, 0.2, 1);
  --dur-fast:   140ms;
  --dur-base:   260ms;
  --dur-reveal: 420ms;
}

/* The page is dark throughout, so the old light/dark inversion no longer marks
   a change of audience. The class is kept as a no-op alias because the demo
   markup still references it; removing it would mean editing four components
   for no visual gain. */
.act--ink { --paper: var(--panel-min); }

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 1ms; --dur-base: 1ms; --dur-reveal: 1ms; }
}

/* === END OF FILE (FILENAME: assets/css/tokens.css) === */
