:root {
  --bg: #0b0c10;
  --panel: #13151b;
  --panel-2: #191c24;
  --line: #242833;
  --line-2: #2f3442;
  --text: #eceef3;
  --muted: #8b91a1;
  --faint: #5b6172;
  --accent: #ff5d8f;
  --danger: #ff5a5a;
  --ok: #2ed3a0;

  --vocals: #ff5d8f;
  --drums: #ffb02e;
  --bass: #7c6cff;
  --guitar: #2ed3a0;
  --piano: #4cc3ff;
  --other: #c58bff;

  --head-w: 330px;
  --radius: 12px;
  --sans: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  color-scheme: dark;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.45 var(--sans);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
[hidden] { display: none !important; }
button, input, select { font: inherit; color: inherit; }
a { color: inherit; }
svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex: none; }
kbd {
  font: 500 11px/1 var(--mono);
  padding: 3px 5px;
  border-radius: 5px;
  border: 1px solid var(--line-2);
  border-bottom-width: 2px;
  background: var(--panel-2);
  color: var(--text);
}
.muted { color: var(--muted); }
.c-vocals { color: var(--vocals); } .c-drums { color: var(--drums); } .c-bass { color: var(--bass); }
.c-guitar { color: var(--guitar); } .c-piano { color: var(--piano); } .c-other { color: var(--other); }

/* ------------------------------------------------------------------ buttons */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  height: 38px; padding: 0 16px;
  border-radius: 10px;
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  font-weight: 600;
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .05s;
  white-space: nowrap;
}
.btn:hover { background: #222632; border-color: #3a4052; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: default; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: #1a0710; }
.btn-primary:hover { background: #ff79a3; border-color: #ff79a3; }
.btn-danger { color: var(--danger); }
.icon-btn {
  display: grid; place-items: center;
  width: 38px; height: 38px;
  border-radius: 50%;
  border: 1px solid var(--line-2);
  background: transparent;
  cursor: pointer;
  color: var(--muted);
}
.icon-btn:hover { color: var(--text); background: var(--panel-2); }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px;
  border-radius: 999px;
  border: 1px solid var(--line-2);
  background: transparent;
  color: var(--muted);
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
}
.chip svg { width: 16px; height: 16px; }
.chip:hover { color: var(--text); border-color: #3a4052; }
.chip[aria-pressed="true"] { color: #0b0c10; background: var(--text); border-color: var(--text); }
.chip.subtle { border-color: transparent; }
.chip:disabled { opacity: .4; cursor: default; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ------------------------------------------------------------------ top bar */
.topbar {
  display: flex; align-items: center; gap: 28px;
  height: 68px; padding: 0 20px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.brand { display: flex; align-items: center; gap: 10px; font-size: 18px; letter-spacing: -.01em; white-space: nowrap; }
.brand b { font-weight: 700; }
.brand-mark { display: flex; align-items: center; gap: 2px; height: 22px; }
.brand-mark i { display: block; width: 4px; border-radius: 2px; animation: eq 1.4s ease-in-out infinite; }
.brand-mark i:nth-child(1) { background: var(--vocals); height: 10px; animation-delay: -.2s; }
.brand-mark i:nth-child(2) { background: var(--drums); height: 20px; animation-delay: -.6s; }
.brand-mark i:nth-child(3) { background: var(--bass); height: 14px; animation-delay: -.9s; }
.brand-mark i:nth-child(4) { background: var(--guitar); height: 18px; animation-delay: -.4s; }
body:not(.is-playing) .brand-mark i { animation-play-state: paused; }
@keyframes eq { 0%, 100% { transform: scaleY(1); } 50% { transform: scaleY(.45); } }

.add-form { flex: 1; display: flex; gap: 10px; max-width: 900px; }
.url-field {
  flex: 1; display: flex; align-items: center; gap: 10px;
  height: 40px; padding: 0 14px;
  border-radius: 10px;
  border: 1px solid var(--line-2);
  background: var(--bg);
  transition: border-color .15s, box-shadow .15s;
}
.url-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px rgb(255 93 143 / .15); }
.url-field svg { color: var(--faint); }
.url-field input { flex: 1; min-width: 0; border: 0; outline: 0; background: transparent; font-size: 14px; }
.url-field input::placeholder { color: var(--faint); }
#model-select {
  height: 40px; max-width: 220px; padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--line-2);
  background: var(--panel-2);
  cursor: pointer;
}
.add-form .btn { height: 40px; }

/* ------------------------------------------------------------------ layout */
.layout { display: grid; grid-template-columns: 300px 1fr; height: calc(100% - 68px); }
main { overflow: auto; position: relative; }
.view { min-height: 100%; }

/* ------------------------------------------------------------------ sidebar */
.sidebar { border-right: 1px solid var(--line); background: var(--panel); display: flex; flex-direction: column; min-height: 0; }
.sidebar-scroll { flex: 1; overflow: auto; padding-bottom: 12px; }
.side-section + .side-section { border-top: 1px solid var(--line); margin-top: 6px; }
.side-head { display: flex; align-items: center; gap: 8px; padding: 16px 18px 8px; }
.side-head h2 { margin: 0; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.side-head .chip { margin-left: auto; }
.side-sub { margin: 12px 18px 4px; font-size: 11px; letter-spacing: .1em; text-transform: uppercase; color: var(--faint); font-weight: 600; }
.count { font: 12px var(--mono); color: var(--faint); }
.library-list, .side-list { list-style: none; margin: 0; padding: 0 10px; }
.side-empty { color: var(--faint); padding: 0 18px; margin: 4px 0 8px; font-size: 13px; }
.chip.tiny { height: 26px; padding: 0 10px; font-size: 12px; }
.new-playlist { display: flex; gap: 6px; padding: 0 12px 8px; }
.new-playlist input {
  flex: 1; min-width: 0; height: 32px; padding: 0 10px; border-radius: 8px;
  border: 1px solid var(--line-2); background: var(--bg); outline: none;
}
.new-playlist input:focus { border-color: var(--accent); }

.pl-item {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: 10px; cursor: pointer; border: 1px solid transparent;
}
.pl-item:hover { background: var(--panel-2); }
.pl-item.active { background: var(--panel-2); border-color: var(--line-2); }
.pl-item.active::before {
  content: ""; position: absolute; left: -10px; top: 10px; bottom: 10px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--accent);
}
.pl-icon {
  width: 34px; height: 34px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  background: linear-gradient(135deg, rgb(255 93 143 / .25), rgb(124 108 255 / .25));
  color: var(--text);
}
.pl-icon svg { width: 16px; height: 16px; }
.pl-item .info { min-width: 0; flex: 1; }
.pl-item .title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-item .sub { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-item .live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); flex: none; animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .3; } }

/* Now playing (shown when the mixer isn't on screen) */
.now-playing {
  display: flex; align-items: center; gap: 10px;
  margin: 0 10px 10px; padding: 8px;
  border-radius: 12px; background: var(--panel-2); border: 1px solid var(--line-2);
}
.np-play {
  width: 36px; height: 36px; border-radius: 50%; border: 0; flex: none;
  display: grid; place-items: center; background: var(--text); color: var(--bg); cursor: pointer;
}
.np-play svg { width: 16px; height: 16px; fill: currentColor; stroke: none; }
.np-play .i-pause { display: none; }
body.is-playing .np-play .i-play { display: none; }
body.is-playing .np-play .i-pause { display: block; }
.np-info { min-width: 0; flex: 1; text-align: left; background: none; border: 0; cursor: pointer; padding: 0; display: flex; flex-direction: column; }
.np-title { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.np-sub { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

.song-item {
  position: relative;
  display: grid; grid-template-columns: 48px 1fr; gap: 12px; align-items: center;
  padding: 10px; margin-bottom: 2px;
  border-radius: 10px;
  cursor: pointer;
  border: 1px solid transparent;
}
.song-item:hover { background: var(--panel-2); }
.song-item.active { background: var(--panel-2); border-color: var(--line-2); }
.song-item.active::before {
  content: ""; position: absolute; left: -10px; top: 14px; bottom: 14px; width: 3px;
  border-radius: 0 3px 3px 0; background: var(--accent);
}
.song-item .thumb { width: 48px; height: 48px; border-radius: 8px; }
.song-item .info { min-width: 0; }
.song-item .title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.song-item .sub { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.song-item .status { font-size: 12px; margin-top: 4px; display: flex; align-items: center; gap: 6px; color: var(--muted); }
.song-item .status.err { color: var(--danger); }
.song-item .minibar { height: 3px; border-radius: 2px; background: var(--line-2); overflow: hidden; margin-top: 6px; }
.song-item .minibar div { height: 100%; background: var(--accent); transition: width .4s; }
.song-item .dots { display: flex; gap: 3px; margin-top: 6px; }
.song-item .dots i { width: 6px; height: 6px; border-radius: 50%; }
.song-item .del {
  position: absolute; right: 8px; top: 8px;
  opacity: 0;
  width: 26px; height: 26px; border-radius: 7px;
  display: grid; place-items: center;
  background: var(--panel); border: 1px solid var(--line-2);
  color: var(--muted); cursor: pointer;
  font-size: 11px; font-weight: 600;
}
.song-item .del svg { width: 14px; height: 14px; }
.song-item:hover .del, .song-item .del.confirm { opacity: 1; }
.song-item .del:hover { color: var(--danger); }
.song-item .del.confirm { width: auto; padding: 0 8px; color: #fff; background: var(--danger); border-color: var(--danger); }

.thumb { object-fit: cover; background: var(--panel-2); display: block; }
.thumb.placeholder { background: linear-gradient(135deg, #252a36, #15171d); }

/* ------------------------------------------------------------------ welcome */
.welcome { display: grid; place-items: center; padding: 40px; }
.welcome-inner { max-width: 560px; }
.welcome-bars { display: flex; align-items: flex-end; gap: 6px; height: 64px; margin-bottom: 28px; }
.welcome-bars i { width: 14px; border-radius: 7px; background: var(--c); animation: eq 1.6s ease-in-out infinite; }
.welcome-bars i:nth-child(1) { height: 40%; animation-delay: -.3s; }
.welcome-bars i:nth-child(2) { height: 90%; animation-delay: -.8s; }
.welcome-bars i:nth-child(3) { height: 60%; animation-delay: -.1s; }
.welcome-bars i:nth-child(4) { height: 100%; animation-delay: -1.1s; }
.welcome-bars i:nth-child(5) { height: 50%; animation-delay: -.5s; }
.welcome-bars i:nth-child(6) { height: 75%; animation-delay: -.9s; }
.welcome-bars i { transform-origin: bottom; }
.welcome h1 { font-size: 44px; line-height: 1.05; letter-spacing: -.03em; margin: 0 0 16px; }
.welcome p { color: var(--muted); font-size: 16px; margin: 0 0 28px; }
.welcome p b { font-weight: 600; }
.steps { list-style: none; padding: 0; margin: 0; display: grid; gap: 10px; }
.steps li { display: flex; align-items: center; gap: 12px; color: var(--text); }
.steps li span {
  display: grid; place-items: center; width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--line-2); font: 500 12px var(--mono); color: var(--muted);
}

/* --------------------------------------------------------------- processing */
.processing { display: grid; place-items: center; padding: 40px; }
.proc-card { width: min(560px, 100%); background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 24px; }
.proc-head { display: flex; gap: 16px; align-items: center; margin-bottom: 22px; }
.proc-head .thumb { width: 96px; height: 54px; border-radius: 8px; }
.proc-titles { min-width: 0; }
.proc-title { font-size: 18px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bigbar { height: 8px; border-radius: 4px; background: var(--line); overflow: hidden; }
.bigbar > div {
  height: 100%; width: 0;
  background: linear-gradient(90deg, var(--vocals), var(--drums), var(--guitar), var(--piano), var(--bass));
  background-size: 400px 100%;
  transition: width .5s ease;
}
.bigbar.small { height: 4px; width: 220px; }
.stages { list-style: none; padding: 0; margin: 20px 0 0; display: grid; gap: 10px; }
.stages li { display: flex; align-items: center; gap: 10px; color: var(--faint); }
.stages li .mark { width: 18px; height: 18px; border-radius: 50%; border: 1.5px solid var(--line-2); display: grid; place-items: center; }
.stages li .mark svg { width: 12px; height: 12px; stroke-width: 3; }
.stages li .pct { margin-left: auto; font: 12px var(--mono); }
.stages li.done { color: var(--muted); }
.stages li.done .mark { background: var(--ok); border-color: var(--ok); color: #06261c; }
.stages li.active { color: var(--text); }
.stages li.active .mark { border-color: var(--accent); border-top-color: transparent; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.error-box {
  margin-top: 18px; padding: 12px 14px;
  border-radius: 10px; border: 1px solid rgb(255 90 90 / .35); background: rgb(255 90 90 / .08);
  color: #ffb3b3; font-size: 13px; word-break: break-word;
}
.proc-actions { display: flex; gap: 10px; justify-content: flex-end; margin-top: 22px; }

/* -------------------------------------------------------------------- mixer */
.mixer { padding: 24px 28px 28px; max-width: 1600px; }
.song-head { display: flex; align-items: center; gap: 18px; margin-bottom: 20px; }
.song-head .thumb { width: 112px; height: 63px; border-radius: 10px; }
.song-titles { flex: 1; min-width: 0; }
.song-titles h1 { margin: 0; font-size: 24px; letter-spacing: -.02em; line-height: 1.2; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.song-meta { display: flex; align-items: center; gap: 12px; color: var(--muted); margin-top: 4px; flex-wrap: wrap; }
.song-meta a { display: inline-flex; align-items: center; gap: 4px; text-decoration: none; }
.song-meta a:hover { color: var(--text); }
.song-meta a svg { width: 14px; height: 14px; }
.pill { font: 11px var(--mono); padding: 2px 8px; border-radius: 999px; border: 1px solid var(--line-2); color: var(--faint); }

.transport {
  display: flex; align-items: center; gap: 22px;
  padding: 12px 16px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  margin-bottom: 12px;
}
.transport-buttons { display: flex; align-items: center; gap: 10px; }
.play-btn {
  width: 48px; height: 48px; border-radius: 50%; border: 0;
  background: var(--text); color: var(--bg);
  display: grid; place-items: center; cursor: pointer;
  transition: transform .1s;
}
.play-btn:hover { transform: scale(1.05); }
.play-btn svg { width: 22px; height: 22px; fill: currentColor; stroke: none; }
.play-btn .i-pause { display: none; }
body.is-playing .play-btn .i-play { display: none; }
body.is-playing .play-btn .i-pause { display: block; }
/* Starting (waiting for the audio to come up, or for the song to load first): the play icon,
   dimmed, in a spinning ring. Not the pause icon: that reads as "already playing" and
   invites a second tap, which cancels. The ring fades in after a moment so a quick start
   doesn't flicker. */
body.is-starting .play-btn .i-play, body.is-starting .np-play .i-play, body.is-starting .stage-play .i-play { opacity: .45; }
.play-btn, .np-play { position: relative; }
body.is-starting .play-btn::after, body.is-starting .np-play::after, body.is-starting .stage-play::after {
  content: ""; position: absolute; inset: -4px; border-radius: 50%;
  border: 2px solid transparent; border-top-color: var(--accent);
  animation: spin .8s linear infinite, fade-in .2s .15s both;
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
.clock { font: 500 20px var(--mono); letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.clock .sep { color: var(--faint); margin: 0 6px; }
#time-total { color: var(--muted); }
/* In place of the clock while the song loads (or after it failed to). */
.load-status {
  font: 500 15px var(--mono); color: var(--muted); font-variant-numeric: tabular-nums;
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.transport-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.master { display: flex; align-items: center; gap: 8px; color: var(--muted); margin-left: 8px; }

.presets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }

/* range inputs */
input[type="range"] {
  -webkit-appearance: none; appearance: none;
  width: 110px; height: 18px; background: transparent; cursor: pointer;
  --fill: var(--text); --pct: 66.6%;
}
input[type="range"]::-webkit-slider-runnable-track {
  height: 4px; border-radius: 2px;
  background: linear-gradient(90deg, var(--fill) var(--pct), var(--line-2) var(--pct));
}
input[type="range"]::-moz-range-track { height: 4px; border-radius: 2px; background: var(--line-2); }
input[type="range"]::-moz-range-progress { height: 4px; border-radius: 2px; background: var(--fill); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; width: 14px; height: 14px; border-radius: 50%;
  background: #fff; margin-top: -5px; border: 0; box-shadow: 0 1px 4px rgb(0 0 0 / .5);
}
input[type="range"]::-moz-range-thumb { width: 14px; height: 14px; border-radius: 50%; background: #fff; border: 0; }

/* board: track heads on the left, time-aligned lanes on the right */
.board {
  position: relative;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden;
  user-select: none; -webkit-user-select: none;
}
.board-row { display: grid; grid-template-columns: var(--head-w) 1fr; }
.head-cell { border-right: 1px solid var(--line); }
.ruler-row { height: 28px; border-bottom: 1px solid var(--line); }
.ruler { position: relative; overflow: hidden; }
.ruler span {
  position: absolute; top: 0; bottom: 0;
  padding: 7px 0 0 5px;
  border-left: 1px solid var(--line-2);
  font: 10px var(--mono); color: var(--faint);
}

.track { display: grid; grid-template-columns: var(--head-w) 1fr; height: 76px; border-bottom: 1px solid var(--line); --c: var(--other); }
.track:last-child { border-bottom: 0; }
.track-head {
  display: flex; align-items: center; gap: 10px;
  padding: 0 14px 0 0;
  border-right: 1px solid var(--line);
  position: relative;
}
.track-head::before { content: ""; align-self: stretch; width: 4px; background: var(--c); opacity: 1; transition: opacity .15s; }
.track.off .track-head::before { opacity: .2; }

.toggle {
  display: flex; align-items: center; gap: 10px;
  flex: 1; min-width: 0; height: 52px; padding: 0 6px;
  background: transparent; border: 0; border-radius: 8px;
  cursor: pointer; text-align: left;
}
.toggle:hover { background: var(--panel-2); }
.switch {
  position: relative; flex: none;
  width: 34px; height: 20px; border-radius: 10px;
  background: var(--line-2);
  transition: background .15s;
}
.switch::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 14px; height: 14px; border-radius: 50%; background: #9aa0ae;
  transition: transform .15s, background .15s;
}
/* .enabled = the track's own switch; .off = actually silent (switch off, or another track soloed) */
.track.enabled .switch { background: var(--c); }
.track.enabled .switch::after { transform: translateX(14px); background: #fff; }
.track.enabled.off .switch { background: color-mix(in srgb, var(--c) 35%, var(--line-2)); }
.tname { display: flex; flex-direction: column; min-width: 0; overflow: hidden; }
.tname b { font-weight: 600; font-size: 15px; white-space: nowrap; transition: color .15s; }
.tname small { color: var(--faint); font-size: 11px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tname small kbd { font-size: 9px; padding: 1px 4px; border-bottom-width: 1px; margin-right: 2px; color: var(--muted); }
.track.off .tname b { color: var(--faint); }

.track-ctrls { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
.track-ctrls .row { display: flex; align-items: center; gap: 6px; }
.track-ctrls input[type="range"] { width: 76px; --fill: var(--c); }
.track.off input[type="range"] { --fill: var(--faint); }
.solo, .dl {
  width: 24px; height: 24px; border-radius: 6px;
  display: grid; place-items: center;
  border: 1px solid var(--line-2); background: transparent;
  font: 600 11px var(--mono); color: var(--muted);
  cursor: pointer; text-decoration: none;
}
.dl svg { width: 13px; height: 13px; }
.solo:hover, .dl:hover { color: var(--text); border-color: #3a4052; }
.solo[aria-pressed="true"] { background: var(--drums); border-color: var(--drums); color: #241500; }
.track .vol-readout { font: 10px var(--mono); color: var(--faint); width: 30px; text-align: right; }

.lane { position: relative; overflow: hidden; }
.lane canvas { position: absolute; inset: 8px 0; width: 100%; height: calc(100% - 16px); display: block; }
.lane .played { position: absolute; inset: 0; width: 0; overflow: hidden; }
.lane .played canvas { width: var(--lane-w, 100%); }
.lane .wave-base { opacity: .28; }
.track.off .lane { filter: grayscale(1); opacity: .45; }
.track.silent-hint .tname small { color: #a98b4a; }

/* overlay spanning all lanes: playhead, loop region, hover line, pointer input */
.overlay {
  position: absolute; top: 0; bottom: 0; right: 0;
  left: var(--head-w);
  cursor: text;
  touch-action: pan-y; /* vertical swipes scroll the page; horizontal drags select a loop */
}
.playhead {
  position: absolute; top: 0; bottom: 0; left: 0; width: 2px; margin-left: -1px;
  background: #fff; box-shadow: 0 0 10px rgb(255 255 255 / .6);
  pointer-events: none;
  will-change: transform;
}
.playhead::before {
  content: ""; position: absolute; top: 0; left: -5px;
  border: 6px solid transparent; border-top-color: #fff;
}
.hover-line { position: absolute; top: 0; bottom: 0; width: 1px; background: rgb(255 255 255 / .25); pointer-events: none; }
.hover-line span {
  position: absolute; top: 5px; left: 6px;
  font: 10px var(--mono); color: var(--text);
  background: var(--panel-2); padding: 1px 5px; border-radius: 4px; border: 1px solid var(--line-2);
}
.loop-region {
  position: absolute; top: 0; bottom: 0;
  background: rgb(255 255 255 / .06);
  border-left: 1px solid rgb(255 255 255 / .5); border-right: 1px solid rgb(255 255 255 / .5);
  pointer-events: none;
}
.loop-region.on { background: rgb(255 176 46 / .12); border-color: var(--drums); }

.loading-veil { position: absolute; inset: 0; display: grid; place-items: center; background: rgb(19 21 27 / .85); backdrop-filter: blur(2px); z-index: 2; }
/* No track rows yet (or none after a failed load): keep room for the veil's message and its button. */
#tracks:empty { min-height: 160px; }
.loading-box { display: grid; justify-items: center; gap: 12px; color: var(--muted); }
/* A load that failed: no spinner or progress, just the message and a retry button. */
.loading-veil.failed .spinner, .loading-veil.failed .bigbar { display: none; }
.spinner { width: 28px; height: 28px; border-radius: 50%; border: 3px solid var(--line-2); border-top-color: var(--accent); animation: spin .8s linear infinite; }

.hints { color: var(--faint); font-size: 12px; margin: 14px 2px 0; line-height: 2; }
.hints kbd { font-size: 10px; }

/* --------------------------------------------------------------- auth screen */
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
#app { height: 100%; }
.auth-screen {
  height: 100%; overflow: auto; display: grid; place-items: center; padding: 24px 16px;
  background:
    radial-gradient(600px 400px at 20% 10%, rgb(255 93 143 / .10), transparent 70%),
    radial-gradient(600px 400px at 80% 90%, rgb(124 108 255 / .10), transparent 70%),
    var(--bg);
}
.auth-card {
  width: min(440px, 100%);
  background: var(--panel); border: 1px solid var(--line); border-radius: 18px;
  padding: 32px;
}
.brand.big { font-size: 22px; margin-bottom: 26px; }
.auth-card h1 { font-size: 30px; letter-spacing: -.02em; line-height: 1.1; margin: 0 0 10px; }
.auth-card p { margin: 0 0 22px; }
.login-form { display: grid; gap: 10px; }
.login-form input {
  height: 46px; padding: 0 14px; border-radius: 10px; font-size: 15px;
  border: 1px solid var(--line-2); background: var(--bg); outline: none;
}
.login-form input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgb(255 93 143 / .15); }
.login-form .btn, .btn.wide { height: 46px; justify-content: center; width: 100%; }
.fine { font-size: 12px; color: var(--faint); margin: 14px 0 0 !important; }
.auth-icon {
  width: 52px; height: 52px; border-radius: 14px; display: grid; place-items: center;
  background: rgb(255 93 143 / .12); color: var(--accent); margin-bottom: 18px;
}
.auth-icon svg { width: 26px; height: 26px; }
/* Over the app, for a guest reaching for something that needs an account. */
.auth-screen.sheet {
  position: fixed; inset: 0; z-index: 60; height: auto;
  background: rgb(0 0 0 / .6); backdrop-filter: blur(4px);
}
.auth-card { position: relative; }
.auth-close { position: absolute; top: 14px; right: 14px; }
body.booting #app, body.booting #auth-screen { visibility: hidden; }
.boot-status {
  position: fixed; inset: 0; z-index: 100; margin: 0; padding: 24px;
  display: grid; place-items: center; text-align: center; color: var(--muted);
}

/* ------------------------------------------------------------------ account */
.account { display: flex; align-items: center; gap: 12px; margin-left: auto; }
.account-text { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.25; min-width: 0; }
.account-email { font-size: 13px; max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-usage { font: 11px var(--mono); color: var(--faint); }
.btn-small { height: 32px; padding: 0 12px; font-size: 13px; border-radius: 8px; }
.icon-btn.square { border-radius: 10px; width: 40px; height: 40px; }
.icon-btn.small { width: 30px; height: 30px; }
.icon-btn.small svg { width: 14px; height: 14px; }
svg.fill { fill: currentColor; stroke: none; width: 14px; height: 14px; }
.link-btn { display: inline-flex; align-items: center; gap: 6px; background: none; border: 0; padding: 0; cursor: pointer; font-weight: 600; }
.link-btn:hover { color: var(--accent); }

/* -------------------------------------------------------------- playlist view */
.playlist-view { padding: 28px; max-width: 1100px; }
.pl-head { display: flex; align-items: flex-end; gap: 22px; margin-bottom: 20px; }
.pl-cover {
  width: 132px; height: 132px; border-radius: 14px; flex: none; overflow: hidden;
  display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr;
  background: linear-gradient(135deg, rgb(255 93 143 / .35), rgb(124 108 255 / .35));
}
.pl-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pl-cover.single { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.pl-titles { min-width: 0; flex: 1; }
.pl-kicker { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
.pl-name { font-size: 36px; letter-spacing: -.03em; line-height: 1.1; margin: 6px 0 8px; overflow-wrap: anywhere; }
.pl-name-input {
  font: 700 32px var(--sans); letter-spacing: -.03em; width: 100%;
  margin: 4px 0 8px; padding: 2px 8px; border-radius: 8px;
  border: 1px solid var(--accent); background: var(--bg); outline: none;
}
.pl-meta { color: var(--muted); }
.pl-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.share-panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 14px 16px; margin-bottom: 18px;
}
.share-panel p { margin: 0 0 10px; font-size: 13px; }
.share-row { display: flex; gap: 8px; flex-wrap: wrap; }
.share-row input {
  flex: 1; min-width: 200px; height: 38px; padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--line-2); background: var(--bg); font: 13px var(--mono); color: var(--muted);
}

.pl-items { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); overflow: hidden; }
.pl-items:empty { display: none; }
.pl-row {
  display: grid; grid-template-columns: 22px 28px 44px minmax(0, 1fr) auto auto; align-items: center; gap: 12px;
  padding: 8px 14px 8px 8px; border-bottom: 1px solid var(--line);
}
.pl-row:last-child { border-bottom: 0; }
.pl-row:hover { background: var(--panel-2); }
.pl-row.playing { background: rgb(255 93 143 / .07); }
.pl-row.playing .pl-num { color: var(--accent); }
.pl-row.dragging { opacity: .4; }
.pl-row.drop-before { box-shadow: inset 0 2px 0 var(--accent); }
.pl-row.drop-after { box-shadow: inset 0 -2px 0 var(--accent); }
.drag-handle { cursor: grab; color: var(--faint); display: grid; place-items: center; }
.drag-handle svg { width: 14px; height: 14px; }
.pl-row:not([draggable="true"]) .drag-handle { visibility: hidden; }
.pl-num { font: 12px var(--mono); color: var(--faint); text-align: right; }
.pl-row .thumb { width: 44px; height: 44px; border-radius: 6px; }
.pl-row .info { min-width: 0; cursor: pointer; }
.pl-row .title { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-row .sub { color: var(--muted); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-row .status { font-size: 12px; color: var(--muted); }
.pl-row .status.err { color: var(--danger); }
.pl-row .dur { font: 12px var(--mono); color: var(--muted); }
.row-actions { display: flex; gap: 4px; opacity: 0; }
.pl-row:hover .row-actions, .pl-row:focus-within .row-actions { opacity: 1; }
.row-btn {
  width: 28px; height: 28px; border-radius: 7px; display: grid; place-items: center;
  background: transparent; border: 1px solid var(--line-2); color: var(--muted); cursor: pointer;
}
.row-btn:hover { color: var(--text); background: var(--panel); }
.row-btn.danger:hover { color: var(--danger); }
.row-btn svg { width: 14px; height: 14px; }
.row-btn:disabled { opacity: .3; cursor: default; }
.pl-empty { color: var(--faint); }

.pl-add { margin-top: 26px; }
.pl-add-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.pl-add-head h2 { margin: 0; font-size: 15px; }
.pl-add-head input {
  margin-left: auto; height: 32px; width: 200px; padding: 0 10px; border-radius: 8px;
  border: 1px solid var(--line-2); background: var(--bg); outline: none;
}
.pl-add-list { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(min(260px, 100%), 1fr)); gap: 8px; }
.pl-add-list li { min-width: 0; }
.pl-add-list li {
  display: flex; align-items: center; gap: 10px; padding: 8px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel);
}
.pl-add-list .thumb { width: 36px; height: 36px; border-radius: 6px; flex: none; }
.pl-add-list .info { min-width: 0; flex: 1; }
.pl-add-list .title { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-add-list .sub { font-size: 11px; color: var(--muted); }

/* ------------------------------------------------------------------- lyrics */
/* The reel (lyrics.js): the song's lines in one column that glides up as it plays. The line
   being sung sits on the singing spot (--anchor, a fraction of the window's height from the
   top) at full brightness and size, each word filling with pink as it's sung. Sung lines fade
   out above it in the pink they were sung in; the next lines wait below in white, bright
   enough to read ahead. Each row is its own layer that lyrics.js places with a transform; the
   window around them (the mixer's panel, or the stage) sets the size and the spot. */
.lyrics {
  --ly-sung: var(--vocals);
  --ly-unsung: #fff;
  --ly-font: "Inter Tight", var(--sans);
  position: relative;
  margin-bottom: 14px; padding: 4px 22px 12px;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
}
body.lyrics-off .mixer .lyrics { display: none; }
.ly-window {
  --anchor: .3;
  --ly-size: 27px;
  position: relative; height: 300px; overflow: hidden;
  /* Lines fade in at the bottom and out at the top instead of being cut off. */
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 15%, #000 76%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 15%, #000 76%, transparent);
}
.ly-reel {
  --glide: 520ms;
  position: relative; height: 100%;
  max-width: 800px; margin: 0 auto;
  font: 800 var(--ly-size)/1.16 var(--ly-font);
  letter-spacing: -.018em;
  font-synthesis: none; -webkit-text-size-adjust: 100%;
}
.mixer .ly-reel { margin: 0; max-width: 860px; } /* left-aligned with the panel, like its header and footer */
.ly-reel.jumped { animation: ly-fade-in .22s ease-out; }
@keyframes ly-fade-in { from { opacity: 0; } }
/* --d: rows from the singing spot (capped at 6). A move glides like a spring that doesn't
   overshoot; the rows below the spot follow a beat apart, a ripple rather than a block. */
.ly-row {
  --d: 6;
  --ripple: calc(min(var(--d), 4) * 40ms);
  position: absolute; top: 0; left: 0; right: 0;
  margin: 0; padding: .06em 0;
  overflow-wrap: break-word; text-wrap: balance;
  transform-origin: 0 0;
  visibility: hidden; opacity: 0;
  transition:
    transform var(--glide) cubic-bezier(.22, 1, .36, 1) var(--ripple),
    opacity .4s ease,
    visibility 0s linear .4s; /* hidden once faded out */
  cursor: pointer;
}
.ly-row.is-past, .ly-row.is-active, .ly-reel.is-back .ly-row { --ripple: 0s; }
.ly-row.is-shown {
  visibility: visible;
  opacity: max(.34, calc(.95 - .2 * var(--d))); /* next .75, then .55, .35 */
  transition:
    transform var(--glide) cubic-bezier(.22, 1, .36, 1) var(--ripple),
    opacity .4s ease;
  will-change: transform, opacity;
}
.ly-row.is-shown.is-past { opacity: max(.1, calc(.5 - .16 * var(--d))); } /* .34, .18, then .1 */
.ly-row.is-shown.is-active, .ly-row.is-shown.is-finishing { opacity: 1; }
.ly-reel.snap .ly-row, .ly-row.arriving { transition: none; }
/* A pointer over a line lights it (it's a link to that spot). Not under a mouse left idle on the
   stage, with its pointer hidden: each sung line would light up as it glides past. */
@media (hover: hover) {
  .mixer .ly-row.is-shown:not(.is-active):hover,
  .stage:not([data-idle]) .ly-row.is-shown:not(.is-active):hover,
  body:not(.is-playing) .stage .ly-row.is-shown:not(.is-active):hover { opacity: .92; }
}
/* Mid-song on the stage, a touch on a line only picks it: a second touch jumps there. */
.ly-row.is-shown.is-armed { opacity: 1; z-index: 2; } /* (even once the reel has carried it up among the sung lines) */
.ly-row.is-armed::after {
  content: "Tap again to sing from here";
  position: absolute; left: 0; top: 100%; z-index: 1; margin-top: .25em;
  padding: .55em 1em; border-radius: 999px;
  background: var(--ly-sung); color: #1a0710;
  font: 700 15px/1 var(--ly-font); letter-spacing: 0; white-space: nowrap;
  box-shadow: 0 6px 20px rgb(0 0 0 / .35);
}
.ly-outro.is-armed::after { content: "Tap again to start it now"; }
.ly-outro:not(.has-next).is-armed::after { content: "Tap again to start from the top"; }
/* Pink means "being sung now": a line just sung cools to white as it fades away. */
.ly-line { color: var(--ly-unsung); }
.ly-line.is-past:not(.is-finishing) .ly-word { animation: ly-cool .45s ease-out both; }
@keyframes ly-cool { from { color: var(--ly-sung); } }
/* The karaoke wipe: --p (0-1) is how much of the word has been sung. The edge is soft (--e
   wide) and runs from just before the word to just past it, so a word ends fully pink; sung
   words also rise a touch. Words sung through switch to plain pink (.done): same look, and
   cheaper to paint. */
.ly-word { display: inline-block; padding-block: .1em; margin-block: -.1em; } /* room for accents in the fill */
.ly-line.is-active .ly-word, .ly-line.is-finishing .ly-word {
  --e: .55em;
  color: transparent;
  background-image: linear-gradient(90deg,
    var(--ly-sung) calc(var(--p, 0) * (100% + var(--e)) - var(--e)),
    var(--ly-unsung) calc(var(--p, 0) * (100% + var(--e))));
  -webkit-background-clip: text; background-clip: text;
  translate: 0 calc(var(--p, 0) * -.05em);
}
.ly-line.is-active .ly-word.done, .ly-line.is-finishing .ly-word.done { color: var(--ly-sung); background-image: none; }
/* A long note on a short word glows while it's held (only on the line being sung: a jump can
   leave the class behind on a line that isn't). It blooms in and fades out rather than switching. */
.ly-line .ly-word { transition: filter .35s ease-out; }
.ly-line.is-active .ly-word.is-held, .ly-line.is-finishing .ly-word.is-held {
  filter: drop-shadow(0 0 .09em rgb(255 160 195 / .8));
}
/* Backing vocals: "so do I (do I)". */
.ly-bv { font-size: .66em; font-weight: 700; }
.ly-bv-line { font-size: .8em; }
/* The intro and long breaks: dots that light up one per third of the wait, breathe, and
   swell just before the singing comes back. */
.ly-dots {
  --k: 0;
  display: flex; align-items: center; gap: .26em; height: 1.16em;
  color: var(--ly-sung);
  transform-origin: .15em 50%;
}
.ly-dots i {
  --n: 0;
  width: .3em; height: .3em; border-radius: 50%; background: currentColor;
  opacity: calc(.22 + .78 * clamp(0, var(--k) * 3 - var(--n), 1));
}
.ly-dots i:nth-child(2) { --n: 1; }
.ly-dots i:nth-child(3) { --n: 2; }
.ly-break .ly-dots { animation: ly-breathe 4.5s ease-in-out infinite; }
.ly-break .ly-dots.is-ending { animation: ly-breathe 4.5s ease-in-out infinite, ly-swell 1.5s cubic-bezier(.45, 0, .55, 1) both; }
.ly-break:not(.is-active) .ly-dots, body:not(.is-playing) .ly-break .ly-dots { animation-play-state: paused; }
@keyframes ly-breathe { 50% { transform: scale(1.18); } }
@keyframes ly-swell { 0%, 100% { scale: 1; } 70% { scale: 1.3; } }
/* The intro's title card (on the stage; the mixer has the title right above). */
.ly-intro-name { display: block; margin-bottom: .34em; color: #fff; }
.ly-intro-art { display: none; }
.stage .ly-intro-art {
  display: block; width: 3.4em; aspect-ratio: 16 / 9; object-fit: cover; margin-bottom: .42em;
  border-radius: .14em; box-shadow: 0 .25em .9em rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .08);
}
.is-caps { letter-spacing: .02em !important; }
.ly-intro-name b { display: block; font-size: 1.24em; line-height: 1.02; letter-spacing: -.03em; }
.ly-intro-name span { display: block; margin-top: .24em; font-size: .52em; font-weight: 600; letter-spacing: -.005em; color: rgb(255 255 255 / .62); }
.mixer .ly-intro-name { display: none; }
/* The end of the song: the next one (and when it starts: tap to start it now), or, with nothing
   queued, this one's name and a "sing it again". */
.ly-outro { font-size: .62em; color: #fff; }
.ly-outro-k { display: block; margin-bottom: .45em; font-size: .62em; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: rgb(255 255 255 / .62); }
.ly-outro-art { display: block; width: 5.4em; aspect-ratio: 16 / 9; object-fit: cover; margin-bottom: .5em; border-radius: .22em; box-shadow: 0 .4em 1.4em rgb(0 0 0 / .5), 0 0 0 1px rgb(255 255 255 / .08); }
.ly-outro b { display: block; font-size: 1.34em; line-height: 1.06; letter-spacing: -.025em; }
.ly-outro b + span { display: block; margin-top: .16em; font-weight: 600; color: rgb(255 255 255 / .62); }
.ly-outro-in { display: block; margin-top: .7em; font-size: .62em; font-weight: 700; color: rgb(255 255 255 / .62); font-variant-numeric: tabular-nums; }
.ly-outro-done { display: block; font-weight: 600; color: rgb(255 255 255 / .62); }
.ly-outro-again {
  display: inline-flex; align-items: center; gap: .4em; margin-top: .6em;
  padding: .45em .9em .45em .75em; border-radius: 999px;
  border: 1px solid rgb(255 255 255 / .22); background: rgb(255 255 255 / .08);
  font-size: .7em; font-weight: 700;
}
.ly-outro-again svg { width: 1em; height: 1em; }
@media (hover: hover) { .ly-outro:hover .ly-outro-again { background: rgb(255 255 255 / .16); } }
.mixer .ly-outro-art { display: none; }
.lyrics-cover { display: none; }
@media (prefers-reduced-motion: reduce) {
  /* No sliding, scaling or ripples: rows swap in place with a quick crossfade. The word fill
     stays: it's the timing, not decoration. */
  .ly-row, .ly-row.is-shown { transition: opacity .15s ease, visibility 0s linear .15s; }
  .ly-row.is-shown { transition: opacity .15s ease; }
  .ly-break .ly-dots, .ly-break .ly-dots.is-ending, .ly-reel.jumped { animation: none; }
  .ly-line .ly-word { transition: none; }
  .ly-line.is-past:not(.is-finishing) .ly-word { animation: none; }
  .ly-line.is-active .ly-word, .ly-line.is-finishing .ly-word { translate: none; }
}
@media (prefers-contrast: more) {
  .ly-row.is-shown { opacity: max(.6, calc(1 - .1 * var(--d))); }
  .ly-row.is-shown.is-past { opacity: .6; }
}

/* Opens the stage. */
.ly-expand {
  position: absolute; z-index: 2; top: 10px; right: 10px;
  display: inline-flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 13px 0 11px;
  border-radius: 999px; border: 1px solid var(--line-2);
  background: rgb(25 28 36 / .92); color: var(--text);
  font-size: 12px; font-weight: 600; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.ly-expand svg { width: 15px; height: 15px; }
.ly-expand:hover { border-color: var(--accent); background: rgb(255 93 143 / .12); }

.lyrics-status { margin: 0; padding: 30px 0 18px; text-align: center; color: var(--muted); }
/* While lyrics are on their way (loading, syncing) the panel keeps the reel's height, so the
   board under it doesn't jump when they come. */
.mixer .lyrics-status.busy { min-height: 300px; display: grid; place-items: center; padding: 0; }
.lyrics-status.busy { animation: lyrics-pulse 1.6s ease-in-out infinite; }
.lyrics-status.err { color: #ffb3b3; }
@keyframes lyrics-pulse { 50% { opacity: .55; } }
@media (prefers-reduced-motion: reduce) { .lyrics-status.busy { animation: none; } }
.lyrics-foot { display: flex; align-items: center; gap: 16px; min-height: 18px; margin-top: 12px; font-size: 12px; color: var(--faint); }
.lyrics-source { flex: 1; min-width: 0; }
.lyrics-foot .link-btn { color: var(--muted); font-size: 12px; }
.lyrics-foot .link-btn:hover { color: var(--accent); }

.lyrics-picker { margin-top: 12px; padding-top: 14px; border-top: 1px solid var(--line); }
.lp-head { display: flex; align-items: center; gap: 10px; }
.lp-search { display: flex; flex: 1; gap: 8px; min-width: 0; }
.lp-search input {
  flex: 1; min-width: 0; height: 32px; padding: 0 10px; border-radius: 8px;
  border: 1px solid var(--line-2); background: var(--bg); outline: none;
}
.lp-search input:focus { border-color: var(--accent); }
.lp-note { margin: 10px 0 0; color: var(--muted); font-size: 13px; }
.lp-note:empty { display: none; }
.lp-results { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; max-height: 300px; overflow-y: auto; }
.lp-results li {
  display: flex; align-items: center; gap: 12px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
}
.lp-results li.current { border-color: rgb(255 93 143 / .45); }
.lr-main { flex: 1; min-width: 0; display: grid; }
.lr-main b, .lr-main span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lr-main b { font-size: 13px; }
.lr-main span { font-size: 12px; color: var(--muted); }
.lr-meta { display: grid; justify-items: end; gap: 3px; font: 11px var(--mono); color: var(--muted); white-space: nowrap; }
.pill.ok { color: var(--ok); border-color: rgb(46 211 160 / .4); }
.lr-using { font-size: 12px; font-weight: 600; color: var(--accent); padding: 0 6px; }
.lp-alt { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.lp-fine { margin: 10px 0 2px; font-size: 12px; color: var(--faint); }

/* ------------------------------------------------------------- karaoke stage */
/* stage.js: the lyrics over the whole screen (#lyrics moves in), on the song's artwork blurred
   to colour, with the song and its controls docked at the bottom. Lyrics, dock and top bar keep
   to one column (--col) that grows with the lyrics; the dock's type grows on a big screen
   (--dock), to read from a couch. */
html.stage-on, html.stage-on body { overflow: hidden; overscroll-behavior: none; }
html.stage-on #app { visibility: hidden; } /* under the stage: not painted at all */
.stage {
  --ly-scale: 1;
  --stage-ly: calc(clamp(26px, min(8.4vw, 6.4vh), 100px) * var(--ly-scale));
  --col: max(1000px, 21 * var(--stage-ly));
  --pad: max(20px, 3.5vw);
  --dock: 1;
  --ink-2: rgb(255 255 255 / .64);
  position: fixed; inset: 0; z-index: 40;
  display: grid; grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-columns: minmax(0, 1fr); /* never wider than the screen: long names shrink, not the stage grow */
  background: #08080c; color: #fff;
  font-family: "Inter Tight", var(--sans); font-synthesis: none;
  overflow: hidden;
  /* One finger never scrolls the page under it (so the browser's bars stay put); two still zoom. */
  touch-action: pinch-zoom;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  transition: opacity .22s ease-out;
}
@supports (height: 1svh) {
  .stage { --stage-ly: calc(clamp(26px, min(8.4vw, 6.4svh), 100px) * var(--ly-scale)); }
}
@starting-style { .stage { opacity: 0; } }
.stage:focus { outline: none; }
@media (hover: hover) and (pointer: fine) {
  body.is-playing .stage[data-idle] { cursor: none; } /* a mouse left still while singing */
}

/* The artwork: a tiny canvas scaled up (which blurs it), drifting slowly, under a scrim that
   keeps every line readable whatever the colours, darkest under the dock. */
.stage-art { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.stage-art-layer {
  position: absolute; left: -15%; top: -15%; width: 130%; height: 130%;
  opacity: 0; transition: opacity 1.4s ease;
  animation: stage-drift 46s ease-in-out infinite alternate;
}
.stage-art-layer.in { opacity: 1; }
body:not(.is-playing) .stage-art-layer { animation-play-state: paused; }
html.stage-on #app .brand-mark i { animation: none; } /* out of sight under the stage */
.stage-art-layer.no-art {
  background:
    radial-gradient(55% 65% at 28% 32%, rgb(255 93 143 / .5), transparent 70%),
    radial-gradient(55% 65% at 76% 72%, rgb(124 108 255 / .5), transparent 70%),
    #140d24;
}
@keyframes stage-drift {
  from { transform: scale(1) rotate(0deg); }
  to { transform: scale(1.12) rotate(5deg) translate(-2%, 1.5%); }
}
.stage-art::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(to bottom, rgb(8 8 12 / .62), rgb(8 8 12 / .44) 22%, rgb(8 8 12 / .44) 58%, rgb(8 8 12 / .93)),
    radial-gradient(130% 95% at 50% 42%, transparent 48%, rgb(8 8 12 / .5));
}

/* Top: the playlist and the place in it, then lyrics size, full screen, close. */
.stage-top {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: max(14px, env(safe-area-inset-top)) max(var(--pad), (100% - var(--col)) / 2) 0;
}
.stage-brand { display: flex; align-items: center; gap: 12px; min-width: 0; font-size: calc(13px * var(--dock)); font-weight: 600; line-height: 1.2; color: var(--ink-2); }
.stage-brand .brand-mark { height: 18px; }
.stage-brand .brand-mark i { animation: none; background: rgb(255 255 255 / .5); }
.stage-set { display: flex; min-width: 0; white-space: nowrap; }
#stage-set-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
#stage-set-pos { flex: none; white-space: pre; } /* the name gives way first; pre keeps the space before the dot */
.stage-top-btns { display: flex; align-items: center; gap: 8px; flex: none; }
.stage-btn {
  position: relative;
  width: 44px; height: 44px; flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: 50%;
  background: rgb(255 255 255 / .09); color: rgb(255 255 255 / .88);
  cursor: pointer;
  transition: background .15s, color .15s, transform .1s, opacity .15s;
}
.stage-btn::before { content: ""; position: absolute; inset: min(0px, calc(50% - 22px)); } /* 44 px to touch, however small drawn */
.stage-btn svg { width: 20px; height: 20px; }
@media (hover: hover) { .stage-btn:hover:not(:disabled, [aria-disabled="true"]) { background: rgb(255 255 255 / .18); color: #fff; } }
.stage-btn:active:not(:disabled, [aria-disabled="true"]) { transform: scale(.93); }
.stage-btn:is(:disabled, [aria-disabled="true"]) { opacity: .3; cursor: default; }
#stage-fs .i-leave, html.is-fullscreen #stage-fs .i-enter { display: none; }
html.is-fullscreen #stage-fs .i-leave { display: block; }
/* A− A+ as one pill. */
.stage-size { display: flex; gap: 8px; border-radius: 999px; background: rgb(255 255 255 / .09); }
.stage-size .stage-btn { background: none; }

/* The lyrics, as big as the screen allows: the size follows the narrower of the width (phones)
   and the height (laptops, TVs), times the size picked. */
.stage-main { position: relative; z-index: 1; min-height: 0; }
.stage .lyrics {
  position: absolute; inset: 0; margin: 0; padding: 0;
  display: flex; flex-direction: column; justify-content: center;
  background: none; border: 0; border-radius: 0;
}
.stage .lyrics, .stage .ly-window { --ly-size: var(--stage-ly); }
.stage .ly-expand, .stage .lyrics-foot, .stage .lyrics-picker { display: none !important; }
.stage .ly-window {
  --anchor: .36;
  flex: 1; height: auto; min-height: 0;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 13%, #000 84%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 13%, #000 84%, transparent);
}
.stage .ly-reel, .stage .lyrics-cover, .stage .lyrics-status { width: min(var(--col), 100% - 2 * var(--pad)); max-width: none; }
/* No lines yet (loading, syncing, none found): the song's name, and what's happening. */
.stage .lyrics:not(.has-lines) .lyrics-cover {
  display: grid; gap: .24em; margin: 0 auto;
  font: 800 var(--ly-size)/1.02 var(--ly-font);
}
.stage .lyrics-cover b { font-size: 1.24em; letter-spacing: -.03em; }
.stage .lyrics-cover span { font-size: .52em; font-weight: 600; color: var(--ink-2); }
.stage .lyrics-status {
  margin: 0 auto; padding: 22px 0 0;
  text-align: left; color: var(--ink-2); font-size: calc(18px * var(--dock)); font-weight: 600;
}
.stage .lyrics-status.err { color: #ffb3b3; }

/* The dock: seek bar and clock, then the song, the transport, guide vocals and up next. */
.stage-dock { position: relative; z-index: 3; padding: 2px var(--pad) max(16px, env(safe-area-inset-bottom)); }
.stage-dock > * { max-width: var(--col); margin-inline: auto; }
.stage-seek { --p: 0; position: relative; height: 26px; cursor: pointer; touch-action: none; }
.stage-seek:focus-visible { outline: none; }
@media (hover: none) { .stage-seek::before { content: ""; position: absolute; inset: -9px 0; } } /* 44 px to touch */
.seek-track {
  position: absolute; left: 0; right: 0; top: 50%; height: 4px; margin-top: -2px;
  border-radius: 2px; background: rgb(255 255 255 / .2); overflow: hidden;
  transition: transform .15s;
}
.stage-seek:focus-visible .seek-track { box-shadow: 0 0 0 2px var(--accent); }
.seek-fill { position: absolute; inset: 0; background: #fff; transform-origin: 0 50%; transform: scaleX(var(--p)); will-change: transform; }
.seek-loop { position: absolute; top: 0; bottom: 0; background: rgb(255 176 46 / .6); }
.seek-thumb-rail { position: absolute; inset: 0; transform: translateX(calc(var(--p) * 100%)); will-change: transform; pointer-events: none; }
.seek-thumb {
  position: absolute; left: -7px; top: 50%; width: 14px; height: 14px; margin-top: -7px;
  border-radius: 50%; background: #fff; box-shadow: 0 1px 6px rgb(0 0 0 / .45);
  transform: scale(0); transition: transform .15s;
}
.stage-seek:focus-visible .seek-thumb, .stage-seek.is-scrubbing .seek-thumb { transform: scale(1); }
@media (hover: hover) {
  .stage-seek:hover .seek-track { transform: scaleY(1.5); }
  .stage-seek:hover .seek-thumb { transform: scale(1); }
}
@media (hover: none) {
  .seek-thumb { transform: scale(.8); }
  .stage-seek.is-scrubbing .seek-thumb { transform: scale(1.2); }
}
.stage-times {
  display: flex; justify-content: space-between; margin-top: -3px;
  font-size: calc(13px * var(--dock)); font-weight: 600; line-height: 1; color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.stage-bar { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; gap: 20px; margin-top: 10px; }
.stage-song { display: flex; align-items: center; gap: calc(14px * var(--dock)); min-width: 0; }
.stage-thumb {
  width: calc(54px * var(--dock)); height: calc(54px * var(--dock)); flex: none;
  border-radius: calc(10px * var(--dock)); object-fit: cover;
  background: rgb(255 255 255 / .08); box-shadow: 0 8px 24px rgb(0 0 0 / .45);
}
.stage-names { min-width: 0; }
.stage-title { font-size: calc(18px * var(--dock)); font-weight: 800; letter-spacing: -.015em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stage-artist { margin-top: 2px; font-size: calc(14px * var(--dock)); font-weight: 500; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stage-transport { display: flex; align-items: center; gap: 16px; }
.stage-transport .stage-btn { width: calc(44px * var(--dock)); height: calc(44px * var(--dock)); }
.stage-transport .stage-btn svg { width: calc(20px * var(--dock)); height: calc(20px * var(--dock)); }
.stage-play {
  position: relative; width: calc(66px * var(--dock)); height: calc(66px * var(--dock)); flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: 50%; background: #fff; color: #0b0c10;
  box-shadow: 0 10px 30px rgb(0 0 0 / .4);
  cursor: pointer; transition: transform .12s;
}
.stage-play svg { width: calc(28px * var(--dock)); height: calc(28px * var(--dock)); fill: currentColor; stroke: none; }
@media (hover: hover) { .stage-play:hover { transform: scale(1.05); } }
.stage-play:active { transform: scale(.94); }
.stage-play .i-pause { display: none; }
body.is-playing .stage-play .i-play { display: none; }
body.is-playing .stage-play .i-pause { display: block; }
/* While singing, the pause button steps back: glass, not the brightest thing on the stage. */
body.is-playing .stage-play { background: rgb(255 255 255 / .14); color: #fff; box-shadow: none; }
@media (hover: hover) { body.is-playing .stage-play:hover { background: rgb(255 255 255 / .22); } }
.stage-extras { display: flex; align-items: center; justify-content: flex-end; gap: 10px; min-width: 0; }
.stage-chip {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; flex: none;
  height: calc(44px * var(--dock)); padding: 0 calc(16px * var(--dock)) 0 calc(13px * var(--dock));
  border-radius: 999px; border: 1px solid rgb(255 255 255 / .18);
  background: rgb(255 255 255 / .07); color: rgb(255 255 255 / .74);
  font-size: calc(14px * var(--dock)); font-weight: 700; line-height: 1; cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.stage-chip svg { width: calc(18px * var(--dock)); height: calc(18px * var(--dock)); }
.stage-chip .slash { display: none; }
.stage-chip[aria-pressed="false"] .slash { display: inline; }
.stage-chip[aria-pressed="true"] { color: #fff; background: rgb(255 255 255 / .16); border-color: rgb(255 255 255 / .5); }
@media (hover: hover) { .stage-chip:hover { border-color: rgb(255 255 255 / .4); } }
.stage-upnext {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: 10px;
  min-width: 0; max-width: calc(340px * var(--dock)); height: calc(54px * var(--dock)); padding: 0 10px 0 calc(16px * var(--dock));
  border-radius: calc(16px * var(--dock)); border: 1px solid rgb(255 255 255 / .14);
  background: rgb(255 255 255 / .07); color: #fff;
  font: inherit; text-align: left; cursor: pointer;
  transition: background .15s, border-color .15s;
}
@media (hover: hover) { .stage-upnext:hover { background: rgb(255 255 255 / .12); } }
.stage-upnext[aria-expanded="true"] { border-color: rgb(255 255 255 / .5); }
.stage-upnext-k { grid-area: 1 / 1; font-size: calc(11px * var(--dock)); font-weight: 800; line-height: 1.3; letter-spacing: .15em; text-transform: uppercase; white-space: nowrap; color: rgb(255 255 255 / .62); }
.stage-upnext-names { grid-area: 2 / 1; display: flex; align-items: baseline; gap: 7px; min-width: 0; line-height: 1.3; }
.stage-upnext-names b { min-width: 0; font-size: calc(15px * var(--dock)); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stage-upnext-names span { flex: 1 1 0; min-width: 0; font-size: calc(13px * var(--dock)); color: rgb(255 255 255 / .6); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stage-upnext.is-last .stage-upnext-names b { font-weight: 600; color: rgb(255 255 255 / .74); }
.stage-upnext > svg { grid-area: 1 / 2 / 3 / 3; width: 18px; height: 18px; color: rgb(255 255 255 / .5); }

/* The queue: a panel at the right of the lyrics (a sheet rising from the dock on phones). It
   keeps to the lyrics' row, so the dock and top bar stay usable under it. */
.stage-queue {
  grid-row: 2 / 3; grid-column: 1 / 2;
  position: absolute; z-index: 5; top: 8px; right: 12px; bottom: 8px;
  width: min(420px, calc(100% - 24px));
  display: flex; flex-direction: column;
  background: #16171f; border: 1px solid rgb(255 255 255 / .1); border-radius: 22px;
  box-shadow: 0 30px 80px rgb(0 0 0 / .55);
  animation: sq-in .28s cubic-bezier(.22, 1, .36, 1);
}
@keyframes sq-in { from { opacity: 0; transform: translateX(28px); } }
@keyframes sq-up { from { opacity: 0; transform: translateY(36px); } }
.sq-head { display: flex; align-items: center; gap: 12px; padding: 20px 14px 12px 22px; }
.sq-titles { flex: 1; min-width: 0; }
.sq-kicker { display: block; font-size: 11px; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--accent); }
.sq-head h2 { margin: 3px 0 0; font-size: 21px; font-weight: 800; letter-spacing: -.02em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sq-list {
  flex: 1; min-height: 0; margin: 0; padding: 2px 8px 14px; list-style: none;
  overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y pinch-zoom;
}
.sq-row {
  width: 100%; display: grid; grid-template-columns: 26px 46px minmax(0, 1fr) auto; align-items: center; gap: 12px;
  padding: 8px 12px 8px 8px; border: 0; border-radius: 14px;
  background: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
  transition: background .15s;
}
@media (hover: hover) { .sq-row:hover:not(:disabled) { background: rgb(255 255 255 / .08); } }
.sq-row:disabled { cursor: default; }
.sq-row.is-current { background: rgb(255 93 143 / .15); }
/* Sung already (still a button: it goes back to that song), dimmed with colour, which keeps it readable. */
.sq-row.is-done .sq-thumb { opacity: .45; }
.sq-row.is-done .sq-names b { color: rgb(255 255 255 / .72); }
.sq-row.is-done :is(.sq-names span, .sq-num, .sq-dur) { color: rgb(255 255 255 / .5); }
.sq-row.is-waiting { opacity: .5; } /* not split yet: disabled */
.sq-num { font-size: 13px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; color: rgb(255 255 255 / .5); text-align: center; }
.sq-thumb { width: 46px; height: 46px; border-radius: 9px; object-fit: cover; display: block; background: rgb(255 255 255 / .08); }
.sq-names { display: grid; min-width: 0; }
.sq-names b { font-size: 15px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sq-names span { margin-top: 1px; font-size: 13px; color: rgb(255 255 255 / .6); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sq-row.is-current .sq-names span { color: var(--accent); font-weight: 700; }
.sq-dur { font-size: 13px; font-weight: 600; line-height: 1; font-variant-numeric: tabular-nums; color: rgb(255 255 255 / .5); }
.sq-eq { display: inline-flex; align-items: flex-end; gap: 2px; height: 14px; }
.sq-eq i { width: 3px; height: 100%; border-radius: 1px; background: var(--accent); transform-origin: bottom; animation: eq 1.1s ease-in-out infinite; }
.sq-eq i:nth-child(2) { animation-delay: -.4s; }
.sq-eq i:nth-child(3) { animation-delay: -.7s; }
body:not(.is-playing) .sq-eq i { animation-play-state: paused; }
/* A wide screen: the lyrics move over beside the queue rather than under it. */
@media (min-width: 961px) and (min-height: 501px) {
  .stage:has(> .stage-queue:not([hidden])) > .stage-main { margin-right: 444px; }
}

/* Big screens (a TV across the room): the dock's type and controls grow with the lyrics. The
   full step waits for 1080p widths, so a big laptop (1728 px) keeps its lines to come. */
@media (min-width: 1200px) and (min-height: 820px) { .stage { --dock: 1.15; } }
@media (min-width: 1800px) and (min-height: 1000px) {
  .stage { --dock: 1.4; }
  .stage-top .stage-btn { width: 52px; height: 52px; }
  .stage-top .stage-btn svg { width: 24px; height: 24px; }
}

/* Full screen (likely a TV): keep clear of the edges, which TVs can crop. */
html.is-fullscreen .stage { --pad: max(24px, 5vw); }
html.is-fullscreen .stage-top { padding-top: max(16px, 3.5vh); }
html.is-fullscreen .stage-dock { padding-bottom: max(16px, 3.5vh); }
@media (hover: none) {
  html.is-fullscreen .stage-top { padding-left: max(72px, var(--pad)); } /* iPad puts its own close button top left */
}

/* Tablets upright and narrow windows: the song and transport on one row, guide vocals and up
   next on the next (or, with nothing up next, guide vocals by the transport). Not phones on their
   side: they keep their one-row dock below, play centred whether or not anything is up next. */
@media (max-width: 960px) and (min-height: 501px) {
  .stage-bar { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "song transport" "extras extras"; row-gap: 12px; }
  .stage-song { grid-area: song; }
  .stage-transport { grid-area: transport; }
  .stage-extras { grid-area: extras; justify-content: stretch; }
  .stage-extras:not(:has(> :not([hidden]))) { display: none; }
  .stage-upnext { flex: 1; max-width: none; }
  .stage-bar:not(:has(#stage-upnext:not([hidden]))) { grid-template-columns: minmax(0, 1fr) auto auto; grid-template-areas: "song extras transport"; }
  .stage-bar:not(:has(#stage-upnext:not([hidden]))) .stage-chip { width: calc(44px * var(--dock)); padding: 0; }
  .stage-bar:not(:has(#stage-upnext:not([hidden]))) .stage-chip span { display: none; }
}

/* Phones, upright: the singing spot sits higher, so two lines to come fit above the dock. */
@media (max-width: 640px) {
  .stage { --pad: 18px; }
  .stage-top { padding-top: max(10px, env(safe-area-inset-top)); }
  .stage-btn { width: 40px; height: 40px; }
  .stage-btn svg { width: 18px; height: 18px; }
  .stage .ly-window {
    --anchor: .28;
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 11%, #000 90%, transparent);
    mask-image: linear-gradient(to bottom, transparent, #000 11%, #000 90%, transparent);
  }
  .stage-bar { gap: 12px; margin-top: 6px; }
  .stage-song { gap: 10px; }
  .stage-transport { gap: 14px; } /* a pause tapped a little off mustn't skip the song */
  .stage-transport .stage-btn { background: none; }
  .stage-thumb { width: 44px; height: 44px; border-radius: 8px; }
  .stage-title { font-size: 16px; }
  .stage-artist { font-size: 13px; }
  .stage-play { width: 56px; height: 56px; }
  .stage-play svg { width: 24px; height: 24px; }
  .stage-upnext { height: 44px; }
  .stage-queue {
    top: auto; left: 0; right: 0; bottom: 0; width: auto; max-height: 58%;
    border-radius: 22px 22px 0 0; border-width: 1px 0 0;
    animation-name: sq-up;
  }
  /* With the queue open, the line being sung moves up, clear of the sheet. */
  .stage:has(> .stage-queue:not([hidden])) .ly-window { --anchor: .14; }
}
/* Phones upright, the dock tightened: the times either side of the seek bar instead of a row of
   their own, and guide vocals and up next as matching pills, each a thumb high (up next keeps its
   two lines, so the whole title shows, and the artist). Everything stays on screen. */
@media (max-width: 640px) and (min-height: 501px) {
  .stage-dock { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; column-gap: 10px; align-items: center; }
  .stage-dock > * { margin-inline: 0; } /* (auto margins would shrink the seek bar inside a grid) */
  .stage-times { display: contents; }
  #stage-elapsed { grid-area: 1 / 1; }
  .stage-seek { grid-area: 1 / 2; }
  #stage-left { grid-area: 1 / 3; text-align: right; }
  .stage-bar { grid-column: 1 / -1; row-gap: 8px; margin-top: 4px; }
  .stage-extras:has(#stage-upnext:not([hidden])) .stage-chip, .stage-upnext { height: 44px; }
  .stage-upnext { border-radius: 999px; padding: 0 12px 0 18px; }
}
/* Phones on their side (and short windows): one slim dock row, and the top buttons float over
   the faded top of the lyrics, so the lyrics keep the height. */
@media (max-height: 500px) {
  .stage { grid-template-rows: 0 minmax(0, 1fr) auto; }
  .stage-top { align-self: start; padding-top: 8px; pointer-events: none; }
  .stage-top-btns { pointer-events: auto; }
  .stage-brand { visibility: hidden; } /* the playlist and the place in it are in the queue */
  .stage-top .stage-btn { width: 36px; height: 36px; }
  .stage-bar { grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); grid-template-areas: none; margin-top: 2px; gap: 12px; }
  .stage-song, .stage-transport, .stage-extras { grid-area: auto; }
  .stage-thumb { width: 40px; height: 40px; }
  .stage-play { width: 46px; height: 46px; }
  .stage-play svg { width: 20px; height: 20px; }
  .stage-chip, .stage-upnext { height: 44px; }
  .stage-chip span { display: none; }
  .stage-chip { width: 44px; padding: 0; }
  .stage-dock { padding-bottom: max(8px, env(safe-area-inset-bottom)); }
  /* The queue panel sits over the floating top buttons here: they step out while it's open
     (it has its own close button, and Escape and Q work). */
  .stage:has(> .stage-queue:not([hidden])) .stage-top-btns { visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .stage, .stage-art-layer { transition: none; }
  .stage-art-layer, .stage-queue, .sq-eq i { animation: none; }
}
/* Increase Contrast: the art only tints, nothing fades out, secondary text brightens. */
@media (prefers-contrast: more) {
  .stage { --ink-2: rgb(255 255 255 / .86); }
  .stage-art::after { background: rgb(8 8 12 / .82); }
  .stage .ly-window {
    -webkit-mask-image: linear-gradient(to bottom, transparent, #000 6%, #000 94%, transparent);
    mask-image: linear-gradient(to bottom, transparent, #000 6%, #000 94%, transparent);
  }
  .stage-upnext-names span, .sq-names span { color: rgb(255 255 255 / .86); }
}
@media (forced-colors: active) {
  .stage-art { display: none; }
  .seek-track { border: 1px solid CanvasText; }
  .seek-fill, .seek-thumb { forced-color-adjust: none; background: Highlight; }
  .ly-line.is-active .ly-word.done, .ly-line.is-finishing .ly-word.done { forced-color-adjust: none; color: Highlight; }
}

/* ---------------------------------------------------------------- queue bar */
.queue-bar {
  display: flex; align-items: center; gap: 14px;
  padding: 8px 12px; margin-bottom: 16px;
  border-radius: 10px; background: rgb(255 93 143 / .08); border: 1px solid rgb(255 93 143 / .25);
  font-size: 13px;
}
.queue-pos { font: 12px var(--mono); color: var(--muted); }
.queue-nav { display: flex; gap: 4px; }
.queue-upnext { color: var(--muted); margin-left: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* -------------------------------------------------------------- menu */
.song-actions { display: flex; gap: 8px; align-items: center; }
.menu-wrap { position: relative; }
.menu {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 5;
  min-width: 220px; max-height: 320px; overflow: auto;
  background: var(--panel-2); border: 1px solid var(--line-2); border-radius: 10px;
  padding: 6px; box-shadow: 0 12px 30px rgb(0 0 0 / .45);
}
.menu button {
  display: block; width: 100%; text-align: left; padding: 8px 10px; border-radius: 7px;
  background: none; border: 0; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.menu button:hover, .menu button:focus-visible { background: var(--line); }
.menu button:disabled { color: var(--faint); cursor: default; background: none; }
.menu hr { border: 0; border-top: 1px solid var(--line-2); margin: 6px 0; }

/* --------------------------------------------------- audio diagnostics panel */
.lk-diag {
  position: fixed; left: 8px; bottom: 8px; z-index: 50; width: min(440px, calc(100% - 16px));
  background: rgb(10 11 14 / .92); color: #cfd3dc; border: 1px solid var(--line-2); border-radius: 10px;
  font: 11px/1.4 ui-monospace, SFMono-Regular, Menlo, monospace;
}
.lk-diag-head { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-bottom: 1px solid var(--line); }
.lk-diag-head b { flex: 1; font: 600 12px/1 inherit; }
.lk-diag-head button {
  border: 1px solid var(--line-2); background: none; color: inherit; border-radius: 6px; padding: 2px 8px; cursor: pointer;
}
.lk-diag pre { margin: 0; padding: 6px 8px; max-height: 32vh; overflow: auto; white-space: pre-wrap; word-break: break-word; }

/* -------------------------------------------------------------------- toast */
.toast {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 20px);
  background: var(--text); color: var(--bg);
  padding: 10px 16px; border-radius: 10px; font-weight: 500;
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
  width: max-content; max-width: min(560px, calc(100% - 32px)); z-index: 60;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.err { background: var(--danger); color: #fff; }
.toast.has-action.show { pointer-events: auto; }
.toast-action {
  margin-left: 6px; padding: 4px 10px; border-radius: 7px; border: 0; cursor: pointer;
  font: inherit; font-weight: 600; background: rgb(0 0 0 / .14); color: inherit;
}

/* -------------------------------------------------------------- responsive */
.menu-btn, .nav-backdrop { display: none; }

/* Laptops / small desktops: slimmer track heads. */
@media (max-width: 1180px) {
  :root { --head-w: 270px; }
  .layout { grid-template-columns: 260px 1fr; }
  .account-email { max-width: 160px; }
}

/* Tablets and phones: sidebar becomes a drawer, page scrolls normally. */
@media (max-width: 860px) {
  body { overflow: auto; }
  #app, .layout { height: auto; }
  .layout { display: block; }
  main { overflow: visible; }

  .topbar { flex-wrap: wrap; height: auto; gap: 10px 12px; padding: 10px 16px 12px; }
  .menu-btn { display: grid; order: 0; }
  .brand { order: 1; font-size: 17px; }
  .account { order: 2; }
  .account-text { display: none; }
  .add-form { order: 3; flex: 1 1 100%; max-width: none; flex-wrap: wrap; gap: 8px; }
  .url-field { flex: 1 1 100%; }
  /* Text inputs under 16px make iOS Safari zoom the page on focus. */
  .url-field input, .login-form input, .new-playlist input, .pl-add-head input, .pl-name-input, select { font-size: 16px; }
  #model-select { flex: 1 1 auto; max-width: none; min-width: 0; }

  .sidebar {
    position: fixed; top: 0; bottom: 0; left: -100%; z-index: 30;
    width: min(330px, 86vw); max-height: none;
    border-right: 1px solid var(--line); box-shadow: 0 0 40px rgb(0 0 0 / .5);
    transition: left .22s ease;
  }
  body.nav-open .sidebar { left: 0; }
  body.nav-open { overflow: hidden; }
  .nav-backdrop { position: fixed; inset: 0; z-index: 29; background: rgb(0 0 0 / .55); }
  body.nav-open .nav-backdrop { display: block; }
  .sidebar-scroll { padding-bottom: 90px; }

  /* Now-playing docks to the bottom of the screen. */
  .now-playing {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 25; margin: 0;
    border-radius: 0; border-width: 1px 0 0;
    padding: 8px 16px calc(8px + env(safe-area-inset-bottom));
    background: color-mix(in srgb, var(--panel-2) 94%, transparent); backdrop-filter: blur(8px);
  }
  body.has-np main { padding-bottom: 72px; }
  body.has-np .toast { bottom: 84px; }

  .mixer, .playlist-view { padding: 16px; }
  .welcome, .processing { padding: 24px 16px; }
  .welcome h1 { font-size: 34px; }
  .transport { flex-wrap: wrap; gap: 12px; }
  .transport-right { margin-left: 0; flex: 1 1 100%; justify-content: space-between; }
  .load-status { flex: 1 1 0; } /* in the clock's place, never a row of its own */
  .master { margin-left: auto; }
  .queue-upnext { display: none; }
}

/* Phones. */
@media (max-width: 600px) {
  :root { --head-w: 146px; }
  .account .btn-small { padding: 0 10px; }

  .song-head { flex-wrap: wrap; gap: 12px; }
  .song-head .thumb { width: 80px; height: 45px; }
  .song-titles h1 {
    font-size: 19px; white-space: normal;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  }
  .song-actions { flex: 1 1 100%; flex-wrap: wrap; }
  .song-actions .btn { height: 34px; padding: 0 12px; font-size: 13px; }
  /* The buttons sit at the left edge here: open the menu rightwards, on screen. */
  .menu { right: auto; left: 0; max-width: calc(100vw - 32px); }

  .clock { font-size: 17px; }
  .load-status { font-size: 13px; }
  .lyrics { padding: 4px 14px 10px; }
  .ly-window { height: 248px; --ly-size: 21px; }
  .mixer .lyrics-status.busy { min-height: 248px; }
  .ly-expand span { display: none; }
  .ly-expand { width: 32px; padding: 0; justify-content: center; }
  .ly-expand::before { content: ""; position: absolute; inset: -6px; } /* 44 px to touch */
  .lp-search input { font-size: 16px; }
  .lp-results li { flex-wrap: wrap; }
  .lr-main { flex-basis: 100%; }
  .lr-meta { justify-items: start; grid-auto-flow: column; gap: 10px; margin-right: auto; }
  .play-btn { width: 44px; height: 44px; }
  .transport { padding: 10px 12px; }
  .master input[type="range"] { width: 96px; }

  /* One swipeable row of presets instead of three wrapped rows. */
  .presets { flex-wrap: nowrap; overflow-x: auto; margin: 0 -16px 12px; padding: 0 16px 4px; scrollbar-width: none; }
  .presets::-webkit-scrollbar { display: none; }
  .presets .chip { flex: none; }

  /* Narrow track heads: switch + name + solo. Volume/download live in the wide layout. */
  .track { height: 62px; }
  .track-head { gap: 4px; padding-right: 6px; }
  .toggle { gap: 7px; padding: 0 4px; height: 46px; }
  .switch { width: 28px; height: 16px; }
  .switch::after { width: 10px; height: 10px; }
  .track.enabled .switch::after { transform: translateX(12px); }
  .tname b { font-size: 13px; }
  .tname small { display: none; }
  .track-ctrls .row:last-child, .track-ctrls .dl { display: none; }
  .solo { width: 26px; height: 26px; }
  .ruler span { font-size: 9px; padding-left: 3px; }

  .pl-head { gap: 14px; align-items: center; }
  .pl-cover { width: 84px; height: 84px; border-radius: 10px; }
  .pl-name { font-size: 24px; }
  .pl-name-input { font-size: 22px; }
  .pl-actions .btn { height: 36px; padding: 0 12px; font-size: 13px; }
  .pl-row { grid-template-columns: 22px 40px minmax(0, 1fr) auto; gap: 10px; padding: 8px 10px 8px 6px; }
  .pl-row .drag-handle, .pl-row .dur { display: none; }
  .pl-row .thumb { width: 40px; height: 40px; }
  .pl-add-head { flex-wrap: wrap; }
  .pl-add-head input { margin-left: 0; width: 100%; }
  .pl-add-list { grid-template-columns: minmax(0, 1fr); }
  .pl-row [data-act="play"] { display: none; } /* tapping the row plays it */
  .row-actions { gap: 2px; }

  .proc-card { padding: 18px; }
  .proc-head .thumb { width: 72px; height: 40px; }
  .auth-card { padding: 24px 20px; }
  .auth-card h1 { font-size: 26px; }
}

/* Touch screens: no hover, no keyboard shortcuts. */
@media (hover: none) {
  .hints { display: none; }
  .row-actions { opacity: 1; }
  .song-item { padding-right: 44px; } /* room for the always-visible remove button */
  .song-item .del { opacity: .7; top: 50%; transform: translateY(-50%); }
  .row-btn, .solo { min-width: 32px; min-height: 32px; }
  .welcome .steps kbd { display: none; }
}

/* =========================================================== live sessions */
/* The host's side (live.js). Guests have their own page (join.html + join.css). */
:root {
  --paper: #f6f4ef; /* the QR tile: scanners want dark on light */
  --ink: #0b0c10;
}
.live-dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--accent); box-shadow: 0 0 0 0 rgb(255 93 143 / .6);
  animation: live-pulse 1.8s ease-out infinite;
}
@keyframes live-pulse { 0% { box-shadow: 0 0 0 0 rgb(255 93 143 / .55); } 70%, 100% { box-shadow: 0 0 0 7px rgb(255 93 143 / 0); } }
.qr-tile { display: block; background: var(--paper); color: var(--ink); border-radius: 10px; padding: 6px; line-height: 0; }
.qr-tile .qr { width: 100%; height: auto; display: block; }
svg.qr { stroke: none; } /* not a line icon: the global svg rule would stroke every module */
.live-icon .live-dot { opacity: 1; animation: live-pulse 1.8s ease-out infinite; }
.mono { font-family: var(--mono); }

/* Sidebar */
.live-side { padding-bottom: 4px; }
.live-start {
  display: flex; align-items: center; gap: 12px; width: calc(100% - 20px); margin: 12px 10px 6px; padding: 12px;
  border-radius: 12px; border: 1px dashed var(--line-2); background: none; cursor: pointer; text-align: left;
  transition: border-color .15s, background .15s;
}
.live-start:hover { border-color: rgb(255 93 143 / .55); background: rgb(255 93 143 / .05); }
.live-start-icon {
  width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; flex: none;
  background: rgb(255 93 143 / .14); color: var(--accent);
}
.live-start-text { display: grid; min-width: 0; }
.live-start-text b { font-weight: 600; }
.live-start-text small { color: var(--muted); font-size: 12px; }
.live-icon { background: rgb(255 93 143 / .16); }
.live-item .sub { color: var(--muted); }
.live-badge-count {
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: 10px; flex: none;
  display: grid; place-items: center; font: 600 11px var(--mono); background: var(--accent); color: #1a0710;
}

/* The control room */
.live-view { padding: 28px; max-width: 1100px; }
.lv-head { margin-bottom: 16px; }
.lv-kicker { display: flex; align-items: center; gap: 8px; font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); font-weight: 600; }
#lv-name { cursor: text; }
.lv-actions #lv-go[data-mode="next"] svg { display: none; }
.lv-top { display: grid; grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); gap: 12px; margin-bottom: 8px; }
.lv-join, .lv-stage { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px; }
.lv-join { display: flex; gap: 18px; align-items: center; }
.lv-join-qr { width: 128px; flex: none; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: 10px; }
.lv-join-text { min-width: 0; }
.lv-join-lead { margin: 0; color: var(--muted); font-size: 13px; }
.lv-join-lead b { color: var(--text); font-weight: 600; }
.lv-code { font: 500 40px/1.15 var(--mono); letter-spacing: .1em; margin: 4px 0 10px; white-space: nowrap; }
.lv-join-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.state-dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.chip.is-open { color: var(--ok); border-color: rgb(46 211 160 / .35); }
.chip.is-paused { color: var(--drums); border-color: rgb(255 176 46 / .4); }
.lv-stage { display: flex; flex-direction: column; gap: 10px; border-color: rgb(255 93 143 / .25); background: linear-gradient(180deg, rgb(255 93 143 / .06), transparent 70%), var(--panel); }
.lv-stage-label { font-size: 12px; color: var(--accent); font-weight: 600; }
.lv-stage-song { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lv-stage-song .thumb { width: 56px; height: 56px; border-radius: 8px; flex: none; }
.lv-stage-song .info { min-width: 0; }
.lv-stage-song .title { font-size: 17px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lv-stage-song .sub { color: var(--muted); }
.lv-stage-next { margin-top: auto; padding-top: 10px; border-top: 1px solid var(--line); color: var(--muted); font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lv-stage-next b { color: var(--text); font-weight: 600; }
.lv-stage-empty { margin: 0; color: var(--muted); }
.lv-stage-empty b { color: var(--text); }

.lv-block { margin-top: 26px; }
.lv-block-head { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.lv-block-head h2 { margin: 0; font-size: 15px; }
.lv-block-head .btn { margin-left: auto; }
.lv-count { font: 12px var(--mono); color: var(--faint); margin-left: 4px; }
.lv-empty { color: var(--faint); margin: 0; padding: 18px; border: 1px dashed var(--line-2); border-radius: var(--radius); text-align: center; }
.lv-pending .pl-row { grid-template-columns: 44px minmax(0, 1fr) auto auto; padding-left: 12px; }
.lv-pending { border-color: rgb(255 176 46 / .3); }
.lv-decide { display: flex; gap: 6px; }
.btn-ok { color: var(--ok); border-color: rgb(46 211 160 / .4); }
.btn-ok:hover { background: rgb(46 211 160 / .12); border-color: var(--ok); }
.btn-ok svg { width: 15px; height: 15px; }
.lv-tag { font-size: 12px; color: var(--drums); margin-top: 2px; }
.lv-tag.err { color: var(--danger); }
.lv-row .sub { display: flex; align-items: baseline; gap: 8px; }
.lv-singer {
  background: none; border: 0; padding: 0; cursor: pointer; color: var(--text); font-weight: 500;
  border-bottom: 1px dashed var(--line-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 60%;
}
.lv-singer:hover { color: var(--accent); border-color: var(--accent); }
.lv-by { color: var(--faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lv-singer-edit {
  height: 26px; padding: 0 8px; border-radius: 6px; border: 1px solid var(--accent); background: var(--bg);
  outline: none; width: min(220px, 100%);
}
.lv-row.on-deck { background: rgb(255 93 143 / .05); }
.lv-deck { font: 600 11px var(--sans); color: var(--accent); border: 1px solid rgb(255 93 143 / .4); padding: 2px 8px; border-radius: 999px; }
.lv-queue .pl-row.dragging { opacity: .4; }
.lv-add .pl-add-head { flex-wrap: wrap; }
.lv-add .pl-add-head h2 { margin-right: auto; }
.lv-add .pl-add-head input { margin-left: 0; }
.lv-singer-input { width: 210px !important; }
.lv-history { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel); }
.lv-history li { display: grid; grid-template-columns: 72px minmax(0, 1fr) minmax(0, auto); gap: 12px; padding: 9px 14px; border-bottom: 1px solid var(--line); font-size: 13px; }
.lv-history li:last-child { border-bottom: 0; }
.lv-time { font: 12px var(--mono); color: var(--faint); }
.lv-h-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lv-h-singer { color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Settings */
.lv-settings {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(440px, 100%), 1fr)); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; margin-bottom: 18px;
}
.lv-set { display: flex; align-items: center; gap: 16px; padding: 14px 16px; background: var(--panel); }
.lv-set-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.lv-set-text b { font-weight: 600; }
.lv-set-text small { color: var(--muted); font-size: 12px; line-height: 1.4; }
.lv-set.kind-choice, .lv-set.kind-songbook { flex-wrap: wrap; }
.lv-set.kind-choice .lv-set-text, .lv-set.kind-songbook .lv-set-text { flex-basis: 100%; }
.lv-set select { height: 34px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--line-2); background: var(--panel-2); max-width: 100%; }
.seg { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 2px; border-radius: 10px; background: var(--bg); border: 1px solid var(--line-2); }
.seg button { height: 28px; padding: 0 11px; border-radius: 8px; border: 0; background: none; color: var(--muted); cursor: pointer; font-weight: 500; font-size: 13px; }
.seg button:hover { color: var(--text); }
.seg button[aria-checked="true"] { background: var(--text); color: var(--bg); }
.switch-btn { background: none; border: 0; padding: 4px; cursor: pointer; flex: none; }
.switch-btn .switch { display: block; }
.switch-btn[aria-checked="true"] .switch { background: var(--accent); }
.switch-btn[aria-checked="true"] .switch::after { transform: translateX(14px); background: #fff; }

/* On the mixer: the bar for the song on stage, and the join code by the lyrics */
.live-bar {
  display: flex; align-items: center; gap: 14px; padding: 8px 8px 8px 12px; margin-bottom: 16px;
  border-radius: 10px; background: rgb(255 93 143 / .08); border: 1px solid rgb(255 93 143 / .25); font-size: 13px;
}
.live-bar .link-btn { gap: 8px; }
.live-bar-now { font-weight: 600; white-space: nowrap; }
.live-bar-next { color: var(--muted); margin-left: auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.live-bar .btn-small svg { width: 14px; height: 14px; }
.live-bar + .queue-bar { display: none !important; } /* one queue at a time */
.lyrics { position: relative; }
.lyrics.has-live-badge { padding-right: 150px; }
.live-badge {
  position: absolute; top: 64px; right: 16px; width: 118px; padding: 0; border: 0; background: none; cursor: zoom-in; /* under "Full screen" */
  display: grid; gap: 8px; justify-items: center; text-align: center; z-index: 1;
}
.live-badge .qr-tile { width: 100%; padding: 5px; border-radius: 9px; }
.lb-text { display: grid; gap: 1px; }
.lb-lead { font-size: 11px; color: var(--muted); }
.lb-code { font: 500 17px/1.2 var(--mono); letter-spacing: .08em; color: var(--text); white-space: nowrap; }

/* The join code, big */
.live-code-overlay {
  position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; padding: 24px;
  background: rgb(6 7 10 / .9); backdrop-filter: blur(6px);
}
.lco-card {
  position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: clamp(24px, 4vw, 56px);
  width: min(1100px, 100%); padding: clamp(24px, 4vw, 48px);
  background: var(--panel); border: 1px solid var(--line-2); border-radius: 24px;
}
.lco-qr { width: min(48vh, 420px, 70vw); }
.lco-qr .qr-tile { padding: 14px; border-radius: 18px; }
.lco-text h2 { margin: 0 0 14px; font-size: clamp(30px, 4.4vw, 56px); line-height: 1.02; letter-spacing: -.03em; }
.lco-or { margin: 0; color: var(--muted); font-size: clamp(15px, 1.6vw, 20px); }
.lco-or b { color: var(--text); font-weight: 600; }
.lco-code { font: 500 clamp(40px, 7vw, 96px)/1.1 var(--mono); letter-spacing: .1em; margin-top: 6px; white-space: nowrap; }
.lco-empty { margin: 18px 0 0; color: var(--accent); font-size: clamp(14px, 1.4vw, 18px); }
.lco-close { position: absolute; top: 16px; right: 16px; }

/* Between singers */
.live-next {
  position: fixed; inset: 0; z-index: 55; overflow: auto; display: grid; align-items: center;
  padding: clamp(24px, 6vw, 96px);
  background:
    radial-gradient(900px 600px at 15% 20%, rgb(255 93 143 / .16), transparent 70%),
    radial-gradient(900px 600px at 90% 90%, rgb(124 108 255 / .14), transparent 70%),
    var(--bg);
}
.ln-inner { max-width: 1200px; }
.ln-kicker { margin: 0 0 8px; font-size: clamp(16px, 2vw, 26px); color: var(--accent); font-weight: 600; }
.ln-who {
  margin: 0; font-size: clamp(56px, 11vw, 172px); line-height: .95; letter-spacing: -.045em; font-weight: 700;
  overflow-wrap: anywhere; animation: ln-in .5s cubic-bezier(.2, .8, .2, 1) both;
}
.ln-who.is-title { font-size: clamp(44px, 8vw, 120px); }
@keyframes ln-in { from { opacity: 0; transform: translateY(18px); } }
.ln-song { display: flex; align-items: center; gap: 16px; margin-top: clamp(18px, 3vw, 36px); min-width: 0; }
.ln-song .thumb { width: clamp(56px, 7vw, 96px); aspect-ratio: 1; height: auto; border-radius: 10px; flex: none; }
.ln-title { font-size: clamp(20px, 2.6vw, 36px); font-weight: 600; letter-spacing: -.01em; line-height: 1.15; }
.ln-artist { font-size: clamp(15px, 1.6vw, 22px); color: var(--muted); }
.ln-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: clamp(24px, 4vw, 48px); }
.ln-ring { position: relative; width: 56px; height: 56px; display: grid; place-items: center; }
.ln-ring svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); stroke-width: 3; }
.ln-ring circle { stroke: var(--line-2); }
.ln-ring .ln-ring-fill { stroke: var(--accent); transition: stroke-dashoffset .2s linear; }
.ln-ring span { font: 600 20px var(--mono); }
.ln-controls .btn { height: 46px; padding: 0 20px; font-size: 15px; }
.ln-after { margin: 22px 0 0; color: var(--muted); font-size: clamp(14px, 1.4vw, 18px); }
.ln-after:empty { display: none; }
.ln-join { position: fixed; right: clamp(16px, 3vw, 40px); bottom: clamp(16px, 3vw, 40px); display: flex; align-items: center; gap: 14px; }
.ln-join .qr-tile { width: clamp(84px, 9vw, 132px); }
.ln-join div:last-child { display: grid; }
.ln-join b { font-size: 14px; }
.ln-join .mono { font-size: clamp(18px, 2vw, 26px); letter-spacing: .08em; }
.ln-close { position: fixed; top: 16px; right: 16px; }

@media (max-width: 860px) {
  .live-view { padding: 16px; }
  .lv-top { grid-template-columns: minmax(0, 1fr); }
  .lv-join-qr { width: 104px; }
  .lv-code { font-size: 32px; }
  .lv-singer-input { width: 100% !important; }
  .live-bar-next { display: none; }
  .live-bar-now { margin-right: auto; }
  /* The badge sits above the lyrics instead of beside them. */
  .lyrics.has-live-badge { padding-right: 14px; }
  .live-badge {
    position: static; width: auto; margin: -4px 0 10px auto; grid-auto-flow: column; justify-content: end; align-items: center;
    text-align: left;
  }
  .live-badge .qr-tile { width: 54px; padding: 3px; border-radius: 6px; }
  .lco-card { grid-template-columns: minmax(0, 1fr); justify-items: center; text-align: center; }
  .lco-qr { width: min(72vw, 360px); }
  .ln-join { display: none; }
}
@media (max-width: 600px) {
  .lv-join { gap: 14px; }
  .lv-join-qr { width: 88px; }
  .lv-code { font-size: 26px; }
  .lv-pending .pl-row { grid-template-columns: 40px minmax(0, 1fr); }
  .lv-pending .dur { display: none; }
  .lv-decide { grid-column: 1 / -1; justify-content: flex-end; }
  .lv-history li { grid-template-columns: 58px minmax(0, 1fr); }
  .lv-h-singer { grid-column: 2; margin-top: -8px; }
  .lv-set { padding: 12px; }
  .live-bar .btn-small { padding: 0 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .live-dot, .ln-who { animation: none; }
}
