/* ============================================================================
   FELLOW 2026 — DESIGN TOKENS
   Generated from index.html. Import before your own styles.

     <link rel="stylesheet" href="tokens.css">
     <html data-mode="dark" data-palette="clay">

   TWO AXES, set as attributes on <html>:
     data-mode    = "dark" | "light"                  surfaces + text
     data-palette = "clay" | "amber" | "neutral"      support ramp + glow

   Ember (#ef4633) is CONSTANT across all palettes — it is the one loud action.
   Read DESIGN.md before using these: the rules that make the system work are
   constraints, not values, and several are not recoverable from the hex codes.
   ============================================================================ */

:root{
  /* Brand & accent — THREE ROLES, ONE EACH:
       ember   = ACT      — the single loud action. CTA fills, primary marks, current-state.
       voltage = NOTICE   — highlight washes, soft emphasis. Not a CTA.
       support = NAVIGATE — links, focus rings, data series, the glow.
     If a new colour doesn't fit one of these three roles, it doesn't belong in brand.

     EMBER IS CONSTANT ACROSS ALL PALETTES. Only the SUPPORT ramp and the glow swap.
     Palette is selected with data-palette on <html>: "clay" (default) | "amber" | "neutral".
     Every palette is warm — separation from ember comes from CHROMA and VALUE, not hue,
     so the support ramp is always lower-chroma than ember. See § Palettes below. */
  --accent-ember:#ef4633;           /* PRIMARY accent — the CTA fill */
  --accent-ember-hover:#e73623;
  --accent-ember-press:#d12c1a;
  --accent-ember-ink:#17150f;       /* text/icon ON an ember fill — 4.86:1. White is only 3.76:1 → fails AA */
  --accent-ember-muted:#e08978;     /* desaturated step — data viz, avatars, category coding */
  --accent-ember-tint:color-mix(in srgb,var(--accent-ember) 10%,var(--surface)); /* faint bg wash */
  --accent-ember-soft:color-mix(in srgb,var(--accent-ember) 22%,var(--surface)); /* soft fill / chip bg */
  --accent-voltage:#efd46c;
  --accent-voltage-ink:#17150f;
  /* Support ramp — tint/soft derive from whichever palette is active, so they need no per-palette value.
     -on is #17150f in every palette: white fails AA on clay (4.02) and is unusable on amber/bone. */
  --accent-support-tint:color-mix(in srgb,var(--accent-support) 12%,var(--surface));  /* faint bg wash — selected row, info panel */
  --accent-support-soft:color-mix(in srgb,var(--accent-support) 26%,var(--surface));  /* soft fill / chip bg */
  --accent-support-on:#17150f;                                                        /* text / icon on a support fill */
  --accent-voltage-hover:#eccc50;   /* retained for the highlight ramp — voltage is no longer a button */
  --accent-voltage-press:#e9c435;
  --accent-voltage-soft:color-mix(in srgb,var(--accent-voltage) 18%,var(--surface)); /* soft highlight — reads on dark; pale on paper */
  /* Glow stops — defined per palette below (§ Palettes). */
  /* Tertiary — data viz & category only.
     PRUNED 2026-07: tertiary-coral (#dc8375) removed — it was a desaturated #ef4633, i.e. the ember
     accent by another name. Use --accent-ember-muted instead.
     tertiary-cyan (#00e4f4) removed — a neon that never sat on these warm surfaces and duplicated
     --accent-support-bright. (The labs previously carried a stale pre-mute palette — neon #00e4f4/#fdfc00
     glow + cool grays — and were realigned to these canonical values in the same pass.) */
  --tertiary-green:#6e9a4c;
  /* Semantic
     NOTE: with a red primary accent, red-vs-red is unavoidable. Error is pulled to a cool crimson
     (hue ~351 vs ember's ~6) so the two don't read as the same colour, but colour alone is NOT a
     sufficient error signal here — always pair with the icon + border treatment (see .alert.error). */
  --semantic-success:#22a559;
  --semantic-warning:#fdfc00;
  --semantic-error:#d92d43;
  /* Dashboard subject accents — category coding (blue + tertiary trio + one new amber).
     Surfaced by the Fellow Signal stress test: 4 co-equal categories need 4 accents. */
  --subj-eng:#0c77ce;   /* Engagement → blue */
  --subj-out:var(--accent-ember-muted);   /* Outcomes → muted ember (was the standalone coral hex) */
  --subj-ops:#e0952b;   /* Operations → amber (NEW: dashboard-only, keeps voltage reserved for the CTA) */
  --subj-rec:#6e9a4c;   /* Recognition → green */
  /* Low-chroma tints for the icon badge — mix the accent into the current surface, so they adapt per mode */
  --subj-eng-tint:color-mix(in srgb,var(--subj-eng) 16%,var(--surface));
  --subj-out-tint:color-mix(in srgb,var(--subj-out) 16%,var(--surface));
  --subj-ops-tint:color-mix(in srgb,var(--subj-ops) 16%,var(--surface));
  --subj-rec-tint:color-mix(in srgb,var(--subj-rec) 16%,var(--surface));
  /* Dashboard health — distinct from the voltage CTA (amber ≠ voltage yellow) */
  --dash-good:#22a559;
  --dash-warn:#e0952b;
  --dash-bad:var(--semantic-error);
  --dash-fill:var(--hairline);
  /* Radius */
  --r-xs:4px; --r-sm:6px; --r-md:10px; --r-lg:14px; --r-xl:20px; --r-xxl:28px; --r-pill:9999px; --r-full:9999px;
  /* Spacing */
  --s-xxs:4px; --s-xs:8px; --s-sm:12px; --s-base:16px; --s-md:20px; --s-lg:24px; --s-xl:32px; --s-xxl:48px; --s-xxxl:72px; --s-section:120px;
  /* Fonts */
  /* Licensed Typekit family FIRST (lowercase-hyphenated kit name), then Google substitute (fallback),
     then Thai fallback, then system. Per-glyph fallback: Latin resolves to the Latin face and Thai
     glyphs fall through to the Thai font. */
  --font-display:'itc-avant-garde-gothic-pro','Jost','Bai Jamjuree','Helvetica Neue',Arial,sans-serif;
  --font-body:'scandia-web','Hanken Grotesk','proxima-nova-thai-looped','IBM Plex Sans Thai Looped',system-ui,sans-serif;
  /* Label voice: was monospace (Space Mono) → now geometric Nexa. NOTE: not monospace, so metadata/timestamps are not tabular-aligned. */
  --font-mono:'nexa','Montserrat','IBM Plex Sans Thai Looped',system-ui,sans-serif;
  /* Glow grain. A heavy blur leaves a gradient perfectly smooth, which on a wide, low-contrast
     wash shows as banding — visible stepped rings, worst in light mode where the stops sit close
     together. Fractal noise at low alpha breaks the steps up. It is a fixed 160px tile at screen
     scale, NOT scaled with the glow, so the texture reads the same at any glow size. Desaturated
     (feColorMatrix saturate 0) so it never tints the palette. */
  --glow-grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.22'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)'/%3E%3C/svg%3E");
}
/* ============================================================
   § PALETTES — data-palette on <html>. Ember never changes; the SUPPORT ramp and glow do.
   All three are warm: ember stays the only high-chroma colour, so the CTA is never out-shouted.
   -link / -hover are mode-dependent too, so they resolve further down (§ Palette × mode).
   ============================================================ */
/* A · CLAY (default) — monochrome warm. Terracotta / sand / rust.
   The glow deep+abyss run deliberately dark: clay sits close to ember in hue, so the area
   behind the CTA has to stay low-value or the primary button loses its separation. */
:root,[data-palette="clay"]{
  --accent-support:#c9603f; --accent-support-bright:#d99a72; --accent-support-deep:#8a4a35;
  --glow-edge:#f2a07a; --glow-core:#c9603f; --glow-deep:#7d2f2a; --glow-abyss:#120705;
  --series-1:#f9e2d6; --series-2:#efab8b; --series-3:#d16f4a; --series-4:#9c4a2c; --series-5:#5e2c1f;
  --glow-dim-edge:#8f4430; --glow-dim-core:#5e2a20; --glow-dim-deep:#2e1512;
  --glow-tint-edge:#fff0e4; --glow-tint-core:#ffdcc6; --glow-tint-deep:#ffc0a0;
}
/* B · AMBER — fire palette. Amber / gold / deep rust. The loudest of the three;
   amber is bright enough that it must never be used for an action. */
[data-palette="amber"]{
  --accent-support:#e0952b; --accent-support-bright:#efd46c; --accent-support-deep:#8c3520;
  --glow-edge:#f7b06a; --glow-core:#e0762f; --glow-deep:#8c3520; --glow-abyss:#140906;
  --series-1:#fbeccd; --series-2:#f2ce85; --series-3:#e0952b; --series-4:#a8681a; --series-5:#5e3a0e;
  --glow-dim-edge:#96601c; --glow-dim-core:#5e3a0e; --glow-dim-deep:#2e1c07;
  --glow-tint-edge:#fff7ea; --glow-tint-core:#ffecc9; --glow-tint-deep:#ffd9a3;
}
/* C · NEUTRAL — ember is the ONLY saturated colour. Bone / taupe / stone.
   Maximum subtlety: nothing else carries chroma, so ember cannot be competed with. */
[data-palette="neutral"]{
  --accent-support:#c9bda8; --accent-support-bright:#e8e0d0; --accent-support-deep:#6b6153;
  --glow-edge:#e8a58f; --glow-core:#a86a63; --glow-deep:#4a2f33; --glow-abyss:#120c0d;
  --series-1:#ece4d8; --series-2:#cfc2ad; --series-3:#a89880; --series-4:#786a56; --series-5:#463e32;
  --glow-dim-edge:#6b5148; --glow-dim-core:#40302c; --glow-dim-deep:#1f1614;
  --glow-tint-edge:#f9efe9; --glow-tint-core:#f0e2da; --glow-tint-deep:#e3cdc4;
}

/* Dark mode (default) */
/* ============================================================
   SOFTENED WARM NEUTRALS — paper/cream light, warm charcoal dark.
   Nothing is pure #fff / #000: off-white bg, bone text, soft near-black ink. */
[data-mode="dark"]{
  --canvas:#0f0e0b; --canvas-soft:#15130f;
  --surface:#1a1713; --surface-elevated:#232019; --surface-inverted:#f4f1e8;
  --hairline:rgba(244,241,232,0.10); --hairline-soft:rgba(244,241,232,0.06); --hairline-strong:rgba(244,241,232,0.20);
  --text-primary:#f2efe6; --text-body:#b9b4a7; --text-muted:#847f71; --text-faint:#5c584e;
  --inverted-text:#17150f; --accent-voltage-ink:#17150f;
  --accent-support-link:#d99a72; --accent-support-hover:#e8b18d;   /* clay palette · sand reads on charcoal — 8.10:1 */
  --accent-ember-link:#ef4633; --accent-ember-hover-text:#f46352;  /* ember reads as text on charcoal — 5.14:1 */
  --semantic-error-text:#ef5a6e;                                    /* error text lightens on charcoal — 5.84:1 */
  --glow-opacity:1; --glow-sink:var(--glow-abyss); --shadow-elev:0 8px 30px rgba(0,0,0,0.5);
  --glass-bg:rgba(15,14,11,0.62); --glass-border:rgba(244,241,232,0.10); --glass-highlight:rgba(244,241,232,0.07);
}
[data-mode="light"]{
  --canvas:#f6f4ee; --canvas-soft:#efece3;
  --surface:#fcfbf6; --surface-elevated:#f2efe7; --surface-inverted:#17150f;
  --hairline:#e5e0d4; --hairline-soft:#efebe1; --hairline-strong:#d8d2c4;
  --text-primary:#1b1a16; --text-body:#4c4a42; --text-muted:#837f72; --text-faint:#b0ab9d;
  --inverted-text:#f4f1e8; --accent-voltage-ink:#17150f;
  --accent-support-link:#8a4a35; --accent-support-hover:#6e3826;   /* clay palette · sand is only 2.0:1 on paper → deepen to rust, 6.14:1 */
  --accent-ember-link:#c12715; --accent-ember-hover-text:#a51f10;  /* ember at full chroma is only 3.4:1 on paper → deepen to 5.35:1 */
  --semantic-error-text:#b81e32;                                    /* 5.84:1 on paper */
  --glow-opacity:0.55; --glow-sink:transparent; --shadow-elev:0 8px 24px rgba(60,50,30,0.10);
  --glass-bg:rgba(246,244,238,0.70); --glass-border:rgba(23,21,15,0.08); --glass-highlight:rgba(255,255,255,0.55);
}
/* § Palette × mode — LIGHT-MODE GLOW ("barely-there wash").
   The glow ramp was the one thing in this system that didn't resolve per mode, and that was the bug:
   clay's stops measure L .45/.21/.07 against a canvas at .905, so on paper they read as SHADOW, not
   bloom — and dropping opacity to .55 to soften it stripped the chroma too, giving grey-brown.
   These lifted stops sit just under the canvas with their chroma intact, so they read as tinted light.
   Opacity goes back to 1 in light mode: the colours no longer need muting to stay soft.
   NOTE: --glow-abyss is deliberately NOT overridden. It doubles as the background of the dark
   showcase surfaces (.glow-card, .canvas-tile, .slide, .thumb, .ad, .web-banner, .feature-visual),
   all of which set color:#fff — lightening it would put white text on a pale ground.
   Selectors are doubled (compound + descendant) so the § Palettes doc rows, which carry
   data-palette WITHOUT data-mode, also pick up the light-mode ramp. */
[data-mode="light"]{--glow-opacity:1}
[data-mode="light"][data-palette="clay"],   [data-mode="light"] [data-palette="clay"]{
  --glow-edge:var(--glow-tint-edge); --glow-core:var(--glow-tint-core); --glow-deep:var(--glow-tint-deep);}
[data-mode="light"][data-palette="amber"],  [data-mode="light"] [data-palette="amber"]{
  --glow-edge:var(--glow-tint-edge); --glow-core:var(--glow-tint-core); --glow-deep:var(--glow-tint-deep);}
[data-mode="light"][data-palette="neutral"],[data-mode="light"] [data-palette="neutral"]{
  --glow-edge:var(--glow-tint-edge); --glow-core:var(--glow-tint-core); --glow-deep:var(--glow-tint-deep);}

/* § Palette × mode — link/hover need BOTH axes: a mid-tone warm that reads on charcoal
   is unusable on paper, so each palette carries a deepened light-mode pair.
   Verified against the mode's canvas; all >= 4.5:1. */
[data-mode="dark"][data-palette="amber"]  {--accent-support-link:#e0a03c;--accent-support-hover:#eab35c} /* 8.51:1 */
[data-mode="dark"][data-palette="neutral"]{--accent-support-link:#c9bda8;--accent-support-hover:#ded4c4} /* 10.41:1 */
[data-mode="light"][data-palette="amber"] {--accent-support-link:#8c5a12;--accent-support-hover:#7d4f0f} /* 5.32:1 */
[data-mode="light"][data-palette="neutral"]{--accent-support-link:#5c5346;--accent-support-hover:#4f473c} /* 6.87:1 */
:root{ --glass-blur:18px; }

/* ============================================================
   GLOW BY SURFACE — the rule: glow stops follow the SURFACE they're painted on,
   not the page mode. Three sets per palette:
     --glow-*        page-level, resolves by mode (hero, .newsletter, .glow-tile — they follow the canvas)
     --glow-dim-*    for ALWAYS-DARK surfaces
     --glow-tint-*   for ALWAYS-LIGHT surfaces
   Getting this wrong is what made the slides milky in light mode and the CTA band muddy in dark:
   both take a surface that contradicts the page, so page-mode stops are the wrong ones.
   Overridden at property level (0,2,0+) so these beat .glow regardless of mode or palette. */

/* Always-dark surfaces — painted on --glow-abyss. The normal edge stop (clay #f2a07a, L .454)
   against L .003 is a ~150x jump and blooms into a milky wash, so they take the dim set. */
   NOTE: these set the gradient on .glow::before, not .glow — the blur moved onto that pseudo so
   the grain layer can stay sharp. Overriding `background` on .glow itself would no longer paint. */
.glow-card .glow::before,.feature-visual .glow::before,.canvas-tile .glow::before,.ad .glow::before,
.web-banner .glow::before,.slide .glow::before,.thumb .glow::before,
[data-mode="light"] .cta-band .glow::before{
  background:
    radial-gradient(closest-side at 35% 35%, var(--glow-dim-edge), transparent 70%),
    radial-gradient(closest-side at 55% 50%, var(--glow-dim-core), transparent 75%),
    radial-gradient(closest-side at 60% 65%, var(--glow-dim-deep), transparent 80%);
}
.glow-card .glow,.feature-visual .glow,.canvas-tile .glow,.ad .glow,
.web-banner .glow,.slide .glow,.thumb .glow,
[data-mode="light"] .cta-band .glow{ opacity:1; }
/* .cta-band uses --surface-inverted, so it flips against the page: cream in dark mode,
   charcoal in light. Its glow therefore takes the OPPOSITE set to the page. */
[data-mode="dark"] .cta-band .glow{ opacity:1; }
[data-mode="dark"] .cta-band .glow::before{
  background:
    radial-gradient(closest-side at 35% 35%, var(--glow-tint-edge), transparent 70%),
    radial-gradient(closest-side at 55% 50%, var(--glow-tint-core), transparent 75%),
    radial-gradient(closest-side at 60% 65%, var(--glow-tint-deep), transparent 80%);
}

/* ----------------------------------------------------------------------------
   .glow — the assembled gradient. Give the container position:relative and
   overflow:hidden, then size/position .glow per context. See DESIGN.md § Glow.

   Two layers, because `filter` applies to an element's whole rendered subtree — grain composited
   inside a blurred element is smeared into flat mush:
     ::before  the gradient stack, and the ONLY thing that carries blur(60px)
     ::after   the grain, unblurred, masked to the gradient's own falloff so no noise shows
               past the glow's edge as a square or ring
   ---------------------------------------------------------------------------- */
.glow{
  position:absolute; border-radius:var(--r-full); pointer-events:none;
  opacity:var(--glow-opacity);
}
.glow::before,.glow::after{ content:''; position:absolute; inset:0; border-radius:inherit; }
.glow::before{
  filter:blur(60px);
  background:
    radial-gradient(closest-side at 35% 35%, var(--glow-edge), transparent 70%),
    radial-gradient(closest-side at 55% 50%, var(--glow-core), transparent 75%),
    radial-gradient(closest-side at 60% 65%, var(--glow-deep), transparent 80%),
    radial-gradient(circle at 50% 50%, var(--glow-sink), transparent 90%);
}
.glow::after{
  background-image:var(--glow-grain);
  background-size:160px 160px;
  background-repeat:repeat;
  -webkit-mask-image:radial-gradient(closest-side at 50% 50%, #000 15%, transparent 78%);
  mask-image:radial-gradient(closest-side at 50% 50%, #000 15%, transparent 78%);
}
