/* eski design tokens — the source of truth is the eski-style skill.
   Values here are ported verbatim from that skill (§1). Do not invent tokens;
   if a value is wrong, fix it in the skill and re-port so the two never drift. */

/* Jost (variable, weights 100-900) as a real binary woff2 — NOT the base64 @import this used to
   be (docs/design/_fonts.css, still the source for the design docs/gallery, which don't ship to
   users and stay on the base64 copy). @import serialized the request behind tokens.css's own
   download before the font was even discovered, and base64 runs ~33% larger than the binary on
   the wire; OPTIMIZATION.md §1.3. index.html preloads this same file, and font-display:swap here
   means the fallback font paints immediately and swaps in once Jost lands — never invisible text. */
@font-face{font-family:'Jost';src:url('fonts/jost-variable.woff2') format('woff2');font-weight:100 900;font-style:normal;font-display:swap}

/* Gnomon (indestructible-type, OFL), subset to 'eski!' glyphs only — 2.5KB, so it's kept inline as
   base64 rather than a separate binary file (an extra request would cost more than this saves,
   and it's the loading-screen wordmark: it needs to be available the instant tokens.css itself is,
   with no second round trip). REGRESSION FIX (2026-09-01, owner: "the eski loading logo isn't in
   gnomon anymore"): --font-wordmark referenced 'Gnomon' but nothing ever @font-face'd it in this
   file — the app used to get it for free via docs/design/_fonts.css's base64 @import (which also
   carried this same stub), and that @import was removed when Jost became a direct binary reference
   above without checking whether anything ELSE was riding along on the same import. */
@font-face{font-family:'Gnomon';font-style:normal;font-weight:100 900;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}

/* --- LIGHT (the complete palette lives on bare :root) --------------------- */
:root{
  /* planes: paper -> surface -> plate -> paper1, four background steps */
  --paper:#FCFCFC; --surface:#EFEFEF; --plate:#E1E1E1; --paper1:#D7D7D7;
  --ink:#131313; --soft:#363636; --muted:#5C5C5C;
  --line:#CFCFCF; --line2:#B0B0B0;
  --on-ink:#FCFCFC; --tagbg:#DCDCDC; --danger:#C63A28; --railbg:#E4E4E4;
  /* the one sanctioned non-mono accent: a gold star (starred files). Reads on both
     themes, so it is defined once here and not swapped in the dark block. */
  --star:#E0A92A;

  /* Member identity hues (server-scoped; never on public profile/Feed).
     30 perceptually-even hues — baked from the gallery's authoritative OKLCH
     generator: H=(i*12+25)°, light L=0.585 C=0.125. The gallery computes these
     live in JS; the app bakes the same output into tokens so the two agree. Do
     NOT hand-edit individual hexes — regenerate from the gallery formula. */
  --m1:#BA5B55; --m2:#B95E43; --m3:#B66231; --m4:#B0681C; --m5:#A86E00; --m6:#9D7400;
  --m7:#917B00; --m8:#828107; --m9:#718623; --m10:#5D8B37; --m11:#468F4A; --m12:#26915D;
  --m13:#00936F; --m14:#009380; --m15:#009290; --m16:#00909F; --m17:#008CAC; --m18:#0088B6;
  --m19:#2083BE; --m20:#407EC4; --m21:#5779C6; --m22:#6A73C5; --m23:#7A6DC1; --m24:#8968BA;
  --m25:#9564B0; --m26:#A060A4; --m27:#AA5C97; --m28:#B15A87; --m29:#B65977; --m30:#B95966;

  /* Tag-type hues (P11) — a typed tag (bpm:142, key:F-min…) reads in its type's fixed colour,
     the same across every file. Generated with the SAME OKLCH method as the member hues
     (light L=0.585 C=0.125) so they harmonise with the mono system instead of fighting it.
     These are NOT member identity — they're content metadata, and unlike the member hue they
     may appear anywhere (explorer, feed, details). Theme-swapped below. */
  --tt-bpm:#467dc4; --tt-key:#359055; --tt-genre:#9a62ab; --tt-mood:#ae6916; --tt-instrument:#009194;
  /* the SAME generator's L/C, exposed as tokens (not baked into a hex) so a CUSTOM tag type — any
     type:value not in the fixed set above (P38) — can compute oklch(var(--tt-l) var(--tt-c) <hash
     hue>deg) at runtime (tags.js customHue()): the browser's own theme-swap handles light/dark, no
     JS dark-mode detection needed. */
  --tt-l:0.585; --tt-c:0.125;

  /* Search-modifier colour (P27/P34, 2026-08-31; muted 2026-08-31 — owner: "magenta for tags is a
     bit confusing") — a search modifier (in:/hastag:/by:/…) needs its OWN colour so it reads as
     neither a grey untyped tag nor a coloured typed tag when it sits next to either in the search
     rail. Same OKLCH hue as the first pass (H=338°, still the hue that maximises RGB distance from
     all 5 --tt- hues) but at HALF the tag chroma (C=0.07 vs 0.125) — full-chroma magenta read as
     just another vivid tag colour, defeating the point; desaturating it differentiates by KIND (a
     muted dusty mauve reads as UI chrome) rather than only by hue, which a 6th saturated colour next
     to 5 others never fully achieves. Never used on a tag; a tag stays --tt-<type> or --soft. C is
     NOT --tt-c (that token is specifically for tags, incl. custom hashed ones) — --mod carries its
     own lower chroma inline. Theme-swapped below. */
  --mod:#976c8a;

  /* type scale */
  --fs-mi:11px; --fs-xs:12px; --fs-sm:13px; --fs:14.5px; --fs-lg:16px; --fs-xl:20px;
  --font:'Jost','Avenir Next','Segoe UI',Arial,sans-serif;
  /* the eski! wordmark face — Gnomon (@font-face above), falls back to the body face if it ever
     fails to load. One token → every wordmark switches at once. */
  --font-wordmark:'Gnomon',var(--font);

  /* space, radius, motion */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:40px;
  --r:3px; --t:120ms ease;
  --hair-inset:14px;          /* L/R gap on a dialog/rail hairline */

  /* pane widths (workspace, prototyped at 1440) */
  --rail:58px; --chan:232px; --mem:210px;
}

/* --- DARK (redefine only what changes; keep both blocks identical) -------- */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --paper:#0A0A0A; --surface:#171717; --plate:#242424; --paper1:#2B2B2B;
    --ink:#F4F4F4; --soft:#C8C8C8; --muted:#9A9A9A;
    --line:#303030; --line2:#484848;
    --on-ink:#0A0A0A; --tagbg:#2C2C2C; --danger:#F07C63; --railbg:#040404;
    /* dark member hues: same generator, dark L=0.79 C=0.112 */
    --m1:#FA9E96; --m2:#F9A187; --m3:#F5A579; --m4:#EFA96D; --m5:#E6AF65; --m6:#DCB561;
    --m7:#CFBB62; --m8:#C0C168; --m9:#B0C672; --m10:#9ECA7F; --m11:#8CCE8E; --m12:#79D09E;
    --m13:#68D2AE; --m14:#59D2BF; --m15:#50D1CE; --m16:#4FCFDD; --m17:#57CCE9; --m18:#64C8F4;
    --m19:#74C4FC; --m20:#86BFFF; --m21:#97B9FF; --m22:#A8B4FF; --m23:#B8AFFE; --m24:#C7AAF7;
    --m25:#D4A5EE; --m26:#DFA1E2; --m27:#E99ED5; --m28:#F19DC6; --m29:#F69CB6; --m30:#F99CA6;
    /* dark tag-type hues: same generator, dark L=0.79 C=0.112 */
    --tt-bpm:#8abdff; --tt-key:#81cf97; --tt-genre:#d9a4e9; --tt-mood:#edab6b; --tt-instrument:#4fd1d2; --mod:#d6acc9; --tt-l:0.79; --tt-c:0.112;
  }
}
:root[data-theme="dark"]{
  --paper:#0A0A0A; --surface:#171717; --plate:#242424; --paper1:#2B2B2B;
  --ink:#F4F4F4; --soft:#C8C8C8; --muted:#9A9A9A;
  --line:#303030; --line2:#484848;
  --on-ink:#0A0A0A; --tagbg:#2C2C2C; --danger:#F07C63; --railbg:#040404;
  /* dark member hues: same generator, dark L=0.79 C=0.112 */
  --m1:#FA9E96; --m2:#F9A187; --m3:#F5A579; --m4:#EFA96D; --m5:#E6AF65; --m6:#DCB561;
  --m7:#CFBB62; --m8:#C0C168; --m9:#B0C672; --m10:#9ECA7F; --m11:#8CCE8E; --m12:#79D09E;
  --m13:#68D2AE; --m14:#59D2BF; --m15:#50D1CE; --m16:#4FCFDD; --m17:#57CCE9; --m18:#64C8F4;
  --m19:#74C4FC; --m20:#86BFFF; --m21:#97B9FF; --m22:#A8B4FF; --m23:#B8AFFE; --m24:#C7AAF7;
  --m25:#D4A5EE; --m26:#DFA1E2; --m27:#E99ED5; --m28:#F19DC6; --m29:#F69CB6; --m30:#F99CA6;
  /* dark tag-type hues: same generator, dark L=0.79 C=0.112 */
  --tt-bpm:#8abdff; --tt-key:#81cf97; --tt-genre:#d9a4e9; --tt-mood:#edab6b; --tt-instrument:#4fd1d2; --mod:#d6acc9; --tt-l:0.79; --tt-c:0.112;
}
