/* ============================================================
   themes.css — the token contract, the built-in palettes and
   the theme picker / editor chrome

   Two orthogonal axes, never one overloaded attribute:

     <html data-theme="midnight" data-mode="dark">

   `data-theme` is palette IDENTITY. Every palette declares both
   grounds in one declaration via light-dark(), so a theme never
   has to opt out of following the system.

   `data-mode` is POLARITY, and 'system' is the *absence* of an
   override rather than a lookup into some other theme's name.
   It is expressed purely as `color-scheme`, which means the
   light/dark switch needs no JavaScript at all — and it gives
   Theme.isLight() a single honest source of truth to read back.

   Nothing here declares a bare :root block. Every rule is
   attribute-selected, so css/styles.css's :root (lines 6-28)
   survives untouched as the fallback if this file fails to load
   or if the browser is too old for light-dark().
   ============================================================ */

/* ------------------------------------------------------------
   THE CONTRACT

   chrome    --bg --bg-2 --panel --panel-2 --stroke --stroke-2
             --tx --tx-2 --tx-3
   accents   --a1 --a2 --a3          (artwork overrides these
                                      at inline-style priority)
   semantic  --tx-on-accent --danger --warn --ok
   brand     --sp --sp-2 --tx-on-sp --yt --sc --am
   surfaces  --sunk --art-1 --art-2 --thumb --thumb-2 --knob --scrim
   shape     --r-sm --r --r-lg --r-xl --ease --shadow --blur --font

   A built-in only has to restate what it actually changes; the
   two blocks below carry every sane default. js/theme.js keeps
   the same list in Theme.TOKENS and refuses to write anything
   outside it.
   ------------------------------------------------------------ */

/* Zero-specificity so a palette block (0,2,0) always wins, and
   so none of these can shadow a same-named token in styles.css.
   Everything named here is genuinely new. */
:where(:root){
  /* Default polarity. Explicit modes below outrank this. */
  color-scheme:dark;

  --tx-on-accent:#fff;
  /* These three are read as TEXT — .pill-btn.danger, .sp-who
     small.free, .pick-delta — so they cannot be the one-ground
     literals styles.css could afford when there was only ever a
     near-black behind them. The dark values are exactly what
     styles.css hardcoded; the light ones are the same hues pushed
     down to 4.8:1 or better against every palette's light --bg. */
  --danger:light-dark(#c0102f,#ff7a92);
  --warn:light-dark(#8a5300,#ffb020);
  --ok:light-dark(#0b7a3b,#3ddc84);

  /* Provider brand colors. Fixed by the brands themselves, but
     tokenised so a theme can dial them back if it wants to. */
  --sp:#1ed760; --sp-2:#12b954; --tx-on-sp:#0b1f14;
  --yt:#ff0033;
  --sc:#ff5500;
  --am:#fa243c;

  /* Derived from --tx, so these follow any palette for free. */
  --thumb:color-mix(in oklab,var(--tx) 14%,transparent);
  --thumb-2:color-mix(in oklab,var(--tx) 26%,transparent);

  --sunk:light-dark(rgba(16,18,32,.05),rgba(0,0,0,.22));
  --art-1:light-dark(#e7e6f2,#20203a);
  --art-2:light-dark(#d8d7e6,#12121f);
  --knob:light-dark(#1a1a24,#ffffff);
  --scrim:light-dark(rgba(250,250,255,.88),rgba(0,0,0,.78));
}

/* Shape and feel: shared by every built-in, restated at palette
   specificity because styles.css:6-28 already owns these names. */
:root[data-theme],[data-thm]{
  --r-sm:10px; --r:16px; --r-lg:22px; --r-xl:30px;
  --ease:cubic-bezier(.22,1,.36,1);
  --blur:saturate(180%) blur(22px);
  --shadow:0 18px 50px -12px light-dark(rgba(26,22,48,.24),rgba(0,0,0,.75));
  --font:'Outfit',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
}

/* ============================================================
   BUILT-IN PALETTES

   --tx-on-accent is restated by every palette whose DARK accent is
   a bright one. White ink is only legible on midnight's deep violet;
   on #3ecf7a or #89b4fa it lands at 2.0-2.8:1 on the app's most
   prominent fill (.pill-btn.primary, .play-btn, .card-play), so the
   label punches out in the palette's own ground instead. The light
   half stays #fff — down there --a1 is the deep member of the pair.

   Every block is duplicated onto [data-thm='id'] so any element
   can carry a palette. That is what makes the picker swatches
   real (a card renders in the theme it offers) and lets the
   editor read a palette's resolved values off a probe element
   without ever applying it to the page.
   ============================================================ */

/* ---------- midnight — the shipping look, unchanged ---------- */
:root[data-theme='midnight'],[data-thm='midnight']{
  --bg:light-dark(#f6f5fb,#07070d);
  --bg-2:light-dark(#eceaf6,#0c0c16);
  --panel:light-dark(rgba(22,20,31,.045),rgba(255,255,255,.045));
  --panel-2:light-dark(rgba(22,20,31,.075),rgba(255,255,255,.07));
  --stroke:light-dark(rgba(22,20,31,.12),rgba(255,255,255,.09));
  --stroke-2:light-dark(rgba(22,20,31,.22),rgba(255,255,255,.16));
  --tx:light-dark(#16141f,#f2f3f8);
  --tx-2:light-dark(rgba(22,20,31,.70),rgba(242,243,248,.62));
  --tx-3:light-dark(rgba(22,20,31,.46),rgba(242,243,248,.38));
  --a1:light-dark(#6a41f0,#7c5cff);
  --a2:light-dark(#0090b8,#00d4ff);
  --a3:light-dark(#d81b74,#ff4d9d);
}

/* ---------- noir — monochrome, accents collapsed to ink ---------- */
:root[data-theme='noir'],[data-thm='noir']{
  --bg:light-dark(#fafafa,#0a0a0a);
  --bg-2:light-dark(#f0f0f0,#131313);
  --panel:light-dark(rgba(0,0,0,.04),rgba(255,255,255,.05));
  --panel-2:light-dark(rgba(0,0,0,.075),rgba(255,255,255,.085));
  --stroke:light-dark(rgba(0,0,0,.13),rgba(255,255,255,.1));
  --stroke-2:light-dark(rgba(0,0,0,.26),rgba(255,255,255,.2));
  --tx:light-dark(#141414,#f5f5f5);
  --tx-2:light-dark(rgba(20,20,20,.70),rgba(245,245,245,.60));
  --tx-3:light-dark(rgba(20,20,20,.46),rgba(245,245,245,.36));
  --a1:light-dark(#141414,#f5f5f5);
  --a2:light-dark(#4a4a4a,#b9b9b9);
  --a3:light-dark(#6e6e6e,#8a8a8a);
  /* The one palette where the accent is the same value as the
     text, so white-on-accent would vanish. */
  --tx-on-accent:light-dark(#fafafa,#0a0a0a);
  --r-sm:6px; --r:10px; --r-lg:14px; --r-xl:18px;
  --shadow:0 14px 40px -14px light-dark(rgba(0,0,0,.22),rgba(0,0,0,.85));
}

/* ---------- daylight — light-first, crisp and neutral ---------- */
:root[data-theme='daylight'],[data-thm='daylight']{
  --bg:light-dark(#ffffff,#10131a);
  --bg-2:light-dark(#f3f6fb,#171c26);
  --panel:light-dark(rgba(16,24,40,.042),rgba(255,255,255,.05));
  --panel-2:light-dark(rgba(16,24,40,.075),rgba(255,255,255,.08));
  --stroke:light-dark(rgba(16,24,40,.11),rgba(255,255,255,.1));
  --stroke-2:light-dark(rgba(16,24,40,.21),rgba(255,255,255,.19));
  --tx:light-dark(#101828,#eef2f8);
  --tx-2:light-dark(rgba(16,24,40,.70),rgba(238,242,248,.64));
  --tx-3:light-dark(rgba(16,24,40,.47),rgba(238,242,248,.40));
  --a1:light-dark(#2f6bff,#6f97ff);
  --a2:light-dark(#00a0a0,#2fd4d4);
  --a3:light-dark(#e0457b,#ff6f9c);
  --tx-on-accent:light-dark(#fff,#10131a);
}

/* ---------- ocean — deep teal water, warm sand accent ---------- */
:root[data-theme='ocean'],[data-thm='ocean']{
  --bg:light-dark(#f0f8fc,#04121c);
  --bg-2:light-dark(#e1eff7,#08202f);
  --panel:light-dark(rgba(6,35,47,.05),rgba(120,220,255,.06));
  --panel-2:light-dark(rgba(6,35,47,.085),rgba(120,220,255,.1));
  --stroke:light-dark(rgba(6,35,47,.13),rgba(120,220,255,.13));
  --stroke-2:light-dark(rgba(6,35,47,.24),rgba(120,220,255,.26));
  --tx:light-dark(#06232f,#e3f4ff);
  --tx-2:light-dark(rgba(6,35,47,.72),rgba(227,244,255,.64));
  --tx-3:light-dark(rgba(6,35,47,.48),rgba(227,244,255,.40));
  --a1:light-dark(#0e7f97,#12b8d8);
  --a2:light-dark(#118a72,#4fe0b0);
  --a3:light-dark(#b2651a,#ffb64d);
  --tx-on-accent:light-dark(#fff,#04121c);
}

/* ---------- ember — banked coals ---------- */
:root[data-theme='ember'],[data-thm='ember']{
  --bg:light-dark(#fdf6f2,#120a08);
  --bg-2:light-dark(#f7e9e1,#1c100c);
  --panel:light-dark(rgba(42,20,9,.05),rgba(255,164,120,.06));
  --panel-2:light-dark(rgba(42,20,9,.085),rgba(255,164,120,.1));
  --stroke:light-dark(rgba(42,20,9,.13),rgba(255,164,120,.14));
  --stroke-2:light-dark(rgba(42,20,9,.24),rgba(255,164,120,.26));
  --tx:light-dark(#2a1409,#fdece4);
  --tx-2:light-dark(rgba(42,20,9,.72),rgba(253,236,228,.64));
  --tx-3:light-dark(rgba(42,20,9,.48),rgba(253,236,228,.40));
  --a1:light-dark(#c8471a,#ff6b3d);
  --a2:light-dark(#a06400,#ffb03d);
  --a3:light-dark(#c62a5f,#ff3d7f);
  --tx-on-accent:light-dark(#fff,#120a08);
}

/* ---------- forest — moss and lichen ---------- */
:root[data-theme='forest'],[data-thm='forest']{
  --bg:light-dark(#f3f8f4,#07120c);
  --bg-2:light-dark(#e5f0e8,#0d1c14);
  --panel:light-dark(rgba(12,33,22,.05),rgba(150,235,180,.055));
  --panel-2:light-dark(rgba(12,33,22,.085),rgba(150,235,180,.095));
  --stroke:light-dark(rgba(12,33,22,.13),rgba(150,235,180,.13));
  --stroke-2:light-dark(rgba(12,33,22,.24),rgba(150,235,180,.24));
  --tx:light-dark(#0c2116,#e6f5ec);
  --tx-2:light-dark(rgba(12,33,22,.72),rgba(230,245,236,.64));
  --tx-3:light-dark(rgba(12,33,22,.48),rgba(230,245,236,.40));
  --a1:light-dark(#1f8a4d,#3ecf7a);
  --a2:light-dark(#5c8f14,#9fd94a);
  --a3:light-dark(#a8760c,#ffc857);
  --tx-on-accent:light-dark(#fff,#07120c);
}

/* ---------- orchid — violet with a cold cyan third ---------- */
:root[data-theme='orchid'],[data-thm='orchid']{
  --bg:light-dark(#faf5fd,#100715);
  --bg-2:light-dark(#f0e5f8,#1a0c22);
  --panel:light-dark(rgba(34,15,44,.05),rgba(226,170,255,.06));
  --panel-2:light-dark(rgba(34,15,44,.085),rgba(226,170,255,.1));
  --stroke:light-dark(rgba(34,15,44,.13),rgba(226,170,255,.14));
  --stroke-2:light-dark(rgba(34,15,44,.24),rgba(226,170,255,.26));
  --tx:light-dark(#220f2c,#f6e9ff);
  --tx-2:light-dark(rgba(34,15,44,.72),rgba(246,233,255,.64));
  --tx-3:light-dark(rgba(34,15,44,.48),rgba(246,233,255,.40));
  --a1:light-dark(#8b35d6,#c26bff);
  --a2:light-dark(#c22e93,#ff7ad0);
  --a3:light-dark(#0f7f9e,#63e6ff);
  --tx-on-accent:light-dark(#fff,#100715);
}

/* ---------- mocha — warm neutral, low contrast on purpose ---------- */
:root[data-theme='mocha'],[data-thm='mocha']{
  --bg:light-dark(#eff1f5,#1e1e2e);
  --bg-2:light-dark(#e6e9ef,#26263a);
  --panel:light-dark(rgba(76,79,105,.06),rgba(205,214,244,.055));
  --panel-2:light-dark(rgba(76,79,105,.1),rgba(205,214,244,.09));
  --stroke:light-dark(rgba(76,79,105,.16),rgba(205,214,244,.11));
  --stroke-2:light-dark(rgba(76,79,105,.28),rgba(205,214,244,.22));
  --tx:light-dark(#3c3f56,#cdd6f4);
  --tx-2:light-dark(rgba(60,63,86,.76),rgba(205,214,244,.66));
  --tx-3:light-dark(rgba(60,63,86,.52),rgba(205,214,244,.42));
  --a1:light-dark(#1e66f5,#89b4fa);
  --a2:light-dark(#179299,#94e2d5);
  --a3:light-dark(#ea76cb,#f5c2e7);
  /* Latte's own peach is 2.3:1 on this ground and --warn is read as
     text, so the light half is dropped to the same hue at 4.5:1. */
  --warn:light-dark(#a35c00,#f9e2af);
  --danger:light-dark(#d20f39,#f38ba8);
  --tx-on-accent:light-dark(#fff,#1e1e2e);
}

/* ============================================================
   MODE

   These come after the palettes on purpose: at equal (0,2,0)
   specificity, source order decides, so an explicit mode always
   outranks whatever polarity a palette assumed.
   ============================================================ */
:root[data-mode='light']{color-scheme:light}
:root[data-mode='dark']{color-scheme:dark}
/* The whole of "system": hand the choice back to the UA. */
:root[data-mode='system']{color-scheme:light dark}

/* ============================================================
   LEGACY FALLBACK

   Without light-dark() every token above is invalid at computed
   value time, which would take the whole UI down rather than
   degrade it. Under @supports the palettes simply never apply,
   styles.css's dark :root stands, and each theme still gets to
   tint the accents — which is most of its identity anyway.
   ============================================================ */
@supports not (color:light-dark(#fff,#000)){
  :root[data-theme='noir']{--a1:#f5f5f5;--a2:#b9b9b9;--a3:#8a8a8a;--tx-on-accent:#0a0a0a}
  :root[data-theme='daylight']{--tx-on-accent:#10131a;--a1:#6f97ff;--a2:#2fd4d4;--a3:#ff6f9c}
  :root[data-theme='ocean']{--tx-on-accent:#04121c;--a1:#12b8d8;--a2:#4fe0b0;--a3:#ffb64d}
  :root[data-theme='ember']{--tx-on-accent:#120a08;--a1:#ff6b3d;--a2:#ffb03d;--a3:#ff3d7f}
  :root[data-theme='forest']{--tx-on-accent:#07120c;--a1:#3ecf7a;--a2:#9fd94a;--a3:#ffc857}
  :root[data-theme='orchid']{--tx-on-accent:#100715;--a1:#c26bff;--a2:#ff7ad0;--a3:#63e6ff}
  :root[data-theme='mocha']{--tx-on-accent:#1e1e2e;--a1:#89b4fa;--a2:#94e2d5;--a3:#f5c2e7}
  :where(:root){
    --sunk:rgba(0,0,0,.22);--art-1:#20203a;--art-2:#12121f;
    --knob:#fff;--scrim:rgba(0,0,0,.78);
    --shadow:0 18px 50px -12px rgba(0,0,0,.75);
    /* color-mix() predates light-dark() by a year, so a browser in
       here usually still has it — but if it does not, an invalid
       --thumb takes the scrollbar and both range tracks with it. */
    --thumb:rgba(255,255,255,.14);--thumb-2:rgba(255,255,255,.26);
    /* Same reason: without light-dark() these would be invalid, and
       an invalid --danger takes every delete affordance with it. */
    --danger:#ff7a92;--warn:#ffb020;--ok:#3ddc84;
  }
}

/* ============================================================
   PICKER + EDITOR CHROME  (.thm-*)
   ============================================================ */
.thm-panel{
  position:fixed;z-index:130;inset:auto 0 0 0;margin:0 auto;
  width:min(720px,100%);max-height:min(84vh,780px);
  display:flex;flex-direction:column;
  border-radius:var(--r-xl) var(--r-xl) 0 0;
  background:color-mix(in oklab,var(--bg-2) 96%,transparent);
  backdrop-filter:var(--blur);-webkit-backdrop-filter:var(--blur);
  border:1px solid var(--stroke-2);border-bottom:none;
  box-shadow:var(--shadow);
  animation:thmRise .28s var(--ease);
}
@keyframes thmRise{from{transform:translateY(22px);opacity:0}to{transform:none;opacity:1}}
@media (min-width:900px){
  .thm-panel{inset:50% auto auto 50%;transform:translate(-50%,-50%);
    border-radius:var(--r-xl);border-bottom:1px solid var(--stroke-2)}
  @keyframes thmRise{from{transform:translate(-50%,-46%);opacity:0}
                     to{transform:translate(-50%,-50%);opacity:1}}
}
.thm-scrim{position:fixed;inset:0;z-index:129;background:rgba(0,0,0,.5);
  backdrop-filter:blur(6px);animation:fade .2s var(--ease)}

.thm-head{display:flex;align-items:center;gap:12px;padding:18px 20px 12px;flex:none}
.thm-head h3{font-size:18px;font-weight:750;letter-spacing:-.3px;flex:1;min-width:0}
.thm-head .thm-x{width:32px;height:32px;border-radius:10px;display:grid;place-items:center;
  color:var(--tx-3);flex:none}
.thm-head .thm-x:hover{background:var(--panel-2);color:var(--tx)}
.thm-head .thm-x svg{width:15px;height:15px}

.thm-body{flex:1;min-height:0;overflow-y:auto;padding:0 20px 4px;
  display:flex;flex-direction:column;gap:18px}
.thm-foot{display:flex;gap:8px;flex-wrap:wrap;justify-content:flex-end;
  padding:14px 20px calc(16px + var(--sa-b,0px));flex:none;
  border-top:1px solid var(--stroke)}
.thm-foot .thm-spacer{flex:1}

.thm-group{display:flex;flex-direction:column;gap:9px}
.thm-group > h4{font-size:11px;text-transform:uppercase;letter-spacing:.09em;
  color:var(--tx-3);font-weight:700}
.thm-note{font-size:11.5px;color:var(--tx-3);line-height:1.65}

/* ---------- mode switch ---------- */
.thm-modes{display:inline-flex;gap:3px;padding:3px;border-radius:99px;
  background:var(--panel);border:1px solid var(--stroke);align-self:flex-start}
.thm-modes button{padding:6px 14px;border-radius:99px;font-size:12px;font-weight:600;
  color:var(--tx-3);transition:.16s var(--ease)}
.thm-modes button:hover{color:var(--tx)}
.thm-modes button.active{background:linear-gradient(135deg,var(--a1),var(--a2));
  color:var(--tx-on-accent)}

/* ---------- palette grid ---------- */
.thm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:10px}
.thm-card{
  position:relative;padding:11px;border-radius:var(--r);text-align:left;
  background:var(--bg);border:1px solid var(--stroke-2);
  transition:.18s var(--ease);overflow:hidden;
}
.thm-card:hover{transform:translateY(-2px);box-shadow:var(--shadow)}
.thm-card.active{border-color:var(--a2);box-shadow:0 0 0 1px var(--a2)}
.thm-card .thm-strip{display:flex;gap:4px;margin-bottom:9px}
.thm-card .thm-strip i{flex:1;height:26px;border-radius:7px}
.thm-card .thm-strip i:nth-child(1){background:linear-gradient(135deg,var(--a1),var(--a2))}
.thm-card .thm-strip i:nth-child(2){background:var(--a3)}
.thm-card .thm-strip i:nth-child(3){background:var(--panel-2);border:1px solid var(--stroke)}
.thm-card .thm-name{display:block;font-size:13px;font-weight:650;color:var(--tx);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.thm-card .thm-sub{display:block;font-size:10.5px;color:var(--tx-3);margin-top:1px}
.thm-card .thm-tick{position:absolute;top:9px;right:9px;width:17px;height:17px;
  border-radius:50%;display:grid;place-items:center;
  background:var(--a2);color:var(--tx-on-accent)}
.thm-card .thm-tick svg{width:10px;height:10px;stroke-width:3.4}

/* ---------- token rows ---------- */
.thm-row{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:11px;
  background:var(--panel);border:1px solid var(--stroke)}
/* :not(.switch) matters: the toggle is a <label> too, and letting the
   generic row rule give it flex:1 stretches the 34px pill across the
   whole row. */
.thm-row > label:not(.switch){flex:1;min-width:0;font-size:12.5px;color:var(--tx-2)}
.thm-row label small{display:block;font-size:10px;color:var(--tx-3);
  font-family:ui-monospace,monospace;margin-top:1px}
.thm-row input[type=color]{width:34px;height:28px;padding:0;flex:none;cursor:pointer;
  background:none;border:1px solid var(--stroke-2);border-radius:8px}
.thm-row input[type=color]::-webkit-color-swatch-wrapper{padding:2px}
.thm-row input[type=color]::-webkit-color-swatch{border:none;border-radius:6px}
.thm-row input[type=range]{width:96px;flex:none}
.thm-row input[type=text],.thm-row select{
  width:180px;flex:none;height:30px;padding:0 9px;border-radius:9px;font-size:12px;
  background:var(--panel-2);border:1px solid var(--stroke);outline:none}
.thm-row input[type=text]:focus{border-color:var(--a2)}
.thm-row output{width:38px;flex:none;text-align:right;font-size:11px;color:var(--tx-3);
  font-variant-numeric:tabular-nums}
.thm-row.bad{border-color:var(--danger)}

/* ---------- editor layout + live preview ---------- */
.thm-editor-grid{display:grid;gap:14px}
@media (min-width:860px){.thm-editor-grid{grid-template-columns:1fr 280px;align-items:start}}
.thm-tokens{display:flex;flex-direction:column;gap:7px;min-width:0}
.thm-preview{
  position:sticky;top:0;border-radius:var(--r);overflow:hidden;
  border:1px solid var(--stroke-2);min-height:190px;background:var(--bg);
}
.thm-errors{display:flex;flex-direction:column;gap:4px;font-size:11.5px;color:var(--danger)}

/* The shadow-root mock. These rules are injected into the shadow
   tree by js/theme.js, not matched from here — kept alongside the
   rest of the theme chrome so the two never drift apart. */

/* ---------- import / export ---------- */
.thm-io textarea{
  width:100%;min-height:120px;padding:11px 13px;border-radius:11px;resize:vertical;
  background:var(--panel);border:1px solid var(--stroke);outline:none;
  font-family:ui-monospace,monospace;font-size:11.5px;line-height:1.6;color:var(--tx);
}
.thm-io textarea:focus{border-color:var(--a2)}

@media (prefers-reduced-motion:reduce){
  .thm-panel{animation:none}
  .thm-card:hover{transform:none}
}

/* ============================================================
   TOKENISING OVERRIDES

   css/styles.css is off-limits to this module, and it carries
   114 hardcoded hex values that were all written against one
   permanently dark ground. Everything below re-points the ones
   that would actually break — or read as a bug — under a light
   or monochrome palette.

   These work by source order, not by specificity: this file is
   linked after styles.css, and every selector is copied
   byte-for-byte from it, so each pair ties at equal specificity
   and the later one (here) wins. Do not "tidy" these selectors;
   they are quotations.
   ============================================================ */

/* --- text drawn on top of an accent fill ---------------------
   noir's accent IS its text colour, so a hardcoded white here
   renders white-on-white. --tx-on-accent is the token that
   knows which way round the palette runs. */
::selection{background:var(--a1);color:var(--tx-on-accent)}
.upload-btn{color:var(--tx-on-accent)}
.pill-btn.primary{color:var(--tx-on-accent)}
.card-play{color:var(--tx-on-accent)}
.play-btn{color:var(--tx-on-accent)}
.viz-modes button.active{color:var(--tx-on-accent)}
.np-tabs button.active{color:var(--tx-on-accent)}
.scope button.active{background:var(--a1);color:var(--tx-on-accent)}
.marker label{color:var(--tx-on-accent)}
.ab-btn.a.set .ab-key{color:var(--tx-on-accent)}
.ab-toggle.on{color:var(--tx-on-accent)}
.loop-card .lc-play{color:var(--tx-on-accent)}
.lyric-line .loop-line{color:var(--tx-on-accent)}
.switch input:checked+span::after{background:var(--tx-on-accent)}

/* --- surfaces that were "translucent white over black" ------- */
*::-webkit-scrollbar-thumb{background:var(--thumb);background-clip:content-box}
*::-webkit-scrollbar-thumb:hover{background:var(--thumb-2);background-clip:content-box}
.lyrics-body{background:var(--sunk)}
.k-bar{background:var(--thumb)}
.theater-track{background:var(--thumb)}
/* A <select>'s popup is UA-painted; without this it stays black
   on a light palette. */
.select option{background:var(--bg-2);color:var(--tx)}
/* The chevron is baked into a data URI with stroke='white', which is
   invisible on every light ground. A data URI cannot read a token, so
   this is the one place a literal is unavoidable — mid grey clears
   3:1 against both ends of every palette. Longhand on purpose: it has
   to beat the `background:` shorthand in styles.css:224 without
   restating the fill, the position or the size. */
.select{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23808790' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")}
.hover-time{background:var(--scrim);color:var(--tx)}
.played .knob{background:var(--knob)}
input[type=range]::-webkit-slider-runnable-track{
  background:linear-gradient(90deg,var(--a2) var(--p,0%),var(--thumb) var(--p,0%))}
input[type=range]::-moz-range-track{background:var(--thumb)}
input[type=range]::-webkit-slider-thumb{background:var(--knob)}
input[type=range]::-moz-range-thumb{background:var(--knob)}

/* --- artwork placeholders ------------------------------------
   A near-black plate reads as a hole punched in a light theme. */
.card-art{background:linear-gradient(135deg,var(--art-1),var(--art-2))}
.row-art{background:linear-gradient(135deg,var(--art-1),var(--art-2))}
.art-wrap{background:linear-gradient(135deg,var(--art-1),var(--art-2))}
.pb-art{background:linear-gradient(135deg,var(--art-1),var(--art-2))}
.loop-card .lc-art{background:linear-gradient(135deg,var(--art-1),var(--art-2))}
.card-art .ph{color:color-mix(in oklab,var(--tx) 26%,transparent)}
.pb-art-fallback{color:color-mix(in oklab,var(--tx) 26%,transparent)}

/* --- status colours ------------------------------------------ */
.pill-btn.danger{color:var(--danger)}
.pill-btn.danger:hover{background:color-mix(in oklab,var(--danger) 16%,transparent);
  border-color:color-mix(in oklab,var(--danger) 42%,transparent)}
.ctx-item.danger{color:var(--danger)}
.loop-acts button.del:hover{color:var(--danger);
  background:color-mix(in oklab,var(--danger) 16%,transparent)}
.loop-card .lc-del:hover{color:var(--danger);
  background:color-mix(in oklab,var(--danger) 16%,transparent)}
.sp-actions button.danger:hover{color:var(--danger);
  border-color:color-mix(in oklab,var(--danger) 42%,transparent);
  background:color-mix(in oklab,var(--danger) 14%,transparent)}
.offset-ctl [data-offset-reset]:hover{color:var(--danger)}
.pick-delta.bad{background:color-mix(in oklab,var(--danger) 16%,transparent);color:var(--danger)}
.pick-delta.ok{background:color-mix(in oklab,var(--warn) 18%,transparent);color:var(--warn)}
.pick-delta.good{background:color-mix(in oklab,var(--ok) 18%,transparent);color:var(--ok)}
.sp-who small.free{color:var(--warn)}
.am-box .am-expiry.soon{color:var(--warn)}

/* --- provider brand colours ---------------------------------- */
.sp-connect{color:var(--tx-on-sp);background:linear-gradient(135deg,var(--sp),var(--sp-2))}
.sp-avatar{background:linear-gradient(135deg,var(--sp),var(--sp-2));color:var(--tx-on-sp)}
.searching .spin{border-color:var(--thumb);border-top-color:var(--sp)}
.connect-dot{background:var(--sp)}
.sp-who small{color:var(--sp)}
.src-badge{background:color-mix(in oklab,var(--sp) 16%,transparent);color:var(--sp)}
.card-art .src-badge{background:var(--scrim)}
.pl-item .pl-mark{color:var(--sp)}
.scope button[data-scope="spotify"].active{background:var(--sp);color:var(--tx-on-sp)}
.row-add,.card-add{color:var(--tx-on-sp);
  background:linear-gradient(135deg,var(--sp),var(--sp-2))}
.search-cta:hover{border-color:var(--sp)}
.search-cta svg{color:var(--sp)}
.bpm-tag.sim{color:var(--sp);border-color:color-mix(in oklab,var(--sp) 30%,transparent)}
.connect-btn.remote{color:var(--sp)}
.dev-row.on{background:color-mix(in oklab,var(--sp) 12%,transparent);
  border-color:color-mix(in oklab,var(--sp) 35%,transparent)}
.dev-row.on .dev-name{color:var(--sp)}
.dev-row.on .dev-icon{background:color-mix(in oklab,var(--sp) 16%,transparent);color:var(--sp)}
.dev-bars i{background:var(--sp)}
.sonos-room.on{background:color-mix(in oklab,var(--sp) 10%,transparent);
  border-color:color-mix(in oklab,var(--sp) 30%,transparent)}
.sonos-room.on .dev-name{color:var(--sp)}
.sonos-room.on .dev-icon{background:color-mix(in oklab,var(--sp) 16%,transparent);color:var(--sp)}
.room-btn.link.on{color:var(--sp);background:color-mix(in oklab,var(--sp) 14%,transparent)}
.sonos-room.output{border-color:color-mix(in oklab,var(--sp) 55%,transparent);
  background:color-mix(in oklab,var(--sp) 14%,transparent)}
.output-label{color:var(--sp)}
.scope button[data-scope="youtube"].active{background:var(--yt);color:#fff}
.src-badge.yt{background:color-mix(in oklab,var(--yt) 16%,transparent);
  color:color-mix(in oklab,var(--yt) 78%,var(--tx))}
.am-box .am-expiry.gone{color:var(--danger)}
.src-badge.sc{color:var(--sc);background:color-mix(in oklab,var(--sc) 16%,transparent)}
.scope button[data-scope="soundcloud"].active{background:var(--sc);color:#fff}
.src-badge.am{color:var(--am);background:color-mix(in oklab,var(--am) 16%,transparent)}
.scope button[data-scope="apple"].active{background:var(--am);color:#fff}

/* --- theater backdrop ----------------------------------------
   A hardcoded near-black ground behind the whole app; it has to
   follow the palette or theater mode ignores the theme entirely. */
body.theater::before{
  background:radial-gradient(70vw 70vw at 50% 0%,
    color-mix(in oklab,var(--a1) 22%,transparent), transparent 60%),
    color-mix(in oklab,var(--bg) 92%,#000);
}

/* --- typography ---------------------------------------------
   The only place --font is consumed, so a custom theme's family
   choice actually reaches the page. */
body{font-family:var(--font,'Outfit',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif)}
