/* ==========================================================================
   CYGM design tokens
   --------------------------------------------------------------------------
   Two layers, on purpose.

   PRIMITIVES are raw values with no opinion about what they are for.
   SEMANTICS say what a thing means. Every stylesheet on this site reads from
   the semantic layer only, never from a primitive and never from a literal.

   That split is what makes the look retunable. Changing --accent-1 here
   restyles every border, hover, focus ring and tint on the site, because those
   are derived from it with color-mix() rather than written out by hand.

   The rule that keeps it true: no hex value may appear anywhere in this
   codebase outside this file. Grep for one before shipping. A stray literal is
   not a small mess, it is a value that has silently stopped answering to the
   theme.

   --------------------------------------------------------------------------
   WHAT CHANGED, 2026-09-09 (second pass)

   An achromatic, square, shadowless pass was tried here and rejected. This file
   now carries the original cygm.me design language back verbatim: the navy and
   cyan ramp, 16px card corners, 100px pill buttons, the accent glow, the Outfit
   display face and the spring easing. The specification is the <style> block in
   ../../index.html, which is the live site.

   What survives from the rejected pass, because it is architecture rather than
   look: the two-layer token split below, the theme presets, and the rule that
   no hex value exists outside this file.

   A byte-for-byte copy of the achromatic version is kept beside this file as
   tokens-archive-2026-09-09-instrument.css. It is not loaded by anything.
   ========================================================================== */

@layer reset, tokens, base, layout, components, utilities;

/* The other two families are declared in the document head, which is owned by
   another track. Outfit is added here instead, which costs it the preload the
   other two get. */
@font-face {
  font-family: 'Outfit';
  src: url('/fonts/outfit-var.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@layer tokens {

/* --------------------------------------------------------------------------
   LAYER 1 - PRIMITIVES
   -------------------------------------------------------------------------- */
:root {

  /* Ground. The original CYGM navy ramp. */
  --ink-900: #0a0e17;   /* page */
  --ink-800: #0f1420;   /* section */
  --ink-750: #151b2b;   /* tertiary, table header */
  --ink-700: #141a2a;   /* card */
  --ink-600: #1a2236;   /* card hover, raised */

  /* Foreground ramp, unchanged from the original site. The dimmest step was
     already lifted once for contrast and is left where it was found. */
  --fg-100: #e8ecf4;
  --fg-300: #939db0;
  --fg-500: #7d8ca6;

  /* The accent. Cyan, used as atmosphere as well as signal: it tints the
     hairlines, washes the badges and glows behind the primary action. */
  --accent-1: #00d4ff;
  --accent-2: #00a8cc;

  /* Signal colours. The product's own green, amber and red. These mean glucose
     state and nothing else: never a button, never a border, never a hover.
     Note the red is about 4.3:1 on this ground, so it carries large readings
     and headline figures but must not be used for small body text. */
  --signal-green: #22c55e;
  --signal-amber: #eab308;
  --signal-red:   #ef4444;
  /* The danger callout only: a dark orange edge with a red glow behind it. */
  --signal-orange:   #c2410c;
  --signal-red-deep: #7f1d1d;

  /* Spacing. One 4px-based scale. Every margin, padding and gap is a step on
     it. An arbitrary value is a bug. */
  --step-1: 0.25rem;
  --step-2: 0.5rem;
  --step-3: 0.75rem;
  --step-4: 1rem;
  --step-5: 1.5rem;
  --step-6: 2rem;
  --step-7: 3rem;
  --step-8: 4rem;
  --step-9: 6rem;
  --step-10: 8rem;

  /* Radii. 16px surfaces and a full pill on every button. These two carry more
     of the brand than any single colour here does. */
  --radius-hard: 0;
  --radius-tight: 6px;
  --radius-sm: 10px;
  --radius-soft: 16px;
  --radius-pill: 100px;

  --hairline: 1px;

  /* Type. Three families, matching the original's assignments. Outfit is the
     display face and carries every heading, wordmark and headline figure. DM
     Sans is body and button copy. JetBrains Mono is the voice of labels,
     versions, part references and tabular numbers.
     Outfit is declared here rather than in the document head because the head
     include is owned by another track; see the @font-face block below. */
  --family-display: 'Outfit', 'Outfit fallback', 'DM Sans', system-ui, -apple-system, sans-serif;
  --family-sans: 'DM Sans', 'DM Sans fallback', system-ui, -apple-system, 'Helvetica Neue', Arial, sans-serif;
  --family-mono: 'JetBrains Mono', 'JetBrains Mono fallback', ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, monospace;

  /* Type scale. Every size keeps a rem term so it still answers to a reader's
     own font-size setting, and scales on vi rather than vw so it behaves
     correctly inside a container query. */
  --size-2xs:  clamp(0.6875rem, 0.67rem + 0.09vi, 0.75rem);
  --size-xs:   clamp(0.75rem,   0.72rem + 0.15vi, 0.8125rem);
  --size-sm:   clamp(0.875rem,  0.85rem + 0.15vi, 0.9375rem);
  --size-base: clamp(1rem,      0.96rem + 0.2vi,  1.0625rem);
  --size-lg:   clamp(1.125rem,  1.05rem + 0.4vi,  1.375rem);
  --size-xl:   clamp(1.5rem,    1.3rem  + 1vi,    2rem);
  --size-2xl:  clamp(2rem,      1.6rem  + 2vi,    3rem);
  /* The display face is wider per character than the body face, and the hero
     heading has only a 560px column to live in. This cap is the largest size at
     which "A $40 open-source" still sets on one line there. */
  --size-3xl:  clamp(2.25rem,   1.6rem  + 3.2vi,  3.75rem);

  --leading-tight: 1.08;
  --leading-snug: 1.25;
  --leading-body: 1.6;

  --tracking-label: 0.09em;
  --tracking-tight: -0.015em;

  /* Motion. Two curves. The decelerating one carries anything that travels;
     the spring overshoots slightly and is reserved for buttons, where the
     overshoot is what makes a press read as physical. */
  --dur-fast: 200ms;
  --dur: 300ms;
  --dur-slow: 400ms;
  --dur-reveal: 800ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease: var(--ease-out);
}

/* --------------------------------------------------------------------------
   LAYER 2 - SEMANTICS

   Components read from here and only from here. To retheme the site, repoint
   these. Never edit a component file to change a colour.
   -------------------------------------------------------------------------- */
:root {

  --color-page:         var(--ink-900);
  --color-surface:      var(--ink-700);
  --color-surface-alt:  var(--ink-800);
  --color-surface-tertiary: var(--ink-750);
  --color-surface-high: var(--ink-600);

  --color-text:        var(--fg-100);
  --color-text-muted:  var(--fg-300);
  --color-text-faint:  var(--fg-500);

  --color-accent:     var(--accent-1);
  --color-accent-2:   var(--accent-1);   /* links */
  --color-accent-dim: var(--accent-2);

  /* Everything below is derived, which is the machinery that makes one edit
     above propagate across the site.

     These mixes are in srgb rather than oklab because they stand in for the
     original's literal rgba() values, and oklab shifts the result's hue away
     from what the live site actually renders. */
  --color-border:        color-mix(in srgb, var(--color-text) 6%,   transparent);
  --color-border-strong: color-mix(in srgb, var(--color-accent) 20%, transparent);
  --color-wash:          color-mix(in srgb, var(--color-accent) 8%,  transparent);
  --color-wash-strong:   color-mix(in srgb, var(--color-accent) 18%, transparent);
  --color-surface-hover: var(--ink-600);

  /* The glow. Two strengths: the halo behind a hovered button, the radial bloom
     behind the hero, and the tint inside a badge. */
  --color-glow:        color-mix(in srgb, var(--color-accent) 15%, transparent);
  --color-glow-strong: color-mix(in srgb, var(--color-accent) 30%, transparent);
  --color-hover-veil:  color-mix(in srgb, var(--color-text) 4%, transparent);
  --color-grid:        color-mix(in srgb, var(--color-accent) 3%, transparent);

  --glucose-low:  var(--signal-red);
  --glucose-ok:   var(--signal-green);
  --glucose-high: var(--signal-amber);

  --radius-card:   var(--radius-soft);
  --radius-button: var(--radius-pill);
  --radius-input:  var(--radius-sm);

  --space-section: clamp(4rem, 10vw, 8rem);
  --space-card:    var(--step-5);
  --space-gutter:  var(--step-5);

  --font-display: var(--family-display);
  --font-body: var(--family-sans);
  --font-mono: var(--family-mono);

  /* Measure is capped in characters, not pixels, because the comfortable
     reading width is a function of the type rather than of the viewport. */
  --measure: 68ch;
  --measure-narrow: 56ch;
  --container: 1200px;
  --container-narrow: 780px;

  --focus-ring: 2px solid var(--color-accent);
  --focus-offset: 2px;

  color-scheme: dark;
}

/* --------------------------------------------------------------------------
   THEME PRESETS

   Set data-theme on the html element to switch. These exist because a look has
   to be judged on a real page at real size on a real phone, and switching
   should cost one attribute rather than an edit.

   Every preset repoints the semantic layer only. Structure never changes: the
   radii, the glow treatments and the monospace voice are the same in all of
   them, so a preset whose accent is a warm bone glows bone rather than cyan.

   Signal green, amber and red never change across themes. They mean a glucose
   state, and a meaning that shifts with a theme is not a meaning.
   -------------------------------------------------------------------------- */

/* INSTRUMENT - the achromatic pass from 2026-09-09, kept whole.
   Warm bone on a neutral near-black, with no brand colour at all, so the three
   signal colours are the only saturated things on the page. Hairlines and the
   accent are the same value here, which is what makes it read as a silkscreened
   panel rather than as a product. */
[data-theme='instrument'] {
  --ink-900: #0b0d0f;
  --ink-800: #101315;
  --ink-700: #101315;
  --ink-600: #1f2326;
  --fg-100: #ede7da;
  --fg-300: #a3a7a5;
  --fg-500: #6e7370;
  --ink-750: #16191c;
  --accent-1: #ede7da;
  --accent-2: #aebcc9;
  --color-accent-2: #aebcc9;
  --color-border-strong: color-mix(in srgb, var(--fg-100) 22%, transparent);
  /* A bone accent at the cyan's glow strength washes out to grey fog, so this
     preset glows at roughly half strength. */
  --color-glow:        color-mix(in srgb, var(--accent-1) 7%,  transparent);
  --color-glow-strong: color-mix(in srgb, var(--accent-1) 14%, transparent);
}

/* PHOSPHOR - warm and test-equipment adjacent, with an amber-leaning accent. */
[data-theme='phosphor'] {
  --ink-900: #0a0a0a;
  --ink-800: #121110;
  --ink-700: #161412;
  --ink-600: #242120;
  --fg-100: #f2e9d8;
  --fg-300: #a8a196;
  --fg-500: #736d64;
  --ink-750: #1b1917;
  --accent-1: #c9b98f;
  --accent-2: #8a7f63;
  --color-accent-2: #c9b98f;
}

/* GRAPHITE - the coolest and flattest option, closest to a documentation site.
   Almost no warmth and a steel accent rather than a cyan one. */
[data-theme='graphite'] {
  --ink-900: #0c0e10;
  --ink-800: #131619;
  --ink-700: #1a1e22;
  --ink-600: #232830;
  --fg-100: #e8ebee;
  --fg-300: #9aa2aa;
  --fg-500: #676e75;
  --ink-750: #1e232a;
  --accent-1: #9fb0bf;
  --accent-2: #64727e;
  --color-accent-2: #9fb0bf;
}

/* --------------------------------------------------------------------------
   DENSITY

   The site serves two audiences at once. A parent reading the hero wants air.
   A builder reading a parts table wants the whole table on one screen. Rather
   than settle on one compromise spacing, a section opts into a tier.
   -------------------------------------------------------------------------- */
[data-density='compact'] {
  --space-section: var(--step-7);
  --space-card: var(--step-4);
}

/* --------------------------------------------------------------------------
   Honour the reader's motion setting. Everything that moves on this site is
   decoration, so there is no reduced version worth preserving.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 1ms;
    --dur: 1ms;
    --dur-slow: 1ms;
    --dur-reveal: 1ms;
  }
}

} /* @layer tokens */
