* { box-sizing: border-box; margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; }
/* Inline SVG icon (replaces emoji in buttons/labels) — scales with the text size. */
.svi { width: 1.1em; height: 1.1em; flex: none; vertical-align: -0.18em; }
:root, [data-theme="classic"] {
  /* CLASSIC — default dark + Spotify green */
  --bg: #0b0e14; --bg2: #11161f; --bg3: #1a2230; --border: #1e2632;
  --text: #e6edf3; --dim: #9aa7b8; --mute: #5a6678;
  --accent: #1db954; --accent2: #4f8df9; --sidebar-bg: #07090d; --danger: #ff6b6b;
}
/* Non-classic themes: backgrounds stay close to the classic neutral dark with only
   a FAINT hue tint — the accent is what makes each theme distinct, not the surface. */
[data-theme="blue"] {
  --bg: #090d15; --bg2: #11161f; --bg3: #1b2336; --border: #212a3f;
  --text: #e3e9f3; --dim: #93a1b8; --mute: #586677;
  --accent: #4f8df9; --accent2: #79aaff; --sidebar-bg: #06090f; --danger: #e25c5c;
}
[data-theme="neutral"] {
  --bg: #0c0f15; --bg2: #12171f; --bg3: #1c2431; --border: #232b38;
  --text: #e3e8ef; --dim: #919daf; --mute: #5d6878;
  --accent: #8a99ad; --accent2: #aebccf; --sidebar-bg: #080b10; --danger: #e25c5c;
}
[data-theme="synthwave"] {
  --bg: #0d0814; --bg2: #150f1f; --bg3: #241934; --border: #2b1d40;
  --text: #ece2f3; --dim: #a596b8; --mute: #6d5f82;
  --accent: #ff2cb6; --accent2: #00f0ff; --sidebar-bg: #08050e; --danger: #ff5a8a;
}
[data-theme="crimson"] {
  --bg: #100a0c; --bg2: #181113; --bg3: #2a1f23; --border: #31242a;
  --text: #f0e2e4; --dim: #b0989c; --mute: #7a626a;
  --accent: #e63946; --accent2: #ff8a96; --sidebar-bg: #0b0608; --danger: #ff5a68;
}
[data-theme="forest"] {
  --bg: #0a0f0c; --bg2: #111913; --bg3: #1d2a22; --border: #223029;
  --text: #e2ece6; --dim: #97aaa0; --mute: #5f7268;
  --accent: #34d399; --accent2: #5ff5b8; --sidebar-bg: #070b09; --danger: #ff6b6b;
}
[data-theme="amber"] {
  --bg: #100d08; --bg2: #181510; --bg3: #2a241a; --border: #302a20;
  --text: #ece6da; --dim: #b0a690; --mute: #79705c;
  --accent: #f59e0b; --accent2: #ffc04a; --sidebar-bg: #0b0805; --danger: #ff6b6b;
}
[data-theme="royal"] {
  --bg: #0c0a14; --bg2: #14121f; --bg3: #241f34; --border: #2a233c;
  --text: #e7e2f3; --dim: #9d92b8; --mute: #685d82;
  --accent: #a78bfa; --accent2: #c4adff; --sidebar-bg: #08060f; --danger: #ff6b6b;
}

/* ════════════ SPECIAL themes — richer surfaces + animated FX (particles in #themeFx) ════════════ */
[data-theme="gold"] {
  /* Black-and-gold luxury: near-black surfaces, a bright gilt border, and a reusable
     metallic gradient (alternating dark/bright/pale stops = a reflective gold sheen). */
  --bg: #0a0702; --bg2: #15110a; --bg3: #271e10; --border: #4a3717;
  --text: #f8f0d8; --dim: #cbb482; --mute: #8a7549;
  --accent: #ecc94f; --accent2: #fff0bf; --sidebar-bg: #060401; --danger: #ff6b6b;
  --gold-metal: linear-gradient(135deg, #8a6512 0%, #e6bf52 15%, #fff3cf 30%, #f0cb60 44%, #b8860b 58%, #ecc94f 76%, #c99a22 100%);
  --gold-edge: #ffe9a8;
}
[data-theme="cosmic"] {
  --bg: #05060f; --bg2: #0b0e20; --bg3: #1a2046; --border: #232a55;
  --text: #e6e9ff; --dim: #9aa3d4; --mute: #5f6798;
  --accent: #8b7bff; --accent2: #4fd6ff; --sidebar-bg: #03040b; --danger: #ff6b8a;
}
[data-theme="sakura"] {
  --bg: #140a10; --bg2: #20111a; --bg3: #3a2030; --border: #46293c;
  --text: #fce7f0; --dim: #d2a4bb; --mute: #976a82;
  --accent: #ff8fb8; --accent2: #ffd1e2; --sidebar-bg: #0e0710; --danger: #ff5a8a;
}
[data-theme="ember"] {
  --bg: #100804; --bg2: #1d0f06; --bg3: #381d0c; --border: #46240f;
  --text: #ffe9d8; --dim: #ca9b7a; --mute: #8c6449;
  --accent: #ff6b2c; --accent2: #ffb05a; --sidebar-bg: #0a0502; --danger: #ff5a4a;
}
[data-theme="winter"] {
  --bg: #070b12; --bg2: #0d141f; --bg3: #1b2838; --border: #213040;
  --text: #eaf2fb; --dim: #9fb4cc; --mute: #647688;
  --accent: #7ec8f0; --accent2: #cfeaff; --sidebar-bg: #05080e; --danger: #ff6b6b;
}
/* ════════════ MIXED themes — two distinct accent hues that blend across signature surfaces ════════════ */
[data-theme="firefrost"] {
  --bg: #0c0e12; --bg2: #12161d; --bg3: #1d2530; --border: #26303c;
  --text: #eaf0f4; --dim: #9fb0ba; --mute: #62707e;
  --accent: #ff5e3a; --accent2: #46d9ff; --sidebar-bg: #08090d; --danger: #ff6b6b;
}
[data-theme="aurora"] {
  --bg: #0a0f11; --bg2: #10171c; --bg3: #1b2a2c; --border: #213237;
  --text: #e6f0ee; --dim: #97aeac; --mute: #5e7372;
  --accent: #34d399; --accent2: #5b8dff; --sidebar-bg: #060c0d; --danger: #ff6b6b;
}
[data-theme="sunset"] {
  --bg: #110b0d; --bg2: #1a1114; --bg3: #2c1d22; --border: #342229;
  --text: #f4e6e9; --dim: #b89aa1; --mute: #7e626a;
  --accent: #ff5d8f; --accent2: #ffb24a; --sidebar-bg: #0c0608; --danger: #ff5a68;
}
[data-theme="vapor"] {
  --bg: #0c0a14; --bg2: #13111f; --bg3: #221f36; --border: #2a2540;
  --text: #ece6f6; --dim: #a99dc4; --mute: #6c6190;
  --accent: #b56bff; --accent2: #36e0d0; --sidebar-bg: #08060f; --danger: #ff6b8a;
}
[data-theme="firefrost"] html { background: radial-gradient(120% 90% at 10% -10%, #2a1108 0%, #0c0e12 55%), radial-gradient(110% 85% at 92% 112%, #06242f 0%, #0c0e12 58%); }
[data-theme="aurora"] html { background: radial-gradient(120% 90% at 14% -12%, #0c2a1e 0%, #0a0f11 56%), radial-gradient(110% 85% at 90% 110%, #0d1c3a 0%, #0a0f11 58%); }
[data-theme="sunset"] html { background: radial-gradient(120% 95% at 50% -15%, #2c1020 0%, #110b0d 58%), radial-gradient(110% 80% at 88% 112%, #2e1c08 0%, #110b0d 60%); }
[data-theme="vapor"] html { background: radial-gradient(120% 90% at 18% -10%, #221045 0%, #0c0a14 56%), radial-gradient(110% 85% at 86% 110%, #062e2c 0%, #0c0a14 58%); }
/* Blend the two hues across EVERY prominent accent block (class set in applyTheme) so
   neither colour dominates — hue A alone is used in far more places than hue B. */
.theme-mixed .btns .play { background: linear-gradient(135deg, var(--accent), var(--accent2)); }
.theme-mixed .pheader .play-all, .theme-mixed .play-all { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: var(--bg); }
.theme-mixed .seek-fill { background: linear-gradient(to right, var(--accent) 0, var(--accent2) var(--fill, 0%), var(--bg3) var(--fill, 0%) 100%); }
.theme-mixed .src-pill.active,
.theme-mixed .gc-tab.active,
.theme-mixed .gtab.active,
.theme-mixed .sort-toggle input:checked ~ .dl-switch,
.theme-mixed .dl-toggle input:checked ~ .dl-switch,
.theme-mixed .mr-toggle input:checked ~ .dl-switch,
.theme-mixed .dl-app-btn,
.theme-mixed .sync-queue-btn.primary,
.theme-mixed .dc-btn.dc-primary,
.theme-mixed .dialog-actions .dlg-ok,
.theme-mixed .chat-input button,
.theme-mixed .list li .unread-badge,
.theme-mixed .row .q-resume-tag,
.theme-mixed .progress-fill,
.theme-mixed .dc-prog-fill,
.theme-mixed .toast-bar { background-image: linear-gradient(120deg, var(--accent), var(--accent2)); }
/* Pull hue B into a few recurring small accents so it's present, not just in big blocks. */
.theme-mixed .home-card .live-dot,
.theme-mixed #shuffleBtn.active::after,
.theme-mixed .dc-dot.on { background: var(--accent2); }
.theme-mixed .linkbtn:hover,
.theme-mixed .nav-link.active,
.theme-mixed .activity-log .log-pl,
.theme-mixed .src-sub a:hover { color: var(--accent2); }

/* Per-theme background wash on <html> (behind the FX layer + content). */
[data-theme="gold"] html { background: radial-gradient(135% 105% at 50% -25%, #2a1d08 0%, #0a0702 62%); }
[data-theme="cosmic"] html { background: radial-gradient(120% 90% at 78% -10%, #161139 0%, #05060f 55%), radial-gradient(100% 80% at 12% 8%, #051e30 0%, #05060f 60%); }
[data-theme="sakura"] html { background: radial-gradient(120% 95% at 50% -15%, #2a1320 0%, #140a10 60%); }
[data-theme="ember"] html { background: radial-gradient(120% 80% at 50% 115%, #2e1206 0%, #100804 55%); }
[data-theme="winter"] html { background: radial-gradient(120% 95% at 50% -15%, #122236 0%, #070b12 58%); }

/* Theme FX particle layer — fixed, BEHIND the (transparent) content so it reads as background. */
.theme-fx { position: fixed; inset: 0; pointer-events: none; z-index: -1; overflow: hidden; }
.theme-fx span { position: absolute; top: -8%; will-change: transform, opacity; }

/* ── SYNTHWAVE scene — the /hub sunset (sky + stars + slitted sun + mountains +
   perspective grid + horizon glow). Injected into #themeFx (home only) and into the
   Now-Playing view by buildThemeFx/the NPV builder. Hidden everywhere else. ── */
.sw-scene { position: absolute; inset: 0; overflow: hidden; display: none; }
html[data-theme="synthwave"] .npv .sw-scene { display: block; z-index: -1; filter: blur(3px); transform: scale(1.03); } /* full sunset = Now-Playing backdrop (lightly softened; scale hides blurred edges) */
html[data-theme="synthwave"] .npv { background: transparent; }            /* let the scene show through */
/* NPV particle layer (gold/cosmic/winter/sakura) — absolute within the NPV, above its
   background but behind its content; inherits inset/overflow/z-index from .theme-fx. */
.npv .npv-fx { position: absolute; }
/* HOME gets a lighter "spicy" synthwave ambience (no 3D grid / no big sun) so the normal
   home layout still reads — neon wash + faint stars + a flat glowing horizon + scanlines. */
.sw-home { position: absolute; inset: 0; overflow: hidden; display: none; background:
  radial-gradient(82% 52% at 50% -12%, rgba(255,44,182,.20), transparent 70%),
  radial-gradient(60% 45% at 86% 6%, rgba(0,240,255,.12), transparent 70%),
  radial-gradient(95% 60% at 50% 118%, rgba(123,0,160,.26), transparent 72%); }
body[data-view="home"] #themeFx .sw-home { display: block; }
.sw-home-stars { position: absolute; left: 0; right: 0; top: 0; height: 52%; opacity: .55; background-repeat: no-repeat; animation: sw-twinkle 4s ease-in-out infinite;
  background-image:
    radial-gradient(1px 1px at 14% 16%, #fff, transparent), radial-gradient(1px 1px at 31% 8%, #fff, transparent),
    radial-gradient(1px 1px at 48% 20%, #ffe9ff, transparent), radial-gradient(1px 1px at 66% 12%, #fff, transparent),
    radial-gradient(2px 2px at 80% 24%, #fff, transparent), radial-gradient(1px 1px at 90% 14%, #fff, transparent),
    radial-gradient(1px 1px at 22% 34%, #fff, transparent), radial-gradient(1px 1px at 58% 36%, #fff, transparent); }
.sw-home-scan { position: absolute; inset: 0; background: repeating-linear-gradient(0deg, transparent 0 2px, rgba(120,180,255,.03) 2px 3px); }
.sw-home-horizon { position: absolute; left: 0; right: 0; bottom: 9vh; height: 2px;
  background: linear-gradient(90deg, transparent, #ff2cb6 28%, #00f0ff 72%, transparent);
  box-shadow: 0 0 18px #ff2cb6, 0 0 38px rgba(0,240,255,.5); opacity: .8; }
/* Neon glow on the home greeting for that synthwave pop. */
html[data-theme="synthwave"] .home h2.home-greet { text-shadow: 0 0 8px rgba(255,44,182,.7), 0 0 20px rgba(255,44,182,.35); }
html[data-theme="synthwave"] .home-sec { color: var(--accent2); text-shadow: 0 0 10px rgba(0,240,255,.4); }
.sw-sky { position: absolute; inset: 0; background:
  radial-gradient(ellipse at 50% 80%, #ff2cb6 0%, transparent 38%),
  linear-gradient(180deg, #02000a 0%, #0a0030 32%, #2a0044 56%, #6b0073 76%, #c20a7e 90%, #ff2cb6 100%); }
.sw-stars { position: absolute; left: 0; right: 0; top: 0; height: 62%; background-repeat: no-repeat; animation: sw-twinkle 4s ease-in-out infinite;
  background-image:
    radial-gradient(1px 1px at 12% 18%, #fff, transparent), radial-gradient(1px 1px at 27% 9%, #fff, transparent),
    radial-gradient(2px 2px at 45% 22%, #fff, transparent), radial-gradient(1px 1px at 63% 14%, #fff, transparent),
    radial-gradient(1px 1px at 78% 28%, #fff, transparent), radial-gradient(2px 2px at 88% 12%, #fff, transparent),
    radial-gradient(1px 1px at 8% 35%, #fff, transparent), radial-gradient(1px 1px at 55% 30%, #ffe9ff, transparent),
    radial-gradient(1px 1px at 92% 38%, #fff, transparent), radial-gradient(2px 2px at 18% 45%, #fff, transparent); }
.sw-sun { position: absolute; left: 50%; bottom: 20vh; transform: translateX(-50%); width: 54vh; height: 54vh; display: grid; place-items: center; filter: drop-shadow(0 0 60px rgba(255,44,182,.6)); }
.sw-sun-disc { width: 100%; height: 100%; border-radius: 50%;
  background:
    repeating-linear-gradient(0deg, transparent 0, transparent 14px, rgba(6,0,20,.92) 14px, rgba(6,0,20,.92) 18px),
    linear-gradient(180deg, #ffe629 0%, #ffae00 25%, #ff4dd9 55%, #d600ff 80%, #6b00aa 100%);
  -webkit-mask: radial-gradient(circle, #000 60%, transparent 60%); mask: radial-gradient(circle, #000 60%, transparent 60%);
  animation: sw-sun-pulse 6s ease-in-out infinite; }
.sw-mountains { position: absolute; left: 0; right: 0; bottom: 20vh; height: 15vh; }
.sw-mountains svg { width: 100%; height: 100%; display: block; }
.sw-grid { position: absolute; left: -10%; right: -10%; bottom: -28vh; height: 48vh; /* top edge meets the 20vh horizon */
  background-image: linear-gradient(rgba(0,240,255,.6) 1px, transparent 1px), linear-gradient(90deg, rgba(0,240,255,.6) 1px, transparent 1px);
  background-size: 60px 60px, 60px 60px; transform: perspective(450px) rotateX(62deg); transform-origin: center top;
  animation: sw-grid-scroll 1.6s linear infinite; filter: drop-shadow(0 0 4px rgba(0,240,255,.7)) drop-shadow(0 0 10px rgba(0,240,255,.35)); }
.sw-glow { position: absolute; left: 0; right: 0; bottom: calc(20vh - 2px); height: 4px;
  background: linear-gradient(90deg, transparent, #00f0ff 20%, #ff2cb6 50%, #00f0ff 80%, transparent);
  box-shadow: 0 0 30px #ff2cb6, 0 0 60px #00f0ff, 0 0 12px #fff; }
/* Darken the centre a touch so list text stays readable over the bright sun. */
.sw-vignette { position: absolute; inset: 0; background: radial-gradient(ellipse at 50% 42%, transparent 40%, rgba(2,0,12,.62) 100%); }
@keyframes sw-twinkle { 0%, 100% { opacity: .85; } 50% { opacity: .4; } }
@keyframes sw-sun-pulse { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.15); } }
@keyframes sw-grid-scroll { 0% { background-position: 0 0, 0 0; } 100% { background-position: 0 60px, 0 0; } }
/* GOLD — slow-rising shimmering dust. */
.theme-fx .fx-gold { width: 4px; height: 4px; border-radius: 50%; top: auto; bottom: -8%; background: radial-gradient(circle, #ffe79a, #f5c542 60%, transparent 72%);
  box-shadow: 0 0 6px 1px rgba(245,197,66,.7); animation: fx-rise linear infinite, fx-twinkle ease-in-out infinite; }
/* COSMIC — tiny twinkling stars (small + dim so they sit in the distance). */
.fx-star { width: 2px; height: 2px; border-radius: 50%; background: #eaf0ff; box-shadow: 0 0 3px 0.5px rgba(150,170,255,.6);
  top: auto; animation: fx-twinkle ease-in-out infinite, fx-float-slow ease-in-out infinite; }
/* WINTER — snowflakes drifting down + swaying. */
.fx-snow { width: 6px; height: 6px; border-radius: 50%; background: radial-gradient(circle, #fff, rgba(220,238,255,.6) 70%, transparent);
  opacity: .85; animation: fx-fall-soft linear infinite, fx-sway ease-in-out infinite; }
/* SAKURA — petals falling + swaying. */
.fx-petal { width: 11px; height: 11px; background: linear-gradient(135deg, #ffd1e2, #ff8fb8);
  border-radius: 100% 0 100% 0; opacity: .85; animation: fx-fall linear infinite, fx-sway ease-in-out infinite; }
/* EMBER — live sparks: rise on a wavering heat-current + cool/shrink, while flickering.
   Structured like the working gold/winter FX: anim 1 = motion (transform + curl), anim 2
   = opacity flicker (kept above 0 so they stay visible). */
.theme-fx .fx-ember { width: 5px; height: 5px; border-radius: 50%; top: auto; bottom: -6%; will-change: transform, margin-left, opacity;
  background: radial-gradient(circle, #fff3c4 8%, #ffb14d 42%, #ff5a1f 70%, transparent 80%);
  box-shadow: 0 0 8px 2px rgba(255,90,31,.8), 0 0 16px 5px rgba(255,140,45,.3);
  animation: fx-ember-rise linear infinite, fx-ember-flicker ease-in-out infinite; }
.fx-ember:nth-child(3n) { width: 3px; height: 3px; background: radial-gradient(circle, #fff7d8 8%, #ffc857 48%, #ff8a22 74%, transparent 82%); } /* small yellow-hot */
.fx-ember:nth-child(4n) { background: radial-gradient(circle, #ffd08a 10%, #ff6a26 52%, #d62b16 76%, transparent 84%); box-shadow: 0 0 8px 2px rgba(214,43,22,.75); } /* deep red */
@keyframes fx-ember-rise {
  0%   { transform: translateY(0) scale(1);       margin-left: 0; }
  28%  { margin-left: 15px; }
  52%  { margin-left: -11px; transform: translateY(-56vh) scale(.75); }
  76%  { margin-left: 13px; }
  100% { transform: translateY(-116vh) scale(.3); margin-left: -6px; }
}
@keyframes fx-ember-flicker { 0%, 100% { opacity: .35; } 20% { opacity: 1; } 45% { opacity: .5; } 70% { opacity: .95; } 88% { opacity: .6; } }
@keyframes fx-rise { from { transform: translateY(0); } to { transform: translateY(-118vh); } }
@keyframes fx-rise-fade { 0% { transform: translateY(0) translateX(0); opacity: 0; } 12% { opacity: .9; } 85% { opacity: .6; } 100% { transform: translateY(-115vh) translateX(20px); opacity: 0; } }
@keyframes fx-fall { from { transform: translateY(0) rotate(0deg); } to { transform: translateY(116vh) rotate(360deg); } }
@keyframes fx-fall-soft { from { transform: translateY(0); } to { transform: translateY(116vh); } }
@keyframes fx-sway { 0%, 100% { margin-left: 0; } 50% { margin-left: 42px; } }
@keyframes fx-twinkle { 0%, 100% { opacity: .2; } 50% { opacity: .9; } }
@keyframes fx-float-slow { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-7px); } }

/* Track-start effect (special themes) — a themed sheen sweeps across the bottom
   player bar + a brief glow on its top edge. Lives inside .player, clipped to it. */
.player-fx { position: absolute; inset: 0; pointer-events: none; overflow: hidden; z-index: 4;
  box-shadow: inset 0 2px 0 0 var(--accent); animation: player-glow 1.05s ease-out forwards; }
.player-fx::before { content: ''; position: absolute; top: 0; bottom: 0; left: -45%; width: 45%;
  background: linear-gradient(90deg, transparent, color-mix(in srgb, var(--accent) 38%, transparent) 50%, transparent);
  animation: player-sweep 0.95s cubic-bezier(.4,0,.2,1) forwards; }
@keyframes player-sweep { from { left: -45%; } to { left: 100%; } }
.player-fx.rev::before { animation-name: player-sweep-rev; } /* going backwards → sweep right→left */
@keyframes player-sweep-rev { from { left: 100%; } to { left: -45%; } }
@keyframes player-glow { 0% { box-shadow: inset 0 2px 0 0 var(--accent); opacity: 0; } 18% { opacity: 1; } 100% { box-shadow: inset 0 0 0 0 transparent; opacity: 0; } }

/* GOLD shine extras — a sweeping sheen on the play button + brighter accent glow. */
/* ── GOLD luxury treatment ─────────────────────────────────────────────────────
   A domed metallic "coin" play button with a light streak sweeping across, metallic
   sheen on every accent block, gilt-edged surfaces and gold-clipped headings. */
/* The play button is a domed metallic coin: layer 1 is a white light-streak that sweeps
   across (the glint), layer 2 the metallic gold that gently shifts — both animated via
   background-position so no pseudo-element is needed (::before/::after are already used). */
[data-theme="gold"] .btns .play {
  color: #3a2a08; border: 1px solid var(--gold-edge);
  background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,.85) 50%, transparent 58%), var(--gold-metal);
  background-size: 250% 250%, 200% 200%; background-position: 160% 0, 0% 50%;
  box-shadow: 0 6px 22px rgba(236,201,79,.5), inset 0 2px 2px rgba(255,255,255,.75), inset 0 -3px 7px rgba(120,80,10,.55);
  animation: gold-coin 5s ease-in-out infinite;
}
[data-theme="gold"] .btns .play svg { filter: drop-shadow(0 1px 0 rgba(255,255,255,.45)); }
[data-theme="gold"] .btns .play:hover { filter: brightness(1.07); transform: scale(1.06); }
/* Every prominent accent block becomes brushed gold with a slow living sheen. */
[data-theme="gold"] .pheader .play-all,
[data-theme="gold"] .play-all,
[data-theme="gold"] .dl-app-btn,
[data-theme="gold"] .sync-queue-btn.primary,
[data-theme="gold"] .dc-btn.dc-primary,
[data-theme="gold"] .dialog-actions .dlg-ok,
[data-theme="gold"] .chat-input button,
[data-theme="gold"] .gc-tab.active,
[data-theme="gold"] .gtab.active,
[data-theme="gold"] .src-pill.active {
  background-image: var(--gold-metal); background-size: 220% 220%; color: #3a2a08;
  border: 1px solid color-mix(in srgb, var(--gold-edge) 55%, transparent);
  box-shadow: 0 2px 12px rgba(236,201,79,.32), inset 0 1px 0 rgba(255,255,255,.5);
  animation: gold-sheen 7s ease-in-out infinite;
}
/* Gilt edges + warm glow on the main surfaces for a jewellery-box feel. */
[data-theme="gold"] .pheader, [data-theme="gold"] .home-card, [data-theme="gold"] .modal {
  border-color: color-mix(in srgb, var(--accent) 26%, var(--border));
}
[data-theme="gold"] .home-card:hover { box-shadow: 0 8px 26px rgba(236,201,79,.18); }
[data-theme="gold"] .sidebar { box-shadow: inset -1px 0 0 color-mix(in srgb, var(--accent) 22%, transparent); }
/* Metallic gold-leaf text on titles (NOT .brand — it holds the logo, which currentColor
   would turn transparent). */
[data-theme="gold"] .pheader h2, [data-theme="gold"] .np-title {
  background: linear-gradient(180deg, #fff6d5 6%, #f2cd5a 42%, #b9851a 76%, #ffe9a8 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent;
}
@keyframes gold-sheen { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
/* Streak sweeps right→left once (layer 1) while the metal shifts (layer 2), then rests. */
@keyframes gold-coin {
  0%   { background-position: 160% 0, 0% 50%; }
  28%  { background-position: -160% 0, 100% 50%; }
  100% { background-position: -160% 0, 0% 50%; }
}
html, body { height: 100%; overscroll-behavior-x: none; } /* no horizontal pull = no browser back-swipe stealing the sidebar gesture */
/* The embedded ArskaSoft chat widget shows on the landing + marketing pages, but
   NOT over the actual app UI. music.html has #landing (hidden unless shown); when
   it's hidden we're in the app → hide the widget. Standalone pages have no #landing
   so this never matches there → widget stays visible. */
body:has(#landing[hidden]):not(.aw-show) #aw-widget { display: none !important; }
/* Base surface lives on <html> so the #themeFx particle layer (z-index:-1) can sit
   BETWEEN it and the (transparent) content — particles read as background, not overlay. */
html { background: var(--bg); }
body { background: transparent; color: var(--text); font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif; overflow: hidden; }
button { font-family: inherit; cursor: pointer; }
img { display: block; }

#app { display: grid; grid-template-columns: var(--sb-w, 250px) 1fr; grid-template-rows: 1fr 92px; height: 100vh; height: 100dvh; position: relative; }

/* Sidebar */
.sidebar { grid-row: 1; grid-column: 1; background: var(--sidebar-bg); border-right: 1px solid var(--border); padding: 16px 12px; overflow-y: auto; overflow-x: hidden; }

/* Desktop sidebar resize handle — sits on the sidebar/main boundary */
.sb-resizer { position: absolute; top: 0; bottom: 92px; left: var(--sb-w, 250px); width: 9px; transform: translateX(-5px); z-index: 60; cursor: col-resize; touch-action: none; }
.sb-resizer::after { content: ""; position: absolute; top: 0; bottom: 0; left: 4px; width: 2px; background: transparent; transition: background .15s ease; }
.sb-resizer:hover::after, .sb-resizer.dragging::after { background: var(--accent); }
body.sb-resizing { cursor: col-resize; user-select: none; }
.how-btn { display: inline-flex; align-items: center; gap: 4px; padding: 5px 11px; font-size: 12px; color: var(--dim); background: var(--bg3); border: 1px solid var(--border); border-radius: 999px; cursor: pointer; flex-shrink: 0; transition: color .15s ease, border-color .15s ease; }
.how-btn:hover { color: var(--text); border-color: var(--accent); }
/* The topbar reacts to ITS OWN width (which shrinks with the window AND a wider sidebar),
   not the viewport — so the right-side cluster can never be pushed off-screen. */
.topbar-c { container-type: inline-size; }
@container (max-width: 1100px) { .how-btn .how-label { display: none; } } /* icon-only when it tightens */
@container (max-width: 1100px) {
  /* The fixed 520px search column is too greedy here → let the search flex and the side
     clusters take their content width, so the buttons always stay in view. */
  .topbar { grid-template-columns: auto minmax(0, 1fr) auto; }
  .search-wrap { max-width: none; }
}
@container (max-width: 940px) { .online-badge, #howBtn { display: none; } } /* drop the extras before they crowd */
.how-modal { width: 580px; }
.how-diagram { margin: 2px auto 18px; max-width: 100%; }
.how-diagram svg { max-height: 240px; }
/* AI overview modal */
.ai-overview { font-size: 14px; line-height: 1.65; color: var(--text); white-space: pre-wrap; min-height: 48px;
  background: color-mix(in srgb, var(--accent) 7%, var(--bg3)); border: 1px solid var(--border); border-left: 3px solid var(--accent);
  border-radius: 10px; padding: 13px 15px; }
.ai-overview .ai-err { color: var(--danger); }
.ai-spin { display: inline-block; width: 13px; height: 13px; vertical-align: -2px; margin-right: 4px; border: 2px solid color-mix(in srgb, var(--accent) 35%, transparent); border-top-color: var(--accent); border-radius: 50%; animation: spin .8s linear infinite; }
/* "Update available" modal (shown on app open when a newer version is published) */
.upd-modal { width: 380px; max-width: 100%; text-align: center; }
.upd-badge { font-size: 40px; line-height: 1; margin-bottom: 4px; }
.upd-modal h3 { font-size: 20px; font-weight: 700; margin: 2px 0 6px; }
.upd-sub { font-size: 14px; color: var(--text); margin-bottom: 8px; }
.upd-sub b { color: var(--accent); }
.upd-notes { font-size: 13px; color: var(--dim); background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px; margin: 0 0 10px; white-space: pre-wrap; text-align: left; }
.upd-url { color: var(--accent); font-weight: 700; user-select: all; -webkit-user-select: all; word-break: break-all; }
.upd-copy { flex: 1; padding: 11px 14px; border-radius: 9px; font-size: 14px; font-weight: 700; cursor: pointer; background: var(--bg3); border: 1px solid var(--accent); color: var(--accent); transition: background .15s ease; }
.upd-copy:hover { background: color-mix(in srgb, var(--accent) 12%, var(--bg3)); }
.upd-actions { display: flex; gap: 10px; margin-top: 16px; }
.upd-later, .upd-go { flex: 1; padding: 11px 14px; border-radius: 9px; font-size: 14px; font-weight: 700; cursor: pointer; text-align: center; text-decoration: none; box-sizing: border-box; }
.upd-later { background: var(--bg3); border: 1px solid var(--border); color: var(--text); transition: border-color .15s ease; }
.upd-later:hover { border-color: var(--accent); }
.upd-go { background: var(--accent); border: 1px solid var(--accent); color: #06120a; display: inline-flex; align-items: center; justify-content: center; gap: 6px; transition: filter .15s ease; }
.upd-go:hover { filter: brightness(1.06); }
.how-body { font-size: 14px; line-height: 1.6; color: var(--text); }
.how-live { display: flex; justify-content: center; align-items: center; gap: 8px; width: fit-content; margin: 20px auto 0; padding: 7px 15px; border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 12%, var(--bg3)); border: 1px solid var(--border); font-size: 13px; }
.how-live b { color: var(--text); font-weight: 700; }
.how-live .ob-dot { width: 8px; height: 8px; border-radius: 50%; background: #2ecc71; box-shadow: 0 0 9px #2ecc71; animation: hcPulse 2.2s ease-in-out infinite; flex-shrink: 0; }
.how-live .how-live-sub { color: var(--dim); }
.how-body p { margin-bottom: 12px; }
.how-body p:last-child { margin-bottom: 0; }
.how-body strong { color: var(--accent2, var(--accent)); }
/* Brand lockup: big logo + stacked wordmark/tagline, filling the sidebar width. */
.brand { color: var(--accent); margin: 8px 4px 16px; padding: 6px 4px; display: flex; align-items: center; gap: 13px; cursor: pointer; width: 100%; }
.brand-text { display: flex; flex-direction: column; justify-content: center; min-width: 0; flex: 1; gap: 3px; }
.brand-name {
  font-weight: 900; font-size: 32px; line-height: 1; letter-spacing: -1px;
  color: var(--text); /* fallback */
  background: linear-gradient(90deg, var(--text) 0%, var(--text) 42%, var(--accent) 50%, var(--text) 58%, var(--text) 100%);
  background-size: 200% auto;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: sw-shimmer 6s linear infinite; /* soft accent sweep */
}
.brand-tag { font-size: 11.5px; font-weight: 600; letter-spacing: .2px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Scroll by exactly one tile (= the 200% size) so the loop is seamless (both
   gradient ends are var(--text), so text meets text with no visible jump). */
@keyframes sw-shimmer { from { background-position: 200% 0; } to { background-position: 0 0; } }

/* "Download the Android app" button in Settings */
.dl-app-btn { display: inline-flex; align-items: center; gap: 8px; margin-top: 6px; padding: 10px 16px; font-size: 14px; font-weight: 700; color: #fff; background: var(--accent); border: 0; border-radius: 10px; text-decoration: none; transition: filter .15s ease, transform .08s ease; }
.dl-app-btn:hover { filter: brightness(1.08); }
.dl-app-btn:active { transform: translateY(1px); }
.dl-app-btn[hidden] { display: none; } /* explicit display:inline-flex above would otherwise beat [hidden] */
/* Settings → Get the apps: visual download cards (web). */
.set-dl { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.set-dl-card { display: flex; align-items: center; gap: 12px; padding: 11px 13px; border-radius: 11px; text-decoration: none;
  color: var(--text); background: var(--bg3); border: 1px solid var(--border); transition: border-color .15s ease, background .15s ease, transform .08s ease; }
.set-dl-card:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--bg3)); }
.set-dl-card:active { transform: translateY(1px); }
.set-dl-ico { flex-shrink: 0; width: 38px; height: 38px; border-radius: 9px; display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent); }
.set-dl-ico svg { width: 21px; height: 21px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.set-dl-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.set-dl-tx b { font-size: 13.5px; font-weight: 700; }
.set-dl-tx small { font-size: 11.5px; color: var(--dim); line-height: 1.35; }
.set-dl-ver { font-size: 11px; font-weight: 600; color: var(--accent); }
.set-dl-go { flex-shrink: 0; font-size: 16px; color: var(--accent); }
/* Settings action buttons (Ask AudaBot, Welcome page) — icon card style. */
.set-action { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; margin-top: 6px; padding: 11px 13px;
  border-radius: 11px; background: var(--bg3); border: 1px solid var(--border); color: var(--text); cursor: pointer;
  transition: border-color .15s ease, background .15s ease, transform .08s ease; }
.set-action:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--bg3)); }
.set-action:active { transform: translateY(1px); }
.set-action .sa-ico { flex-shrink: 0; width: 36px; height: 36px; border-radius: 9px; display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent); }
.set-action .sa-ico svg { width: 20px; height: 20px; fill: none; stroke: var(--accent); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.set-action .sa-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.set-action .sa-tx b { font-size: 13.5px; font-weight: 700; color: var(--text); }
.set-action .sa-tx small { font-size: 11.5px; color: var(--dim); line-height: 1.35; }
.set-action .sa-go { flex-shrink: 0; font-size: 20px; color: var(--mute); }
.brand-logo { flex-shrink: 0; display: block; width: 48px; height: 48px; filter: drop-shadow(0 2px 10px rgba(29, 185, 84, .25)); }
.brand-logo line { stroke: currentColor; stroke-width: 7; stroke-linecap: round; fill: none; transform-box: fill-box; transform-origin: center; transition: transform .22s ease; }
/* Hover (desktop): the bars ripple like an equalizer, staggered into a wave. */
.brand:hover .brand-logo line { animation: sw-eq .9s ease-in-out infinite; }
.brand:hover .brand-logo line:nth-child(1) { animation-delay: 0s; }
.brand:hover .brand-logo line:nth-child(2) { animation-delay: .07s; }
.brand:hover .brand-logo line:nth-child(3) { animation-delay: .14s; }
.brand:hover .brand-logo line:nth-child(4) { animation-delay: .21s; }
.brand:hover .brand-logo line:nth-child(5) { animation-delay: .28s; }
.brand:hover .brand-logo line:nth-child(6) { animation-delay: .35s; }
.brand:hover .brand-logo line:nth-child(7) { animation-delay: .42s; }
@keyframes sw-eq { 0%, 100% { transform: scaleY(.55); } 50% { transform: scaleY(1.15); } }
.tagline { color: var(--dim); font-size: 11px; line-height: 1.5; margin: 0 6px 20px; }
.nav-item { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--dim); font-size: 14px; font-weight: 600; padding: 8px 8px; border-radius: 6px; }
.nav-item:hover, .nav-item.active { color: var(--text); background: var(--bg3); }
.section { margin-top: 22px; }
.section-head { display: flex; justify-content: space-between; align-items: center; color: var(--mute); font-size: 11px; text-transform: uppercase; letter-spacing: 1px; font-weight: 700; padding: 0 8px 6px; }
.section-head button { background: none; border: 1px solid var(--border); color: var(--dim); width: 22px; height: 22px; border-radius: 5px; line-height: 1; }
.section-head button:hover { color: var(--text); border-color: var(--accent); }
.list { list-style: none; }
.list li { display: flex; align-items: center; gap: 10px; padding: 5px 8px; border-radius: 6px; color: var(--dim); font-size: 13px; cursor: pointer; }
.list li:hover, .list li.active { background: var(--bg3); color: var(--text); }
.list li .li-text { min-width: 0; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Currently-playing list highlight: accent text + an animated equalizer glyph. */
.list li.np-list { color: var(--text); }
.list li.np-list .li-text { color: var(--accent); font-weight: 600; }
.list li.np-list .cover { box-shadow: 0 0 0 1.5px var(--accent); }
.li-eq { display: none; }
.list li.np-list .li-eq { display: inline-flex; align-items: flex-end; gap: 1.5px; height: 11px; margin-right: 5px; flex-shrink: 0; vertical-align: middle; }
.list li.np-list .li-eq i { width: 2.5px; background: var(--accent); border-radius: 1px; transform-origin: bottom; animation: liEq .9s ease-in-out infinite; }
.list li.np-list .li-eq i:nth-child(1) { height: 40%; animation-delay: -.2s; }
.list li.np-list .li-eq i:nth-child(2) { height: 100%; animation-delay: -.5s; }
.list li.np-list .li-eq i:nth-child(3) { height: 65%; animation-delay: 0s; }
.list li.np-list.np-paused .li-eq i { animation-play-state: paused; }
@keyframes liEq { 0%, 100% { transform: scaleY(.35); } 50% { transform: scaleY(1); } }
.list li .badge { font-size: 10px; color: var(--mute); margin-left: 6px; }

/* square cover (playlist song collage / group member images) */
.cover { width: 38px; height: 38px; border-radius: 5px; overflow: hidden; flex-shrink: 0; background: var(--bg2); display: block; }
.cover > img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cover-grid { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.cover-2 { display: grid; grid-template-columns: 1fr 1fr; }
.cover-3 { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.cover-3 > :first-child { grid-row: 1 / 3; } /* one tall on the left, two stacked on the right */
.cover-grid img, .cover-2 img, .cover-3 img, .cover-grid .ph { width: 100%; height: 100%; object-fit: cover; display: block; }
.cover-grid .ph { background: var(--bg3); }
.cover-2 img, .cover-3 img { border: 0.5px solid var(--bg); }
.cover-empty { display: flex; align-items: center; justify-content: center; font-size: 16px; color: var(--mute); }

/* App-wide avatar with coloured-initials fallback (real photo overlays only if set) */
.avatar-fb { position: relative; display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; color: #fff; font-size: 10px; font-weight: 700; text-shadow: 0 1px 1px rgba(0,0,0,.4); overflow: hidden; flex-shrink: 0; }
.avatar-fb .avatar-init { position: relative; z-index: 0; line-height: 1; }
.avatar-fb .avatar-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1; }
.stack-av.avatar-fb, .chat-av.avatar-fb { font-size: 11px; }
.member-av.avatar-fb { font-size: 9px; }
/* As group-cover collage cells: square tiles that fill the grid cell */
.cover .avatar-fb { width: 100%; height: 100%; border-radius: 0; font-size: 9px; }
.cover-2 .avatar-fb, .cover-3 .avatar-fb, .cover-grid .avatar-fb { border: 0.5px solid var(--bg); }
.linkbtn { background: none; border: none; color: var(--dim); font-size: 12px; padding: 6px 8px; text-decoration: underline; }
.linkbtn:hover { color: var(--accent2); }
/* Sidebar nav link (e.g. Recently played) — looks like a row, not a link */
.nav-link { display: block; width: calc(100% - 16px); margin: 2px 8px 8px; text-align: left; text-decoration: none;
  font-size: 13px; color: var(--text); border-radius: 8px; padding: 8px 10px; cursor: pointer; }
.nav-link:hover { background: rgba(255,255,255,.06); color: var(--text); }
.nav-link.active { background: rgba(255,255,255,.09); color: var(--accent2); }

/* ── Sync QR panel (sidebar, below Groups) ── */
.qr-panel { margin: 6px 8px 2px; }
.qr-box {
  display: flex; align-items: center; justify-content: center;
  background: #fff; border-radius: 8px; padding: 10px;   /* white quiet zone — keeps the code scannable on any theme */
  width: fit-content;
}
.qr-box svg, .qr-box img { display: block; width: 148px; height: 148px; }
.qr-hint { font-size: 11px; color: var(--mute); margin-top: 7px; line-height: 1.45; }

/* Main */
.main { grid-row: 1; grid-column: 2; display: flex; flex-direction: column; overflow: hidden; position: relative; }
/* Scroll-track marker for the currently-playing song in the open list. */
.play-blip { position: absolute; right: 3px; width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 5px 0 color-mix(in srgb, var(--accent) 70%, transparent); pointer-events: none; z-index: 6;
  transform: translateY(-50%); transition: top .35s ease, opacity .25s ease; opacity: 0; display: none; }
.play-blip.show { display: block; opacity: 1; }
.play-blip.paused { background: var(--dim); box-shadow: none; }
/* Classic theme: keep the marker its signature green even if the accent is customised. */
[data-theme="classic"] .play-blip:not(.paused) { background: #1db954; box-shadow: 0 0 5px 0 color-mix(in srgb, #1db954 70%, transparent); }
/* 3-column grid keeps the search box centered (aligned over the centered results
   card) regardless of how wide the account/menu items on either side are. */
.topbar { display: grid; grid-template-columns: 1fr minmax(0, 520px) 1fr; align-items: center; gap: 16px; padding: 14px 22px; border-bottom: 1px solid var(--border); }
.search-wrap { grid-column: 2; width: 100%; max-width: 520px; }
#searchInput { width: 100%; background: var(--bg2); border: 1px solid var(--border); color: var(--text); border-radius: 999px; padding: 10px 16px; font-size: 14px; outline: none; }
#searchInput:focus { border-color: var(--accent); }
.account { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.account button { background: var(--bg3); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 12px; font-size: 13px; }
.account button:hover { border-color: var(--accent); }
.account .uname { color: var(--accent); font-weight: 600; }
/* Combined account + settings control: [avatar · name · gear] opens Settings */
.account .user-chip { display: inline-flex; align-items: center; gap: 8px; padding: 4px 10px 4px 5px; background: var(--bg3); border: 1px solid var(--border); border-radius: 999px; max-width: 230px; cursor: pointer; color: var(--text); font-size: 13px; transition: border-color .15s ease; }
.account .user-chip:hover { border-color: var(--accent); }
.user-chip:hover .chip-gear { color: var(--text); transform: rotate(40deg); }
.user-chip .uname { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chip-av.avatar-fb { width: 24px; height: 24px; font-size: 10px; }
.chip-gear { width: 16px; height: 16px; color: var(--dim); flex-shrink: 0; transition: color .15s ease, transform .25s ease; }
/* Settings modal: profile block at the top — [avatar · name/sub] … [manage ↗] */
.settings-user { display: flex; align-items: center; gap: 10px; padding: 12px 2px 14px; }
.settings-user[hidden] { display: none; }
.su-av.avatar-fb { width: 38px; height: 38px; font-size: 13px; flex-shrink: 0; }
.su-text { min-width: 0; flex: 1; }
.su-name { font-weight: 700; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.su-sub { font-size: 11px; color: var(--dim); margin-top: 2px; }
.su-manage { flex-shrink: 0; font-size: 12px; padding: 6px 10px; }
/* Log out at the bottom of the settings modal */
.logout-btn { display: block; width: 100%; margin-top: 12px; padding: 9px 12px; border-radius: 8px; background: var(--bg3); border: 1px solid var(--border); color: var(--dim); font-size: 13px; cursor: pointer; transition: color .15s ease, border-color .15s ease; }
.logout-btn:hover { color: var(--danger); border-color: var(--danger); }
.logout-btn[hidden] { display: none; }
@media (max-width: 760px) { .account .user-chip { padding: 3px 8px 3px 3px; } .user-chip .uname { display: none; } } /* avatar+gear chip on phones */
.content { flex: 1; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; padding: 20px 22px 28px; }
/* Condensed sticky title: slides in once the big hero title scrolls out of view. */
.pl-stickybar { position: sticky; top: 0; height: 0; z-index: 30; }
.plsb-inner { position: absolute; top: -20px; left: -22px; right: -22px; display: flex; align-items: center; gap: 10px;
  padding: 12px 22px; background: color-mix(in srgb, var(--bg) 84%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border); box-shadow: 0 6px 18px rgba(0,0,0,.28);
  transform: translateY(-100%); opacity: 0; pointer-events: none; transition: transform .22s ease, opacity .22s ease; }
.pl-stickybar.show .plsb-inner { transform: translateY(0); opacity: 1; pointer-events: auto; }
.plsb-name { font-size: 15px; font-weight: 700; display: inline-flex; align-items: center; gap: 8px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.plsb-top { margin-left: auto; flex-shrink: 0; background: var(--bg3); color: var(--text); border: 1px solid var(--border); border-radius: 8px; padding: 6px 9px; display: inline-flex; align-items: center; cursor: pointer; transition: border-color .15s ease, color .15s ease, background .15s ease; }
.plsb-top:hover { border-color: var(--accent); color: var(--accent); }
.plsb-top svg { width: 17px; height: 17px; }
.content h2 { font-size: 20px; margin-bottom: 14px; }
.muted { color: var(--dim); }

/* Search overlay — a dimmed backdrop over the open list with a floating result
   card (not full-width). Sits below the search bar so you can keep typing. */
.search-overlay { position: absolute; left: 0; right: 0; top: var(--topbar-h, 56px); bottom: 0; z-index: 60; display: flex; flex-direction: column; padding: 16px; background: rgba(0,0,0,.5); backdrop-filter: blur(2px); animation: overlayIn .15s ease; }
.search-overlay[hidden] { display: none; }
.search-panel { width: 100%; max-width: 720px; margin: 0 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; background: var(--bg2); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 24px 70px rgba(0,0,0,.55); padding: 18px 20px; animation: dialogPop .18s ease; }
.search-panel h2 { font-size: 20px; margin-bottom: 14px; }
@media (max-width: 700px) { .search-overlay { padding: 10px; } .search-panel { padding: 14px 14px 18px; border-radius: 12px; } }

/* Track rows */
.rows { display: flex; flex-direction: column; gap: 2px; }
.row { display: grid; grid-template-columns: 44px 1fr auto auto; align-items: center; gap: 12px; padding: 8px 10px; border-radius: 8px; cursor: pointer;
  touch-action: pan-y; /* horizontal swipes are ours (swipe-right = queue) */
  content-visibility: auto; contain-intrinsic-size: auto 60px; /* big lists: browser skips layout/paint of off-screen rows */ }
/* Swipe-right-to-queue: the ⏭ hint rides in from the left with the row */
.row.swiping { position: relative; background: var(--bg2); z-index: 2; }
.row.swiping::after { content: '⏭'; position: absolute; left: -70px; top: 50%; transform: translateY(-50%);
  width: 56px; text-align: center; font-size: 22px; color: var(--dim); transition: color .12s ease; }
.row.swipe-ready { background: color-mix(in srgb, var(--accent) 14%, var(--bg2)); }
.row.swipe-ready::after { content: '⏭'; color: var(--accent); text-shadow: 0 0 12px var(--accent); }
.row:hover { background: var(--bg2); }
.thumb { position: relative; width: 44px; height: 44px; flex-shrink: 0; }
.row img { width: 44px; height: 44px; border-radius: 5px; object-fit: cover; background: var(--bg3); }
.play-ov { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(0,0,0,.5); color: #fff; border-radius: 5px; font-size: 15px; opacity: 0; transition: opacity .15s ease; pointer-events: none; }
/* Search result already saved in one of the user's lists → corner check badge + tooltip. */
.thumb .lib-check { position: absolute; top: -4px; right: -4px; z-index: 3; width: 16px; height: 16px; border-radius: 50%; background: var(--accent); color: var(--bg); font-size: 10px; font-weight: 800; line-height: 1; display: flex; align-items: center; justify-content: center; box-shadow: 0 1px 4px rgba(0,0,0,.5); cursor: default; }
/* Fuzzy match (different upload of a song you have) → faded "?" badge. */
.thumb .lib-check.lib-maybe { background: color-mix(in srgb, var(--accent) 52%, transparent); font-size: 11px; }
.thumb .lib-check::after { content: attr(data-tip); position: absolute; bottom: calc(100% + 7px); left: 50%; transform: translateX(-50%) translateY(3px);
  white-space: nowrap; background: #0a0c10; color: var(--text); border: 1px solid var(--border); font-size: 11px; font-weight: 600; padding: 4px 8px; border-radius: 6px;
  box-shadow: 0 6px 18px rgba(0,0,0,.5); opacity: 0; pointer-events: none; transition: opacity .12s ease, transform .12s ease; z-index: 12; }
.thumb .lib-check::before { content: ''; position: absolute; bottom: calc(100% + 2px); left: 50%; transform: translateX(-50%); border: 5px solid transparent; border-top-color: #0a0c10; opacity: 0; transition: opacity .12s ease; z-index: 12; }
.thumb .lib-check:hover::after { opacity: 1; transform: translateX(-50%) translateY(0); }
.thumb .lib-check:hover::before { opacity: 1; }
@media (hover: hover) { .row:hover .play-ov { opacity: 1; } }
.t-meta { min-width: 0; display: flex; align-items: center; gap: 8px; }
.t-text { min-width: 0; flex: 1; }
.listeners { display: flex; align-items: center; flex-shrink: 0; }
.avatar { width: 22px; height: 22px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: #fff; border: 2px solid var(--bg); text-shadow: 0 1px 1px rgba(0,0,0,.4); cursor: pointer; transition: transform .12s ease; }
.avatar:hover { transform: scale(1.18); position: relative; z-index: 1; }
.listeners .avatar:not(:first-child) { margin-left: -7px; }
.row:hover .avatar { border-color: var(--bg2); }
/* currently-playing row (your own playback) highlighted in theme colours */
.row.playing { background: color-mix(in srgb, var(--accent) 15%, transparent); box-shadow: inset 3px 0 0 var(--accent); }
.row.playing .t-title { color: var(--accent); }
.row.playing .play-ov { opacity: 1; }
/* Play overlay contents: ▶ icon (on hover) vs animated equalizer (when playing) */
.play-ov .eq { display: none; align-items: flex-end; gap: 2px; height: 18px; }
.play-ov .eq i { width: 3px; height: 5px; background: var(--accent); border-radius: 1px; animation: eqPlay .9s ease-in-out infinite; }
.play-ov .eq i:nth-child(2) { animation-delay: .3s; }
.play-ov .eq i:nth-child(3) { animation-delay: .15s; }
@keyframes eqPlay { 0%, 100% { height: 5px; } 50% { height: 17px; } }
/* Playing row → hide ▶, show the equalizer (frozen when paused) */
.row.playing .play-ov .pl-ic { display: none; }
.row.playing .play-ov .eq { display: flex; }
.row.playing.paused .play-ov .eq i { animation-play-state: paused; }
/* While a track is loading/buffering, swap the overlay for a spinner */
.row.buffering .play-ov { opacity: 1; }
.row.buffering .play-ov .pl-ic, .row.buffering .play-ov .eq { display: none; }
.row.buffering .play-ov::after { content: ''; width: 18px; height: 18px; border: 2.5px solid rgba(255,255,255,.35); border-top-color: #fff; border-radius: 50%; animation: spin .8s linear infinite; }
.row .t-title { font-size: 14px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row .t-sub { font-size: 12px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Clickable artist name → artist modal */
.artist-link { cursor: pointer; }
.artist-link:hover { color: var(--accent); text-decoration: underline; }
/* Artist modal */
/* ── Artist page ─────────────────────────────────────────────────────────────
   A full artist view rather than a bare list: hero, a "Popular" section led by
   plays, then every song we know with its own find box. */
/* Stops ABOVE the player bar, like the search overlay — the transport stays
   visible, unblurred and usable while you browse an artist. */
.overlay.artist-overlay { bottom: var(--player-h, 96px); }
.modal.artist-modal { width: min(96vw, 1080px); max-width: min(96vw, 1080px); height: 100%; max-height: 100%;
  display: flex; flex-direction: column; padding: 0; overflow: hidden; position: relative; }
.artist-modal .artist-body { overflow-y: auto; flex: 1; padding: 0 22px 28px; }
.artist-close { position: absolute; top: 14px; right: 14px; z-index: 3; background: rgba(0,0,0,.42); backdrop-filter: blur(6px); }
/* Hero: the top track's art, blown up and blurred behind it. */
.artist-hero { position: relative; margin: 0 -22px 8px; padding: 42px 22px 22px; overflow: hidden; }
.artist-hero::before { content: ''; position: absolute; inset: 0; background-image: var(--art); background-size: cover; background-position: center;
  filter: blur(42px) saturate(1.5); transform: scale(1.25); opacity: .45; }
.artist-hero::after { content: ''; position: absolute; inset: 0; background: linear-gradient(180deg, transparent, var(--bg2) 92%); }
.artist-hero-in { position: relative; z-index: 1; display: flex; align-items: flex-end; gap: 22px; }
.artist-pic { width: 168px; height: 168px; border-radius: 50%; object-fit: cover; flex-shrink: 0; box-shadow: 0 18px 46px rgba(0,0,0,.6); }
.artist-pic-none { display: flex; align-items: center; justify-content: center; background: var(--bg3); color: var(--mute); }
.artist-pic-none .svi { width: 56px; height: 56px; }
.artist-hero-txt { min-width: 0; }
.artist-kicker { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--dim); }
.artist-kicker .svi { width: 14px; height: 14px; }
.artist-name { font-size: clamp(28px, 5vw, 54px); font-weight: 800; line-height: 1.05; margin: 6px 0 8px; overflow-wrap: anywhere; }
.artist-stats { color: var(--dim); font-size: 13px; }
.artist-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
.artist-play, .artist-btn { display: inline-flex; align-items: center; gap: 8px; border-radius: 999px; cursor: pointer;
  font-size: 13px; font-weight: 700; text-decoration: none; padding: 10px 20px; border: 1px solid var(--border); background: var(--bg3); color: var(--text); }
.artist-play { background: var(--accent); border-color: transparent; color: var(--bg); padding: 11px 26px; font-size: 14px; }
.artist-play:hover { filter: brightness(1.08); }
.artist-btn:hover { border-color: var(--accent); }
.artist-play .svi, .artist-btn .svi { width: 16px; height: 16px; }
.artist-sec { font-size: 19px; font-weight: 800; margin: 22px 0 6px; }
.artist-sec-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 4px; }
.artist-sec-row .artist-sec { margin: 22px 0 6px; }
.artist-sec-row .pl-find { margin-left: auto; }
.artist-loading { color: var(--mute); font-size: 13px; padding: 6px 2px 10px; }
/* Latest / Most played segmented control. */
.artist-seg { display: inline-flex; background: var(--bg2); border: 1px solid var(--border); border-radius: 999px; padding: 2px; }
.artist-seg button { background: none; border: 0; border-radius: 999px; padding: 6px 14px; font-size: 12.5px; font-weight: 700; color: var(--dim); cursor: pointer; }
.artist-seg button.on { background: var(--accent); color: var(--bg); }
.artist-seg button:not(.on):hover { color: var(--text); }
@media (max-width: 760px) {
  .overlay.artist-overlay { padding: 0; }
  .modal.artist-modal { width: 100vw; max-width: 100vw; height: 100%; max-height: 100%; border-radius: 0; }
  .artist-modal .artist-body { padding: 0 14px 24px; }
  .artist-hero { margin: 0 -14px 8px; padding: 34px 14px 18px; }
  .artist-hero-in { flex-direction: column; align-items: flex-start; gap: 14px; }
  .artist-pic { width: 116px; height: 116px; }
  .artist-sec-row .pl-find { margin-left: 0; flex: 1 1 100%; }
}
.row .t-src { color: var(--mute); opacity: .6; text-transform: uppercase; font-size: 11px; }
/* "🔗 via <list>" chip on a live-linked row — tinted, clickable (→ source list). */
.row .t-via { margin-left: 8px; padding: 1px 7px; border-radius: 999px; font-size: 11px; font-weight: 600;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, transparent);
  white-space: nowrap; cursor: pointer; }
.row .t-via:hover { background: color-mix(in srgb, var(--accent) 28%, transparent); }
.row .t-views { color: var(--mute); white-space: nowrap; }
/* "Time listened" badge: total real seconds you've heard this song. */
.row .t-listened { margin-left: 8px; display: inline-flex; align-items: center; gap: 3px; padding: 1px 7px 1px 5px; border-radius: 999px;
  font-size: 11px; font-weight: 600; white-space: nowrap; color: var(--accent2, var(--accent));
  background: color-mix(in srgb, var(--accent2, var(--accent)) 14%, transparent); }
.row .t-listened .svi { width: 11px; height: 11px; }
.row .pill { font-size: 10px; color: var(--mute); display: inline-flex; align-items: center; gap: 5px; white-space: nowrap; }
.row .pill.pending, .row .pill.downloading { color: var(--accent2); }
.row .pill.pending::before, .row .pill.downloading::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--accent2); animation: pulse 1s ease-in-out infinite; }
.row .pill.ready { color: var(--accent); } .row .pill.failed { color: var(--danger); }
/* Spotify-import placeholder: no playable source yet (fix via ⋯ → Set source URL) */
.row .pill.nosource { color: var(--danger); border: 1px solid color-mix(in srgb, var(--danger) 45%, transparent); border-radius: 999px; padding: 2px 8px; }
@keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
.row .acts { display: flex; gap: 6px; }
/* Hold Shift → swap each removable row's ⋯ for an instant-delete ✕ (same slot) */
.row .quick-del { display: none; background: none; border: 1px solid color-mix(in srgb, var(--danger) 55%, var(--border)); color: var(--danger); border-radius: 6px; padding: 5px 9px; font-size: 12px; line-height: 1; cursor: pointer; }
.row .quick-del:hover { background: color-mix(in srgb, var(--danger) 18%, transparent); border-color: var(--danger); }
body.shift-del .row .quick-del { display: inline-flex; align-items: center; }
body.shift-del .row .acts:has(.quick-del) .kebab { display: none; } /* only swap when a ✕ exists (linked rows keep their ⋯) */
.row .acts button { background: none; border: 1px solid var(--border); color: var(--dim); border-radius: 6px; padding: 5px 9px; font-size: 12px; }
.row .acts button:hover { color: var(--text); border-color: var(--accent); }
.dur { color: var(--dim); font-size: 12px; display: inline-flex; align-items: center; gap: 7px; }
/* Group lists: who added the song, next to the duration — listener-avatar look
   (coloured initials + optional real photo) but static: no pulse, no eq badge. */
.row-adder { position: relative; width: 22px; height: 22px; font-size: 9px; cursor: default; flex-shrink: 0; }
.row-adder:hover { transform: none; z-index: auto; }
.row-adder .avatar-init { position: relative; z-index: 0; }
.row-adder .avatar-img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; z-index: 1; }

/* "← Back to <group>" link above a group list's hero */
.back-btn { background: none; border: none; color: var(--dim); font-size: 13px; font-weight: 600; padding: 4px 4px; margin-bottom: 4px; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; transition: color .15s ease; }
.back-btn:hover { color: var(--accent2); }
/* Group hero: scale the member-avatar collage initials up for the big cover */
.group-hero .cover .avatar-fb { font-size: 30px; }
.group-hero .cover-2 .avatar-fb, .group-hero .cover-3 .avatar-fb, .group-hero .cover-grid .avatar-fb { font-size: 17px; }
/* Group banner = BACKGROUND of the hero; the cover + name overlay on top of it
   (with a scrim for readability). A group without a banner keeps the plain hero. */
.group-hero { position: relative; overflow: hidden; }
.group-hero.has-banner { min-height: 210px; align-items: flex-end; border: none; }
.gh-banner { position: absolute; inset: 0; z-index: 0; }
.gh-banner img { width: 100%; height: 100%; object-fit: cover; display: block; }
.group-hero.has-banner::after { content: ''; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(180deg, rgba(0,0,0,.12), rgba(0,0,0,.78)); } /* darken bottom so text reads */
.group-hero.has-banner > .cover-edit, .group-hero.has-banner > .ph-info { position: relative; z-index: 1; }
.group-hero.has-banner .ph-type { color: rgba(255,255,255,.8); }
.group-hero.has-banner h2 { color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.5); }
.group-hero.has-banner .ph-meta, .group-hero.has-banner .ph-desc { color: rgba(255,255,255,.88); }
/* banner edit pen (top-right of the hero), shown on hover */
.gh-banner-pen { z-index: 2; }
.group-hero:hover .gh-banner-pen { opacity: 1; }
/* "Add banner" button (top-right) when the group has no banner yet */
.gh-banner-add { position: absolute; top: 12px; right: 12px; z-index: 2; background: var(--bg3);
  border: 1px solid var(--border); color: var(--text); border-radius: 8px; padding: 6px 12px;
  font-size: 12px; font-weight: 600; cursor: pointer; opacity: .85; transition: border-color .15s ease, opacity .15s ease; }
.gh-banner-add:hover { border-color: var(--accent); opacity: 1; }
@media (max-width: 700px) { .group-hero.has-banner { min-height: 150px; } }

/* Hover-to-edit pen on cover/banner images (top-right corner) */
.img-edit { position: relative; display: inline-block; flex-shrink: 0; line-height: 0; }
.img-edit-pen { position: absolute; top: 8px; right: 8px; width: 30px; height: 30px; border-radius: 50%; border: none;
  background: rgba(0,0,0,.55); color: #fff; font-size: 14px; line-height: 1; cursor: pointer; z-index: 4;
  display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity .15s ease, background .15s ease; }
.img-edit:hover .img-edit-pen, .group-banner:hover .img-edit-pen { opacity: 1; }
.img-edit-pen:hover { background: var(--accent); color: var(--bg); }
/* On touch (no hover), keep the pen faintly visible so it's discoverable */
@media (hover: none) { .img-edit-pen { opacity: .8; } }
.pheader { display: flex; align-items: center; gap: 14px; margin-bottom: 16px; }
.pheader h2 { margin: 0; }
.pheader button { background: var(--bg3); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 12px; font-size: 13px; display: inline-flex; align-items: center; gap: 6px; transition: border-color .15s ease, background .15s ease, color .15s ease; }
.pheader button:hover { border-color: var(--accent); }
.pheader .play-all { background: var(--accent); color: #06120a; border: none; font-weight: 700; }
/* "Most viewed first" sort toggle (slider switch), shown in the results header */
.results-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; }
.results-head h2 { margin-bottom: 0; }
.rh-controls { display: flex; align-items: center; gap: 10px; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
/* Drag audio files onto an open playlist → upload (download-power users). The
   inset ring stays at the visible edges even while the list scrolls. */
#content.file-drop { box-shadow: inset 0 0 0 2px var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); border-radius: 12px; }
/* Source filter pills (All / YouTube / SoundCloud) */
.src-filter { display: inline-flex; background: var(--bg2); border: 1px solid var(--border); border-radius: 999px; padding: 2px; }
.src-pill { background: none; border: 0; color: var(--dim); font-size: 12px; font-weight: 600; padding: 5px 12px; border-radius: 999px; cursor: pointer; white-space: nowrap; transition: color .15s ease, background .15s ease; }
.src-pill:hover { color: var(--text); }
.src-pill.active { background: var(--accent); color: var(--bg); }
.sort-toggle { display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0; cursor: pointer; user-select: none; font-size: 13px; font-weight: 600; color: var(--dim); white-space: nowrap; padding: 5px 6px; transition: color .15s ease; }
.sort-toggle:hover { color: var(--text); }
.sort-toggle input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.sort-toggle input:checked ~ .dl-switch { background: var(--accent); }
.sort-toggle input:checked ~ .dl-switch .dl-knob { transform: translateX(15px); }
.sort-toggle:has(input:checked) { color: var(--accent); }
/* Find-in-list box in the playlist header. */
.pl-find { display: inline-flex; align-items: center; gap: 7px; padding: 0 10px; height: 34px; border-radius: 9px;
  background: var(--bg2); border: 1px solid var(--border); color: var(--mute); transition: border-color .15s ease; }
.pl-find:focus-within { border-color: var(--accent); color: var(--accent); }
.pl-find .svi { width: 15px; height: 15px; flex-shrink: 0; }
.pl-find input { width: 168px; min-width: 0; background: none; border: 0; outline: 0; color: var(--text); font-size: 13px; padding: 0; }
.pl-find input::placeholder { color: var(--mute); }
.pl-find input::-webkit-search-cancel-button { display: none; } /* we draw our own ✕ */
.pl-find button { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px;
  background: none; border: 0; border-radius: 50%; color: var(--mute); cursor: pointer; flex-shrink: 0; }
.pl-find button:hover { color: var(--text); background: var(--bg3); }
.pl-find button[hidden] { display: none; }
.pl-nofind { display: flex; align-items: center; gap: 9px; color: var(--mute); font-size: 14px; padding: 22px 4px; }
.pl-nofind .svi { width: 17px; height: 17px; }
@media (max-width: 760px) { .pl-find { flex: 1 1 100%; } .pl-find input { width: 100%; } }

.sort-sel { background: var(--bg3); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 6px 10px; font-size: 13px; cursor: pointer; transition: border-color .15s ease; }
.sort-sel:hover { border-color: var(--accent); }
/* "View only" badge shown in the header of someone else's public list */
.pheader .ro-note { display: inline-flex; align-items: center; gap: 6px; color: var(--dim); font-size: 13px; padding: 6px 10px; border: 1px dashed var(--border); border-radius: 6px; }
.sort-sel:focus { outline: none; border-color: var(--accent); }
.pheader .play-all:hover { filter: brightness(1.06); }
.pheader button.danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); margin-left: auto; }
.pheader button.danger:hover { color: #fff; background: var(--danger); border-color: var(--danger); }
.member-stack { display: inline-flex; align-items: center; }
.member-stack .stack-av { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; border: 2px solid var(--bg); background: var(--bg3); }
.member-stack .stack-av:not(:first-child), .member-stack .stack-more { margin-left: -8px; }
.member-stack .stack-more { width: 28px; height: 28px; border-radius: 50%; background: var(--bg3); border: 2px solid var(--bg); display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: var(--dim); }
.members { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 18px; }

/* collapsible section header */
.toggle-head { cursor: pointer; user-select: none; display: inline-flex; align-items: center; gap: 7px; }
.toggle-head:hover { color: var(--text); }
.toggle-head .chev { display: inline-block; transition: transform .15s ease; font-size: 11px; }
.toggle-head.open .chev { transform: rotate(90deg); }
.toggle-head .count { color: var(--mute); font-weight: 400; font-size: 11px; background: var(--bg3); border-radius: 999px; padding: 1px 8px; }

/* group activity log */
.activity-log { list-style: none; margin: 8px 0 8px; display: flex; flex-direction: column; gap: 2px; max-width: 640px; }
.activity-log[hidden] { display: none; } /* explicit display: flex above would otherwise beat the hidden attribute */
.activity-log li { display: flex; align-items: center; gap: 10px; padding: 7px 8px; border-radius: 6px; font-size: 13px; color: var(--dim); }
.activity-log li:hover { background: var(--bg2); }
.activity-log .log-av { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; background: var(--bg3); flex-shrink: 0; }
.activity-log .log-text { min-width: 0; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.activity-log .log-actor { color: var(--text); font-weight: 600; }
.activity-log .log-track { color: var(--text); }
.activity-log .log-pl { color: var(--accent2); }
.activity-log .log-time { color: var(--mute); font-size: 11px; flex-shrink: 0; }
.member { display: inline-flex; align-items: center; gap: 7px; background: var(--bg2); border: 1px solid var(--border); border-radius: 999px; padding: 3px 12px 3px 3px; font-size: 12px; }
.member-av { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; background: var(--bg3); flex-shrink: 0; }
.member-avwrap { position: relative; display: inline-flex; flex-shrink: 0; }
/* Online presence dot, bottom-right of the avatar. Hidden until online. */
.member .online-dot, .gc-mem .online-dot { position: absolute; right: -1px; bottom: -1px; width: 9px; height: 9px; border-radius: 50%; z-index: 2; /* above the avatar image */
  background: var(--mute); border: 2px solid var(--bg2); display: none; }
.member.online .online-dot, .gc-mem.on .online-dot { display: block; background: #2fd562; }
.member.online { border-color: color-mix(in srgb, #2fd562 40%, var(--border)); }
/* Currently listening → accent ring around the avatar (group members + "online now"). */
.member-avwrap.listening .avatar-fb { box-shadow: 0 0 0 2px var(--accent); }
/* Right-side tabbed panel (Members | Chat) — only one panel shown at a time. */
.gc-tabs { display: flex; gap: 6px; padding: 0 0 10px; flex-shrink: 0; }
.gc-tab { flex: 1; padding: 8px; background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; color: var(--dim); font-weight: 600; font-size: 12.5px; cursor: pointer; }
.gc-tab.active { background: var(--accent); color: var(--bg); border-color: transparent; }
.gc-tab .gc-mem-count { color: inherit; opacity: .8; }
.gc-tab .tab-dot { display: none; width: 7px; height: 7px; border-radius: 50%; background: var(--accent2, #4ea1ff); margin-left: 6px; vertical-align: middle; }
.gc-tab.has-unread .tab-dot { display: inline-block; }
.gc-tab.active .tab-dot { display: none; }
.gc-panel { display: none; flex: 1; min-height: 0; flex-direction: column; }
.gc-panel.active { display: flex; }
/* Group members panel: admin badge, online sorted first, now-playing line. */
.gc-mem-head { display: flex; justify-content: space-between; align-items: center; font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--mute); padding: 2px 2px 8px 12px; flex-shrink: 0; }
.gc-add { background: var(--bg2); border: 1px dashed var(--border); color: var(--dim); border-radius: 999px; padding: 3px 11px; font-size: 11.5px; cursor: pointer; }
.gc-add:hover { color: var(--text); border-color: var(--accent); }
.gc-mem-count { font-size: 11px; font-weight: 600; color: var(--accent); margin-left: 6px; }
.gc-mem-list { display: flex; flex-direction: column; gap: 2px; flex: 1; min-height: 0; overflow-y: auto; }
.gc-mem { display: flex; align-items: center; gap: 9px; padding: 5px 6px 5px 12px; border-radius: 8px; cursor: pointer; }
.gc-mem:hover { background: var(--bg3); }
.gc-mem .gc-av { width: 30px; height: 30px; border-radius: 50%; }
.gc-av.avatar-fb { font-size: 11px; }

/* ── Full-page empty state (e.g. a private / missing list) ── */
.page-state { max-width: 420px; margin: clamp(40px, 12vh, 120px) auto 0; padding: 0 20px; text-align: center; display: flex; flex-direction: column; align-items: center; }
.page-state-ico { display: inline-flex; align-items: center; justify-content: center; width: 76px; height: 76px; border-radius: 50%; background: var(--bg3); color: var(--accent); margin-bottom: 18px; }
.page-state-ico svg { width: 38px; height: 38px; }
.page-state-title { margin: 0 0 8px; font-size: 22px; }
.page-state-msg { margin: 0; color: var(--dim); font-size: 14px; line-height: 1.5; }

/* ── User profile modal (avatar, name, song count, public lists) ── */
.modal.profile-modal { width: min(640px, 94vw); }
.profile-top { display: flex; align-items: center; gap: 14px; padding: 2px 0 14px; }
.profile-av { position: relative; display: inline-flex; flex-shrink: 0; }
.prof-av.avatar-fb { width: 64px; height: 64px; font-size: 22px; }
.profile-av { position: relative; display: inline-flex; }
.profile-av .online-dot { position: absolute; right: 3px; bottom: 3px; width: 14px; height: 14px; border-radius: 50%; z-index: 2; border: 2.5px solid var(--bg2); display: none; }
.profile-av.on .online-dot { display: block; background: #2fd562; }
.profile-av.listening .avatar-fb { box-shadow: 0 0 0 3px var(--accent), 0 0 12px color-mix(in srgb, var(--accent) 40%, transparent); }
.profile-name { font-size: 20px; font-weight: 800; }
.profile-meta { color: var(--dim); font-size: 13px; margin-top: 2px; }
.profile-section { margin-top: 4px; }
.profile-section + .profile-section { margin-top: 16px; }
.profile-np { margin-top: 6px; }
.profile-np .row { padding: 6px 8px; border-radius: 8px; background: var(--bg3); }
.profile-lists { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 8px; }
/* min-width:0 lets each card shrink to its column so a long name truncates instead of
   stretching its column and skewing the 2-up grid. */
.profile-lists .home-card { cursor: pointer; min-width: 0; }
.profile-lists .home-card .hc-text { flex: 1; min-width: 0; }
/* Let public-list names wrap (up to 2 lines) instead of truncating in the narrow cards. */
.profile-lists .hc-name { white-space: normal; overflow: visible; text-overflow: clip; overflow-wrap: anywhere; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
@media (max-width: 480px) { .profile-lists { grid-template-columns: 1fr; } }
.gc-mem-info { flex: 1; min-width: 0; }
.gc-mem-name { font-size: 13px; font-weight: 600; display: flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.gc-admin { font-size: 10px; font-weight: 700; color: var(--accent); }
/* Pending (invited, not yet accepted) member rows — greyed, at the bottom. */
.gc-mem.pending { opacity: .62; }
.gc-mem.pending .member-avwrap { filter: grayscale(.4); }
.gc-pending-tag { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--mute); border: 1px solid var(--border); border-radius: 999px; padding: 1px 7px; }
.gc-mem-sub { font-size: 11.5px; color: var(--mute); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gc-mem.on .gc-np { color: var(--accent); }
/* Members listening together share a colour (--sync): a left accent bar + 🎧 badge. */
.gc-mem.synced { box-shadow: inset 3px 0 0 var(--sync); background: color-mix(in srgb, var(--sync) 9%, transparent); }
.gc-mem.synced .gc-synced { margin-left: 5px; font-size: 11px; color: var(--sync); }
.gc-mem:not(.on) { opacity: .65; }
.gc-mem .member-sync { color: var(--accent); background: none; border: none; font-size: 14px; padding: 3px 5px; border-radius: 6px; cursor: pointer; flex-shrink: 0; }
.gc-mem .member-sync:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.member-sync { background: none; border: none; color: var(--accent); font-size: 13px; line-height: 1; margin-left: 2px; padding: 2px 4px; border-radius: 6px; cursor: pointer; }
.member-sync:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.member-x { background: none; border: none; color: var(--mute); font-size: 11px; line-height: 1; margin-left: 2px; padding: 2px 3px; border-radius: 4px; }
.member-x:hover { color: var(--danger); background: var(--bg3); }
.add-member { background: var(--bg2); border: 1px dashed var(--border); color: var(--dim); border-radius: 999px; padding: 4px 14px; font-size: 12px; }
.add-member:hover { color: var(--text); border-color: var(--accent); }

/* Player bar */
.player { grid-column: 1 / 3; grid-row: 2; position: relative; /* anchors the bottom-placed EQ ribbon */ background: linear-gradient(180deg, var(--bg2), var(--bg)); border-top: 1px solid var(--border); box-shadow: 0 -6px 24px rgba(0,0,0,.25); display: grid; grid-template-columns: 1fr 2fr 1fr; align-items: center; gap: 16px; padding: 0 18px; }
.np { display: flex; align-items: center; gap: 12px; min-width: 0; }
/* Clickable when playback came from a list you can open → jump to it + scroll there. */
.np.np-clickable { cursor: pointer; border-radius: 10px; transition: background .15s ease; }
.np.np-clickable:hover { background: color-mix(in srgb, var(--text) 7%, transparent); }
.np.np-clickable:hover .np-title { color: var(--accent); }
.np-art { position: relative; width: 54px; height: 54px; border-radius: 8px; background: var(--bg3); flex-shrink: 0; overflow: hidden; display: flex; align-items: center; justify-content: center; box-shadow: 0 3px 10px rgba(0,0,0,.45); }
.np-art img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.np-art img.ytbars { --npz: 1.34; transform: scale(var(--npz)); } /* crop baked-in 4:3 YT letterbox bars */
.np-note { color: var(--mute); font-size: 22px; }
.np-meta { min-width: 0; }
.np-title { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-artist { font-size: 12px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.controls { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.btns { display: flex; align-items: center; gap: 10px; }
.btns button { background: none; border: none; color: var(--dim); font-size: 20px; width: 40px; height: 40px; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: all .15s ease; }
.btns button svg { width: 20px; height: 20px; }
.btns .play svg { width: 22px; height: 22px; }
/* Like the play button: just brighten + scale on hover, no colour/background swap. */
.btns button:hover { filter: brightness(1.5); transform: scale(1.14); }
.btns button:active { transform: scale(.92); }
#shuffleBtn { position: relative; width: 30px; height: 30px; }
#shuffleBtn svg { width: 15px; height: 15px; display: block; }
#shuffleBtn.active { color: var(--accent); }
#shuffleBtn.active:hover { color: var(--accent); }
#shuffleBtn.active::after { content: ''; position: absolute; left: 50%; bottom: 1px; transform: translateX(-50%); width: 4px; height: 4px; border-radius: 50%; background: var(--accent); } /* Spotify-style "on" dot */
.btns .ctl-spacer { width: 30px; height: 30px; flex: none; pointer-events: none; } /* matches shuffle so Play stays centered */
body.npv-open .btns .ctl-spacer { width: 50px; height: 50px; }
body.npv-open #shuffleBtn svg { width: 26px; height: 26px; }
.btns .play { position: relative; width: 52px; height: 52px; background: var(--accent); color: var(--bg); font-size: 19px; box-shadow: 0 4px 16px color-mix(in srgb, var(--accent) 45%, transparent); }
.btns .play:hover { filter: brightness(1.12); transform: scale(1.06); }

/* Loading state: spinner on the play button + over the album art */
.np-spinner { position: absolute; inset: 0; display: none; align-items: center; justify-content: center; background: rgba(0,0,0,.5); border-radius: 8px; }
.player.loading .np-spinner { display: flex; }
.np-spinner::after { content: ''; width: 22px; height: 22px; border: 2.5px solid rgba(255,255,255,.25); border-top-color: #fff; border-radius: 50%; animation: spin .8s linear infinite; }
.player.loading .btns .play { color: transparent; pointer-events: none; }
.player.loading .btns .play::after { content: ''; position: absolute; inset: 0; margin: auto; width: 18px; height: 18px; border: 2.5px solid color-mix(in srgb, var(--bg) 30%, transparent); border-top-color: var(--bg); border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

.seekrow { display: flex; align-items: center; gap: 10px; width: 100%; max-width: 540px; font-size: 11px; color: var(--dim); }
.seekrow span { font-variant-numeric: tabular-nums; min-width: 34px; }
.seekrow #curTime { text-align: right; }
.seekrow #durTime { text-align: left; }
.seekrow input { flex: 1; }
.seekrow .seek-wrap { flex: 1; }
.seekrow .seek-wrap input { width: 100%; }

/* ── YouTube chapter markers on the seekbar ── */
.seek-wrap { position: relative; display: flex; align-items: center; }
/* The visible track is a separate layer so the chapter gaps (a transparent mask,
   see renderSeekMarks) can show the real background through it WITHOUT touching the
   thumb. The <input> itself is transparent — it just carries the thumb + clicks. */
.seek-fill { position: absolute; left: 0; right: 0; top: 50%; height: 5px; transform: translateY(-50%); border-radius: 999px; pointer-events: none; background: linear-gradient(to right, var(--accent) 0 var(--fill, 0%), var(--bg3) var(--fill, 0%) 100%); }
.seek-wrap.has-chapters .seek-fill { height: 6px; }
#seek { background: transparent; position: relative; z-index: 2; } /* keep the thumb above the fill/hover layers */
#seek::-moz-range-track { background: transparent; }
#seek::-moz-range-progress { background: transparent; }
/* Hovered chapter swells to read as a fatter segment. */
.seek-hover { position: absolute; top: 50%; transform: translateY(-50%); height: 9px; border-radius: 999px; pointer-events: none; background: color-mix(in srgb, var(--text) 22%, transparent); transition: height .1s ease; }
.seek-hover[hidden] { display: none; }
/* Floating title tooltip while hovering the bar. */
.seek-tip { position: absolute; bottom: calc(100% + 9px); transform: translateX(-50%); max-width: 300px; padding: 6px 10px; border-radius: 7px; background: #0a0c10; border: 1px solid var(--border); color: var(--text); font-size: 12.5px; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-shadow: 0 6px 18px rgba(0,0,0,.5); pointer-events: none; z-index: 5; }
.seek-tip .seek-tip-time { color: var(--accent); font-variant-numeric: tabular-nums; margin-right: 6px; }
.seek-tip[hidden] { display: none; }

/* custom range sliders (seek + volume) with a filled track */
.player input[type=range] { -webkit-appearance: none; appearance: none; height: 5px; border-radius: 999px; cursor: pointer; background: linear-gradient(to right, var(--accent) 0 var(--fill, 0%), var(--bg3) var(--fill, 0%) 100%); }
.player input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 13px; height: 13px; border-radius: 50%; background: var(--text); box-shadow: 0 1px 4px rgba(0,0,0,.5); transition: transform .12s ease; }
.player input[type=range]:hover::-webkit-slider-thumb { transform: scale(1.25); background: var(--accent2); }
.player input[type=range]::-moz-range-thumb { width: 13px; height: 13px; border: none; border-radius: 50%; background: var(--text); }
.player input[type=range]::-moz-range-track { height: 5px; border-radius: 999px; background: var(--bg3); }
.player input[type=range]::-moz-range-progress { height: 5px; border-radius: 999px; background: var(--accent); }

/* Live stream / unknown-length source: no meaningful position → a flat,
   non-interactive bar and a red "LIVE" label instead of bogus times. */
body.live-stream #seek { background: color-mix(in srgb, var(--danger) 28%, var(--bg3)); cursor: default; }
body.live-stream #seek::-webkit-slider-thumb { opacity: 0; pointer-events: none; transform: none; }
body.live-stream #seek::-moz-range-thumb { opacity: 0; }
body.live-stream #seek::-moz-range-progress { background: transparent; }
body.live-stream #durTime { color: var(--danger); font-weight: 700; letter-spacing: .3px; }

.right { display: flex; align-items: center; justify-content: flex-end; gap: 12px; }
.status { font-size: 11px; color: var(--accent2); white-space: nowrap; }
.status:not(:empty) { background: color-mix(in srgb, var(--accent2) 14%, transparent); padding: 3px 9px; border-radius: 999px; }
.volwrap { position: relative; display: flex; align-items: center; gap: 8px; color: var(--dim); font-size: 14px; }
.volwrap input { width: 90px; }
/* 0–100 readout bubble above the slider while adjusting volume. */
.vol-val { position: absolute; bottom: calc(100% + 9px); left: 0; min-width: 28px; text-align: center; background: var(--bg2); color: var(--text); border: 1px solid var(--border); border-radius: 7px; padding: 2px 7px; font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.4; white-space: nowrap; pointer-events: none; opacity: 0; transform: translate(-50%, 5px); transition: opacity .12s ease, transform .12s ease; box-shadow: 0 6px 18px rgba(0,0,0,.28); }
.vol-val::after { content: ""; position: absolute; top: 100%; left: 50%; margin-left: -5px; border: 5px solid transparent; border-top-color: var(--bg2); }
.vol-val.show { opacity: 1; transform: translate(-50%, 0); }

/* drag-to-reorder */
.row.drag { grid-template-columns: 18px 44px 1fr auto auto; }
.row .grip { color: var(--mute); cursor: grab; font-size: 14px; user-select: none; line-height: 1; text-align: center; }
/* Playlist rows lead with their position instead of the ⠿ grip. Wider than the
   grip column so three digits still fit; declared after .row.drag so a row that
   is both numbered and draggable takes this template. */
.row.numbered, .row.numbered.drag { grid-template-columns: 26px 44px 1fr auto auto; }
.row .rownum { color: var(--mute); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; text-align: center; user-select: none; line-height: 1; }
.row.numbered.drag .rownum { cursor: grab; }
.row.dragging .rownum { color: var(--accent); font-weight: 700; }
/* Phones: the number and the duration both give their width back to the song
   title. The .dur span itself stays in flow — it still carries the "added by"
   avatar on group lists — so the column count keeps matching the base template.
   Scoped to .numbered, i.e. playlist rows; search/history keep their durations. */
@media (max-width: 760px) {
  .row.numbered, .row.numbered.drag { grid-template-columns: 44px 1fr auto auto; }
  .row.numbered .rownum, .row.numbered .dur-t { display: none; }
}
.row.dragging { opacity: 1; background: color-mix(in srgb, var(--accent) 18%, var(--bg2)); outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 8px; box-shadow: 0 10px 28px rgba(0,0,0,.5); position: relative; z-index: 5; }
.row.dragging .grip { color: var(--accent); }
/* Pointer-based (desktop) song drag: grabbing cursor + floating chip for add-drags */
body.dragging-song, body.dragging-song * { cursor: grabbing !important; user-select: none !important; -webkit-user-select: none !important; }
/* While a long-press drag is live the row must stop handing vertical movement to
   the browser's scroller (.row is normally touch-action: pan-y), or the list
   scrolls out from under the song you're carrying. */
body.dnd-song .row { touch-action: none; }
.drag-ghost { position: fixed; z-index: 6000; transform: translate(12px, 10px); max-width: 260px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  padding: 6px 12px; border-radius: 8px; pointer-events: none; font-size: 13px; font-weight: 600;
  background: var(--bg2); color: var(--text); border: 1px solid var(--accent); box-shadow: 0 10px 30px rgba(0,0,0,.5); opacity: .96; }
/* Over a target list: the chip flips to an accent "＋ add" pill so intent is obvious. */
.drag-ghost.adding { background: var(--accent); color: #fff; border-color: var(--accent); }
.drag-ghost.adding::before { content: "＋ "; font-weight: 700; }
/* While a song is being dragged, sidebar playlists AND groups invite the drop */
body.dnd-song #playlistList li[data-pl], body.dnd-song #groupList li[data-gr], body.dnd-song #groupList .sublist li[data-pl] { outline: 1px dashed color-mix(in srgb, var(--accent) 40%, transparent); outline-offset: -1px; }
#playlistList li.drop-target, #groupList li.drop-target { background: color-mix(in srgb, var(--accent) 26%, transparent); outline: 2px solid var(--accent); outline-offset: -1px; border-radius: 6px; }
/* Reordering: the list being dragged dims; a folder header lights up when you can file into it. */
#playlistList li.dragging { opacity: .4; }
#playlistList .folder-row.drop-into { background: color-mix(in srgb, var(--accent) 18%, transparent); outline: 1.5px dashed var(--accent); outline-offset: -1px; border-radius: 6px; }

/* Group sub-list (▸ caret expands the group's playlists in the sidebar) */
.sh-actions { display: inline-flex; align-items: center; gap: 6px; }
.section-head button .svi { width: 13px; height: 13px; vertical-align: -1px; }
/* Per-list / per-folder kebab — revealed on hover (always shown on touch). */
.list li .li-menu { margin-left: auto; flex-shrink: 0; background: none; border: none; color: var(--mute); padding: 2px 4px; border-radius: 5px; cursor: pointer; opacity: 0; transition: opacity .12s ease, color .12s ease, background .12s ease; }
.list li .li-menu .svi { width: 16px; height: 16px; display: block; }
.list li:hover .li-menu, .list li .li-menu:focus-visible { opacity: 1; }
.list li .li-menu:hover { color: var(--text); background: color-mix(in srgb, var(--text) 12%, transparent); }
.folder-row .folder-ico { color: var(--dim); }
.folder-row .folder-ico .svi { width: 1.45em; height: 1.45em; }
@media (max-width: 760px) { .list li .li-menu { opacity: .55; } }
.grp-caret { background: none; border: none; color: var(--mute); font-size: 11px; line-height: 1; padding: 4px 3px; margin: 0 -2px 0 -4px; cursor: pointer; flex-shrink: 0; transition: transform .18s ease, color .15s ease; }
.grp-caret:hover { color: var(--text); }
.grp-caret.open { transform: rotate(90deg); }
/* Group sublist: collapsed to max-height 0 when closed; JS sets the pixel height so it animates. */
.list li.subwrap { display: block; padding: 0; background: none; cursor: default; overflow: hidden; max-height: 0; transition: max-height .26s cubic-bezier(.4, 0, .2, 1); }
.sublist { list-style: none; margin: 0; padding: 2px 0 6px 34px; position: relative; opacity: 0; transition: opacity .24s ease; }
.list li.subwrap.open .sublist { opacity: 1; }
/* Nesting guide line down the left of the indented lists. */
.sublist::before { content: ""; position: absolute; left: 16px; top: 3px; bottom: 7px; width: 1.5px; background: var(--border); border-radius: 2px; }
.sublist li { padding: 4px 8px; font-size: 12.5px; }
.sublist .cover { width: 28px; height: 28px; border-radius: 4px; }
.sublist .sub-empty { font-size: 11px; padding: 3px 8px; }

/* Playlist colour dot (sidebar names, add-to-playlist menus, header button) */
.pl-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; flex-shrink: 0; vertical-align: 0; }
.pheader h2 .pl-dot { width: 13px; height: 13px; margin-right: 9px; vertical-align: 1px; box-shadow: 0 0 10px currentColor; }
.pl-dot.big { width: 14px; height: 14px; margin: 0; display: block; }
.pl-color-btn { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: 8px; background: var(--bg3); border: 1px solid var(--border); cursor: pointer; }
.pl-color-btn:hover { border-color: var(--accent); }
.color-menu .swatches { display: grid; grid-template-columns: repeat(6, 26px); gap: 7px; padding: 8px 6px 6px; }
.color-menu .swatch { width: 26px; height: 26px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0; display: inline-flex; align-items: center; justify-content: center; line-height: 1; }
.color-menu .swatch:hover { transform: scale(1.15); }
.color-menu .swatch.sel { border-color: var(--text); }
.color-menu .swatch.none { background: var(--bg3); color: var(--dim); border: 1px dashed var(--border); font-size: 12px; line-height: 1; }
.row.moved { position: relative; z-index: 2; background: var(--bg2); } /* lifts while sliding into a new spot */

/* sidebar "someone is listening" — left-side beacon on the cover + glow ring,
   so it's obvious the list is live and joinable. */
.list li { position: relative; }
.list li.live .cover { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 70%, transparent); animation: listenGlow 1.7s ease-in-out infinite; }
.list li.live .li-text { color: var(--text); }
/* the pulsing "live" ball, sat on the cover's bottom-right corner (fixed 38px cover) */
.list li.live::after {
  content: ''; position: absolute; left: 39px; top: 36px;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--accent); border: 2px solid var(--sidebar-bg);
  z-index: 3; pointer-events: none;
  animation: livePulse 1.4s ease-out infinite;
}
/* Groups list: keep the green outline glow on the cover, but no pulsing ball. */
#groupList li.live::after { display: none; }
@keyframes livePulse {
  0%   { box-shadow: 0 0 5px var(--accent), 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent); }
  70%  { box-shadow: 0 0 5px var(--accent), 0 0 0 9px transparent; }
  100% { box-shadow: 0 0 5px var(--accent), 0 0 0 0 transparent; }
}
@keyframes listenGlow {
  0%, 100% { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 45%, transparent); }
  50%      { box-shadow: 0 0 0 2px var(--accent), 0 0 10px color-mix(in srgb, var(--accent) 45%, transparent); }
}

/* toasts */
/* Sits above the player, whose height is fixed on desktop but grows with content
   on mobile — --player-h is measured live in app.js (updatePlayerH). */
#toasts { position: fixed; right: 18px; bottom: calc(var(--player-h, 96px) + 12px); z-index: 200; display: flex; flex-direction: column; gap: 8px; }
.toast { position: relative; overflow: hidden; background: var(--bg3); border: 1px solid var(--border); border-left: 3px solid var(--accent); color: var(--text); padding: 10px 14px 12px; border-radius: 8px; font-size: 13px; max-width: 340px; box-shadow: 0 10px 30px rgba(0,0,0,.5); animation: toastIn .2s ease; }
.toast.out { opacity: 0; transform: translateY(8px); transition: opacity .3s, transform .3s; }
/* Persistent group-invitation toast (Accept / Decline; no auto-dismiss). */
.toast-invite { max-width: 360px; padding: 12px 14px; display: flex; flex-direction: column; gap: 11px; }
.toast-invite .ti-main { display: flex; gap: 11px; align-items: flex-start; }
.toast-invite .ti-ico { flex: none; width: 34px; height: 34px; border-radius: 9px; display: inline-flex; align-items: center; justify-content: center; color: var(--accent); background: color-mix(in srgb, var(--accent) 15%, transparent); }
.toast-invite .ti-ico .svi { width: 18px; height: 18px; }
.toast-invite .ti-text { min-width: 0; }
.toast-invite .ti-title { font-weight: 700; font-size: 13px; margin-bottom: 2px; }
.toast-invite .ti-sub { font-size: 12.5px; color: var(--dim); line-height: 1.4; }
.toast-invite .ti-sub b { color: var(--text); font-weight: 600; }
.toast-invite .ti-actions { display: flex; gap: 8px; justify-content: flex-end; }
.toast-invite .ti-btn { padding: 6px 15px; border-radius: 7px; font-size: 12.5px; font-weight: 700; cursor: pointer; border: 1px solid var(--border); background: var(--bg2); color: var(--text); transition: filter .12s ease, border-color .12s ease, color .12s ease; }
.toast-invite .ti-btn:disabled { opacity: .5; cursor: default; }
.toast-invite .ti-decline:hover { border-color: var(--danger); color: var(--danger); }
.toast-invite .ti-accept { background: var(--accent); border-color: var(--accent); color: var(--bg); }
.toast-invite .ti-accept:hover { filter: brightness(1.08); }
.toast-bar { position: absolute; left: 0; bottom: 0; height: 3px; width: 100%; background: var(--accent); transform-origin: left; animation: toastBar var(--toast-dur, 7000ms) linear forwards; }
.toast.toast-err { border-left-color: var(--danger); }
.toast.toast-err .toast-bar { background: var(--danger); }
/* Sticky import-progress toast (no auto-dismiss; live bar + cancel) */
.toast-import { min-width: 280px; }
.toast-import .ti-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 4px; }
.toast-import .ti-title { font-weight: 700; }
.toast-import .ti-cancel { background: var(--bg2); border: 1px solid var(--border); color: var(--dim); border-radius: 6px; padding: 3px 10px; font-size: 12px; cursor: pointer; transition: color .15s ease, border-color .15s ease; }
.toast-import .ti-cancel:hover { color: var(--danger); border-color: var(--danger); }
.toast-import .ti-cancel[disabled] { opacity: .55; cursor: default; pointer-events: none; }
.toast-import .ti-msg { color: var(--dim); font-size: 12px; white-space: pre-line; }
.toast-import .progress-track { margin: 9px 0 0; }
/* A track that failed to play — dimmed, with a struck-through, red title */
.row.unavailable { opacity: .55; }
.row.unavailable .t-title { color: var(--danger); text-decoration: line-through; }
.row.unavailable .play-ov { opacity: 1; font-size: 18px; }
.row.unavailable .play-ov .pl-ic, .row.unavailable .play-ov .eq { display: none; }
.row.unavailable .play-ov::after { content: '⚠'; color: var(--danger); }
@keyframes toastIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes toastBar { from { transform: scaleX(1); } to { transform: scaleX(0); } }

/* "Listen together" sync bar — floats above the player */
#syncBar { position: fixed; left: 50%; bottom: calc(var(--player-h, 96px) + 8px); transform: translateX(-50%) translateY(8px); z-index: 180; /* above the Now Playing view (150) + spectrum (155), below toasts (200) */ display: flex; align-items: center; gap: 10px; background: var(--bg3); border: 1px solid var(--accent); border-radius: 999px; padding: 6px 8px 6px 14px; box-shadow: 0 12px 34px rgba(0,0,0,.55); opacity: 0; pointer-events: none; transition: opacity .2s ease, transform .2s ease; max-width: calc(100vw - 24px); }
#syncBar:empty { display: none; }
#syncBar.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
#syncBar .sync-ic { font-size: 15px; }
#syncBar .sync-avs { display: inline-flex; flex-shrink: 0; }
#syncBar .sync-av { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; border: 2px solid var(--bg3); background: var(--bg2); }
#syncBar .sync-av:not(:first-child) { margin-left: -8px; }
#syncBar .sync-text { font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#syncBar #syncLeave { background: var(--bg2); border: 1px solid var(--border); color: var(--text); border-radius: 999px; padding: 5px 14px; font-size: 12px; font-weight: 600; flex-shrink: 0; }
#syncBar #syncLeave:hover { border-color: var(--danger); color: var(--danger); }
/* Clickable summary → expands upward into the detailed participant list. */
#syncBar .sync-main { display: inline-flex; align-items: center; gap: 10px; min-width: 0; background: none; border: none; color: inherit; font: inherit; cursor: pointer; padding: 0; }
#syncBar .sync-caret { display: inline-flex; color: var(--dim); transform: rotate(-90deg); transition: transform .18s ease; flex-shrink: 0; }
#syncBar .sync-caret .svi { width: 15px; height: 15px; }
#syncBar.expanded .sync-caret { transform: rotate(90deg); }
.sync-detail { position: absolute; left: 50%; bottom: calc(100% + 10px); transform: translateX(-50%) translateY(8px); width: max-content; min-width: 230px; max-width: min(340px, 92vw); background: var(--bg2); border: 1px solid var(--border); border-radius: 14px; padding: 8px; box-shadow: 0 18px 50px rgba(0,0,0,.6); opacity: 0; pointer-events: none; transition: opacity .18s ease, transform .18s ease; }
#syncBar.expanded .sync-detail { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.sync-d-head { display: flex; align-items: center; gap: 7px; font-size: 12px; font-weight: 700; color: var(--dim); padding: 4px 8px 8px; }
.sync-d-head .svi { width: 15px; height: 15px; }
.sync-d-row { display: flex; align-items: center; gap: 4px; }
.sync-d-av.avatar-fb { width: 32px; height: 32px; border-radius: 50%; font-size: 12px; flex-shrink: 0; }
.sync-d-info { min-width: 0; }
.sync-d-name { display: flex; align-items: center; gap: 6px; font-size: 13.5px; font-weight: 600; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.sync-d-sub { font-size: 11px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sync-d-badge { font-size: 9.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px; padding: 1px 6px; border-radius: 999px; background: var(--bg3); color: var(--dim); }
.sync-d-badge.you { background: color-mix(in srgb, var(--accent) 18%, var(--bg3)); color: var(--accent); }
.sync-d-badge.host { display: inline-flex; align-items: center; gap: 3px; background: color-mix(in srgb, var(--accent) 22%, var(--bg3)); color: var(--accent); }
.sync-d-badge.host .svi { width: 11px; height: 11px; }
.sync-d-badge.muted-tag { background: var(--bg3); color: var(--mute); text-transform: none; letter-spacing: 0; font-weight: 600; }
/* Host tools: appear on other people's rows when I'm the lead. */
.sync-d-tools { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }
.sync-d-tool { flex-shrink: 0; background: none; border: none; color: var(--dim); display: inline-flex; padding: 5px; border-radius: 7px; cursor: pointer; transition: color .15s ease, background .15s ease; }
.sync-d-tool .svi { width: 16px; height: 16px; }
.sync-d-tool:hover { background: var(--bg3); color: var(--text); }
.sync-d-tool.sh-ctl.on { color: var(--accent); }
.sync-d-tool.sh-host:hover { color: var(--accent); }
.sync-d-tool.sh-kick:hover { color: #ff5c5c; background: color-mix(in srgb, #ff5c5c 14%, transparent); }
/* Listen-only: the host revoked my control → transport greyed out + inert. */
.ctl-locked { opacity: .32; cursor: not-allowed; pointer-events: none; filter: grayscale(0.4); }
/* Currently-playing list (named only if the viewer has access; clickable when so). */
.sync-d-list { display: flex; align-items: center; gap: 7px; width: 100%; font-size: 12px; color: var(--dim); padding: 4px 8px 9px; border: none; border-bottom: 1px solid var(--border); margin-bottom: 6px; background: none; font-family: inherit; text-align: left; }
.sync-d-list .svi { width: 14px; height: 14px; flex-shrink: 0; }
.sync-d-list b { color: var(--text); font-weight: 600; }
.sync-d-list-btn { cursor: pointer; border-radius: 8px; transition: color .15s ease; }
.sync-d-list-btn:hover { color: var(--text); }
.sync-d-list-btn:hover b { color: var(--accent); }
/* Per-user row: profile-click area + expand caret. */
.sync-d-user .sync-d-row { align-items: center; }
.sync-d-who { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; padding: 6px 8px; border: none; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; border-radius: 9px; transition: background .15s ease; }
.sync-d-who:hover { background: var(--bg3); }
.sync-d-expand { margin-left: auto; flex-shrink: 0; background: none; border: none; color: var(--dim); display: inline-flex; padding: 4px; border-radius: 6px; cursor: pointer; transform: rotate(90deg); transition: transform .18s ease, color .15s ease, background .15s ease; }
.sync-d-expand .svi { width: 16px; height: 16px; }
.sync-d-expand:hover { color: var(--text); background: var(--bg3); }
.sync-d-user.open .sync-d-expand { transform: rotate(-90deg); }
.sync-d-devices { display: none; padding: 0 8px 6px 52px; }
.sync-d-user.open .sync-d-devices { display: block; }
.sync-dev { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-size: 12px; }
.sync-dev-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--mute); flex-shrink: 0; }
.sync-dev-dot.on { background: #2fd562; }
.sync-dev-label { color: var(--text); }
.sync-dev-muted { color: var(--mute); font-size: 11px; }
@media (max-width: 760px) { #syncBar .sync-text { max-width: 44vw; } }

/* ── Device picker (player-bar button + popover) ── */
#devBtn { display: inline-flex; align-items: center; justify-content: center; padding: 0; }
#devBtn[hidden] { display: none; }                  /* inline-flex would otherwise defeat the hidden attribute */
#devBtn svg { display: block; }                     /* no text baseline → icon sits dead-center in the 32px button */
#devBtn.remote { color: var(--accent); }            /* playback elsewhere / muted → lit up like Spotify's cast icon */
#devBar { position: fixed; right: 14px; bottom: calc(var(--player-h, 96px) + 10px); z-index: 181; background: var(--bg2); border: 1px solid var(--border); border-radius: 12px; padding: 8px; min-width: 260px; box-shadow: 0 12px 40px rgba(0,0,0,.55); }
#devBar[hidden] { display: none; }
#devBar .dev-head { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--mute); padding: 4px 10px 8px; }
#devBar .dev-row { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; background: none; border: none; color: var(--text); font-size: 13px; padding: 8px 10px; border-radius: 6px; cursor: pointer; }
#devBar .dev-row:hover { background: var(--bg3); }
#devBar .dev-row.active { color: var(--accent); font-weight: 600; }
#devBar .dev-label { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#devBar .dev-ck { flex-shrink: 0; width: 17px; height: 17px; border: 1.5px solid var(--border); border-radius: 5px; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; color: var(--bg); }
#devBar .dev-ck.on { background: var(--accent); border-color: var(--accent); }
#devBar .dev-lead { flex-shrink: 0; font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--bg); background: var(--accent); border-radius: 4px; padding: 1px 5px; }
#devBar .dev-sep { height: 1px; background: var(--border); margin: 5px 4px; }
#devBar .dev-row.dev-none { color: var(--dim); }
#devBar .dev-row.dev-none:hover { color: var(--text); }
@media (max-width: 760px) { #devBar { right: 8px; } }

/* row context menu (⋯) */
.row .acts .kebab { display: inline-flex; align-items: center; justify-content: center; padding: 5px 7px; }
.row .acts .kebab .svi { width: 18px; height: 18px; }
/* z-index 360: above .overlay (300) and #ytWrap.modal-live (301) so a row's ⋯/right-click
   menu opened from inside the artist modal (or any overlay) stays on top, not under it. */
.menu { position: absolute; background: var(--bg2); border: 1px solid var(--border); border-radius: 8px; padding: 6px; z-index: 360; min-width: 200px; max-height: calc(100vh - 16px); overflow-y: auto; box-shadow: 0 12px 40px rgba(0,0,0,.5); }
.menu button { display: block; width: 100%; text-align: left; background: none; border: none; color: var(--text); font-size: 13px; padding: 7px 10px; border-radius: 5px; }
.menu button:hover { background: var(--bg3); }
.menu .mh { color: var(--mute); font-size: 11px; padding: 4px 10px; }
/* Sub-labels inside "Add to playlist": separate personal lists from each group. */
/* Section headers in the add-to-playlist list ("Personal" / each group). One
   treatment for both — they were 10px uppercase+tracked vs 11px normal-case, which
   read as two unrelated things. Sized up to sit properly beside the cover rows,
   with the group icon aligned instead of floating as inline text. */
.menu .msub { display: flex; align-items: center; gap: 6px; color: var(--accent);
  font-size: 11.5px; font-weight: 700; text-transform: none; letter-spacing: 0;
  padding: 11px 10px 5px; opacity: 1; }
.menu .msub .svi { width: 13px; height: 13px; flex-shrink: 0; }
/* "All playlists ▸" flyout trigger + its side submenu. */
.menu button.has-sub { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.menu button.has-sub.open { background: var(--bg3); }
.menu .sub-caret { color: var(--mute); font-size: 11px; }
.menu .pl-gtag { opacity: .75; font-size: 11px; }
.menu.submenu { z-index: 361; }
.menu .msep { height: 1px; background: var(--border); margin: 6px 4px; }
.menu button.danger { color: var(--danger); }
/* Second line in the "send to which Discord server?" picker — what that bot is doing. */
.dc-pick-sub { display: block; color: var(--mute); font-size: 11px; margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 260px; }
/* The sheet identity header is rendered into every menu but only shown once the
   menu becomes a bottom sheet (see the max-width:760px block) — desktop popups
   are anchored right next to the row, so they don't need restating. */
.sheet-head { display: none; }

/* ── Mobile: popup menus become bottom sheets ────────────────────────────────
   On a phone an anchored popup lands wherever the tapped kebab happened to be —
   often half off-screen, with 13px targets. Below ~760px every .menu instead
   slides up from the bottom edge, full width, with big tap targets and a grab
   handle. The slide-up is a plain CSS animation (not a JS-toggled class) so it
   runs on insertion, can't flash at the wrong position, and still works if the
   enhancement JS below never runs. The anchoring math in app.js keeps running
   and setting inline top/left — !important overrides it rather than making
   every call site branch. */
@media (max-width: 760px) {
  .menu {
    position: fixed !important;
    left: 0 !important; right: 0 !important; bottom: 0 !important; top: auto !important;
    width: auto !important; min-width: 0 !important; max-width: none !important;
    max-height: 72vh !important;
    border-radius: 18px 18px 0 0;
    border-left: 0; border-right: 0; border-bottom: 0;
    padding: 0 8px calc(10px + env(safe-area-inset-bottom, 0px));
    box-shadow: 0 -14px 44px rgba(0, 0, 0, .55);
    overscroll-behavior: contain;
    animation: sheetUp .3s cubic-bezier(.32, .72, 0, 1);
  }
  .menu::before { /* grab handle */
    content: ''; display: block; width: 40px; height: 4px; border-radius: 2px;
    background: var(--border); margin: 10px auto 8px;
  }
  .menu button { padding: 13px 14px; font-size: 15px; border-radius: 8px; }
  .menu .mh { font-size: 12px; padding: 8px 14px 5px; }
  .menu .msub { padding: 13px 14px 6px; font-size: 12.5px; }
  .menu .msub .svi { width: 15px; height: 15px; }
  .menu .msep { margin: 6px 10px; }
  .menu .dc-pick-sub { font-size: 12px; max-width: 100%; }
  .menu.submenu { z-index: 362; } /* the "All playlists" flyout stacks over its parent sheet */
  /* Identity header: which song / list this sheet is acting on. */
  .menu .sheet-head { display: flex; align-items: center; gap: 12px; padding: 4px 12px 12px; margin-bottom: 4px; border-bottom: 1px solid var(--border); }
  .menu .sheet-head .cover { width: 48px; height: 48px; flex: 0 0 48px; border-radius: 6px; font-size: 20px; }
  .menu .sheet-head-txt { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .menu .sheet-head-title { font-weight: 700; font-size: 15px; line-height: 1.25; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .menu .sheet-head-sub { color: var(--mute); font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Back out of a sub-sheet to the menu underneath it. */
  .menu .sheet-back { color: var(--mute); font-weight: 600; padding: 10px 12px; margin-bottom: 2px; border-bottom: 1px solid var(--border); border-radius: 0; }
  .menu .sheet-back:hover { background: none; color: var(--text); }
  /* Dismissal is a transition, not an animation, so a sheet dragged part-way
     down carries on from where the finger left it instead of snapping back. */
  .menu.closing { transition: transform .2s ease-in; transform: translateY(100%) !important; }
}
@keyframes sheetUp { from { transform: translateY(100%); } to { transform: translateY(0); } }
.menu-scrim { position: fixed; inset: 0; background: rgba(0, 0, 0, .5); z-index: 359; animation: scrimIn .3s ease both; }
.menu-scrim.closing { animation: scrimOut .2s ease both; }
@keyframes scrimIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes scrimOut { from { opacity: 1; } to { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .menu, .menu.closing, .menu-scrim, .menu-scrim.closing { animation: none; transition: none; }
}

/* ── Header right cluster + icon buttons ── */
.header-right { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 10px; min-width: 0; max-width: 100%; }
/* Let the account chip's name truncate when the topbar gets tight, so the chip never
   overflows the search bar or runs off the right edge (it shrinks to avatar + gear). */
.header-right .account, .header-right .user-chip { min-width: 0; }
.user-chip .uname { min-width: 0; }
.icon-btn { background: var(--bg3); border: 1px solid var(--border); color: var(--dim); width: 36px; height: 36px; border-radius: 8px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; transition: all .2s ease; }
.icon-btn:hover { color: var(--text); border-color: var(--accent); }
.icon-btn svg { width: 18px; height: 18px; }
.hamburger { display: none; grid-column: 1; justify-self: start; }

/* ── Home screen — greeting hero, live group listening, recently played ── */
.home { max-width: 960px; margin: 0 auto; }
.home-hero { position: relative; text-align: center; padding: 30px 12px 10px; }
.home-hero::before { content: ''; position: absolute; inset: -30px -60px 0; background: radial-gradient(55% 90% at 50% 25%, color-mix(in srgb, var(--accent) 13%, transparent), transparent 72%); pointer-events: none; }
.home h2.home-greet { position: relative; font-size: clamp(24px, 4vw, 36px); font-weight: 800; letter-spacing: -.4px; margin: 0;
  background: linear-gradient(92deg, var(--text) 10%, var(--accent) 55%, var(--accent2)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.home-tag { position: relative; color: var(--dim); font-size: 14px; margin-top: 7px; }
.home-sec { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .9px; color: var(--dim); margin: 24px 0 10px; }
.home-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
/* Home "Online now" — group friends online, reusing the group members-panel rows. */
.home-friends { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 4px 12px; }
.home-friends .gc-mem { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 7px 10px; }
.home-friends .gc-mem:hover { background: var(--bg3); }
.home-card { position: relative; display: flex; align-items: center; gap: 12px; padding: 11px 13px; border: 1px solid var(--border); border-radius: 14px; cursor: pointer;
  background: linear-gradient(180deg, var(--bg2), color-mix(in srgb, var(--bg2) 72%, var(--bg))); box-shadow: 0 2px 10px rgba(0,0,0,.20);
  transition: border-color .15s ease, background .15s ease, transform .15s ease, box-shadow .15s ease; }
.home-card:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--accent) 65%, var(--border)); background: var(--bg3); box-shadow: 0 10px 24px rgba(0,0,0,.35); }
.home-card .cover { width: 56px; height: 56px; border-radius: 10px; flex-shrink: 0; font-size: 22px; box-shadow: 0 3px 10px rgba(0,0,0,.4); }
.hc-text { min-width: 0; }
.hc-name { font-weight: 700; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The list currently playing shows the same equalizer bars as a playing row */
.home-card .eq { display: none; align-items: flex-end; gap: 2px; height: 12px; margin-right: 7px; vertical-align: -1px; }
.home-card .eq i { width: 3px; height: 5px; background: var(--accent); border-radius: 1px; animation: eqPlay .9s ease-in-out infinite; }
.home-card .eq i:nth-child(2) { animation-delay: .3s; }
.home-card .eq i:nth-child(3) { animation-delay: .15s; }
.home-card.playing .eq { display: inline-flex; }
.home-card.playing.paused .eq i { animation-play-state: paused; }
.home-card.playing { border-color: color-mix(in srgb, var(--accent) 65%, var(--border)); }
.home-card.playing .hc-name { color: var(--accent); }
.hc-sub { font-size: 12px; color: var(--dim); margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-card.live { border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); box-shadow: 0 2px 14px color-mix(in srgb, var(--accent) 22%, transparent); }
.home-card .live-dot { position: absolute; top: 10px; right: 10px; width: 9px; height: 9px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 8px var(--accent); animation: hcPulse 1.6s ease-in-out infinite; }
@keyframes hcPulse { 50% { opacity: .35; } }
.home-empty { text-align: center; color: var(--dim); font-size: 14px; line-height: 1.6; padding: 30px 16px; background: var(--bg2); border: 1px dashed var(--border); border-radius: 14px; }
/* Leave-sync prompt: "Add to the queue" — the primary action while a queue runs */
.sync-queue-btn { display: block; width: 100%; margin: 2px 0 12px; padding: 11px 14px; border-radius: 10px;
  background: var(--bg3); border: 1px solid var(--border); color: var(--text); font-size: 14px; font-weight: 600; cursor: pointer;
  transition: border-color .15s ease, filter .15s ease; }
.sync-queue-btn:hover { border-color: var(--accent); filter: brightness(1.08); }
.sync-queue-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--bg); font-weight: 800; font-size: 15px; padding: 15px;
  box-shadow: 0 6px 20px color-mix(in srgb, var(--accent) 40%, transparent); }
/* Leave-sync dialog: the big "Play for everyone" primary, then smaller options below. */
.sync-all-btn { display: block; width: 100%; text-align: left; margin: 2px 0 10px; padding: 14px 16px; border-radius: 12px;
  background: var(--accent); border: 1px solid var(--accent); color: var(--bg); font-size: 15px; font-weight: 800; cursor: pointer;
  box-shadow: 0 6px 20px color-mix(in srgb, var(--accent) 40%, transparent); transition: filter .15s ease; }
.sync-all-btn:hover { filter: brightness(1.08); }
.sync-all-btn small { display: block; font-size: 11.5px; font-weight: 600; opacity: .85; margin-top: 3px; }
.sync-mini { display: block; width: 100%; text-align: left; margin: 0 0 8px; padding: 9px 13px; border-radius: 9px;
  background: var(--bg3); border: 1px solid var(--border); color: var(--text); font-size: 13px; font-weight: 600; cursor: pointer;
  transition: border-color .15s ease; }
.sync-mini:hover { border-color: var(--accent); }
.sync-mini-lg { padding: 13px 16px; border-radius: 12px; font-size: 15px; font-weight: 700; margin-bottom: 10px; }
.sync-mini-lg small { display: block; font-size: 11.5px; font-weight: 600; color: var(--dim); margin-top: 3px; }
.dialog-actions .dlg-leave { background: var(--bg3); border: 1px solid var(--border); color: var(--danger); }
.dialog-actions .dlg-leave:hover { border-color: var(--danger); }

/* Import-source manager (🔄 Sources modal) + confirm-dialog checkbox */
.dlg-check { display: flex; align-items: center; gap: 9px; margin: 4px 2px 14px; font-size: 13px; color: var(--dim); cursor: pointer; user-select: none; }
.dlg-check input { width: 15px; height: 15px; accent-color: var(--accent); cursor: pointer; }
.src-row { display: flex; align-items: center; gap: 10px; padding: 10px 2px; border-bottom: 1px solid var(--border); }
.src-row:last-child { border-bottom: none; }
.src-info { min-width: 0; flex: 1; }
.src-name { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.src-sub { font-size: 11px; color: var(--dim); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.src-sub a { color: var(--mute); text-decoration: none; }
.src-sub a:hover { color: var(--accent2); text-decoration: underline; }
.src-auto { padding: 4px 9px 4px 7px; font-size: 11px; flex-shrink: 0; }
.mini-btn { background: var(--bg3); border: 1px solid var(--border); color: var(--dim); border-radius: 7px; padding: 6px 10px; font-size: 12px; cursor: pointer; flex-shrink: 0; transition: color .15s ease, border-color .15s ease; }
.mini-btn:hover { color: var(--text); border-color: var(--accent); }
.mini-btn.danger:hover { color: var(--danger); border-color: var(--danger); }
.mini-btn[disabled] { opacity: .55; pointer-events: none; }

/* "More like this" suggestions at the bottom of a playlist */
.suggest { margin-top: 22px; padding-top: 16px; border-top: 1px solid var(--border); }
.suggest-head { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.suggest-head h3 { font-size: 15px; margin: 0; }
.suggest-head .muted { font-size: 12px; }
.suggest-head .mini-btn { margin-left: auto; }
.suggest-show-btn { display: inline-flex; align-items: center; gap: 8px; background: var(--bg3); border: 1px solid var(--border); color: var(--text);
  border-radius: 9px; padding: 9px 16px; font-size: 13px; font-weight: 600; cursor: pointer; transition: color .15s ease, border-color .15s ease, background .15s ease; }
.suggest-show-btn:hover { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--bg3)); }
.suggest-show-btn svg { width: 16px; height: 16px; }
.suggest-add { flex-shrink: 0; background: var(--bg3); border: 1px solid var(--border); color: var(--dim); border-radius: 999px; padding: 4px 11px; font-size: 12px; font-weight: 600; cursor: pointer; white-space: nowrap; transition: color .15s ease, border-color .15s ease; }
.suggest-add:hover { color: var(--accent); border-color: var(--accent); }
.suggest-add.added { color: var(--accent); border-color: var(--accent); }
.suggest-add[disabled] { cursor: default; }

/* Playlist view hero banner — big cover, totals, members, live listeners */
.pl-hero { position: relative; display: flex; align-items: center; gap: 20px; padding: 20px; margin-bottom: 16px; border-radius: 16px; border: 1px solid var(--border);
  background: linear-gradient(180deg, color-mix(in srgb, var(--plc, var(--accent)) 13%, var(--bg2)), var(--bg2)); }
.pl-hero .cover { width: 112px; height: 112px; border-radius: 14px; font-size: 42px; flex-shrink: 0; box-shadow: 0 12px 32px rgba(0,0,0,.45); }
.ph-info { min-width: 0; flex: 1; }
.ph-type { font-size: 11px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; color: var(--dim); margin-bottom: 5px; }
.pl-hero h2 { font-size: clamp(22px, 3vw, 30px); margin: 0 0 7px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-hero h2 .pl-dot { width: 14px; height: 14px; margin-right: 10px; vertical-align: 2px; box-shadow: 0 0 10px currentColor; }
.ph-meta { font-size: 13px; color: var(--dim); display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.ph-desc { margin-top: 8px; font-size: 13px; color: var(--dim); line-height: 1.5; white-space: pre-wrap; word-break: break-word; max-width: 680px; }
/* Saved AI overview — a stylish pull-quote in the banner. The info hugs its content
   (instead of flex:1) when a quote is present, so the quote shifts left toward the cover. */
.pl-hero:has(.ph-quote) .ph-info { flex: 0 1 auto; }
/* fit-content so the box hugs the text → the corner marks stay close to it; capped
   width for long ones; margin:auto centers it in the banner's free space. */
.ph-quote { position: relative; flex: 0 1 auto; align-self: center; width: fit-content; max-width: min(620px, 60%);
  margin: 0 auto; padding: 14px 30px; text-align: center;
  font-size: 15px; line-height: 1.7; font-weight: 500; color: var(--dim); }
.ph-quote::before, .ph-quote::after { position: absolute; font-size: 38px; line-height: 1; color: var(--accent); opacity: .5; font-family: Georgia, 'Times New Roman', serif; }
.ph-quote::before { content: '\201C'; left: 0; top: 0; }            /* top-left, by the text */
.ph-quote::after { content: '\201D'; right: 0; bottom: -14px; }    /* bottom-right, by the text */
.ph-quote-x { position: absolute; top: -2px; right: -2px; background: none; border: none; color: var(--mute); font-size: 11px; cursor: pointer; padding: 2px 5px; border-radius: 4px; opacity: 0; transition: opacity .15s ease; }
.ph-quote:hover .ph-quote-x { opacity: 1; }
.ph-quote-x:hover { color: var(--danger); background: var(--bg3); }
/* Narrow: wrap the quote to a full-width row below the cover+info. */
@media (max-width: 720px) { .pl-hero { flex-wrap: wrap; } .ph-quote { flex: 1 1 100%; max-width: none; text-align: left; padding: 10px 14px 4px; border-top: 1px solid var(--border); } .ph-quote::before { display: inline; margin: 0; } }
.ph-live { margin-top: 10px; display: flex; align-items: center; gap: 10px; }
.ph-live .ph-live-txt { font-size: 13px; color: var(--accent); font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ph-live .listeners { flex-shrink: 0; }
@media (max-width: 760px) {
  .pl-hero { gap: 14px; padding: 14px; }
  .pl-hero .cover { width: 78px; height: 78px; font-size: 28px; }
}

/* Personal/group chip on Home cards */
.hc-chip { display: inline-block; font-size: 10px; font-weight: 700; padding: 1px 7px; margin-right: 7px; border-radius: 999px;
  background: var(--bg3); border: 1px solid var(--border); color: var(--dim); vertical-align: 1px;
  max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hc-chip.grp { color: var(--accent2); border-color: color-mix(in srgb, var(--accent2) 45%, var(--border)); background: color-mix(in srgb, var(--accent2) 12%, var(--bg3)); }
/* Home "Live now" cards: listener avatars (clickable → sync) by the right edge */
.hc-listeners { margin-left: auto; margin-right: 16px; flex-shrink: 0; display: flex; align-items: center; }
/* Group view: shared-playlist cards (home-card look + live listener bubbles) */
.gpl-grid { margin-bottom: 6px; }
.gpl-head { margin: 20px 0 12px; }
.gpl-card .listeners { margin-left: auto; flex-shrink: 0; }
.gpl-card .hc-name .pl-dot { vertical-align: 1px; }
.home-empty .he-note { display: block; font-size: 30px; color: var(--mute); margin-bottom: 8px; }
.brand { cursor: pointer; }

/* "N online" badge — topbar right; hover shows active listeners */
.online-badge { display: inline-flex; align-items: center; gap: 8px; width: fit-content; padding: 5px 13px;
  border: 1px solid var(--border); border-radius: 999px; font-size: 12px; color: var(--dim); cursor: default; flex-shrink: 0;
  background: linear-gradient(180deg, var(--bg2), color-mix(in srgb, var(--bg2) 70%, var(--bg))); }
.online-badge b { color: var(--text); font-weight: 700; }
.online-badge .ob-dot { width: 8px; height: 8px; border-radius: 50%; background: #2ecc71; box-shadow: 0 0 9px #2ecc71; animation: hcPulse 2.2s ease-in-out infinite; flex-shrink: 0; }
.online-badge[hidden] { display: none; }
@media (max-width: 760px) { .home-hero { padding-top: 14px; } .home-grid { grid-template-columns: 1fr; } }

/* ── Settings modal ── */
/* Player → Now Playing expand button */
.np-expand { background: var(--bg3); border: 1px solid var(--border); color: var(--dim); width: 32px; height: 32px; border-radius: 8px; font-size: 16px; line-height: 1; cursor: pointer; flex-shrink: 0; transition: color .15s ease, border-color .15s ease; }
.np-expand:hover { color: var(--text); border-color: var(--accent); }
/* Listening-together toggle: hides/shows the sync bar, but always carries the
   headcount so dismissing the bar never hides that others are listening. */
.sync-toggle { width: auto; min-width: 32px; padding: 0 7px; display: inline-flex; align-items: center; gap: 5px; color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
/* The display above is an AUTHOR rule, so it outranks the browser's
   [hidden] { display: none } — without this the button stays on screen showing 0
   when there's no session. Same trap as any hidden flex/grid element. */
.sync-toggle[hidden] { display: none; }
.sync-toggle .svi { width: 16px; height: 16px; }
.sync-toggle .sync-toggle-n { font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }
.sync-toggle.off { color: var(--dim); border-color: var(--border); }
.sync-toggle.off:hover { color: var(--text); }
/* "Up next" queue chip — appears in the bar while songs are queued */
.queue-chip { width: auto; padding: 0 10px; font-size: 13px; font-weight: 700; color: var(--accent); }
.queue-chip[hidden] { display: none; }
/* Queue dropdown — compact rows matching the normal track lists */
#queueMenu { min-width: 320px; max-width: 420px; }
#queueMenu .q-head { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--dim); padding: 4px 8px 8px; }
#queueMenu .q-rows { max-height: 50vh; overflow-y: auto; }
/* grip · # · art · title/artist · who queued it · length · remove */
#queueMenu .q-row { display: grid; grid-template-columns: 16px 18px 36px 1fr auto auto auto; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 8px; }
/* The slot is always present (empty when solo) so rows stay aligned with each other. */
#queueMenu .q-by { width: 22px; height: 22px; font-size: 9px; flex-shrink: 0; }
#queueMenu .q-by-none { width: 0; }
#queueMenu .q-row:hover { background: var(--bg3); }
#queueMenu .q-row.q-dragging { background: var(--bg3); opacity: .6; }
#queueMenu .q-grip { color: var(--mute); cursor: grab; font-size: 13px; text-align: center; touch-action: none; user-select: none; }
#queueMenu .q-n { color: var(--mute); font-size: 11px; text-align: right; font-variant-numeric: tabular-nums; }
#queueMenu .q-thumb { width: 36px; height: 36px; border-radius: 6px; object-fit: cover; background: var(--bg3); }
#queueMenu .q-meta { min-width: 0; }
#queueMenu .q-title { display: block; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#queueMenu .q-artist { display: block; font-size: 11px; color: var(--dim); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#queueMenu .q-dur { font-size: 11px; color: var(--dim); font-variant-numeric: tabular-nums; }
#queueMenu .q-x { background: none; border: none; color: var(--mute); font-size: 13px; padding: 5px 7px; border-radius: 6px; cursor: pointer; }
#queueMenu .q-x:hover { color: var(--danger); background: var(--bg2); }
#queueMenu .q-empty { padding: 12px 14px; color: var(--mute); font-size: 13px; }
/* Footer: where playback continues after the queue drains */
#queueMenu .q-foot:not(:empty) { margin-top: 6px; padding-top: 8px; border-top: 1px solid var(--border); }
#queueMenu .q-after-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--accent); padding: 2px 8px 4px; }
#queueMenu .q-after-row { grid-template-columns: 36px 1fr auto; opacity: .85; cursor: default; }
#queueMenu .q-after-row:hover { background: none; }
#queueMenu .q-after-end { padding: 2px 8px 6px; color: var(--mute); font-size: 12px; }

/* "Plays after the queue" marker on a list row — accent fades L→R, gone by mid */
.row.queue-resume { background: linear-gradient(to right, color-mix(in srgb, var(--accent) 28%, transparent), transparent 50%); }
.row .q-resume-tag { display: inline-block; margin-left: 8px; font-size: 10px; font-weight: 700; vertical-align: 1px; color: var(--bg); background: var(--accent); border-radius: 999px; padding: 1px 7px; white-space: nowrap; }
/* ── Now Playing fullscreen cover-flow (covers content; stops above the player bar) ── */
.npv { position: fixed; top: 0; left: 0; right: 0; bottom: var(--player-h, 96px); z-index: 150;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: radial-gradient(120% 90% at 50% 30%, color-mix(in srgb, var(--accent) 8%, var(--bg2)), var(--bg) 72%);
  padding: 28px 0 18px; animation: npvIn .22s ease; }
.npv[hidden] { display: none; }
@keyframes npvIn { from { opacity: 0; } to { opacity: 1; } }
.npv-close { position: absolute; top: 16px; right: 18px; width: 40px; height: 40px; border-radius: 10px; background: var(--bg3); border: 1px solid var(--border); color: var(--dim); font-size: 16px; cursor: pointer; z-index: 4; }
.npv-close:hover { color: var(--text); border-color: var(--accent); }
.npv-stage { position: relative; width: 100%; flex: 0 0 auto; height: calc(clamp(150px, 44vmin, 360px) + 90px); overflow: hidden; display: flex; align-items: center; }
.npv-strip { display: flex; align-items: center; transition: transform .62s cubic-bezier(.33,1,.68,1); will-change: transform; }
.npv-strip.no-anim { transition: none; }
.npv-cover { flex: 0 0 clamp(150px, 44vmin, 360px); height: clamp(150px, 44vmin, 360px); display: flex; align-items: center; justify-content: center;
  transform: scale(.64); transition: transform .62s cubic-bezier(.33,1,.68,1); cursor: pointer; }
.npv-cover.cur { transform: scale(1); }
/* The cover-flow fade lives on the artwork (not the whole cover) so the title/artist
   caption underneath keeps its own, more readable opacity. The fade + caption ease in
   sync with the slide so everything rolls forward together. */
.npv-cover .npv-art, .npv-cover .npv-noart { opacity: .28; transition: opacity .62s cubic-bezier(.33,1,.68,1); }
.npv-cap { transition: opacity .62s cubic-bezier(.33,1,.68,1); }
.npv-cover.cur .npv-art, .npv-cover.cur .npv-noart { opacity: 1; }
.npv-art, .npv-noart { width: 90%; height: 90%; border-radius: 16px; box-shadow: 0 26px 70px rgba(0,0,0,.6); }
.npv-art { overflow: hidden; } /* clips the zoomed letterbox-crop below to the rounded square */
.npv-art img { width: 100%; height: 100%; object-fit: cover; display: block; }
.npv-art img.ytbars { --npz: 1.34; transform: scale(var(--npz)); } /* 360/270 — crops the baked-in 4:3 letterbox bars */
.npv-noart { display: flex; align-items: center; justify-content: center; background: var(--bg3); color: var(--mute); font-size: 64px; }
/* Manual-queue covers woven into the strip get a loud badge + accent ring,
   and stay clearly brighter than ordinary neighbour covers. */
.npv-cover { position: relative; }
.npv-cover[data-kind="up"] .npv-art, .npv-cover[data-kind="up"] .npv-noart {
  opacity: .75; outline: 3px solid var(--accent); outline-offset: -3px;
  box-shadow: 0 26px 70px rgba(0,0,0,.6), 0 0 22px color-mix(in srgb, var(--accent) 45%, transparent);
}
/* Title + artist caption under each non-current cover (the current one uses .npv-meta). */
.npv-cap { position: absolute; top: calc(95% + 16px); left: 50%; transform: translateX(-50%); width: 90%; text-align: center; opacity: .5; pointer-events: none; }
.npv-cap-t { font-size: 16.5px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.npv-cap-a { font-size: 14px; color: var(--dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 3px; }
.npv-cover.cur .npv-cap { opacity: 0; } /* center already shows the big title/artist below the stage */
.npv-q { position: absolute; bottom: 9%; left: 50%; transform: translateX(-50%); z-index: 2;
  font-size: 14px; font-weight: 800; letter-spacing: .8px; text-transform: uppercase; white-space: nowrap;
  color: var(--bg); background: var(--accent); border-radius: 999px; padding: 5px 14px; pointer-events: none;
  box-shadow: 0 4px 14px rgba(0,0,0,.5), 0 0 16px color-mix(in srgb, var(--accent) 55%, transparent); }
.npv-q::before { content: '⏭ '; }
.npv-empty { color: var(--mute); font-size: 16px; padding: 40px; }
.npv-meta { text-align: center; margin-top: -14px; padding: 0 24px; max-width: 92vw; position: relative; } /* stage has 45px shadow padding below the cover — pull the text back under the image */
/* Track-swap text slide: real title/artist (direct children) come in from the
   side of the new song; a ghost copy of the old text fades out the other way. */
.npv-ghost { position: absolute; inset: 0; padding: 0 24px; pointer-events: none; }
.npv-ghost.to-left { animation: npvTxtOutL .5s ease forwards; }
.npv-ghost.to-right { animation: npvTxtOutR .5s ease forwards; }
.npv-meta.from-right > .npv-title, .npv-meta.from-right > .npv-artist { animation: npvTxtInR .5s ease backwards; }
.npv-meta.from-left > .npv-title, .npv-meta.from-left > .npv-artist { animation: npvTxtInL .5s ease backwards; }
@keyframes npvTxtOutL { to { opacity: 0; transform: translateX(-70px); } }
@keyframes npvTxtOutR { to { opacity: 0; transform: translateX(70px); } }
@keyframes npvTxtInR { from { opacity: 0; transform: translateX(70px); } }
@keyframes npvTxtInL { from { opacity: 0; transform: translateX(-70px); } }
.npv-title { font-size: 22px; font-weight: 800; color: var(--text); margin-bottom: 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.npv-artist { font-size: 14px; color: var(--dim); }
.npv-arrow { position: absolute; top: 50%; transform: translateY(-50%); z-index: 3; width: 46px; height: 46px; border-radius: 50%;
  background: color-mix(in srgb, var(--bg3) 80%, transparent); border: 1px solid var(--border); color: var(--text); font-size: 24px; line-height: 1; cursor: pointer; transition: background .15s ease, border-color .15s ease; }
.npv-arrow:hover { background: var(--bg3); border-color: var(--accent); }
.npv-prev { left: 24px; }
.npv-next { right: 24px; }
@media (max-width: 760px) { .npv-arrow { display: none; } .npv-title { font-size: 18px; } }

/* ── Browsing the cover-flow (peek) ──────────────────────────────────────────
   Drag / wheel / arrows move the strip without touching playback. */
.npv-stage { cursor: grab; touch-action: pan-y; }   /* horizontal is ours, vertical still scrolls */
.npv-stage.dragging { cursor: grabbing; }
.npv-stage.dragging .npv-cover { cursor: grabbing; }
/* ── Marking the playing track ───────────────────────────────────────────────
   ONE element parked above the playing cover, not a pseudo-element on each cover:
   it carries the same translate the strip does, so it GLIDES across as the
   playing track changes instead of jumping between nodes. Rule on top, label
   under it. */
.npv-mark { position: absolute; top: 6px; left: 50%; z-index: 4; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  transition: transform .62s cubic-bezier(.33, 1, .68, 1); will-change: transform; }
.npv-mark[hidden] { display: none; }
.npv-mark.no-anim { transition: none; }
.npv-mark-line { display: block; width: 108px; height: 3px; border-radius: 999px; background: var(--accent);
  box-shadow: 0 0 14px color-mix(in srgb, var(--accent) 70%, transparent); }
.npv-mark-txt { font-size: 10px; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; color: var(--accent); white-space: nowrap; }
.npv-cover.playing { cursor: default; }   /* clicking what's already playing does nothing */

/* ── Hover: play this one ────────────────────────────────────────────────────
   Covers have always been click-to-play; nothing said so. */
.npv-play {
  position: absolute; top: 50%; left: 50%; z-index: 3; pointer-events: none;
  width: 26%; height: 26%; max-width: 74px; max-height: 74px; min-width: 38px; min-height: 38px;
  display: flex; align-items: center; justify-content: center; border-radius: 50%;
  background: color-mix(in srgb, var(--bg) 55%, transparent); backdrop-filter: blur(6px);
  border: 2px solid #fff; color: #fff; box-shadow: 0 8px 26px rgba(0, 0, 0, .55);
  opacity: 0; transform: translate(-50%, -50%) scale(.82);
  transition: opacity .16s ease, transform .16s cubic-bezier(.34, 1.56, .64, 1);
}
.npv-play .svi { width: 46%; height: 46%; margin-left: 6%; }  /* optical centring of the triangle */
.npv-cover:not(.playing):hover .npv-play { opacity: 1; transform: translate(-50%, -50%) scale(1); }
/* Lift the artwork's cover-flow dimming on hover so the target reads clearly. */
.npv-cover:not(.playing):not(.cur):hover .npv-art, .npv-cover:not(.playing):not(.cur):hover .npv-noart { opacity: .92; }
.npv-cover:not(.playing):not(.cur):hover .npv-cap { opacity: .9; }
@media (hover: none) { .npv-play { display: none; } }  /* no hover state to reveal it */
/* While peeking the big title is a PREVIEW, not the now-playing line — dim it a
   touch so the two states aren't confusable at a glance. */
.npv.npv-peeking .npv-title { color: var(--dim); }
.npv-return { position: absolute; left: 50%; transform: translateX(-50%); bottom: calc(var(--player-h, 96px) + 16px); z-index: 5;
  display: inline-flex; align-items: center; gap: 7px; padding: 9px 16px; border-radius: 999px; cursor: pointer;
  font-size: 13px; font-weight: 700; color: var(--bg); background: var(--accent); border: 0;
  box-shadow: 0 8px 26px color-mix(in srgb, var(--accent) 40%, transparent); animation: npvRetIn .22s ease; }
.npv-return[hidden] { display: none; }
.npv-return .svi { width: 15px; height: 15px; }
.npv-return:hover { filter: brightness(1.08); }
@keyframes npvRetIn { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
/* While the Now Playing view is open (mobile only), the screen becomes a
   Spotify-style player: the view extends to the bottom edge and the player bar
   floats transparently on top of it — track info hidden (it's under the big
   cover), seekbar above big play/pause buttons, lifted off the screen bottom. */
@media (max-width: 760px) {
  body.npv-open .npv { bottom: 0; padding-bottom: calc(var(--player-h, 96px) + 8px); }
  body.npv-open .player { background: none; border-top: none; box-shadow: none; padding: 10px 22px 38px; }
  body.npv-open .player .np, body.npv-open .player .right { display: none; }
  body.npv-open .controls { flex-direction: column-reverse; gap: 18px; }
  body.npv-open .btns { gap: 28px; }
  body.npv-open .btns button { width: 50px; height: 50px; font-size: 24px; }
  body.npv-open .btns .play { width: 70px; height: 70px; font-size: 24px; }
  body.npv-open .player input[type=range] { height: 6px; }
  body.npv-open .seekrow { font-size: 12px; gap: 12px; }
}
/* With the Now Playing view open, lift the sync pill clear of the controls/track info */
body.npv-open #syncBar { bottom: calc(var(--player-h, 96px) + 64px); }
/* …and raise the player bar above the view (150) so its music-reactive bass glow
   (box-shadow radiating past its top edge) isn't painted under the npv. */
body.npv-open .player { position: relative; z-index: 160; }

/* Custom tooltip (replaces native title="") — floating, styled, smart-placed */
.tip { position: fixed; left: 0; top: 0; z-index: 9999; pointer-events: none; max-width: 260px;
  background: color-mix(in srgb, var(--bg2) 92%, var(--accent)); color: var(--text);
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border)); border-radius: 8px;
  padding: 6px 10px; font-size: 12px; line-height: 1.4; font-weight: 500; white-space: normal;
  box-shadow: 0 10px 30px rgba(0,0,0,.5); opacity: 0; transform: translateY(-3px);
  transition: opacity .12s ease, transform .12s ease; }
.tip.show { opacity: 1; transform: none; }
.tip::after { content: ''; position: absolute; left: var(--tip-arrow, 50%); transform: translateX(-50%);
  border: 5px solid transparent; }
.tip[data-placement="bottom"]::after { bottom: 100%; border-bottom-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.tip[data-placement="top"]::after { top: 100%; border-top-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }

.overlay { position: fixed; inset: 0; background: rgba(0,0,0,.6); backdrop-filter: blur(2px); display: flex; align-items: center; justify-content: center; z-index: 300; padding: 20px; animation: overlayIn .2s ease; }
@keyframes overlayIn { from { opacity: 0; } to { opacity: 1; } }
.overlay[hidden] { display: none; }
.modal { background: var(--bg2); border: 1px solid var(--border); border-radius: 14px; width: 420px; max-width: 100%; max-height: 85vh; overflow-y: auto; padding: 22px; box-shadow: 0 24px 70px rgba(0,0,0,.6); animation: dialogPop .2s ease; }
.modal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 18px; }
.modal-head h3 { font-size: 18px; font-weight: 700; }
.modal-section { margin-bottom: 18px; }
.modal-label { font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: var(--mute); font-weight: 700; margin-bottom: 10px; }

/* ── Settings modal: wider, with each section as a card; two columns on desktop ── */
.modal.settings-modal { width: min(94vw, 740px); padding: 22px 24px; }
.settings-modal .settings-body { margin-top: 4px; }
.settings-modal .modal-section { margin: 0 0 14px; padding: 14px 15px 12px; background: color-mix(in srgb, var(--text) 3%, var(--bg2)); border: 1px solid var(--border); border-radius: 12px; }
.settings-modal .modal-section > .modal-label:first-child { margin-top: 0; }
.settings-modal .modal-label { color: var(--accent); }
@media (min-width: 700px) {
  .settings-modal .settings-body { column-count: 2; column-gap: 16px; }
  .settings-modal .modal-section { break-inside: avoid; -webkit-column-break-inside: avoid; }
}
/* unified dialogs (alert/confirm/prompt) */
.dialog { width: 400px; } /* pop animation comes from .modal */
@keyframes dialogPop { from { opacity: 0; transform: translateY(8px) scale(.98); } to { opacity: 1; transform: none; } }
.dialog .modal-head { margin-bottom: 12px; }
.dialog-msg { font-size: 14px; color: var(--text); line-height: 1.5; margin-bottom: 16px; white-space: pre-wrap; word-break: break-word; }
/* loader dialog: centered spinner + message for multi-second operations */
.loader-dialog { text-align: center; }
.loader-spin { width: 34px; height: 34px; margin: 6px auto 14px; border: 3px solid color-mix(in srgb, var(--accent) 25%, transparent); border-top-color: var(--accent); border-radius: 50%; animation: spin .8s linear infinite; }
.loader-msg { margin-bottom: 0; text-align: center; }
/* progress bar (showProgress): determinate fill, or an indeterminate sweep when
   the phase length is unknown (e.g. spotdl reading a Spotify playlist) */
.progress-track { position: relative; height: 8px; margin: 16px 2px 2px; border-radius: 999px; background: var(--bg3); overflow: hidden; }
.progress-fill { height: 100%; width: 0; border-radius: 999px; background: var(--accent); transition: width .3s ease; }
.progress-track.indet .progress-fill { width: 38%; position: absolute; left: 0; animation: progIndet 1.1s ease-in-out infinite; transition: none; }
@keyframes progIndet { 0% { left: -40%; } 100% { left: 100%; } }
/* playlist stats modal */
.stats-box { display: flex; flex-direction: column; }
.stat-row { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; padding: 12px 4px; border-bottom: 1px solid var(--border); font-size: 14px; }
.stat-row:last-child { border-bottom: none; }
.stat-k { color: var(--dim); }
.stat-v { color: var(--text); font-weight: 700; text-align: right; }
.stat-note { color: var(--mute); font-weight: 400; font-size: 12px; }
.dialog-input { width: 100%; background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 8px; padding: 10px 12px; font-size: 14px; outline: none; margin-bottom: 18px; }
.dialog-input:focus { border-color: var(--accent); }
textarea.dialog-input { resize: vertical; min-height: 80px; font-family: inherit; line-height: 1.5; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 10px; flex-wrap: wrap; } /* wrap: an either/or dialog has three buttons */
/* Second affirmative choice (e.g. "Invite to mine") — reads as a real option, not a cancel. */
.dialog-actions .dlg-alt { border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); color: var(--accent); }
.dialog-actions .dlg-alt:hover { border-color: var(--accent); }
.dialog-actions button { background: var(--bg3); border: 1px solid var(--border); color: var(--text); border-radius: 8px; padding: 8px 16px; font-size: 13px; font-weight: 600; }
.dialog-actions button:hover { border-color: var(--accent); }
.dialog-actions .dlg-ok { background: var(--accent); color: var(--bg); border-color: transparent; }
.dialog-actions .dlg-ok:hover { filter: brightness(1.1); }
.dialog-actions .dlg-ok.danger { background: var(--danger); color: #fff; }

.theme-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.acct-link { display: inline-block; color: var(--accent2); text-decoration: none; font-size: 13px; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--bg3); }
.acct-link:hover { border-color: var(--accent); color: var(--text); }
.theme-option { display: flex; align-items: center; gap: 10px; padding: 9px 11px; background: var(--bg3); border: 1px solid var(--border); color: var(--text); border-radius: 8px; font-size: 13px; text-align: left; transition: all .15s ease; }
.theme-option:hover { border-color: var(--accent); }
.theme-option.active { border-color: var(--accent); box-shadow: inset 2px 0 0 var(--accent); }
.theme-option.active::after { content: '✓'; margin-left: auto; color: var(--accent); font-weight: bold; }
/* Mini "player tile" preview: the theme's bg with an accent album dot + a partly
   filled accent progress bar, so each option previews bg + accent at a glance. */
.theme-swatch { width: 38px; height: 27px; border-radius: 6px; background: var(--sw2); border: 1px solid rgba(255,255,255,.14); position: relative; overflow: hidden; flex-shrink: 0; }
.theme-swatch::before { content: ''; position: absolute; left: 5px; top: 5px; width: 9px; height: 9px; border-radius: 50%; background: var(--sw1); }
.theme-swatch::after { content: ''; position: absolute; left: 5px; right: 5px; bottom: 5px; height: 3px; border-radius: 2px; background: linear-gradient(90deg, var(--sw1) 0 55%, color-mix(in srgb, var(--sw1) 22%, var(--sw2)) 55% 100%); }
.theme-swatch.shiny { background: linear-gradient(150deg, color-mix(in srgb, var(--sw1) 16%, var(--sw2)), var(--sw2) 65%); }
/* Mixed-theme preview: album dot in hue A, progress bar blends hue A → hue B (--sw3). */
.theme-swatch.mix::before { background: var(--sw1); }
.theme-swatch.mix::after { background: linear-gradient(90deg, var(--sw1) 0 25%, var(--sw3) 70% 100%); }

/* ── Mobile drawer backdrop ── */
.backdrop { position: fixed; inset: 0; background: rgba(0,0,0,.5); z-index: 90; opacity: 0; pointer-events: none; transition: opacity .25s ease; }
.backdrop.show { opacity: 1; pointer-events: auto; }

/* ── Mobile layout ── */
@media (max-width: 760px) {
  #app { grid-template-columns: 1fr; grid-template-rows: 1fr auto; }
  .sb-resizer { display: none; }
  .main { grid-column: 1; grid-row: 1; }
  .player { grid-column: 1; grid-row: 2; }

  /* Sidebar becomes a swipeable off-canvas drawer */
  .sidebar { position: fixed; top: 0; left: 0; bottom: 0; width: 80%; max-width: 300px; z-index: 100; transform: translateX(-100%); transition: transform .28s ease; box-shadow: 0 0 40px rgba(0,0,0,.6); }
  .sidebar.open { transform: translateX(0); }

  .hamburger { display: flex; }
  .topbar { padding: 10px 12px; gap: 8px; grid-template-columns: auto minmax(0, 1fr) auto; }
  /* Search gets the full topbar width; the right-side extras go (the account
     chip stays — it's the only way to log in on mobile). */
  .search-wrap { max-width: none; }
  #searchInput { font-size: 16px; padding: 11px 16px; } /* ≥16px also stops iOS zooming in on focus */
  .content { padding: 16px 14px 24px; }
  .content h2 { font-size: 18px; }

  /* Tighter track rows */
  .row { gap: 8px; }
  /* Mobile "more" button: a bigger, round, borderless touch target (Material-style). */
  .row .acts .kebab { width: 40px; height: 40px; padding: 0; border: none; border-radius: 50%; color: var(--dim); }
  .row .acts .kebab:hover, .row .acts .kebab:active { background: var(--bg3); border: none; }
  .row .acts .kebab .svi { width: 22px; height: 22px; }
  /* The inline artist name is NOT tappable on mobile (too many mis-taps); use the
     row's ⋯ → "View artist" instead. Tapping it just plays the row like the rest. */
  .row .t-sub .artist-link { pointer-events: none; text-decoration: none; color: inherit; }

  /* Header actions wrap instead of overflowing (content clips overflow-x) */
  .pheader { gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
  .pheader h2 { flex-basis: 100%; font-size: 18px; }
  .pheader button, .sort-sel { padding: 7px 11px; font-size: 12px; }
  .pheader button.danger { margin-left: 0; } /* flow inline once wrapped, don't force to the far edge */
  .members { gap: 8px; }

  /* Player: now-playing + status on top row, controls span the bottom */
  .player { grid-template-columns: 1fr auto; grid-template-rows: auto auto; height: auto; padding: 8px 12px 10px; gap: 4px 10px; }
  .np { grid-column: 1; grid-row: 1; min-width: 0; }
  /* Shrink the ART BOX (the img fills it via inset:0) — sizing only the img left
     it 42px inside a 54px box, with the placeholder peeking out on two edges. */
  .np-art { width: 42px; height: 42px; }
  .right { grid-column: 2; grid-row: 1; gap: 8px; } /* tighter — the sync toggle is a 5th item up here */
  .volwrap { display: none; }
  .controls { grid-column: 1 / -1; grid-row: 2; }
  .seekrow { max-width: none; }

  .modal { width: 100%; }
}

/* Hidden YouTube IFrame player — offscreen (not display:none, which can throttle playback) */
#ytWrap { position: fixed; left: -9999px; top: 0; width: 320px; height: 180px; pointer-events: none; opacity: 0; }
/* "🎬 Video" in the Now Playing view: the SAME wrap, CSS-positioned over the
   stage (inline coords from JS). Never re-parented — that would reload the iframe. */
#ytWrap.npv-live { border-radius: 14px; overflow: hidden; background: #000;
  border: 1.5px solid color-mix(in srgb, var(--accent) 60%, var(--border));
  box-shadow: 0 18px 52px rgba(0,0,0,.65), 0 0 26px color-mix(in srgb, var(--accent) 22%, transparent);
  z-index: 152; }
#ytWrap.npv-live iframe { width: 100% !important; height: 100% !important; display: block; }
/* Same easing/duration as .npv-strip so the video and the covers move as one. */
#ytWrap.npv-live { transition: transform .62s cubic-bezier(.33, 1, .68, 1); will-change: transform; }
#ytWrap.npv-live.no-anim { transition: none; }
#ytWrap.be-yt #scPlayer { display: none; }
/* ── Theatre: the video fills the Now Playing area ────────────────────────────
   Deliberately NOT browser fullscreen — that would cover the player bar too, and
   with the YouTube player at controls:0 there'd be nothing left to pause or seek
   with. The area already ends above the bar, so the transport stays usable. */
.npv.theatre .npv-stage, .npv.theatre .npv-meta, .npv.theatre .npv-arrow,
.npv.theatre .npv-mark, .npv.theatre .npv-return { visibility: hidden; }
.npv.theatre { background: var(--bg); }
.npv-fs-btn { position: absolute; top: 64px; right: 18px; z-index: 4; width: 38px; height: 38px; border-radius: 10px;
  background: var(--bg2); border: 1px solid var(--border); color: var(--dim); cursor: pointer; font-size: 15px; }
.npv-fs-btn:hover { color: var(--text); border-color: var(--accent); }
.npv-fs-btn[hidden] { display: none; }
.npv.theatre .npv-fs-btn { z-index: 155; background: rgba(0, 0, 0, .5); border-color: rgba(255, 255, 255, .22); color: #fff; }
#ytWrap.be-sc #ytPlayer { display: none; }
/* Video mode keeps the cover-flow: only the CENTRE cover yields to the video —
   the neighbouring covers stay peeking out on both sides (and stay clickable,
   since the video wrap passes pointer events through). --vid-gap (set from JS,
   half the video's overhang) spreads the covers clear of the video. */
/* Hide the artwork of the cover the VIDEO sits on — not whatever happens to be
   centred. Since browsing arrived those differ: scrolling another song into the
   middle was blanking its art and caption while the video had moved away. */
.npv.video-mode .npv-cover.playing .npv-art, .npv.video-mode .npv-cover.playing .npv-noart { opacity: 0; }
/* Hide the video's caption only while it's CENTRED (the big .npv-meta names it
   there). Slid off to one side it needs its own label like any other cover. */
.npv.video-mode .npv-cover.playing.cur .npv-cap { opacity: 0; }
.npv.video-mode .npv-cover.playing:not(.cur) .npv-cap { opacity: .85; }
/* A non-playing cover in the middle is a normal cover again: full art, and its
   caption stays hidden only because .npv-meta below already names it. */
.npv.video-mode .npv-cover.cur:not(.playing) .npv-art, .npv.video-mode .npv-cover.cur:not(.playing) .npv-noart { opacity: 1; }
/* Only the slot the VIDEO occupies needs widening — a 16:9 embed is wider than
   the square cover it replaces, so its neighbours have to clear it. Every other
   cover keeps the normal covers-only spacing; applying this to all of them spread
   the whole strip out for no reason. */
.npv.video-mode .npv-cover.playing { margin: 0 var(--vid-gap, 90px); }
.npv.video-mode .npv-meta { margin-top: 6px; } /* don't pull the text up under the video */
.npv-video-btn { position: absolute; top: 16px; left: 18px; z-index: 4; padding: 9px 14px; border-radius: 10px;
  background: var(--bg3); border: 1px solid var(--border); color: var(--dim); font-size: 13px; cursor: pointer;
  transition: color .15s ease, border-color .15s ease; }
.npv-video-btn:hover { color: var(--text); border-color: var(--accent); }
.npv-video-btn[hidden] { display: none; }
/* Queue chip inside the Now Playing view (the bar's chip is hidden there on mobile) */
.npv-queue-btn { position: absolute; top: 64px; left: 18px; z-index: 4; padding: 9px 14px; border-radius: 10px;
  background: var(--bg3); border: 1px solid var(--border); color: var(--accent); font-size: 13px; font-weight: 700; cursor: pointer;
  transition: color .15s ease, border-color .15s ease; }
.npv-queue-btn:hover { border-color: var(--accent); }
.npv-queue-btn[hidden] { display: none; }

/* "Download all songs" toggle in the playlist header */
/* "Download all" pill toggle — styled switch around a visually-hidden checkbox */
.dl-toggle { display: inline-flex; align-items: center; gap: 9px; font-size: 13px; color: var(--dim); cursor: pointer; user-select: none; padding: 5px 13px 5px 9px; border: 1px solid var(--border); border-radius: 999px; background: var(--bg3); transition: border-color .15s ease, color .15s ease, background .15s ease; }
.dl-toggle:hover { color: var(--text); border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); }
.dl-toggle input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.dl-switch { position: relative; width: 34px; height: 19px; border-radius: 999px; background: color-mix(in srgb, var(--text) 22%, transparent); transition: background .2s ease; flex-shrink: 0; }
.dl-knob { position: absolute; top: 2px; left: 2px; width: 15px; height: 15px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.45); transition: transform .2s ease; }
.dl-toggle input:checked ~ .dl-switch { background: var(--accent); }
.dl-toggle input:checked ~ .dl-switch .dl-knob { transform: translateX(15px); }
.dl-toggle:has(input:checked) { color: var(--text); border-color: color-mix(in srgb, var(--accent) 55%, var(--border)); background: color-mix(in srgb, var(--accent) 12%, var(--bg3)); }
.dl-toggle:has(input:checked) .dl-toggle-label { color: var(--accent); font-weight: 600; }
.dl-toggle input:focus-visible ~ .dl-switch { outline: 2px solid var(--accent); outline-offset: 2px; }
.dl-toggle-label { white-space: nowrap; }

/* Settings: music-responsive toggles */
.exp-badge { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .5px; color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border)); border-radius: 999px; padding: 1px 7px; margin-left: 6px; vertical-align: middle; }
.modal-hint { font-size: 12px; color: var(--mute); line-height: 1.5; margin: -2px 0 10px; }
.mr-toggle { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 2px; cursor: pointer; font-size: 14px; color: var(--text); border-bottom: 1px solid var(--border); user-select: none; }
.mr-toggle:last-of-type { border-bottom: none; }
.mr-toggle input { position: absolute; opacity: 0; width: 0; height: 0; pointer-events: none; }
.mr-toggle input:checked ~ .dl-switch { background: var(--accent); }
.mr-toggle input:checked ~ .dl-switch .dl-knob { transform: translateX(15px); }
.mr-toggle input:focus-visible ~ .dl-switch { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Music-responsive effects — driven by --mr-level/--mr-bass/--mr-treble (0..1),
   set by the analyser loop in app.js; default to 0 when idle/disabled. */
/* Loudness — album art pulse + play-button & seek-thumb glow */
/* PERF: all per-frame effects below are compositor-only (transform/opacity on
   their own layers via will-change) — animating box-shadow/filter instead
   forced large CPU repaints every frame and dragged the whole UI down. */
body.mr-loud .np img { transform: scale(calc(var(--npz, 1) * (1 + var(--mr-bass-abs, 0) * 0.22))); transform-origin: center; transition: transform .04s linear; will-change: transform; } /* cover bump = ABSOLUTE bass level (fixed, not auto-ranged); --npz keeps the YT letterbox crop */
/* …and the big cover in the Now Playing view pulses the same way (zooms inside
   its clipped rounded square; --npz preserves the YT letterbox crop) */
body.mr-loud .npv-cover.cur .npv-art img { transform: scale(calc(var(--npz, 1) * (1 + var(--mr-bass-abs, 0) * 0.22))); transform-origin: center; transition: transform .04s linear; will-change: transform; }
/* Play-button glow: a pre-painted radial halo faded with opacity (GPU), not a box-shadow */
.btns .play::before { content: ''; position: absolute; inset: -16px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 55%, transparent), transparent 68%);
  opacity: 0; will-change: opacity; }
body.mr-loud .btns .play::before { opacity: var(--mr-level, 0); }

/* Bass — player bar glow: pre-painted gradient sheet above the bar, faded with
   opacity (snaps, no transition). Replaces the old per-frame box-shadow. */
.player-glow { position: absolute; left: 0; right: 0; bottom: 100%; height: 90px; pointer-events: none; opacity: 0;
  background: linear-gradient(to top, color-mix(in srgb, var(--accent) 50%, transparent), transparent 72%);
  will-change: opacity; }
body.mr-bass .player-glow { opacity: calc(var(--mr-bass, 0) * 1.15); }

/* Spectrum ribbon — a live EQ across the top edge of the window. Bars hang down
   from the top; heights are set per-frame in JS. pointer-events:none so it never
   blocks the topbar underneath. */
#mrSpectrum { position: fixed; left: 0; right: 0; top: 0; height: 44px; display: none; align-items: flex-start; gap: 2px; padding: 0 6px; pointer-events: none; z-index: 155; opacity: .6; }
#mrSpectrum.show { display: flex; }
#mrSpectrum i { flex: 1 1 0; height: 100%; transform: scaleY(0); transform-origin: top; border-radius: 0 0 3px 3px; background: linear-gradient(to bottom, var(--accent), color-mix(in srgb, var(--accent) 10%, transparent)); will-change: transform; }
/* Bottom placement — the ribbon is INSIDE .player (JS reparents it), absolutely
   anchored to the bar's top edge, so it follows the bar through any layout or
   transform change with no measured offset. */
#mrSpectrum.pos-bottom { position: absolute; top: auto; bottom: 100%; left: 0; right: 0; align-items: flex-end; }
#mrSpectrum.pos-bottom i { transform-origin: bottom; border-radius: 3px 3px 0 0; background: linear-gradient(to top, var(--accent), color-mix(in srgb, var(--accent) 10%, transparent)); }
/* Settings sub-option row (e.g. ribbon position) */
.mr-suboption { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 2px 8px 6px; font-size: 13px; color: var(--dim); }

/* Full-screen bump — the whole UI scales up with the bass envelope (zooms out
   on a hit, settles back). Scale UP only so no background gaps show at the edges.
   Scales BODY (not #app) so the fixed overlays outside #app — Now Playing view,
   spectrum ribbon, sync pill — bump together with the player bar; scaling only
   #app made the EQ bars and the npv visibly detach from the bar on every hit. */
body.mr-bump { transform: scale(calc(1 + var(--mr-bass-abs, 0) * 0.03)); transform-origin: center center; transition: transform .05s linear; will-change: transform; }
#scPlayer { width: 320px; height: 166px; border: 0; }

/* ── Group view: two-column layout with chat on the right ── */
.group-layout { display: flex; gap: 18px; height: 100%; }
.group-main { flex: 1; min-width: 0; overflow-y: auto; padding-right: 4px; }
/* min-width:0 is load-bearing: a flex item won't shrink below its MIN-CONTENT
   width by default, and a long nowrap song title in a member row contributes its
   full length — clipping it visually doesn't change that. Without this the panel
   (and the dock) stretch to fit the title and squeeze everything else. */
.group-chat { position: relative; width: 320px; min-width: 0; flex-shrink: 0; display: flex; flex-direction: column; border-left: 1px solid var(--border); min-height: 0; transition: width .18s ease; }
/* Collapse / expand handle — top-right of the panel; recentres when collapsed. */
.gc-collapse { position: absolute; top: 0; right: 0; z-index: 2; width: 28px; height: 28px; display: flex; align-items: center; justify-content: center; background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; color: var(--dim); cursor: pointer; transition: color .15s ease, border-color .15s ease, transform .18s ease; }
.gc-collapse:hover { color: var(--text); border-color: var(--accent); }
/* Pin the Members/Chat panel to the right edge of the app, playlist-sidebar style. */
/* Sits in the tab row, left of "Members". */
.gc-pin { flex: 0 0 auto; width: 30px; height: 30px; align-self: center;
  display: flex; align-items: center; justify-content: center; background: none;
  border: 1px solid transparent; border-radius: 8px; color: var(--mute); cursor: pointer;
  transition: color .15s ease, border-color .15s ease, background .15s ease; }
.gc-pin:hover { background: var(--bg3); }
.gc-pin:hover { color: var(--text); border-color: var(--accent); }
.gc-pin.on { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 55%, transparent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.gc-pin .svi { width: 15px; height: 15px; }
/* Lives INSIDE the main view, beside the content and below the top bar — so
   pinning never narrows the bar (which was shoving the settings button inward).
   The panel keeps its own group-view styling; the dock only sets the width. */
.main-body { flex: 1; min-height: 0; display: flex; }
.main-body > .content { min-width: 0; }
.gc-dock { position: relative; flex: 0 0 var(--gc-w, 320px); min-width: 0; min-height: 0; display: flex; transition: flex-basis .18s ease; }
.gc-dock[hidden] { display: none; }
.gc-dock .group-chat { width: 100%; min-width: 0; }
/* Collapsed: the column shrinks with the panel (it used to stay full width, so
   collapsing looked like it did nothing), and there's nothing left to resize. */
.gc-dock.collapsed { flex-basis: 56px; }
.gc-dock.collapsed .gc-resizer { display: none; }
/* Draggable edge, mirroring the playlist sidebar's handle. */
.gc-resizer { position: absolute; top: 0; bottom: 0; left: 0; width: 9px; transform: translateX(-5px);
  z-index: 60; cursor: col-resize; touch-action: none; }
.gc-resizer::after { content: ''; position: absolute; inset: 0 4px; background: transparent; transition: background .15s ease; }
.gc-resizer:hover::after, .gc-resizer.dragging::after { background: var(--accent); }
/* Not enough width on a phone/tablet — fall back to the in-page panel. */
@media (max-width: 1100px) { .gc-dock { display: none; } }
.gc-collapse .svi { width: 16px; height: 16px; }
.group-chat .gc-tabs { padding-right: 34px; } /* leave room for the handle */

/* Collapsed: a slim strip showing only member avatars. */
.group-chat.collapsed { width: 56px; }
.group-chat.collapsed .gc-tabs,
.group-chat.collapsed .gc-mem-head,
.group-chat.collapsed .gc-panel-chat { display: none; }
.group-chat.collapsed .gc-collapse { right: 50%; transform: translateX(50%) rotate(180deg); top: 2px; }

.group-chat.collapsed .gc-panel-members { padding-top: 38px; } /* clear the handle */
.group-chat.collapsed .gc-mem-list { gap: 4px; }
.group-chat.collapsed .gc-mem { justify-content: center; padding: 4px 0; gap: 0; }
.group-chat.collapsed .gc-mem-info,
.group-chat.collapsed .gc-mem .member-sync,
.group-chat.collapsed .gc-mem .member-x { display: none; }
.group-chat.collapsed .gc-mem .member-avwrap { margin: 0; }
.chat-head { font-size: 13px; font-weight: 700; color: var(--text); padding: 4px 12px 10px; border-bottom: 1px solid var(--border); }
.chat-msgs { flex: 1; min-height: 0; overflow-y: auto; padding: 12px; display: flex; flex-direction: column; gap: 10px; }
.chat-msg { display: flex; gap: 8px; align-items: flex-start; }
.chat-av { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex-shrink: 0; background: var(--bg3); }
.chat-bubble { background: var(--bg2); border: 1px solid var(--border); border-radius: 10px; padding: 6px 10px; min-width: 0; }
.chat-meta { display: flex; gap: 8px; align-items: baseline; margin-bottom: 2px; }
.chat-user { font-size: 12px; font-weight: 700; color: var(--text); }
.chat-time { font-size: 10px; color: var(--dim); }
.chat-body { font-size: 13px; color: var(--text); white-space: pre-wrap; word-break: break-word; line-height: 1.4; }
.chat-msg.mine { flex-direction: row-reverse; }
.chat-msg.mine .chat-bubble { border-color: var(--accent); background: var(--bg3); }
.chat-input { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); }
.chat-input input { flex: 1; min-width: 0; background: var(--bg2); border: 1px solid var(--border); color: var(--text); border-radius: 999px; padding: 8px 14px; font-size: 13px; outline: none; }
.chat-input input:focus { border-color: var(--accent); }
.chat-input button { flex-shrink: 0; background: var(--accent); color: #06120a; border: none; border-radius: 50%; width: 36px; height: 36px; font-size: 14px; cursor: pointer; }

/* Themed scrollbars for the app's scroll areas (mostly visible on desktop;
   phones use transient overlay bars). Firefox via scrollbar-*, WebKit via
   ::-webkit-scrollbar. The thumb is a translucent pill that accents on hover. */
.chat-msgs, .content, .sidebar, .menu, .search-panel, .modal { scrollbar-width: thin; scrollbar-color: color-mix(in srgb, var(--text) 24%, transparent) transparent; }
.chat-msgs::-webkit-scrollbar, .content::-webkit-scrollbar, .sidebar::-webkit-scrollbar, .menu::-webkit-scrollbar, .search-panel::-webkit-scrollbar, .modal::-webkit-scrollbar { width: 10px; height: 10px; }
.chat-msgs::-webkit-scrollbar-track, .content::-webkit-scrollbar-track, .sidebar::-webkit-scrollbar-track, .menu::-webkit-scrollbar-track, .search-panel::-webkit-scrollbar-track, .modal::-webkit-scrollbar-track { background: transparent; }
.chat-msgs::-webkit-scrollbar-thumb, .content::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb, .menu::-webkit-scrollbar-thumb, .search-panel::-webkit-scrollbar-thumb, .modal::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--text) 22%, transparent);
  border-radius: 999px; border: 2px solid transparent; background-clip: padding-box;
}
.chat-msgs::-webkit-scrollbar-thumb:hover, .content::-webkit-scrollbar-thumb:hover, .sidebar::-webkit-scrollbar-thumb:hover, .menu::-webkit-scrollbar-thumb:hover, .search-panel::-webkit-scrollbar-thumb:hover, .modal::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, var(--accent) 65%, var(--text)); background-clip: padding-box;
}

/* Group/Chat tab switch — only shown on narrow screens (see media query). */
.group-tabs { display: none; }
.gtab { flex: 1; padding: 10px; background: var(--bg3); border: 1px solid var(--border); border-radius: 9px; color: var(--dim); font-weight: 600; font-size: 13px; }
.gtab.active { background: var(--accent); color: var(--bg); border-color: transparent; }
.gtab .tab-dot { display: none; width: 7px; height: 7px; border-radius: 50%; background: var(--accent2, #4ea1ff); margin-left: 6px; vertical-align: middle; }
.gtab.has-unread .tab-dot { display: inline-block; }
.gtab.active .tab-dot { display: none; }
@media (max-width: 820px) {
  /* One full-height panel at a time (no nested page scroll), toggled by the tabs. */
  .group-tabs { display: flex; gap: 8px; margin-bottom: 12px; flex-shrink: 0; }
  .group-layout { flex-direction: column; gap: 0; height: 100%; min-height: 0; }
  .group-main { overflow-y: auto; min-height: 0; padding-right: 0; flex: 1; }
  .group-chat { width: auto; border-left: none; border-top: none; min-height: 0; flex: 1; }
  .group-layout.tab-main .group-chat { display: none; }
  .group-layout.tab-side .group-main { display: none; }
  /* Mobile: the top Group/Members/Chat tabs drive the panel, so hide the in-aside tab row. */
  .gc-tabs { display: none; }
  /* Collapse is a desktop affordance — full-width tabbed panel on mobile ignores it. */
  .gc-collapse { display: none; }
  .group-chat.collapsed { width: auto; }
  .group-chat.collapsed .gc-mem-head { display: flex; }
  .group-chat.collapsed .gc-panel-chat.active { display: flex; }
  .group-chat.collapsed .gc-panel-members { padding-top: 0; }
  .group-chat.collapsed .gc-mem { justify-content: flex-start; padding: 5px 6px 5px 12px; gap: 9px; }
  .group-chat.collapsed .gc-mem-info { display: block; }
  .group-chat.collapsed .gc-mem .member-sync, .group-chat.collapsed .gc-mem .member-x { display: inline-flex; }
}

/* Unread group-chat bubble on the sidebar — sits at the far right (the "live"
   listening beacon is now an absolutely-positioned ball on the cover, so the two
   never collide). */
.list li .unread-badge { margin-left: auto; flex-shrink: 0; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--accent); color: #06120a; font-size: 11px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }

/* "Downloaded to server" indicator on track rows */
.dl-icon { color: var(--accent); font-size: 15px; line-height: 1; font-weight: 700; opacity: .9; flex-shrink: 0; cursor: default; }

/* "Friend is listening" avatar on a track row: profile image + listening animation */
.listeners .avatar { position: relative; overflow: visible; }
.listeners .avatar:not(:first-child) { margin-left: -5px; }
.listeners .avatar .avatar-init { position: relative; z-index: 0; }
.listeners .avatar .avatar-img { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: 50%; object-fit: cover; z-index: 1; }
.listeners .avatar.listening { animation: listenerPulse 1.5s ease-out infinite; }
.listeners .avatar.travel { z-index: 6; } /* above neighbouring rows while gliding to a new song */
@keyframes listenerPulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent); } 70% { box-shadow: 0 0 0 6px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }
.listeners .avatar .eq { position: absolute; right: -3px; bottom: -3px; z-index: 2; display: flex; align-items: flex-end; gap: 1px; height: 10px; padding: 1px 2px; background: var(--sidebar-bg); border-radius: 4px; }
.listeners .avatar .eq i { width: 2px; height: 3px; background: var(--accent); border-radius: 1px; animation: eqBar .9s ease-in-out infinite; }
.listeners .avatar .eq i:nth-child(2) { animation-delay: .3s; }
.listeners .avatar .eq i:nth-child(3) { animation-delay: .15s; }
@keyframes eqBar { 0%, 100% { height: 3px; } 50% { height: 9px; } }

/* Listener avatar sits right next to the song title (not pushed to the far right),
   and a bit bigger so the profile picture reads clearly. */
.t-meta .t-text { flex: 0 1 auto; }
.listeners .avatar { width: 28px; height: 28px; font-size: 11px; }

.menu button[disabled] { opacity: .5; cursor: default; }
/* Add-to-playlist rows are checkboxes: tick = the song is in that list, click
   toggles it either way. */
.menu button.pl-pick { display: flex; align-items: center; gap: 8px; }
.menu .pl-check { flex: 0 0 16px; width: 16px; height: 16px; border: 1.5px solid var(--border); border-radius: 4px;
  display: inline-flex; align-items: center; justify-content: center; font-size: 11px; line-height: 1; color: transparent; transition: background .12s ease, border-color .12s ease, color .12s ease; }
.menu button.pl-pick.in-list .pl-check { background: var(--accent); border-color: var(--accent); color: var(--bg); }
.menu button.pl-pick.in-list { color: var(--text); }
/* Cover art in the add-to-playlist list — the same collage/cover the sidebar
   shows, scaled to menu size. */
.menu .pl-pick .cover { flex: 0 0 26px; width: 26px; height: 26px; border-radius: 5px; font-size: 12px; }
.menu .pl-pick-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 760px) { .menu .pl-pick .cover { flex-basis: 34px; width: 34px; height: 34px; border-radius: 6px; font-size: 15px; } }
@media (max-width: 760px) { .menu .pl-check { flex-basis: 20px; width: 20px; height: 20px; font-size: 13px; } }

/* In the group view, let the shared-playlist title shrink so the listener bubble
   sits right next to it (not pushed to the far-right corner). */
.group-main .list li .li-text { flex: 0 1 auto; }
.group-main .list li .listeners { margin-left: 4px; }

/* Download-state indicator now lives next to the song title — keep it from being squished. */
.t-meta .pill, .t-meta .dl-icon { flex-shrink: 0; }

/* Group member count on the right of the sidebar entry: person icon + number */
.list li .member-count { margin-left: auto; flex-shrink: 0; display: inline-flex; align-items: center; gap: 3px; font-size: 11px; color: var(--mute); }
.list li:hover .member-count, .list li.active .member-count { color: var(--dim); }
.list li .member-count svg { opacity: .85; }

/* ── "Discord music" panel (group view) ─────────────────────────────────────── */
.discord-card { margin: 4px 0 18px; padding: 14px 16px; background: linear-gradient(180deg, var(--bg2), var(--bg2) 60%, var(--bg)); border: 1px solid var(--border); border-radius: 14px; }
.discord-card:empty { display: none; }
.dc-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.dc-title { font-weight: 700; font-size: 15px; color: var(--text); }
.dc-vc { font-size: 12px; color: var(--dim); background: var(--bg3); padding: 2px 8px; border-radius: 999px; }
.dc-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--mute); flex-shrink: 0; }
.dc-dot.on { background: var(--accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent); }
.dc-x { margin-left: auto; background: none; border: 1px solid var(--border); color: var(--mute); border-radius: 8px; width: 24px; height: 24px; cursor: pointer; }
.dc-x:hover { color: var(--danger); border-color: var(--danger); }
.dc-sub { font-size: 13px; margin: 4px 0 10px; }
.dc-btn { padding: 7px 13px; font-size: 13px; font-weight: 600; color: var(--text); background: var(--bg3); border: 1px solid var(--border); border-radius: 9px; cursor: pointer; transition: border-color .15s, background .15s; }
.dc-btn:hover { border-color: var(--accent); }
.dc-btn.dc-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.dc-btn.dc-primary:hover { filter: brightness(1.08); }
.dc-btn.dc-sm { padding: 5px 10px; font-size: 12px; }
.dc-picker { display: flex; flex-wrap: wrap; gap: 8px; }
.dc-pick { background: var(--bg3); }

/* compact bot strip */
.dc-strip-now { display: flex; align-items: center; gap: 8px; font-size: 14px; margin: 4px 0 10px; min-width: 0; }
.dc-strip-state { flex-shrink: 0; }
.dc-strip-title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dc-strip-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dc-strip-actions .dc-sub { margin: 0; }

/* now playing */
.dc-now { display: flex; gap: 12px; align-items: center; padding: 8px 0; }
.dc-now.dc-idle { opacity: .85; }
.dc-thumb { width: 56px; height: 56px; border-radius: 8px; object-fit: cover; flex-shrink: 0; background: var(--bg3); }
.dc-thumb.dc-noimg { display: flex; align-items: center; justify-content: center; font-size: 22px; color: var(--mute); }
.dc-meta { min-width: 0; flex: 1; }
.dc-track { font-weight: 600; font-size: 14px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dc-by { font-size: 12px; margin-top: 2px; }
.dc-prog { display: flex; align-items: center; gap: 8px; margin-top: 7px; }
/* Click or drag to seek the bot. The padding is a fat hit area for a bar that
   still LOOKS 5px tall (background-clip keeps the paint in the content box); the
   matching negative margin keeps the row's layout height unchanged. */
.dc-prog-bar { flex: 1; height: 17px; padding: 6px 0; margin: -6px 0; background: var(--bg3); background-clip: content-box; border-radius: 999px; cursor: pointer; touch-action: none; }
.dc-prog-fill { position: relative; height: 100%; width: 0; background: var(--accent); border-radius: 999px; transition: width .5s linear; }
.dc-prog-bar.seeking .dc-prog-fill { transition: none; } /* the fill must track the pointer, not trail it */
.dc-prog-fill::after { content: ''; position: absolute; right: 0; top: 50%; width: 10px; height: 10px; margin-top: -5px; border-radius: 50%; background: var(--accent); opacity: 0; transition: opacity .12s ease; }
.dc-prog-bar:hover .dc-prog-fill::after, .dc-prog-bar.seeking .dc-prog-fill::after { opacity: 1; }
.dc-prog-time { font-size: 11px; color: var(--mute); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.dc-listen { flex-shrink: 0; align-self: center; padding: 7px 11px; font-size: 13px; font-weight: 600; color: var(--text); background: var(--bg3); border: 1px solid var(--border); border-radius: 999px; cursor: pointer; white-space: nowrap; transition: border-color .15s, background .15s, color .15s; }

/* Bot mini-player — docked bottom-left, above the player bar, under the sidebar */
#botMini { position: fixed; left: 10px; bottom: calc(var(--player-h, 96px) + 8px); width: 230px; max-width: calc(100vw - 20px); z-index: 60;
  background: var(--bg2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 11px;
  box-shadow: 0 10px 30px rgba(0,0,0,.5); display: none; }
#botMini.show { display: block; animation: bmIn .18s ease; }
#botMini.drop { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent), 0 10px 30px rgba(0,0,0,.5); }
@keyframes bmIn { from { opacity: 0; transform: translateY(8px); } }
.bm-row { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
.bm-ic { font-size: 14px; flex-shrink: 0; }
.bm-title { flex: 1; min-width: 0; font-size: 12px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bm-btn { display: inline-flex; align-items: center; justify-content: center; background: none; border: none; color: var(--dim); cursor: pointer; line-height: 1; padding: 2px 3px; flex-shrink: 0; }
.bm-btn .svi { width: 14px; height: 14px; }
.bm-btn:hover { color: var(--text); }
.bm-btn:hover { color: var(--text); }
.bm-prog { display: flex; align-items: center; gap: 7px; margin-bottom: 9px; }
.bm-bar { flex: 1; height: 16px; padding: 6px 0; margin: -6px 0; background: var(--bg3); background-clip: content-box; border-radius: 999px; cursor: pointer; touch-action: none; }
.bm-fill { position: relative; height: 100%; width: 0; background: var(--accent); border-radius: 999px; transition: width .5s linear; }
.bm-bar.seeking .bm-fill { transition: none; }
.bm-fill::after { content: ''; position: absolute; right: 0; top: 50%; width: 9px; height: 9px; margin-top: -4.5px; border-radius: 50%; background: var(--accent); opacity: 0; transition: opacity .12s ease; }
.bm-bar:hover .bm-fill::after, .bm-bar.seeking .bm-fill::after { opacity: 1; }
.bm-time { font-size: 10px; color: var(--mute); font-variant-numeric: tabular-nums; flex-shrink: 0; }
.bm-ctl { display: flex; gap: 8px; justify-content: center; }
.bm-cbtn { display: inline-flex; align-items: center; justify-content: center; background: var(--bg3); border: 1px solid var(--border); color: var(--text); border-radius: 7px; padding: 5px 16px; cursor: pointer; transition: border-color .15s ease, background .15s ease; }
.bm-cbtn .svi { width: 15px; height: 15px; }
.bm-cbtn:hover { border-color: var(--accent); }
/* Toasts go edge-to-edge on a phone rather than a narrow card floating right. */
@media (max-width: 760px) {
  #toasts { left: 10px; right: 10px; bottom: calc(var(--player-h, 96px) + 10px); }
  #toasts .toast { max-width: none; }
}
.dc-listen:hover { border-color: var(--accent); }
.dc-listen.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.dc-more { font-size: 13px; }

/* transport */
.dc-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 6px 0 4px; }
.dc-cbtn { width: 34px; height: 34px; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; background: var(--bg3); border: 1px solid var(--border); border-radius: 8px; color: var(--text); cursor: pointer; transition: border-color .15s, background .15s; }
.dc-cbtn:hover { border-color: var(--accent); }
.dc-cbtn.on { border-color: var(--accent); color: var(--accent); }
.dc-vol { display: inline-flex; align-items: center; gap: 4px; margin-left: 4px; }
.dc-adv { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; padding-left: 8px; margin-left: 4px; border-left: 1px solid var(--border); }
.dc-volval { font-size: 12px; color: var(--dim); min-width: 34px; text-align: center; font-variant-numeric: tabular-nums; }

/* queue */
.dc-queue { margin-top: 6px; }
.dc-qhead { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; margin: 8px 0 4px; }
.dc-qitem { display: flex; align-items: center; gap: 8px; padding: 5px 8px; border-radius: 7px; }
.dc-qitem:hover { background: var(--bg3); }
.dc-qn { width: 18px; text-align: right; color: var(--mute); font-size: 12px; flex-shrink: 0; }
.dc-qt { flex: 1; min-width: 0; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dc-qdur { font-size: 11px; flex-shrink: 0; }
.dc-qbtns { display: flex; gap: 2px; flex-shrink: 0; opacity: 0; transition: opacity .12s; }
.dc-qitem:hover .dc-qbtns { opacity: 1; }
.dc-qx { width: 22px; height: 22px; background: none; border: 0; color: var(--mute); cursor: pointer; border-radius: 5px; font-size: 11px; }
.dc-qx:hover { color: var(--text); background: var(--bg2); }
.dc-qx:disabled { opacity: .3; cursor: default; }

/* add / search */
.dc-add { margin-top: 12px; border-top: 1px solid var(--border); padding-top: 12px; }
.dc-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.dc-lbl { font-size: 12px; color: var(--dim); flex-shrink: 0; }
.dc-select, .dc-input { background: var(--bg); border: 1px solid var(--border); color: var(--text); border-radius: 8px; padding: 7px 10px; font-size: 13px; }
.dc-searchrow .dc-input { flex: 1; min-width: 0; }
.dc-select { flex: 1; }
.dc-results { display: flex; flex-direction: column; gap: 6px; }
.dc-res { display: flex; align-items: center; gap: 10px; padding: 6px; border-radius: 8px; background: var(--bg); }
.dc-res-thumb { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; background: var(--bg3); flex-shrink: 0; }
.dc-res-meta { flex: 1; min-width: 0; }
.dc-res-title { font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dc-res-sub { font-size: 11px; }
.dc-res-actions { display: flex; gap: 5px; flex-shrink: 0; }

/* ── Full Discord player view ─────────────────────────────────────────────── */
.dc-strip-status { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.discord-view { max-width: 920px; margin: 0 auto; padding: 8px 4px 40px; }
.dv-top { display: flex; align-items: center; gap: 10px; margin-bottom: 18px; }
.dv-back { width: 34px; height: 34px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg2); color: var(--text); cursor: pointer; font-size: 16px; flex-shrink: 0; }
.dv-back:hover { border-color: var(--accent); }
.dv-guild { font-weight: 800; font-size: 18px; }
.dv-now { display: flex; gap: 18px; align-items: center; margin-bottom: 14px; }
.dv-art { width: 120px; height: 120px; border-radius: 12px; object-fit: cover; background: var(--bg3); flex-shrink: 0; }
.dv-art.dv-noart { display: flex; align-items: center; justify-content: center; color: var(--mute); }
.dv-art.dv-noart .svi { width: 40px; height: 40px; }
.dv-meta { min-width: 0; flex: 1; }
.dv-title { font-size: 22px; font-weight: 800; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dv-now.dv-idle .dv-title { color: var(--mute); }
.dv-by { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13px; margin: 8px 0 12px; }
.dv-req { color: var(--dim); }
/* Play state as a chip, so it reads at a glance and can say "Stopped". */
.dv-state { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px 3px 7px; border-radius: 999px;
  font-size: 12px; font-weight: 700; background: var(--bg3); color: var(--dim); }
.dv-state .svi { width: 13px; height: 13px; }
.dv-state.dv-playing { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); }

/* ── Transport ──────────────────────────────────────────────────────────────
   One visually primary action (play/pause) with the secondaries flanking it,
   instead of a flat row of same-weight emoji buttons. */
.dv-controls { margin: 6px 0 18px; }
.dv-transport { display: flex; align-items: center; justify-content: center; gap: 10px; }
.dv-tb { width: 42px; height: 42px; flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid transparent; border-radius: 50%; color: var(--dim); cursor: pointer;
  transition: color .15s ease, background .15s ease, border-color .15s ease, transform .1s ease; }
.dv-tb .svi { width: 20px; height: 20px; }
.dv-tb:hover { color: var(--text); background: var(--bg3); }
.dv-tb:active { transform: scale(.93); }
.dv-tb.on { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.dv-tb.dv-play { width: 58px; height: 58px; background: var(--accent); color: var(--bg); border-color: transparent;
  box-shadow: 0 6px 20px color-mix(in srgb, var(--accent) 35%, transparent); }
.dv-tb.dv-play .svi { width: 26px; height: 26px; }
.dv-tb.dv-play:hover { filter: brightness(1.08); background: var(--accent); color: var(--bg); }
.dv-tb.dv-sm { width: 34px; height: 34px; }
.dv-tb.dv-sm .svi { width: 17px; height: 17px; }
.dv-more .svi { transition: transform .18s ease; transform: rotate(90deg); }   /* ▸ → ▾ */
.dv-more.on .svi { transform: rotate(-90deg); }

/* Utility row: volume as a real slider (was −/+ nudge buttons) + the disclosure. */
.dv-utility { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 12px; }
.dv-vol { display: inline-flex; align-items: center; gap: 8px; color: var(--dim); }
.dv-vol .svi { width: 17px; height: 17px; flex-shrink: 0; }
.dv-volrange { width: 130px; accent-color: var(--accent); cursor: pointer; }
.dv-volval { font-size: 12px; color: var(--dim); min-width: 38px; font-variant-numeric: tabular-nums; }

/* Filters, behind the ⌄ disclosure. Labelled chips — the old row was bare emoji. */
.dv-adv { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.dv-chip { display: inline-flex; align-items: center; gap: 7px; padding: 7px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  background: var(--bg3); border: 1px solid var(--border); color: var(--dim); cursor: pointer; transition: color .15s, border-color .15s, background .15s; }
.dv-chip .svi { width: 15px; height: 15px; }
.dv-chip:hover { color: var(--text); border-color: var(--accent); }
.dv-chip.on { color: var(--accent); border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.dv-stepper { gap: 4px; padding: 4px 6px; cursor: default; font-variant-numeric: tabular-nums; }
.dv-stepper > span { min-width: 44px; text-align: center; }
.dv-step { width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; background: none; border: 0; border-radius: 50%; color: var(--dim); cursor: pointer; }
.dv-step:hover { color: var(--accent); background: var(--bg2); }
.dv-step .svi { width: 13px; height: 13px; }

/* ── Queue ── */
.dv-qhead { margin: 22px 0 6px; font-size: 12px; text-transform: uppercase; letter-spacing: .07em; }
/* The queue is built from the app's own .row markup, so it inherits the whole
   song-list look; only the bits a remote queue needs are added here. */
.dq-noart { width: 44px; height: 44px; border-radius: 5px; background: var(--bg3); color: var(--mute); display: flex; align-items: center; justify-content: center; }
.dq-noart .svi { width: 18px; height: 18px; }
.dq-row .rownum { cursor: grab; }            /* the number column is the grip */
.dq-row.dragging .rownum { cursor: grabbing; }
.dq-del { display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }
.dq-del .svi { width: 14px; height: 14px; }
.dq-row .acts { opacity: 0; transition: opacity .12s; }
.dq-row:hover .acts, .dq-row:focus-within .acts { opacity: 1; }
.dq-del:hover { color: var(--danger) !important; border-color: var(--danger) !important; }
body.dq-dragging .dq-row { touch-action: none; }
.dv-empty { display: flex; align-items: center; gap: 8px; color: var(--mute); font-size: 13px; padding: 10px 2px; }
.dv-add { margin: 8px 0 4px; }
.dv-hint { font-size: 11.5px; margin-top: 6px; line-height: 1.45; }
.dv-hint b { color: var(--dim); font-weight: 700; }

/* Touch: the hover-reveal queue actions never appear, so pin them on, and give
   the transport room to breathe on a narrow screen. */
@media (max-width: 760px) {
  .dv-art { width: 84px; height: 84px; }
  .dv-title { font-size: 18px; }
  .dq-row .acts { opacity: 1; }
  .dv-transport { gap: 6px; }
  .dv-utility { gap: 10px; }
  .dv-volrange { width: 96px; }
}
@media (hover: none) { .dq-row .acts { opacity: 1; } }

/* ══════════════════════════════════════════════════════════════════════════
   Landing (logged-out / first visit). Full-screen overlay inside the SPA;
   inherits the active theme via the same CSS vars the app uses.
   ══════════════════════════════════════════════════════════════════════════ */
.landing { position: fixed; inset: 0; z-index: 5000; overflow-y: auto; overflow-x: hidden;
  background: radial-gradient(120% 90% at 50% -10%, color-mix(in srgb, var(--accent) 9%, var(--bg)) 0%, var(--bg) 55%);
  color: var(--text); -webkit-font-smoothing: antialiased; scroll-behavior: smooth; }
.landing[hidden] { display: none; }
.landing * { box-sizing: border-box; }

/* Drifting aurora + grain atmosphere */
.ld-aurora { position: fixed; inset: -20% -10% auto -10%; height: 90vh; z-index: 0; pointer-events: none; filter: blur(70px); opacity: .55;
  background:
    radial-gradient(40% 50% at 22% 30%, color-mix(in srgb, var(--accent) 65%, transparent), transparent 70%),
    radial-gradient(38% 48% at 80% 18%, color-mix(in srgb, var(--accent2) 60%, transparent), transparent 70%),
    radial-gradient(34% 40% at 60% 60%, color-mix(in srgb, var(--accent) 40%, transparent), transparent 70%);
  animation: ld-drift 22s ease-in-out infinite alternate; }
@keyframes ld-drift { from { transform: translate3d(-3%, -2%, 0) scale(1); } to { transform: translate3d(4%, 3%, 0) scale(1.12); } }
.ld-grain { position: fixed; inset: 0; z-index: 1; pointer-events: none; opacity: .035; mix-blend-mode: overlay;
  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'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E"); }
.landing > *:not(.ld-aurora):not(.ld-grain) { position: relative; z-index: 2; }

/* Shared bits */
.ld-logo { width: 30px; height: 30px; flex-shrink: 0; }
.ld-logo line { stroke: var(--accent); stroke-width: 7; stroke-linecap: round; }
.ld-logo line:nth-child(even) { stroke: var(--accent2); }
.ld-logo.sm { width: 20px; height: 20px; }
.ld-btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; text-decoration: none; white-space: nowrap;
  font: 600 14px system-ui, -apple-system, 'Segoe UI', sans-serif; border-radius: 11px; cursor: pointer; border: 1px solid transparent;
  padding: 10px 18px; transition: transform .12s ease, box-shadow .2s ease, background .2s ease, border-color .2s ease; }
.ld-btn:active { transform: translateY(1px) scale(.99); }
.ld-primary { color: #fff; border: 0; background: linear-gradient(135deg, var(--accent), var(--accent2)); box-shadow: 0 6px 22px color-mix(in srgb, var(--accent) 38%, transparent); }
.ld-primary:hover { transform: translateY(-2px); box-shadow: 0 12px 34px color-mix(in srgb, var(--accent) 50%, transparent); }
.ld-ghost { color: var(--text); background: color-mix(in srgb, var(--text) 6%, transparent); border-color: var(--border); }
.ld-ghost:hover { transform: translateY(-2px); border-color: color-mix(in srgb, var(--accent) 60%, var(--border)); background: color-mix(in srgb, var(--accent) 10%, transparent); }
.ld-lg { padding: 14px 26px; font-size: 15.5px; border-radius: 13px; }

/* Nav */
/* Floating pill navbar — detached, blurred, centered link group */
.ld-nav { position: sticky; top: 14px; z-index: 50; display: flex; align-items: center; gap: 14px;
  width: min(1120px, calc(100% - 28px)); margin: 14px auto 0; padding: 9px 9px 9px 18px;
  border-radius: 18px; border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
  background: color-mix(in srgb, var(--bg2) 70%, transparent); backdrop-filter: blur(16px) saturate(1.3);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .3); }
.ld-brand { display: flex; align-items: center; gap: 10px; font: 800 20px 'Bricolage Grotesque', system-ui, sans-serif; letter-spacing: -.4px; color: var(--text); text-decoration: none; flex-shrink: 0; }
.ld-nav-cta { display: flex; gap: 10px; flex-shrink: 0; }

/* Hero */
.ld-hero { max-width: 940px; margin: 0 auto; padding: clamp(56px, 11vh, 130px) clamp(20px, 5vw, 40px) 40px; text-align: center; }
.ld-eyebrow { display: inline-block; font: 600 12.5px system-ui, sans-serif; letter-spacing: 2.5px; text-transform: uppercase; color: var(--accent);
  padding: 6px 14px; border: 1px solid color-mix(in srgb, var(--accent) 40%, var(--border)); border-radius: 999px; background: color-mix(in srgb, var(--accent) 8%, transparent); }
.ld-title { margin: 22px 0 0; font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 800; line-height: 1.03; letter-spacing: -1.6px;
  font-size: clamp(38px, 7vw, 78px); }
.ld-grad { background: linear-gradient(105deg, var(--accent), var(--accent2) 55%, var(--accent)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
/* Inline highlight (marker style) — e.g. "AI-assisted matching" */
.ld-hl { color: var(--accent); font-weight: 700; background: color-mix(in srgb, var(--accent) 14%, transparent); padding: 1px 6px; border-radius: 6px; }
.ld-sub { max-width: 660px; margin: 22px auto 0; font-size: clamp(15.5px, 2.1vw, 19px); line-height: 1.6; color: var(--dim); }
.ld-cta { display: flex; flex-wrap: wrap; gap: 14px; justify-content: center; margin-top: 34px; }
/* staggered hero entrance */
.ld-hero > * { animation: ld-rise .7s cubic-bezier(.2,.7,.2,1) both; }
.ld-hero > .ld-eyebrow { animation-delay: .02s; }
.ld-hero > .ld-title { animation-delay: .1s; }
.ld-hero > .ld-sub { animation-delay: .2s; }
.ld-hero > .ld-cta { animation-delay: .3s; }
.ld-hero > .ld-diagram { animation-delay: .42s; }
@keyframes ld-rise { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }

/* Hero equalizer (bars injected by app.js) */
.ld-eq { display: flex; align-items: flex-end; justify-content: center; gap: 4px; height: 90px; margin: 54px auto 0; max-width: 520px; }
.ld-eq i { flex: 1; max-width: 9px; border-radius: 6px; background: linear-gradient(to top, var(--accent), var(--accent2)); transform-origin: bottom;
  animation: ld-eq-bounce 1.1s ease-in-out infinite; }
@keyframes ld-eq-bounce { 0%, 100% { transform: scaleY(.18); } 50% { transform: scaleY(1); } }

/* Hero diagram: sources → Audacord → synced devices */
.ld-diagram { max-width: 900px; margin: 46px auto 0; }
.ld-diagram .dev-ico { fill: none; stroke: var(--dim); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ld-diagram svg { width: 100%; height: auto; display: block; overflow: visible; }
.ld-diagram .node { fill: color-mix(in srgb, var(--text) 6%, transparent); stroke: color-mix(in srgb, var(--border) 90%, transparent); stroke-width: 1.5; }
.ld-diagram text { fill: var(--text); font: 600 18px system-ui, -apple-system, 'Segoe UI', sans-serif; }
.ld-diagram .hub-label { fill: var(--accent); font-weight: 800; font-size: 20px; }
.ld-diagram .ld-grp { fill: var(--dim); font-weight: 700; font-size: 15px; }
.ld-diagram .grp-dot.me { fill: var(--accent); }
.ld-diagram .grp-dot.friend { fill: var(--accent2); }
.ld-diagram .base { fill: none; stroke: color-mix(in srgb, var(--border) 85%, transparent); stroke-width: 2; }
.ld-diagram .flow { fill: none; stroke: var(--accent); stroke-width: 2.4; stroke-linecap: round; stroke-dasharray: 4 13; animation: ld-flow 1.05s linear infinite; }
@keyframes ld-flow { to { stroke-dashoffset: -34; } }
.ld-diagram .ring { fill: none; stroke: var(--accent); stroke-width: 2; opacity: 0; transform-box: fill-box; transform-origin: center; animation: ld-ring 2.8s ease-out infinite; }
.ld-diagram .ring.r2 { animation-delay: 1.4s; }
@keyframes ld-ring { 0% { transform: scale(.74); opacity: .5; } 80% { opacity: 0; } 100% { transform: scale(1.7); opacity: 0; } }
.ld-diagram .core { fill: url(#ldHub); filter: drop-shadow(0 6px 20px color-mix(in srgb, var(--accent) 45%, transparent)); }
.ld-diagram .heq rect { fill: #04130c; transform-box: fill-box; transform-origin: bottom; animation: ld-eq-bounce 1.05s ease-in-out infinite; }
.ld-diagram .heq rect:nth-child(1) { animation-delay: -.2s; }
.ld-diagram .heq rect:nth-child(2) { animation-delay: -.5s; }
.ld-diagram .heq rect:nth-child(3) { animation-delay: -.05s; }
.ld-diagram .heq rect:nth-child(4) { animation-delay: -.35s; }
.ld-diagram .heq rect:nth-child(5) { animation-delay: -.65s; }
.ld-diagram .sync { fill: var(--accent); transform-box: fill-box; transform-origin: center; animation: ld-sync 1.6s ease-in-out infinite; }
@keyframes ld-sync { 0%, 100% { opacity: .35; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.15); } }
.ld-diagram-cap { display: flex; gap: 9px; align-items: center; justify-content: center; margin-top: 16px; color: var(--dim); font-size: 13.5px; }
.ld-diagram-cap .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); animation: ld-sync 1.6s ease-in-out infinite; }
@media (max-width: 560px) { .ld-diagram text { font-size: 23px; } .ld-diagram .hub-label { font-size: 25px; } .ld-diagram .ld-grp { font-size: 19px; } }

/* Mobile navbar: hamburger + slide-in drawer */
.ld-burger { display: none; margin-left: auto; width: 42px; height: 42px; flex-shrink: 0; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  background: color-mix(in srgb, var(--text) 6%, transparent); border: 1px solid var(--border); border-radius: 11px; cursor: pointer; }
.ld-burger span { display: block; width: 18px; height: 2px; border-radius: 2px; background: var(--text); transition: transform .2s ease, opacity .2s ease; }
.ld-burger.open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.ld-burger.open span:nth-child(2) { opacity: 0; }
.ld-burger.open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
.ld-mobnav { position: fixed; top: 0; right: 0; bottom: 0; width: min(80vw, 320px); z-index: 6000; transform: translateX(100%);
  transition: transform .28s cubic-bezier(.2, .7, .2, 1); background: var(--bg2); border-left: 1px solid var(--border);
  box-shadow: -20px 0 50px rgba(0, 0, 0, .5); padding: calc(20px + env(safe-area-inset-top, 0px)) 18px 28px; display: flex; flex-direction: column; gap: 4px; }
.ld-mobnav.open { transform: none; }
.ld-mobnav-brand { display: flex; align-items: center; gap: 10px; padding: 4px 8px 16px; margin-bottom: 10px; border-bottom: 1px solid var(--border);
  font: 800 22px 'Bricolage Grotesque', system-ui, sans-serif; letter-spacing: -.4px; color: var(--text); }
.ld-mobnav-brand .ld-logo { width: 28px; height: 28px; }
.ld-mobnav a { padding: 13px 14px; border-radius: 11px; color: var(--text); text-decoration: none; font: 600 16px system-ui, -apple-system, 'Segoe UI', sans-serif; }
.ld-mobnav a:hover, .ld-mobnav a.active { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); }
.ld-mob-cta { margin-top: 16px; display: grid; gap: 10px; }
.ld-mob-cta .ld-btn { width: 100%; padding: 13px 18px; }
.ld-mob-backdrop { position: fixed; inset: 0; z-index: 5500; background: rgba(0, 0, 0, .55); opacity: 0; visibility: hidden; transition: opacity .25s ease, visibility .25s ease; }
.ld-mob-backdrop.open { opacity: 1; visibility: visible; }
@media (max-width: 820px) { .ld-burger { display: flex; } .ld-nav-cta { display: none; } }
@media (min-width: 821px) { .ld-mobnav, .ld-mob-backdrop { display: none; } }

/* Scrollable marketing pages + themed scrollbar (overrides the app's body overflow:hidden) */
.ld-page { overflow-y: auto; overflow-x: hidden; }
.landing, .ld-page { scrollbar-width: thin; scrollbar-color: var(--accent) transparent; }
.landing::-webkit-scrollbar, .ld-page::-webkit-scrollbar { width: 12px; }
.landing::-webkit-scrollbar-track, .ld-page::-webkit-scrollbar-track { background: transparent; }
.landing::-webkit-scrollbar-thumb, .ld-page::-webkit-scrollbar-thumb { border-radius: 999px; border: 3px solid var(--bg); background: linear-gradient(var(--accent), var(--accent2)); }
.landing::-webkit-scrollbar-thumb:hover, .ld-page::-webkit-scrollbar-thumb:hover { background: linear-gradient(var(--accent2), var(--accent)); }

/* Sections */
.ld-section { max-width: 1080px; margin: 0 auto; padding: clamp(40px, 8vh, 96px) clamp(20px, 5vw, 40px); }
/* "Three steps" + a compact stats panel beside them */
.ld-steps-row { display: flex; align-items: flex-start; gap: clamp(24px, 5vw, 60px); margin-top: clamp(20px, 3vw, 34px); }
.ld-steps-row .ld-steps { flex: 1; min-width: 0; margin: 0; }
.ld-stats { flex: 0 0 auto; width: clamp(212px, 27vw, 264px); display: flex; flex-direction: column; gap: 4px;
  padding: clamp(14px, 1.8vw, 20px) clamp(16px, 2vw, 22px); border-radius: 18px;
  border: 1px solid color-mix(in srgb, var(--accent) 26%, var(--border));
  background: radial-gradient(120% 130% at 50% 0%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 62%), color-mix(in srgb, var(--accent) 4%, rgba(255,255,255,.015));
  box-shadow: 0 22px 60px -36px color-mix(in srgb, var(--accent) 65%, transparent); }
.ld-stats[hidden] { display: none; }
.ld-stat { display: flex; align-items: center; gap: 13px; padding: 12px 2px; }
.ld-stat + .ld-stat { border-top: 1px solid color-mix(in srgb, var(--accent) 15%, var(--border)); }
.ld-stat-ico { width: 40px; height: 40px; flex: none; display: inline-flex; align-items: center; justify-content: center; border-radius: 12px; position: relative;
  color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); }
.ld-stat-ico svg { width: 21px; height: 21px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.ld-stat-ico--live::after { content: ''; position: absolute; top: 6px; right: 6px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); animation: ldPulse 1.9s ease-out infinite; }
@keyframes ldPulse { 0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); } 70%, 100% { box-shadow: 0 0 0 9px transparent; } }
.ld-stat-body { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }
.ld-stat-n { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 700; font-size: clamp(26px, 3.2vw, 34px); line-height: 1; letter-spacing: -1px; font-variant-numeric: tabular-nums;
  background: linear-gradient(105deg, var(--accent), var(--accent2) 60%, var(--accent)); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; }
.ld-stat-l { font-size: 12.5px; color: var(--dim); margin-top: 3px; }
@media (max-width: 820px) {
  .ld-steps-row { flex-direction: column; }
  .ld-stats { width: 100%; flex-direction: row; }
  .ld-stat { flex: 1; }
  .ld-stat + .ld-stat { border-top: none; border-left: 1px solid color-mix(in srgb, var(--accent) 15%, var(--border)); }
}
.ld-h2 { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 700; font-size: clamp(26px, 4.2vw, 42px); letter-spacing: -.8px; text-align: center; line-height: 1.1; }

/* Feature grid */
.ld-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 46px; }
.ld-card { padding: 26px 24px; border-radius: 18px; border: 1px solid var(--border); background: linear-gradient(180deg, color-mix(in srgb, var(--text) 4%, transparent), transparent);
  transition: transform .22s ease, border-color .22s ease, box-shadow .22s ease; }
.ld-card:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); box-shadow: 0 16px 40px rgba(0,0,0,.3); }
.ld-ico { display: inline-flex; align-items: center; justify-content: center; width: 46px; height: 46px; border-radius: 12px;
  background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent); }
.ld-ico svg { width: 24px; height: 24px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ld-card h3 { margin: 16px 0 8px; font-size: 19px; font-weight: 700; letter-spacing: -.3px; }
.ld-card p { font-size: 14.5px; line-height: 1.6; color: var(--dim); }

/* Steps */
.ld-steps { list-style: none; max-width: 720px; margin: 46px auto 0; padding: 0; display: grid; gap: 14px; }
.ld-steps li { display: flex; gap: 18px; align-items: flex-start; padding: 22px 24px; border-radius: 16px; border: 1px solid var(--border);
  background: color-mix(in srgb, var(--text) 3%, transparent); }
.ld-step-n { flex-shrink: 0; width: 40px; height: 40px; border-radius: 11px; display: grid; place-items: center; font: 800 18px 'Bricolage Grotesque', system-ui, sans-serif;
  color: #fff; background: linear-gradient(135deg, var(--accent), var(--accent2)); box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 34%, transparent); }
.ld-steps h3 { font-size: 18px; font-weight: 700; }
.ld-steps p { margin-top: 5px; font-size: 14.5px; line-height: 1.55; color: var(--dim); }

/* Downloads */
.ld-downloads { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 40px; }
.ld-dl-card { display: flex; align-items: center; gap: 16px; padding: 22px 24px; border-radius: 18px; text-decoration: none; color: var(--text);
  border: 1px solid var(--border); background: linear-gradient(180deg, color-mix(in srgb, var(--text) 4%, transparent), transparent);
  transition: transform .2s ease, border-color .2s ease, box-shadow .2s ease; }
.ld-dl-card:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--accent) 50%, var(--border)); box-shadow: 0 16px 40px rgba(0, 0, 0, .3); }
.ld-dl-ico { flex-shrink: 0; width: 48px; height: 48px; border-radius: 12px; display: inline-flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent); }
.ld-dl-ico svg { width: 26px; height: 26px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ld-dl-text { flex: 1; min-width: 0; }
.ld-dl-text h3 { font-size: 17px; font-weight: 700; letter-spacing: -.2px; }
.ld-dl-text p { font-size: 13px; line-height: 1.5; color: var(--dim); margin-top: 4px; }
.ld-dl-btn { flex-shrink: 0; padding: 10px 16px; border-radius: 10px; font-size: 13.5px; font-weight: 700; color: #fff; white-space: nowrap;
  background: linear-gradient(135deg, var(--accent), var(--accent2)); box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 32%, transparent); }
@media (max-width: 720px) { .ld-downloads { grid-template-columns: 1fr; } .ld-dl-card { flex-wrap: wrap; } .ld-dl-btn { width: 100%; text-align: center; } }
/* Downloads page: a centered single-column stack (reads as a clean list). */
.dl-grid { grid-template-columns: 1fr; max-width: 640px; margin-left: auto; margin-right: auto; }
.dl-ver { font-size: 12px; font-weight: 600; color: var(--accent); margin-left: 6px; }
.dl-card-note { font-size: 12px !important; color: var(--mute) !important; margin-top: 7px !important; }
.dl-card-note code { background: color-mix(in srgb, var(--text) 10%, transparent); padding: 0 5px; border-radius: 4px; font-size: 11.5px; }

/* Transparency callout: we don't host the audio */
.ld-trust { max-width: 840px; text-align: center; }
.ld-trust-ico { display: inline-flex; width: 54px; height: 54px; border-radius: 14px; align-items: center; justify-content: center; margin-bottom: 18px;
  background: color-mix(in srgb, var(--accent) 14%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent); }
.ld-trust-ico svg { width: 28px; height: 28px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.ld-trust .ld-sub { margin-left: auto; margin-right: auto; }
.ld-trust-links { margin-top: 16px; color: var(--mute); font-size: 13.5px; }
.ld-trust-links a { color: var(--accent); text-decoration: none; }
.ld-trust-links a:hover { text-decoration: underline; }

/* Final CTA */
.ld-final { text-align: center; max-width: 760px; }
.ld-final .ld-sub { margin-top: 14px; }
.ld-final .ld-cta { margin-top: 28px; }

/* Footer */
.ld-footer { display: flex; flex-wrap: wrap; gap: 10px 18px; align-items: center; justify-content: space-between;
  max-width: 1080px; margin: 0 auto; padding: 30px clamp(20px, 5vw, 40px) 48px; border-top: 1px solid var(--border); color: var(--mute); font-size: 13px; }
.ld-foot-brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; color: var(--dim); }

/* Scroll reveal */
.landing .reveal { opacity: 0; transform: translateY(26px); transition: opacity .6s ease, transform .6s cubic-bezier(.2,.7,.2,1); }
.landing .reveal.in { opacity: 1; transform: none; }
.ld-grid .reveal:nth-child(2) { transition-delay: .06s; }
.ld-grid .reveal:nth-child(3) { transition-delay: .12s; }
.ld-grid .reveal:nth-child(5) { transition-delay: .06s; }
.ld-grid .reveal:nth-child(6) { transition-delay: .12s; }

@media (max-width: 900px) { .ld-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) {
  .ld-grid { grid-template-columns: 1fr; }
  .ld-nav-cta .ld-ghost { display: none; }
  .ld-cta { flex-direction: column; align-items: stretch; }
  .ld-eq { height: 64px; }
}
/* ── Standalone pages (pricing / privacy / terms) — reuse the landing language ── */
.ld-page { min-height: 100vh; -webkit-font-smoothing: antialiased;
  /* Anchor the gradient to the VIEWPORT (like .landing, which is fixed) so it doesn't
     stretch to the full content height and leave the bottom of long pages flat. */
  background: radial-gradient(120% 90% at 50% -10%, color-mix(in srgb, var(--accent) 9%, var(--bg)) 0%, var(--bg) 55%) fixed; color: var(--text); }
.ld-page .ld-nav { position: sticky; }
.ld-foot-links { display: flex; flex-wrap: wrap; gap: 8px 18px; }
.ld-foot-links a { color: var(--dim); text-decoration: none; font-size: 13px; }
.ld-foot-links a:hover { color: var(--accent); }

/* Pricing hero + single free plan */
.ld-price-hero { max-width: 820px; margin: 0 auto; text-align: center; padding: clamp(48px, 9vh, 96px) clamp(20px, 5vw, 40px) 0; position: relative; z-index: 2; }
.ld-plan { max-width: 460px; margin: 44px auto 0; padding: 36px 32px; border-radius: 22px; text-align: center; position: relative; z-index: 2;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--border)); background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 11%, transparent), transparent);
  box-shadow: 0 24px 60px rgba(0,0,0,.35); }
.ld-plan .ld-plan-name { font: 600 12.5px system-ui, sans-serif; letter-spacing: 2.5px; text-transform: uppercase; color: var(--accent); }
.ld-plan .ld-price { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 800; font-size: 66px; line-height: 1; letter-spacing: -2px; margin-top: 10px; }
.ld-plan .ld-price small { font-size: 17px; color: var(--dim); font-weight: 600; letter-spacing: 0; }
.ld-plan .ld-plan-sub { color: var(--dim); margin-top: 8px; font-size: 14.5px; }
.ld-plan ul { list-style: none; text-align: left; margin: 26px auto 0; max-width: 330px; display: grid; gap: 11px; padding: 0; }
.ld-plan li { display: flex; gap: 11px; align-items: flex-start; color: var(--text); font-size: 15px; line-height: 1.4; }
.ld-plan li::before { content: "✓"; color: var(--accent); font-weight: 800; flex-shrink: 0; }
.ld-plan .ld-btn { margin-top: 28px; width: 100%; }
.ld-note { max-width: 560px; margin: 30px auto 0; text-align: center; color: var(--mute); font-size: 13.5px; line-height: 1.6; position: relative; z-index: 2; }

/* Legal / document body */
.ld-doc { max-width: 820px; margin: 0 auto; padding: clamp(36px, 6vh, 72px) clamp(20px, 5vw, 40px) 56px; position: relative; z-index: 2; }
.ld-doc h1 { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 800; font-size: clamp(32px, 5vw, 50px); letter-spacing: -1px; line-height: 1.05; }
.ld-doc .ld-updated { color: var(--mute); font-size: 13px; margin-top: 10px; }
.ld-doc h2 { font-family: 'Bricolage Grotesque', system-ui, sans-serif; font-weight: 700; font-size: clamp(19px, 3vw, 25px); letter-spacing: -.4px; margin: 36px 0 8px; color: var(--text); }
.ld-doc p, .ld-doc li { color: var(--dim); line-height: 1.7; font-size: 15.5px; }
.ld-doc p { margin: 10px 0; }
.ld-doc ul { margin: 10px 0 10px 4px; padding-left: 20px; }
.ld-doc li { margin: 6px 0; }
.ld-doc a { color: var(--accent); }
.ld-doc strong { color: var(--text); }

/* ── Marketing pages: always the GREEN theme, regardless of the app's active theme ── */
.landing, .ld-page {
  --bg: #0b0e14; --bg2: #11161f; --bg3: #1a2230; --border: #1e2632;
  --text: #e6edf3; --dim: #9aa7b8; --mute: #5a6678;
  --accent: #1db954; --accent2: #2dd4bf; --sidebar-bg: #07090d; --danger: #ff6b6b;
}

/* Brand logo: equalizer ripple on hover — same motion as the app's sidebar brand */
.ld-logo line { transform-box: fill-box; transform-origin: center; transition: transform .22s ease; }
.ld-brand:hover .ld-logo line { animation: sw-eq .9s ease-in-out infinite; }
.ld-brand:hover .ld-logo line:nth-child(1) { animation-delay: 0s; }
.ld-brand:hover .ld-logo line:nth-child(2) { animation-delay: .07s; }
.ld-brand:hover .ld-logo line:nth-child(3) { animation-delay: .14s; }
.ld-brand:hover .ld-logo line:nth-child(4) { animation-delay: .21s; }
.ld-brand:hover .ld-logo line:nth-child(5) { animation-delay: .28s; }
.ld-brand:hover .ld-logo line:nth-child(6) { animation-delay: .35s; }
.ld-brand:hover .ld-logo line:nth-child(7) { animation-delay: .42s; }

/* Navbar page links — a centered segmented pill */
.ld-nav-links { display: flex; align-items: center; gap: 2px; margin: 0 auto; padding: 4px; border-radius: 12px;
  border: 1px solid color-mix(in srgb, var(--border) 60%, transparent); background: color-mix(in srgb, var(--text) 5%, transparent); }
.ld-nav-links a { padding: 7px 15px; border-radius: 9px; color: var(--dim); text-decoration: none;
  font: 600 13.5px system-ui, -apple-system, 'Segoe UI', sans-serif; transition: color .15s ease, background .15s ease; }
.ld-nav-links a:hover { color: var(--text); background: color-mix(in srgb, var(--text) 9%, transparent); }
.ld-nav-links a.active { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
@media (max-width: 820px) { .ld-nav-links { display: none; } }

/* Standalone pages: bottom-anchored footer even on short pages */
.ld-page { display: flex; flex-direction: column; }
.ld-page .ld-footer { margin-top: auto; }

/* "Made for" use-case band */
.ld-uses { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; margin-top: 42px; }
.ld-use { padding: 20px; border-radius: 16px; border: 1px solid var(--border); background: color-mix(in srgb, var(--text) 3%, transparent); }
.ld-use h3 { font-size: 16px; font-weight: 700; letter-spacing: -.2px; }
.ld-use p { margin-top: 6px; font-size: 13.5px; line-height: 1.55; color: var(--dim); }
@media (max-width: 860px) { .ld-uses { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .ld-uses { grid-template-columns: 1fr; } }
