:root {
  /* ---- Tunables ---- */
  --hero: 380px;          /* size of the fixed centered jewel-case frame */
  --perspective: 1700px;
  --side-scale: 0.5;      /* size of side CDs relative to the framed disc */
  --gap-frac: 0.07;       /* gap (× hero) between frame and first side CD */
  --step-extra: 0.045;    /* extra spacing (× hero) between side CDs */
  --side-rotate: 20deg;   /* subtle 3D Y-rotation on side CDs */
  --side-depth: 70px;     /* translateZ recession per step */
  --max-visible: 4;
  /* Non-full view: how far to lift the disc + now-playing group up from the
     window's vertical center so the WHOLE player (disc + info + controls) is
     centered, rather than the disc being centered and the info hanging below.
     ≈ half the height the info/controls add beneath the disc. Tune if needed. */
  --np-lift: 90px;
  --dither-opacity: 0.34; /* 1-bit dither strength over the CD art */
  --speed: 620ms;
  --ease: cubic-bezier(0.16, 0.84, 0.30, 1);

  /* Figma disc geometry: Ellipse 509x509 @ (50,41) in a 600 frame */
  --disc-left: 8.333%;
  --disc-top: 6.833%;
  --disc-size: 84.833%;

  /* Figma now-playing card: 203x214 @ abs (2368,730) -> rel in 600 frame */
  --glass-left: 64.83%;
  --glass-top: 2.33%;
  --glass-w: 33.83%;
  --glass-h: 35.67%;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }

body {
  min-height: 100%;
  display: grid;
  place-items: center;
  font-family: "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
  color: #e9edf5;
  background:
    radial-gradient(1100px 700px at 50% 12%, #1b2233 0%, transparent 60%),
    linear-gradient(180deg, #0e1119 0%, #070809 100%);
  overflow-x: hidden;
}

/* ---------------- Player shell ---------------- */
.player {
  position: relative;
  width: min(100%, 1180px);
  height: 700px;
  display: grid;
  place-items: center;
  user-select: none;
  -webkit-user-select: none;
  touch-action: pan-y;
  perspective: var(--perspective);
}

/* The 3D stage everything is positioned within */
.player__frame,
.player__track {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--hero);
  height: var(--hero);
  transform: translate(-50%, -50%);
}

/* ---- Fixed jewel-case frame (stays centered) ---- */
.player__frame {
  z-index: 10;
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 40px 80px -30px rgba(0, 0, 0, 0.85);
  pointer-events: none;
}
.player__case {
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
}

/* Frame overlay: sits ABOVE the disc (z 20/25) so parts like a tonearm render on top */
.player__overlay {
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--hero);
  height: var(--hero);
  transform: translate(-50%, -50%);
  object-fit: cover;
  z-index: 26;
  pointer-events: none;
  -webkit-user-drag: none;
}
.player__overlay[hidden] { display: none; }

/* ---- Moving CD track ---- */
.player__track {
  z-index: 20;
  transform-style: preserve-3d;
  transform: translate(-50%, -50%);
  pointer-events: none;          /* discs re-enable themselves */
}

/* Each CD = circular art + dither + CD sheen + spindle hole */
.disc {
  position: absolute;
  left: var(--disc-left);
  top: var(--disc-top);
  width: var(--disc-size);
  aspect-ratio: 1 / 1;
  border-radius: 50%;
  overflow: hidden;
  transform-origin: center center;
  will-change: transform, opacity;
  pointer-events: auto;
  cursor: pointer;
  transition:
    transform var(--speed) var(--ease),
    opacity   var(--speed) var(--ease),
    filter    var(--speed) var(--ease);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, 0.55),
    0 14px 30px -10px rgba(0, 0, 0, 0.75);
}
.player.is-dragging .disc { transition: none; }
.disc.is-active { cursor: grab; }
.player.is-dragging .disc.is-active { cursor: grabbing; }

/* Rotating layer: holds the printed art + dither (spins around the spindle) */
.disc__spin {
  position: absolute;
  inset: 0;
  transform-origin: 50% 50%;
  will-change: transform;
  backface-visibility: hidden;
}

.disc__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
  -webkit-user-drag: none;
}

/* Bayer 16x16 ordered dither (canvas), shown on the playing/active disc */
.disc__dcanvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
.disc.is-active.has-fx .disc__dcanvas { opacity: 1; }
/* Color Flow: hide the album photo and put a black fill behind, so only the flowing colour
   (the effect canvas) is visible and nothing behind the disc shows through. */
.disc.is-active.fx-flow .disc__art { opacity: 0; }
.disc.is-active.fx-flow .disc__spin { background: #000; }

/* CD sheen — faint concentric grooves + a soft radial shine */
.disc__shine {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    repeating-radial-gradient(circle at 50% 50%,
      rgba(255, 255, 255, 0.0) 0px,
      rgba(255, 255, 255, 0.0) 2px,
      rgba(255, 255, 255, 0.035) 3px,
      rgba(0, 0, 0, 0.04) 4px),
    radial-gradient(circle at 34% 30%,
      rgba(255, 255, 255, 0.22) 0%,
      rgba(255, 255, 255, 0.0) 38%);
  mix-blend-mode: screen;
  opacity: 0.6;
}

/* CD spindle hole + hub */
.disc__hole {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 17%;
  aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background:
    radial-gradient(circle,
      #07090d 0%,
      #07090d 40%,
      rgba(150, 162, 180, 0.55) 42%,
      rgba(90, 100, 116, 0.35) 50%,
      rgba(20, 24, 30, 0.0) 54%);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.85),
    0 1px 1px rgba(255, 255, 255, 0.08);
  pointer-events: none;
}

/* ---- Now-playing panel (below the cassette frame, 24px gap) ---- */
.nowplaying {
  position: absolute;
  left: 50%;
  top: calc(50% + var(--hero) / 2 + 24px);   /* 24px below the frame */
  transform: translateX(-50%);
  width: min(var(--hero), 92vw);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: 14px;
  color: #fff;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  pointer-events: none;                       /* children re-enable themselves */
}

/* Non-full (windowed) view: lift the disc + now-playing group up by --np-lift so
   the whole player is vertically centered in the window, instead of the disc
   being centered and the info/controls hanging into the lower half. Full-screen
   view (body.is-full) bottom-anchors its own layout and is unaffected. */
body:not(.is-full) .player__frame,
body:not(.is-full) .player__track,
body:not(.is-full) .player__overlay {
  top: calc(50% - var(--np-lift));
}
body:not(.is-full) .nowplaying {
  top: calc(50% - var(--np-lift) + var(--hero) / 2 + 24px);
}

/* body wrapper: head / progress / controls stacked as a column */
.np__body {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 100%;
  min-width: 0;
}

/* Mini cassette (jewel case + album-art disc) — shown in the lyrics-mode bar only.
   Figma 134:477: a 120px case with the current song's art printed on the disc. */
.np__cover {
  display: none;
  position: relative;
  flex: none;
  width: 73px; height: 73px;
  border-radius: 9px;
  overflow: hidden;
  background: #0c0e13;
  box-shadow: 0 14px 34px -14px rgba(0, 0, 0, 0.75);
  pointer-events: none;
}
.np__cover-case {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
}
.np__cover-disc {              /* album art on the disc, covering the case's blue disc */
  position: absolute;
  left: 50%; top: 49%;
  width: 79%; aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6), inset 0 0 10px rgba(0, 0, 0, 0.4);
}
.np__cover-art {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  -webkit-user-drag: none;
}
.np__cover-hub {               /* centre spindle hole */
  position: absolute;
  left: 50%; top: 50%;
  width: 21%; aspect-ratio: 1 / 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%,
    #0c0e13 0 38%, rgba(255, 255, 255, 0.20) 40% 46%, #0c0e13 48%);
}

/* Lyrics mode: the now-playing card becomes the Figma 134:477 bar
   (mini cassette on the left, song info + transport on the right). */
.player.show-lyrics .nowplaying {
  flex-direction: row;
  align-items: flex-start;
  gap: 26px;
  width: min(calc(var(--hero) + 172px), 94vw, 630px);
}
.player.show-lyrics .np__cover { display: block; }

.np__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}
.np__title {
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.2;
}
.np__artist {
  margin-top: 3px;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.6);
}

/* ---------- Smoky title/artist transition (Bennett Feely "Smoky Text") ----------
   On a track change the old line dissolves into smoke and drifts off; the new line
   condenses back out of the smoke. --dir (+1/-1) makes the smoke follow the CD swipe
   direction. The letter itself is transparent and painted by a 0-blur text-shadow
   (the reference's trick) so blurring the shadow turns the glyph into a soft cloud. */
.np__title, .np__artist, .np__meta { overflow: visible; }
.np__title, .np__artist { position: relative; }
.smoke-line { display: inline-block; white-space: pre; }
.smoke-line.is-out { position: absolute; left: 0; top: 0; pointer-events: none; }
.smoke-line span {
  display: inline-block;
  color: transparent;
  text-shadow: 0 0 0 var(--smoke-col, #fff);
  white-space: pre;
  will-change: transform, opacity, text-shadow;
}
.smoke-line.is-out span { animation: smokeOut 0.75s both; }
.smoke-line.is-out span:nth-child(even) { animation-name: smokeOutB; }
.smoke-line.is-in  span { animation: smokeIn 0.7s both; }
.smoke-line.is-in  span:nth-child(even) { animation-name: smokeInB; }

@keyframes smokeOut {
  0%   { opacity: 1; }
  60%  { text-shadow: 0 0 22px var(--smoke-col, #fff); }
  100% { transform: translate3d(calc(7rem * var(--dir, 1)), -3.4rem, 0)
                     rotate(calc(-38deg * var(--dir, 1))) skewX(calc(64deg * var(--dir, 1))) scale(1.5);
         text-shadow: 0 0 12px var(--smoke-col, #fff); opacity: 0; }
}
@keyframes smokeOutB {   /* mirrored wisp (reference's smoky-mirror) for alternate letters */
  0%   { opacity: 1; }
  60%  { text-shadow: 0 0 26px var(--smoke-col, #fff); }
  100% { transform: translate3d(calc(8.6rem * var(--dir, 1)), -3.4rem, 0)
                     rotate(calc(-38deg * var(--dir, 1))) skewX(calc(-64deg * var(--dir, 1))) scale(1.9);
         text-shadow: 0 0 12px var(--smoke-col, #fff); opacity: 0; }
}
@keyframes smokeIn {
  0%   { transform: translate3d(calc(7rem * var(--dir, 1)), -3.4rem, 0)
                    rotate(calc(-38deg * var(--dir, 1))) skewX(calc(64deg * var(--dir, 1))) scale(1.5);
         text-shadow: 0 0 12px var(--smoke-col, #fff); opacity: 0; }
  40%  { text-shadow: 0 0 22px var(--smoke-col, #fff); }
  100% { transform: none; text-shadow: 0 0 0 var(--smoke-col, #fff); opacity: 1; }
}
@keyframes smokeInB {
  0%   { transform: translate3d(calc(8.6rem * var(--dir, 1)), -3.4rem, 0)
                    rotate(calc(-38deg * var(--dir, 1))) skewX(calc(-64deg * var(--dir, 1))) scale(1.9);
         text-shadow: 0 0 12px var(--smoke-col, #fff); opacity: 0; }
  40%  { text-shadow: 0 0 26px var(--smoke-col, #fff); }
  100% { transform: none; text-shadow: 0 0 0 var(--smoke-col, #fff); opacity: 1; }
}

/* From Uiverse.io by KSAplay */
.container input {
  position: absolute;
  opacity: 0;
  cursor: pointer;
  height: 0;
  width: 0;
}

.container {
  display: block;
  position: relative;
  cursor: pointer;
  font-size: 20px;
  user-select: none;
  transition: 100ms;
}

.checkmark {
  top: 0;
  left: 0;
  height: 2em;
  width: 2em;
  transition: 100ms;
  animation: dislike_effect 400ms ease;
}

.container input:checked ~ .checkmark path {
  fill: #ff5353;
  stroke-width: 0;
}

.container input:checked ~ .checkmark {
  animation: like_effect 400ms ease;
}

.container:hover {
  transform: scale(1.1);
}

@keyframes like_effect {
  0% { transform: scale(0); }
  50% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

@keyframes dislike_effect {
  0% { transform: scale(0); }
  50% { transform: scale(1.2); }
  100% { transform: scale(1); }
}

/* fit + clickable inside the now-playing panel; default outline heart */
.container { pointer-events: auto; flex: none; font-size: 13px; line-height: 0; }
.checkmark path { fill: none; stroke: #fff; stroke-width: 2; }
/* suppress animation on programmatic sync (song change) */
.container.no-anim .checkmark { animation: none !important; }

.np__progress {
  display: flex;
  align-items: center;
  gap: 12px;
}
.np__time {
  font-size: 12px;
  color: rgba(255, 255, 255, 0.7);
  font-variant-numeric: tabular-nums;
  min-width: 40px;
}
.np__time:last-child { text-align: right; }
.np__bar {
  position: relative;
  flex: 1;
  height: 4px;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.18);
  cursor: pointer;
  pointer-events: auto;                /* interactive (panel is pointer-events:none) */
  touch-action: none;
  transition: height 120ms ease;
}
/* Enlarged invisible hit area so the thin bar is easy to grab/drag */
.np__bar::before {
  content: "";
  position: absolute;
  inset: -10px 0;
}
.np__bar:hover,
.np__bar:active { height: 6px; }
.np__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  border-radius: 4px;
  background: #fff;
}
.np__fill::after { display: none; }   /* replaced by the liquid-glass lens thumb */

/* Runtime thumb — Maxuiux glass-lens style. At rest it's a solid white pill; while
   the user drags (.is-scrubbing) it turns transparent and becomes a refractive
   liquid lens (#mini-liquid-lens displaces the track/fill behind it) with a specular
   rim, and squishes. Layers toggle opacity between the two states. */
.np__thumb {
  position: absolute;
  right: 0; top: 50%;
  width: 28px; height: 14px;
  transform: translate(50%, -50%);
  border-radius: 999px;
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
  background-color: #fff;
  box-shadow: 0 1px 6px 0 rgba(0, 30, 63, 0.30), 0 0 2px 0 rgba(0, 9, 20, 0.35);
  opacity: 0;                       /* hidden until the bar is hovered / being dragged */
  transition: transform 0.15s ease, box-shadow 0.15s ease,
              background-color 0.15s ease, opacity 0.15s ease;
}
.np__bar:hover .np__thumb,
.np__thumb.is-scrubbing { opacity: 1; }
.np__thumb-filter,
.np__thumb-overlay,
.np__thumb-specular {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: 0;
}
.np__thumb-filter {
  z-index: 0;
  backdrop-filter: blur(0.6px);
  -webkit-backdrop-filter: blur(0.6px);
  filter: url(#mini-liquid-lens);
}
.np__thumb-overlay {
  z-index: 1;
  background-color: rgba(255, 255, 255, 0.1);
}
.np__thumb-specular {
  z-index: 2;
  box-shadow:
    inset 1px 1px 0 rgba(120, 190, 255, 0.35),
    inset 1px 3px 0 rgba(28, 63, 90, 0.10),
    inset 0 0 22px rgb(255 255 255 / 55%),
    inset -1px -1px 0 rgba(120, 190, 255, 0.22);
}
/* Dragging: solid pill dissolves into the refractive glass lens + squish. */
.np__thumb.is-scrubbing {
  background-color: transparent;
  box-shadow: none;
  transform: translate(50%, -50%) scaleY(0.96) scaleX(1.08);
}
.np__thumb.is-scrubbing .np__thumb-filter,
.np__thumb.is-scrubbing .np__thumb-overlay,
.np__thumb.is-scrubbing .np__thumb-specular { opacity: 1; }

.np__controls {
  position: relative;                  /* anchor for the right-aligned lyrics button */
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 34px;
  pointer-events: auto;
}

/* Lyrics toggle — sits at the right edge of the controls row so it lands directly
   below the heart, while play/prev/next stay centered. */
.np__lyrics {
  position: absolute;
  right: 0; top: 50%;
  transform: translateY(-50%);
  width: 26px; height: 26px;
  display: grid; place-items: center;
  padding: 0; border: 0; background: none;
  color: rgba(255, 255, 255, 0.72); cursor: pointer;
  pointer-events: auto;
  transition: transform 140ms ease, color 140ms ease, opacity 140ms ease;
}
.np__lyrics svg {
  width: 22px; height: 22px;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
.np__lyrics svg circle { fill: currentColor; stroke: none; }
.np__lyrics:hover { color: #fff; }
.np__lyrics:active { transform: translateY(-50%) scale(0.88); }
.np__lyrics[aria-pressed="true"] { color: #ff5353; }
.np__ctrl {
  display: grid; place-items: center;
  width: 26px; height: 26px;
  padding: 0; border: 0; background: none;
  color: #fff; cursor: pointer;
  transition: transform 140ms ease, opacity 140ms ease;
}
.np__ctrl svg { width: 100%; height: 100%; fill: currentColor; }
.np__ctrl--play { width: 42px; height: 42px; }
.np__ctrl:hover { opacity: 0.82; }
.np__ctrl:active { transform: scale(0.88); }

/* Play / pause icon swap */
.np__ctrl--play .ic-play { display: none; }
.np__ctrl--play .ic-pause { display: block; }
.np__ctrl--play[aria-pressed="false"] .ic-play { display: block; }
.np__ctrl--play[aria-pressed="false"] .ic-pause { display: none; }

/* ============================================================================
   Apple-Music-style synced lyrics — focused 3-line window.
   Shows only three lines at a time: the PREVIOUS line fading out (dim + blurred),
   the CURRENT line sharp and bright, and the NEXT line coming in (dim). The
   current line gooey-morphs from the previous one using the same "morphing text"
   effect as Sable's spoken caption (#vtThreshold goo filter + cross-blur layers).
   The whole stage sits IN PLACE of the CD (frame/discs/overlay fade out).
   ============================================================================ */
.lyrics-stage {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  /* exactly the footprint of the now-playing card / CD frame it replaces */
  width: min(var(--hero), 92vw);
  height: var(--hero);
  z-index: 24;                          /* above frame(10)/discs(20), below arrows */
  overflow: hidden;
  pointer-events: auto;
  opacity: 0;
  transition: opacity 0.4s ease;
  /* fade the top & bottom edges so the leaving/arriving lines dissolve at the rim */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 24%, #000 76%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, #000 24%, #000 76%, transparent 100%);
}
.lyrics-stage[hidden] { display: none; }
/* full view: sit exactly where the CD frame is (bottom-anchored), same size */
body.is-full .lyrics-stage {
  top: auto;
  bottom: 257px;
  transform: translateX(-50%);
}

/* Focused lyric view — EXACTLY the caption's gooey "morphing text" effect.
   The current line sits at the centre and, on each advance, morphs from the
   previous line into the new one using two overlaid layers that cross-blur; the
   #vtThreshold filter fuses the blurred halos into liquid metaballs (identical
   engine to Sable's spoken caption). A faint preview of the next line sits below.
   Font rules: Anton is a display face — used UPPERCASE with open tracking. */
.lyrics-flow {
  position: absolute;
  inset: 0;
  overflow: hidden;
}
.lyr-cur, .lyr-next {
  position: absolute;
  left: 0; right: 0;
  padding: 0 14px;
  text-align: center;
  font-family: "Anton", "Inter", system-ui, -apple-system, sans-serif;
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.035em;
  color: #fff;
  cursor: pointer;
}
/* current line — centred, bright. Font + gap SCALE WITH THE STAGE (--hero) so the
   lyrics shrink with the frame when the window is minimised / on mobile / full view,
   and never spill into the CD frame above or the now-playing card below. */
.lyr-cur {
  top: 50%;
  transform: translateY(-50%);
  font-size: 24px;                 /* normal (not-full) view — the minimised frame */
  line-height: 1.08;
  text-shadow: 0 0 26px rgba(255, 255, 255, 0.22);
}
/* next line — faint hint below the current line */
.lyr-next {
  top: calc(50% + 74px);
  transform: translateY(-50%);
  font-size: 20px;
  line-height: 1.08;
  opacity: 0.32;
  filter: blur(0.6px);
  transition: opacity 0.5s ease;
}
/* full screen: the frame is large, so scale the lyrics up with it */
body.is-full .lyr-cur  { font-size: clamp(28px, calc(var(--hero) * 0.06), 44px); }
body.is-full .lyr-next {
  font-size: clamp(22px, calc(var(--hero) * 0.05), 36px);
  top: calc(50% + var(--hero) * 0.2);
}
.lyr-next:empty { opacity: 0; }

/* the two morph layers — overlaid + cross-blurred, fused by the threshold.
   Threshold is applied ONLY while morphing so the settled line stays crisp. */
.lyr-morph { position: relative; display: block; }
.lyr-morph .m1 { display: block; }
.lyr-morph .m2 { position: absolute; left: 0; right: 0; top: 0; opacity: 0; }
.lyr-morph .m1, .lyr-morph .m2 { will-change: opacity, filter; }
.lyr-morph.is-morphing { filter: url(#vtThreshold) blur(0.6px); }

/* subtle rise as the new line settles (a hint of "coming up" under the morph) */
@keyframes lyr-rise {
  from { transform: translateY(calc(-50% + 15px)); }
  to   { transform: translateY(-50%); }
}
.lyr-cur.is-rising { animation: lyr-rise 0.55s cubic-bezier(0.22, 0.61, 0.36, 1); }

/* plain (un-timed) lyrics fallback — a simple centered readable block */
.lyrics-plain {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 8px;
  padding: 0 16px;
  overflow-y: auto;
  font-family: "Anton", "Inter", system-ui, -apple-system, sans-serif;
  font-size: clamp(19px, 2.1vw, 25px);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.035em;
  line-height: 1.25;
  color: rgba(255, 255, 255, 0.72);
  scrollbar-width: none;
}
.lyrics-plain[hidden] { display: none; }
.lyrics-plain::-webkit-scrollbar { display: none; }
/* Notice shown atop plain (un-timed) lyrics so a non-scrolling track reads as
   "no synced data" rather than "sync is broken". */
.lyr-plain-note {
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  text-transform: none;
  letter-spacing: 0.01em;
  font-size: clamp(12px, 1.1vw, 14px);
  font-weight: 500;
  color: rgba(255, 255, 255, 0.42);
  margin-bottom: 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
  max-width: 40ch;
}

.lyrics-status {
  position: absolute;
  inset: 0;
  display: none;
  place-items: center;
  text-align: center;
  padding: 0 24px;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  font-size: 15px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.55);
  pointer-events: none;
}
.lyrics-stage.is-empty .lyrics-status { display: grid; }
.lyrics-stage.is-empty .lyrics-flow,
.lyrics-stage.is-empty .lyrics-plain { display: none; }
.lyrics-stage.is-plain .lyrics-flow { display: none; }

/* ---- toggle: swap CD frame <-> lyrics ---- */
.player__frame,
.player__track,
.player__overlay { transition: opacity 0.4s ease; }
.player.show-lyrics .player__frame,
.player.show-lyrics .player__track,
.player.show-lyrics .player__overlay {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s ease;
}
.player.show-lyrics .lyrics-stage { opacity: 1; }

/* ---------------- Arrows ---------------- */
.player__arrow {
  position: absolute;
  top: 50%;
  z-index: 80;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  color: #fff;
  cursor: pointer;
  transform: translateY(-50%);
  transition: background 200ms ease, transform 160ms ease, border-color 200ms ease;
}
.player__arrow:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.32); }
.player__arrow:active { transform: translateY(-50%) scale(0.92); }
.player__arrow--prev { left: 16px; }
.player__arrow--next { right: 16px; }
.player__arrow svg {
  width: 20px; height: 20px;
  fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}

/* ---------------- Dots ---------------- */
.player__dots {
  position: absolute;
  bottom: 2px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 9px;
  z-index: 80;
}
.player__dots button {
  width: 7px; height: 7px;
  padding: 0; border: none; border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
  cursor: pointer;
  transition: background 220ms ease, width 220ms ease, border-radius 220ms ease;
}
.player__dots button.is-active {
  width: 22px; border-radius: 4px;
  background: #fff;
}

/* ---------------- Immersive backdrop (full view) ---------------- */
.stage-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  background-position: center;
  background-size: cover;
  filter: blur(50px) brightness(0.42) saturate(1.25);
  transform: scale(1.25);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.6s ease;
}
.stage-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 42%, transparent 28%, rgba(0, 0, 0, 0.6) 100%);
}
body.is-full .stage-bg { opacity: 1; }

/* ---------------- Effect picker (top-right, below the + , icon-only) ---------------- */
.fx-picker {
  position: fixed;
  top: 76px;
  right: 20px;
  z-index: 95;
}
.fx-toggle {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(20, 22, 28, 0.5);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.fx-toggle:hover { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.3); }
.fx-toggle:active { transform: scale(0.92); }
.fx-ic { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.fx-picker.is-open .fx-toggle { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.32); }

.fx-menu {
  position: absolute;
  top: 0;
  right: calc(100% + 8px);   /* fly out to the left of the icon */
  min-width: 156px;
  max-height: 320px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px;
  border-radius: 20px;
  background: rgba(24, 26, 32, 0.92);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  backdrop-filter: blur(20px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 20px 50px -16px rgba(0, 0, 0, 0.7);
  transform-origin: top left;
  animation: fx-pop 0.16s ease;
}
.fx-menu[hidden] { display: none; }      /* respect the hidden attr (chevron closed) */
@keyframes fx-pop { from { opacity: 0; transform: translateY(-6px) scale(0.97); } }
.fx-opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  text-align: left;
  padding: 9px 12px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: rgba(255, 255, 255, 0.78);
  font: 500 13px/1 "Inter", system-ui, sans-serif;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.fx-opt:hover { background: rgba(255, 255, 255, 0.08); color: #fff; }
.fx-opt.is-active { color: #fff; }
.fx-opt.is-active::after { content: "✓"; font-size: 12px; color: #fff; }

/* ---------------- Frame switcher (top-right, below the playlist icon) ---------------- */
.frame-picker {
  position: fixed;
  top: 188px;
  right: 20px;
  z-index: 94;
}

/* ---------------- Voice control mic (bottom-right, aligned with the full-view button) ---------------- */
.mic-btn {
  position: fixed;
  bottom: 24px;
  right: 20px;
  z-index: 122;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(20, 22, 28, 0.6);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.mic-btn:hover { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.3); }
.mic-btn:active { transform: scale(0.92); }
/* "Hey Maya" wake mode active (toggled by LONG-PRESSING the mic) — a pulsing sonar
   ripple radiating from the button. Only shown while armed; the plain push-to-talk
   click uses the calm static teal state below (no ripple). */
.mic-btn.wake-on { border-color: rgba(39, 229, 243, 0.55); }
.mic-btn.wake-on::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-color: #27e5f3;
  z-index: -1;
  animation: mic-listening 1.3s ease-out infinite;
}
@keyframes mic-listening {
  from { transform: scale(1); opacity: 0.3; }
  to   { transform: scale(2); opacity: 0; }
}
.mic-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Listening = a calm static teal state (no ripple animation) */
.mic-btn.is-listening {
  background: rgba(41, 115, 115, 0.55);
  border-color: #297373;
  color: #dff5f5;
}

/* Voice status toast (transcript + blob/icon), bottom-center */
.voice-toast {
  position: fixed;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%) translateY(10px) scale(0.96);
  z-index: 120;
  height: 40px;                              /* Figma 78:211/212 — fixed frame height */
  max-width: min(220px, 92vw);               /* max-width 220 */
  box-sizing: border-box;
  padding: 7px 17px;                         /* Figma px-17 py-7 */
  border-radius: 999px;
  background: rgba(18, 20, 26, 0.92);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  backdrop-filter: blur(14px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 16px 40px -14px rgba(0, 0, 0, 0.7);
  color: #fff;
  font: 500 13px/16.9px "Inter", system-ui, sans-serif;
  letter-spacing: -0.0762px;
  display: flex;
  align-items: center;
  gap: 7px;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.34s cubic-bezier(0.22, 1, 0.36, 1), transform 0.42s cubic-bezier(0.22, 1, 0.36, 1);
}
.voice-toast.is-show { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
.voice-toast[hidden] { display: none; }
.voice-toast { overflow: hidden; }        /* keep all content clipped inside the pill */
.voice-toast .vt-text {
  width: 153px; height: 20px; flex: none; position: relative; overflow: hidden; white-space: nowrap;
}
/* While listening: fixed-width pill. Each spoken word spawns at the right, then slides
   LEFT and fades out (opacity -> 0), like the reference Z animation mirrored to go left. */
.voice-toast.listening .vt-text {
  width: 153px;
  height: 20px;
  position: relative;
  overflow: hidden;         /* clip the typed + flying characters to the chip */
  text-overflow: clip;
}
/* The transcript is typed out char-by-char, right-anchored (newest at the right edge) */
.vt-line {
  position: absolute;
  left: 0;
  top: 0;
  line-height: 20px;
  white-space: nowrap;
  transition: transform 0.34s cubic-bezier(0.22, 1, 0.36, 1);   /* buttery iOS glide */
  will-change: transform;
}
/* Each new character materialises in — soft blur + rise + scale (iOS style) */
.vt-line > span { display: inline-block; animation: charIn 0.36s cubic-bezier(0.22, 1, 0.36, 1) both; }
@keyframes charIn {
  from { opacity: 0; transform: translateY(5px) scale(0.85); filter: blur(2.5px); }
  to   { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}
/* An overflowed character detaches and floats up-and-LEFT, gently expanding + blurring as it
   dissolves away — like a Z drifting off, tuned to feel like iOS. */
.vt-fly {
  position: absolute;
  top: 0;
  line-height: 20px;
  white-space: pre;
  animation: charDrift 0.7s cubic-bezier(0.22, 1, 0.36, 1) forwards;
  will-change: transform, opacity, filter;
}
/* the overflowed character dissolves at the left edge (clipped by the chip) */
@keyframes charDrift {
  0%   { transform: translate(0, 0) scale(1); opacity: 1; filter: blur(0); }
  100% { transform: translate(-12px, -4px) scale(0.82); opacity: 0; filter: blur(1.5px); }
}
.voice-toast .vt-ic { color: #ff5f70; flex: none; }
.voice-toast .vt-ic:empty { display: none; }

/* Sable speaking (Figma 78:212): teal text on the single-line frame */
.voice-toast.sable .vt-text { color: #256060; }

/* --- EXACT reference morph, TWO words per unit: two centered overlapping layers cross-blur
   into the next pair, the threshold fuses the overlap into liquid blobs. Rendered at 64px
   (thick strokes so the goo survives) then scaled to 16px. 612×80 × 0.25 ≈ the 153×20 slot. */
.vt-morph {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 612px;
  height: 80px;
  transform: translate(-50%, -50%) scale(0.25);   /* 612×80 × 0.25 ≈ 153×20; ~16px display */
  transform-origin: center center;
  filter: url(#vtThreshold) blur(0.6px);           /* reference: threshold + blur(0.6px) */
}
.vt-morph .m1,
.vt-morph .m2 {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;      /* two words, centered */
  white-space: nowrap;
  font-size: 64px;              /* fat strokes so the blurred blob survives the threshold (goo) */
  font-weight: 700;
  letter-spacing: -1px;
  color: inherit;               /* teal via .voice-toast.sable .vt-text, else white */
  will-change: opacity, filter;
}

/* Rive blob as the pill's leading icon (Figma 80:227/228) */
.vt-blob {
  display: none;
  flex: none;
  position: relative;
  width: 26px;
  height: 26px;
  overflow: hidden;                 /* clip the oversized canvas so the blob fills the frame */
  border-radius: 13px;
}
.vt-blob canvas {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 164px;                     /* zoom into the centre so the white artboard ring is cropped out */
  height: 164px;
  display: block;
}
/* The Rive blob is the chip's icon in every state (listening / searching / playing) */
.voice-toast.has-blob .vt-blob { display: inline-block; }
.voice-toast.has-blob .vt-ic { display: none; }

/* No listening animation — the mic icon stays visible; the button just turns teal. */
.mic-btn .loader { display: none; }
.mic-btn.is-listening .loader { display: none; }

/* Listening ripple (Uiverse.io by Smit-Prajapati) — red, no logo, sized for the mic button */
.loader {
  --size: 34px;
  --duration: 1.8s;
  --wave: 255, 255, 255;             /* white — matches the app's controls */
  height: var(--size);
  aspect-ratio: 1;
  position: relative;
}
.loader .box {
  position: absolute;
  background: linear-gradient(0deg, rgba(255, 255, 255, 0.05) 0%, rgba(255, 255, 255, 0.12) 100%);
  border-radius: 50%;
  border-top: 1.5px solid rgba(var(--wave), 1);
  box-shadow: rgba(0, 0, 0, 0.35) 0 2px 4px 0;
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  animation: ripple-mic var(--duration) infinite ease-in-out;
}
.loader .box:nth-child(1) { inset: 40%; z-index: 99; }
.loader .box:nth-child(2) { inset: 30%; z-index: 98; border-top-color: rgba(var(--wave), 0.8); animation-delay: 0.18s; }
.loader .box:nth-child(3) { inset: 20%; z-index: 97; border-top-color: rgba(var(--wave), 0.6); animation-delay: 0.36s; }
.loader .box:nth-child(4) { inset: 10%; z-index: 96; border-top-color: rgba(var(--wave), 0.45); animation-delay: 0.54s; }
.loader .box:nth-child(5) { inset: 0%;  z-index: 95; border-top-color: rgba(var(--wave), 0.3); animation-delay: 0.72s; }
.loader .logo { display: none; }     /* remove the Uiverse logo */
@keyframes ripple-mic {
  0%, 100% { transform: scale(1); box-shadow: rgba(0, 0, 0, 0.35) 0 1px 3px 0; }
  50% { transform: scale(1.22); box-shadow: rgba(0, 0, 0, 0.35) 0 3px 5px 0; }
}
.frame-picker.is-open .fx-toggle { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.32); }

/* ---------------- Playlist selector (top-right, below the effect icon, icon-only) ---------------- */
.pl-picker {
  position: fixed;
  top: 132px;
  right: 20px;
  z-index: 96;
}
.pl-toggle {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(20, 22, 28, 0.5);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.pl-toggle:hover { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.3); }
.pl-toggle:active { transform: scale(0.92); }
.pl-ic { width: 22px; height: 22px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.pl-picker.is-open .pl-toggle { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.32); }

.pl-menu {
  position: absolute;
  top: 0;
  right: calc(100% + 8px);   /* fly out to the left of the icon */
  width: 240px;
  border-radius: 20px;
  background: rgba(24, 26, 32, 0.94);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
  backdrop-filter: blur(20px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 20px 50px -16px rgba(0, 0, 0, 0.7);
  overflow: hidden;
  animation: fx-pop 0.16s ease;
}
.pl-menu[hidden] { display: none; }
.pl-list { max-height: 260px; overflow-y: auto; padding: 6px; display: flex; flex-direction: column; gap: 2px; }
.pl-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 9px 12px;
  border: 0;
  border-radius: 9px;
  background: transparent;
  color: rgba(255, 255, 255, 0.82);
  font: 500 13.5px/1.2 "Inter", system-ui, sans-serif;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s ease;
}
.pl-item:hover { background: rgba(255, 255, 255, 0.08); }
.pl-item.is-active { color: #fff; }
.pl-item.is-active::after { content: "✓"; font-size: 12px; }
.pl-item__meta { min-width: 0; }
.pl-item__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pl-item__count { font-size: 11px; color: rgba(255, 255, 255, 0.45); margin-top: 2px; }
.pl-item__del {
  flex: none; width: 22px; height: 22px; display: grid; place-items: center;
  border: 0; border-radius: 6px; background: transparent; color: rgba(255,255,255,0.4);
  cursor: pointer; font-size: 15px; line-height: 1;
}
.pl-item__del:hover { background: rgba(255, 80, 80, 0.2); color: #ff6b6b; }

.pl-create { display: flex; gap: 6px; padding: 8px; border-top: 1px solid rgba(255, 255, 255, 0.08); }
.pl-create input {
  flex: 1; min-width: 0; height: 34px; padding: 0 10px;
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 9px;
  background: rgba(255, 255, 255, 0.06); color: #fff; font-size: 13px; outline: 0;
}
.pl-create input:focus { border-color: rgba(255, 255, 255, 0.28); }
.pl-createbtn {
  flex: none; width: 34px; height: 34px; border: 0; border-radius: 9px;
  background: #fff; color: #111; font-size: 18px; line-height: 1; cursor: pointer;
}

/* ---------------- "Add to playlist" chooser ---------------- */
.pladd-overlay {
  position: fixed; inset: 0; z-index: 110;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0; transition: opacity 0.22s ease;
}
.pladd-overlay.is-open { opacity: 1; }
.pladd {
  position: fixed;
  z-index: 111;
  top: 50%; left: 50%;
  width: min(340px, 92vw);
  max-height: 70vh;
  display: flex; flex-direction: column;
  border-radius: 24px;
  background: rgba(26, 28, 34, 0.98);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  backdrop-filter: blur(24px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.75);
  color: #fff;
  font-family: "Inter", system-ui, sans-serif;
  transform: translate(-50%, -50%) scale(0.94);
  opacity: 0;
  transition: transform 0.24s cubic-bezier(0.22, 0.7, 0.3, 1), opacity 0.24s ease;
}
.pladd.is-open { transform: translate(-50%, -50%) scale(1); opacity: 1; }
/* CRITICAL: `.pladd { display:flex }` overrides the UA `[hidden]{display:none}`, so a
   CLOSED .pladd modal (room/Spotify/add) stays laid out at opacity:0 and, being
   position:fixed + centered, silently swallows clicks meant for whatever is open
   beneath it (e.g. tapping a playlist row in the add-to-playlist chooser). Force
   hidden modals + their overlays out of the layout so they can't intercept. */
.pladd[hidden], .pladd-overlay[hidden] { display: none !important; }
.pladd__head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 16px 10px; font-size: 15px; font-weight: 600;
}
.pladd__close {
  width: 28px; height: 28px; display: grid; place-items: center;
  border: 0; border-radius: 8px; background: rgba(255, 255, 255, 0.08);
  color: #fff; cursor: pointer;
}
.pladd__close svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.pladd__new { display: flex; gap: 6px; padding: 0 14px 10px; }
.pladd__new input {
  flex: 1; min-width: 0; height: 38px; padding: 0 12px;
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 10px;
  background: rgba(255, 255, 255, 0.06); color: #fff; font-size: 14px; outline: 0;
}
.pladd__new input:focus { border-color: rgba(255, 255, 255, 0.28); }
.pladd__newbtn {
  flex: none; height: 38px; padding: 0 12px; border: 0; border-radius: 10px;
  background: #fff; color: #111; font-weight: 600; font-size: 13px; cursor: pointer; white-space: nowrap;
}
.pladd__list {
  overflow-y: auto; padding: 4px 8px 12px;
  display: flex; flex-direction: column; gap: 2px;
}
.pladd__item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 12px; border: 0; border-radius: 10px;
  background: transparent; color: #fff; cursor: pointer; text-align: left;
  transition: background 0.15s ease;
}
.pladd__item:hover { background: rgba(255, 255, 255, 0.08); }
.pladd__name { font-size: 14px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pladd__meta { flex: none; font-size: 12px; color: rgba(255, 255, 255, 0.5); }
.pladd__item.is-in .pladd__meta { color: #2ec45f; }

/* ---------------- Mobile FAB Toggle ---------------- */
.mobile-fab { display: none; }

/* ---------------- Add-song button (top-right) ---------------- */
.add-btn {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 95;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 50%;
  background: rgba(20, 22, 28, 0.5);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease, border-color 0.2s ease;
}
.add-btn:hover { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.32); }
.add-btn:active { transform: scale(0.92); }
.add-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

/* ---------------- Add-song sheet (right side) ---------------- */
.sheet-overlay {
  position: fixed;
  inset: 0;
  z-index: 99;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.sheet-overlay.is-open { opacity: 1; }

.sheet {
  position: fixed;
  top: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 100;
  width: min(390px, 92vw);
  display: flex;
  flex-direction: column;
  border-radius: 26px;
  background: rgba(22, 24, 30, 0.92);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  backdrop-filter: blur(24px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.7);
  color: #fff;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  transform: translateX(calc(100% + 24px));
  transition: transform 0.36s cubic-bezier(0.22, 0.7, 0.3, 1);
  overflow: hidden;
}
.sheet.is-open { transform: translateX(0); }

.sheet__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 18px 10px;
}
.sheet__title { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -0.01em; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sheet__headbtns { flex: none; display: flex; gap: 8px; margin-left: 10px; }
#plSheetDelete:hover { background: rgba(255, 80, 80, 0.22); color: #ff6b6b; }
.sheet__close {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 0; border-radius: 8px; background: rgba(255, 255, 255, 0.08);
  color: #fff; cursor: pointer; transition: background 0.2s ease;
}
.sheet__close:hover { background: rgba(255, 255, 255, 0.16); }
.sheet__close svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.sheet__search {
  position: relative;
  display: flex;
  align-items: center;
  margin: 4px 18px 8px;
  padding: 0 10px;
  height: 42px;
  border-radius: 11px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.1);
}
.sheet__search:focus-within { border-color: rgba(255, 255, 255, 0.28); }
.sheet__search-ic { width: 17px; height: 17px; flex: none; fill: none; stroke: rgba(255,255,255,0.55); stroke-width: 2; stroke-linecap: round; }
.sheet__search input {
  flex: 1;
  min-width: 0;
  margin: 0 6px;
  border: 0; outline: 0; background: none;
  color: #fff; font-size: 14px;
}
.sheet__search input::placeholder { color: rgba(255, 255, 255, 0.4); }
.sheet__clear {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: 6px; background: rgba(255, 255, 255, 0.12);
  color: #fff; cursor: pointer;
}
.sheet__clear svg { width: 12px; height: 12px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.sheet__results {
  flex: 1;
  overflow-y: auto;
  padding: 6px 10px 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.result {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 8px;
  border-radius: 12px;
  cursor: pointer;
  transition: background 0.15s ease;
}
.result:hover { background: rgba(255, 255, 255, 0.07); }
.result__thumb {
  width: 56px; height: 56px; flex: none;
  border-radius: 9px; object-fit: cover;
  background: #2a2e38;
}
.result__meta { flex: 1; min-width: 0; }
.result__title {
  font-size: 13.5px; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.result__artist {
  margin-top: 2px;
  font-size: 12px; color: rgba(255, 255, 255, 0.55);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.result__actions { flex: none; display: flex; gap: 6px; }
.result__btn {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 0; border-radius: 8px;
  background: rgba(255, 255, 255, 0.12);
  color: #fff; cursor: pointer;
  transition: background 0.15s ease, transform 0.12s ease;
}
.result__btn svg { width: 15px; height: 15px; fill: currentColor; stroke: none; }
.result__add svg { fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; }
/* already in a playlist -> filled heart */
.result__add.is-saved svg { fill: #ff5353; stroke: none; }
.result__btn:hover { background: rgba(255, 255, 255, 0.22); }
.result__btn:active { transform: scale(0.9); }
.result__add.is-added { background: #2ec45f; }
.result__add.is-added svg { display: none; }
/* Adding a song to a playlist requires a Google sign-in — hide both add-to-
   playlist affordances (the search-result "+" and the now-playing heart) for
   logged-out visitors. login.js sets body.is-signed-in only when signed in. */
body:not(.is-signed-in) .result__add,
body:not(.is-signed-in) #heartBtn { display: none !important; }
/* Playing state: swap the play triangle for the green loading wave (Uiverse.io by mrpumps31232) */
.loading-wave {
  display: none;
  align-items: flex-end;
  justify-content: center;
  height: 18px;
}
.loading-bar {
  width: 2.5px;
  height: 3px;
  margin: 0 1px;
  background-color: #2ec45f;   /* green */
  border-radius: 2px;
  animation: loading-wave-animation 1s ease-in-out infinite;
}
.loading-bar:nth-child(2) { animation-delay: 0.1s; }
.loading-bar:nth-child(3) { animation-delay: 0.2s; }
.loading-bar:nth-child(4) { animation-delay: 0.3s; }
@keyframes loading-wave-animation {
  0% { height: 3px; }
  50% { height: 16px; }
  100% { height: 3px; }
}
/* Same 30x30 button as the play icon — just swap the triangle for the wave */
.result.is-playing .result__play { background: rgba(255, 255, 255, 0.08); overflow: visible; }
.result.is-playing .result__playic { display: none; }
.result.is-playing .loading-wave { display: flex; }

/* remove-from-playlist button (playlist drawer) */
.result__remove svg { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.result__remove:hover { background: rgba(255, 80, 80, 0.22); color: #ff6b6b; }

/* Playlist drawer: tab strip to switch / create playlists */
.pl-tabs {
  display: flex; gap: 6px; flex-wrap: nowrap;
  padding: 12px 16px 6px; overflow-x: auto; scrollbar-width: none;
}
.pl-tabs::-webkit-scrollbar { display: none; }
.pl-tab {
  flex: none; padding: 6px 13px; border: 0; border-radius: 999px;
  background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.72);
  font: 500 13px/1 "Inter", system-ui, sans-serif; cursor: pointer; white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease;
}
.pl-tab:hover { background: rgba(255, 255, 255, 0.15); color: #fff; }
.pl-tab.is-active { background: #fff; color: #16181d; }
.pl-tab--new { font-weight: 600; }
.pl-newinput {
  flex: none; width: 140px; padding: 6px 12px; border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.24); background: rgba(0, 0, 0, 0.28);
  color: #fff; font: 500 13px/1 "Inter", system-ui, sans-serif; outline: none;
}
.pl-newinput::placeholder { color: rgba(255, 255, 255, 0.4); }

.sheet__state {
  padding: 22px 14px;
  text-align: center;
  color: rgba(255, 255, 255, 0.5);
  font-size: 13px;
  line-height: 1.5;
}
.sheet__spinner {
  width: 22px; height: 22px; margin: 0 auto 10px;
  border: 2px solid rgba(255, 255, 255, 0.2);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.sheet__settings {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding: 12px 18px 16px;
  font-size: 12px;
}
.sheet__settings summary { cursor: pointer; color: rgba(255, 255, 255, 0.6); list-style: none; }
.sheet__settings summary::-webkit-details-marker { display: none; }
.sheet__key { display: flex; gap: 6px; margin-top: 10px; }
.sheet__key input {
  flex: 1; min-width: 0;
  height: 34px; padding: 0 10px;
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 9px;
  background: rgba(255, 255, 255, 0.06); color: #fff; font-size: 13px; outline: 0;
}
.sheet__keybtn {
  height: 34px; padding: 0 14px;
  border: 0; border-radius: 9px;
  background: #fff; color: #111; font-weight: 600; font-size: 13px; cursor: pointer;
}
.sheet__hint { margin: 9px 0 0; color: rgba(255, 255, 255, 0.4); line-height: 1.5; }

/* ---------------- Full-view toggle (floating, bottom-right) ---------------- */
.view-toggle {
  position: fixed;
  right: 20px;
  bottom: 84px;            /* sits above the Agentation toolbar */
  z-index: 95;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 50%;
  background: rgba(20, 22, 28, 0.5);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease, border-color 0.2s ease;
}
.view-toggle:hover { background: rgba(40, 44, 54, 0.8); border-color: rgba(255, 255, 255, 0.3); }
.view-toggle:active { transform: scale(0.92); }
.view-toggle svg {
  width: 20px; height: 20px;
  fill: none; stroke: currentColor;
  stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.view-toggle .ic-collapse { display: none; }
body.is-full .view-toggle .ic-expand { display: none; }
body.is-full .view-toggle .ic-collapse { display: block; }

/* ---------------- Full view layout ---------------- */
body.is-full { --hero: min(72vmin, calc(100dvh - 294px)); }
body.is-full .player { height: 100dvh; }
/* Bottom-anchored stack (bottom-up): 24 pad, chip(40), 40 gap, panel, 24 gap, case */
body.is-full .nowplaying {
  top: auto;
  bottom: 104px;                 /* 24 pad + 40 chip + 40 gap below the transport row */
}
body.is-full .player__frame,
body.is-full .player__track {
  top: auto;
  bottom: 257px;                 /* 104 panel-bottom + ~129 panel + 24 gap */
  transform: translateX(-50%);
}
body.is-full .player__arrow { opacity: 0; pointer-events: none; }

/* Full view: caption/mic pill sits at the very bottom-center, 40px below the
   transport buttons (which end at bottom:104px). Pill is 40px tall + 24px pad. */
body.is-full .voice-toast {
  bottom: 24px;
}

/* Small visible YouTube player tucked in a corner (ToS: keep it visible) */
/* ---------- Source switch: YouTube <-> Spotify ---------- */
/* Liquid-glass segmented control — ported from the freefrontend "Liquid Glass
   Switcher" reference. The material is built entirely from a STACK of inset
   box-shadows tuned by two reflex knobs (--glass-reflex-light / -dark) mixed with
   color-mix(), over a faint glass tint. liquidglass.js layers the real backdrop
   refraction (#liquid-glass) on top via an inline backdrop-filter; the -webkit-
   line is the frost-only fallback for engines without SVG backdrop-filter. */
.source-switch {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 95;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border: none;
  border-radius: 99em;
  --c-glass: #bbbbbc;
  --c-light: #fff;
  --c-dark: #000;
  --glass-reflex-light: 0.55;   /* tuned up from the ref's dark 0.3 so the rim reads on our dark bg */
  --glass-reflex-dark: 2;
  --saturation: 150%;
  background-color: color-mix(in srgb, var(--c-glass) 12%, transparent);
  -webkit-backdrop-filter: blur(8px) saturate(var(--saturation));
  backdrop-filter: blur(8px) saturate(var(--saturation));
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 10%), transparent),
    inset 1.8px 3px 0px -2px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 90%), transparent),
    inset -2px -2px 0px -2px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 80%), transparent),
    inset -3px -8px 1px -6px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 60%), transparent),
    inset -0.3px -1px 4px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 12%), transparent),
    inset -1.5px 2.5px 0px -2px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 20%), transparent),
    inset 0px 3px 4px -2px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 20%), transparent),
    inset 2px -6.5px 1px -4px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 10%), transparent),
    0px 1px 5px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 10%), transparent),
    0px 6px 16px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 8%), transparent);
  transition: background-color 400ms cubic-bezier(1, 0, 0.4, 1),
              box-shadow 400ms cubic-bezier(1, 0, 0.4, 1);
}
.src-btn {
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: transparent; cursor: pointer;
  opacity: 0.42; filter: grayscale(0.7);
  transition: opacity 0.18s ease, filter 0.18s ease, background 0.18s ease, transform 0.12s ease;
}
.src-btn svg { width: 22px; height: 22px; display: block; }
.src-btn:hover { opacity: 0.8; filter: grayscale(0.2); }
.src-btn:active { transform: scale(0.9); }
.src-btn { position: relative; z-index: 1; }        /* icons sit under the glass lens */
.src-btn.is-active { opacity: 1; filter: none; background: transparent; }  /* lens replaces the flat highlight */

/* Selection capsule — the reference's ::after glass pill. It sits BEHIND the icons
   (z-index 0) as a brighter glass segment, its own reflex box-shadow stack, and
   slides between segments on the reference's cubic-bezier(1,0,0.4,1) easing while
   squashing horizontally toward its travel direction (srcSquash, driven by JS). */
.src-thumb {
  position: absolute;
  top: 4px; left: 4px;
  width: 34px; height: 34px;
  border-radius: 99em;
  z-index: 0;
  pointer-events: none;
  background-color: color-mix(in srgb, var(--c-glass) 36%, transparent);
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 10%), transparent),
    inset 2px 1px 0px -1px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 90%), transparent),
    inset -1.5px -1px 0px -1px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 80%), transparent),
    inset -2px -6px 1px -5px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 60%), transparent),
    inset -1px 2px 3px -1px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 20%), transparent),
    inset 0px -4px 1px -2px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 10%), transparent),
    0px 3px 6px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 8%), transparent);
  transition: transform 0.44s cubic-bezier(1, 0, 0.4, 1);
}
.src-thumb.src-squash { animation: srcSquash 440ms ease; }
@keyframes srcSquash { 0% { scale: 1 1; } 50% { scale: 1.18 1; } 100% { scale: 1 1; } }

/* ---------- Connect Spotify modal ---------- */
.sp-modal__body { padding: 4px 4px 6px; display: flex; flex-direction: column; gap: 10px; }
.sp-hint { margin: 0; font-size: 12.5px; line-height: 1.5; color: rgba(255, 255, 255, 0.62); }
.sp-hint b { color: rgba(255, 255, 255, 0.9); font-weight: 600; }
.sp-redirect {
  display: block; padding: 8px 10px; border-radius: 8px;
  background: rgba(0, 0, 0, 0.35); border: 1px solid rgba(255, 255, 255, 0.12);
  font: 500 12px/1.3 ui-monospace, "SF Mono", Menlo, monospace; color: #1ED760;
  word-break: break-all; user-select: all;
}
.sp-input {
  padding: 10px 12px; border-radius: 9px;
  border: 1px solid rgba(255, 255, 255, 0.18); background: rgba(0, 0, 0, 0.28);
  color: #fff; font-size: 13px; outline: none;
}
.sp-input:focus { border-color: rgba(30, 215, 96, 0.55); }
.sp-connect {
  padding: 11px 14px; border: 0; border-radius: 999px;
  background: #1ED760; color: #05341a; font: 700 14px/1 "Inter", system-ui, sans-serif;
  cursor: pointer; transition: transform 0.12s ease, filter 0.15s ease;
}
.sp-connect:hover { filter: brightness(1.06); }
.sp-connect:active { transform: scale(0.97); }
.sp-connect:disabled { opacity: 0.5; cursor: default; }
.sp-status { margin: 0; font-size: 12px; line-height: 1.4; color: rgba(255, 255, 255, 0.6); min-height: 14px; }
.sp-status.is-err { color: #ff7676; }
.sp-status.is-ok { color: #1ED760; }

/* YouTube audio player: kept full-size (so audio plays) but parked offscreen — no visible badge */
#yt-host {
  position: fixed;
  left: -10000px;
  bottom: 0;
  width: 220px;
  height: 130px;
  overflow: hidden;
  z-index: 0;
  pointer-events: none;
}
#yt-host iframe { position: absolute; top: 0; left: 0; width: 220px; height: 130px; border: 0; }

@media (max-width: 600px) {
  :root { --hero: calc(100vw - 48px); --side-rotate: 16deg; }
  .player { height: 100dvh; }
  .player__arrow { width: 40px; height: 40px; }

  /* Hide view-toggle on mobile */
  .view-toggle { display: none !important; }

  /* Bottom right mic-btn */
  .mic-btn { bottom: 24px; left: auto; right: 20px; }

  /* Mobile FAB Toggle */
  .mobile-fab {
    display: grid;
    position: fixed;
    bottom: 24px;
    left: 20px;
    z-index: 100;
    width: 46px;
    height: 46px;
    border: 1px solid rgba(255, 255, 255, 0.16);
    border-radius: 50%;
    background: rgba(20, 22, 28, 0.8);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    cursor: pointer;
    color: #fff;
  }
  .mobile-fab svg { transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); width: 24px; height: 24px; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; fill: none; }
  body.fab-active .mobile-fab svg { transform: rotate(45deg); }

  /* FAB Menu Items: stacked above the FAB but hidden and scaled down */
  .add-btn, .fx-picker, .pl-picker, .frame-picker, .room-btn {
    top: auto;
    bottom: 24px;
    left: 20px;
    right: auto;
    opacity: 0;
    pointer-events: none;
    transform: translateY(0) scale(0.5);
    transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease;
  }
  
  /* When expanded, translate them up to form a column */
  body.fab-active .add-btn { transform: translateY(-60px) scale(1); opacity: 1; pointer-events: auto; }
  body.fab-active .fx-picker { transform: translateY(-116px) scale(1); opacity: 1; pointer-events: auto; }
  body.fab-active .pl-picker { transform: translateY(-172px) scale(1); opacity: 1; pointer-events: auto; }
  body.fab-active .frame-picker { transform: translateY(-228px) scale(1); opacity: 1; pointer-events: auto; }
  body.fab-active .room-btn { transform: translateY(-284px) scale(1); opacity: 1; pointer-events: auto; }

  /* Dropdowns for FAB menu items: fly rightwards */
  .fx-menu, .pl-menu {
    left: calc(100% + 12px);
    right: auto;
    top: auto;
    bottom: 0;
    transform-origin: bottom left;
  }
}

/* ============================================================
   Listening room: launcher, join/create modal, member panel.
   Reuses the .pladd / .add-btn / .sheet visual language.
   ============================================================ */
.room-btn {
  position: fixed;
  top: 244px;           /* in the right-side stack: below the frame, above the mic */
  right: 20px;
  z-index: 95;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 50%;
  background: rgba(20, 22, 28, 0.5);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  backdrop-filter: blur(10px) saturate(140%);
  color: #fff;
  cursor: pointer;
  transition: background 0.2s ease, transform 0.15s ease, border-color 0.2s ease;
}
.room-btn:hover { background: rgba(40, 44, 54, 0.85); border-color: rgba(255, 255, 255, 0.32); }
.room-btn:active { transform: scale(0.92); }
.room-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.room-btn--disabled { opacity: 0.4; }

/* connected -> highlight the launcher */
.room-btn.is-live { background: rgba(46, 196, 95, 0.22); border-color: rgba(46, 196, 95, 0.55); }

/* ---- join / create modal (extends .pladd) ---- */
.room-modal__body { padding: 4px 16px 16px; display: flex; flex-direction: column; gap: 10px; }
.room-input {
  height: 40px; padding: 0 12px; width: 100%;
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 10px;
  background: rgba(255, 255, 255, 0.06); color: #fff; font-size: 14px; outline: 0;
  font-family: inherit;
}
.room-input:focus { border-color: rgba(255, 255, 255, 0.28); }
.room-modal__join { display: flex; gap: 6px; }
.room-modal__join .room-input { flex: 1; min-width: 0; }
.room-join {
  flex: none; height: 40px; padding: 0 16px; border: 0; border-radius: 10px;
  background: #fff; color: #111; font-weight: 600; font-size: 13px; cursor: pointer;
}
.room-modal__or {
  display: flex; align-items: center; text-align: center;
  color: rgba(255, 255, 255, 0.4); font-size: 12px; margin: 2px 0;
}
.room-modal__or::before, .room-modal__or::after {
  content: ""; flex: 1; height: 1px; background: rgba(255, 255, 255, 0.12);
}
.room-modal__or span { padding: 0 10px; }
.room-create {
  height: 40px; border: 1px solid rgba(255, 255, 255, 0.16); border-radius: 10px;
  background: rgba(255, 255, 255, 0.06); color: #fff; font-weight: 600; font-size: 14px; cursor: pointer;
  transition: background 0.15s ease;
}
.room-create:hover { background: rgba(255, 255, 255, 0.12); }
.room-status { margin: 2px 0 0; font-size: 12px; min-height: 16px; color: rgba(255, 255, 255, 0.6); }
.room-status.is-err { color: #ff6b6b; }
.room-status.is-ok { color: #2ec45f; }

/* ---- member panel (Discord-style sidebar, left) ---- */
.room-panel {
  position: fixed;
  top: 12px; left: 12px; bottom: 12px;
  z-index: 100;
  width: min(248px, 82vw);
  display: flex; flex-direction: column;
  border-radius: 26px;
  background: rgba(22, 24, 30, 0.92);
  -webkit-backdrop-filter: blur(24px) saturate(150%);
  backdrop-filter: blur(24px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: 0 30px 80px -20px rgba(0, 0, 0, 0.7);
  color: #fff;
  font-family: "Inter", system-ui, -apple-system, sans-serif;
  transform: translateX(calc(-100% - 24px));
  transition: transform 0.36s cubic-bezier(0.22, 0.7, 0.3, 1);
  overflow: hidden;
}
.room-panel.is-open { transform: translateX(0); }
.room-panel__head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 16px 16px 12px; border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.room-panel__code { display: flex; align-items: center; gap: 8px; min-width: 0; }
.room-panel__label { font-size: 10px; letter-spacing: 0.12em; color: rgba(255, 255, 255, 0.4); font-weight: 700; }
.room-panel__codeval { font-size: 15px; font-weight: 700; letter-spacing: 0.04em; font-variant-ligatures: none; }
.room-panel__copy {
  border: 0; border-radius: 6px; padding: 3px 7px; cursor: pointer;
  background: rgba(255, 255, 255, 0.08); color: rgba(255, 255, 255, 0.7); font-size: 11px;
}
.room-panel__copy:hover { background: rgba(255, 255, 255, 0.16); color: #fff; }
.room-panel__leave {
  flex: none; border: 0; border-radius: 8px; padding: 6px 10px; cursor: pointer;
  background: rgba(255, 80, 80, 0.14); color: #ff6b6b; font-size: 12px; font-weight: 600;
}
.room-panel__leave:hover { background: rgba(255, 80, 80, 0.24); }
.room-panel__members {
  flex: none; max-height: 34%; overflow-y: auto; padding: 8px;
  display: flex; flex-direction: column; gap: 2px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.room-member {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 8px; border-radius: 9px;
}
.room-member:hover { background: rgba(255, 255, 255, 0.05); }
.room-member__av {
  flex: none; width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; font-size: 13px; font-weight: 700;
  background: rgba(255, 255, 255, 0.12); color: #fff;
}
.room-member.is-bot .room-member__av { background: rgba(150, 120, 255, 0.28); color: #cbb8ff; }
.room-member__name {
  font-size: 14px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.room-member.is-self .room-member__name { color: rgba(255, 255, 255, 0.7); }
.room-member.is-bot .room-member__name { color: #cbb8ff; }

/* ---- room chat feed + input ---- */
.room-chat {
  flex: 1; min-height: 0; overflow-y: auto;
  padding: 12px 12px 6px;
  display: flex; flex-direction: column; gap: 10px;
}
.room-msg { display: flex; flex-direction: column; gap: 2px; max-width: 100%; }
.room-msg__who {
  font-size: 11px; font-weight: 700; letter-spacing: 0.01em;
  color: rgba(255, 255, 255, 0.5);
}
.room-msg__text {
  font-size: 13.5px; line-height: 1.45; color: #fff;
  background: rgba(255, 255, 255, 0.06);
  padding: 7px 10px; border-radius: 4px 12px 12px 12px;
  white-space: pre-wrap; word-break: break-word;
}
.room-msg.is-self .room-msg__who { color: rgba(255, 255, 255, 0.7); }
.room-msg.is-self .room-msg__text { background: rgba(255, 255, 255, 0.11); }
.room-msg.is-bot .room-msg__who { color: #cbb8ff; }
.room-msg.is-bot .room-msg__text {
  background: rgba(150, 120, 255, 0.16);
  border: 1px solid rgba(150, 120, 255, 0.22);
}
.room-msg--thinking .room-msg__text { color: rgba(255, 255, 255, 0.6); letter-spacing: 0.15em; animation: room-blink 1.1s ease-in-out infinite; }
.room-msg--system { align-self: center; text-align: center; font-size: 12px; color: rgba(255, 200, 120, 0.9); background: rgba(255, 180, 90, 0.1); border: 1px solid rgba(255, 180, 90, 0.2); padding: 6px 10px; border-radius: 8px; max-width: 92%; }

/* ============================================================
   Siri-style voice conversation chip (bottom-center, fixed size).
   You speak -> grey (#606060); Sable speaks -> teal (#297373).
   ============================================================ */
.convo {
  position: fixed;
  left: 50%;
  bottom: 96px;                  /* Sable's reply sits above the listening pill */
  z-index: 120;
  transform: translateX(-50%) translateY(14px);
  opacity: 0;
  transition: opacity 0.32s ease, transform 0.32s cubic-bezier(0.22, 0.7, 0.3, 1);
  pointer-events: none;
}
.convo.is-open { opacity: 1; transform: translateX(-50%) translateY(0); }
.convo__chip {
  width: 480px;
  max-width: 92vw;
  height: 150px;                 /* fixed height as requested */
  box-sizing: border-box;
  border-radius: 26px;
  padding: 18px 24px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 8px;
  overflow-y: auto;
  background: linear-gradient(135deg, rgba(58, 42, 92, 0.6), rgba(26, 58, 66, 0.6));
  -webkit-backdrop-filter: blur(26px) saturate(160%);
  backdrop-filter: blur(26px) saturate(160%);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 26px 70px -20px rgba(0, 0, 0, 0.65);
  font-family: "Inter", system-ui, -apple-system, sans-serif;
}
.convo__chip::-webkit-scrollbar { width: 0; }        /* clean, no scrollbar */
.convo__you {
  color: #606060;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.35;
}
.convo__you:empty { display: none; }
.convo__sable {
  color: #297373;
  font-size: 22px;
  font-weight: 600;
  line-height: 1.38;
  letter-spacing: -0.01em;
}
.convo__sable:empty { display: none; }
/* smooth word-by-word reveal (staggered by inline animation-delay) */
.convo__sable .w,
.convo__you .w {
  display: inline-block;
  opacity: 0;
  transform: translateY(7px);
  filter: blur(3px);
  animation: convoWordIn 0.34s cubic-bezier(0.22, 0.7, 0.3, 1) forwards;
}
@keyframes convoWordIn {
  to { opacity: 1; transform: translateY(0); filter: blur(0); }
}
@keyframes room-blink { 0%, 100% { opacity: 0.35; } 50% { opacity: 0.9; } }

.room-chat__form {
  flex: none; display: flex; gap: 6px; padding: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.room-chat__input {
  flex: 1; min-width: 0; height: 38px; padding: 0 12px;
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 10px;
  background: rgba(255, 255, 255, 0.06); color: #fff; font-size: 14px; outline: 0;
  font-family: inherit;
}
.room-chat__input:focus { border-color: rgba(255, 255, 255, 0.28); }
.room-chat__send {
  flex: none; width: 38px; height: 38px; display: grid; place-items: center;
  border: 0; border-radius: 10px; background: #fff; color: #111; cursor: pointer;
}
.room-chat__send svg { width: 18px; height: 18px; fill: currentColor; }

/* ============================================================================
   Apple-style Liquid Glass — unified tile treatment for every UI surface.
   Frost (backdrop blur+saturate) + refraction (backdrop url(#liquid-glass) bends
   the background — the "liquid" lensing, Chromium) + specular rim (inset light
   highlights) + a light adaptive tint. Safari/FF fall back to frost (no url()).
   ========================================================================== */
.player__arrow,
.fx-toggle, .fx-menu,
.mic-btn,
.voice-toast,
.pl-toggle, .pl-menu,
.pladd,
.add-btn,
.sheet,
.view-toggle,
.room-btn, .room-panel,
.convo__chip {
  /* Same liquid material as the source switch: a stacked-inset box-shadow reflex
     tuned by --glass-reflex-light / -dark and color-mix(), over a faint glass tint.
     liquidglass.js layers the real #liquid-glass refraction on registered elements;
     the -webkit- line is the frost-only fallback (no SVG backdrop-filter). */
  --c-glass: #bbbbbc;
  --c-light: #fff;
  --c-dark: #000;
  --glass-reflex-light: 0.55;
  --glass-reflex-dark: 2;
  --saturation: 150%;
  background: color-mix(in srgb, var(--c-glass) 12%, transparent) !important;
  border: none;
  -webkit-backdrop-filter: blur(8px) saturate(var(--saturation));
  backdrop-filter: url(#liquid-glass) blur(8px) saturate(var(--saturation));
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 10%), transparent),
    inset 1.8px 3px 0px -2px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 90%), transparent),
    inset -2px -2px 0px -2px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 80%), transparent),
    inset -3px -8px 1px -6px color-mix(in srgb, var(--c-light) calc(var(--glass-reflex-light) * 60%), transparent),
    inset -0.3px -1px 4px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 12%), transparent),
    inset -1.5px 2.5px 0px -2px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 20%), transparent),
    inset 0px 3px 4px -2px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 20%), transparent),
    inset 2px -6.5px 1px -4px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 10%), transparent),
    0px 1px 5px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 10%), transparent),
    0px 6px 16px 0px color-mix(in srgb, var(--c-dark) calc(var(--glass-reflex-dark) * 8%), transparent);
}
/* Hover brighten removed by request: glass elements keep their resting frost on
   hover (no lightening). Press/:active states are unchanged. */

/* ============================================================================
   Liquid Glass — accessibility (Apple HIG). Honor the system settings:
   Reduce Transparency → opaque surfaces; Increase Contrast → stronger edges;
   Reduce Motion → drop the springy/shimmer animation. The JS engine also skips
   generating refraction maps when Reduce Transparency is on (see liquidglass.js).
   ========================================================================== */
@media (prefers-reduced-transparency: reduce) {
  .player__arrow, .fx-toggle, .fx-menu, .mic-btn, .voice-toast, .pl-toggle,
  .pl-menu, .pladd, .add-btn, .sheet, .view-toggle, .source-switch,
  .room-btn, .room-panel, .convo__chip {
    background: rgba(22, 24, 30, 0.97) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    box-shadow: 0 8px 24px -10px rgba(0, 0, 0, 0.7) !important;
  }
  .src-thumb, .np__thumb {
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    background: rgba(255, 255, 255, 0.92) !important;
  }
  .np__thumb-filter { -webkit-backdrop-filter: none !important; backdrop-filter: none !important; filter: none !important; }
}
@media (prefers-contrast: more) {
  .player__arrow, .fx-toggle, .fx-menu, .mic-btn, .voice-toast, .pl-toggle,
  .pl-menu, .pladd, .add-btn, .sheet, .view-toggle, .source-switch,
  .room-btn, .room-panel, .convo__chip {
    background: rgba(18, 20, 26, 0.95) !important;
    border-color: rgba(255, 255, 255, 0.55) !important;
  }
  .np__title, .fx-opt, .pladd__name { color: #fff !important; }
}
@media (prefers-reduced-motion: reduce) {
  .src-thumb, .np__thumb, .voice-toast { transition-duration: 1ms !important; }
  .mic-btn.wake-on::before { animation: none !important; opacity: 0.2 !important; }
  .smoke-line.is-in span, .smoke-line.is-out span { animation-duration: 1ms !important; }
}

/* Liquid Glass — behaviour / motion / interaction.
   A specular sheen that tracks the pointer (--gx/--gy set by liquidglass.js), so
   light appears to play across the glass as you move over it — the "liquid" feel.
   Elements keep their own :active press states. Disabled under Reduce Motion. */
.lg-sheen {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: 2;
  opacity: 0;
  background: radial-gradient(circle 72px at var(--gx, 50%) var(--gy, 12%),
              rgba(255, 255, 255, 0.42), rgba(255, 255, 255, 0.06) 48%, transparent 72%);
  transition: opacity 0.28s ease;
  mix-blend-mode: screen;
}
/* Hover sheen removed by request: no light/frost glow appears when hovering any
   glass element (the .lg-sheen stays at opacity 0). */
/* Gel press: registered glass buttons brighten a touch on press (spring is on the
   buttons already). Scoped to the round tiles so it never overrides positioned
   transforms (arrows/pill use their own). */
.mic-btn:active, .view-toggle:active, .fx-toggle:active,
.pl-toggle:active, .add-btn:active, .room-btn:active { filter: brightness(1.18); }
@media (prefers-reduced-motion: reduce) { .lg-sheen { display: none; } }

/* ============================================================================
   Sign-in drawer — Figma "music" 122:53. Slides in from the LEFT, max 480px.
   Faithful to the design tokens (Manrope / Hanken Grotesk / Spline Sans, colours,
   spacing), adapted into the app's vanilla CSS. The .login-google button is wired
   to Google sign-in in login.js.
   ========================================================================== */
.login-overlay {
  position: fixed; inset: 0; z-index: 199;
  background: rgba(0, 0, 0, 0.55);
  opacity: 0; transition: opacity 0.32s ease;
}
.login-overlay.is-open { opacity: 1; }
.login-overlay[hidden] { display: none; }

.login-drawer {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 200;
  width: min(480px, 100vw);
  display: flex;
  background: #080a0c;
  border-right: 1px solid #000510;
  box-shadow: 2px 2px 24px rgba(37, 96, 96, 0.16), 24px 0 60px -20px rgba(0, 0, 0, 0.7);
  transform: translateX(-100%);
  transition: transform 0.42s cubic-bezier(0.22, 0.7, 0.24, 1);
  will-change: transform;
  overflow-y: auto;
  font-family: "Manrope", "Inter", system-ui, sans-serif;
}
.login-drawer.is-open { transform: translateX(0); }
.login-drawer[hidden] { display: none; }

.login-drawer__close {
  position: absolute; top: 16px; right: 16px; z-index: 2;
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, 0.06); color: rgba(255, 255, 255, 0.7);
  transition: background 0.18s ease, color 0.18s ease;
}
.login-drawer__close:hover { background: rgba(255, 255, 255, 0.12); color: #fff; }
.login-drawer__close svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }

.login-inner {
  flex: 1; min-height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 80px; padding: 48px;
  box-sizing: border-box;
}

/* ---- login card ---- */
.login-card {
  width: 300px; max-width: 100%;
  display: flex; flex-direction: column; align-items: center;
}
.login-logo {
  position: relative; width: 80px; height: 80px; margin-bottom: 14px;
}
.login-logo__glow {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; filter: blur(28px); opacity: 0.35;
  transform: scale(1.05);
  animation: login-glow 8s ease-in-out infinite;
}
@keyframes login-glow { 0%, 100% { transform: scale(1.02) rotate(0deg); opacity: 0.3; } 50% { transform: scale(1.12) rotate(20deg); opacity: 0.45; } }
.login-logo__disc {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain;
}
.login-title {
  margin: 0; font-weight: 500; font-size: 24px; line-height: 28px;
  color: rgba(255, 255, 255, 0.92); text-align: center;
}
.login-sub {
  margin: 8px 0 0; font-weight: 400; font-size: 14px; line-height: 24px;
  color: rgba(255, 255, 255, 0.52); text-align: center;
}
.login-google {
  margin-top: 32px;
  width: 300px; max-width: 100%; height: 40px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  border: 0; border-radius: 8px; cursor: pointer;
  background: #4581ff; color: #fff;
  font-family: inherit; font-weight: 400; font-size: 14px; line-height: 24px;
  transition: background 0.18s ease, transform 0.12s ease, box-shadow 0.18s ease;
}
.login-google:hover { background: #397bff; box-shadow: 0 8px 22px -8px rgba(69, 129, 255, 0.7); }
.login-google:active { transform: scale(0.98); }
.login-google:disabled { opacity: 0.6; cursor: default; }
.login-google__g { width: 17px; height: 16px; display: block; }
.login-rule {
  width: calc(100% - 32px); height: 1px; margin-top: 24px;
  background: rgba(255, 255, 255, 0.06);
}
.login-fine {
  margin: 24px 0 0; text-align: center;
  font-family: "Spline Sans", "Inter", system-ui, sans-serif;
  font-weight: 400; font-size: 11px; line-height: 16.5px;
  color: rgba(255, 255, 255, 0.52);
}

/* ---- quote + listeners ---- */
.login-foot {
  display: flex; flex-direction: column; align-items: center; gap: 22px;
}
.login-quote { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.login-quote__text {
  margin: 0; width: 295px; max-width: 100%; text-align: center;
  font-family: "Hanken Grotesk", "Inter", system-ui, sans-serif;
  font-weight: 400; font-size: 16px; line-height: 23px; letter-spacing: 0.16px;
  color: #256060;
}
.login-quote__by {
  margin: 0; text-align: center;
  font-family: "Hanken Grotesk", "Inter", system-ui, sans-serif;
  font-weight: 400; font-size: 15px; line-height: 22px; letter-spacing: 0.3px;
  color: rgba(82, 82, 82, 0.7);
}
.login-avatars { display: flex; align-items: center; gap: 10.5px; }
.login-av {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  overflow: hidden; flex: none;
}
.login-av__img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
.login-av--ring {
  width: 50px; height: 50px; overflow: visible;
  display: grid; place-items: center;
}
.login-av--ring .login-av__img {
  position: relative; z-index: 1;      /* photo on TOP of the ring backing */
  width: 42px; height: 42px;
}
.login-av__ring {
  position: absolute; inset: 0; z-index: 0; width: 50px; height: 50px;
  transform: rotate(-90deg); animation: login-ring 6s linear infinite;
}
@keyframes login-ring { to { transform: rotate(270deg); } }

@media (prefers-reduced-motion: reduce) {
  .login-logo__glow, .login-av__ring { animation: none; }
  .login-drawer { transition: none; }
}
