/* ============================================================
   tokens.css — the ONLY file permitted to contain literal hex.
   A raw hex, px font-size or cubic-bezier() anywhere else is a bug.
   Enforced advisorily by .claude/hooks/guard.ps1 and /design-check.
   ============================================================ */

/* Registering the panel hairline as a typed custom property is what lets a
   single variable drive all four edges AND still transition on hover. An
   unregistered custom property is a token swap, not an animatable value.
   Degrades to an instant swap where @property is unsupported. */
@property --panel-hair {
  syntax: "<color>";
  inherits: true;
  initial-value: transparent;
}

@layer tokens {

  :root {
    color-scheme: dark;

    /* ---------- PEEPO GREEN — the one accent ---------- */
    --peepo-300: #a6cc6c;
    /* link on dark */
    --peepo-500: #74a63a;
    /* PRIMARY ACCENT — 6.8:1 on --surface-0 */
    --peepo-600: #5c8a2c;
    /* hover / pressed */
    --peepo-700: #456a20;
    /* link + focus ring on paper — 5.6:1 */

    /* ---------- MASCOT ART PALETTE ----------
       These are not used by any stylesheet. An SVG file cannot read a custom
       property from the page that embeds it, so the mascot exports carry
       these values literally. They live here because this file is the single
       place anyone will look for "what green is the frog", and a value that
       exists in ten SVGs and nowhere else is a value that drifts.
         --peepo-mascot   body fill
         --peepo-belly    belly and highlight
         --peepo-shadow   shading, never a gradient
       Changing one of these means re-exporting img/bog-*.svg. */
    --peepo-mascot: #8cbb4a;
    --peepo-belly: #c2dc97;
    --peepo-shadow: #2f4a16;

    /* ---------- SURFACES (warm graphite, NEVER blue-black, never #000) ----
       If someone "cleans this up" to a neutral black the entire identity
       greys out. The green shift is the point. ---------------------------- */
    --surface-0: #0b0c0a;
    --surface-1: #121411;
    --surface-2: #191c17;
    --surface-3: #212520;

    /* ---------- BONE (warm; #FFFFFF is banned site-wide) ---------- */
    --bone-0: #f2f0e6;
    /* 17.2:1 on --surface-0 */
    --bone-200: #a8a69b;
    /*  8.0:1 */
    --bone-300: #807f76;
    /*  4.9:1 */

    /* ---------- HAIRLINES = the entire elevation system ---------- */
    --hair-1: rgba(242, 240, 230, 0.09);
    --hair-2: rgba(242, 240, 230, 0.16);
    --hair-3: rgba(242, 240, 230, 0.30);
    --hair-accent: rgba(140, 187, 74, 0.45);

    /* ---------- SIGNAL — four DISTINCT hues, <=14px, <1% coverage ---------- */
    --sig-live: #e4572e;
    /* ERROR / 404 / LIVE. Max ONE per page. */
    --sig-work: #e0a32e;
    /* IN DEVELOPMENT / WIP */
    --sig-done: #3f8f63;
    /* RELEASED — deliberately NOT --peepo-500, or a
                                 shipped chip reads as interactive */
    --sig-idle: #6e7b84;
    /* ARCHIVED / PROTOTYPE / VACANT — cool, so it
                                 is not confusable with --bone-300 */

    /* signal-on-paper variants — all clear 4.5:1 on --paper-0 */
    --sig-live-ink: #a82e10;
    --sig-work-ink: #8a5b00;
    --sig-done-ink: #2a6644;
    --sig-idle-ink: #4a5760;

    /* ---------- PAPER (document surface) ---------- */
    --paper-0: #f4f2e9;
    --paper-1: #e9e6da;
    --paper-2: #dcd8ca;
    --paper-3: #cbc7b6;
    --ink-0: #14160f;
    --ink-100: #33362c;
    --ink-200: #5e6157;
    --hair-l1: rgba(20, 22, 15, 0.14);
    --hair-l2: rgba(20, 22, 15, 0.24);

    /* ---------- SEMANTIC ALIASES — components read ONLY these ---------- */
    --bg: var(--surface-0);
    --bg-1: var(--surface-1);
    --bg-2: var(--surface-2);
    --bg-3: var(--surface-3);
    --fg: var(--bone-0);
    --fg-2: var(--bone-200);
    --fg-3: var(--bone-300);
    --hair: var(--hair-1);
    --hair-strong: var(--hair-2);
    --hair-hot: var(--hair-3);
    --link: var(--peepo-300);
    --accent: var(--peepo-500);
    --accent-fg: var(--surface-0);
    /* label on accent fill. NEVER white. */
    --focus: var(--peepo-500);
    /* separate token — swaps on paper */
    --live: var(--sig-live);
    --work: var(--sig-work);
    --done: var(--sig-done);
    --idle: var(--sig-idle);

    /* ---------- TYPE SCALE ---------- */
    --t-micro: clamp(0.75rem, 0.72rem + 0.12vw, 0.8125rem);
    /* 12->13, prose floor */
    --t-code: 0.6875rem;
    /* 11px, emote codes only */
    --t-meta: clamp(0.6875rem, 0.65rem + 0.18vw, 0.8125rem);
    /* 11->13 */
    --t-label: clamp(0.75rem, 0.71rem + 0.20vw, 0.875rem);
    /* 12->14 */
    --t-body: clamp(1rem, 0.96rem + 0.20vw, 1.125rem);
    /* 16->18 */
    --t-lede: clamp(1.125rem, 1.05rem + 0.36vw, 1.375rem);
    /* 18->22 */
    --t-h3: clamp(1.25rem, 1.13rem + 0.60vw, 1.75rem);
    /* 20->28 */
    --t-h2: clamp(1.75rem, 1.40rem + 1.75vw, 3rem);
    /* 28->48 */
    --t-h1: clamp(2.25rem, 1.70rem + 2.75vw, 5rem);
    /* 36->80 */
    --t-hero: clamp(2.25rem, 1.10rem + 5.75vw, 8.5rem);
    /* 36->136 */
    --t-numeral: clamp(2.75rem, 1.90rem + 4.25vw, 7rem);
    /* 44->112 */

    /* ---------- TRACKING (bimodal — no middle ground) ----------
       Display negative, chrome positive, body zero. Archivo Expanded at
       -0.025em sitting directly above Martian Mono caps at +0.14em IS the
       typographic signature. Nothing else is needed. -------------------- */
    --ls-hero: -0.025em;
    --ls-h1: -0.02em;
    --ls-h2: -0.015em;
    --ls-h3: -0.01em;
    --ls-body: 0;
    --ls-label: 0.10em;
    --ls-meta: 0.10em;
    --ls-micro: 0.14em;

    /* ---------- SPACING: 4px base, INSIDE components only ---------- */
    --s-1: 4px;
    --s-2: 8px;
    --s-3: 12px;
    --s-4: 16px;
    --s-5: 24px;
    --s-6: 32px;
    --s-7: 48px;
    --s-8: 64px;
    --s-9: 96px;

    /* ---------- SECTION RHYTHM — governs the page ---------- */
    --pad-section: clamp(4.5rem, 8vw, 12rem);
    /*  72 -> 192 */
    --pad-section-sm: clamp(3rem, 6vw, 6rem);
    /*  48 ->  96 */
    --pad-bleed: 0;
    /* media touches its neighbours */
    --gap-block: clamp(0.75rem, 1.2vw, 1.75rem);
    /*  12 ->  28 */
    --gap-grid: clamp(1rem, 1.6vw, 1.5rem);
    /*  16 ->  24 */
    --gutter: clamp(1rem, 4vw, 2.5rem);
    /*  16 ->  40 */
    /* DESKTOP RATIO 192:28 ~= 6.9:1. THIS RATIO *IS* THE RESTRAINT.
       Templated sites run ~2:1. Do not "tighten" it. */

    /* ---------- CONTAINERS ---------- */
    --w-tight: 46ch;
    --w-text: 64ch;
    --w-container: 1440px;

    /* ---------- CHROME GEOMETRY ---------- */
    --frame-inset: clamp(8px, 1.4vw, 24px);
    --h-header: 64px;
    --h-ticker: 28px;
    --h-hero: 88svh;
    /* 76svh below 768px — svh/dvh ONLY, never vh */

    /* ---------- RADII (two exceptions, total) ---------- */
    --r-0: 0;
    --r-pill: 999px;
    /* ONLY the 6px status dot + icon hit-areas */

    /* ---------- BORDERS ---------- */
    --bd: 1px solid var(--hair);
    --bd-strong: 1px solid var(--hair-strong);
    --tick: 8px;
    /* corner tick arm length */

    /* ---------- SHADOWS — the complete list ---------- */
    --inset-top: inset 0 1px 0 rgba(242, 240, 230, 0.05);
    --bloom-live: 0 0 12px -2px rgba(228, 87, 46, 0.55);

    /* ---------- SCRIMS & MASKS ----------
       The solidified header. No backdrop-filter: at 0.92 alpha the blur is
       invisible and it would pin a compositor layer for the page's life. */
    --scrim-header: rgba(11, 12, 10, 0.92);
    --scrim-modal: rgba(11, 12, 10, 0.94);
    --scrim-art: linear-gradient(to top, rgba(11, 12, 10, 0.92), rgba(11, 12, 10, 0));
    /* Opaque stop for mask-image gradients. Never used as a visible colour. */
    --mask-solid: #000;

    /* ---------- MOTION ---------- */
    --ease-out-hud: cubic-bezier(0.16, 1, 0.30, 1);
    --ease-inout-mech: cubic-bezier(0.85, 0, 0.15, 1);
    --ease-out-quick: cubic-bezier(0.33, 1, 0.68, 1);
    --ease-frog: cubic-bezier(0.34, 1.35, 0.50, 1);
    /* [data-mascot] ONLY */
    --dur-1: 120ms;
    --dur-2: 200ms;
    --dur-3: 320ms;
    --dur-4: 480ms;
    --dur-5: 720ms;
    --dur-frog: 380ms;
    /* The 70ms stagger step is written by reveal.js, which cannot read a
       custom property cheaply, so it is a constant there rather than a dead
       token here. Keep the two in sync. */

    /* ---------- Z-INDEX ---------- */
    --z-raised: 10;
    --z-header: 40;
    --z-ticker: 41;
    --z-hud: 60;
    /* pointer-events: none */
    --z-tray: 61;
    /* the frog only */
    --z-sheet: 80;
    --z-modal: 90;
    --z-skiplink: 100;

    /* ---------- NOISE — one layer, ~600 bytes, the cheapest production
       value in existence. It is what makes phone photography, commissioned
       vector and screenshots cohere. ----------------------------------- */
    --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
  }

  /* ---------- DOCUMENT SURFACE — section-scoped, not route-scoped ---------- */
  [data-surface="document"] {
    color-scheme: light;
    --bg: var(--paper-0);
    --bg-1: var(--paper-1);
    --bg-2: var(--paper-2);
    --bg-3: var(--paper-3);
    --fg: var(--ink-0);
    --fg-2: var(--ink-100);
    --fg-3: var(--ink-200);
    --hair: var(--hair-l1);
    --hair-strong: var(--hair-l2);
    --hair-hot: var(--hair-l2);
    --link: var(--peepo-700);
    /* Fill AND focus ring must clear 3:1 on paper. --peepo-500 on --paper-0
       is 2.58:1, which fails WCAG 2.4.13 / 1.4.11. */
    --accent: var(--peepo-700);
    --accent-fg: var(--paper-0);
    --focus: var(--peepo-700);
    --live: var(--sig-live-ink);
    --work: var(--sig-work-ink);
    --done: var(--sig-done-ink);
    --idle: var(--sig-idle-ink);
    --scrim-header: rgba(244, 242, 233, 0.92);
    --scrim-art: linear-gradient(to top, rgba(244, 242, 233, 0.92), rgba(244, 242, 233, 0));
  }

  /* ---------- HIGH CONTRAST ----------
     Hairlines carry component state (rest -> hover), and a state indicator
     must clear 3:1. Lighthouse does not test WCAG 1.4.11, so this branch is
     the gate, not the audit score. -------------------------------------- */
  @media (prefers-contrast: more) {
    :root {
      --hair-1: rgba(242, 240, 230, 0.34);
      --hair-2: rgba(242, 240, 230, 0.52);
      --hair-3: rgba(242, 240, 230, 0.78);
    }

    [data-surface="document"] {
      --hair-l1: rgba(20, 22, 15, 0.40);
      --hair-l2: rgba(20, 22, 15, 0.62);
    }
  }

  /* ---------- FORCED COLORS ----------
     No forced-color-adjust: none anywhere. Opting elements out would
     preserve the authored (now invisible) hairlines, which is the exact
     opposite of the intent. Remapping the tokens is the whole fix. ------ */
  @media (forced-colors: active) {
    :root {
      --hair: CanvasText;
      --hair-strong: CanvasText;
      --hair-hot: Highlight;
      --hair-accent: Highlight;
    }
  }
}
