/* ─────────────────────────────────────────────
   NEONDROME — premium shell

   The streak system drives --accent / --accent-2
   through #app[data-streak], and every themed
   surface (buttons, HUD, glows) follows them
   with a transition — so a hot streak re-skins
   the interface live.
   ───────────────────────────────────────────── */

:root{
  --bg:       #050510;
  --ink:      #f2f3ff;
  --ink-dim:  #9aa0c7;
  --ink-soft: #c9cdf0;
  --line:     rgba(160,170,255,.14);
  --line-hi:  rgba(255,255,255,.09);
  --glass:    rgba(21,23,52,.55);
  --glass-2:  rgba(13,14,34,.72);

  --lane-0:   #22d3ee;
  --lane-1:   #fb3b6d;
  --lane-2:   #4ade80;

  --perfect:  #ffd94a;
  --great:    #4ade80;
  --good:     #22d3ee;
  --miss:     #fb3b6d;
  --gold:     #ffd94a;

  --pf-max:   520px;
  --safe-t:   env(safe-area-inset-top, 0px);
  --safe-b:   env(safe-area-inset-bottom, 0px);

  --ease-pop: cubic-bezier(.2,1.4,.4,1);
}

*{ box-sizing:border-box; margin:0; padding:0; }

/* ── app shell: a game, not a document ───────────────────
   The page itself never scrolls, never zooms, never selects.
   Everything lives inside #app, which is pinned to the device
   edges; only designated inner regions may scroll. */
html,body{
  height:100%;
  height:100dvh;                          /* ignores iOS toolbar chrome */
  background:var(--bg);
  color:var(--ink);
  font-family:-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  overscroll-behavior:none;
  overflow:hidden;
  position:fixed;
  inset:0;
  touch-action:manipulation;              /* kills the 300ms double-tap zoom */
  -webkit-user-select:none; user-select:none;
  -webkit-touch-callout:none;             /* no long-press "copy/share image" */
  -webkit-tap-highlight-color:transparent;
}

body{
  background:
    radial-gradient(120% 85% at 50% -12%, #171238 0%, transparent 58%),
    radial-gradient(95% 65% at 50% 112%, #101733 0%, transparent 62%),
    var(--bg);
}

/* the one place text selection is wanted */
input, textarea{ -webkit-user-select:text; user-select:text; }

/* ── streak theming ──────────────────────────
   data-streak on #app is set by the game:
   0 rest · 1 GROOVE · 2 ON FIRE · 3 MUSE MODE */
#app{
  position:fixed; inset:0;
  height:100dvh;
  overflow:hidden;
  --accent:   #22d3ee;
  --accent-2: #fb3b6d;
}
#app[data-streak="1"]{ --accent:#a78bfa; --accent-2:#e879f9; }
#app[data-streak="2"]{ --accent:#fb923c; --accent-2:#f43f5e; }
#app[data-streak="3"]{ --accent:#ffd94a; --accent-2:#f0abfc; }

/* ambient nebulae — one static layer per tier, crossfaded by opacity.
   Opacity is compositor-only, so the tier change never stalls the
   canvas (the previous filter transition did). */
.aura{
  position:absolute; inset:-22%;
  z-index:0; pointer-events:none;
  opacity:0;
  transition:opacity 1.1s ease;
  will-change:opacity;
}
.aura-0{
  background:
    radial-gradient(42% 34% at 20% 16%, rgba(93,90,222,.34), transparent 70%),
    radial-gradient(38% 30% at 82% 80%, rgba(34,211,238,.16), transparent 70%),
    radial-gradient(30% 26% at 70% 8%,  rgba(251,59,109,.10), transparent 70%);
  opacity:.85;
}
.aura-1{
  background:
    radial-gradient(42% 34% at 20% 16%, rgba(147,97,253,.38), transparent 70%),
    radial-gradient(38% 30% at 82% 80%, rgba(232,121,249,.18), transparent 70%),
    radial-gradient(30% 26% at 70% 8%,  rgba(99,102,241,.14), transparent 70%);
}
.aura-2{
  background:
    radial-gradient(42% 34% at 20% 16%, rgba(249,115,22,.36), transparent 70%),
    radial-gradient(38% 30% at 82% 80%, rgba(244,63,94,.20), transparent 70%),
    radial-gradient(30% 26% at 70% 8%,  rgba(253,224,71,.12), transparent 70%);
}
.aura-3{
  background:
    radial-gradient(42% 34% at 20% 16%, rgba(255,196,64,.40), transparent 70%),
    radial-gradient(38% 30% at 82% 80%, rgba(240,171,252,.20), transparent 70%),
    radial-gradient(30% 26% at 70% 8%,  rgba(165,243,252,.14), transparent 70%);
}
#app[data-streak="1"] .aura-0,
#app[data-streak="2"] .aura-0,
#app[data-streak="3"] .aura-0{ opacity:0; }
#app[data-streak="1"] .aura-1{ opacity:.95; }
#app[data-streak="2"] .aura-2{ opacity:1; }
#app[data-streak="3"] .aura-3{ opacity:1; }

/* twinkling star canvas — driven by js/stars.js, paused during play */
#cosmos{
  position:absolute; inset:0;
  z-index:0; pointer-events:none;
}

/* film grain — plain low opacity; blend modes over a live canvas
   are a per-frame compositing tax */
#app::after{
  content:""; position:absolute; inset:0;
  z-index:2; pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
  background-size:160px 160px;
  opacity:.04;
}

[hidden]{ display:none !important; }

/* ── screens ─────────────────────────────── */
.screen{
  position:absolute; inset:0; z-index:1;
  display:none;
  align-items:center; justify-content:center;
  padding:calc(22px + var(--safe-t)) 18px calc(22px + var(--safe-b));
  /* vertical only, never horizontal, and never chained to the page */
  overflow-x:hidden;
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  touch-action:pan-y;
  scrollbar-width:none;
}
.screen::-webkit-scrollbar{ display:none; }
.screen.is-active{ display:flex; animation:screenIn .5s cubic-bezier(.22,1,.36,1) both; }
@keyframes screenIn{
  from{ opacity:0; transform:translateY(22px) scale(.976); filter:blur(7px); }
  60%{ filter:blur(0); }
  to{ opacity:1; transform:none; filter:blur(0); }
}

.stack{
  width:100%; max-width:var(--pf-max);
  display:flex; flex-direction:column; gap:14px;
  margin:auto;
}

.panel{
  position:relative;
  background:linear-gradient(180deg, var(--glass), var(--glass-2));
  -webkit-backdrop-filter:blur(22px);
  backdrop-filter:blur(22px);
  border:1px solid var(--line);
  border-radius:24px;
  padding:26px 22px;
  box-shadow:
    inset 0 1px 0 var(--line-hi),
    0 30px 80px rgba(0,0,0,.6);
}

h2{ font-size:19px; font-weight:800; letter-spacing:.14em; text-transform:uppercase; }
.screen-title{ text-align:center; color:var(--ink-dim); font-size:13px; letter-spacing:.22em; }
.screen-title.is-vs{ color:#ff9a5c; text-shadow:0 0 22px rgba(255,120,60,.5); }

/* ── logo — the drome ────────────────────── */
.logo{
  position:relative;
  text-align:center; margin-bottom:10px;
  padding:26px 0 4px;
  animation:levitate 6s ease-in-out infinite;
}
@keyframes levitate{ 0%,100%{ transform:translateY(0); } 50%{ transform:translateY(-7px); } }

/* coloured light rays behind the mark (transform-only spin) */
.burst{
  position:absolute; left:50%; top:46%;
  width:150vw; height:150vw; max-width:820px; max-height:820px;
  transform:translate(-50%,-50%);
  pointer-events:none;
  background:
    repeating-conic-gradient(from 0deg,   rgba(255,45,85,.20)  0deg 9deg,  transparent 9deg  32deg),
    repeating-conic-gradient(from 14deg,  rgba(0,145,255,.18)  0deg 7deg,  transparent 7deg  27deg),
    repeating-conic-gradient(from 7deg,   rgba(80,255,120,.11) 0deg 5deg,  transparent 5deg  23deg),
    repeating-conic-gradient(from 20deg,  rgba(190,80,255,.13) 0deg 6deg,  transparent 6deg  37deg),
    radial-gradient(circle, rgba(140,80,255,.28), transparent 58%);
  -webkit-mask-image:radial-gradient(circle, #000 26%, transparent 66%);
  mask-image:radial-gradient(circle, #000 26%, transparent 66%);
  animation:burstSpin 90s linear infinite;
  will-change:transform;
}
@keyframes burstSpin{ to{ transform:translate(-50%,-50%) rotate(360deg); } }

/* The mark. Neon is glow, so the whole thing is drop-shadowed rather
   than each stroke being given its own filter -- one composite layer
   instead of six, which matters on the title screen where the ray
   burst is already spinning underneath. */
.drome{
  position:relative; z-index:1;
  display:block; margin:0 auto;
  width:min(280px,72vw); height:auto;
  filter:drop-shadow(0 0 10px rgba(120,200,255,.55))
         drop-shadow(0 0 34px rgba(160,90,255,.42));
}
.dr-vp{ filter:drop-shadow(0 0 7px rgba(255,255,255,.95)); }

/* a slow pulse on the dome so it reads as lit tube, not printed line */
@keyframes dromeHum{ 0%,100%{ opacity:1; } 55%{ opacity:.82; } }
.dr-arc{ animation:dromeHum 4.5s ease-in-out infinite; }

.logo-word{
  position:relative; z-index:2;
  margin-top:6px;
  font-size:min(40px,10.4vw);
  font-weight:900; letter-spacing:.22em; text-indent:.22em;
  line-height:1;
  background:linear-gradient(180deg,#eafcff 0%,#8ee9ff 42%,#c9a2ff 72%,#ff7fdd 100%);
  -webkit-background-clip:text; background-clip:text;
  color:transparent;
  filter:drop-shadow(0 0 14px rgba(120,200,255,.5))
         drop-shadow(0 2px 1px rgba(0,0,0,.8));
}

.logo-sub{
  margin-top:10px; font-size:10px; letter-spacing:.42em; text-indent:.42em;
  text-transform:uppercase; color:var(--ink-dim);
  position:relative; z-index:1;
}

.menu{ display:flex; flex-direction:column; gap:11px; }

/* ── buttons — chunky arcade bezels, not flat glass ── */
.btn{
  position:relative; overflow:hidden;
  appearance:none;
  border:1px solid rgba(0,0,0,.75);
  background:
    linear-gradient(180deg, rgba(255,255,255,.16) 0%, rgba(255,255,255,0) 46%),
    linear-gradient(180deg, #2b2d5c 0%, #191a3a 52%, #0f1028 100%);
  color:var(--ink);
  font:inherit; font-weight:900; font-size:14px;
  letter-spacing:.16em; text-indent:.16em;
  padding:17px 18px; border-radius:14px;
  cursor:pointer;
  text-shadow:0 1px 2px rgba(0,0,0,.7);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.35),
    inset 0 -3px 8px rgba(0,0,0,.6),
    0 5px 0 #06060f,
    0 12px 26px rgba(0,0,0,.5);
  transition:transform .06s, box-shadow .06s, filter .2s;
  -webkit-tap-highlight-color:transparent;
}
.btn::after{                       /* sheen sweep */
  content:""; position:absolute; inset:0;
  background:linear-gradient(115deg, transparent 30%, rgba(255,255,255,.16) 48%, transparent 62%);
  background-size:250% 100%; background-position:130% 0;
  transition:background-position .7s ease;
  pointer-events:none;
}
.btn:hover::after{ background-position:-130% 0; }
.btn:hover{ filter:brightness(1.12); }
.btn:active{
  transform:translateY(5px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.25),
    inset 0 3px 10px rgba(0,0,0,.7),
    0 0 0 #06060f,
    0 3px 10px rgba(0,0,0,.4);
}

.btn-primary{
  background:
    linear-gradient(180deg, rgba(255,255,255,.42) 0%, rgba(255,255,255,0) 44%),
    linear-gradient(180deg,
      color-mix(in srgb, var(--accent) 62%, #ffffff) 0%,
      color-mix(in srgb, var(--accent) 92%, #000814) 55%,
      color-mix(in srgb, var(--accent) 70%, #000814) 100%);
  border-color:rgba(0,0,0,.6);
  color:#04141f;
  text-shadow:0 1px 0 rgba(255,255,255,.45);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.75),
    inset 0 -3px 9px rgba(0,0,0,.35),
    0 5px 0 color-mix(in srgb, var(--accent) 34%, #000000),
    0 0 34px color-mix(in srgb, var(--accent) 40%, transparent);
}
.btn-primary:active{
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 0 3px 10px rgba(0,0,0,.35),
    0 0 0 color-mix(in srgb, var(--accent) 34%, #000000),
    0 0 20px color-mix(in srgb, var(--accent) 30%, transparent);
}
.btn-ghost{
  background:transparent; box-shadow:none; color:var(--ink-dim);
  border-color:transparent; text-shadow:none; font-weight:800;
}
.btn-ghost:hover{ color:var(--ink); }
.btn-ghost:active{ transform:none; box-shadow:none; }
.btn-row{ display:flex; gap:10px; }
.btn-row .btn{ flex:1; }

.btn-vs{
  background:
    linear-gradient(180deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,0) 44%),
    linear-gradient(180deg, #f2622c 0%, #b82413 55%, #6d1409 100%);
  color:#fff;
  text-shadow:0 2px 3px rgba(0,0,0,.75), 0 0 1px rgba(0,0,0,.9);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -3px 9px rgba(0,0,0,.4),
    0 5px 0 #430d05,
    0 0 30px rgba(255,110,50,.32);
}
.btn-vs:active{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5), inset 0 3px 10px rgba(0,0,0,.4),
             0 0 0 #4d1108, 0 0 18px rgba(255,110,50,.3);
}

.btn-load{
  background:
    linear-gradient(180deg, rgba(255,255,255,.20) 0%, rgba(255,255,255,0) 46%),
    linear-gradient(180deg, #4a3a9e 0%, #2c2168 55%, #1a1244 100%);
  color:#e6dfff;
}

.hint{ text-align:center; font-size:12px; color:var(--ink-dim); line-height:1.8; }

/* ── how to ──────────────────────────────── */
.howto{ padding-left:20px; display:flex; flex-direction:column; gap:10px;
        font-size:14px; line-height:1.6; color:var(--ink-soft); }
.howto b{ color:var(--ink); }
.judge-legend{ display:flex; gap:8px; flex-wrap:wrap; justify-content:center; margin:4px 0; }

.j{ font:800 10px/1 ui-monospace,SFMono-Regular,Menlo,monospace; letter-spacing:.1em;
    padding:5px 9px; border-radius:7px; background:rgba(10,10,26,.8);
    border:1px solid var(--line); }
.j-perfect{ color:var(--perfect); } .j-great{ color:var(--great); }
.j-good{ color:var(--good); }       .j-miss{ color:var(--miss); }

.tier{
  display:inline-block; margin:2px 1px 0;
  font:800 10px/1.5 ui-monospace,Menlo,monospace; letter-spacing:.08em;
  padding:2px 7px; border-radius:6px; white-space:nowrap;
}
.tier-1{ background:rgba(167,139,250,.14); color:#c4b5fd; }
.tier-2{ background:rgba(251,146,60,.14);  color:#fdba74; }
.tier-3{ background:rgba(255,217,74,.16);  color:#ffd94a; }

/* ── difficulty pills ────────────────────── */
.diff-row{
  display:flex; gap:5px; padding:5px;
  /* nothing may ever escape the rounded frame again */
  overflow:hidden;
  background:var(--glass-2);
  border:1px solid var(--line); border-radius:15px;
  box-shadow:inset 0 1px 0 var(--line-hi);
}
.diff{
  flex:1 1 0; min-width:0; appearance:none; cursor:pointer;
  border:1px solid transparent; background:transparent; color:var(--ink-dim);
  font:800 11px/1 inherit; letter-spacing:.16em; text-indent:.16em;
  padding:11px 6px; border-radius:11px;
  transition:all .2s;
  -webkit-tap-highlight-color:transparent;
}
.diff.is-on{
  background:linear-gradient(180deg, rgba(64,64,140,.85), rgba(38,38,90,.85));
  color:var(--ink); border-color:rgba(140,140,255,.35);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14), 0 6px 18px rgba(60,60,180,.35);
}

/* ── setup screen ────────────────────────── */
.setup-block{ display:flex; flex-direction:column; gap:7px; }
.setup-label{ font:800 9.5px ui-monospace,Menlo,monospace; letter-spacing:.22em;
              color:var(--ink-dim); padding-left:4px; }

/* the chosen settings, tappable to go back and change them */
.setup-chip{
  align-self:center;
  appearance:none; cursor:pointer;
  border:1px solid var(--line); border-radius:99px;
  background:rgba(10,10,26,.7);
  color:var(--ink-soft);
  font:800 10px/1 ui-monospace,Menlo,monospace; letter-spacing:.16em;
  padding:8px 14px;
  box-shadow:inset 0 1px 0 var(--line-hi);
  -webkit-tap-highlight-color:transparent;
}
.setup-chip::after{ content:' ✎'; opacity:.55; }
.setup-chip:active{ transform:translateY(1px); }

/* ── song list ───────────────────────────── */
.songlist{ display:flex; flex-direction:column; gap:11px; }
.songlist .song{ animation:rowIn .55s cubic-bezier(.22,1,.36,1) both; }
.songlist .song:nth-child(1){ animation-delay:.04s; }
.songlist .song:nth-child(2){ animation-delay:.09s; }
.songlist .song:nth-child(3){ animation-delay:.14s; }
.songlist .song:nth-child(4){ animation-delay:.19s; }
.songlist .song:nth-child(5){ animation-delay:.24s; }
.songlist .song:nth-child(n+6){ animation-delay:.28s; }
@keyframes rowIn{
  from{ opacity:0; transform:translateY(16px) scale(.98); }
  to{ opacity:1; transform:none; }
}
.song{
  position:relative; overflow:hidden;
  display:flex; align-items:center; gap:14px;
  width:100%; text-align:left; cursor:pointer;
  border:1px solid var(--line); border-radius:19px;
  background:linear-gradient(180deg, var(--glass), var(--glass-2));
  -webkit-backdrop-filter:blur(18px);
  backdrop-filter:blur(18px);
  box-shadow:inset 0 1px 0 var(--line-hi), 0 14px 34px rgba(0,0,0,.35);
  padding:13px 15px; color:inherit; font:inherit;
  -webkit-tap-highlight-color:transparent;
  transition:transform .12s, border-color .2s, box-shadow .2s;
}
.song:hover{
  transform:translateY(-1px);
  border-color:color-mix(in srgb, var(--sc, #22d3ee) 45%, transparent);
  box-shadow:inset 0 1px 0 var(--line-hi), 0 18px 40px rgba(0,0,0,.45),
             0 0 30px color-mix(in srgb, var(--sc, #22d3ee) 16%, transparent);
}
.song:active{ transform:scale(.985); }
.song-cover{
  flex:none; width:48px; height:48px; border-radius:14px;
  display:flex; align-items:center; justify-content:center;
  font-size:21px; color:rgba(255,255,255,.92);
  text-shadow:0 1px 4px rgba(0,0,0,.4);
  background:
    radial-gradient(120% 120% at 22% 18%, rgba(255,255,255,.38), transparent 42%),
    linear-gradient(145deg,
      color-mix(in srgb, var(--sc, #22d3ee) 85%, #ffffff),
      color-mix(in srgb, var(--sc, #22d3ee) 55%, #000000));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.45),
    0 8px 20px color-mix(in srgb, var(--sc, #22d3ee) 35%, transparent);
}
.song-main{ flex:1; min-width:0; }
.song-title{ font-size:16px; font-weight:800; letter-spacing:-.01em; line-height:1.22;
             display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2;
             overflow:hidden; }
.song-meta{ font-size:11px; color:var(--ink-dim); margin-top:3.5px; letter-spacing:.06em; }
.song-credit{
  margin-top:3px; font:600 9.5px/1.4 ui-monospace,Menlo,monospace;
  color:var(--ink-dim); letter-spacing:.04em;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.song-credit.is-link{ color:#8fb8ff; text-decoration:underline; text-underline-offset:2px; }

.song-best{ text-align:right; font:700 10px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;
            color:var(--ink-dim); white-space:nowrap; }
.song-best b{ display:block; font-size:15px; color:var(--gold);
              text-shadow:0 0 16px rgba(255,217,74,.35); }
.stars{ letter-spacing:2px; color:var(--sc, #22d3ee); font-size:11px; }

.song-acts{ flex:none; display:flex; flex-direction:column; gap:5px; margin-left:2px; }
.song-del,.song-ren{
  flex:none; width:26px; height:26px;
  border:1px solid var(--line); border-radius:8px;
  background:rgba(0,0,0,.35); color:var(--ink-dim);
  font:700 14px/1 inherit; cursor:pointer;
  transition:color .15s, border-color .15s;
  -webkit-tap-highlight-color:transparent;
}
.song-ren{ font-size:11px; }
.song-del:hover{ color:var(--miss); border-color:var(--miss); }
.song-ren:hover{ color:var(--good); border-color:var(--good); }

.tag{
  display:inline-block; margin-left:6px; padding:2.5px 7px; border-radius:6px;
  background:linear-gradient(180deg, rgba(120,95,255,.35), rgba(80,60,190,.35));
  border:1px solid rgba(150,125,255,.35);
  color:#d5c8ff;
  font:800 8px/1.4 ui-monospace,Menlo,monospace; letter-spacing:.14em;
  vertical-align:1.5px;
}

/* ── settings rows ───────────────────────── */
.row{ display:flex; flex-direction:column; gap:8px; font-size:13px; }
.row > span{ display:flex; justify-content:space-between; color:var(--ink-soft); }
.row b{ font:700 13px ui-monospace,SFMono-Regular,Menlo,monospace; color:var(--lane-0); }
.row small{ font-size:11px; color:var(--ink-dim); }
input[type=range]{
  appearance:none; -webkit-appearance:none;
  width:100%; height:6px; border-radius:99px;
  background:rgba(120,130,255,.16); outline:none;
  box-shadow:inset 0 1px 2px rgba(0,0,0,.4);
}
input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none; appearance:none;
  width:23px; height:23px; border-radius:50%;
  background:
    radial-gradient(100% 100% at 30% 25%, rgba(255,255,255,.7), transparent 45%),
    linear-gradient(180deg,#3fe8ff,#0d8ed4);
  cursor:pointer;
  box-shadow:0 2px 8px rgba(0,0,0,.5), 0 0 14px rgba(34,211,238,.6);
}
input[type=range]::-moz-range-thumb{
  width:23px; height:23px; border:0; border-radius:50%;
  background:#2ee6ff; cursor:pointer;
}
.toggle{ display:flex; align-items:center; gap:10px; font-size:14px; cursor:pointer; color:var(--ink-soft); }
.toggle input{ width:20px; height:20px; accent-color:#2ee6ff; }

.text-input{
  appearance:none; width:100%;
  border:1px solid var(--line); border-radius:12px;
  background:rgba(8,8,22,.8); color:var(--ink);
  font:inherit; font-size:16px;            /* ≥16px stops iOS zoom-on-focus */
  padding:13px 14px;
  outline:none;
  box-shadow:inset 0 1px 3px rgba(0,0,0,.5);
}
.text-input:focus{ border-color:color-mix(in srgb, var(--accent) 55%, transparent);
                   box-shadow:inset 0 1px 3px rgba(0,0,0,.5),
                              0 0 16px color-mix(in srgb, var(--accent) 25%, transparent); }

/* ── calibration ─────────────────────────── */
.calib{ text-align:center; }
.calib h2{ margin-bottom:16px; }
.calib .btn-row{ margin-top:18px; }

/* three pucks pulsing in sequence — a preview of the real thing */
.cal-art{ display:flex; gap:16px; justify-content:center; margin:22px 0 18px; }
.cal-art span{
  width:46px; height:46px; border-radius:50%;
  background:radial-gradient(circle at 34% 28%, rgba(255,255,255,.22), transparent 46%), #0b0b16;
  border:3px solid var(--lane-0);
  animation:calPulse 1.8s ease-in-out infinite;
}
.cal-art span:nth-child(2){ border-color:var(--lane-1); animation-delay:.6s; }
.cal-art span:nth-child(3){ border-color:var(--lane-2); animation-delay:1.2s; }
@keyframes calPulse{
  0%,60%,100%{ transform:scale(1); box-shadow:0 0 0 rgba(255,255,255,0); }
  15%{ transform:scale(1.16); box-shadow:0 0 22px currentColor; }
}

.cal-readout{ display:flex; align-items:baseline; justify-content:center; gap:8px; margin:10px 0 6px; }
.cal-readout b{
  font:900 italic 58px/1 -apple-system,BlinkMacSystemFont,"Arial Black",sans-serif;
  font-variant-numeric:tabular-nums; color:#fff;
  text-shadow:0 3px 0 rgba(0,0,0,.6), 0 0 34px color-mix(in srgb, var(--accent) 55%, transparent);
}
.cal-readout small{ font:800 13px ui-monospace,Menlo,monospace; letter-spacing:.16em; color:var(--ink-dim); }
.cal-meta{ font:700 10px ui-monospace,Menlo,monospace; letter-spacing:.1em; color:var(--ink-dim); margin-top:8px; }

/* in-level: the canvas is the whole story, so strip the HUD back */
.mode-cal .hud-score,
.mode-cal .hud-acc{ display:none; }

/* ── game screen ─────────────────────────── */
.screen-game{ padding:0; }
.playfield{
  position:relative;
  width:100%; max-width:var(--pf-max); height:100%;
  margin:0 auto;
  background:#04040c;
  box-shadow:0 0 0 1px var(--line), 0 0 110px rgba(0,0,0,.92);
  overflow:hidden;
}
#stage{ position:absolute; inset:0; width:100%; height:100%; touch-action:none; display:block; }

/* glossy black console bar across the top (PWA-notch aware) */
.hud{
  position:absolute; left:0; right:0; top:0;
  padding:calc(8px + var(--safe-t)) 12px 9px;
  pointer-events:none; z-index:1;
  background:
    linear-gradient(180deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,0) 40%),
    linear-gradient(180deg, rgba(8,8,16,.96) 0%, rgba(8,8,16,.88) 70%, rgba(8,8,16,0) 100%);
  border-bottom:1px solid rgba(255,255,255,.09);
  box-shadow:0 6px 20px rgba(0,0,0,.55);
}
.hud-top{ display:flex; align-items:center; gap:10px; }
.icon-btn{
  pointer-events:auto; cursor:pointer;
  width:38px; height:38px; flex:none;
  border:1px solid rgba(0,0,0,.7);
  border-radius:11px;
  background:
    linear-gradient(180deg, rgba(255,255,255,.20) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg,#2a2b46,#12121f);
  color:#cfd4f5;
  font-size:11px; line-height:1;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28), 0 3px 0 #05050c;
  -webkit-tap-highlight-color:transparent;
}
.icon-btn:active{ transform:translateY(3px); box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 0 0 #05050c; }
.hud-song{ flex:1; min-width:0; }
.hud-song span{ display:block; font-size:12.5px; font-weight:800; letter-spacing:.05em;
                white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hud-song small{ font-size:8.5px; letter-spacing:.24em; color:var(--ink-dim); text-transform:uppercase; }
.hud-score{
  font:900 27px/1 -apple-system,BlinkMacSystemFont,"Arial Black",sans-serif;
  font-style:italic;
  font-variant-numeric:tabular-nums;
  color:#fff;
  -webkit-text-stroke:1px rgba(0,0,0,.6);
  text-shadow:0 2px 0 rgba(0,0,0,.65),
              0 0 20px color-mix(in srgb, var(--accent) 60%, transparent);
  transition:text-shadow .6s;
}

.progress{ margin-top:5px; height:2px; background:rgba(255,255,255,.06); border-radius:99px; overflow:hidden; }
.progress-fill{ height:100%; width:0; background:var(--accent);
                box-shadow:0 0 8px color-mix(in srgb, var(--accent) 70%, transparent);
                transition:width .2s linear, background .6s; }
.hud-acc{ margin-top:4px; text-align:right;
          font:700 11px ui-monospace,SFMono-Regular,Menlo,monospace;
          font-variant-numeric:tabular-nums; color:var(--ink-dim); }

/* ── 2-player: the canvas draws each half's own HUD.
      The top of the screen belongs to player 2's pucks, so the pause
      chip moves onto the centre divider where neither board plays. ── */
.mode-2p .hud{
  top:50%; padding:0;
  background:none; border-bottom:0; box-shadow:none;
  height:0;
}
.mode-2p .hud-song,
.mode-2p .hud-score,
.mode-2p .hud-acc,
.mode-2p .progress{ display:none; }
.mode-2p .hud-top{ position:relative; height:0; }
.mode-2p .icon-btn{
  position:absolute; right:8px; top:-19px;
  width:34px; height:34px;
}

.overlay{
  position:absolute; inset:0; z-index:5;
  display:flex; align-items:center; justify-content:center;
  background:rgba(4,4,12,.78);
  -webkit-backdrop-filter:blur(14px);
  backdrop-filter:blur(14px);
  padding:calc(20px + var(--safe-t)) 20px calc(20px + var(--safe-b));
}
.overlay .panel{ width:100%; max-width:330px; display:flex; flex-direction:column; gap:11px; text-align:center; }
.overlay-top{ position:fixed; z-index:50; }

.countdown{
  position:absolute; inset:0; z-index:4;
  display:flex; align-items:center; justify-content:center;
  font:900 118px/1 -apple-system,BlinkMacSystemFont,sans-serif;
  color:#fff;
  text-shadow:0 0 56px color-mix(in srgb, var(--accent) 85%, transparent),
              0 0 18px rgba(255,255,255,.5);
  pointer-events:none;
}
.countdown.pop{ animation:cd .5s ease-out both; }
@keyframes cd{ from{ transform:scale(1.7); opacity:0; } 40%{ opacity:1; } to{ transform:scale(.85); opacity:0; } }

/* ── results ─────────────────────────────── */
.results{ text-align:center; gap:12px; display:flex; flex-direction:column; }

/* head-to-head */
.r-vs{ display:flex; flex-direction:column; gap:14px; }
.r-winner{
  font:900 italic 27px/1.1 -apple-system,BlinkMacSystemFont,"Arial Black",sans-serif;
  color:#ffd94a;
  -webkit-text-stroke:1px rgba(0,0,0,.55);
  text-shadow:0 3px 0 rgba(0,0,0,.5), 0 0 34px rgba(255,217,74,.5);
  animation:rankIn .55s var(--ease-pop) both;
}
.r-vs-grid{ display:grid; grid-template-columns:1fr 1fr; gap:10px; }
.r-vs-col{
  display:flex; flex-direction:column; gap:4px; align-items:center;
  padding:14px 8px; border-radius:14px;
  border:1px solid rgba(0,0,0,.7);
  background:
    linear-gradient(180deg, rgba(255,255,255,.10) 0%, rgba(255,255,255,0) 45%),
    linear-gradient(180deg,#1d1e3c,#101024);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 5px 0 #07070f;
}
.r-vs-col span{ font:800 9px ui-monospace,Menlo,monospace; letter-spacing:.18em; color:var(--ink-dim); }
.r-vs-col b{ font:900 italic 26px/1 -apple-system,BlinkMacSystemFont,sans-serif;
             font-variant-numeric:tabular-nums; color:#fff;
             text-shadow:0 2px 0 rgba(0,0,0,.6); }
.r-vs-col small{ font:700 10px ui-monospace,Menlo,monospace; color:var(--ink-dim); }
.r-vs-col.is-win{
  border-color:rgba(255,217,74,.5);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 5px 0 #4a3a06,
             0 0 30px rgba(255,217,74,.28);
}
.r-vs-col.is-win b{ color:#ffd94a; }
/* rank medallion — dark glass disc with an accuracy ring sweeping it */
.r-medal{
  position:relative; align-self:center;
  width:168px; height:168px;
  display:flex; align-items:center; justify-content:center;
  --p:0;                                  /* accuracy %, animated from JS */
  --rank-c:#4ade80;
  animation:rankIn .6s var(--ease-pop) both;
}
@keyframes rankIn{ from{ transform:scale(2.1) rotate(-8deg); opacity:0; } to{ transform:none; opacity:1; } }

.r-ring{
  position:absolute; inset:0; border-radius:50%;
  background:conic-gradient(from -90deg,
    var(--rank-c) calc(var(--p) * 1%),
    rgba(255,255,255,.07) 0);
  -webkit-mask:radial-gradient(circle, transparent 0 61%, #000 62.5%);
  mask:radial-gradient(circle, transparent 0 61%, #000 62.5%);
  filter:drop-shadow(0 0 13px color-mix(in srgb, var(--rank-c) 55%, transparent));
}
.r-medal::before{                          /* glass face */
  content:""; position:absolute; left:50%; top:50%;
  width:62%; height:62%; transform:translate(-50%,-50%);
  border-radius:50%;
  background:
    radial-gradient(circle at 32% 26%, rgba(255,255,255,.16), transparent 46%),
    radial-gradient(circle, color-mix(in srgb, var(--rank-c) 20%, #0b0b16) 0%, #06060e 74%);
  box-shadow:inset 0 2px 5px rgba(255,255,255,.16), inset 0 -8px 18px rgba(0,0,0,.75),
             0 0 32px color-mix(in srgb, var(--rank-c) 26%, transparent);
}
.rank{
  position:relative; z-index:1;
  font:900 italic 62px/1 -apple-system,BlinkMacSystemFont,"Arial Black",sans-serif;
  color:var(--rank-c);
  -webkit-text-stroke:1px rgba(0,0,0,.45);
  text-shadow:0 3px 0 rgba(0,0,0,.5), 0 0 28px color-mix(in srgb, var(--rank-c) 65%, transparent);
}
.r-medal[data-r="S"]{ --rank-c:#ffd94a; }
.r-medal[data-r="A"]{ --rank-c:#4ade80; }
.r-medal[data-r="B"]{ --rank-c:#22d3ee; }
.r-medal[data-r="C"]{ --rank-c:#a78bfa; }
.r-medal[data-r="D"]{ --rank-c:#fb3b6d; }

.r-accline{ display:flex; align-items:baseline; justify-content:center; gap:7px; margin-top:-6px; }
.r-accline b{ font:800 17px ui-monospace,Menlo,monospace; font-variant-numeric:tabular-nums; color:var(--ink); }
.r-accline small{ font:700 9px ui-monospace,Menlo,monospace; letter-spacing:.2em; color:var(--ink-dim); }

/* score delta vs the previous best */
.r-delta{ font:800 11px ui-monospace,Menlo,monospace; letter-spacing:.12em;
          min-height:13px; color:var(--ink-dim); }
.r-delta.is-best{ color:var(--gold); text-shadow:0 0 18px rgba(255,217,74,.45); }

/* judgment mix at a glance */
.r-bar{
  display:flex; height:10px; border-radius:6px; overflow:hidden;
  background:rgba(4,4,12,.85);
  border:1px solid rgba(0,0,0,.7);
  box-shadow:inset 0 1px 3px rgba(0,0,0,.8);
}
.r-bar i{
  display:block; width:0; height:100%;
  transition:width .75s cubic-bezier(.22,1,.36,1);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.3);
}

.r-song b{ display:block; font-size:18px; }
.r-song small{ font-size:9.5px; letter-spacing:.24em; color:var(--ink-dim); text-transform:uppercase; }
.r-score{ font:800 42px/1 ui-monospace,SFMono-Regular,Menlo,monospace;
          font-variant-numeric:tabular-nums; color:var(--ink);
          text-shadow:0 0 30px rgba(255,255,255,.14); }
.r-badges{ display:flex; gap:8px; justify-content:center; min-height:24px; flex-wrap:wrap; }
.badge{ font:800 10px/1 ui-monospace,Menlo,monospace; letter-spacing:.16em;
        padding:7px 12px; border-radius:99px; border:1px solid transparent; }
.badge-new{ background:rgba(80,62,0,.55); border-color:rgba(255,217,74,.4);
            color:var(--gold); box-shadow:0 0 24px rgba(255,217,74,.3); }
.badge-fc{ background:rgba(6,58,32,.6); border-color:rgba(74,222,128,.35); color:var(--great); }
.badge-fail{ background:rgba(66,12,30,.6); border-color:rgba(251,59,109,.35); color:var(--miss); }

.r-grid{ display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.r-grid > div{
  position:relative; overflow:hidden;
  display:flex; justify-content:space-between; align-items:center;
  background:linear-gradient(180deg, rgba(24,26,54,.8), rgba(12,13,32,.8));
  border:1px solid rgba(0,0,0,.6);
  border-radius:11px; padding:10px 12px 10px 15px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.09);
  animation:rowIn .5s cubic-bezier(.22,1,.36,1) both;
}
.r-grid > div::before{                     /* colored edge per judgment */
  content:""; position:absolute; left:0; top:0; bottom:0; width:3px;
  background:var(--c, var(--ink-dim)); box-shadow:0 0 10px var(--c, transparent);
}
.r-grid .c-perfect{ --c:var(--perfect); animation-delay:.05s; }
.r-grid .c-great{ --c:var(--great); animation-delay:.10s; }
.r-grid .c-good{ --c:var(--good); animation-delay:.15s; }
.r-grid .c-miss{ --c:var(--miss); animation-delay:.20s; }
.r-grid .c-combo{ --c:#a78bfa; animation-delay:.25s; grid-column:1 / -1; }
.r-grid span{ font:700 9.5px ui-monospace,Menlo,monospace; letter-spacing:.14em; color:var(--ink-dim); }
.r-grid b{ font:800 16px ui-monospace,Menlo,monospace; font-variant-numeric:tabular-nums; color:var(--ink); }

/* ── add a song ──────────────────────────── */
.add-panel{ max-width:380px; }
.add-pane{ display:flex; flex-direction:column; gap:10px; }
.hint-sm{ font-size:11px; opacity:.75; }
.add-searchrow{ display:flex; gap:8px; }
.add-searchrow .text-input{ flex:1; }
.add-searchrow .btn{ flex:none; padding-left:18px; padding-right:18px; }
.add-msg{ min-height:16px; font:700 11px/1.5 ui-monospace,Menlo,monospace;
          color:var(--miss); text-align:center; }
.add-msg.ok{ color:var(--great); }

.add-results{
  display:flex; flex-direction:column; gap:6px;
  max-height:32vh; overflow-y:auto; overscroll-behavior:contain;
  scrollbar-width:none;
}
.add-results::-webkit-scrollbar{ display:none; }
.sr{
  display:flex; align-items:center; gap:10px;
  padding:8px; border-radius:12px; cursor:pointer;
  background:linear-gradient(180deg, rgba(30,32,68,.8), rgba(14,15,36,.8));
  border:1px solid rgba(0,0,0,.6);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.08);
  -webkit-tap-highlight-color:transparent;
}
.sr:active{ transform:scale(.985); }
.sr img{ width:40px; height:40px; border-radius:8px; flex:none; background:#12122a; }
.sr div{ flex:1; min-width:0; text-align:left; }
.sr b{ display:block; font-size:13px; font-weight:800;
       white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.sr small{ display:block; font-size:10px; color:var(--ink-dim);
           white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* ── share sheet ─────────────────────────── */
.btn-share{
  background:
    linear-gradient(180deg, rgba(255,255,255,.26) 0%, rgba(255,255,255,0) 44%),
    linear-gradient(180deg, #b467ff 0%, #7a2fd6 55%, #45178a 100%);
  color:#fff;
  text-shadow:0 2px 3px rgba(0,0,0,.7);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.5),
    inset 0 -3px 9px rgba(0,0,0,.4),
    0 5px 0 #2a0d55,
    0 0 30px rgba(160,90,255,.35);
}
.btn-share:active{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4), inset 0 3px 10px rgba(0,0,0,.45),
             0 0 0 #2a0d55, 0 0 18px rgba(160,90,255,.3);
}

.share-panel{ max-width:360px; }
.share-preview{
  display:flex; justify-content:center;
  padding:10px 0 4px;
}
.share-preview canvas{
  max-height:38vh; max-width:100%;
  height:auto; width:auto;
  border-radius:12px;
  border:1px solid rgba(255,255,255,.12);
  box-shadow:0 14px 34px rgba(0,0,0,.6);
}
.share-fmt{ display:flex; gap:6px; padding:4px; border-radius:13px;
            background:var(--glass-2); border:1px solid var(--line); }
.share-note{ min-height:15px; font:700 10px ui-monospace,Menlo,monospace;
             letter-spacing:.1em; color:var(--great); text-align:center; }

/* privacy — long-form text, so it reads rather than shouts */
.pv{ margin:0; font-size:13px; line-height:1.6; color:var(--ink-dim); }
.pv b{ color:var(--ink); }
.pv-h{ margin:14px 0 -2px; font:800 10px/1 ui-monospace,Menlo,monospace;
       letter-spacing:.18em; text-transform:uppercase; color:var(--accent); }
.pv-l{ margin:0; padding-left:18px; font-size:13px; line-height:1.6; color:var(--ink-dim); }
.pv-l li{ margin:6px 0; }
.pv-l b{ color:var(--ink); }
.pv-contact{ margin-top:14px; }
.pv a{ color:var(--accent); text-decoration:none; font-weight:700; }
.pv a:active{ opacity:.6; }
.pv-dim{ font-size:11px; opacity:.6; }

/* a secondary action that shouldn't compete with the two input rows */
.btn-sm{ padding-block:9px; font-size:11px; letter-spacing:.14em; }

/* search is out — offer the two routes that still work rather than a
   dead message */
.nosearch{ display:flex; flex-direction:column; gap:10px; padding:4px 2px 2px; }
.nosearch-msg{ margin:0; font-size:12px; line-height:1.45; color:var(--ink-dim); text-align:center; }
.nosearch-label{ font:800 9px/1 ui-monospace,Menlo,monospace; letter-spacing:.18em;
                 color:var(--ink-dim); }
.nosearch-find{ font-size:11px; font-weight:700; color:var(--accent); text-decoration:none;
                text-align:center; }
.nosearch-find:active{ opacity:.6; }

/* shown only after a stall has lasted a few seconds */
.stall-note{ position:absolute; left:50%; top:52%; transform:translate(-50%,-50%);
             z-index:40; display:flex; flex-direction:column; align-items:center; gap:6px;
             padding:14px 20px; border-radius:14px; text-align:center;
             background:rgba(6,6,16,.82); border:1px solid var(--line);
             backdrop-filter:blur(6px);
             font:800 13px/1.3 ui-monospace,Menlo,monospace; letter-spacing:.08em;
             color:var(--ink); }
.stall-note small{ font-size:10px; font-weight:700; letter-spacing:.1em; color:var(--ink-dim); }

/* the rows above this line cost nothing; the ones below spend one of
   the day's hundred YouTube lookups — worth making visible */
.res-sep{ display:flex; align-items:center; gap:8px; margin:10px 2px 6px;
          font:800 9px/1 ui-monospace,Menlo,monospace; letter-spacing:.18em;
          color:var(--ink-dim); }
.res-sep::before, .res-sep::after{ content:''; flex:1; height:1px; background:var(--line); }

/* says what the clip actually contains, so nobody expects the song */
.share-fine{ margin:-4px 0 0; font-size:11px; font-weight:600; line-height:1.45;
             color:var(--ink-dim); text-align:center; }

/* ── analyser ────────────────────────────── */
.an-name{ font-size:14px; color:var(--ink); word-break:break-word; }
.an-bar{ height:8px; border-radius:99px; background:rgba(10,10,26,.85);
         box-shadow:inset 0 1px 2px rgba(0,0,0,.5); overflow:hidden; }
.an-fill{
  height:100%; width:0;
  background:linear-gradient(90deg,#a78bfa,#2ee6ff,#ffd94a);
  background-size:200% 100%;
  animation:shimmer 2s linear infinite;
  transition:width .12s linear;
}
.an-pct{ font:800 24px ui-monospace,Menlo,monospace; color:var(--lane-0); }

@media (max-width:360px){
  .r-grid{ grid-template-columns:1fr; }
  .rank{ font-size:68px; }
  .logo-muse{ font-size:64px; }
}

/* ── YouTube levels ───────────────────────
   The player is one absolutely-positioned box that is never
   re-parented (moving an iframe in the DOM reloads it, which would
   kill playback between the tap step and the run). It gets moved by
   rect instead — over the tap panel, then over the top of the
   playfield. */
#yt-stage{
  position:absolute; z-index:60;
  overflow:hidden; background:#000;
  border:1px solid rgba(255,255,255,.14);
  box-shadow:0 10px 30px rgba(0,0,0,.65);
}
#yt-stage iframe{ display:block; width:100%; height:100%; border:0; }
/* swallow taps so they never reach YouTube's own controls */
#yt-stage .yt-veil{ position:absolute; inset:0; background:transparent; }

/* the strip pushes the board and the HUD down by its own height */
.mode-yt #stage{ top:var(--yt-h,0px); height:calc(100% - var(--yt-h,0px)); }
.mode-yt .hud{ top:var(--yt-h,0px); padding-top:8px; }
/* 2P puts the video on the split line instead of above the lanes, so the
   canvas keeps its full height and Renderer carves the band out inside it */
.mode-2p.mode-yt #stage{ top:0; height:100%; }

.yt-or{ display:flex; align-items:center; gap:10px; color:var(--ink-dim);
        font:800 9px/1 ui-monospace,Menlo,monospace; letter-spacing:.22em;
        text-transform:uppercase; }
.yt-or::before, .yt-or::after{ content:''; flex:1; height:1px; background:var(--line); }

.yt-panel{ max-width:400px; }
/* placeholder the floating player is positioned over */
.yt-slotbox{ width:100%; aspect-ratio:16/9; border-radius:12px; background:#08080f;
             border:1px solid var(--line); }
.yt-name{ font-size:13px; font-weight:800; color:var(--ink); word-break:break-word; }
.yt-tapbtn{ font-size:15px; padding-top:16px; padding-bottom:16px; }
.yt-dots{ display:flex; gap:8px; justify-content:center; min-height:12px; }
.yt-dots i{ width:11px; height:11px; border-radius:50%;
            background:rgba(255,255,255,.13); border:1px solid rgba(255,255,255,.18);
            transition:background .12s, transform .12s; }
.yt-dots i.on{ background:var(--accent); transform:scale(1.25);
               box-shadow:0 0 12px color-mix(in srgb, var(--accent) 70%, transparent); }
.yt-tag{ background:#fb3b6d !important; color:#fff !important; }

/* a disabled game button must read as unavailable, not just inert */
.btn[disabled]{ opacity:.38; filter:saturate(.35); pointer-events:none; }

/* the ready-gate must sit above the video strip, not under it */
#yt-go{ z-index:65; }

/* ── public library + leaderboard ─────────── */
.song-dl{
  flex:none; align-self:center;
  padding:9px 13px; border-radius:10px;
  border:1px solid rgba(0,0,0,.7);
  background:linear-gradient(180deg, rgba(255,255,255,.18) 0%, rgba(255,255,255,0) 45%),
             linear-gradient(180deg,#2ee6ff,#1897c4);
  color:#04202a; font:900 10px/1 ui-monospace,Menlo,monospace; letter-spacing:.12em;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.4), 0 3px 0 #05050c;
  -webkit-tap-highlight-color:transparent;
}
.song-dl:active{ transform:translateY(3px); box-shadow:inset 0 1px 0 rgba(255,255,255,.3), 0 0 0 #05050c; }
.song-dl[disabled]{ opacity:.45; filter:saturate(.3); }
.song-flag{
  flex:none; align-self:center; width:26px; height:26px;
  border-radius:8px; border:1px solid var(--line);
  background:rgba(255,255,255,.05); color:var(--ink-dim); font-size:12px;
  -webkit-tap-highlight-color:transparent;
}

.r-board{ display:flex; flex-direction:column; gap:8px; }
.r-board-head{ display:flex; align-items:center; gap:8px; }
.r-board-head span{ font:800 9px/1 ui-monospace,Menlo,monospace; letter-spacing:.22em;
                    color:var(--ink-dim); white-space:nowrap; }
.r-board-head .text-input{ flex:1; padding:8px 10px; font-size:12px; }
.r-board-list{ display:flex; flex-direction:column; gap:4px; max-height:150px; overflow-y:auto; }
.lb{
  display:flex; align-items:center; gap:9px;
  padding:7px 10px; border-radius:9px;
  background:rgba(255,255,255,.04); border:1px solid var(--line);
  font-size:12px;
}
.lb.is-me{ border-color:color-mix(in srgb, var(--accent) 60%, transparent);
           background:color-mix(in srgb, var(--accent) 12%, transparent); }
.lb i{ font-style:normal; width:20px; color:var(--ink-dim);
       font:800 10px ui-monospace,Menlo,monospace; }
.lb b{ flex:1; min-width:0; font-weight:700; overflow:hidden;
       text-overflow:ellipsis; white-space:nowrap; }
.lb span{ font:800 12px ui-monospace,Menlo,monospace; font-variant-numeric:tabular-nums; }
.r-board-note{ font-size:10px; line-height:1.5; color:var(--ink-dim); text-align:center; }


/* ── beat nudge (pause menu, YouTube levels) ── */
.nudge{ display:flex; flex-direction:column; gap:7px; align-items:center;
        padding:11px 12px; border-radius:13px;
        background:rgba(255,255,255,.05); border:1px solid var(--line); }
.nudge-label{ font:800 9px/1 ui-monospace,Menlo,monospace; letter-spacing:.22em; color:var(--ink-dim); }
.nudge-row{ display:flex; align-items:center; gap:14px; }
.nudge-row b{ min-width:74px; text-align:center;
              font:900 17px ui-monospace,Menlo,monospace; font-variant-numeric:tabular-nums; color:var(--ink); }
.nudge-btn{
  width:44px; height:38px; flex:none; cursor:pointer;
  border:1px solid rgba(0,0,0,.7); border-radius:11px;
  background:linear-gradient(180deg, rgba(255,255,255,.20) 0%, rgba(255,255,255,0) 45%),
             linear-gradient(180deg,#2a2b46,#12121f);
  color:#cfd4f5; font-size:13px; line-height:1;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28), 0 3px 0 #05050c;
  -webkit-tap-highlight-color:transparent;
}
.nudge-btn:active{ transform:translateY(3px); box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 0 0 #05050c; }
.nudge small{ font-size:10px; line-height:1.45; color:var(--ink-dim); text-align:center; }

/* Four-up tab rows (ADD A SONG) don't fit at 375px with the default
   tracking: measured 307px of tabs in a 284px frame, and the
   letter-spacing plus matching text-indent is most of the excess. */
.diff-row.is-four .diff{
  font-size:10px; letter-spacing:.03em; text-indent:0; padding-left:2px; padding-right:2px;
}
@media (max-width:340px){
  .diff-row.is-four .diff{ font-size:9px; letter-spacing:0; }
}

/* ── results: full screen, must fit without scrolling ──────
   Measured before this pass: 905px of content in a 667px viewport,
   with the medallion alone taking 389px. Budget is ~570px at 375x667,
   so every block below is sized against that. */
.screen-results{
  align-items:stretch; justify-content:flex-start;
  padding:calc(10px + var(--safe-t)) 14px calc(78px + var(--safe-b));
}
.screen-results .stack{ gap:8px; margin:auto 0; }
.results{ text-align:center; }

/* medallion 389 -> 150, with accuracy moved inside the ring */
.screen-results .r-medal{
  width:150px; height:150px; margin:0 auto;
}
.screen-results .rank{ font-size:56px; }
.r-inacc{
  position:absolute; left:0; right:0; bottom:24px;
  font:800 11px ui-monospace,Menlo,monospace;
  font-variant-numeric:tabular-nums; color:var(--ink-dim);
  pointer-events:none;
}

/* one line, never two */
.screen-results .r-song b{
  font-size:15px; line-height:1.25;
  display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.screen-results .r-song small{ font-size:8.5px; }
.screen-results .r-score{ font-size:34px; }
.screen-results .r-badges{ min-height:0; }

/* five stat chips in one row instead of a 136px grid */
.screen-results .r-grid{
  display:flex; gap:5px;
}
.screen-results .r-grid > div{
  flex:1 1 0; min-width:0;
  display:flex; flex-direction:column; align-items:center; gap:2px;
  padding:7px 2px;
}
.screen-results .r-grid .c-combo{ grid-column:auto; }
.screen-results .r-grid span{ font-size:7.5px; letter-spacing:.06em; }
.screen-results .r-grid b{ font-size:14px; }

.screen-results .r-board-list{ max-height:none; gap:3px; }
.screen-results .lb{ padding:5px 9px; font-size:11.5px; }
.lb em{ font-style:normal; font:700 8.5px ui-monospace,Menlo,monospace;
        letter-spacing:.1em; color:var(--ink-dim); flex:none; }
.r-board-head b{ color:var(--accent); }
.screen-results .r-board-note{ font-size:9px; }

/* the way out, pinned above the home indicator */
.r-actions{
  position:absolute; left:0; right:0; bottom:0; z-index:3;
  display:flex; gap:7px;
  padding:9px 14px calc(9px + var(--safe-b));
  background:linear-gradient(180deg, rgba(5,5,16,0) 0%, rgba(5,5,16,.92) 42%);
}
.r-actions .btn{ flex:1 1 0; min-width:0; padding:13px 4px; font-size:11.5px; letter-spacing:.08em; }

/* the automatic beat fix */
#fix-overlay{ z-index:66; }
#fix-overlay .panel{ max-width:340px; text-align:center; }
.fix-amt{ font:800 11px ui-monospace,Menlo,monospace; letter-spacing:.14em;
          color:var(--great); }

/* ── challenge link landing ──────────────── */
.ch-song{ font-size:17px; font-weight:800; color:var(--ink); text-align:center; line-height:1.3; }
.ch-prefs{ display:flex; flex-direction:column; align-items:center; gap:8px; }
.ch-prefs span{ font:700 10px ui-monospace,Menlo,monospace; letter-spacing:.16em;
                color:var(--ink-dim); text-transform:uppercase; }
.ch-pills{ display:flex; gap:7px; }
.ch-pills b{
  padding:8px 15px; border-radius:11px;
  background:color-mix(in srgb, var(--accent) 16%, transparent);
  border:1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  color:var(--ink); font:800 11px ui-monospace,Menlo,monospace; letter-spacing:.12em;
}
.ch-score{ text-align:center; font:800 13px ui-monospace,Menlo,monospace;
           letter-spacing:.1em; color:var(--gold); }

/* Short phones (SE-class, 568px): 617px of results still wants ~50px.
   The action bar is pinned so the way out is never lost either way,
   but it should fit outright rather than nearly. */
@media (max-height:620px){
  .screen-results .r-medal{ width:116px; height:116px; }
  .screen-results .rank{ font-size:44px; }
  .r-inacc{ bottom:17px; font-size:10px; }
  .screen-results .r-score{ font-size:28px; }
  .screen-results .r-song b{ font-size:13.5px; }
  .screen-results .stack{ gap:6px; }
  .screen-results .r-board-note{ display:none; }
  .screen-results .r-grid b{ font-size:13px; }
}

/* ── bottom nav ───────────────────────────
   Replaces the per-screen BACK button. Sits above every screen and
   below the game, so a run stays edge-to-edge. */
.nav{
  position:absolute; left:0; right:0; bottom:0; z-index:5;
  display:flex; gap:2px;
  padding:6px 8px calc(6px + var(--safe-b));
  background:
    linear-gradient(180deg, rgba(255,255,255,.07) 0%, rgba(255,255,255,0) 34%),
    linear-gradient(180deg, rgba(8,8,18,.90) 0%, rgba(6,6,14,.98) 60%);
  border-top:1px solid var(--line);
  box-shadow:0 -10px 30px rgba(0,0,0,.55);
  -webkit-backdrop-filter:blur(18px); backdrop-filter:blur(18px);
}
.nav-btn{
  flex:1 1 0; min-width:0; appearance:none; cursor:pointer;
  display:flex; flex-direction:column; align-items:center; gap:3px;
  padding:8px 2px 6px; border:0; border-radius:12px;
  background:transparent; color:var(--ink-dim);
  font:800 8.5px/1 ui-monospace,Menlo,monospace; letter-spacing:.1em;
  transition:color .18s, background .18s;
  -webkit-tap-highlight-color:transparent;
}
.nav-ico{ font-size:15px; line-height:1; }
.nav-btn.is-on{
  color:var(--accent);
  background:color-mix(in srgb, var(--accent) 13%, transparent);
}
.nav-btn:active{ transform:translateY(1px); }

/* screens keep clear of the bar */
body.has-nav .screen{ padding-bottom:calc(84px + var(--safe-b)); }
/* results already pins its own action row — stack it above the bar */
body.has-nav .r-actions{ bottom:calc(60px + var(--safe-b)); padding-bottom:9px; }
body.has-nav .screen-results{ padding-bottom:calc(140px + var(--safe-b)); }

/* difficulty + length, in place on the track list */
.pick{ display:flex; flex-direction:column; gap:8px;
       padding:11px 12px; border-radius:16px;
       background:var(--glass-2); border:1px solid var(--line); }
.pick-row{ display:flex; flex-direction:column; gap:5px; }
.pick-label{ font:800 8.5px/1 ui-monospace,Menlo,monospace; letter-spacing:.22em;
             color:var(--ink-dim); }
.pick .diff-row{ background:transparent; border:0; box-shadow:none; padding:0; gap:5px; }
.pick .diff{ padding:9px 4px; font-size:10.5px; letter-spacing:.08em; text-indent:0; }

/* ── album sleeve with a vinyl peeking out ─────────────
   All CSS, no image assets: the grooves are a repeating radial
   gradient and the label picks up the row's own --sc accent. */
.cover{
  position:relative; flex:none;
  width:82px; height:56px;          /* sleeve + the slice of record */
  align-self:center;
}
.vinyl{
  position:absolute; top:50%; right:0;
  width:56px; height:56px; margin-top:-28px;
  border-radius:50%;
  background:
    radial-gradient(circle at 50% 50%,
      color-mix(in srgb, var(--sc,#a78bfa) 85%, #000) 0 17%,
      #0b0b12 17.5% 19%,
      transparent 19.5%),
    repeating-radial-gradient(circle at 50% 50%,
      #15151f 0 1.5px, #0a0a11 1.5px 3px),
    #0d0d15;
  box-shadow:0 3px 10px rgba(0,0,0,.75), inset 0 0 0 1px rgba(255,255,255,.06);
  transition:transform .22s var(--ease-pop, ease);
}
/* a sheen across the record so it reads as vinyl, not a dark circle */
.vinyl::after{
  content:''; position:absolute; inset:0; border-radius:50%;
  background:linear-gradient(122deg, rgba(255,255,255,.16) 0 12%,
                                     rgba(255,255,255,0) 26% 60%,
                                     rgba(255,255,255,.09) 74% 84%,
                                     rgba(255,255,255,0) 92%);
}
.sleeve{
  position:absolute; left:0; top:50%;
  width:56px; height:56px; margin-top:-28px;
  border-radius:9px; overflow:hidden;
  background:linear-gradient(145deg,
    color-mix(in srgb, var(--sc,#a78bfa) 70%, transparent),
    color-mix(in srgb, var(--sc,#a78bfa) 24%, #0a0a14));
  border:1px solid rgba(255,255,255,.14);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22), 0 4px 12px rgba(0,0,0,.5);
  display:flex; align-items:center; justify-content:center;
}
.sleeve img{ width:100%; height:100%; object-fit:cover; display:block; }
.sleeve img + span{ display:none; }        /* art wins over the glyph */
.sleeve span{ font-size:20px; color:#fff; text-shadow:0 2px 6px rgba(0,0,0,.6); }
.song:active .vinyl{ transform:translateX(5px) rotate(22deg); }

/* ── compact rows: 91 songs shouldn't be four lines each ── */
.song{ padding:9px 11px; gap:11px; }
.song-title{
  font-size:14px; line-height:1.25; font-weight:800;
  display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
  -webkit-line-clamp:none;
}
.song-by{
  font-size:11.5px; color:var(--ink-dim);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.song-meta{ font-size:10px; letter-spacing:.02em; }

/* ── genre chips: scroll, never collide ── */
#lib-genres{
  display:flex; flex-wrap:nowrap; overflow-x:auto; overflow-y:hidden;
  gap:5px; scrollbar-width:none; -webkit-overflow-scrolling:touch;
  -webkit-mask-image:linear-gradient(90deg,#000 0 92%,transparent 100%);
          mask-image:linear-gradient(90deg,#000 0 92%,transparent 100%);
}
#lib-genres::-webkit-scrollbar{ display:none; }
#lib-genres .diff{
  flex:0 0 auto; white-space:nowrap;
  padding-left:13px; padding-right:13px; font-size:10px; letter-spacing:.08em;
}

/* Frozen header, shared by the library and the track list: with ~98
   rows, having to scroll back to the top to search, change genre or
   change difficulty is the whole friction. The list
   passes underneath, so the bar needs its own ground — a blur plus a
   soft fade at the bottom edge, so rows dissolve into it instead of
   being sliced off by a hard line.

   The negative inline margin lets the ground reach past the rows'
   rounded corners and shadows; without it they peek out at the sides. */
.frozen-head{
  position:sticky; top:calc(-2px - var(--safe-t)); z-index:6;
  display:flex; flex-direction:column; gap:10px;
  margin-inline:-18px; padding:12px 18px 10px;
  /* the dissolve is a fixed distance from the bottom edge, not a
     percentage: this header is ~100px on the library and ~280px on the
     track list, and a percentage fade left the search field sitting in
     the transparent part with rows showing through it */
  background:linear-gradient(180deg,
    rgba(6,6,16,.97) 0,
    rgba(6,6,16,.97) calc(100% - 18px),
    rgba(6,6,16,0)   100%);
  -webkit-backdrop-filter:blur(14px);
          backdrop-filter:blur(14px);
}
/* the fade is part of the background, so give the controls clear air
   above the dissolve rather than letting chips sit in it */
.frozen-head #lib-genres{ margin-bottom:6px; }

/* A scroll container's own top padding is part of the scrollable area,
   so rows slide up into the strip above the frozen bar and peek out.
   Nothing is drawn in that strip at rest — it is the safe-area inset —
   so covering it permanently is free.

   The cover hangs off <body>, NOT off .screen, and that is the whole
   trick: .screen carries a filter, which makes it the containing block
   for fixed descendants, so a fixed child of it scrolls away with the
   list instead of staying put. Anchoring to body keeps it genuinely
   fixed. :has() scopes it to the one screen that needs it. */
body:has(#screen-library.is-active, #screen-select.is-active)::before{
  content:''; position:fixed; left:0; right:0; top:0;
  height:calc(22px + var(--safe-t)); z-index:7;
  background:rgba(6,6,16,.97);
  pointer-events:none;
}

/* ── list search + empty states ── */
.text-input.search{ padding:11px 13px; font-size:13px; }
.empty{ display:flex; flex-direction:column; gap:11px; align-items:center;
        padding:22px 14px; text-align:center; }
.empty p{ margin:0; font-size:13px; color:var(--ink-dim); }
.empty .btn{ width:100%; }

/* inline icons: font-independent, so iOS can't draw tofu where a glyph
   used to be. They inherit colour from whatever contains them. */
.ic{ display:block; flex:none; }
.sleeve span .ic{ opacity:.92; filter:drop-shadow(0 2px 4px rgba(0,0,0,.55)); }
.song-ren .ic, .song-del .ic, .song-flag .ic{ margin:0 auto; }
.icon-btn .ic, .nudge-btn .ic{ margin:0 auto; }

/* the beat learned something this run — a note, not an interruption */
.r-tuned{ font:700 10px ui-monospace,Menlo,monospace; letter-spacing:.06em;
          color:var(--great); opacity:.85; }
