/* ═══════════════════════════════════════════════════════════════════════
   streamingmusic.io — design system
   The listening room: warm charcoal, burnished ember, porcelain actions.
   Editorial serif for names, a quiet grotesk for prose, and a monospace
   whisper for anything measured — BPM, LUFS, labels. Ember is reserved
   for sound (playing, live, level); porcelain is the colour of an action.
   ═══════════════════════════════════════════════════════════════════════ */

/* The prototype's type, self-hosted (SIL OFL; licenses in fonts/).
   Fraunces — soft, round, with an optical-size axis — is the display voice,
   set light at large sizes and in italic for the brass eyebrow lines.
   Inter carries everything read. IBM Plex Mono is the label voice, tracked
   wide. The same three, the same roles, as ~/dev/prototypes/streamingmusic. */
@font-face{
  font-family:"Fraunces";font-style:normal;font-weight:300 700;font-display:swap;
  src:url("/fonts/fraunces.woff2") format("woff2")}
@font-face{
  font-family:"Fraunces";font-style:italic;font-weight:300 700;font-display:swap;
  src:url("/fonts/fraunces-italic.woff2") format("woff2")}
@font-face{
  font-family:"Inter";font-style:normal;font-weight:100 900;font-display:swap;
  src:url("/fonts/inter.woff2") format("woff2")}
@font-face{
  font-family:"IBM Plex Mono";font-style:normal;font-weight:400;font-display:swap;
  src:url("/fonts/plex-mono-400.woff2") format("woff2")}
@font-face{
  font-family:"IBM Plex Mono";font-style:normal;font-weight:500;font-display:swap;
  src:url("/fonts/plex-mono-500.woff2") format("woff2")}

:root{
  /* ground — charcoal warmed toward umber, matte hardware black */
  --bg:#0C0A09;
  --bg-1:#100E0C;
  --bg-2:#161310;
  --surface:rgba(255,255,255,.03);
  --surface-2:rgba(255,255,255,.055);
  --surface-3:rgba(255,255,255,.085);

  /* ember — one warm ramp, burnished rather than neon */
  --flame-1:#C6511F;
  --flame-2:#D96F33;
  --flame-3:#E08F4C;
  --ember:#E4AE6E;
  --gold:#EDD2A6;
  --flame-rgb:217,111,51;
  --heart:#CE3A5C;
  --heart-rgb:206,58,92;

  /* type — warm porcelain down to parchment grey. --ink-3 must hold AA
     (≥4.5:1) on --bg: it carries table headers, durations and fine print. */
  --ink-0:#F3EEE5;
  --ink-1:#C9C2B4;
  --ink-2:#9B9486;
  --ink-3:#867E6D;

  /* structure */
  --line:rgba(255,255,255,.07);
  --line-2:rgba(255,255,255,.12);
  --line-3:rgba(255,255,255,.2);

  /* accent driven by the playing artwork */
  --a1:#D96F33; --a2:#E4AE6E; --glow:217,111,51;

  --r-xs:7px; --r-sm:9px; --r:12px; --r-lg:16px; --r-xl:18px; --r-2xl:22px;
  --pill:999px;

  --sh-1:0 1px 2px rgba(0,0,0,.4);
  --sh-2:0 12px 30px -14px rgba(0,0,0,.8);
  --sh-3:0 40px 90px -40px rgba(0,0,0,.95);
  --hi:inset 0 1px 0 rgba(255,255,255,.07);

  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-io:cubic-bezier(.65,.05,.36,1);
  --expo:cubic-bezier(.16,1,.3,1);

  --gut:clamp(20px,4.2vw,56px);
  --side:272px;
  --playerh:92px;

  --sans:"Inter",system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --serif:"Fraunces",ui-serif,Georgia,"Times New Roman",serif;
  --display:"Fraunces",ui-serif,Georgia,"Times New Roman",serif;
  --mono:"IBM Plex Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
}

*{box-sizing:border-box;margin:0;padding:0}
/* `hidden` only sets display:none via the UA sheet — any author `display`
   rule defeats it, and nearly every panel here sets one. */
[hidden]{display:none !important}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  min-height:100%;background:var(--bg);color:var(--ink-0);
  font-family:var(--sans);font-size:16px;line-height:1.68;font-weight:400;
  font-optical-sizing:auto;font-kerning:normal;letter-spacing:0;
  font-feature-settings:"kern" 1,"liga" 1,"calt" 1;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  text-rendering:optimizeLegibility;
}
button,input,select,textarea{font:inherit;color:inherit;letter-spacing:inherit}
button{background:none;border:0;cursor:pointer;color:inherit}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
code{font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace;font-size:.88em}
::selection{background:rgba(217,111,51,.32);color:#fff}
:focus-visible{outline:2px solid var(--flame-3);outline-offset:3px;border-radius:6px}
.sprite{display:none}
.ic{width:18px;height:18px;flex:none;display:block;fill:none;stroke:currentColor;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}

::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:rgba(255,255,255,.1);border-radius:99px;
  border:3px solid transparent;background-clip:content-box}
::-webkit-scrollbar-thumb:hover{background:rgba(255,255,255,.18);background-clip:content-box}

/* ══════════════════════════════════════════════════════ boot + grain ═══ */
.boot{position:fixed;inset:0;z-index:300;display:grid;place-items:center;background:var(--bg);
  transition:opacity .55s var(--ease),visibility .55s}
.boot.gone{opacity:0;visibility:hidden}
.grain{position:fixed;inset:0;z-index:400;pointer-events:none;opacity:.03;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:200px}

/* ═════════════════════════════════════════════════════════════ brand ═══ */
.brand{display:inline-flex;align-items:center;gap:11px;flex:none}
.wordmark{font-family:var(--serif);font-size:19px;font-weight:400;letter-spacing:.01em;
  color:var(--ink-0);white-space:nowrap;font-optical-sizing:auto}
.brand.center{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:10px;margin-bottom:22px}

/* Knocked-out PNGs of the written note and the champagne wordmark. The source
   files have a baked black field; these copies have the field removed so they
   sit on the room, the charcoal chrome, and the auth card. */
.mark-img{width:18px;height:auto;flex:none;display:block;transform-origin:center;
  animation:notehead .55s var(--expo) .18s backwards,
            notebreathe var(--note-beat,2.6s) var(--ease-io) var(--note-phase,1.4s) infinite;
  animation-play-state:running,paused}
.mark-img.lg{width:56px}
.word-img{height:17px;width:auto;flex:none;display:block}
.brand.center .mark-img{width:36px}
.brand.center .word-img{height:18px}
@keyframes notehead{from{opacity:0;transform:scale(.55)}}
/* amplitude stays small on purpose — a valve warming, not a beacon */
@keyframes notebreathe{0%,100%{opacity:1;transform:scale(1)}
  50%{opacity:.62;transform:scale(.94)}}

/* ═══════════════════════════════════════════════════════════ buttons ═══ */
.btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:9px;
  height:46px;padding:0 24px;border-radius:var(--pill);flex:none;
  font-size:14px;font-weight:600;letter-spacing:.02em;white-space:nowrap;overflow:hidden;
  transition:transform .22s var(--ease),box-shadow .22s var(--ease),
             background .22s var(--ease),border-color .22s var(--ease),color .2s}
.btn:disabled{opacity:.55;pointer-events:none}
.btn .ic{width:17px;height:17px}
.btn.sm{height:38px;padding:0 17px;font-size:13.5px;gap:7px}
.btn.sm .ic{width:15px;height:15px}
.btn.lg{height:53px;padding:0 30px;font-size:15.5px}
.btn.full{width:100%}

/* Porcelain on charcoal. The one bright thing on the page is the thing you
   press — no gradient, no shine sweep, no coloured glow. */
.btn.primary{color:#171209;background:var(--ink-0);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),0 14px 30px -16px rgba(0,0,0,.9)}
.btn.primary:hover{transform:translateY(-1px);background:#FFFDF8;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6),0 18px 38px -18px rgba(0,0,0,.95)}
.btn.primary:active{transform:translateY(0)}

.btn.ghost{color:var(--ink-1);background:transparent;border:1px solid var(--line-2);
  box-shadow:var(--hi)}
.btn.ghost:hover{color:var(--ink-0);background:rgba(255,255,255,.05);border-color:var(--line-3);
  transform:translateY(-1px)}
.btn.light{background:#F3EEE5;color:#171209;box-shadow:0 10px 30px -14px rgba(0,0,0,.7)}
.btn.light:hover{transform:translateY(-1px);background:#fff}
.btn.outline{color:var(--ink-0);border:1px solid rgba(255,255,255,.26);background:transparent}
.btn.outline:hover{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.5);transform:translateY(-1px)}
.btn .arr{transition:transform .28s var(--ease)}
.btn:hover .arr{transform:translateX(4px)}

.icon-btn{display:inline-grid;place-items:center;width:38px;height:38px;border-radius:var(--pill);
  color:var(--ink-2);transition:.2s var(--ease);flex:none}
.icon-btn.ghost:hover{color:var(--ink-0);background:var(--surface-2)}

.spin{width:15px;height:15px;flex:none;border-radius:50%;display:inline-block;
  border:2px solid rgba(255,255,255,.28);border-top-color:#fff;animation:spin .7s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

.chip,.credit-chip{display:inline-flex;align-items:center;gap:7px;height:30px;padding:0 12px;
  border-radius:var(--pill);border:1px solid var(--line-2);background:var(--surface);
  font-family:var(--mono);font-size:10px;font-weight:500;letter-spacing:.12em;
  color:var(--ink-2);transition:.2s var(--ease)}
.chip .ic{width:14px;height:14px}
/* The coin carries the accent the ⚡ used to; the count stays ink so the number
   is what you read first. */
.credit-chip .ic{width:15px;height:15px;color:var(--flame-3)}
.chip:hover{color:var(--ink-1);border-color:var(--line-3)}
.chip.on{color:var(--ember);border-color:rgba(228,174,110,.36);background:rgba(217,111,51,.08)}
.credit-chip{font-family:var(--sans);letter-spacing:.02em;font-size:12.5px;font-weight:500;
  height:34px;color:var(--ink-1)}

/* Mono micro-label — the measured voice. A short ember rule leads it in;
   centred headers drop the rule so the axis stays clean. */
.kicker{display:inline-flex;align-items:center;gap:10px;font-family:var(--mono);
  font-size:11px;font-weight:500;letter-spacing:.28em;text-transform:uppercase;
  color:var(--ink-3)}
.kicker::before{content:"";width:20px;height:1px;background:var(--flame-3);
  opacity:.85;flex:none}
.sec-head.center .kicker::before,.s-eyebrow::before{display:none}
/* No gradient text anywhere: the accent word is solid ember at the same
   weight — colour is the only emphasis. Ink, not effects. */
.grad{color:var(--ember)}

/* Reveal on scroll. Scoped to `.js` — set by the script right before the
   observer is wired — so the page is never left blank if the script fails to
   run, fails to parse, or the browser has no IntersectionObserver. */
.js [data-reveal]{opacity:0;transform:translateY(22px);
  transition:opacity .85s var(--expo) var(--d,0ms),transform .85s var(--expo) var(--d,0ms)}
.js [data-reveal].in{opacity:1;transform:none}

/* ══════════════════════════════════════════════════════════ LANDING ═══ */
.lp{position:relative;overflow-x:clip}
.lp::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(70vw 60vh at 78% -6%,rgba(217,111,51,.09),transparent 62%),
    radial-gradient(60vw 50vh at 4% 32%,rgba(120,92,60,.06),transparent 65%),
    var(--bg)}

/* ─────────────────────────────────────────────────────────── mast ─── */
/* No chrome bar. The note writes itself in above the cabinet, the wordmark
   sits under it, and sign-in is a whisper on the same axis. */
.lp-mast{position:relative;z-index:3;flex:none;display:flex;flex-direction:column;align-items:center;
  gap:16px;margin:0 auto clamp(26px,3.6vh,44px);padding:0 var(--gut);text-align:center}
.lp-mast-brand{flex-direction:column;align-items:center;gap:8px;justify-content:center}
.lp-mast-brand .mark-img{width:clamp(18px,2.2vw,22px)}
.lp-mast-brand .word-img{width:min(280px,68vw);height:auto}
.lp-mast-auth{display:flex;align-items:center;justify-content:center;min-height:1.2em}
.lp-mast-guest{display:inline-flex;align-items:baseline;gap:10px}
.lp-auth{padding:0;border:0;background:none;font-family:var(--serif);font-style:italic;
  font-weight:400;font-size:15px;letter-spacing:.01em;color:rgba(243,238,229,.52);
  transition:color .22s var(--ease)}
.lp-auth:hover,.lp-auth:focus-visible{color:var(--ink-0)}
.lp-auth-sep{color:rgba(243,238,229,.28);font-size:14px;line-height:1;pointer-events:none}
.only-sm{display:none}

/* ──────────────────────────────────────────────────────────── hero ─── */
/* Full-bleed hero. The artwork runs edge to edge; the copy and the set sit
   on the same axis, with the mast as the only mark above the cabinet. */
.hero{position:relative;isolation:isolate;display:block;
  padding:clamp(36px,6vh,72px) 0 clamp(34px,4.4vw,60px)}
.hero-bleed{position:absolute;inset:0;z-index:0;overflow:hidden;pointer-events:none}
.hero-pic,.hero-pic img{position:absolute;inset:0;width:100%;height:100%;display:block}
.hero-pic{z-index:0}
.hero-veil,.hero-glow{z-index:2}
/* right/40% keeps the dancer and the band in frame as the viewport narrows, and
   holds the sunset above the horizon rather than the foliage below it. */
/* The room is shot at night already — lift it a touch rather than grade it
   down. Centred composition now: the lamp and the armchair frame the copy
   and the receiver from both edges. */
.hero-pic img{object-fit:cover;object-position:50% 58%;
  filter:brightness(1.07) saturate(.96);
  transform-origin:50% 52%;
  animation:hero-settle 2.4s var(--expo) both,
            hero-drift 90s var(--ease-io) 2.4s infinite alternate}
/* One settle on load — the frame eases in rather than snapping. Never a loop:
   a hero that keeps moving is a hero you stop reading. */
@keyframes hero-settle{from{transform:scale(1.055);opacity:.55}to{transform:scale(1);opacity:1}}
/* …then a drift so slow it reads as a locked-off shot easing on a dolly:
   five percent of travel across a minute and a half, back again the next.
   Ambience, not signal — reduced-motion stills it like everything else. */
@keyframes hero-drift{to{transform:scale(1.05) translate3d(-.6%,-.9%,0)}}
@keyframes hero-drift-band{to{transform:scale(1.32) translate3d(-1%,-1%,0)}}

/* Legibility for the words only. The dark pool sits up top where the
   headline reads; the cabinet below floats on the living room itself — no
   backdrop behind the radio — and the page takes over in a short fade at
   the very bottom. */
.hero-veil{position:absolute;inset:0;
  background:
    radial-gradient(88% 46% at 50% 15%,rgba(12,10,9,.8) 0%,
                    rgba(12,10,9,.42) 58%,rgba(12,10,9,0) 86%),
    linear-gradient(180deg,rgba(12,10,9,.66) 0%,rgba(12,10,9,.2) 20%,
                    rgba(12,10,9,.1) 40%,rgba(12,10,9,.1) 72%,rgba(12,10,9,0) 82%),
    linear-gradient(0deg,#0C0A09 0%,rgba(12,10,9,.92) 5%,rgba(12,10,9,.55) 12%,
                    rgba(12,10,9,.2) 19%,rgba(12,10,9,0) 27%)}
/* A warm lift where the sun sits, so the ember palette and the artwork agree. */
/* The two lights in the room — the sconce over the shelves and the brass
   lamp by the turntable — swell on offset 9s and 14s periods, so the glow
   never visibly loops. Valve warmth, not a beacon. */
.hero-glow{position:absolute;inset:0;pointer-events:none;
  filter:blur(46px);mix-blend-mode:screen;
  /* --room-glow is the deck's low end (app.js), 0 when silent: the room sits
     a little dimmer until the music plays, then the light leans into it. */
  opacity:calc(.72 + var(--room-glow,0) * .28)}
.hero-glow::before{content:"";position:absolute;right:8%;top:16%;width:38%;height:56%;
  background:radial-gradient(circle at 55% 40%,rgba(224,143,76,.16),transparent 60%);
  animation:lamp-breathe 9s var(--ease-io) infinite alternate}
.hero-glow::after{content:"";position:absolute;left:2%;top:22%;width:34%;height:52%;
  background:radial-gradient(circle at 42% 45%,rgba(233,195,136,.12),transparent 58%);
  animation:lamp-breathe 14s var(--ease-io) -6s infinite alternate}
@keyframes lamp-breathe{from{opacity:.5;transform:scale(.985)}to{opacity:1;transform:scale(1.02)}}

.hero-copy{position:relative;z-index:2;width:100%;max-width:760px;
  margin:0 auto;padding:0 var(--gut);text-align:center}
.hero-copy h1{font-size:clamp(46px,6.8vw,104px)}

@keyframes ping{0%{box-shadow:0 0 0 0 rgba(224,143,76,.6)}70%,100%{box-shadow:0 0 0 9px rgba(224,143,76,0)}}

h1{font-family:var(--display);font-weight:340;letter-spacing:-.022em;line-height:1.02;
  font-size:clamp(44px,6.6vw,100px);margin:22px 0 0;font-optical-sizing:auto;
  font-optical-sizing:auto;font-variation-settings:"opsz" 72;text-wrap:balance}
h1 .ln{display:block}
/* the accent word is Fraunces italic in brass — the prototype's eyebrow device */
h1 .grad{font-style:italic;font-weight:340}

.lede{max-width:44em;margin:20px auto 0;font-size:clamp(15.5px,1.1vw,17.5px);line-height:1.7;
  color:var(--ink-1);font-weight:380;letter-spacing:-.008em}

.cta-row{display:flex;flex-wrap:wrap;gap:12px;margin-top:22px}

/* ────────────────────────────────────────────────── the receiver ─── */
/* The hero's instrument: one hairline plate holding the station presets,
   the deck, and the one honest line about what is free. The active tile
   carries the only colour on the rail — brass means "this one is sounding". */
.receiver{position:relative;z-index:2;width:min(1080px,calc(100% - 2 * var(--gut)));
  margin:clamp(30px,3.8vw,52px) auto 0;padding:16px 18px 10px;
  border:1px solid rgba(255,255,255,.1);border-radius:var(--r-xl);
  background:linear-gradient(180deg,rgba(24,20,16,.82),rgba(13,11,9,.94));
  backdrop-filter:blur(20px) saturate(130%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07),0 60px 120px -50px rgba(0,0,0,.95)}
.receiver .preview{border:0;background:none;box-shadow:none;border-radius:0;
  padding:14px 2px 12px}
.receiver .deck-rail{border-bottom:1px solid var(--line)}
.deck-note{margin:0 2px;padding:10px 2px 8px;border-top:1px solid var(--line);font-size:12.5px;color:var(--ink-3);font-weight:350}
.deck-head{display:flex;align-items:baseline;justify-content:center;gap:14px;
  margin-bottom:14px}
.deck-all{display:inline-flex;align-items:center;gap:7px;font-size:13px;
  color:var(--ink-2);transition:color .2s var(--ease)}
.deck-all:hover{color:var(--ink-0)}
.deck-all .ic{width:14px;height:14px}
.deck-rail{display:grid;grid-auto-flow:column;grid-auto-columns:clamp(96px,9vw,120px);
  gap:13px;overflow-x:auto;padding:4px 4px 14px;margin:0 -4px;
  scroll-snap-type:x proximity;scrollbar-width:none}
.deck-rail::-webkit-scrollbar{display:none}
.st-tile{display:flex;flex-direction:column;gap:8px;text-align:left;
  scroll-snap-align:start;border-radius:var(--r);
  transition:transform .3s var(--expo)}
.st-tile:hover{transform:translateY(-3px)}
.st-tile-art{position:relative;width:100%;aspect-ratio:1;border-radius:var(--r);
  overflow:hidden;border:1px solid var(--line);background:var(--bg-2);
  transition:border-color .25s var(--ease),box-shadow .25s var(--ease)}
.st-tile-art img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .5s var(--expo)}
.st-tile:hover .st-tile-art img{transform:scale(1.045)}
.st-tile-art::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(12,10,9,.06),rgba(12,10,9,.42) 88%)}
.st-i{position:absolute;top:8px;left:9px;z-index:2;font-family:var(--mono);
  font-size:9px;letter-spacing:.14em;color:rgba(243,238,229,.8)}
/* Selection is light, not a border: the chosen tile's art comes up to full
   brightness while the rest sit back. The ember dot and mono line carry
   the rest. */
.st-tile-art img{filter:brightness(.86) saturate(.94);transition:filter .35s var(--ease)}
.st-tile.on .st-tile-art img,.st-tile:hover .st-tile-art img{filter:brightness(1.05) saturate(1)}
.st-tile.on .st-tile-art::after{background:linear-gradient(180deg,rgba(12,10,9,0),rgba(12,10,9,.22) 88%)}
.st-tile-name{font-family:var(--serif);font-size:14.5px;font-weight:500;
  letter-spacing:-.014em;line-height:1.2;color:var(--ink-1);
  font-optical-sizing:auto;transition:color .2s}
.st-tile:hover .st-tile-name,.st-tile.on .st-tile-name{color:var(--ink-0)}
.st-tile-meta{display:inline-flex;align-items:center;gap:6px;
  font-family:var(--mono);font-size:9px;font-weight:500;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3)}
.st-tile.on .st-tile-meta{color:var(--ember)}
.st-tile.on .st-tile-meta::before{content:"";width:5px;height:5px;
  border-radius:50%;background:var(--ember);
  box-shadow:0 0 0 0 rgba(228,174,110,.6);animation:ping 2.2s var(--ease-io) infinite}
/* ─────────────────────────────────────────────── player preview bar ─── */
.preview-wrap{max-width:1320px;margin:0 auto;padding:14px var(--gut) 0}
.preview{display:grid;align-items:center;gap:16px;padding:13px 16px;border-radius:var(--r-lg);
  grid-template-columns:auto minmax(150px,1.1fr) minmax(0,2.6fr) auto auto auto;
  background:linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.02));
  border:1px solid var(--line-2);
  box-shadow:var(--hi),0 30px 70px -40px rgba(0,0,0,1)}
.pv-cover{position:relative;width:52px;height:52px;border-radius:13px;overflow:hidden;flex:none}
/* Falls back to the gradient until the real sleeve loads. */
.pv-cover-art{position:absolute;inset:0;background-size:cover;background-position:center;
  background-color:#3E2413;
  background-image:radial-gradient(circle at 30% 22%,#E9C388,#D96F33 46%,#3E2413 100%);
  transition:background-image .4s var(--ease)}
.pv-cover-art::after{content:"";position:absolute;inset:0;
  background:repeating-linear-gradient(180deg,rgba(0,0,0,.14) 0 2px,transparent 2px 6px)}
/* The play control only dims away once something is actually playing. */
.preview.playing .pv-play{background:rgba(10,8,6,.2)}
.preview.playing .pv-play:hover{background:rgba(10,8,6,.55)}
.preview.playing{border-color:rgba(224,143,76,.3)}
.pv-meta b{transition:color .3s var(--ease)}
.preview.playing .pv-meta b{color:var(--ember)}
.pv-play{position:absolute;inset:0;display:grid;place-items:center;color:#fff;
  background:rgba(10,8,6,.42);backdrop-filter:blur(2px);transition:.2s var(--ease)}
.pv-play:hover{background:rgba(10,8,6,.6)}
.pv-play .ic{width:20px;height:20px}
.pv-meta{min-width:0;display:flex;flex-direction:column;line-height:1.35}
.pv-meta b{font-family:var(--serif);font-size:15px;font-weight:500;letter-spacing:-.018em;
  font-optical-sizing:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pv-meta small{font-size:12px;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pv-wave{position:relative;height:38px;cursor:pointer}
.pv-wave .bars{gap:3px}
.pv-time{font-size:12.5px;color:var(--ink-2);font-variant-numeric:tabular-nums;white-space:nowrap}
.pv-more{margin-left:2px}
/* Keep and favourite are the gate: they open the account dialog. */
.pv-keep{display:flex;align-items:center;gap:4px}
.preview .icon.keep{width:36px;height:36px}
.preview .icon.keep .ic{width:15px;height:15px}

/* Shared waveform primitive. Bars are capped narrow and spread with
   space-between so the shape stays legible at any container width. */
.bars{position:absolute;inset:0;display:flex;align-items:center;justify-content:space-between;gap:2px}
.bars i{flex:1 1 0;min-width:1px;max-width:3.5px;border-radius:99px;
  background:rgba(255,255,255,.16);height:var(--h,40%);transition:background .2s}
.bars.hot{clip-path:inset(0 calc(100% - var(--p,0%)) 0 0)}
.bars.hot i{background:linear-gradient(180deg,var(--ember),var(--flame-1))}

/* ────────────────────────────────────────────────── the statement ─── */
/* An editor's paragraph, not a feature grid. Serif at reading pace, with a
   hairline-ruled row of measured facts underneath — numbers first, mono
   captions after, the way a spec sheet reads. */
.manifesto{max-width:920px}
.manifesto-line{font-family:var(--serif);font-weight:360;
  font-size:clamp(24px,2.9vw,38px);line-height:1.3;
  letter-spacing:-.012em;color:var(--ink-0);text-wrap:pretty}
.manifesto-line em{font-style:italic;font-weight:400;color:var(--flame-3)}
.manifesto-facts{list-style:none;display:grid;grid-template-columns:repeat(3,minmax(0,1fr));
  gap:24px;margin-top:clamp(30px,4vw,48px);padding-top:24px;border-top:1px solid var(--line)}
.manifesto-facts li{display:flex;flex-direction:column;gap:7px}
.manifesto-facts b{font-family:var(--serif);font-size:clamp(23px,2.4vw,31px);font-weight:500;
  letter-spacing:-.02em;line-height:1;font-variant-numeric:tabular-nums;font-optical-sizing:auto}
.manifesto-facts span{font-size:10px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3)}
@media(max-width:640px){
  .manifesto-facts{grid-template-columns:1fr;gap:16px}
  .manifesto-facts li{flex-direction:row;align-items:baseline;gap:12px}
  .manifesto-facts b{min-width:96px}
}

/* ─────────────────────────────────────────────────────── sections ─── */
.sec{position:relative;max-width:1320px;margin:0 auto;padding:clamp(58px,7.4vw,110px) var(--gut)}
.sec.tight{padding-block:clamp(30px,4vw,60px) clamp(34px,4.4vw,68px)}
/* The steps grid already carries its own bottom air — don't stack two full
   section paddings before the closing panel. */
#start{padding-top:clamp(24px,3.4vw,52px)}
.sec-head{max-width:640px;margin-bottom:clamp(34px,4.4vw,60px)}
.sec-head.center{margin-inline:auto;text-align:center}
h2{font-family:var(--display);font-weight:360;letter-spacing:-.015em;line-height:1.12;
  font-size:clamp(34px,4.6vw,58px);margin-top:16px;font-optical-sizing:auto;
  font-optical-sizing:auto;font-variation-settings:"opsz" 48;text-wrap:balance}
.sec-sub{margin-top:18px;color:var(--ink-2);font-size:16.5px;font-weight:380;line-height:1.68}
.sec-head.center .sec-sub{max-width:48ch;margin-inline:auto}

/* pricing */
.price-grid{display:grid;gap:18px;grid-template-columns:repeat(3,minmax(0,1fr))}
.price-card{position:relative;display:flex;flex-direction:column;gap:12px;
  padding:26px 24px 24px;border-radius:var(--r-xl);
  background:linear-gradient(180deg,rgba(255,255,255,.048),rgba(255,255,255,.014));
  border:1px solid var(--line);box-shadow:var(--hi),0 24px 50px -40px rgba(0,0,0,1)}
.price-card h3{font-family:var(--serif);font-size:22px;font-weight:500;letter-spacing:-.022em;
  font-optical-sizing:auto}
.price-amt{font-family:var(--serif);font-size:clamp(40px,4.4vw,54px);font-weight:400;
  letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums;
  font-optical-sizing:auto}
.price-amt small{display:inline-block;margin-left:6px;font-family:var(--sans);
  font-size:15px;font-weight:400;letter-spacing:0;color:var(--ink-2);vertical-align:middle}
.price-blurb{color:var(--ink-2);font-size:14.5px;font-weight:380;line-height:1.62}
.price-card .btn{width:100%;margin-top:auto}
.price-card.recommended{border-color:rgba(228,174,110,.34);
  background:linear-gradient(180deg,rgba(217,111,51,.07),rgba(255,255,255,.02));
  box-shadow:var(--hi),0 34px 70px -44px rgba(0,0,0,.95)}
.price-rec{font-family:var(--mono);font-size:10px;font-weight:500;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ember)}
.price-rules{max-width:640px;margin:clamp(36px,4.6vw,56px) auto 0}
.price-rules h3{font-family:var(--serif);font-size:22px;font-weight:500;letter-spacing:-.02em;
  margin-bottom:16px;text-align:center}
.price-rules ul{list-style:none;display:flex;flex-direction:column;gap:10px}
.price-rules li{position:relative;padding-left:18px;color:var(--ink-1);font-size:15px;
  font-weight:380;line-height:1.55}
.price-rules li::before{content:"";position:absolute;left:0;top:.62em;width:7px;height:7px;
  border-radius:50%;background:var(--flame-3)}
.price-fine{margin-top:18px;color:var(--ink-3);font-size:13.5px;font-weight:380;line-height:1.6;
  text-align:center}
/* The landing shows no price table — the offer lives at /pricing, which
   serves this same shell and reveals only the section below. */
body:not(.pricing-page) #pricing{display:none}
body.pricing-page #landing main{display:flex;flex-direction:column}
body.pricing-page .hero,
body.pricing-page .manifesto,
body.pricing-page #start{display:none !important}
body.pricing-page #pricing{order:-1;padding-top:clamp(120px,14vh,168px)}
.lp-links a[aria-current="page"]{color:var(--ink-0)}
@media(max-width:900px){
  .price-grid{grid-template-columns:1fr}
}

/* ───────────────────────────────────────────────────────────── cta ─── */
/* The closing words sit directly on the page — no plate, no glow, no bars.
   A hairline above is the only structure. */
.cta{position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:30px;padding:clamp(40px,5vw,72px) 0 0;border-top:1px solid var(--line)}
.cta-copy{position:relative;z-index:2}
.cta-copy h2{font-size:clamp(32px,4.2vw,56px);color:var(--ink-0);margin:0}
.cta-copy p{margin-top:14px;font-size:16.5px;color:var(--ink-1);font-weight:380;max-width:38ch}
.cta-btns{position:relative;z-index:2;display:flex;flex-wrap:wrap;gap:12px}

/* ──────────────────────────────────────────────────────────── foot ─── */
.lp-foot{border-top:1px solid var(--line);background:rgba(8,7,6,.6)}
.foot-in{max-width:1320px;margin:0 auto;padding:clamp(40px,5vw,64px) var(--gut) 36px;
  display:flex;align-items:flex-start;justify-content:space-between;gap:28px;flex-wrap:wrap}
.foot-brand p{margin:16px 0 0;font-size:13.5px;color:var(--ink-2);max-width:34ch;line-height:1.6;font-weight:350}
.foot-links{display:flex;align-items:center;gap:28px;padding-top:9px}
.foot-links a{font-size:13.5px;color:var(--ink-2);transition:color .2s}
.foot-links a:hover{color:var(--ink-0)}
.foot-bar{max-width:1320px;margin:0 auto;padding:18px var(--gut) 30px;border-top:1px solid var(--line);
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px;
  font-size:12.5px;color:var(--ink-3)}
.foot-legal{display:flex;align-items:center;gap:18px}
.foot-legal a:hover{color:var(--ink-1)}
.status{display:inline-flex;align-items:center;gap:7px;padding:4px 11px;border-radius:var(--pill);
  border:1px solid var(--line-2);background:var(--surface);color:var(--ink-2);
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase}
.status i{width:6px;height:6px;border-radius:50%;background:var(--ember);
  box-shadow:0 0 0 0 rgba(228,174,110,.6);animation:ping 2.4s var(--ease-io) infinite}

/* ══════════════════════════════════════════════════ ACCESS PANEL (auth) ═══ */
/* Sign in / new library. Hardware from the same cabinet as the hero receiver:
   an engraved rail down the left, a tuning scale across the top whose needle
   reads the mode, a throw switch that sets it, and a pilot lamp that reads the
   form — dark, amber once the fields are filled, working while the request is
   out, red on a fault. Landscape and asymmetric on purpose: the account door
   to this room should look machined for it, not lifted from a component set.

   Everything is namespaced `gate-`. Three sheets load on this page and the last
   one wins any name they share — a bare `.pw` on the password field once lost
   to studio.css and laid the label, input and toggle out in a row. */
.gate{position:fixed;inset:0;z-index:200;display:flex;align-items:center;justify-content:center;
  padding:clamp(20px,5vw,44px);overflow-y:auto;
  background:radial-gradient(76% 60% at 50% 54%,rgba(217,111,51,.11),transparent 64%),rgba(7,6,5,.82);
  backdrop-filter:blur(16px) saturate(115%);animation:fade .28s var(--ease)}
@keyframes fade{from{opacity:0}to{opacity:1}}

.gate-panel{position:relative;margin:auto;width:100%;max-width:760px;isolation:isolate;
  display:grid;grid-template-columns:46px minmax(0,1fr);border-radius:9px;overflow:hidden;
  background:linear-gradient(180deg,#1A1613,#100E0C 58%,#0B0A09);
  border:1px solid rgba(255,255,255,.13);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.09),inset 0 -1px 0 rgba(0,0,0,.9),
             0 60px 120px -50px rgba(0,0,0,1),0 0 100px -34px rgba(217,111,51,.3);
  animation:latch .5s var(--expo)}
/* It doesn't fade up. It seats, like a drawer pushed home. */
@keyframes latch{
  from{opacity:0;transform:translateY(30px)}
  64%{opacity:1;transform:translateY(-4px)}
  to{opacity:1;transform:none}}
/* Brushed metal — a vertical grain too fine to read as a pattern. */
.gate-brush{position:absolute;inset:0;z-index:3;pointer-events:none;border-radius:inherit;
  background:repeating-linear-gradient(90deg,rgba(255,255,255,.016) 0 1px,transparent 1px 3px)}

.gate-rail{position:relative;display:flex;flex-direction:column;align-items:center;
  justify-content:space-between;gap:14px;padding:15px 0 16px;border-radius:8px 0 0 8px;
  background:linear-gradient(90deg,rgba(0,0,0,.42),rgba(0,0,0,.1));
  border-right:1px solid rgba(0,0,0,.6);box-shadow:1px 0 0 rgba(255,255,255,.05)}
.gate-engrave{writing-mode:vertical-rl;transform:rotate(180deg);white-space:nowrap;
  font-family:var(--mono);font-size:9px;letter-spacing:.32em;text-transform:uppercase;
  color:rgba(243,238,229,.26);text-shadow:0 1px 0 rgba(0,0,0,.9)}
.gate-rail .mark-img{width:14px;opacity:.5}

/* The pilot lamp is the panel's only state display: the form reads back on it. */
.gate-lamp{flex:none;width:8px;height:8px;border-radius:50%;background:#241C16;
  box-shadow:inset 0 1px 1px rgba(0,0,0,.9),0 0 0 1px rgba(255,255,255,.07);
  transition:background .35s var(--ease),box-shadow .35s var(--ease)}
.gate.lit .gate-lamp{background:var(--ember);
  box-shadow:0 0 0 1px rgba(255,255,255,.09),0 0 14px 2px rgba(228,174,110,.45)}
.gate.busy .gate-lamp{background:var(--flame-3);animation:lampwork .9s var(--ease-io) infinite}
.gate.fault .gate-lamp{background:var(--heart);
  box-shadow:0 0 0 1px rgba(255,255,255,.09),0 0 14px 2px rgba(206,58,92,.5)}
@keyframes lampwork{0%,100%{opacity:.32}50%{opacity:1}}

.gate-face{position:relative;display:grid;grid-template-columns:minmax(0,.95fr) minmax(0,1fr);
  padding:0 30px 30px}
/* The scale is the readout the switch below drives: ticks across the face and
   one ember needle that swings to the position you threw. */
.gate-scale{grid-column:1/-1;position:relative;height:30px;margin:0 -30px 26px;
  border-bottom:1px solid rgba(0,0,0,.55);box-shadow:0 1px 0 rgba(255,255,255,.05)}
.gate-scale::before{content:"";position:absolute;left:0;right:0;bottom:0;height:8px;
  background:repeating-linear-gradient(90deg,rgba(243,238,229,.22) 0 1px,transparent 1px 10px);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 10%,#000 72%,transparent 90%);
          mask-image:linear-gradient(90deg,transparent,#000 10%,#000 72%,transparent 90%)}
.gate-needle{position:absolute;bottom:-1px;left:26%;width:1.5px;height:17px;border-radius:1px;
  background:linear-gradient(180deg,rgba(217,111,51,0),var(--flame-2) 35%,var(--ember));
  box-shadow:0 0 10px rgba(217,111,51,.85);transition:left .55s var(--expo)}
.gate[data-mode="register"] .gate-needle{left:60%}

.gate-close{position:absolute;top:7px;right:14px;z-index:5;display:grid;place-items:center;
  width:30px;height:30px;border-radius:6px;color:var(--ink-3);
  border:1px solid transparent;transition:.2s var(--ease)}
.gate-close:hover{color:var(--ink-0);background:rgba(255,255,255,.06);border-color:var(--line-2)}
.gate-close .ic{width:15px;height:15px}

.gate-copy{display:flex;flex-direction:column;padding-right:34px}
.gate-read{display:flex;align-items:baseline;gap:8px;font-family:var(--mono);font-size:9.5px;
  letter-spacing:.22em;text-transform:uppercase;color:var(--ink-3)}
.gate-read b{font-weight:500;color:var(--ember)}
.gate-read b::before{content:"— "}
.gate-copy h2{font-family:var(--serif);font-weight:300;font-size:clamp(27px,3.1vw,33px);
  line-height:1.08;letter-spacing:-.022em;margin:15px 0 0;font-optical-sizing:auto}
.gate-sub{margin-top:11px;max-width:28ch;font-size:13px;line-height:1.62;
  color:var(--ink-2);font-weight:350}

/* A throw switch, not a pair of tabs: two engraved legends and one lever. */
.gate-throw{display:flex;align-items:center;gap:13px;margin:24px 0 26px}
.gate-leg{padding:4px 0;font-family:var(--mono);font-size:10px;letter-spacing:.17em;
  text-transform:uppercase;white-space:nowrap;color:var(--ink-3);
  transition:color .28s var(--ease)}
.gate-leg:hover{color:var(--ink-1)}
.gate-leg[aria-pressed="true"]{color:var(--ink-0)}
.gate-slot{position:relative;flex:none;width:50px;height:21px;border-radius:var(--pill);
  background:linear-gradient(180deg,#080706,#151211);border:1px solid rgba(0,0,0,.75);
  box-shadow:inset 0 2px 5px rgba(0,0,0,.9),0 1px 0 rgba(255,255,255,.05)}
.gate-lever{position:absolute;top:2px;left:2px;width:23px;height:15px;border-radius:8px;
  background-color:#DCD4C6;
  background-image:repeating-linear-gradient(90deg,rgba(0,0,0,.14) 0 1px,transparent 1px 4px),
                   linear-gradient(180deg,#F6F1E8,#B4AB9B);
  box-shadow:0 1px 3px rgba(0,0,0,.85),inset 0 1px 0 rgba(255,255,255,.95);
  transition:transform .36s var(--expo)}
.gate[data-mode="register"] .gate-lever{transform:translateX(23px)}

/* The spec plate — measured, not sold, like the facts row on the page. */
.gate-spec{margin-top:auto;border-top:1px solid rgba(0,0,0,.5);
  box-shadow:0 1px 0 rgba(255,255,255,.045)}
.gate-spec div{display:flex;align-items:baseline;justify-content:space-between;gap:14px;
  padding:9px 0;border-bottom:1px solid rgba(255,255,255,.045)}
.gate-spec div:last-child{border-bottom:0}
.gate-spec dt{font-family:var(--mono);font-size:9px;letter-spacing:.2em;text-transform:uppercase;
  color:var(--ink-3)}
.gate-spec dd{font-size:12px;color:var(--ink-1)}

#auth-form{display:flex;flex-direction:column;padding-left:34px;
  border-left:1px solid rgba(0,0,0,.5);box-shadow:inset 1px 0 0 rgba(255,255,255,.05)}
/* Ruled fields, set in the label voice: a line to write on, not a rounded box
   to fill in. The rule and the label light together on focus. */
.gate-rule{position:relative;display:block;margin-bottom:20px}
.gate-k{display:block;margin-bottom:8px;font-family:var(--mono);font-size:9px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--ink-3);transition:color .25s var(--ease)}
.gate-rule input{width:100%;height:32px;padding:0 54px 6px 0;border:0;border-radius:0;
  background:none;outline:none;color:var(--ink-0);
  font-family:var(--mono);font-size:14px;letter-spacing:.01em;
  border-bottom:1px solid var(--line-2);
  transition:border-color .25s var(--ease),box-shadow .25s var(--ease)}
.gate-rule input::placeholder{color:rgba(134,126,109,.55)}
.gate-rule input:focus{border-bottom-color:rgba(224,143,76,.8);
  box-shadow:0 1px 0 rgba(217,111,51,.45)}
/* The lit rule and the ember label are the focus indicator here; the global
   focus ring would draw a rounded box around a field that has no box. */
.gate-rule input:focus-visible{outline:none}
.gate-rule:focus-within .gate-k{color:var(--ember)}
.gate-reveal{position:absolute;right:0;bottom:7px;padding:3px 1px;font-family:var(--mono);
  font-size:9px;letter-spacing:.18em;text-transform:uppercase;color:var(--ink-3);
  transition:color .2s var(--ease)}
.gate-reveal:hover{color:var(--ember)}

.gate-fault{min-height:16px;margin-top:auto;padding-top:6px;font-family:var(--mono);
  font-size:10.5px;line-height:1.5;letter-spacing:.04em;color:#E8867B}
.gate-fault:not(:empty)::before{content:"Fault — ";letter-spacing:.18em;
  text-transform:uppercase;color:var(--heart)}
.gate-key{position:relative;display:flex;align-items:center;justify-content:center;gap:11px;
  width:100%;height:48px;margin-top:8px;border-radius:6px;color:#171209;
  background-color:#EDE5D8;background-image:linear-gradient(180deg,#FCF8F1,#DCD3C4);
  font-family:var(--mono);font-size:11px;font-weight:500;letter-spacing:.22em;text-transform:uppercase;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),inset 0 -2px 0 rgba(0,0,0,.22),
             0 12px 26px -14px rgba(0,0,0,.95);
  transition:transform .12s var(--ease),filter .22s var(--ease),box-shadow .12s var(--ease)}
.gate-key:hover{filter:brightness(1.05)}
.gate-key:active{transform:translateY(1px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.7),inset 0 -1px 0 rgba(0,0,0,.2),
             0 6px 14px -12px rgba(0,0,0,.9)}
.gate-key:disabled{opacity:.62;pointer-events:none}
.gate-key .spin{border-color:rgba(23,18,9,.25);border-top-color:#171209}
.gate-fine{margin-top:14px;font-size:11px;line-height:1.6;color:var(--ink-3)}

/* Narrow: the panel stops being a slab in the middle of the room and becomes a
   drawer pulled out of the bottom edge — the rail lies down across the top. */
@media(max-width:760px){
  .gate{padding:0;align-items:flex-end}
  .gate-panel{max-width:none;margin:0;grid-template-columns:minmax(0,1fr);
    border-radius:14px 14px 0 0;border-bottom:0;animation:drawer .46s var(--expo)}
  .gate-rail{flex-direction:row;justify-content:flex-start;gap:12px;padding:11px 56px 11px 16px;
    border-radius:14px 14px 0 0;border-right:0;border-bottom:1px solid rgba(0,0,0,.6);
    background:linear-gradient(180deg,rgba(0,0,0,.42),rgba(0,0,0,.08))}
  .gate-engrave{writing-mode:horizontal-tb;transform:none;letter-spacing:.24em}
  .gate-rail .mark-img{margin-left:auto}
  .gate-face{grid-template-columns:minmax(0,1fr);padding:0 20px 24px}
  .gate-scale{margin:0 -20px 20px}
  .gate-close{top:9px;right:10px;width:40px;height:40px}
  .gate-leg{display:inline-flex;align-items:center;min-height:44px;padding:0}
  .gate-rule input{height:44px}
  .gate-reveal{bottom:0;min-width:44px;padding:14px 2px;text-align:right}
  .gate-copy{padding-right:0}
  .gate-copy h2{font-size:26px}
  .gate-sub{max-width:52ch}
  .gate-spec{display:none}
  #auth-form{margin-top:22px;padding-left:0;border-left:0;box-shadow:none}
  .gate-fault{margin-top:0}
}
@keyframes drawer{from{opacity:0;transform:translateY(64px)}to{opacity:1;transform:none}}

.seg{position:relative;display:flex;gap:4px;padding:4px;border-radius:var(--pill);
  background:rgba(0,0,0,.32);border:1px solid var(--line)}
.seg.tiny{padding:3px;gap:2px}
.seg.tiny button{display:grid;place-items:center;width:32px;height:28px;border-radius:var(--pill);
  color:var(--ink-3);transition:.2s var(--ease)}
.seg.tiny button:hover{color:var(--ink-1)}
.seg.tiny button.active{color:var(--ink-0);background:var(--surface-2)}
.seg.tiny .ic{width:15px;height:15px}
/* The Motion control is the one segmented control carrying words rather than
   icons, so it needs its own metrics — the icon sizing clips the labels. */
#motion-control{width:100%}
#motion-control::before{content:"Motion";flex:none;padding:0 4px 0 8px;align-self:center;
  font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3)}
#motion-control button{width:auto;flex:1;height:26px;padding:0 6px;font-size:11.5px;
  font-weight:500;text-transform:capitalize;letter-spacing:.01em}
#motion-control button.active{color:var(--ember);background:rgba(217,111,51,.14)}

/* The app's own dialogs still use boxed fields — see modals below. */
.field{position:relative;display:flex;flex-direction:column;gap:7px}
.field span{font-size:12px;font-weight:500;color:var(--ink-2);padding-left:2px;letter-spacing:.01em}
.field input{height:46px;padding:0 15px;border-radius:13px;background:rgba(0,0,0,.3);
  border:1px solid var(--line-2);outline:none;font-size:14.5px;color:var(--ink-0);
  transition:border-color .22s var(--ease),box-shadow .22s var(--ease),background .22s}
.field input:focus{border-color:rgba(224,143,76,.5);background:rgba(0,0,0,.42);
  box-shadow:0 0 0 4px rgba(217,111,51,.1)}
.field input::placeholder{color:var(--ink-3)}

/* ══════════════════════════════════════════════════════════ modals ═══ */
/* Borrows the auth card's language so the app has one dialog look rather than
   two. Replaces window.prompt/confirm, which cannot be styled, block the tab,
   and — for the occasion picker — could only return a string, which is why
   choosing one used to mean typing a number from a list. */
.modal{position:fixed;inset:0;z-index:220;display:grid;place-items:center;padding:22px;
  background:rgba(8,7,6,.72);backdrop-filter:blur(14px) saturate(120%);
  animation:fade .22s var(--ease)}
.modal.out{animation:fadeout .18s var(--ease) forwards}
@keyframes fadeout{to{opacity:0}}
.modal-card{position:relative;width:100%;max-width:430px;padding:30px 30px 24px;
  border-radius:var(--r-2xl);background:linear-gradient(180deg,#171310,#0F0D0B);
  border:1px solid var(--line-2);box-shadow:var(--hi),0 50px 110px -40px rgba(0,0,0,1);
  animation:cardin .42s var(--expo);text-align:center}
.modal.out .modal-card{animation:none}
.modal-edge{position:absolute;left:14%;right:14%;top:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(224,143,76,.5),transparent)}
.modal-x{position:absolute;top:12px;right:12px;display:grid;place-items:center;
  width:34px;height:34px;border-radius:50%;color:var(--ink-3);transition:.2s var(--ease)}
.modal-x:hover{color:var(--ink-0);background:var(--surface-2)}
.modal-icon{display:grid;place-items:center;width:46px;height:46px;margin:0 auto 14px;
  border-radius:14px;color:var(--ember);
  background:rgba(217,111,51,.13);border:1px solid rgba(224,143,76,.28)}
.modal-icon.danger{color:#E8867B;background:rgba(224,110,95,.13);
  border-color:rgba(224,110,95,.3)}
.modal-icon .ic{width:21px;height:21px}
.modal-card h3{font-family:var(--serif);font-size:22px;font-weight:500;
  letter-spacing:-.02em;line-height:1.22;font-optical-sizing:auto}
.modal-body{margin-top:8px;font-size:13.5px;line-height:1.55;color:var(--ink-2)}
.modal-card .field{margin-top:18px;text-align:left}

/* The occasion picker. A real list beats a numbered prompt: you read the names
   and click one, and the track count tells you which is which. */
.modal-list{display:flex;flex-direction:column;gap:6px;margin-top:18px;
  max-height:min(46vh,320px);overflow-y:auto;text-align:left}
.modal-opt{display:flex;align-items:baseline;gap:10px;padding:12px 14px;min-height:48px;
  border-radius:13px;border:1px solid var(--line);background:var(--surface);
  color:var(--ink-1);transition:.18s var(--ease);width:100%}
.modal-opt:hover,.modal-opt:focus-visible{border-color:rgba(224,143,76,.42);
  background:var(--surface-2);color:var(--ink-0)}
.modal-opt b{font-size:14px;font-weight:550;flex:1;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.modal-opt em{font-style:normal;font-size:11.5px;color:var(--ink-3);flex:none}

.modal-actions{display:flex;gap:10px;justify-content:flex-end;margin-top:20px}
.modal-actions .btn{min-width:104px;justify-content:center}
.btn.danger{background:linear-gradient(135deg,#D9604C,#E8867B);color:#fff;
  box-shadow:0 12px 30px -14px rgba(224,110,95,.7)}
.btn.danger:hover{filter:brightness(1.06)}
.btn:disabled{opacity:.45;pointer-events:none}
/* The page must not scroll behind an open dialog. */
body.modal-open{overflow:hidden}

@media(max-width:560px){
  .modal{padding:14px;place-items:end center}
  .modal-card{max-width:none;padding:26px 22px 20px;
    border-radius:var(--r-2xl) var(--r-2xl) 0 0}
  .modal-actions{flex-direction:column-reverse}
  .modal-actions .btn{width:100%}
}

/* ═════════════════════════════════════════════════════════════ APP ═══ */
#app{display:grid;height:100dvh;position:relative;overflow:hidden;
  grid-template-columns:var(--side) minmax(0,1fr);
  grid-template-rows:minmax(0,1fr) var(--playerh);
  grid-template-areas:"side main" "player player";background:var(--bg)}
.ambient{position:fixed;inset:0;z-index:0;pointer-events:none;transition:background 1.4s var(--ease);
  background:radial-gradient(80vw 60vh at 84% -14%,rgba(var(--glow),.24),transparent 62%),
             radial-gradient(60vw 46vh at 2% 104%,rgba(var(--glow),.1),transparent 66%)}
.scrim{position:fixed;inset:0;z-index:29;background:rgba(8,7,6,.6);backdrop-filter:blur(4px);
  animation:fade .25s}

/* ──────────────────────────────────────────────────────── sidebar ─── */
.sidebar{grid-area:side;position:relative;z-index:30;display:flex;flex-direction:column;gap:14px;
  padding:20px 12px 16px;overflow:hidden;border-right:1px solid var(--line);
  background:linear-gradient(180deg,rgba(16,13,11,.86),rgba(10,9,8,.94));
  backdrop-filter:blur(22px) saturate(140%)}
.side-top{display:flex;align-items:center;justify-content:space-between;padding:0 8px}
.side-nav{display:flex;flex-direction:column;gap:3px}
.nav{position:relative;display:flex;align-items:center;gap:12px;height:42px;padding:0 13px;
  border-radius:12px;font-size:14px;font-weight:460;letter-spacing:-.01em;color:var(--ink-2);
  transition:.2s var(--ease)}
.nav .ic{width:17px;height:17px}
/* The admin entry is an <a>, not a <button>: keep it looking like its siblings. */
a.nav{text-decoration:none;color:inherit}
.nav:hover{color:var(--ink-0);background:var(--surface)}
.nav.active{color:var(--ink-0);background:var(--surface-2)}
.nav.active::before{content:"";position:absolute;left:0;top:50%;transform:translateY(-50%);
  width:2px;height:20px;border-radius:0 2px 2px 0;background:var(--ember)}
.nav.active .ic{color:var(--ember)}

.side-head{display:flex;align-items:center;justify-content:space-between;padding:6px 12px 0;
  font-size:10.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3)}
.side-head button{display:grid;place-items:center;width:24px;height:24px;border-radius:8px;
  color:var(--ink-3);transition:.2s var(--ease)}
.side-head button:hover{color:var(--flame-3);background:rgba(217,111,51,.12)}
.side-head .ic{width:14px;height:14px}
.playlists{flex:1;min-height:30px;overflow-y:auto;display:flex;flex-direction:column;gap:2px;padding-right:2px}
.pl{display:flex;align-items:center;justify-content:space-between;gap:8px;height:36px;padding:0 13px;
  border-radius:10px;font-size:13.5px;color:var(--ink-2);cursor:pointer;transition:.18s var(--ease)}
.pl span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pl small{flex:none;font-size:11px;color:var(--ink-3);padding:1px 7px;border-radius:99px;
  background:var(--surface);transition:.18s}
.pl .pl-delete{display:grid;place-items:center;width:26px;height:26px;margin-right:-7px;
  border-radius:8px;color:var(--ink-3);opacity:0;transition:.18s var(--ease)}
.pl:hover .pl-delete,.pl:focus-within .pl-delete{opacity:1}
.pl .pl-delete:hover{color:#E8867B;background:rgba(224,110,95,.12)}
.pl .pl-delete .ic{width:13px;height:13px}
.pl:hover{color:var(--ink-0);background:var(--surface)}
.pl.active{color:var(--ink-0);background:var(--surface-2)}
.pl.active small{background:rgba(217,111,51,.16);color:var(--ember)}

.side-foot{display:flex;flex-direction:column;gap:10px;padding-top:14px;border-top:1px solid var(--line)}
.stats{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.stat{display:flex;flex-direction:column;padding:9px 11px;border-radius:11px;line-height:1.25;
  background:var(--surface);border:1px solid var(--line)}
.stat b{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
.stat small{font-size:10px;color:var(--ink-3);letter-spacing:.07em;text-transform:uppercase}
.dropzone{display:flex;align-items:center;gap:11px;padding:12px 13px;border-radius:13px;cursor:pointer;
  border:1px dashed var(--line-3);color:var(--ink-2);transition:.22s var(--ease)}
.dropzone span{display:flex;flex-direction:column;line-height:1.3;min-width:0}
.dropzone b{font-size:13px;font-weight:500;color:var(--ink-1)}
.dropzone small{font-size:10.5px;color:var(--ink-3)}
.dropzone:hover,.dropzone.drag{border-color:rgba(224,143,76,.6);color:var(--ember);
  background:rgba(217,111,51,.08)}
.dropzone:hover b,.dropzone.drag b{color:var(--ember)}
.user-chip{display:flex;align-items:center;gap:6px;padding:8px;border-radius:13px;
  background:var(--surface);border:1px solid var(--line)}
/* The account link carries the avatar + name, so it takes the chip's own
   padding back as its hit area: the whole name area is the target. */
.u-account{display:flex;align-items:center;gap:10px;flex:1;min-width:0;
  margin:-4px;padding:4px;border-radius:10px;color:inherit;text-decoration:none;
  transition:.2s var(--ease)}
.u-account:hover,.u-account:focus-visible{background:rgba(217,111,51,.1)}
.u-account:hover .u-meta b,.u-account:focus-visible .u-meta b{color:var(--ember)}
.u-gear{flex:none;width:15px;height:15px;color:var(--ink-3);opacity:0;
  transition:.2s var(--ease)}
.u-account:hover .u-gear,.u-account:focus-visible .u-gear{opacity:1;color:var(--ember)}
.avatar{display:grid;place-items:center;width:34px;height:34px;border-radius:10px;flex:none;
  color:var(--ember);font-size:13px;font-weight:600;
  background:var(--bg-2);border:1px solid rgba(228,174,110,.3)}
.u-meta{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.3}
.u-meta b{font-size:13px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.u-meta small{font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.user-chip button{display:grid;place-items:center;width:30px;height:30px;border-radius:9px;
  color:var(--ink-3);transition:.2s var(--ease)}
.user-chip button:hover{color:#E8867B;background:rgba(224,110,95,.12)}
.user-chip .ic{width:15px;height:15px}

/* ─────────────────────────────────────────────────────────── main ─── */
main{grid-area:main;position:relative;z-index:1;overflow-y:auto;overflow-x:hidden;scroll-behavior:auto}
.topbar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:12px;
  padding:14px clamp(16px,2.4vw,30px);
  background:rgba(12,10,9,.72);backdrop-filter:blur(20px) saturate(150%);
  border-bottom:1px solid var(--line)}
.search-wrap{position:relative;flex:1;max-width:460px}
.s-ico{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--ink-3);
  width:16px;height:16px;pointer-events:none}
#search{width:100%;height:40px;padding:0 44px 0 40px;border-radius:var(--pill);
  background:var(--surface);border:1px solid var(--line);outline:none;font-size:14px;
  color:var(--ink-0);transition:.22s var(--ease)}
#search::placeholder{color:var(--ink-3)}
#search::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
#search:focus{border-color:rgba(224,143,76,.45);background:rgba(255,255,255,.06);
  box-shadow:0 0 0 4px rgba(217,111,51,.08)}
.s-kbd{position:absolute;right:10px;top:50%;transform:translateY(-50%);display:grid;place-items:center;
  min-width:22px;height:22px;padding:0 6px;border-radius:6px;font-size:11px;font-family:var(--sans);
  color:var(--ink-3);background:rgba(255,255,255,.05);border:1px solid var(--line-2);pointer-events:none}
#search:focus + .s-kbd{opacity:0}
.top-right{display:flex;align-items:center;gap:9px;margin-left:auto}
.select-wrap{position:relative}
.select-wrap select{appearance:none;-webkit-appearance:none;height:36px;max-width:170px;
  padding:0 34px 0 14px;border-radius:var(--pill);
  background:var(--surface);border:1px solid var(--line);color:var(--ink-1);font-size:13px;
  outline:none;cursor:pointer;transition:.2s var(--ease)}
.select-wrap select:hover{border-color:var(--line-3);color:var(--ink-0)}
.select-wrap select option{background:#14110E;color:var(--ink-0)}
.genre-filter select{max-width:150px}
.sel-ico{position:absolute;right:12px;top:50%;width:13px;height:13px;color:var(--ink-3);
  transform:translateY(-50%) rotate(90deg);pointer-events:none}

.view{padding:clamp(22px,3vw,36px) clamp(16px,2.4vw,30px) 44px;
  animation:viewin .5s var(--expo) both}
@keyframes viewin{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.view-head{display:flex;align-items:flex-end;justify-content:space-between;gap:20px;flex-wrap:wrap;
  margin-bottom:26px}
.vh-copy{min-width:0}
main h1{font-family:var(--display);font-weight:360;letter-spacing:-.015em;line-height:1.1;
  font-size:clamp(30px,3.4vw,46px);margin-top:12px;font-optical-sizing:auto;
  font-optical-sizing:auto;font-variation-settings:"opsz" 48;text-wrap:balance}
.sub{margin-top:9px;font-size:13.5px;color:var(--ink-2)}
.vh-btns{display:flex;align-items:center;gap:10px;flex-wrap:wrap}

/* ────────────────────────────────────────────────────── tracklist ─── */
.tracklist-head,.tr{display:grid;gap:14px;align-items:center;
  grid-template-columns:32px 46px minmax(0,2.4fr) minmax(0,1.5fr) 58px 148px}
.tracklist-head{padding:0 14px 10px;border-bottom:1px solid var(--line);
  font-size:10.5px;font-weight:600;letter-spacing:.15em;text-transform:uppercase;color:var(--ink-3)}
.tracklist-head span:nth-child(1){text-align:right}
.tracklist-head span:nth-child(5){display:grid;justify-content:end}
.tracklist-head .ic{width:14px;height:14px}
.tracklist{display:flex;flex-direction:column;gap:2px;margin-top:6px}
.tr{position:relative;padding:8px 14px;border-radius:14px;cursor:pointer;
  border:1px solid transparent;transition:background .2s var(--ease),border-color .2s var(--ease);
  animation:rowin .45s var(--expo) both}
@keyframes rowin{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}
.tr:hover{background:var(--surface);border-color:var(--line)}
.tr.playing{background:linear-gradient(90deg,rgba(var(--glow),.16),rgba(var(--glow),.03));
  border-color:rgba(var(--glow),.3)}
.tr.playing .t-title{color:var(--a2)}
.t-idx{font-size:12.5px;color:var(--ink-3);text-align:right;font-variant-numeric:tabular-nums}
.t-art{position:relative;width:46px;height:46px;border-radius:11px;overflow:hidden;flex:none;
  background:linear-gradient(140deg,#2A231B,#161210);border:1px solid var(--line)}
/* The cover has to be positioned too — an absolutely positioned placeholder
   would otherwise paint over an in-flow image regardless of source order. */
.t-art img{position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:cover}
.t-art .ph{position:absolute;inset:0;z-index:0;display:grid;place-items:center;color:var(--ink-3)}
.t-art .ph .ic{width:18px;height:18px}
.t-art .ov{position:absolute;inset:0;z-index:2;display:grid;place-items:center;color:#fff;opacity:0;
  background:rgba(10,9,8,.55);backdrop-filter:blur(2px);transition:opacity .2s var(--ease)}
.t-art .ov .ic{width:18px;height:18px}
.tr:hover .t-art .ov{opacity:1}
.t-main{min-width:0}
.t-title{display:flex;align-items:center;gap:8px;font-size:14.5px;font-weight:500;
  letter-spacing:-.014em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.t-title span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.t-byline{display:flex;align-items:center;gap:7px;min-width:0;margin-top:2px;
  white-space:nowrap;overflow:hidden;color:var(--ink-3);font-size:11.5px}
.t-byline > span{min-width:0;overflow:hidden;text-overflow:ellipsis}
.t-byline > span + span::before{content:"·";margin-right:7px;color:var(--ink-3)}
.t-artist,.t-album{font-size:12.5px;color:var(--ink-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.t-byline .t-artist{flex:0 1 auto}
.t-fact{flex:none;color:var(--ink-3);font-variant-numeric:tabular-nums}
.t-album{color:var(--ink-3)}
.t-dur{font-size:12.5px;color:var(--ink-3);text-align:right;font-variant-numeric:tabular-nums}
.t-actions{display:flex;gap:3px;justify-content:flex-end;opacity:0;transition:opacity .2s var(--ease)}
.tr:hover .t-actions,.tr.playing .t-actions,.tr:focus-within .t-actions{opacity:1}
.t-actions button{display:grid;place-items:center;width:32px;height:32px;border-radius:10px;
  color:var(--ink-3);transition:.18s var(--ease)}
.t-actions button:hover{color:var(--ink-0);background:var(--surface-2);transform:scale(1.08)}
.t-actions button.on{color:var(--flame-2)}
.t-actions button.fav.on{color:var(--heart)}
.t-actions button.on .ic{fill:currentColor}
.t-actions .ic{width:16px;height:16px}
.badge{position:relative;flex:none;padding:2px 7px;border-radius:99px;font-size:9.5px;font-weight:700;letter-spacing:.1em;
  color:var(--ember);background:rgba(217,111,51,.14);border:1px solid rgba(224,143,76,.3)}
.badge::after{content:"";position:absolute;width:44px;height:44px;left:50%;top:50%;
  transform:translate(-50%,-50%)}
.badge:hover,.badge:focus-visible{background:rgba(217,111,51,.24);color:#fff}

/* A single body-level tooltip stays clear of the library's clipped scroll area
   and the grid's right edge. It mirrors aria-label visually; assistive tech uses
   the button's real accessible name and ignores this decorative portal. */
.track-action-tooltip{position:fixed;z-index:320;max-width:min(220px,calc(100vw - 16px));
  padding:7px 10px;border:1px solid rgba(255,255,255,.13);border-radius:9px;
  background:rgba(19,16,13,.96);backdrop-filter:blur(12px) saturate(135%);
  box-shadow:0 10px 28px -12px rgba(0,0,0,.95),inset 0 1px rgba(255,255,255,.045);
  color:var(--ink-1);font-size:11.5px;font-weight:500;line-height:1.2;letter-spacing:.005em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none;
  opacity:0;visibility:hidden;transform:translateY(3px) scale(.985);
  transform-origin:var(--tip-arrow-x,50%) bottom;
  transition:opacity .14s var(--ease),transform .14s var(--ease),visibility 0s linear .14s}
.track-action-tooltip.show{opacity:1;visibility:visible;transform:none;transition-delay:0s}
.track-action-tooltip::after{content:"";position:absolute;left:var(--tip-arrow-x,50%);bottom:-4px;
  width:7px;height:7px;border-right:1px solid rgba(255,255,255,.13);
  border-bottom:1px solid rgba(255,255,255,.13);background:rgba(19,16,13,.96);
  transform:translateX(-50%) rotate(45deg)}
.track-action-tooltip[data-side="bottom"]{transform:translateY(-3px) scale(.985);
  transform-origin:var(--tip-arrow-x,50%) top}
.track-action-tooltip[data-side="bottom"].show{transform:none}
.track-action-tooltip[data-side="bottom"]::after{top:-4px;bottom:auto;
  border:0;border-left:1px solid rgba(255,255,255,.13);
  border-top:1px solid rgba(255,255,255,.13)}
.eqbars{display:inline-flex;align-items:flex-end;gap:2.5px;height:14px;justify-content:flex-end;width:100%}
@keyframes markbop{from{transform:scaleY(.42)}to{transform:scaleY(1)}}
.eqbars i{width:2.5px;border-radius:2px;background:var(--a2);
  animation:markbop .8s var(--ease-io) infinite alternate}
.eqbars i:nth-child(1){height:6px}
.eqbars i:nth-child(2){height:14px;animation-delay:-.28s}
.eqbars i:nth-child(3){height:9px;animation-delay:-.55s}

/* grid mode */
.tracklist.grid{display:grid;gap:20px;margin-top:22px;
  grid-template-columns:repeat(auto-fill,minmax(162px,1fr))}
.tracklist.grid .tr{display:flex;flex-direction:column;align-items:stretch;gap:0;padding:12px;
  border-radius:var(--r-lg);background:var(--surface);border-color:var(--line)}
.tracklist.grid .tr:hover{transform:translateY(-4px);background:var(--surface-2)}
.tracklist.grid .t-idx,.tracklist.grid .t-album,.tracklist.grid .t-dur{display:none}
.tracklist.grid .t-art{width:100%;height:auto;aspect-ratio:1;border-radius:14px;margin-bottom:12px}
.tracklist.grid .t-title{font-size:13.5px}
.tracklist.grid .t-artist{font-size:12px;margin-top:2px}
.tracklist.grid .t-actions{position:absolute;z-index:3;top:18px;right:18px;flex-direction:column;
  padding:3px;border-radius:12px;background:rgba(10,9,8,.72);backdrop-filter:blur(10px)}
.tracklist.grid .t-actions button{width:28px;height:28px}

.skeleton{display:flex;flex-direction:column;gap:2px;margin-top:6px}
.sk-row{height:63px;border-radius:14px;
  background:linear-gradient(100deg,rgba(255,255,255,.035) 28%,rgba(255,255,255,.075) 48%,rgba(255,255,255,.035) 68%);
  background-size:240% 100%;animation:shim 1.5s linear infinite}
@keyframes shim{to{background-position:-240% 0}}

.empty{text-align:center;padding:56px 20px 40px;animation:viewin .5s var(--expo) both}
.empty-art{position:relative;display:grid;place-items:center;width:118px;height:118px;margin:0 auto 24px}
.ea-ring{position:absolute;inset:0;border-radius:50%;border:1px solid var(--line-2);
  background:radial-gradient(circle at 50% 50%,rgba(217,111,51,.14),transparent 68%)}
.ea-ring::after{content:"";position:absolute;inset:-14px;border-radius:50%;
  border:1px solid rgba(255,255,255,.05);animation:pulse-ring 3.4s var(--ease-io) infinite}
@keyframes pulse-ring{0%,100%{transform:scale(1);opacity:.6}50%{transform:scale(1.08);opacity:.2}}
.ea-eq{position:relative;display:flex;align-items:flex-end;gap:4px;height:44px}
.ea-eq i{width:5px;border-radius:3px;background:linear-gradient(180deg,var(--ember),var(--flame-1));
  transform-origin:bottom;animation:eqrise 1.6s var(--ease-io) infinite alternate}
.ea-eq i:nth-child(1){height:16px;animation-duration:1.4s}
.ea-eq i:nth-child(2){height:28px;animation-duration:1.9s;animation-delay:-.5s}
.ea-eq i:nth-child(3){height:40px;animation-duration:1.2s;animation-delay:-.9s}
.ea-eq i:nth-child(4){height:24px;animation-duration:1.7s;animation-delay:-.3s}
.ea-eq i:nth-child(5){height:36px;animation-duration:1.35s;animation-delay:-1.1s}
.ea-eq i:nth-child(6){height:20px;animation-duration:2s;animation-delay:-.7s}
.ea-eq i:nth-child(7){height:13px;animation-duration:1.55s;animation-delay:-1.4s}
.empty h2{font-size:25px;margin-bottom:10px}
.empty p{max-width:40ch;margin:0 auto 24px;color:var(--ink-2);font-size:14.5px;font-weight:350}
.empty-btns{display:flex;gap:11px;justify-content:center;flex-wrap:wrap}

/* ─────────────────────────────────────────────────────── generate ─── */
.gen-grid{display:grid;gap:13px;margin-bottom:22px;
  grid-template-columns:repeat(auto-fill,minmax(232px,1fr))}
.style{position:relative;padding:18px;border-radius:var(--r-lg);cursor:pointer;overflow:hidden;
  background:var(--surface);border:1px solid var(--line);box-shadow:var(--hi);
  transition:transform .35s var(--expo),border-color .25s var(--ease),background .25s}
.style::before{content:"";position:absolute;left:0;right:0;top:0;height:3px;
  background:linear-gradient(90deg,var(--c1),var(--c2));opacity:.75;transition:opacity .25s}
.style:hover{transform:translateY(-3px);border-color:var(--line-3);background:var(--surface-2)}
.style.sel{border-color:rgba(228,174,110,.42);background:rgba(217,111,51,.06);
  box-shadow:var(--hi),0 20px 40px -28px rgba(0,0,0,.9)}
.style.sel::before{opacity:1;height:4px}
.style b{display:block;font-size:15px;font-weight:550;letter-spacing:-.018em;margin-bottom:6px}
.style span{display:block;font-size:12.5px;line-height:1.5;color:var(--ink-2);font-weight:350}
.style .tick{position:absolute;top:14px;right:14px;display:grid;place-items:center;width:22px;height:22px;
  border-radius:50%;color:#171209;opacity:0;transform:scale(.6);
  background:var(--ink-0);transition:.3s var(--expo)}
.style .tick .ic{width:13px;height:13px;stroke-width:2.6}
.style.sel .tick{opacity:1;transform:none}

.gen-bar{display:flex;gap:12px;align-items:center;flex-wrap:wrap}
.gen-input{position:relative;flex:1;min-width:240px;display:flex;align-items:center;gap:10px;
  height:53px;padding:0 18px;border-radius:var(--pill);background:var(--surface);
  border:1px solid var(--line-2);transition:.22s var(--ease)}
.gen-input .ic{width:17px;height:17px;color:var(--flame-3);flex:none}
.gen-input input{flex:1;min-width:0;background:none;border:0;outline:none;font-size:14.5px;color:var(--ink-0)}
.gen-input input::placeholder{color:var(--ink-3)}
.gen-input:focus-within{border-color:rgba(224,143,76,.45);background:rgba(255,255,255,.06);
  box-shadow:0 0 0 4px rgba(217,111,51,.08)}
.gen-fine{margin-top:14px;font-size:12.5px;color:var(--ink-3);font-weight:350}
.jobs-head{margin:34px 0 12px;font-size:10.5px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-3)}
.jobs{display:flex;flex-direction:column;gap:8px}
.job{position:relative;display:flex;align-items:center;gap:13px;padding:14px 18px;border-radius:var(--r);
  background:var(--surface);border:1px solid var(--line);font-size:13.5px;overflow:hidden;
  animation:rowin .45s var(--expo) both}
.job.busy::after{content:"";position:absolute;left:0;bottom:0;height:2px;width:34%;
  background:linear-gradient(90deg,transparent,var(--flame-3),transparent);
  animation:sweep 1.9s var(--ease-io) infinite}
@keyframes sweep{from{transform:translateX(-100%)}to{transform:translateX(400%)}}
.st{flex:none;padding:4px 11px;border-radius:99px;font-size:9.5px;font-weight:700;letter-spacing:.1em;
  text-transform:uppercase}
.st.queued{color:var(--ink-1);background:rgba(255,255,255,.1)}
.st.running{color:var(--ember);background:rgba(217,111,51,.16);border:1px solid rgba(224,143,76,.3)}
.st.done{color:#7BCFA5;background:rgba(116,196,156,.13);border:1px solid rgba(116,196,156,.28)}
.st.failed{color:#E8867B;background:rgba(224,110,95,.13);border:1px solid rgba(224,110,95,.3)}
.job .who{font-weight:500}
.job .msg{margin-left:auto;max-width:52%;font-size:12.5px;color:var(--ink-3);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* ══════════════════════════════════════════════════════════ player ═══ */
.player{grid-area:player;position:relative;z-index:40;display:grid;align-items:center;gap:16px;
  grid-template-columns:minmax(0,1fr) minmax(330px,1.55fr) minmax(0,1fr);
  padding:0 clamp(14px,2vw,26px);
  background:rgba(10,9,8,.9);backdrop-filter:blur(34px) saturate(165%);
  border-top:1px solid rgba(255,255,255,.08);
  box-shadow:0 -18px 40px -30px rgba(0,0,0,.85)}
.p-line{position:absolute;left:0;top:-1px;height:2px;width:0;pointer-events:none;
  background:linear-gradient(90deg,var(--a1),var(--a2));
  box-shadow:0 0 12px rgba(var(--glow),.8);transition:width .1s linear}
.p-left{display:flex;align-items:center;gap:10px;min-width:0}
.p-keep{display:flex;align-items:center;gap:2px;flex:none}
.now{display:flex;align-items:center;gap:13px;min-width:0;cursor:pointer;border-radius:14px;
  padding:4px;margin:-4px;transition:background .2s}
.now:hover{background:var(--surface)}
.art-wrap{position:relative;width:56px;height:56px;border-radius:13px;overflow:hidden;flex:none;
  background:linear-gradient(140deg,#2A231B,#161210);border:1px solid var(--line-2);
  transition:transform .3s var(--expo)}
.now:hover .art-wrap{transform:scale(1.04)}
.art-wrap img{position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:cover}
.art-fallback{position:absolute;inset:0;z-index:0;display:grid;place-items:center;color:var(--ink-3)}
.art-fallback .ic{width:22px;height:22px}
.art-fallback.big .ic{width:74px;height:74px;stroke-width:.9}
.art-wrap .expand{position:absolute;inset:0;z-index:2;display:grid;place-items:center;color:#fff;opacity:0;
  background:rgba(10,9,8,.55);backdrop-filter:blur(2px);transition:opacity .22s var(--ease)}
.art-wrap .expand .ic{width:18px;height:18px}
.now:hover .expand{opacity:1}
.now-meta{min-width:0}
.p-title-row{display:flex;align-items:center;gap:7px;min-width:0}
.p-title-row .p-title{min-width:0}
.p-title{font-family:var(--serif);font-size:15.5px;font-weight:500;letter-spacing:-.02em;
  font-optical-sizing:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.p-source-mark{flex:none;min-width:16px;padding:1px 4px;border:1px solid rgba(228,174,110,.2);
  border-radius:999px;color:rgba(228,174,110,.58);background:rgba(228,174,110,.035);
  font:650 8px/1.35 ui-monospace,"SF Mono",Menlo,monospace;letter-spacing:.06em;
  text-align:center}
.p-artist{font-size:12.5px;color:var(--ink-2);letter-spacing:-.004em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.controls{display:flex;flex-direction:column;align-items:center;gap:7px;width:100%;min-width:0}
.buttons{display:flex;align-items:center;gap:6px}
.icon{position:relative;display:grid;place-items:center;width:36px;height:36px;border-radius:50%;
  color:var(--ink-2);transition:.2s var(--ease);flex:none}
.icon .ic{width:17px;height:17px}
.icon:hover{color:var(--ink-0);background:var(--surface-2)}
.icon.on{color:var(--flame-3)}
.icon.on::after{content:"";position:absolute;bottom:3px;left:50%;transform:translateX(-50%);
  width:3px;height:3px;border-radius:50%;background:currentColor}
.icon.fav .ic{width:19px;height:19px}
.icon.fav.on{color:var(--heart)}
.icon.fav.on .ic{fill:currentColor;stroke:currentColor}
.icon.fav.on::after{display:none}
/* Keep is the one brass control on the transport: a hairline ring, not a jewel. */
.icon.keep{width:40px;height:40px;color:var(--ember);
  border:1px solid rgba(228,174,110,.38);background:rgba(228,174,110,.06)}
.icon.keep .ic{width:16px;height:16px}
.icon.keep:hover{color:var(--gold);border-color:rgba(237,210,166,.6);
  background:rgba(228,174,110,.12);transform:translateY(-1px)}
.icon.keep:active{transform:translateY(0) scale(.96)}
.icon.keep:focus-visible{outline-color:var(--gold)}
.buttons.big .icon.keep{width:48px;height:48px}
.buttons.big .icon.keep .ic{width:18px;height:18px}
.icon.purge{color:var(--ink-3)}
.icon.purge:hover{color:#E8867B;background:rgba(224,110,95,.1)}
.icon.sm{width:30px;height:30px}
.icon.sm .ic{width:15px;height:15px}
.icon.play{width:44px;height:44px;color:#171209;background:var(--ink-0);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5),0 10px 24px -12px rgba(0,0,0,.9)}
.icon.play .ic{width:19px;height:19px}
.icon.play:hover{transform:scale(1.05);background:#FFFDF8;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.6),0 14px 30px -12px rgba(0,0,0,.95)}
.icon.play:active{transform:scale(.97)}
.icon.play.lg{width:70px;height:70px}
.icon.play.lg .ic{width:28px;height:28px}

.seek{display:flex;align-items:center;gap:12px;width:100%;font-size:11.5px;color:var(--ink-3);
  font-variant-numeric:tabular-nums}
.bar{position:relative;flex:1;height:16px;display:flex;align-items:center;cursor:pointer;min-width:0}
.bar::before{content:"";position:absolute;left:0;right:0;height:5px;border-radius:99px;
  background:rgba(255,255,255,.1);transition:height .18s var(--ease)}
.bar:hover::before{height:7px}
.bar .buf{position:absolute;left:0;height:5px;width:0;border-radius:99px;background:rgba(255,255,255,.09);
  transition:height .18s var(--ease),width .3s linear}
.bar:hover .buf{height:7px}
.bar .fill{position:absolute;left:0;height:5px;width:0;border-radius:99px;
  background:linear-gradient(90deg,var(--a1),var(--a2));transition:height .18s var(--ease),width .1s linear;
  box-shadow:0 0 14px -2px rgba(var(--glow),.8)}
.bar:hover .fill{height:7px}
.bar .knob{position:absolute;right:-6px;top:50%;width:13px;height:13px;border-radius:50%;background:#fff;
  transform:translateY(-50%) scale(0);transition:transform .2s var(--expo);
  box-shadow:0 2px 8px rgba(0,0,0,.6)}
.bar:hover .knob,.bar:focus-visible .knob{transform:translateY(-50%) scale(1)}

/* With a real envelope mounted, the flat gradient track steps aside and the
   canvases become the control. The fill element stays for the knob alone. */
.bar.has-wave{height:32px}
.bar.has-wave::before,.bar.has-wave .buf{opacity:0}
.bar.has-wave .fill{height:100%;background:none;box-shadow:none;border-radius:0}
.bar.has-wave .knob{right:-5px;width:11px;height:11px;
  transform:translateY(-50%) scale(1);box-shadow:0 0 10px rgba(var(--glow),.9),0 2px 6px rgba(0,0,0,.7)}
.stage-seek .bar.has-wave{height:46px}
@media(max-width:780px){.bar.has-wave{height:26px}}

.extras{display:flex;align-items:center;gap:12px;justify-content:flex-end;min-width:0}
#viz{width:120px;height:30px;flex:none;opacity:.9}
.vol{display:flex;align-items:center;gap:7px}
#p-vol{width:84px;height:5px;appearance:none;-webkit-appearance:none;border-radius:99px;padding:0;border:0;
  cursor:pointer;outline:none;background-color:rgba(255,255,255,.14);
  background-image:linear-gradient(90deg,var(--a1),var(--a2));
  background-size:var(--v,100%) 100%;background-repeat:no-repeat}
#p-vol::-webkit-slider-thumb{-webkit-appearance:none;width:13px;height:13px;border-radius:50%;
  background:#fff;box-shadow:0 1px 5px rgba(0,0,0,.6);transition:transform .16s var(--ease)}
#p-vol:hover::-webkit-slider-thumb{transform:scale(1.18)}
#p-vol::-moz-range-thumb{width:13px;height:13px;border:0;border-radius:50%;background:#fff}

/* ═══════════════════════════════════════════════════════ immersive ═══ */
.stage{position:fixed;inset:0;z-index:120;display:grid;place-items:center;overflow:hidden;
  background:#080706;animation:fade .4s var(--ease)}
.stage-bg{position:absolute;inset:-14%;filter:blur(90px) saturate(1.7);opacity:.6;
  transition:background 1.1s var(--ease)}
.stage-veil{position:absolute;inset:0;
  background:radial-gradient(120% 80% at 50% 0%,transparent 20%,rgba(5,7,14,.75) 78%)}
.stage-close{position:absolute;top:22px;right:26px;z-index:4;display:grid;place-items:center;
  width:42px;height:42px;border-radius:50%;color:var(--ink-1);
  background:rgba(255,255,255,.06);border:1px solid var(--line-2);backdrop-filter:blur(10px);
  transition:.2s var(--ease)}
.stage-close:hover{color:#fff;background:rgba(255,255,255,.12);transform:rotate(90deg)}
.stage-inner{position:relative;z-index:3;display:grid;align-items:center;width:100%;max-width:1120px;
  grid-template-columns:minmax(0,auto) minmax(0,1fr);gap:clamp(26px,5vw,66px);
  padding:clamp(24px,4vw,44px)}
.stage-art{position:relative;width:clamp(220px,26vw,360px);aspect-ratio:1;border-radius:var(--r-2xl);
  overflow:hidden;background:linear-gradient(140deg,#2A231B,#161210);
  border:1px solid rgba(255,255,255,.14);
  box-shadow:0 60px 120px -40px rgba(0,0,0,1),inset 0 1px 0 rgba(255,255,255,.16);
  animation:artin .7s var(--expo) both}
@keyframes artin{from{opacity:0;transform:translateY(20px) scale(.96)}to{opacity:1;transform:none}}
/* Covers vary in ratio (FlowState renders 16:9) — contain the real image and
   fill the square behind it with a blurred copy so nothing gets cropped. */
.stage-art .art-blur{position:absolute;inset:-18%;width:136%;height:136%;object-fit:cover;
  filter:blur(30px) saturate(1.5);opacity:.8}
.stage-art img#s-art{position:relative;z-index:1;width:100%;height:100%;object-fit:contain}
.stage-meta{min-width:0;animation:artin .7s .08s var(--expo) both}
.s-eyebrow{display:inline-flex;align-items:center;gap:8px;font-size:11px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--flame-3);margin-bottom:16px}
.stage-meta h2{font-size:clamp(30px,4.6vw,60px);line-height:1.03;margin:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stage-meta p{margin-top:12px;font-size:16px;color:var(--ink-2);font-weight:350}
.track-feedback{display:flex;align-items:center;gap:12px;min-height:38px;margin-top:18px;
  color:var(--ink-2);font-size:12.5px}
.feedback-question{font-weight:550;color:var(--ink-1);white-space:nowrap}
.feedback-verdicts{display:flex;align-items:center;padding:3px;border-radius:10px;
  background:rgba(255,255,255,.05);border:1px solid var(--line-2)}
.feedback-verdicts button{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  height:32px;padding:0 11px;border-radius:7px;color:var(--ink-2);font-size:12px;
  transition:.18s var(--ease)}
.feedback-verdicts button .ic{width:13px;height:13px}
.feedback-verdicts button:hover{color:var(--ink-0);background:rgba(255,255,255,.06)}
.feedback-verdicts button[data-feedback-verdict="connects"].active{color:#7BCFA5;
  background:rgba(116,196,156,.13)}
.feedback-verdicts button[data-feedback-verdict="misses"].active{color:#E8867B;
  background:rgba(224,110,95,.13)}
.feedback-aspects{display:flex;align-items:center;gap:9px;min-width:0}
.feedback-aspects > span{color:var(--ink-3);white-space:nowrap}
.feedback-aspects > div{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
.feedback-aspects button{height:28px;padding:0 9px;border-radius:8px;color:var(--ink-3);
  background:rgba(255,255,255,.035);border:1px solid var(--line);font-size:11.5px;
  transition:.18s var(--ease)}
.feedback-aspects button:hover{color:var(--ink-1);border-color:var(--line-3)}
.feedback-aspects button.active{color:var(--ember);border-color:rgba(224,143,76,.4);
  background:rgba(217,111,51,.12)}
.track-feedback button:disabled{cursor:wait;opacity:.72}
#s-viz{width:100%;height:74px;margin:26px 0 12px;opacity:.95}
.stage-seek{margin-bottom:26px;font-size:12.5px}
.buttons.big{gap:14px}
.buttons.big .icon{width:50px;height:50px}
.buttons.big .icon .ic{width:20px;height:20px}
.stage-geek{margin-top:18px}

/* ════════════════════════════════════════════════════════════ toast ═══ */
.toast{position:fixed;left:50%;bottom:calc(var(--playerh) + 22px);z-index:250;
  display:flex;align-items:center;gap:10px;padding:12px 20px;border-radius:var(--pill);
  font-size:13.5px;font-weight:450;letter-spacing:-.008em;color:var(--ink-0);
  background:rgba(16,13,11,.94);backdrop-filter:blur(24px) saturate(160%);
  border:1px solid rgba(255,255,255,.1);box-shadow:var(--hi),0 24px 50px -22px rgba(0,0,0,1);
  opacity:0;transform:translate(-50%,14px) scale(.97);pointer-events:none;
  transition:.32s var(--expo)}
.toast.show{opacity:1;transform:translate(-50%,0) scale(1)}
.toast::before{content:"";width:6px;height:6px;border-radius:50%;flex:none;
  background:var(--flame-3);box-shadow:0 0 10px var(--flame-3)}
.toast.bad::before{background:#E8867B;box-shadow:0 0 10px #E8867B}

/* ══════════════════════════════════════════════════════ responsive ═══ */
@media(max-width:1180px){
  /* Below this there is no clean ground left of the dancer, so the artwork stops
     being a backdrop and becomes a band the copy starts underneath. */
  :root{--hero-band:min(48vh,420px)}
  .hero{min-height:0;display:block;align-items:stretch;
    padding:calc(var(--hero-band) + clamp(18px,3vw,34px)) 0 clamp(34px,5vw,56px)}
  .hero-bleed{inset:0 0 auto 0;height:calc(var(--hero-band) + 110px)}
  /* A short wide band is wider than the source's 16:9, so object-position can no
     longer crop horizontally — the flat left half would fill a third of it.
     Scaling into the dancer is what makes the band read as a composition. */
  .hero-pic img{object-position:76% 46%;transform-origin:74% 48%}
  .hero-pic img{animation:hero-settle-band 2.4s var(--expo) both,
              hero-drift-band 80s var(--ease-io) 2.4s infinite alternate}
  @keyframes hero-settle-band{from{transform:scale(1.4);opacity:.5}to{transform:scale(1.26);opacity:1}}
  .hero-veil{background:
    /* the source's flat navy left edge can enter the band's crop — fade it
       into the page's charcoal before it reads as a second colour */
    linear-gradient(90deg,#0C0A09 0%,rgba(12,10,9,.82) 10%,rgba(12,10,9,.45) 22%,
                    rgba(12,10,9,.14) 32%,rgba(12,10,9,0) 44%),
    linear-gradient(180deg,rgba(12,10,9,.55) 0%,rgba(12,10,9,.06) 18%,
                    rgba(12,10,9,.3) 56%,rgba(12,10,9,.88) 79%,#0C0A09 96%)}
  .hero-copy > *,.hero-copy h1{max-width:none}
}
@media(max-width:960px){
  .only-sm{display:inline-grid}
  .hide-sm{display:none}
  #app{grid-template-columns:1fr;grid-template-areas:"main" "player"}
  /* Full-height drawer above the player — otherwise upload and sign-out sit
     underneath the transport bar and cannot be reached. */
  .sidebar{position:fixed;z-index:60;top:0;bottom:0;left:0;width:min(300px,84vw);
    transform:translateX(-102%);transition:transform .42s var(--expo);
    border-right:1px solid var(--line-2);box-shadow:40px 0 90px -40px rgba(0,0,0,1)}
  .sidebar.open{transform:none}
  .scrim{z-index:55}
  .tracklist-head,.tr{grid-template-columns:28px 44px minmax(0,1fr) 52px 148px}
  .tracklist-head span:nth-child(4),.t-album{display:none}
  .stage-inner{grid-template-columns:1fr;justify-items:center;text-align:center;gap:22px}
  .stage-meta h2{white-space:normal}
  .s-eyebrow{justify-content:center}
  .track-feedback{display:grid;grid-template-columns:1fr;justify-items:center;gap:9px}
  .feedback-verdicts button{height:44px}
  .feedback-aspects{flex-direction:column;gap:8px;width:100%}
  .feedback-aspects > div{display:grid;grid-template-columns:repeat(3,max-content);
    justify-content:center;gap:6px}
  .feedback-aspects button{height:44px}
  .buttons.big{justify-content:center}
  .stage-art{width:min(260px,58vw)}
}
@media(max-width:820px){
  /* Shorter band on a phone — the copy has to start above the fold. */
  :root{--hero-band:min(44vh,340px)}
  .hero-pic img{object-position:74% 48%}
  .lede{font-size:15.5px}
}
@media(max-width:780px){
  /* Two-row player: art + meta on top, transport and seek below. */
  :root{--playerh:142px}
  .art-wrap{width:46px;height:46px;border-radius:12px}
  .icon.play{width:40px;height:40px}
  .icon.play .ic{width:17px;height:17px}
  .preview{grid-template-columns:auto minmax(0,1fr) auto;row-gap:12px}
  .pv-cover{grid-area:1/1}
  .pv-meta{grid-area:1/2}
  .pv-keep{grid-area:1/3}
  .pv-wave{grid-area:2/1/3/4;height:34px}
  .pv-time{grid-area:3/1/4/4;justify-self:end}
  .pv-more{display:none}
  .player{grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:10px 14px}
  /* .now shrinks to its content, which left the favourite stranded in the
     middle of the row aligned to nothing, with dead space to the edge. */
  .p-left .p-keep{margin-left:auto}
  .extras{display:none}
  .controls{grid-column:1/-1;order:3}
  .track-feedback{margin-top:12px}
  .cta{flex-direction:column;align-items:flex-start;text-align:left}
}
@media(max-width:640px){
  /* Two-row header: controls stay reachable, search gets a full line rather
     than being squeezed down to a single visible character. */
  .topbar{flex-wrap:wrap;row-gap:10px}
  .search-wrap{order:3;flex:1 0 100%;max-width:none}
  .top-right{margin-left:auto}
  .top-right #view-mode{display:none}
  .select-wrap select{max-width:145px}
  .s-kbd{display:none}
  #search{padding-right:16px}
}
@media(max-width:560px){
  .view-head{align-items:flex-start;flex-direction:column;gap:14px}
  .tracklist-head,.tr{grid-template-columns:44px minmax(0,1fr) 132px;gap:11px}
  .tracklist-head span:nth-child(1),.t-idx{display:none}
  .tracklist-head span:nth-child(5),.t-dur{display:none}
  .t-actions button.add,.t-actions button.del{display:none}
  .tracklist.grid .t-actions button.add,.tracklist.grid .t-actions button.del{display:grid}
  .tracklist.grid{grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:14px}
}
/* Row actions are hover-revealed on a pointer device; on touch there is no
   hover, so they have to be there from the start. */
/* In the Studio the library toolbar is dead weight: sort order, list-vs-grid and
   the library search do nothing there. New track is the same door you already
   walked through. Hidden rather than disabled — a disabled control still costs a
   row of screen. The search stays on desktop, where it is a global jump and there
   is room for it. */
body.in-studio .top-right .select-wrap,
body.in-studio .top-right #view-mode,
body.in-studio .top-right [data-new-track]{display:none}
@media(max-width:820px){
  /* Every control in the bar is a library control, so in the Studio the bar has
     nothing left to hold but the drawer button. The two-row mobile header still
     reserves the row the search used to sit on, which spent ~130px of a 844px
     screen on one 44px button. Collapse it back to a single row. */
  body.in-studio .topbar .search-wrap{display:none}
  body.in-studio .topbar{flex-wrap:nowrap;row-gap:0;padding-top:10px;padding-bottom:10px}
}

/* ── motion follows the audio ────────────────────────────────────────────────
   Everything below animates to represent playback. `.tr.playing` only means the
   track is loaded, so without this gate the row equalizer, the beat pulses and
   the now-playing ring all kept moving over a paused track — motion that says
   "this is playing" while nothing is.

   animation-play-state, not `animation:none`: the bars freeze mid-pose and
   resume from there, rather than snapping to their start height on every
   pause. */
.eqbars i,
.ea-eq i,
.ea-ring::after{animation-play-state:paused}
html.is-playing .eqbars i,
html.is-playing .ea-eq i,
html.is-playing .ea-ring::after{animation-play-state:running}
/* The wordmark's note breathes only while sound is coming out. The land
   (scale-in) is a one-shot and always plays; the breathe loop is the part
   that claims "this is playing", so it is the part that is gated. Play-state,
   not animation:none — the note freezes mid-breath and resumes, rather than
   snapping to full on every pause. */
html.is-playing .mark-img{animation-play-state:running,running}

@media(hover:none){
  .t-actions{opacity:1}
  .t-art .ov,.art-wrap .expand{display:none}

  /* ── touch targets ──────────────────────────────────────────────────────
     A pointer that is 8px wide and one that is 45px wide do not want the same
     control. Everything reachable by finger gets 44px, which is the Apple HIG
     and Material figure — WCAG 2.2 only asks 24px, but 24px is a target you
     hit eventually rather than one you hit first time.

     Two techniques. Where the row has room the control simply grows. Where it
     does not — the three per-track actions, the seek bar — the drawn size is
     kept and an invisible ::after extends the hit area past the box, so the
     visual rhythm is untouched and only the finger notices. */
  .icon-btn{width:44px;height:44px}
  .player .icon{width:44px;height:44px}
  .player .icon .ic{width:19px;height:19px}
  .seg .tab{height:44px}
  #play-all,#shuffle-all,.btn.sm{min-height:44px}
  .select-wrap select{height:44px}

  /* The seek bar is 16px of drawn height in a 64px player. Expanding the box
     would push the transport row; expanding the hit area does not. */
  .bar{position:relative}
  .bar::after{content:"";position:absolute;left:0;right:0;top:50%;
    height:44px;transform:translateY(-50%)}

  /* Per-track actions sit three-across in a fixed column, so 44px squares
     would collide. They grow to 40 and take the remaining 4px vertically from
     the row, which is 56px tall and has it to give. */
  .t-actions{gap:6px}
  /* flex:none — the row squeezes the actions column on a narrow screen, and
     without it the buttons shrink back below the target size. */
  .t-actions button{width:40px;height:40px;position:relative;flex:none}
  .t-actions button::after{content:"";position:absolute;left:0;right:0;top:50%;
    height:44px;transform:translateY(-50%)}
  /* Grid mode stacks the three actions vertically in the card corner at 28px.
     Stacked, they can afford full width; the ::after grows the other axis. */
  .tracklist.grid .t-actions button{width:40px;height:40px}
  .tracklist.grid .t-actions button::after{left:50%;right:auto;width:44px;
    transform:translate(-50%,-50%)}

  /* The list/grid toggle. These are `.seg.tiny button` with no .tab class, so
     the .seg .tab rule above does not reach them. */
  .seg.tiny button{width:44px;height:44px}
  .seg.tiny{padding:2px}

  /* The wordmark is wide but short; height is what the finger needs. */
  .lp-brand,a.brand{min-height:44px;display:inline-flex;align-items:center}
}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;scroll-behavior:auto !important}
  [data-reveal]{opacity:1;transform:none}
}

/* ------------------------------------------------------------------ radio */
.radio-grid{display:flex;flex-direction:column;gap:28px}
.radio-family{display:flex;flex-direction:column;gap:12px}
.radio-family-label{margin:0;font-size:11px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}
/* Category and collection tiles rather than one card per render style, so they breathe.
   The old 196px track fit five columns of near-identical stations; at 244px
   a card has room for the line that says what the station is. */
.radio-grid-flat{display:grid;grid-template-columns:repeat(auto-fill,minmax(244px,1fr));gap:20px}
.radio-card{position:relative;display:flex;flex-direction:column;gap:0;border:1px solid var(--line);
  border-radius:var(--r-lg);overflow:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.048),rgba(255,255,255,.016));
  cursor:pointer;text-align:left;padding:0;box-shadow:var(--hi);
  transition:transform .28s var(--expo),border-color .22s var(--ease),box-shadow .28s var(--expo)}
.radio-card:hover{transform:translateY(-5px);border-color:rgba(228,174,110,.34);
  box-shadow:var(--hi),0 24px 52px -22px rgba(0,0,0,.92),0 0 0 1px rgba(224,143,76,.08)}
.radio-card.is-active{border-color:rgba(var(--glow),.7);
  box-shadow:var(--hi),0 0 0 1px rgb(var(--glow)),0 22px 48px -16px rgba(0,0,0,.82)}
.radio-card.is-empty{opacity:.45;cursor:default}
.radio-card.is-empty:hover{transform:none;border-color:var(--line);box-shadow:var(--hi)}
.radio-art{width:100%;aspect-ratio:1;object-fit:cover;display:block}
.radio-card picture,.radio-card .radio-art-fallback{position:relative}
.radio-card picture::after{content:"";position:absolute;inset:auto 0 0;height:42%;pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(12,10,9,.78))}
.radio-art-fallback{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;
  font-family:var(--serif);font-size:56px;font-weight:450;font-style:italic;
  font-optical-sizing:auto;color:var(--ink-1);
  background:linear-gradient(135deg,var(--bg-2),var(--bg-1))}
.radio-card-body{padding:14px 16px 16px}
.radio-card-name{font-family:var(--serif);font-weight:500;color:var(--ink-0);
  font-size:17px;line-height:1.2;letter-spacing:-.022em;font-optical-sizing:auto}
/* Clamped rather than truncated with an ellipsis mid-word: two lines holds every
   station blurb in the manifest, and the clamp is there for copy added later. */
.radio-card-blurb{color:var(--ink-2);font-size:13px;line-height:1.45;margin-top:6px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.radio-card-meta{color:var(--ink-3);font-size:12px;margin-top:7px;
  font-variant-numeric:tabular-nums}
.radio-live{color:var(--ember);font-weight:600;margin-left:4px;letter-spacing:.02em}
.radio-loading,.radio-error,.radio-empty{color:var(--ink-2);padding:40px 0;text-align:center}
.radio-error{color:var(--flame-3)}

.p-radio{display:flex;align-items:center;gap:2px}
.p-radio .icon:hover{color:var(--ink-0)}
#p-radio-ban:hover{color:var(--heart)}

.station-back{display:inline-flex;align-items:center;gap:6px;background:none;border:0;
  color:var(--ink-2);font:inherit;cursor:pointer;padding:6px 0;margin-bottom:12px}
.station-back:hover{color:var(--ink-0)}
.station-back .ic{width:16px;height:16px}

.station-hero{display:flex;gap:26px;align-items:flex-end;margin-bottom:28px}
.station-art{width:220px;height:220px;flex:none;border-radius:var(--r-lg);overflow:hidden;
  background:var(--bg-2);box-shadow:0 28px 60px -24px rgba(0,0,0,.9),inset 0 1px 0 rgba(255,255,255,.12)}
.station-art img,.station-art picture{width:100%;height:100%;object-fit:cover;display:block}
.station-art .radio-art-fallback{width:100%;height:100%;display:flex;align-items:center;
  justify-content:center;font-size:72px;font-weight:500;color:var(--ink-3)}
.station-meta{min-width:0;flex:1}
.station-meta .kicker{letter-spacing:.18em}
.station-name{margin:8px 0 10px;font-family:var(--serif);font-weight:500;
  font-size:clamp(32px,4.4vw,52px);line-height:1.04;letter-spacing:-.032em;color:var(--ink-0);
  font-optical-sizing:auto;font-variation-settings:"opsz" 60;text-wrap:balance}
.station-desc{margin:0 0 8px;color:var(--ink-2);max-width:62ch;font-size:15px;line-height:1.55}
/* The member styles a consolidated station shelves. Hidden for the single-style
   stations, where the chip would only repeat the station name back. */
.station-styles{list-style:none;display:flex;flex-wrap:wrap;gap:6px;margin:0 0 14px;padding:0}
.station-styles[hidden]{display:none}
.station-style{border:1px solid var(--line);border-radius:999px;padding:3px 10px;
  font-size:11.5px;color:var(--ink-2);background:var(--surface);cursor:default;
  white-space:nowrap}
.station-facts{margin:0 0 18px;color:var(--ink-3);font-size:13px;
  font-variant-numeric:tabular-nums}
.station-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.station-fav.on,.st-fav.on,#s-fav.on{color:var(--heart)}
.station-fav.on .ic,.st-fav.on .ic,#s-fav.on .ic{fill:currentColor;stroke:currentColor}

.station-tracks{list-style:none;margin:0;padding:0}
.st-row{display:grid;grid-template-columns:28px 44px 1fr auto auto auto;gap:14px;
  align-items:center;padding:8px 10px;border-radius:var(--r-xs);cursor:pointer;
  transition:background .12s ease}
.st-row:hover{background:var(--surface-2)}
/* The row plays the station from this song; the buttons inside it do their own
   thing and must not read as part of that. */
.st-row .st-actions{cursor:default}
.st-row.is-playing{background:var(--surface-2)}
.st-row.is-playing .st-num,.st-row.is-playing .st-title{color:var(--flame-3)}
/* Hidden means "never play this for me" — still listed, visibly demoted, and
   reversible. Removing the row would leave no way to undo it from here. */
.st-row.is-hidden{opacity:.42}
.st-row.is-hidden .st-title{text-decoration:line-through}
.st-num{color:var(--ink-3);font-size:13px;text-align:right;font-variant-numeric:tabular-nums}
.st-art{width:44px;height:44px;border-radius:var(--r-xs);object-fit:cover;display:block;
  background:var(--bg-2)}
.st-art-fallback{display:flex;align-items:center;justify-content:center;
  font-weight:700;color:var(--ink-3)}
.st-main{min-width:0;display:flex;flex-direction:column;gap:2px}
.st-title{color:var(--ink-0);font-weight:500;letter-spacing:-.012em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.st-sub{color:var(--ink-3);font-size:12px}
/* Tabular figures keep the date and duration columns from shifting as values
   change width — the detail that separates a list that feels built from one that
   feels generated. */
.t-date,.st-dur{color:var(--ink-3);font-size:13px;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.t-date{cursor:help;border-bottom:1px dotted transparent}
.st-row:hover .t-date{border-bottom-color:var(--line-3)}
.st-actions{display:flex;align-items:center;gap:2px;opacity:0;transition:opacity .12s ease}
.st-row:hover .st-actions,.st-row:focus-within .st-actions{opacity:1}
/* Touch has no hover, so the actions would be unreachable if they only appeared
   on it. */
@media(hover:none){.st-actions{opacity:1}}
.station-empty{color:var(--ink-3);padding:18px 10px}
.station-more{color:var(--ink-3);font-size:13px;padding:14px 10px 0;margin:0}
.station-more{color:var(--ink-3);font-size:13px;margin-top:14px}

@media (max-width:720px){
  .station-hero{flex-direction:column;align-items:flex-start;gap:16px}
  .station-art{width:150px;height:150px}
  .st-row{grid-template-columns:24px 40px 1fr auto;gap:10px}
  /* The date is the first thing to go when space is tight: it is the least
     load-bearing column, and it stays available on the row's own tooltip. */
  .st-row .t-date{display:none}
}

.radio-body{display:grid;grid-template-columns:1fr 280px;gap:20px;align-items:start}
.radio-upnext{border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);
  padding:16px 16px 14px;position:sticky;top:12px}
.radio-upnext h3{margin:0 0 12px;font-size:11px;font-weight:650;text-transform:uppercase;
  letter-spacing:.14em;color:var(--ink-3)}
.radio-upnext ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
.radio-up-item{display:flex;justify-content:space-between;gap:10px;font-size:13px}
.radio-up-title{color:var(--ink-1);font-weight:500;letter-spacing:-.01em;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.radio-up-style{color:var(--ink-3);flex:none}
.radio-up-empty{color:var(--ink-3);font-size:13px}

@media (max-width:860px){
  .radio-body{grid-template-columns:1fr}
}

/* ------------------------------------------------------------------ keep */
/* Grows out of the player rather than floating as a generic confirm. The
   playing track is the subject; Favourites and occasions are destinations. */
.keep-layer{position:fixed;inset:0;z-index:230;display:grid;
  place-items:end center;padding:18px 18px calc(var(--playerh) + 18px);
  pointer-events:none}
.keep-layer:not([hidden]){pointer-events:auto}
@keyframes fade{from{opacity:0}to{opacity:1}}
@keyframes fadeout{to{opacity:0}}
.keep-scrim{position:absolute;inset:0;border:0;padding:0;background:rgba(8,7,6,.62);
  backdrop-filter:blur(16px) saturate(120%);cursor:default;animation:fade .22s var(--ease)}
.keep-sheet{position:relative;z-index:1;width:min(440px,100%);
  border-radius:var(--r-2xl);overflow:hidden;
  border:1px solid rgba(255,255,255,.13);
  background:
    radial-gradient(90% 50% at 100% -8%,rgba(228,174,110,.12),transparent 58%),
    linear-gradient(180deg,rgba(22,18,15,.98),rgba(12,10,8,.985));
  backdrop-filter:blur(28px) saturate(145%);
  box-shadow:var(--hi),0 40px 90px -36px rgba(0,0,0,.95);
  animation:keepin .42s var(--expo)}
@keyframes keepin{from{opacity:0;transform:translateY(18px) scale(.98)}
  to{opacity:1;transform:none}}
.keep-layer.out .keep-sheet{animation:keepout .2s var(--ease) forwards}
.keep-layer.out .keep-scrim{animation:fadeout .18s var(--ease) forwards}
@keyframes keepout{to{opacity:0;transform:translateY(12px)}}
.keep-edge{position:absolute;left:16%;right:16%;top:0;height:1px;
  background:linear-gradient(90deg,transparent,rgba(228,174,110,.7),transparent)}
.keep-head{display:flex;align-items:flex-start;gap:14px;padding:20px 18px 16px 20px;
  border-bottom:1px solid rgba(255,255,255,.07)}
.keep-track{display:flex;align-items:center;gap:14px;min-width:0;flex:1}
.keep-art{position:relative;width:64px;height:64px;border-radius:14px;overflow:hidden;
  flex:none;background:linear-gradient(140deg,#2A231B,#161210);border:1px solid var(--line-2)}
.keep-art img{position:absolute;inset:0;z-index:1;width:100%;height:100%;object-fit:cover}
.keep-art .art-fallback{position:absolute;inset:0;display:grid;place-items:center;color:var(--ink-3)}
.keep-art .art-fallback .ic{width:22px;height:22px}
.keep-track-copy{min-width:0}
.keep-kicker{margin:0 0 4px;font-size:10.5px;font-weight:650;letter-spacing:.18em;
  text-transform:uppercase;color:var(--gold)}
.keep-track-copy h2{margin:0;font-family:var(--serif);font-size:23px;font-weight:500;
  letter-spacing:-.026em;line-height:1.12;font-optical-sizing:auto;
  font-variation-settings:"opsz" 36;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.keep-track-copy p#keep-artist{margin:5px 0 0;font-size:12.5px;color:var(--ink-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.keep-head .icon{margin-left:auto;color:var(--ink-3)}
.keep-body{display:flex;flex-direction:column;gap:16px;padding:16px 18px 20px}
.keep-dests{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.keep-dest{display:flex;flex-direction:column;align-items:flex-start;gap:10px;
  padding:14px 14px 13px;border-radius:16px;text-align:left;
  border:1px solid rgba(255,255,255,.09);
  background:linear-gradient(160deg,rgba(255,255,255,.055),rgba(255,255,255,.018));
  transition:border-color .18s var(--ease),background .18s var(--ease),transform .18s var(--expo)}
.keep-dest:hover,.keep-dest:focus-visible,.keep-dest.is-open{border-color:rgba(228,174,110,.4);
  background:linear-gradient(160deg,rgba(228,174,110,.1),rgba(255,255,255,.03));
  transform:translateY(-1px)}
.keep-dest.is-on{border-color:rgba(206,58,92,.4);
  background:linear-gradient(160deg,rgba(206,58,92,.12),rgba(255,255,255,.02))}
.keep-dest-icon{display:grid;place-items:center;width:34px;height:34px;border-radius:11px;
  color:var(--gold);background:rgba(228,174,110,.1);border:1px solid rgba(228,174,110,.22)}
.keep-dest-icon .ic{width:16px;height:16px}
.keep-dest.is-on .keep-dest-icon{color:var(--heart);background:rgba(206,58,92,.12);
  border-color:rgba(206,58,92,.28)}
.keep-dest.is-on .keep-dest-icon .ic{fill:currentColor;stroke:currentColor}
.keep-dest-copy{display:flex;flex-direction:column;gap:3px;min-width:0}
.keep-dest-copy b{font-size:14px;font-weight:560;letter-spacing:-.01em}
.keep-dest-copy em{font-style:normal;font-size:12px;line-height:1.35;color:var(--ink-3)}
.keep-create{display:flex;flex-direction:column;gap:12px}
.keep-create .field{margin:0;display:flex;flex-direction:column;gap:7px}
.keep-create .field span{font-size:10.5px;font-weight:650;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}
.keep-create .field input{height:46px;padding:0 14px;border-radius:14px;
  background:rgba(255,255,255,.045);border:1px solid var(--line-2);outline:none;
  color:var(--ink-0);transition:border-color .18s var(--ease),box-shadow .18s var(--ease)}
.keep-create .field input::placeholder{color:var(--ink-3)}
.keep-create .field input:focus{border-color:rgba(228,174,110,.5);
  box-shadow:0 0 0 4px rgba(228,174,110,.1)}
.keep-create .btn{width:100%}
.keep-occasions h3{margin:0 0 8px;font-size:10.5px;font-weight:650;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-3)}
.keep-list{display:flex;flex-direction:column;gap:6px;max-height:min(32vh,240px);
  overflow-y:auto}
.keep-opt{display:flex;align-items:baseline;gap:10px;width:100%;padding:12px 14px;
  border-radius:13px;border:1px solid var(--line);background:var(--surface);
  color:var(--ink-1);transition:.18s var(--ease)}
.keep-opt:hover,.keep-opt:focus-visible{border-color:rgba(228,174,110,.42);
  background:var(--surface-2);color:var(--ink-0)}
.keep-opt b{font-size:14px;font-weight:550;flex:1;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.keep-opt em{font-style:normal;font-size:11.5px;color:var(--ink-3);flex:none}
body.keep-open{overflow:hidden}

@media(max-width:560px){
  .keep-layer{padding:0;place-items:end stretch}
  .keep-sheet{width:100%;max-width:none;border-radius:var(--r-2xl) var(--r-2xl) 0 0}
  .keep-dests{grid-template-columns:1fr}
}

/* ═══════════════════════════════════════════════════ the measured voice ═══ */
/* Every structural micro-label — table heads, section labels, stat captions —
   speaks monospace: the instrument-panel register the serif plays against.
   Late in the sheet on purpose, so it wins the earlier per-component rules. */
.side-head,.tracklist-head,.jobs-head,.stat small,
.radio-family-label,.radio-upnext h3,.keep-kicker,.keep-create .field span,
.keep-occasions h3,.s-eyebrow,.badge,.st,#motion-control::before,
.manifesto-facts span{font-family:var(--mono);font-weight:500}
.s-eyebrow{color:var(--ember)}

/* ═══════════════════════════════════════════════════════════ the set ═══ */
/* The walnut-and-brass cabinet. The photograph carries the cabinet; these
   rules make it an instrument. All geometry is percent-of-cabinet, measured
   off the render, so it holds at every size. */
.receiver[data-mode="set"]{background:none;border-color:transparent;box-shadow:none;
  backdrop-filter:none;padding:0}
.receiver[data-mode="set"] .deck-head{margin-bottom:16px;padding:0 4px;justify-content:center}
.receiver[data-mode="set"] .deck-rail,
.receiver[data-mode="set"] .preview{display:none}
.receiver[data-mode="set"] .deck-note{border-top:0;text-align:center;padding-top:12px}

.deck-tools{display:flex;align-items:baseline;justify-content:center;gap:28px;
  width:min(800px,100%);margin:18px auto 6px}
#book-toggle .caret{width:13px;height:13px;transform:rotate(90deg);
  transition:transform .3s var(--ease)}
#book-toggle.on .caret{transform:rotate(-90deg)}

/* The cabinet ships cut out (real alpha, rounded corners baked into the
   mask), so the shadow hugs the silhouette and the room shows through
   around it — no backdrop box. */
.set-stage{position:relative;width:min(800px,100%);margin:0 auto;user-select:none;
  filter:drop-shadow(0 30px 50px rgba(0,0,0,.5))}
.set-img{width:100%;display:block;transition:filter .6s var(--ease)}
.receiver:not(.live) .set-img{filter:brightness(.9)}

/* the grille leans into the low end — same signal as the room's lamplight */
.set-grille{position:absolute;left:9.25%;top:6.5%;width:81%;height:39%;pointer-events:none;
  background:radial-gradient(60% 72% at 50% 56%,rgba(224,143,76,.5),transparent 70%);
  mix-blend-mode:screen;filter:blur(26px);opacity:calc(var(--room-glow,0) * .55)}

/* the dial: click anywhere on the glass to tune; arrows work when focused */
.set-dial{position:absolute;left:22.41%;top:50.42%;width:54.66%;height:12.53%;cursor:pointer;
  border-radius:8px}
.set-dial:focus-visible{outline:2px solid var(--flame-3);outline-offset:4px}
.set-needle{position:absolute;top:7%;bottom:9%;left:11%;width:2px;
  transform:translateX(-50%);pointer-events:none;
  background:linear-gradient(180deg,transparent,rgba(237,210,166,.95) 16%,
             rgba(217,111,51,.95) 84%,transparent);
  box-shadow:0 0 10px rgba(224,143,76,.8);
  transition:left .9s var(--expo),opacity .5s var(--ease)}
.receiver:not(.live) .set-needle{opacity:.55}

/* the eight presets engraved on the cabinet — a veil dims the seven that are
   not sounding (the artwork bakes one lit; the veil evens the row out) */
.set-presets{position:absolute;left:22.93%;top:67.2%;width:54.44%;height:9.77%;
  display:grid;grid-template-columns:repeat(8,1fr);gap:1.2%}
.set-preset{position:relative;cursor:pointer;border-radius:7px}
.set-preset::before{content:"";position:absolute;inset:2% 5%;border-radius:7px;
  background:rgba(12,10,9,.44);transition:background .25s var(--ease),box-shadow .25s var(--ease)}
.set-preset:hover::before{background:rgba(12,10,9,.16)}
.set-preset.on::before{background:rgba(224,143,76,.07);
  box-shadow:0 0 26px rgba(217,111,51,.4)}
.set-preset:disabled{cursor:default}
.set-preset:focus-visible{outline:2px solid var(--flame-3);outline-offset:2px}

/* Real rotaries: grab and turn. VOLUME's throw is loudness with a power
   click at the bottom; TUNING sweeps the needle live across the band and
   settles on the nearest carrier when the hand lets go. While a knob is
   in hand, every transition drops away so it tracks the finger exactly. */
.set-knob{position:absolute;border-radius:50%;cursor:grab;
  transition:box-shadow .25s var(--ease),transform .15s var(--ease)}
.set-knob.turning{cursor:grabbing}
.set-knob.turning i{transition:none}
.set-stage.tuning .set-needle{transition:opacity .5s var(--ease)}
.set-knob-l{left:8.2%;top:57.22%;width:12.33%;height:17.41%}
.set-knob-r{left:79.47%;top:57.22%;width:12.33%;height:17.41%}
.set-knob:hover{box-shadow:0 0 0 2px rgba(228,174,110,.35),0 0 28px rgba(217,111,51,.3)}
.set-knob:active{transform:scale(.98)}
.set-knob:focus-visible{outline:2px solid var(--flame-3);outline-offset:4px}
/* The tone shelf: BASS, MID and TREBLE are the same rotaries at panel
   scale, each a real filter in the speaker chain. A click returns a knob
   to its detent. Their printed ±5 scales live in the artwork. */
.set-mini-bass{left:31.5%;top:85.67%;width:6.92%;height:9.77%}
.set-mini-mid{left:44.89%;top:85.67%;width:6.92%;height:9.77%}
.set-mini-treble{left:57.67%;top:85.46%;width:6.92%;height:9.77%}
.set-mini i::before{height:24%;width:1.5px;box-shadow:0 0 4px rgba(224,143,76,.45)}
.set-mini:hover{box-shadow:0 0 0 1.5px rgba(228,174,110,.3),0 0 18px rgba(217,111,51,.25)}
/* The knobs turn: a brass pointer rides each rim. POWER swings with play
   and pause; TUNING tracks the station like the needle does. */
.set-knob i{position:absolute;inset:15%;border-radius:50%;pointer-events:none;
  transform:rotate(var(--kr,0deg));transition:transform .6s var(--expo)}
.set-knob i::before{content:"";position:absolute;left:calc(50% - 1px);top:3%;
  width:2px;height:17%;border-radius:2px;
  background:linear-gradient(180deg,var(--gold),rgba(237,210,166,.2));
  box-shadow:0 0 6px rgba(224,143,76,.5)}

/* the placard under the cabinet: title, station, time, the gate */
.placard{position:relative;display:flex;align-items:center;gap:14px;
  width:min(800px,100%);margin:16px auto 0;padding:13px 4px 2px;
  border-top:1px solid var(--line)}
.placard::before{content:"";position:absolute;top:-1px;left:0;height:1px;
  width:calc(var(--np-p,0) * 100%);
  background:linear-gradient(90deg,var(--flame-2),var(--ember))}
.placard-play{flex:none}
.placard-meta{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.35}
.placard-meta b{font-family:var(--serif);font-size:16px;font-weight:500;
  letter-spacing:-.014em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.placard-meta small{font-size:12px;color:var(--ink-2);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.placard-time{font-family:var(--mono);font-size:11px;color:var(--ink-3);
  font-variant-numeric:tabular-nums;white-space:nowrap}

/* ── every station, no account: the book ── */
.book{display:grid;grid-template-rows:0fr;transition:grid-template-rows .55s var(--expo)}
.book.open{grid-template-rows:1fr}
.book-clip{overflow:hidden;min-height:0}
.book-in{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:10px;
  padding:8px 2px 16px}
.receiver[data-mode="set"] .book-in{margin:0 auto 6px;width:min(800px,100%);
  padding:14px;border:1px solid var(--line-2);border-radius:var(--r-lg);
  background:linear-gradient(180deg,rgba(24,20,16,.82),rgba(13,11,9,.94));
  backdrop-filter:blur(20px) saturate(130%)}
.book-tile{display:flex;gap:12px;align-items:center;text-align:left;padding:10px;
  border:1px solid var(--line);border-radius:var(--r);background:var(--surface);
  transition:border-color .2s var(--ease),background .2s var(--ease),transform .25s var(--expo)}
.book-tile:not(.is-dry):hover{transform:translateY(-2px);border-color:var(--line-2);
  background:var(--surface-2)}
.book-tile.on b{color:var(--ember)}
.book-tile.is-dry{opacity:.4}
.book-art{width:52px;height:52px;border-radius:10px;overflow:hidden;flex:none;background:var(--bg-2)}
.book-art img{width:100%;height:100%;object-fit:cover;display:block}
.book-copy{min-width:0;display:flex;flex-direction:column;gap:2px}
.book-copy b{font-family:var(--serif);font-size:14.5px;font-weight:500;letter-spacing:-.012em}
.book-copy em{font-style:normal;font-size:11.5px;color:var(--ink-3);line-height:1.4;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.book-copy small{font-family:var(--mono);font-size:9px;font-weight:500;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3);margin-top:2px}
.book-tile.on .book-copy small{color:var(--ember)}

@media(max-width:640px){
  .deck-tools{flex-direction:column;align-items:center;gap:10px}
  /* two rows: the title gets the first, the controls share the second */
  .placard{flex-wrap:wrap;row-gap:10px}
  .placard-meta{flex:1 1 calc(100% - 58px)}
  .placard-time{order:4;margin-right:auto}
  .placard .pv-keep{order:5}
  .placard > .icon-btn{order:6}
}

/* ═══════════════════════════════════════ the prototype's eyebrow line ═══ */
/* On the landing, section eyebrows are Fraunces italic in brass — a spoken
   line, not a label. The app keeps its mono labels. */
.lp .sec-head .kicker,.lp .deck-head .kicker{font-family:var(--serif);font-style:italic;
  font-weight:400;font-size:clamp(19px,2.1vw,25px);letter-spacing:0;text-transform:none;
  color:var(--flame-3);gap:0}
.lp .sec-head .kicker::before,.lp .deck-head .kicker::before{display:none}

/* ═══════════════════════════════════════════════════ the minimal landing ═══ */
/* body.lp-minimal: just the room, the set and its player. The headline, the
   statement, the closing words and the footer are all still in the document
   (the pricing page and the tests depend on them) — they simply don't show on
   the landing. The receiver is centred in the viewport on the living room. */
body.lp-minimal:not(.pricing-page) .hero-copy,
body.lp-minimal:not(.pricing-page) .deck-head,
body.lp-minimal:not(.pricing-page) .deck-note,
body.lp-minimal:not(.pricing-page) .manifesto,
body.lp-minimal:not(.pricing-page) #start,
body.lp-minimal:not(.pricing-page) .lp-foot{display:none !important}
body.lp-minimal:not(.pricing-page) .hero{min-height:100svh;display:flex;
  flex-direction:column;justify-content:center;
  padding:clamp(28px,5vh,56px) 0 clamp(24px,4vh,40px)}
body.lp-minimal:not(.pricing-page) .receiver{margin-top:0}
/* no headline to protect: the room shows through far more */
body.lp-minimal:not(.pricing-page) .hero-veil{background:
    linear-gradient(180deg,rgba(12,10,9,.6) 0%,rgba(12,10,9,.12) 22%,
                    rgba(12,10,9,.08) 70%,rgba(12,10,9,0) 82%),
    linear-gradient(0deg,#0C0A09 0%,rgba(12,10,9,.85) 6%,rgba(12,10,9,.4) 13%,
                    rgba(12,10,9,0) 24%)}
@media(max-width:1180px){
  /* minimal on a phone: the room fills the screen behind the set, rather
     than the full page's top band */
  body.lp-minimal:not(.pricing-page) .hero-bleed{inset:0;height:auto}
  body.lp-minimal:not(.pricing-page) .hero-pic img{object-position:50% 55%;transform-origin:50% 52%}
  body.lp-minimal:not(.pricing-page) .hero-pic img{animation:hero-settle 2.4s var(--expo) both,hero-drift 90s var(--ease-io) 2.4s infinite alternate}
}
