:root {
  --bg: #06060f;
  --surf: #0c0c1c;
  --surf2: #111127;
  --surf3: #161630;
  --brd: #1c1c38;
  --brd2: #252548;
  --text: #e2e2f4;
  --muted: #525278;
  --muted2: #3a3a60;
  --accent: #5b9cf6;
  --accent2: #a78bfa;
  --green: #4ade80;
  --red: #f87171;
  --amber: #fbbf24;
  --pink: #f472b6;
  --fn: 'Syne', sans-serif;
  --fm: 'JetBrains Mono', monospace;

  /* ── Material Design 3 tokens ──────────────────────────────────────
     Shape scale (M3 §Shape: xs/sm/md/lg/xl + full/pill) and elevation
     (M3 §Elevation: 5 levels, expressed as layered shadows since dark
     surfaces here already carry M3's "tonal elevation" via --surf/-2/-3
     rather than a lighter overlay). State layers are the hover/focus/
     press opacity washes M3 asks every interactive surface to show,
     derived from --accent so they automatically follow whatever a skin
     sets --accent to instead of being hardcoded. None of this is a
     color/shape a skin can't already see or override — skins.js's own
     border-radius knob still lands on top of whatever's set here. */
  --sh-xs: 4px;
  --sh-sm: 8px;
  --sh-md: 12px;
  --sh-lg: 16px;
  --sh-xl: 28px;
  --sh-full: 32px;
  --ev1: 0 1px 2px rgba(0,0,0,.3), 0 1px 3px 1px rgba(0,0,0,.15);
  --ev2: 0 1px 2px rgba(0,0,0,.3), 0 2px 6px 2px rgba(0,0,0,.15);
  --ev3: 0 4px 8px 3px rgba(0,0,0,.15), 0 1px 3px rgba(0,0,0,.3);
  --st-hover: color-mix(in srgb, var(--accent) 8%, transparent);
  --st-focus: color-mix(in srgb, var(--accent) 12%, transparent);
  --st-press: color-mix(in srgb, var(--accent) 12%, transparent);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; }
body {
  background: var(--bg); color: var(--text);
  font-family: var(--fn); font-size: 14px;
  display: flex; flex-direction: column; height: 100vh;
}
body::after {
  content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 500;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.025'/%3E%3C/svg%3E");
}
::-webkit-scrollbar { width: 14px; height: 14px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-thumb { background: var(--brd2); border-radius: var(--sh-full); }
::-webkit-scrollbar-thumb:hover { background: var(--muted2); }
::-webkit-scrollbar-corner { background: var(--bg); }
/* Only boxes that are themselves rounded AND scroll internally need the
   track pulled in from the ends, otherwise the rounded border clips it. The
   page and the tab strips keep the plain full-length thick scrollbar. */
textarea.hi::-webkit-scrollbar-track, #meaning-box::-webkit-scrollbar-track {
  background: transparent; margin: min(calc(var(--sh-lg) * .6), 28px);
}

/* Multi-line fields: padding grows with the corner radius so text and the
   caret never touch the curve. */
textarea.hi {
  padding: calc(10px + var(--sh-md) * .35) calc(14px + var(--sh-md) * .4);
  line-height: 1.55;
}

/* ═══════════════ OVERLAYS (mode select / connect / lobby) ═══════════════ */
.overlay {
  display: none; position: fixed; inset: 0; z-index: 400;
  background: var(--bg); align-items: center; justify-content: center; padding: 20px;
}
.overlay.show { display: flex; }
.overlay-box {
  width: 100%; max-width: 420px; background: var(--surf);
  border: 1px solid var(--brd2); border-radius: var(--sh-lg); box-shadow: var(--ev2);
  padding: 28px 26px;
}
.overlay-box.wide { max-width: 480px; }
.overlay-logo {
  font-size: 20px; font-weight: 800; letter-spacing: .1em;
  color: var(--accent); margin-bottom: 4px;
}
.overlay-sub { font-family: var(--fm); font-size: 12px; color: var(--muted); margin-bottom: 22px; }
.mode-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.mode-card {
  background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-md); color: var(--text);
  padding: 20px 14px; cursor: pointer; text-align: left;
  display: flex; flex-direction: column; gap: 8px; transition: all .15s;
}
.mode-card:hover { border-color: var(--accent); background: var(--st-hover); }
.mode-icon { font-size: 26px; }
.mode-title { font-weight: 700; font-size: 14px; }
.mode-desc { font-family: var(--fm); font-size: 10px; color: var(--muted); line-height: 1.5; }

.overlay-form { display: flex; flex-direction: column; gap: 6px; }
.overlay-form label {
  font-family: var(--fm); font-size: 10px; font-weight: 600;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
  margin-top: 10px;
}
.overlay-form label:first-child { margin-top: 0; }
.hi {
  background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-xs); color: var(--text);
  font-family: var(--fm); font-size: 12px; padding: 9px 12px; outline: none;
  transition: border-color .2s, box-shadow .2s;
}
.hi:focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.hi::placeholder { color: var(--muted); }
.hi.full { width: 100%; }
.hi.mono-lg { font-size: 20px; letter-spacing: .3em; text-align: center; font-weight: 700; }

/* M3 filled button: full (pill) shape, solid primary fill, state layer
   on hover via a slightly dimmed overlay rather than a border change. */
.overlay-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--accent); color: #05050f; border: none; border-radius: var(--sh-full);
  font-family: var(--fn); font-weight: 700; font-size: 13px;
  letter-spacing: .01em; text-transform: uppercase; padding: 12px; box-shadow: var(--ev1);
  cursor: pointer; margin-top: 16px; transition: opacity .2s, box-shadow .2s; width: 100%;
}
.overlay-btn .material-symbols-outlined { font-size: 16px; }
.overlay-btn:hover { opacity: .9; box-shadow: var(--ev2); }
.overlay-btn:active { box-shadow: var(--ev1); }
/* M3 outlined button: transparent fill, 1px outline, no elevation. */
.overlay-btn.ghost {
  background: none; border: 1px solid var(--brd2); color: var(--muted); box-shadow: none; margin-top: 16px;
}
.overlay-btn.ghost:hover { border-color: var(--muted); color: var(--text); background: var(--st-hover); opacity: 1; box-shadow: none; }

.radio-row { display: flex; flex-direction: column; gap: 8px; }
.radio-opt {
  display: flex; align-items: center; gap: 8px; font-size: 13px;
  cursor: pointer; padding: 10px 12px; border: 1px solid var(--brd2); border-radius: var(--sh-sm); transition: border-color .15s, background .15s;
}
.radio-opt:hover { border-color: var(--accent); background: var(--st-hover); }
.radio-opt input { accent-color: var(--accent); }
.radio-sub { font-family: var(--fm); font-size: 10px; color: var(--muted); }

.lobby-tabs { display: flex; gap: 4px; margin-bottom: 16px; border-bottom: 1px solid var(--brd); }
.lobby-tab {
  background: none; border: none; border-bottom: 2px solid transparent; border-radius: var(--sh-xs) var(--sh-xs) 0 0;
  color: var(--muted); font-family: var(--fn); font-weight: 700; font-size: 11px;
  letter-spacing: .08em; text-transform: uppercase; padding: 8px 4px 10px;
  margin-right: 16px; cursor: pointer; transition: color .2s, border-color .2s;
}
.lobby-tab:hover { color: var(--text); }
.lobby-tab.on { color: var(--accent); border-bottom-color: var(--accent); }
.lobby-pane { display: none; flex-direction: column; }
.lobby-pane.on { display: flex; }

.join-code-row { display: flex; flex-direction: column; gap: 0; margin-bottom: 14px; }
.join-code-row .hi { width: 100%; box-sizing: border-box; font-family: var(--fm); letter-spacing: .15em; text-transform: uppercase; }
.join-code-row .overlay-btn { margin-top: 10px; }
.join-code-hint { font-family: var(--fm); font-size: 9px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 6px; }
.public-list { max-height: 280px; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; }
.pl-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-md); cursor: pointer; transition: border-color .15s, background .15s;
}
.pl-item:hover { border-color: var(--accent); background: var(--st-hover); }
.pl-mine { border-color: var(--accent); opacity: .75; }
.pl-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.pl-name { font-weight: 600; font-size: 13px; }
.pl-np { font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pl-np .material-symbols-outlined { font-size: 13px; vertical-align: -2px; margin-right: 3px; color: var(--accent); }
.pl-np.paused .material-symbols-outlined, .pl-np.idle { opacity: .6; }
.pl-np.idle { font-style: italic; }
.pl-count { font-family: var(--fm); font-size: 10px; color: var(--muted); text-align: right; white-space: nowrap; }
.empty.small { padding: 20px; }

/* ═══════════════ APP HEADER ═══════════════ */
.hdr {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 18px; border-bottom: 1px solid var(--brd);
  background: var(--surf); flex-wrap: wrap; flex-shrink: 0; z-index: 10;
}
/* Logo icon. Rotation is driven from JS (UI._logoLoop) so its speed can follow the
   song's BPM without the angle ever jumping; it just stops accumulating when paused.
   Pulse is audio-reactive: JS sets `scale`, `opacity` and --lvl. */
.logo-hex {
  display: inline-block; --lvl: 0;
  width: 28px; height: 28px; object-fit: contain; cursor: pointer;
  user-select: none; -webkit-user-drag: none;
  filter: drop-shadow(0 0 calc(var(--lvl) * 10px) var(--accent));
  will-change: rotate, scale;
}
.logo { gap: 10px; display: flex; align-items: center; font-size: 17px; font-weight: 800; letter-spacing: .18em; text-transform: uppercase; color: var(--accent); flex-shrink: 0; }
.pcm-badge {
  font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .12em;
  background: color-mix(in srgb, var(--accent) 12%, transparent); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent);
  border-radius: var(--sh-full);
  color: var(--accent); padding: 4px 9px; flex-shrink: 0;
}
.hdr-fill { flex: 1; }
/* M3 outlined button — used for header actions (Copy/Disconnect/Leave). */
.hdr-btn {
  background: none; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text);
  font-family: var(--fn); font-weight: 700; font-size: 11px;
  letter-spacing: .04em; text-transform: uppercase; padding: 7px 16px;
  cursor: pointer; transition: all .15s; flex-shrink: 0;
}
.hdr-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--st-hover); }
.hdr-btn.ghost { border-color: transparent; padding: 0;}
.hdr-btn.danger:hover { border-color: var(--red); color: var(--red); background: color-mix(in srgb, var(--red) 8%, transparent); }
#sdot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted2); flex-shrink: 0; }
#sdot.ok { background: var(--green); animation: blink 2.4s ease-in-out infinite; }
#sdot.err { background: var(--red); }
@keyframes blink { 0%,100%{opacity:1} 50%{opacity:.5} }
#stxt { font-family: var(--fm); font-size: 11px; color: var(--muted); white-space: nowrap; }

.lobby-code-badge {
  font-family: var(--fm); font-size: 14px; font-weight: 700; letter-spacing: .25em;
  background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--accent2);
  padding: 5px 12px; flex-shrink: 0;
}
#participants-strip { display: flex; align-items: center; gap: -6px; flex-shrink: 0; }
.pchip {
  width: 26px; height: 26px; border-radius: min(50%, var(--sh-full)); background: var(--surf3);
  border: 2px solid var(--surf); display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 700; color: var(--text); margin-left: -8px; position: relative;
}
.pchip:first-child { margin-left: 0; }
.pchip.is-host { border-color: var(--accent); }

#cors-note {
  display: none; align-items: flex-start; gap: 8px;
  background: color-mix(in srgb, var(--amber) 7%, transparent); border: 1px solid color-mix(in srgb, var(--amber) 25%, transparent);
  border-left: 3px solid var(--amber); border-radius: var(--sh-xs); padding: 8px 14px; font-family: var(--fm);
  font-size: 11px; color: var(--amber); flex-shrink: 0; line-height: 1.5;
}
#cors-note.show { display: flex; }
#cors-note .material-symbols-outlined { font-size: 15px; margin-top: 1px; flex-shrink: 0; }

/* ═══════════════ MAIN LAYOUT ═══════════════ */
#main { display: flex; flex: 1; overflow: hidden; }

#left {
  width:480px; flex-shrink: 0; border-right: 1px solid var(--brd);
  display: flex; flex-direction: column; background: var(--surf);
  overflow-y: auto;
  /* Never show (or reserve room for) a scrollbar here. It used to appear and disappear as
     the window was resized; each time it took ~15px of width, which re-wrapped the controls,
     which changed the fitted size, which toggled the scrollbar again: the whole player
     flickered between two layouts. It can still scroll with the wheel / touch if a window
     is too short for even the smallest cover. */
  scrollbar-width: none;
}
#left::-webkit-scrollbar { display: none; }
#art-wrap { position: relative; aspect-ratio: 1; background: var(--surf2); overflow: hidden; flex-shrink: 0; }
/* Groups info/progress/ctrls so they can be treated as one block —
   on mobile this whole panel gets overlaid on top of the album art instead
   of stacking below it (see the max-width:1000px query). On desktop it's
   just a plain flex column, identical to the old unwrapped layout. */
#player-panel { display: flex; flex-direction: column; min-width: 0; }
#art-img { width: 100%; height: 100%; object-fit: cover; display: block; opacity: 0; transition: opacity .5s; position: relative; }
#art-img.vis { opacity: 1; }
/* The outgoing artwork during a track-change slide (see UI._artShow). Placed
   next to #art-img in the DOM, so the EQ / meter overlays stay above it. */
.art-ghost { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
#art-empty {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; color: var(--muted2);
}
#art-empty .material-symbols-outlined { font-size: 52px; opacity: .4; }
#art-empty span { font-family: var(--fm); font-size: 10px; letter-spacing: .1em; }
#buf-ring {
  display: none; position: absolute; top: 8px; right: 8px; width: 18px; height: 18px;
  border: 2px solid var(--brd2); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite;
}
#buf-ring.show { display: block; }
@keyframes spin { to{ transform: rotate(360deg); } }

#info { padding: 14px 16px; border-bottom: 1px solid var(--brd); }
#info-src { font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .2em; text-transform: uppercase; color: var(--accent2); margin-bottom: 5px; display: flex; align-items: center; gap: 6px; }
#lock-badge { background: color-mix(in srgb, var(--red) 12%, transparent); border: 1px solid color-mix(in srgb, var(--red) 30%, transparent); border-radius: var(--sh-full); color: var(--red); font-size: 8px; padding: 2px 7px; display: none; }
#lock-badge.show { display: inline-block; }
#info-title { font-size: 16px; font-weight: 700; line-height: 1.3; margin-bottom: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#info-artist { font-family: var(--fm); font-size: 11px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#info-req { font-family: var(--fm); font-size: 10px; color: var(--muted2); margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#info-req[hidden] { display: none; }

/* M3 slider track: full-round track + thumb, matching the volume/filter
   sliders below so every draggable range in the app reads the same. */
#prog-wrap { padding: 10px 16px 6px; border-bottom: 1px solid var(--brd); }
#prog-bar { position: relative; height: 4px; background: var(--brd2); cursor: pointer; border-radius: var(--sh-full); margin-bottom: 5px; transition: height .15s; }
#prog-bar:hover { height: 7px; }
#prog-bar.locked { cursor: not-allowed; }
#prog-fill { height: 100%; background: linear-gradient(90deg, var(--accent), var(--accent2)); border-radius: var(--sh-full); pointer-events: none; }
#prog-thumb { position: absolute; top: 50%; transform: translate(-50%,-50%); width: 12px; height: 12px; border-radius: min(50%, var(--sh-full)); background: var(--text); box-shadow: var(--ev1); opacity: 0; pointer-events: none; transition: opacity .15s; }
#prog-bar:hover #prog-thumb { opacity: 1; }
#prog-times { display: flex; justify-content: space-between; font-family: var(--fm); font-size: 10px; color: var(--muted); }

#ctrls { padding: 12px 16px; border-bottom: 1px solid var(--brd); }
#ctrls-main { display: flex; align-items: center; justify-content: center; gap: 8px; margin-bottom: 10px; }
/* M3 icon button: circular hit area, no fill by default, a tinted state
   layer on hover instead of the old plain border/bg swap. */
.cb {
  background: none; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text);
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background .15s, border-color .15s, transform .1s, box-shadow .15s;
}
.cb:hover { background: var(--st-hover); border-color: var(--accent); }
.cb:active { transform: scale(.93); }
.cb:disabled { opacity: .3; cursor: not-allowed; }
.cb:disabled:hover { background: none; border-color: var(--brd2); }
.cb.sm { width: 36px; height: 36px; }
/* M3 FAB: filled primary circle, elevated, for the one high-emphasis
   action in the row (play/pause). */
.cb.lg { width: 56px; height: 56px; background: var(--accent); border-color: var(--accent); color: #05050f; box-shadow: var(--ev2); }
.cb.lg:hover { background: var(--accent2); border-color: var(--accent2); box-shadow: var(--ev3); }
.cb.lg:active { box-shadow: var(--ev1); }
.cb.lg:disabled { background: var(--brd2); border-color: var(--brd2); color: var(--muted); box-shadow: none; }
.cb.on { color: var(--accent); border-color: var(--accent); background: var(--st-hover); }
.cb .material-symbols-outlined { pointer-events: none; }
#ctrls-sec { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; row-gap: 8px; justify-content: space-around;}
.hsep { width: 1px; height: 18px; background: var(--brd2); flex-shrink: 0; display: none;}
#loop-btn { font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .05em; padding: 0 10px; width: auto; min-width: 44px; justify-content: center; }
#gapless-btn { font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .05em; padding: 0 10px; width: auto; min-width: 44px; justify-content: center; }
#vol-row { flex: 1; display: flex; align-items: center; gap: 6px; }
.vol-ico { color: var(--muted); flex-shrink: 0; }

/* ── Material Symbols (player controls) ─────────────────────────────
   Google's standard boilerplate for the variable icon font (see
   https://fonts.google.com/icons), plus per-context sizing so these
   drop into the same button/row layouts the old inline SVGs used. */
.material-symbols-outlined {
  font-family: 'Material Symbols Outlined';
  font-weight: normal;
  font-style: normal;
  font-size: 20px;
  display: inline-block;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  word-wrap: normal;
  white-space: nowrap;
  direction: ltr;
  -webkit-font-smoothing: antialiased;
}
.cb.sm .material-symbols-outlined { font-size: 18px; }
.cb.lg .material-symbols-outlined { font-size: 26px; }
.vol-ico.material-symbols-outlined { font-size: 16px; }
#vol-sl { flex: 1; -webkit-appearance: none; appearance: none; height: 4px; background: var(--brd2); outline: none; cursor: pointer; border-radius: var(--sh-full); }
#vol-sl::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; border-radius: min(50%, var(--sh-full)); background: var(--accent); cursor: pointer; }
#vol-lbl { font-family: var(--fm); font-size: 10px; color: var(--muted); width: 30px; text-align: right; }

#right { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; background: var(--bg); }
#tabs { display: flex; border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; overflow-x: auto; }
/* M3 primary tab: bottom indicator bar + a tinted state layer on hover
   (rather than only a text-color change) so the row reads as a proper
   M3 tab strip instead of plain nav links. */
.tab {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: none; border-bottom: 3px solid transparent; color: var(--muted);
  font-family: var(--fn); font-weight: 700; font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  padding: 11px 18px; cursor: pointer; transition: color .2s, border-color .2s, background .2s; white-space: nowrap;
}
.tab .material-symbols-outlined { font-size: 16px; }
.tab:hover { color: var(--text); background: var(--st-hover); }
.tab.on { color: var(--accent); border-bottom-color: var(--accent); background: var(--st-hover); }
.pane { display: none; flex: 1; flex-direction: column; overflow: hidden; min-height: 0; }
.pane.on { display: flex; }

#search-bar { display: flex; gap: 8px; padding: 12px; border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; }
#si { flex: 1; background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text); font-family: var(--fn); font-size: 14px; padding: 8px 16px; outline: none; transition: border-color .2s, box-shadow .2s; }
#si:focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
#si::placeholder { color: var(--muted); }
#src-sel { background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text); font-family: var(--fm); font-size: 11px; padding: 7px 10px; outline: none; cursor: pointer; flex-shrink: 0; }
#src-sel option { background: var(--surf2); }
/* M3 filled button. */
#btn-srch { background: var(--accent); color: #05050f; border: none; border-radius: var(--sh-full); font-family: var(--fn); font-weight: 700; font-size: 12px; letter-spacing: .02em; text-transform: uppercase; padding: 8px 20px; cursor: pointer; box-shadow: var(--ev1); transition: opacity .2s, box-shadow .2s; flex-shrink: 0; white-space: nowrap; }
#btn-srch:hover { opacity: .9; box-shadow: var(--ev2); }
#sres { flex: 1; overflow-y: auto; padding: 0; container: rows / inline-size; }
.si { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid transparent; border-radius: var(--sh-sm); cursor: pointer; transition: background .15s, border-color .15s; margin-bottom: 2px; }
.si:hover { background: var(--surf2); border-color: var(--brd); }
/* :focus-within mirrors the :hover treatment above for keyboard/gamepad
   navigation, which can focus the row's buttons without ever "hovering"
   them — without this, in-tab navigation (see gamepad.js's navMove)
   landed on a real, clickable button that was invisible the whole time. */
.si:focus-within { background: var(--surf2); border-color: var(--accent); }
.si-th { width: 46px; height: 46px; object-fit: cover; flex-shrink: 0; background: var(--surf2); border-radius: var(--sh-xs); }
.si-nth { width: 46px; height: 46px; flex-shrink: 0; background: var(--surf2); border-radius: var(--sh-xs); display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 16px; }
.si-nth .material-symbols-outlined { font-size: 20px; }
.si-meta { flex: 1; min-width: 0; }
.si-t { font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.si-a { font-family: var(--fm); font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 2px; }
.si-d { font-family: var(--fm); font-size: 10px; color: var(--muted); flex-shrink: 0; }
.si-acts { display: flex; gap: 5px; flex-shrink: 0; opacity: 0; transition: opacity .15s; }
.si:hover .si-acts, .si:focus-within .si-acts { opacity: 1; }
/* M3 tonal button — the small in-row action buttons throughout (Play,
   +Queue, download, presets, etc.) all share this treatment now: pill
   shape, filled on the primary action, otherwise a quiet outline. */
.add-btn { display: inline-flex; align-items: center; gap: 4px; background: none; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text); font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; padding: 5px 10px; cursor: pointer; transition: background .15s, border-color .15s; white-space: nowrap; }
.add-btn .material-symbols-outlined { font-size: 13px; }
.add-btn:hover { background: var(--accent); border-color: var(--accent); color: #05050f; }
.add-btn.pnow:hover { background: var(--green); border-color: var(--green); color: #05050f; }
.add-btn:disabled { opacity: .3; cursor: not-allowed; }

#q-hdr { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; }
#q-info { font-family: var(--fm); font-size: 10px; color: var(--muted); flex: 1; }
/* Server password window (see Auth.prompt in api.js) */
.auth-overlay { z-index: 2000; background: rgba(0,0,0,.72); }
.auth-box .hi { box-sizing: border-box; }
.auth-err { min-height: 18px; margin-top: 8px; font-family: var(--fm); font-size: 11px; color: var(--red, #e5484d); }
.auth-btns { display: flex; justify-content: flex-end; gap: 8px; margin-top: 10px; }
/* Search box (library + queue): search icon, text, clear (x) */
.sbox { display: inline-flex; align-items: center; gap: 4px; width: 150px; min-width: 0; background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-full); padding: 0 6px 0 10px; transition: border-color .15s; }
.sbox:focus-within { border-color: var(--accent); }
.sbox > .material-symbols-outlined { font-size: 15px; color: var(--muted); flex-shrink: 0; transition: color .15s; }
.sbox:focus-within > .material-symbols-outlined { color: var(--accent); }
.sbox input { flex: 1; min-width: 0; width: 100%; background: none; border: none; outline: none; color: var(--text); font-family: var(--fm); font-size: 11px; padding: 5px 0; }
.sbox input::placeholder { color: var(--muted); }
.sx { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; flex-shrink: 0; background: none; border: none; border-radius: 50%; color: var(--muted); cursor: pointer; transition: all .15s; }
.sx[hidden] { display: none; }
.sx:hover { color: var(--text); background: var(--st-hover); }
.sx .material-symbols-outlined { font-size: 14px; }

/* Search hits (library + queue) */
mark { background: color-mix(in srgb, var(--accent) 38%, transparent); color: inherit; border-radius: var(--sh-xs); padding: 0 1px; }

/* Thumbnail wrapper: lets a circular source badge sit on the artwork's corner. */
.th-w { position: relative; display: flex; flex-shrink: 0; }
.src-ico { position: absolute; right: -4px; bottom: -4px; width: 16px; height: 16px; border-radius: min(50%, var(--sh-full)); object-fit: cover; background: var(--surf3, var(--surf2)); border: 2px solid var(--bg); box-sizing: content-box; pointer-events: none; }
.qi .src-ico, .lib-trow .src-ico { width: 14px; height: 14px; }
.src-ico.inline { position: static; width: 18px; height: 18px; border: none; flex-shrink: 0; }
/* M3 outlined button (small, icon+label) — queue toolbar actions. */
.qa { display: inline-flex; align-items: center; gap: 4px; background: none; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--muted); font-family: var(--fm); font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; padding: 5px 10px; cursor: pointer; transition: all .15s; }
.qa .material-symbols-outlined { font-size: 14px; }
.qa:hover { border-color: var(--accent); color: var(--accent); background: var(--st-hover); }
.qa.d:hover { border-color: var(--red); color: var(--red); background: color-mix(in srgb, var(--red) 8%, transparent); }
.qa:disabled { opacity: .3; cursor: not-allowed; }
#ql { flex: 1; overflow-y: auto; padding: 6px; container: rows / inline-size; }
.qi { display: flex; align-items: center; gap: 8px; padding: 7px 10px; border: 1px solid transparent; border-radius: var(--sh-sm); transition: background .15s, border-color .15s; margin-bottom: 2px; }
.qi:hover { background: var(--surf2); border-color: var(--brd); }
.qi:focus-within { background: var(--surf2); border-color: var(--accent); }
.qi.cur { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 6%, transparent); }
.qi[draggable="true"] { cursor: grab; }
.qi.dragging { opacity: .4; }
.q-more { text-align: center; padding: 10px; font-family: var(--fm); font-size: 10px; color: var(--muted); cursor: pointer; }
.q-more:hover { color: var(--text); }
.qi.drag-over { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.qi-drag { color: var(--muted2); font-size: 13px; flex-shrink: 0; cursor: grab; line-height: 1; opacity: 0; transition: opacity .15s; }
.qi:hover .qi-drag, .qi:focus-within .qi-drag { opacity: 1; }
.qi[draggable="false"] .qi-drag { display: none; }
.qi-n { font-family: var(--fm); font-size: 10px; color: var(--muted2); width: 20px; text-align: right; flex-shrink: 0; }
.qi-th { width: 34px; height: 34px; object-fit: cover; flex-shrink: 0; background: var(--surf2); border-radius: var(--sh-xs); }
.qi-nth { width: 34px; height: 34px; flex-shrink: 0; background: var(--surf2); border-radius: var(--sh-xs); display: flex; align-items: center; justify-content: center; color: var(--muted); font-size: 12px; }
.qi-nth .material-symbols-outlined { font-size: 16px; }
.qi-m { flex: 1; min-width: 0; }
.qi-t { font-weight: 600; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qi-a { font-family: var(--fm); font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.qi-d { font-family: var(--fm); font-size: 10px; color: var(--muted); flex-shrink: 0; }
.qi-bs { display: flex; gap: 1px; opacity: 0; transition: opacity .15s; flex-shrink: 0; }
.qi:hover .qi-bs, .qi:focus-within .qi-bs { opacity: 1; }
/* M3 standard icon button — no container, just a circular state layer. */
.qib { background: none; border: none; border-radius: 50%; color: var(--muted); cursor: pointer; padding: 5px; font-size: 13px; display: flex; align-items: center; transition: color .15s, background .15s; line-height: 1; }
.qib .material-symbols-outlined { font-size: 16px; }
.qib:hover { color: var(--text); background: var(--st-hover); }
.qib.del:hover { color: var(--red); background: color-mix(in srgb, var(--red) 10%, transparent); }
.qib.dl:hover { color: var(--accent); }
.qib:disabled { opacity: .3; cursor: not-allowed; }

/* Download format picker — a tiny fixed-position menu spawned next to
   whichever download button was clicked (now-playing or a queue item).
   See UI.openDownloadMenu/closeDownloadMenu in ui.js. */
.dl-menu {
  position: fixed; z-index: 500; background: var(--surf3); border: 1px solid var(--brd2); border-radius: var(--sh-sm);
  box-shadow: var(--ev3); min-width: 150px; padding: 4px; display: flex; flex-direction: column;
}
.dl-opt {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  background: none; border: none; border-radius: var(--sh-xs); color: var(--text); font-family: var(--fn); font-size: 12px;
  padding: 8px 10px; cursor: pointer; text-align: left; transition: background .15s, color .15s;
}
.dl-opt:hover { background: var(--st-hover); color: var(--accent); }
.dl-menu-t { font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); padding: 6px 10px 4px; }
.dl-opt small { font-family: var(--fm); font-size: 9px; color: var(--muted); }
.dl-opt:hover small { color: var(--accent); }

#lyr-hdr { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; }
#lyr-src-lbl { font-family: var(--fm); font-size: 10px; color: var(--muted); flex: 1; }
#lyr-badge, #lyr-lang { display: inline-flex; align-items: center; gap: 4px; font-family: var(--fm); font-size: 10px; line-height: 1; padding: 4px 8px; border-radius: var(--sh-full); border: 1px solid var(--brd2); color: var(--muted); white-space: nowrap; }
#lyr-badge .material-symbols-outlined, #lyr-lang .material-symbols-outlined { font-size: 12px; }
#lyr-badge.synced { color: var(--green); border-color: var(--green); }
#lyr-badge[hidden], #lyr-lang[hidden], #btn-lyr-sync[hidden] { display: none; }
#pane-lyrics { position: relative; }
#btn-lyr-sync { position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); display: inline-flex; align-items: center; gap: 6px; padding: 8px 16px; border-radius: var(--sh-full); border: 1px solid var(--brd2); background: var(--accent); color: var(--bg, #000); font-family: var(--fm); font-size: 12px; font-weight: 700; cursor: pointer; box-shadow: var(--ev3); z-index: 5; animation: lyr-sync-in .2s ease; }
@keyframes lyr-sync-in { from { opacity: 0; transform: translate(-50%, 8px); } to { opacity: 1; transform: translate(-50%, 0); } }
#btn-lyr-sync .material-symbols-outlined { font-size: 16px; }
#lyr-body { flex: 1; overflow-y: auto; padding: 20px 24px; scroll-behavior: smooth; }
.ll { font-size: 18px; font-weight: 600; line-height: 1.7; color: var(--muted); border-radius: var(--sh-xs); transition: color .3s, font-size .2s; cursor: pointer; padding: 2px 6px; margin: 0 -6px; }
.ll-note { font-size: 16px !important; opacity: .5; vertical-align: -2px; }
/* Lyric translation: a smaller second line under each lyric line. */
.ll-tr { display: block; font-size: .72em; font-weight: 500; line-height: 1.45; opacity: .8; font-style: italic; }
.ll-tr:empty, #lyr-body.tr-off .ll-tr { display: none; }
#lyr-tr-lang option, #lyr-provider option { background: var(--surf2); }
/* Translate + provider pickers: a pill with a small icon in front of a borderless select. */
.lyr-prov { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; min-width: 0; background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--muted); padding: 0 4px 0 8px; transition: border-color .15s; }
.lyr-prov:focus-within { border-color: var(--accent); }
.lyr-prov .material-symbols-outlined { font-size: 13px; }
#lyr-tr-lang, #lyr-provider { background: none; border: none; outline: none; color: var(--text); font-family: var(--fm); font-size: 10px; padding: 4px 2px; cursor: pointer; min-width: 0; max-width: 130px; }
@media (max-width: 700px) { #lyr-hdr { flex-wrap: wrap; } }
.ll:hover { color: var(--text); background: var(--st-hover); }
.ll.active { color: var(--text); font-size: 20px; }
.lp { font-size: 14px; line-height: 1.8; color: var(--muted); white-space: pre-wrap; }

.flt-label { font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .15em; text-transform: uppercase; color: var(--muted); margin-bottom: 10px; display: flex; align-items: center; gap: 3px; }
.flt-label .material-symbols-outlined { font-size: 12px; }
/* M3 outlined → filled-tonal on select: presets behave like a chip/toggle
   group — quiet outline at rest, tonal (accent2-tinted) fill when active. */
.preset-btn { background: none; border: 1px solid var(--brd2); border-radius: var(--sh-md); color: var(--text); font-family: var(--fn); font-weight: 600; font-size: 12px; padding: 10px 8px; cursor: pointer; text-align: center; transition: all .15s; line-height: 1.3; }
.preset-btn:hover { border-color: var(--accent2); background: color-mix(in srgb, var(--accent2) 8%, transparent); }
.preset-btn.active { border-color: var(--accent2); background: color-mix(in srgb, var(--accent2) 15%, transparent); color: var(--accent2); }
.preset-btn:disabled { opacity: .3; cursor: not-allowed; }
.flt-row { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.flt-row label { font-family: var(--fm); font-size: 10px; color: var(--muted); width: 80px; flex-shrink: 0; }
.flt-slider { flex: 1; -webkit-appearance: none; appearance: none; height: 4px; background: var(--brd2); outline: none; cursor: pointer; border-radius: var(--sh-full); }
.flt-slider::-webkit-slider-thumb { -webkit-appearance: none; width: 12px; height: 12px; border-radius: min(50%, var(--sh-full)); background: var(--accent2); cursor: pointer; }
.flt-slider:disabled { opacity: .3; }
.flt-val { font-family: var(--fm); font-size: 10px; color: var(--muted); width: 36px; text-align: right; }

/* CHAT */
#pane-chat { }
#chat-log { flex: 1; overflow-y: auto; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; }
.chat-msg { display: flex; flex-direction: column; gap: 3px; max-width: 88%; background: var(--surf2); border-radius: var(--sh-md); padding: 7px 11px; }
.chat-msg .cm-name { font-family: var(--fm); font-size: 10px; font-weight: 700; color: var(--accent2); }
.chat-msg .cm-text { font-size: 13px; line-height: 1.4; word-break: break-word; }
.chat-msg.mine { align-self: flex-end; align-items: flex-end; background: color-mix(in srgb, var(--accent) 12%, var(--surf2)); }
.chat-msg.mine .cm-name { color: var(--green); }
.chat-msg.system { align-self: center; background: none; padding: 2px; }
.chat-msg.system .cm-text { font-family: var(--fm); font-size: 10px; color: var(--muted); font-style: italic; }
#chat-input-row { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; }
#chat-input { flex: 1; background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text); font-family: var(--fn); font-size: 13px; padding: 9px 16px; outline: none; transition: border-color .2s, box-shadow .2s; }
#chat-input:focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
#chat-send { background: var(--accent); color: #05050f; border: none; border-radius: var(--sh-full); font-family: var(--fn); font-weight: 700; font-size: 11px; letter-spacing: .02em; text-transform: uppercase; padding: 9px 18px; cursor: pointer; box-shadow: var(--ev1); transition: opacity .2s, box-shadow .2s; }
#chat-send:hover { opacity: .9; box-shadow: var(--ev2); }

/* ═══════════════ Chat pane: log + input (left) / user list (right) ═══════════════ */
#pane-chat { flex-direction: row; }
#chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; border-right: 1px solid var(--brd); }
#chat-main #chat-log { flex: 1; }
#chat-users { width: 168px; flex-shrink: 0; overflow-y: auto; padding: 14px 10px; }
#chat-users-hdr { font-family: var(--fm); font-size: 10px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); padding: 0 6px 10px; }
#chat-users-hdr span { color: var(--muted2); }
.cu-item { display: flex; align-items: center; gap: 8px; padding: 6px 8px; border-radius: var(--sh-sm); transition: background .15s; }
.cu-item:hover { background: var(--surf2); }
.cu-avatar {
  width: 24px; height: 24px; flex-shrink: 0; border-radius: min(50%, var(--sh-full));
  display: flex; align-items: center; justify-content: center;
  background: var(--surf3); border: 1px solid var(--brd2);
  font-family: var(--fm); font-weight: 700; font-size: 11px; color: var(--muted);
}
.cu-avatar.is-host { border-color: var(--accent); color: var(--accent); }
.cu-meta { min-width: 0; }
.cu-name { font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cu-tag { font-family: var(--fm); font-size: 9px; color: var(--accent); letter-spacing: .05em; }
.cu-empty { padding: 10px 6px; font-family: var(--fm); font-size: 11px; color: var(--muted); }

/* ═══════════════ Config tab ═══════════════ */
#pane-config { overflow-y: auto; }
/* container-type so the card grid below reacts to the width of the Config pane
   itself (which is the viewport minus the side-by-side player on desktop),
   not the viewport — two columns when there's room, one when there isn't. */
#cfg-body { padding: 18px; display: flex; flex-direction: column; gap: 20px; container-type: inline-size; }
.cfg-mode-row, .skins-tabs, .viz-tabs { display: flex; flex-wrap: wrap; gap: 8px; }
/* Skins / Visualizer pills keep their natural width and drop to the next line when the row is too narrow. */
.skin-tab, .viz-tab { flex: 1 0 auto; white-space: nowrap; }
/* M3 outlined → tonal on select (segmented-button style). */
.cfg-mode-btn, .skin-tab, .viz-tab {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  flex: 1; background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--muted);
  font-family: var(--fn); font-weight: 700; font-size: 12px; padding: 10px; cursor: pointer;
  transition: all .15s;
}
.cfg-mode-btn .material-symbols-outlined, .skin-tab .material-symbols-outlined, .viz-tab .material-symbols-outlined { font-size: 15px; }
.cfg-mode-btn:hover, .skin-tab:hover, .viz-tab:hover { border-color: var(--accent); color: var(--text); background: var(--st-hover); }
.cfg-mode-btn.on, .skin-tab.on, .viz-tab.on { border-color: var(--accent); color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.cfg-section { display: none; flex-direction: column; gap: 20px; }
.cfg-section.on { display: grid; grid-template-columns: minmax(0, 1fr); gap: 20px; align-items: stretch; }   /* stretch: cards in the same row share a height instead of leaving ragged gaps */
@container (min-width: 820px) {
  .cfg-section.on { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.cfg-hint { font-family: var(--fm); font-size: 10px; color: var(--muted); line-height: 1.5; margin-bottom: 6px; }
.dj-list { display: flex; flex-direction: column; gap: 4px; }
.dj-item { display: flex; align-items: center; gap: 10px; width: 100%; padding: 6px 10px; background: none; border: 1px solid transparent; border-radius: var(--sh-md, var(--sh-sm)); color: var(--text); font: inherit; text-align: left; cursor: pointer; transition: background .15s, border-color .15s; }
.dj-item:hover:not(:disabled) { background: var(--st-hover); border-color: var(--brd2); }
.dj-item:disabled { cursor: default; }
.dj-item.is-dj { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.dj-name { flex: 1; min-width: 0; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dj-you { color: var(--muted); font-size: 10px; }
.dj-tag { font-family: var(--fm); font-size: 9px; color: var(--accent); letter-spacing: .05em; }
.dj-ico { font-size: 18px; color: var(--muted); }
.dj-item { cursor: default; }
.dj-acts { display: inline-flex; gap: 4px; flex-shrink: 0; flex-wrap: wrap; justify-content: flex-end; }
.dj-btn { padding: 4px 8px; }
.dj-sub { font-family: var(--fm); font-size: 9px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin: 8px 6px 2px; }
.dj-item.is-banned { opacity: .8; }
.dj-item.is-dj .dj-ico { color: var(--accent); }
.dj-item:hover:not(:disabled) .dj-ico { color: var(--accent); }
.pchip.is-dj { border-color: var(--accent2, var(--accent)); }
/* M3 filled card (surface-container). */
.cfg-block { display: flex; flex-direction: column; gap: 6px; padding: 18px; background: var(--surf); border: 1px solid var(--brd); border-radius: var(--sh-lg); }
.cfg-block .overlay-form { gap: 6px; }
.cfg-block label { font-family: var(--fm); font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.cfg-label { font-family: var(--fn); font-weight: 700; font-size: 12px; color: var(--text); margin-bottom: 4px; }
.cfg-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; margin-bottom: 2px;}
.cfg-row label { margin-top: 0; }
.mono-sm, .mono-lg.sm { font-family: var(--fm); font-size: 13px; letter-spacing: .1em; color: var(--accent); min-width: 0; overflow-wrap: anywhere; }
.radio-row.inline { flex-direction: row; }
.radio-row.inline { flex-wrap: wrap; }
.radio-row.inline .radio-opt { flex: 1 1 0; min-width: 0; flex-wrap: wrap; }   /* the (hint) drops to its own line instead of clipping */
#cfg-lobby-name:disabled, #cfg-display-name:disabled { opacity: .5; cursor: not-allowed; }
.radio-row.inline input:disabled { cursor: not-allowed; }

/* EMPTY / LOADING */
.empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 48px 20px; color: var(--muted); text-align: center; flex: 1; }
.empty .material-symbols-outlined { font-size: 44px; opacity: .3; }
.empty p { font-family: var(--fm); font-size: 11px; }
.dots { display: inline-flex; gap: 4px; align-items: center; }
.dots span { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); animation: dp 1.2s ease-in-out infinite; }
.dots span:nth-child(2){animation-delay:.2s} .dots span:nth-child(3){animation-delay:.4s}
@keyframes dp { 0%,80%,100%{transform:scale(.55);opacity:.4} 40%{transform:scale(1);opacity:1} }

/* TOAST — M3 Snackbar: extra-small shape, single elevated surface. */
#toasts { position: fixed; bottom: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 600; pointer-events: none; }
.toast { display: flex; align-items: flex-start; gap: 8px; background: var(--surf3); border: 1px solid var(--brd2); border-left: 3px solid var(--accent); border-radius: var(--sh-xs); color: var(--text); font-family: var(--fm); font-size: 11px; padding: 10px 14px; min-width: 220px; max-width: 340px; animation: tin .25s ease; box-shadow: var(--ev3); line-height: 1.4; }
.toast-ico { flex-shrink: 0; font-size: 16px; margin-top: 1px; color: var(--accent); }
.toast-msg { flex: 1; }
.toast.err { border-left-color: var(--red); }
.toast.err .toast-ico { color: var(--red); }
.toast.ok  { border-left-color: var(--green); }
.toast.ok .toast-ico { color: var(--green); }
.toast.warn{ border-left-color: var(--amber); }
.toast.warn .toast-ico { color: var(--amber); }
.toast.busy { border-left-color: var(--accent); }
.toast-spin { flex-shrink: 0; width: 12px; height: 12px; margin: 2px 2px 0; border: 2px solid var(--brd2); border-top-color: var(--accent); border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes tin { from{transform:translateX(16px);opacity:0} to{transform:translateX(0);opacity:1} }

/* MEANING MODAL — M3 Dialog: extra-large shape, high elevation. */
#meaning-modal { display: none; position: fixed; inset: 0; background: color-mix(in srgb, var(--bg) 85%, transparent); z-index: 300; align-items: center; justify-content: center; padding: 20px; }
#meaning-modal.show { display: flex; }
#meaning-box { background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-xl); box-shadow: var(--ev3); max-width: 560px; width: 100%; max-height: 80vh; overflow-y: auto; padding: 26px; }
#meaning-title { font-size: 18px; font-weight: 700; margin-bottom: 4px; }
#meaning-sub { font-family: var(--fm); font-size: 11px; color: var(--muted); margin-bottom: 16px; }
#meaning-body { font-size: 13px; line-height: 1.75; color: var(--muted); }
#meaning-body p { margin-bottom: 12px; }
#meaning-close { display: flex; align-items: center; justify-content: center; gap: 5px; margin-top: 16px; background: none; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--muted); font-family: var(--fm); font-size: 11px; text-transform: uppercase; padding: 8px 16px; cursor: pointer; transition: all .15s; }
#meaning-close .material-symbols-outlined { font-size: 14px; }
#meaning-close:hover { border-color: var(--red); color: var(--red); background: color-mix(in srgb, var(--red) 8%, transparent); }

@media (max-width: 1000px) {
  #main { flex-direction: column; }

  /* The whole player becomes a single square: art fills it edge-to-edge as
     a background layer, and player-panel (info/progress/ctrls)
     is overlaid on top of it, anchored to the bottom. Nothing here scrolls
     or grows past the square — overflow is just clipped — so there's never
     a scrollbar inside the player on small screens. */
  #left {
    width: 100%; border-right: none; border-bottom: 1px solid var(--brd);
    max-height: none; overflow: hidden; position: relative; aspect-ratio: 1;
  }
  #art-wrap {
    position: absolute; inset: 0; max-height: none; aspect-ratio: auto; z-index: 0;
  }
  #player-panel {
    position: absolute; left: 0; right: 0; bottom: 0; top: auto; z-index: 2;
    max-height: 100%; overflow: hidden;
    background: linear-gradient(to top, color-mix(in srgb, var(--bg) 94%, transparent) 0%, color-mix(in srgb, var(--bg) 82%, transparent) 60%, transparent 100%);
  }
  #info, #prog-wrap, #ctrls { border-bottom-color: rgba(255,255,255,.08); }
  .mode-grid { grid-template-columns: 1fr; }

  /* Tabs: a bit tighter so more of them fit before you have to scroll. */
  .tab { padding: 10px 12px; font-size: 10px; }

  /* Search bar: input+select+button no longer fit on one line at phone
     widths (the button was getting clipped off the right edge) — put the
     search term on its own row and let source/button share the second. */
  #search-bar { flex-wrap: wrap; }
  #si { flex: 1 1 100%; min-width: 0; }
  #src-sel { flex: 1; min-width: 0; }
  #btn-srch { flex: 0 0 auto; }

  /* Chat: the log+input column and the participants sidebar no longer fit
     side by side — stack the (short) participants list above the log
     instead of squeezing both into half-width columns. */
  #pane-chat { flex-direction: column; }
  #chat-main { border-right: none; border-bottom: 1px solid var(--brd); min-height: 0; }
  #chat-users { width: 100%; max-height: 96px; padding: 8px 10px; border-bottom: 1px solid var(--brd); }
  #chat-users-list { display: flex; flex-wrap: wrap; gap: 4px; }
  .cu-item { padding: 4px 8px; background: var(--surf2); border-radius: var(--sh-full); }
  .cu-meta { display: flex; align-items: center; }
  .cu-tag { margin-left: 4px; }
}

/* Row-action buttons (search results' Play/Queue, queue items' reorder/
   remove, the drag handle) are opacity:0-until-:hover, which on a touch
   screen never fires — they'd be invisible and effectively unusable.
   Keep them always visible wherever there's no hover capability at all,
   phone or tablet, regardless of viewport width. */
@media (hover: none) {
  .si-acts, .qi-bs, .qi-drag { opacity: 1; }
}
/* ═══════════════ Queue: requester chips ═══════════════ */
.qi-req {
  font-family: var(--fm); font-size: 9px; letter-spacing: .04em;
  color: var(--muted2); border: 1px solid var(--brd2); padding: 1px 7px;
  margin-left: 7px; border-radius: var(--sh-full); white-space: nowrap;
}
.qi-req.mine { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.qi-req.auto { color: var(--accent2); border-color: color-mix(in srgb, var(--accent2) 30%, transparent); }
.chip-ico { font-size: 10px !important; vertical-align: -1px; margin-right: 2px; }
.qa.on { border-color: var(--green); color: var(--green); }

/* ═══════════════ Skins tab ═══════════════ */
#pane-skins { overflow: hidden; }
#skins-hdr {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 16px;
  border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0;
}
.skins-tabs { flex: 1 1 100%; min-width: 0; }
#skins-mine-count { color: var(--muted2); }

#skins-body { flex: 1; overflow-y: auto; padding: 16px; }
.skin-pane { display: none; flex-direction: column; }
.skin-pane.on { display: flex; }
.skin-section { margin-bottom: 22px; }
.skin-row { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.skin-row label {
  font-family: var(--fm); font-size: 10px; color: var(--muted);
  width: 96px; flex-shrink: 0; text-transform: uppercase; letter-spacing: .06em;
}
.skin-row .hi { flex: 1; min-width: 0; }
.hi.bad { border-color: var(--amber); }

.skin-preset-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 6px; }

.skin-color-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 8px; }
.skin-color { display: flex; align-items: center; gap: 8px; }
.skin-swatch {
  -webkit-appearance: none; appearance: none; width: 34px; height: 34px;
  padding: 0; border: 1px solid var(--brd2); border-radius: var(--sh-sm); background: none; cursor: pointer; flex-shrink: 0;
}
.skin-swatch::-webkit-color-swatch-wrapper { padding: 2px; }
.skin-swatch::-webkit-color-swatch { border: none; border-radius: var(--sh-xs); }
.skin-color-meta { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.skin-color-label { font-family: var(--fm); font-size: 9px; color: var(--muted); text-transform: uppercase; letter-spacing: .08em; }
.skin-color-text { font-size: 10px !important; padding: 3px 6px !important; width: 100%; }

.skin-css {
  width: 100%; min-height: 120px; resize: vertical; line-height: 1.5;
  font-size: 11px; white-space: pre; overflow-x: auto;
}
.skin-warn { color: var(--amber); font-weight: 400; letter-spacing: 0; text-transform: none; margin-left: 6px; }
.skin-note {
  font-family: var(--fm); font-size: 10px; color: var(--muted);
  line-height: 1.6; margin-top: 8px; padding: 9px 11px;
  border-left: 2px solid var(--brd2); border-radius: var(--sh-xs); background: var(--surf2);
}
.skin-note code { color: var(--accent2); }

.skin-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-bottom: 8px; }
.skin-actions .overlay-btn { margin-top: 0; }
/* Skins: Save | Publish | Reset on the first row, Export | Import on the second. */
.skin-actions-main { grid-template-columns: repeat(6, 1fr); }
.skin-actions-main .overlay-btn { grid-column: span 2; }
.skin-actions-main .overlay-btn:nth-child(n+4) { grid-column: span 3; }

.skin-browse-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.skin-sort { display: flex; gap: 4px; flex: 1; }

.skin-list { display: flex; flex-direction: column; gap: 6px; }
.skin-card {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  background: var(--surf); border: 1px solid var(--brd); border-radius: var(--sh-md); transition: border-color .15s;
}
.skin-card:hover { border-color: var(--accent); }
.skin-card-swatches { display: flex; flex-shrink: 0; border: 1px solid var(--brd2); border-radius: var(--sh-xs); overflow: hidden; }
.skin-sw { width: 16px; height: 34px; display: block; }
.skin-card-meta { flex: 1; min-width: 0; }
.skin-card-name { font-weight: 600; font-size: 13px; display: flex; align-items: center; gap: 6px; }
.skin-card-author { font-family: var(--fm); font-size: 10px; color: var(--muted); margin-top: 2px; }
.skin-badge {
  font-family: var(--fm); font-size: 8px; letter-spacing: .08em;
  padding: 2px 6px; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--muted);
}
.skin-badge.pub { color: var(--green); border-color: color-mix(in srgb, var(--green) 30%, transparent); }
.skin-badge.css { color: var(--amber); border-color: color-mix(in srgb, var(--amber) 30%, transparent); }
.skin-card-acts { display: flex; gap: 5px; flex-shrink: 0; }

@media (max-width: 700px) {
  .skin-actions, .skin-actions-main { grid-template-columns: 1fr; }
  .skin-actions-main .overlay-btn, .skin-actions-main .overlay-btn:nth-child(n+4) { grid-column: auto; }
  .skin-color-grid { grid-template-columns: 1fr 1fr; }
  .skin-card { flex-wrap: wrap; }
}

/* ═══════════════ Visualizer tab ═══════════════ */
#pane-viz { overflow: hidden; }
#viz-hdr {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 12px 16px;
  border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0;
}
.viz-tabs { flex: 1 1 100%; min-width: 0; }
#viz-mine-count { color: var(--muted2); }
/* Name + fullscreen sit in the stage's top-right corner, invisible until the
   pointer is over the stage (or something inside the group has focus). */
.viz-overlay {
  position: absolute; top: 10px; right: 10px; z-index: 2;
  display: flex; align-items: center; gap: 8px; max-width: calc(100% - 20px);
  padding: 4px 4px 4px 12px; border-radius: var(--sh-full);
  background: color-mix(in srgb, var(--bg) 60%, transparent);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  opacity: 0; pointer-events: none; transition: opacity .2s;
}
#viz-stage:hover .viz-overlay, .viz-overlay:focus-within { opacity: 1; pointer-events: auto; }
@media (hover: none) { .viz-overlay { opacity: .75; pointer-events: auto; } }   /* touch has no hover */
.viz-active-name {
  min-width: 0; text-align: right; font-family: var(--fm); font-size: 10px;
  color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

#viz-body { flex: 1; overflow-y: auto; padding: 16px; min-height: 0; }
.viz-pane { display: none; flex-direction: column; min-height: 0; }
.viz-pane.on { display: flex; }
#vtab-stage { flex: 1; }

#viz-stage {
  position: relative; width: 100%; aspect-ratio: 16 / 9; min-height: 220px;
  background: var(--surf2); border: 1px solid var(--brd); border-radius: var(--sh-lg);
  overflow: hidden; flex-shrink: 0;
}
#viz-stage:fullscreen { aspect-ratio: auto; height: 100%; border: none; border-radius: 0; background: var(--bg); }
.viz-frame { width: 100%; height: 100%; border: 0; display: block; background: transparent; }

.viz-error {
  display: none; margin-top: 10px; padding: 9px 11px;
  border-left: 3px solid var(--red); border-radius: var(--sh-xs); background: color-mix(in srgb, var(--red) 7%, transparent);
  font-family: var(--fm); font-size: 11px; color: var(--red); line-height: 1.5; word-break: break-word;
}
.viz-error.show { display: block; }
.viz-stage-note {
  margin-top: 10px; font-family: var(--fm); font-size: 10px;
  color: var(--muted); line-height: 1.6;
}

.viz-code {
  width: 100%; min-height: 300px; resize: vertical; line-height: 1.55;
  font-family: var(--fm); font-size: 11px; white-space: pre; overflow: auto; tab-size: 2;
}

.viz-card {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  background: var(--surf); border: 1px solid var(--brd); border-radius: var(--sh-md); transition: border-color .15s;
}
.viz-card:hover { border-color: var(--accent); }
.viz-card-meta { flex: 1; min-width: 0; }
.viz-card-name { font-weight: 600; font-size: 13px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.viz-card-author { font-family: var(--fm); font-size: 10px; color: var(--muted); margin-top: 2px; }
.viz-card-acts { display: flex; gap: 5px; flex-shrink: 0; }

@media (max-width: 700px) {
  #viz-stage { aspect-ratio: 4 / 3; min-height: 180px; }
  .viz-card { flex-wrap: wrap; }
}
/* ═══════════════════ DEBUG TAB ═══════════════════ */
#pane-debug { overflow: hidden; }
#dbg-root { flex: 1; overflow-y: auto; min-height: 0; }
.dbg-wrap { display: flex; flex-direction: column; gap: 16px; padding: 16px; }

.dbg-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.dbg-title { display: inline-flex; align-items: center; gap: 6px; font-weight: 800; font-size: 15px; color: var(--accent); letter-spacing: .04em; }
.dbg-title .material-symbols-outlined { font-size: 17px; }
.dbg-sub { font-family: var(--fm); font-size: 10px; color: var(--muted); flex: 1; }

.dbg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 8px; }
.dbg-card { background: var(--surf); border: 1px solid var(--brd); border-radius: var(--sh-sm); padding: 10px 12px; min-width: 0; }
.dbg-card-k { font-family: var(--fm); font-size: 9px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; margin-bottom: 4px; }
.dbg-card-v { font-family: var(--fm); font-size: 12px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.dbg-section { background: var(--surf); border: 1px solid var(--brd); border-radius: var(--sh-md); padding: 13px 15px; min-width: 0; }
.dbg-section-title { font-weight: 700; font-size: 12px; color: var(--text); margin-bottom: 10px; display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px; }
.dbg-count { font-family: var(--fm); font-size: 10px; color: var(--muted); font-weight: 400; }
.dbg-lane-hint { font-family: var(--fm); font-size: 9px; color: var(--muted); font-weight: 400; }
@media (max-width: 700px) {
  /* the long hint gets its own line under the title; the buttons/status wrap on the line after it */
  .dbg-section-title { row-gap: 6px; align-items: center; }
  .dbg-lane-hint { flex: 1 1 100%; min-width: 0; }
}

.dbg-wave-canvas {
  display: block; width: 100%; height: 110px; border-radius: var(--sh-sm);
  background: var(--surf2); border: 1px solid var(--brd);
}
.dbg-wave-canvas-buf { height: 80px; }

.dbg-seg-toggle { display: flex; gap: 4px; margin-left: auto; }
.dbg-seg-btn {
  background: none; border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--muted);
  font-family: var(--fm); font-size: 9px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; padding: 4px 10px; cursor: pointer; transition: all .15s;
}
.dbg-seg-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--st-hover); }
.dbg-seg-btn.on { border-color: var(--accent2); color: var(--accent2); background: color-mix(in srgb, var(--accent2) 10%, transparent); }

.dbg-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 900px) { .dbg-cols { grid-template-columns: 1fr; } }

.dbg-scroll { max-height: 240px; overflow-y: auto; }
.dbg-table { width: 100%; border-collapse: collapse; font-family: var(--fm); font-size: 10.5px; }
.dbg-table th {
  position: sticky; top: 0; background: var(--surf); text-align: left; color: var(--muted);
  font-weight: 600; text-transform: uppercase; letter-spacing: .04em; font-size: 9px;
  padding: 4px 6px; border-bottom: 1px solid var(--brd2);
}
.dbg-table td { padding: 4px 6px; border-bottom: 1px solid var(--brd); color: var(--text); white-space: nowrap; }
.dbg-table td.dbg-mono { max-width: 160px; overflow: hidden; text-overflow: ellipsis; }
.dbg-table tr.dbg-row-err td { color: var(--red); }
.dbg-empty-row { color: var(--muted2); text-align: center; padding: 10px !important; }

.dbg-list { display: flex; flex-direction: column; gap: 3px; }
.dbg-list-row {
  display: flex; gap: 10px; align-items: baseline; font-family: var(--fm); font-size: 10.5px;
  padding: 4px 6px; background: var(--surf2); border-radius: var(--sh-xs); border-left: 2px solid var(--brd2);
}
.dbg-list-row.dbg-row-err { border-left-color: var(--red); color: var(--red); }
.dbg-list-row.dbg-row-warn { border-left-color: var(--amber); color: var(--amber); }
.dbg-muted { color: var(--muted); margin-left: auto; }
/* ═══════════════ PLAYER + TABS LAYOUT ═══════════════
   The page itself never scrolls any more: the header stays put and everything
   under it is exactly one viewport tall. Two layouts:

   1) Side-by-side (desktop, and any phone/tablet in landscape): the player
      column fills the full height on the left and never moves; the tab strip
      stays at the top of the right column and the *tab content* scrolls
      inside its own box (each pane's list / body has its own overflow).
      The column width is fitted to the viewport height in main.js
      (_initFitPlayerHeight) so the square art + controls leave no gap.
   2) Stacked (portrait phone): see the last block below. */
html, body { overflow: hidden; }
body { height: 100vh; height: 100dvh; }
/* #app is a viewport-tall column: header (+ CORS note) on top, #main fills the rest. */
#app { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#app > .hdr, #app > #cors-note { flex-shrink: 0; }
#main { min-height: 0; overflow: hidden; }

/* ── 1) side-by-side ── */
@media (min-width: 1001px), (max-width: 1000px) and (orientation: landscape) {
  #main { --left-w: 480px; }
  #left {
    width: var(--left-w); height: 100%; min-height: 0;
    border-right: none;      /* #right draws the divider */
    overflow-y: auto;        /* only if the controls ever outgrow the screen */
  }
  /* Cover height is fitted to the window by main.js (_initFitPlayerHeight) so the player
     never needs a scrollbar; square when there's room, shorter (image crops) when not. */
  #art-wrap { height: var(--art-h, var(--left-w)); aspect-ratio: auto; }
  #right { overflow: hidden; border-left: 1px solid var(--brd); }
  #tabs { z-index: 20; box-shadow: var(--ev2); }
}

/* Landscape phones / small tablets: side-by-side instead of the portrait
   "art square with the controls overlaid" layout from the 1000px query
   above (which is as tall as the screen is wide — bigger than the whole
   screen when it's on its side). */
@media (max-width: 1000px) and (orientation: landscape) {
  #main { --left-w: clamp(280px, 36vw, 380px); flex-direction: row; }
  #left { aspect-ratio: auto; border-bottom: none; overflow-x: hidden; overflow-y: auto; }
  /* Art shrinks to whatever height is left after the controls. */
  #art-wrap { position: relative; inset: auto; aspect-ratio: 1; z-index: auto; flex: 0 1 auto; min-height: 72px; }
  #player-panel { position: static; max-height: none; overflow: visible; background: none; }
  #info, #prog-wrap, #ctrls { border-bottom-color: var(--brd); }
  /* Narrow column: let the secondary row wrap, volume on its own line. */
  #ctrls-sec { flex-wrap: wrap; row-gap: 8px; }
  #ctrls-sec .hsep { display: none; }
  #vol-row { flex: 1 1 100%; order: 10; }
}

/* ── 2) stacked, portrait ──
   The art scrolls away and the player's bottom half (title, progress,
   controls) stays frozen at the top, with #tabs pinned beneath it. That only
   works if the art, the panel and the tab content share ONE scroller, so in
   this layout the scroller is #main (everything below the header) — the
   header and the browser page no longer scroll. #left sticks once its top edge
   reaches a *negative* offset: the art's height minus the panel's height. The
   two heights are measured in main.js (_initStickyPlayer). */
@media (max-width: 1000px) and (orientation: portrait) {
  #main { overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; }
  #left {
    flex: none;
    position: sticky; z-index: 30;
    top: calc(var(--player-panel-h, 190px) - var(--player-left-h, 100vw));
    box-shadow: var(--ev3);
  }
  #right { flex: none; overflow: visible; }
  #tabs {
    position: sticky; z-index: 20;
    top: var(--player-panel-h, 190px);
    box-shadow: var(--ev2);
  }
}

/* ── portrait phone: one-line header + collapse-on-scroll ──
   The page is one scroller (#main) under a header, so the header and the
   secondary controls (loop / gapless / shuffle / info / download / volume)
   used to take a big slice of a small screen for good. main.js
   (_initPortraitCompact) toggles body.np-compact while the user scrolls
   down and removes it again on a scroll up or at the very top. Compact =
   the header is gone and only the now-playing card, progress bar and the
   transport row stay pinned. Both collapse through max-height (animated);
   `visibility` flips after the animation so hidden buttons can't be tabbed
   to or tapped. The header is also forced onto ONE line: "NP" instead of
   the wordmark, and the participants overlap like a fanned stack of cards
   (see Lobby._fitParticipants, which sets --pstep from the room available). */
.logo-short { display: none; }
@media (max-width: 1000px) and (orientation: portrait) {
  .hdr {
    flex-wrap: nowrap; gap: 8px; padding: 8px 12px; overflow: hidden; max-height: 64px;
    transition: max-height .2s ease, padding .2s ease, opacity .15s ease, border-width .2s ease, visibility 0s;
  }
  .logo { gap: 4px; font-size: 15px; letter-spacing: .1em; }
  .logo-full { display: none; }
  .logo-short { display: inline; }
  .pcm-badge { display: none; }
  #stxt { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .hdr-btn { padding: 6px 12px; }
  .hdr-btn.ghost { padding: 0; }
  .lobby-code-badge { font-size: 12px; letter-spacing: .16em; padding: 4px 9px; }

  /* The strip takes whatever width is left on the line, flush against Leave. */
  #hdr-lobby .hdr-fill { display: none; }
  #participants-strip { --psize: 24px; flex: 1 1 0; min-width: 0; justify-content: flex-end; overflow: hidden; }
  #participants-strip .pchip { width: var(--psize); height: var(--psize); flex-shrink: 0; margin-left: calc(var(--pstep, 16px) - var(--psize)); }
  #participants-strip .pchip:first-child { margin-left: 0; }

  #ctrls-sec { overflow: hidden; max-height: 200px; transition: max-height .2s ease, opacity .15s ease, visibility 0s; }
  #ctrls-main { transition: margin-bottom .2s ease; }
  #ctrls { transition: padding .2s ease; }

  body.np-compact .hdr {
    max-height: 0; padding-top: 0; padding-bottom: 0; opacity: 0; border-bottom-width: 0; visibility: hidden;
    transition: max-height .2s ease, padding .2s ease, opacity .15s ease, border-width .2s ease, visibility 0s .2s;
  }
  body.np-compact #ctrls-sec { max-height: 0; opacity: 0; visibility: hidden; transition: max-height .2s ease, opacity .15s ease, visibility 0s .2s; }
  body.np-compact #ctrls-main { margin-bottom: 0; }
  body.np-compact #ctrls { padding-top: 8px; padding-bottom: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .hdr, #ctrls-sec, #ctrls-main, #ctrls { transition: none !important; }
}

/* buffered-waveform legend (Debug tab) */
.dbg-key { display: inline-flex; align-items: center; gap: 4px; margin-left: 8px; font-family: var(--fm); font-size: 9px; font-weight: 400; color: var(--muted); }
.dbg-key-sw { display: inline-block; width: 8px; height: 8px; border-radius: var(--sh-xs); }
.dbg-key-sw.played { background: rgba(148,163,184,.55); }
.dbg-key-sw.ready { background: color-mix(in srgb, var(--accent2) 90%, transparent); }

/* ═══════════════ GAME CONTROLLER BADGE ═══════════════ */
.pad-badge {
  display: none; align-items: center; gap: 6px; flex-shrink: 0; cursor: help;
  font-family: var(--fm); font-size: 9px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--green); padding: 4px 9px; border-radius: var(--sh-full);
  background: color-mix(in srgb, var(--green) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--green) 30%, transparent);
  transition: background .12s;
}
.pad-badge svg { width: 14px; height: 14px; flex-shrink: 0; }
.pad-badge .material-symbols-outlined { font-size: 15px; }
.pad-badge.hit { background: color-mix(in srgb, var(--green) 32%, transparent); }
@media (max-width: 700px) { .pad-badge .pad-lbl { display: none; } .pad-badge { padding: 4px 7px; } }

/* ═══════════════ BINDINGS TAB ═══════════════ */
#bindings-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; padding: 14px 16px; border-bottom: 1px solid var(--brd); flex-wrap: wrap; }
.bnd-head-txt h3 { margin: 0 0 4px; font-size: 14px; }
.bnd-head-txt p { margin: 0; font-size: 11px; color: var(--muted); max-width: 46ch; }
.bnd-head-acts { display: flex; gap: 8px; flex-shrink: 0; }
.bnd-col-h { display: grid; grid-template-columns: 1fr 140px 140px; gap: 8px; padding: 8px 16px; font-family: var(--fm); font-size: 9px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--brd); }
#bindings-list { flex: 1; overflow-y: auto; padding: 4px 0 16px; }
.bnd-group-h { padding: 12px 16px 6px; font-family: var(--fm); font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--accent2); }
.bnd-row { display: grid; grid-template-columns: 1fr 140px 140px; gap: 8px; align-items: center; padding: 6px 16px; }
.bnd-row:hover { background: var(--st-hover); }
.bnd-lbl { font-size: 12px; }
.bnd-cell { display: flex; align-items: center; gap: 4px; min-width: 0; }
.bnd-btn { flex: 1; min-width: 0; background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-xs); color: var(--text); font-family: var(--fm); font-size: 11px; padding: 6px 8px; cursor: pointer; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: border-color .12s, background .12s; }
.bnd-btn:hover { border-color: var(--accent); }
.bnd-btn.listening { border-color: var(--green); color: var(--green); background: color-mix(in srgb, var(--green) 10%, transparent); animation: bnd-pulse 1s ease-in-out infinite; }
@keyframes bnd-pulse { 0%,100% { opacity: 1; } 50% { opacity: .6; } }
.bnd-x { flex-shrink: 0; width: 22px; height: 22px; display: flex; align-items: center; justify-content: center; background: none; border: none; color: var(--muted); cursor: pointer; border-radius: var(--sh-xs); }
.bnd-x:hover { color: var(--text); background: var(--surf2); }
.bnd-x .material-symbols-outlined { font-size: 15px; }
@media (max-width: 700px) {
  .bnd-col-h, .bnd-row { grid-template-columns: 1fr 100px 100px; }
  .bnd-head-txt p { max-width: none; }
  /* the two reset buttons share a full-width row at equal widths */
  .bnd-head-txt { flex: 1 1 100%; }
  .bnd-head-acts { flex: 1 1 100%; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .bnd-head-acts .add-btn { justify-content: center; min-width: 0; padding-left: 4px; padding-right: 4px; white-space: nowrap; }
}

/* ═══════════════ ON-SCREEN KEYBOARD ═══════════════ */
/* No floating trigger button — it opens only via a controller's A
   button while a text field has focus (see gamepad.js's _process). */
#vk-overlay {
  position: fixed; inset: 0; z-index: 9995; display: none; align-items: flex-end; justify-content: center;
  background: rgba(4,4,12,.55); backdrop-filter: blur(2px);
}
#vk-overlay.show { display: flex; }
#vk-panel {
  width: 100%; max-width: 620px; background: var(--surf); border: 1px solid var(--brd2); border-bottom: none;
  border-radius: var(--sh-md) var(--sh-md) 0 0; padding: 12px 14px calc(14px + env(safe-area-inset-bottom, 0px));
  box-shadow: 0 -8px 30px rgba(0,0,0,.4);
}
#vk-preview {
  font-family: var(--fm); font-size: 13px; min-height: 20px; padding: 8px 10px; margin-bottom: 10px;
  background: var(--surf2); border: 1px solid var(--brd); border-radius: var(--sh-xs); color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#vk-preview.empty { color: var(--muted); }
#vk-rows { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.vk-row { display: flex; gap: 6px; justify-content: center; }
.vk-k {
  flex: 1; max-width: 46px; height: 38px; display: flex; align-items: center; justify-content: center;
  background: var(--surf2); border: 1px solid var(--brd2); border-radius: var(--sh-xs); color: var(--text);
  font-family: var(--fm); font-size: 13px; text-transform: none; cursor: pointer; transition: background .1s, border-color .1s;
}
.vk-k:hover { border-color: var(--accent); }
.vk-k.sel { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, transparent); }
#vk-bottom { display: flex; gap: 6px; flex-wrap: wrap; }
#vk-bottom .vk-k { flex: 1; max-width: none; font-size: 11px; font-weight: 600; letter-spacing: .04em; }
#vk-bottom .vk-space { flex: 2; }
#vk-bottom [data-vk="shift"].on { border-color: var(--accent2); color: var(--accent2); }
#vk-bottom .vk-go { border-color: var(--green); color: var(--green); }
@media (max-width: 700px) {
  .vk-k { max-width: none; height: 34px; font-size: 12px; }
}

/* ═══════════════ IN-PLACE CONTROLLER BUTTON PROMPTS ("game controller only") ═══════════════ */
/* Each bound action's real GUI control (play button, a tab, an
   on-screen-keyboard key, ...) grows a small badge naming what's bound
   to it — see Pad.ACTION_EL / Pad._renderElementHints in gamepad.js.
   .pad-hint-host just gives the control `position: relative` so the
   badge can anchor to it without affecting layout; visibility is a
   single class on <body> so no per-badge JS toggling is needed. */
.pad-hint-host { position: relative; }
.pad-hint {
  position: absolute; left: 50%; bottom: 3px; transform: translateX(-50%);
  font-family: var(--fm); font-size: 8px; font-weight: 800; line-height: 1; letter-spacing: 0;
  padding: 2px 4px; border-radius: var(--sh-full);
  background: rgba(10,10,18,.88); color: var(--accent); border: 1px solid var(--brd2);
  pointer-events: none; opacity: 0; transition: opacity .12s;
  white-space: nowrap; z-index: 3;
}
body.pad-active .pad-hint:not(.pad-hint-playeronly) { opacity: 1; }
/* Playback/Queue-group badges (play, seek, loop, ...) only light up
   while the player actually has controller focus — see the focus-zone
   note in gamepad.js. Tab-opening and on-screen-keyboard badges are
   exempt (not .pad-hint-playeronly) and stay lit in either zone. */
body.pad-active:not(.pad-tabs-focused) .pad-hint-playeronly { opacity: 1; }
/* A visible cue for which zone currently has controller focus: the
   player control bar dims and drops its "focused" outline once a tab
   takes over, and picks both back up when focus returns to it. */
body.pad-active #ctrls { transition: opacity .15s, filter .15s, outline-color .15s; }
body.pad-active:not(.pad-tabs-focused) #ctrls { outline: 1px solid var(--accent); outline-offset: 6px; border-radius: var(--sh-md); }
body.pad-active.pad-tabs-focused #ctrls { opacity: .45; filter: saturate(.5); outline: 1px solid transparent; outline-offset: 6px; }
/* Makes it obvious what navUp/navDown/navSelect currently landed on —
   only while actually navigating a tab with the controller, so it
   doesn't add a focus ring for ordinary mouse/keyboard use. */
body.pad-active.pad-tabs-focused .pane :focus {
  outline: 2px solid var(--accent) !important;
  outline-offset: 2px;
}
/* Wide/rectangular controls (tabs, the keyboard trigger) get a corner
   badge instead — a bottom-center one would sit on top of their label. */
.pad-hint.corner { left: auto; right: 1px; top: 1px; bottom: auto; transform: none; }
.cb.sm .pad-hint { font-size: 7px; padding: 1px 3px; bottom: 1px; }

/* ── Saved Sessions + reconnect banner ── */
.ss-item { display:flex; align-items:center; gap:8px; padding:8px 10px; background:var(--st-hover); border-radius:var(--sh-lg); }
.ss-info { flex:1; min-width:0; display:flex; flex-direction:column; gap:2px; }
.ss-name { font-size:13px; color:var(--text); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.ss-meta { font-family:var(--fm); font-size:10px; color:var(--muted); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
#sessions-save:disabled { opacity:.45; cursor:default; }
#heal-banner { position:fixed; top:0; left:0; right:0; z-index:9999; align-items:center; justify-content:center; gap:10px; padding:8px 16px; background:var(--surf); border-bottom:1px solid var(--brd); color:var(--text); font-size:13px; box-shadow:var(--ev2); }
.heal-spin { font-size:18px; animation:heal-rot 1.2s linear infinite; }
@keyframes heal-rot { to { transform:rotate(360deg); } }

/* ── Lobby password ── */
.pass-btns { display:flex; gap:8px; }
.pass-btns .overlay-btn { flex:1; }
.pass-btns .overlay-btn:disabled { opacity:.45; cursor:default; }
.pl-lock { font-size:14px; vertical-align:-2px; color:var(--muted); }
/* ═══════════════ MARQUEE ═══════════════
   Overflowing single-line text (see Marquee in utils.js) scrolls to its end
   and back instead of showing "…". The text sits in a .mq-in wrapper that the
   script adds, and only its transform is animated — no layout work per frame.
   It holds briefly at each end. */
.mq { text-overflow: clip !important; }
.mq > .mq-in {
  display: inline-block;
  vertical-align: top;
  flex: none;
  white-space: nowrap;
  animation: mq-slide var(--mq-t, 8s) ease-in-out var(--mq-dl, 0s) infinite alternate;
}
@keyframes mq-slide {
  0%, 14%   { transform: translateX(0); }
  86%, 100% { transform: translateX(calc(-1 * var(--mq-d, 0px))); }
}
@media (prefers-reduced-motion: reduce) {
  .mq > .mq-in { animation: none; }
}

/* Stop button: press-and-hold (Engine.clearHistory) shows a fill while you hold. */
#btn-stop { position: relative; overflow: hidden; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; touch-action: manipulation; }
#btn-stop > * { position: relative; z-index: 1; }
#btn-stop::after { content: ''; position: absolute; inset: 0; background: var(--red); opacity: .4; transform: scaleX(0); transform-origin: left; pointer-events: none; }
#btn-stop.holding::after { transform: scaleX(1); transition: transform .8s linear; }

/* Debug tab list rows: let the title/author shrink and scroll instead of
   widening the whole card. */
.dbg-list-row > span:not(.dbg-mono) { min-width: 0; overflow: hidden; white-space: nowrap; flex: 1 1 0; }
.dbg-list-row > .dbg-muted { flex: 0 1 38%; margin-left: auto; text-align: right; }

/* ── Save-on-leave confirmation (Sessions.confirmSaveOnLeave) ── */
.confirm-overlay { position: fixed; inset: 0; z-index: 500; display: flex; align-items: center; justify-content: center; padding: 20px; background: rgba(0,0,0,.55); }
.confirm-box { width: 100%; max-width: 380px; background: var(--surf); border: 1px solid var(--brd2); border-radius: var(--sh-lg); box-shadow: var(--ev2); padding: 24px 22px; }
.confirm-title { font-size: 16px; font-weight: 800; color: var(--text); margin-bottom: 8px; }
.confirm-text { font-size: 13px; color: var(--muted); line-height: 1.5; }
.confirm-text b { color: var(--text); }
.confirm-btns { display: flex; flex-direction: column; gap: 0; }

/* ── Downloads tab (downloads.js) ── */
#dl-hdr { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; }
#dl-info { font-family: var(--fm); font-size: 10px; color: var(--muted); flex: 1; }
#dl-list { flex: 1; overflow-y: auto; padding: 6px; display: flex; flex-direction: column; }
.dl-item { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border: 1px solid transparent; border-radius: var(--sh-sm); margin-bottom: 2px; transition: background .15s, border-color .15s; flex-shrink: 0; }
.dl-item:hover { background: var(--st-hover); }
.dl-m { flex: 1; min-width: 0; }
.dl-t { font-weight: 600; font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dl-a { font-family: var(--fm); font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dl-bar { position: relative; height: 3px; margin-top: 6px; background: var(--brd2); border-radius: var(--sh-full); overflow: hidden; }
.dl-bar i { position: absolute; left: 0; top: 0; bottom: 0; width: 0; background: var(--accent); border-radius: var(--sh-full); transition: width .15s linear; }
.dl-item.done .dl-bar i { background: var(--green); }
.dl-item.error .dl-bar i { background: var(--red); width: 100% !important; }
.dl-item.canceled .dl-bar i { width: 0 !important; }
.dl-item.preparing .dl-bar i { width: 35% !important; transition: none; animation: dl-ind 1.1s ease-in-out infinite alternate; }
@keyframes dl-ind { from { transform: translateX(0); } to { transform: translateX(185%); } }
.dl-fmt { font-family: var(--fm); font-size: 9px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); border: 1px solid var(--brd2); border-radius: var(--sh-full); padding: 2px 8px; flex-shrink: 0; }
.dl-st { font-family: var(--fm); font-size: 10px; color: var(--muted); width: 150px; flex-shrink: 0; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dl-item.done .dl-st { color: var(--green); }
.dl-item.error .dl-st { color: var(--red); }
.dl-item .dl-bs { opacity: 1; }
@media (max-width: 600px) { .dl-st { width: 96px; } .dl-fmt { display: none; } }

/* ═══════════════ Portrait phone/tablet: search + queue rows ═══════════════
   Every row used to be one line: thumbnail, title AND its whole button strip
   (3 labelled pills / 6 icon buttons). On a phone the buttons took nearly the
   entire width and squeezed the title down to a couple of letters. Now each
   row is two lines — thumbnail + title/artist + duration on top, the action
   buttons on their own full-width line underneath (icon-only in search). */
/* Keyed on the width of the LIST (container query), not the screen: a narrow
   column on a desktop window crowds the title exactly like a phone does. */
@container rows (max-width: 720px) {
  .si-acts, .qi-bs { opacity: 1; }

  /* ── search results ── */
  .si {
    display: grid; align-items: center; column-gap: 10px; row-gap: 8px;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "th meta dur" "acts acts acts";
  }
  .si > .th-w { grid-area: th; }
  .si-meta { grid-area: meta; }
  .si-d { grid-area: dur; }
  .si-acts { grid-area: acts; display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 8px; }
  .si-acts .add-btn { justify-content: center; padding: 7px 0; }
  .si-acts .add-btn .lbl { display: none; }                 /* icons only */
  .si-acts .add-btn .material-symbols-outlined { font-size: 20px; }

  /* ── queue ── */
  .qi {
    display: grid; align-items: center; column-gap: 8px; row-gap: 4px;
    grid-template-columns: auto auto auto minmax(0, 1fr) auto;
    grid-template-areas: "drag n th meta dur" "bs bs bs bs bs";
  }
  .qi-drag { grid-area: drag; }
  .qi-n { grid-area: n; }
  .qi > .th-w { grid-area: th; }
  .qi-m { grid-area: meta; }
  .qi-d { grid-area: dur; }
  .qi-bs {
    grid-area: bs; display: flex; justify-content: space-between; gap: 2px;
    border-top: 1px solid var(--brd); padding-top: 4px; margin-top: 2px;
  }
  .qi-bs .qib { flex: 1; justify-content: center; padding: 7px 0; border-radius: var(--sh-full); }
  .qi-bs .qib .material-symbols-outlined { font-size: 20px; }
}
/* ── Debug › Audio analysis ── */
#dbg-metro-btn { margin-left: 0; }
#dbg-metro-btn.on { background: var(--st-focus); border-color: var(--accent); color: var(--accent); }
.aa-hero { display: flex; align-items: center; gap: 24px; flex-wrap: wrap; margin: 4px 0 12px; }
.aa-bpm { display: flex; align-items: baseline; gap: 6px; }
#aa-bpm-num { font-size: 44px; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; color: var(--accent); }
.aa-bpm-unit { font-size: 14px; opacity: .7; text-transform: uppercase; letter-spacing: .08em; }
.aa-count { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.aa-chip {
  padding: 6px 12px; border-radius: var(--sh-sm); font-size: 18px; font-weight: 600;
  font-variant-numeric: tabular-nums; border: 1px solid rgba(255,255,255,.12);
  opacity: .45; transition: opacity .06s, background .06s, transform .06s;
}
.aa-chip.on { opacity: 1; background: color-mix(in srgb, var(--pink) 22%, transparent); border-color: var(--pink); transform: scale(1.08); }
.aa-chip[data-k="1"].on { background: color-mix(in srgb, var(--amber) 25%, transparent); border-color: var(--amber); }
.aa-arrow { opacity: .35; }
.aa-none { opacity: .5; font-size: 18px; }
.aa-sec { margin-left: 10px; font-size: 12px; color: #22d3ee; opacity: .9; align-self: center; }
#aa-bpm-num.flash { animation: aa-flash .9s ease-out; }
@keyframes aa-flash { 0% { color: #22d3ee; transform: scale(1.12); } 100% { color: var(--accent); transform: scale(1); } }
.aa-tl { margin-top: 12px; display: flex; flex-direction: column; gap: 3px; font-size: 12px; }
.aa-tl-row { display: grid; grid-template-columns: 150px 1fr 56px; align-items: center; gap: 8px; }
.aa-tl-name { color: var(--text); opacity: .85; }
.aa-tl-track { position: relative; height: 8px; border-radius: var(--sh-xs); background: rgba(255,255,255,.06); overflow: hidden; }
.aa-tl-track i { position: absolute; top: 0; bottom: 0; border-radius: var(--sh-xs); background: var(--accent); }
.aa-tl-sec { text-align: right; font-variant-numeric: tabular-nums; opacity: .8; }
.aa-tl-steps { display: flex; flex-wrap: wrap; gap: 4px 12px; padding: 0 0 4px 158px; font-size: 11px; opacity: .6; }
.aa-tl-steps .slow { color: var(--amber); opacity: 1; font-weight: 600; }
.aa-tl-note { margin-top: 4px; opacity: .75; }
@media (max-width: 600px) { .aa-tl-row { grid-template-columns: 100px 1fr 50px; } .aa-tl-steps { padding-left: 0; } }

.aa-anchor { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; margin-right: 8px; }
.aa-anchor .qa { padding: 2px 6px; }
.aa-anchor-lbl { font-size: 11px; opacity: .8; white-space: nowrap; }
.aa-anchor-lbl b { font-variant-numeric: tabular-nums; }

/* ═══════════════ Library tab ═══════════════ */
#lib-bar { display: flex; gap: 8px; padding: 12px; border-bottom: 1px solid var(--brd); background: var(--surf); flex-shrink: 0; }
#lib-in { flex: 1; min-width: 0; background: var(--bg); border: 1px solid var(--brd2); border-radius: var(--sh-full); color: var(--text); font-family: var(--fn); font-size: 14px; padding: 8px 16px; outline: none; transition: border-color .2s, box-shadow .2s; }
#lib-in:focus { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
#lib-in::placeholder { color: var(--muted); }
#btn-lib-add { background: var(--accent); color: #05050f; border: none; border-radius: var(--sh-full); font-family: var(--fn); font-weight: 700; font-size: 12px; letter-spacing: .02em; text-transform: uppercase; padding: 8px 20px; cursor: pointer; box-shadow: var(--ev1); transition: opacity .2s, box-shadow .2s; flex-shrink: 0; white-space: nowrap; }
#btn-lib-add:hover { opacity: .9; box-shadow: var(--ev2); }
#btn-lib-add:disabled { opacity: .5; cursor: wait; }
#lib-hdr { display: flex; align-items: center; gap: 8px; padding: 8px 12px; border-bottom: 1px solid var(--brd); flex-shrink: 0; flex-wrap: wrap; }
#lib-info { flex: 1; min-width: 90px; font-family: var(--fm); font-size: 10px; color: var(--muted); }
#lib-list { flex: 1; overflow-y: auto; min-height: 0; container: rows / inline-size; }
.lib-item { border-bottom: 1px solid transparent; }
.lib-item.open { border-bottom-color: var(--brd); }
.lib-item.col > .lib-row { cursor: pointer; }
.lib-chev { font-size: 18px; color: var(--muted); flex-shrink: 0; margin-right: -4px; }
.lib-sub { padding: 0 0 6px 34px; }
.lib-trow { cursor: default; }
.lib-trow .si-th, .lib-trow .si-nth { width: 34px; height: 34px; }
.lib-ref { opacity: .8; margin-top: 1px; }
#btn-lib-rall.busy { pointer-events: none; opacity: .7; }
#btn-lib-rall.busy .material-symbols-outlined { animation: spin 1s linear infinite; }
.lib-del:hover { background: var(--red, #e5484d); border-color: var(--red, #e5484d); }
/* touch screens have no hover — keep the row actions visible */
@media (hover: none) { .lib-acts, .lib-trow .si-acts { opacity: 1; } }

@container rows (max-width: 720px) {
  .lib-item.col > .lib-row { grid-template-columns: auto auto minmax(0, 1fr) auto; grid-template-areas: "chev th meta dur" "acts acts acts acts"; }
  .lib-chev { grid-area: chev; margin-right: 0; }
  .lib-sub { padding-left: 12px; }
}


/* ───────── About tab (rendered README) ───────── */
#about-body { flex: 1; min-height: 0; overflow-y: auto; padding: 20px 24px 32px; }
.md { color: var(--text); line-height: 1.65; font-size: 14px; max-width: 760px; }
/* The scroller is the full-width pane (so its scrollbar sits at the far right edge);
   the 760px reading width is applied to what's inside it instead. */
#about-body { max-width: none; }
#about-body > * { max-width: 760px; }
.md h1, .md h2, .md h3 { font-family: var(--fn); margin: 1.4em 0 .5em; line-height: 1.25; }
.md h1 { font-size: 26px; margin-top: 0; }
.md h2 { font-size: 18px; padding-bottom: 6px; border-bottom: 1px solid var(--brd); }
.md h3 { font-size: 15px; }
.md p, .md ul, .md ol, .md pre, .md blockquote { margin: 0 0 1em; }
.md ul, .md ol { padding-left: 1.4em; }
.md li { margin: .25em 0; }
.md a { color: var(--accent); text-decoration: none; word-break: break-word; }
.md a:hover { text-decoration: underline; }
.md strong { color: var(--text); font-weight: 700; }
.md code { font-family: var(--fm); font-size: .9em; background: var(--surf2); border: 1px solid var(--brd); border-radius: var(--sh-xs); padding: 1px 5px; }
.md pre { background: var(--surf2); border: 1px solid var(--brd); border-radius: var(--sh-sm); padding: 12px 14px; overflow-x: auto; }
.md pre code { background: none; border: 0; padding: 0; }
.md blockquote { border-left: 3px solid var(--brd2); padding: 2px 14px; color: var(--muted); }
.md hr { border: 0; border-top: 1px solid var(--brd); margin: 1.5em 0; }
.md table { border-collapse: collapse; margin: 0 0 1em; }
.md th, .md td { border: 1px solid var(--brd); padding: 6px 10px; }
.md img { max-width: 100%; }
/* ═══════════════ Narrow / portrait: tidy tab toolbars ═══════════════
   On a phone the Queue, Library and Lyrics toolbars wrapped wherever the
   widths happened to land. Put them on a 6-column grid instead so every row
   is full and every button in a row is the same width. */
@media (max-width: 700px) {
  #q-hdr, #lib-hdr, #lyr-hdr {
    display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 8px 6px; align-items: center;
  }
  /* info text + search box share the first row (2 + 4 columns) */
  #q-info, #lib-info { grid-column: span 2; flex: none; min-width: 0; }
  #q-hdr > .sbox, #lib-hdr > .sbox { grid-column: span 4; width: auto; }
  /* buttons: three to a row, equal width */
  #q-hdr > .qa, #lib-hdr > .qa {
    grid-column: span 2; justify-content: center; min-width: 0;
    padding-left: 4px; padding-right: 4px; gap: 3px; white-space: nowrap;
  }
  /* library: the two "add to queue" actions are the long ones, so they pair up on their own row */
  #lib-hdr > #btn-lib-qall, #lib-hdr > #btn-lib-sall { grid-column: span 3; }

  /* lyrics: source label on its own row, then [translate][provider], then Fetch full width */
  #lyr-src-lbl { grid-column: 1 / -1; flex: none; min-width: 0; }
  #lyr-badge, #lyr-lang { grid-column: span 3; justify-content: center; }
  .lyr-prov { grid-column: span 3; }                       /* [translate][provider] share a row */
  #lyr-tr-lang, #lyr-provider { flex: 1; width: 100%; max-width: none; }
  #btn-lyr-refetch { grid-column: 1 / -1; justify-content: center; }
}

/* Search-result toolbar (built in ui.js): the info text is wrapped in .sres-info,
   which is transparent to layout on wide screens (display: contents) so nothing
   changes there. On a phone it takes the whole first row and the buttons share
   the rows below at equal widths. */
.sres-info { display: contents; }
@media (max-width: 700px) {
  .sres-bar { display: grid !important; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 8px 6px !important; }
  .sres-bar > .sres-info { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px; grid-column: 1 / -1; min-width: 0; }
  .sres-bar > .add-btn {
    grid-column: span 2; margin-left: 0 !important; justify-content: center; min-width: 0;
    padding-left: 4px; padding-right: 4px; white-space: nowrap;
  }
  .sres-bar.n4 > .add-btn { grid-column: span 3; }   /* playlists have four actions: two by two */
}