/**
 * Brand derivation engine.
 *
 * Contract: a preset (neon.css, light.css, ...) writes ONLY --seed-* tokens.
 * This file derives everything else from them. Every component stylesheet
 * under css/ (outside this directory) references tier-3 semantic roles below
 * and nothing above them - never a --seed-* or --brand-* token directly, and
 * never a raw colour literal. scripts/sweep-check.mjs (`make check`) enforces
 * the "no literal outside css/brand/" half of that; the "preset writes only
 * seeds" half is convention, same as the framework this was trimmed from.
 *
 * If a component needs a colour the roles below don't cover, add a role
 * here - do not reach for a literal or a --brand-* reference in the component.
 *
 * Load order against a preset does not matter: the two never declare the same
 * property name, so there's nothing to win a specificity fight over.
 */
:root {
  /* ---- Tier 2: derived. Never hand-edited, never written by a preset. ---- */
  --brand-1: var(--seed-1, oklch(78% 0.19 var(--seed-hue, 152)));
  --brand-2: var(--seed-2, oklch(from var(--brand-1) l c calc(h + 60)));
  --brand-3: var(--seed-3, oklch(from var(--brand-1) calc(l - 0.06) c calc(h - 60)));

  --brand-1-edge: color-mix(in oklab, var(--brand-1), transparent 55%);
  --brand-1-ring: color-mix(in oklab, var(--brand-1), transparent 75%);
  --brand-1-cast: color-mix(in oklab, var(--brand-1), transparent 65%);
  --brand-1-glow: color-mix(in oklab, var(--brand-1), transparent 65%);
  --on-brand-1:   oklch(from var(--brand-1) clamp(0, (0.62 - l) * 999, 1) 0 0);

  --brand-2-edge: color-mix(in oklab, var(--brand-2), transparent 55%);
  --brand-2-ring: color-mix(in oklab, var(--brand-2), transparent 75%);
  --brand-2-cast: color-mix(in oklab, var(--brand-2), transparent 65%);
  --brand-2-glow: color-mix(in oklab, var(--brand-2), transparent 65%);
  --on-brand-2:   oklch(from var(--brand-2) clamp(0, (0.62 - l) * 999, 1) 0 0);

  --brand-3-edge: color-mix(in oklab, var(--brand-3), transparent 55%);
  --brand-3-ring: color-mix(in oklab, var(--brand-3), transparent 75%);
  --brand-3-cast: color-mix(in oklab, var(--brand-3), transparent 65%);
  --brand-3-glow: color-mix(in oklab, var(--brand-3), transparent 65%);
  --on-brand-3:   oklch(from var(--brand-3) clamp(0, (0.62 - l) * 999, 1) 0 0);

  --bg: var(--seed-bg, #05070a);
  --fg: var(--seed-fg, oklch(from var(--bg) clamp(0, (0.5 - l) * 999, 1) 0 0));

  /* ---- Tier 3: semantic roles. The only names components may reference. ---- */
  --ground:     var(--bg);
  --text:       var(--fg);
  --text-muted: var(--seed-text-muted, color-mix(in oklab, var(--fg), var(--bg) 32%));
  --surface:    var(--seed-surface, color-mix(in oklab, var(--bg), var(--fg) 6%));
  --surface-glass: var(--seed-surface-glass,
                     color-mix(in srgb, var(--surface), transparent 28%));

  --accent-key: var(--brand-1);
  --accent-alt: var(--brand-2);
  --on-accent:  var(--on-brand-1);
  --glow:       var(--brand-1-glow);

  /* Accent at three fixed strengths - components name a strength, they never
     compute a mix themselves. */
  --accent-border: var(--brand-1-edge);
  --accent-ring:   var(--brand-1-ring);
  --accent-cast:   var(--brand-1-cast);

  /* Neutral hairline, from --fg not the accent: a mostly-transparent
     accent-derived stroke is invisible on a light ground. */
  --stroke:   var(--seed-stroke, color-mix(in oklab, var(--fg), transparent 86%));
  --stroke-w: var(--seed-stroke-w, 1px);

  /* Halo behind headings, from the ground so it inverts: a black halo behind
     dark text on a light deck is worse than no halo. */
  --text-halo: color-mix(in oklab, var(--bg), transparent 45%);
  --track:     color-mix(in oklab, var(--fg), transparent 94%);

  /* A faint accent wash (table headers) and a faint neutral stripe (zebra
     rows) - named here, at fixed strengths, so a component never mixes a
     colour itself. */
  --surface-accent-wash: color-mix(in oklab, var(--accent-key), transparent 90%);
  --surface-stripe:      color-mix(in oklab, var(--fg), transparent 96%);

  /* Red for the story being thrown off (the Negative story beat). Seeded per
     preset: one red can't be bright enough on the dark ground and still read
     on the light one. */
  --negative: var(--seed-negative, oklch(64% 0.21 20));
  /* Orange for the idea beat - warm, so it stays apart from the red, green
     and cyan beats beside it. Seeded per preset for the same reason. */
  --idea:     var(--seed-idea, oklch(72% 0.17 50));

  --code-keyword: var(--brand-2);
  --code-string:  var(--brand-1);
  --code-comment: var(--text-muted);
  --code-title:   var(--text);
  --code-attr:    var(--brand-3);

  /* Generated stand-in for full-bleed media, until you swap in a real image.
     A role rather than a literal in css/layouts/full-bleed.css because it
     mixes colours, and because deriving it here is what makes it follow a
     brand switch. */
  --plate-image: linear-gradient(135deg,
    color-mix(in oklab, var(--brand-1), var(--bg) 55%) 0%,
    color-mix(in oklab, var(--brand-2), var(--bg) 70%) 55%,
    var(--bg) 100%);

  /* Duotone wash for data-img="duotone" (css/image-treatments.css). A role
     rather than a literal gradient in that file because it mixes two brand
     ramps into one value, which is colour composition a component may not do,
     and because deriving it here is what makes a treated image follow a
     preset switch instead of staying pinned to whichever hues were live when
     it was written. */
  --duotone-wash: linear-gradient(160deg, var(--brand-1), var(--brand-3));

  /* Veil for an image that has to sit UNDER text (data-img="wash"). Derived
     from --ground so it inverts with the brand, but TRANSPARENT where
     --ground is opaque: an opaque wash at mix-blend-mode: normal covers the
     picture completely rather than veiling it, which renders the tile as an
     empty rectangle the exact colour of the slide behind it. Flat rather than
     a radial falloff, because it covers one tile and a gradient across a
     small tile reads as a rendering fault rather than as depth. */
  --img-veil: color-mix(in oklab, var(--ground), transparent 45%);

  /* Backdrop behind a modal/overlay (css/card-detail.css) - dark enough to
     read as "behind" the panel regardless of preset, derived from --ground
     rather than a flat black so it inverts on a light brand. */
  --scrim: color-mix(in oklab, var(--ground), transparent 25%);

  --radius:       var(--seed-radius, 14px);
  --font-display: var(--seed-font-display, ui-sans-serif, system-ui, "Segoe UI", Roboto, sans-serif);
  --font-mono:    var(--seed-font-mono, ui-monospace, "JetBrains Mono", "SF Mono", Menlo, monospace);
}

/* Per-slide/section accent override: put data-brand="2" or "3" on a
   <section> whose own subject makes a different accent meaningful (e.g. a
   slide about the thing your brand-2 colour represents). Not for variety -
   if you're reaching for this to "mix it up", don't; pick one accent and
   keep it. */
[data-brand="1"] {
  --accent-key:    var(--brand-1);
  --accent-alt:    var(--brand-2);
  --on-accent:     var(--on-brand-1);
  --glow:          var(--brand-1-glow);
  --accent-border: var(--brand-1-edge);
  --accent-ring:   var(--brand-1-ring);
  --accent-cast:   var(--brand-1-cast);
}
[data-brand="2"] {
  --accent-key:    var(--brand-2);
  --accent-alt:    var(--brand-3);
  --on-accent:     var(--on-brand-2);
  --glow:          var(--brand-2-glow);
  --accent-border: var(--brand-2-edge);
  --accent-ring:   var(--brand-2-ring);
  --accent-cast:   var(--brand-2-cast);
}
[data-brand="3"] {
  --accent-key:    var(--brand-3);
  --accent-alt:    var(--brand-1);
  --on-accent:     var(--on-brand-3);
  --glow:          var(--brand-3-glow);
  --accent-border: var(--brand-3-edge);
  --accent-ring:   var(--brand-3-ring);
  --accent-cast:   var(--brand-3-cast);
}
