/* Booth: dark booth theme. Colors are semantic tokens; components never use raw hex.
   Contrast (on --surface): --text 16:1, --text-muted 7.5:1, --text-faint 4.8:1. */
/* Booth: dark booth theme matched to the YouTube DJ logo (red, black, silver).
   Colors are semantic tokens; components never use raw hex.
   Contrast on --surface: --text 16.9:1, --text-muted 7.9:1, --text-faint 5.4:1, --accent-text 5.4:1;
   white on --primary 4.9:1. */
:root {
  --bg: #0B0B0D;
  --surface: #141417;
  --surface-2: #1C1C21;
  --surface-3: #26262C;
  --border: #2E2E35;
  --border-strong: #42424B;
  --text: #F5F5F7;
  --text-muted: #A9A9B3;
  --text-faint: #8A8A95;
  --primary: #E11414;          /* logo red, darkened just enough for white text */
  --primary-hover: #C81010;
  --on-primary: #FFFFFF;
  --accent-text: #FF4545;      /* logo red for text and lines on dark */
  --live: #22C55E;
  --on-live: #04230F;
  --stop: #F5F5F7;             /* Stop is light, so it never looks like the red Play */
  --on-stop: #0B0B0D;
  --a: #FF4545;                /* Deck A: red */
  --b: #D4D4DA;                /* Deck B: turntable silver */
  --on-deck: #0B0B0D;
  --warn: #FBBF24;
  --ring: #FCA5A5;
  --radius-lg: 16px;
  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 1px 0 rgba(255, 255, 255, .04) inset, 0 10px 30px rgba(0, 0, 0, .28);
  --ease: cubic-bezier(.2, .8, .2, 1);
  --display: "Barlow Condensed", "Arial Narrow", "Roboto Condensed", sans-serif;
  --body: "Barlow", "Segoe UI", system-ui, sans-serif;
  /* The Booth wordmark only. Permanent Marker has one weight, so nothing asks it for bold. */
  --brand: "Permanent Marker", "Barlow Condensed", cursive;
  /* Legacy names still used by older rules and the login page */
  --plate: var(--bg); --panel: var(--surface); --ink: var(--text); --ink-soft: var(--text-muted); --line: var(--border);
  --on-accent: var(--on-deck);
  color-scheme: dark;
  box-sizing: border-box;
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
  accent-color: var(--primary);
}
*, *::before, *::after { box-sizing: inherit; }
html, body { margin: 0; }
body {
  overscroll-behavior: none;
  background: radial-gradient(1200px 600px at 10% -10%, rgba(240, 0, 0, .12), transparent 60%), var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font: 400 16px/1.5 var(--body);
  -webkit-font-smoothing: antialiased;
}
button, input, select { font: inherit; color: inherit; }
button, select, summary, .tab, .progress, label.check, .file-btn { cursor: pointer; }
:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; border-radius: 6px; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.show-sm { display: none; }
.i { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

.ios-only { display: none !important; }
body.ios p.ios-only, body.ios details.ios-only { display: block !important; }
body.ios label.ios-only { display: flex !important; }
body.ios .mix-btns { grid-template-columns: 1fr; }
body.ios .fade-only { display: none !important; }

/* Touch: no double-tap zoom delay, no grey tap flash */
button, input, select, label, .tab, .progress, summary, a {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

/* Login page card.
   Not fixed: a fixed, viewport-sized box has nothing to scroll, so a card taller than the window
   - a short laptop screen, or a phone in landscape - put the password field out of reach. In
   normal flow the page scrolls the ordinary way and the card still sits centred when it fits.
   isolation keeps the stacking context the travelling glow sits behind. */
.start {
  position: relative; isolation: isolate;
  min-height: 100vh; min-height: 100dvh;
  display: flex; align-items: center; justify-content: center; padding: 24px;
}
.start-card {
  width: min(100%, 26rem); text-align: center; padding: 32px 24px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 20px; box-shadow: var(--shadow);
}
.start-card .brand { font-size: 4rem; margin: 0 0 .25rem; }
@media (max-height: 760px) {
  .login-logo { width: min(240px, 100%); margin-top: -12px; }
  .start-card .brand { font-size: 3rem; }
}
.start-card p { color: var(--text-muted); margin: .5rem 0 1.25rem; }
.start-card .hint { font-size: .9rem; margin-top: 1.25rem; }

/* ---------- Top bar ---------- */
.top {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 16px;
  padding: 10px clamp(12px, 3vw, 28px);
  background: color-mix(in srgb, var(--bg) 82%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}
.brand {
  display: inline-flex; align-items: center; gap: 10px;
  font: 400 2rem/1 var(--brand); letter-spacing: .01em; margin: 0; color: var(--text);
}
.brand-logo { width: 40px; height: 40px; object-fit: contain; }
.login-logo { display: block; width: min(360px, 100%); height: auto; margin: -20px auto 0; filter: drop-shadow(0 12px 36px rgba(240, 0, 0, .28)); }
.start-card .brand { display: block; }
.top-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.master-toggle {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-width: 8.5rem; min-height: 48px; padding: 0 22px; border: 0; border-radius: 999px;
  font: 700 1.3rem/1 var(--display); letter-spacing: .04em; text-transform: uppercase;
  background: var(--stop); color: var(--on-stop);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .35);
  transition: transform 120ms var(--ease), background-color 160ms var(--ease), box-shadow 160ms var(--ease);
}
.master-toggle .i { width: 18px; height: 18px; }
.master-toggle.is-stopped { background: var(--primary); color: var(--on-primary); box-shadow: 0 6px 20px color-mix(in srgb, var(--primary) 40%, transparent); }
@media (hover: hover) { .master-toggle.is-stopped:hover:not(:disabled) { background: var(--primary-hover); } }
.master-toggle .i-when-stopped, .master-toggle.is-stopped .i-when-playing { display: none; }
.master-toggle.is-stopped .i-when-stopped { display: block; }
.master-toggle:disabled { background: var(--surface-3); color: var(--text-faint); box-shadow: none; cursor: not-allowed; }
.master-toggle:active:not(:disabled) { transform: scale(.97); }

.status-pill {
  display: inline-flex; align-items: center; gap: 8px; margin: 0;
  padding: 6px 12px; border-radius: 999px; font-size: .88rem; font-weight: 600;
  background: var(--surface-2); color: var(--text-muted); border: 1px solid var(--border);
}
.status-pill .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-faint); }
.status-pill[data-state="ok"] .dot { background: var(--live); box-shadow: 0 0 0 3px color-mix(in srgb, var(--live) 25%, transparent); }
.status-pill[data-state="warn"] .dot { background: var(--warn); }
.status-pill[data-state="off"] .dot { background: var(--stop); }

/* iPad notice, folded by default */
.banner {
  margin: 12px clamp(12px, 3vw, 28px) 0; padding: 0;
  background: var(--surface); border: 1px solid var(--border); border-left: 4px solid var(--warn);
  border-radius: var(--radius); font-size: .95rem;
}
.banner summary { display: flex; align-items: center; gap: 10px; padding: 10px 14px; min-height: 44px; list-style: none; color: var(--text); }
.banner summary::-webkit-details-marker { display: none; }
.banner summary .i { color: var(--warn); }
.banner-more { margin-left: auto; color: var(--accent-text); font-weight: 600; white-space: nowrap; }
.banner[open] .banner-more { display: none; }
.banner p { margin: 0; padding: 0 14px 12px 44px; color: var(--text-muted); max-width: 70ch; }

/* ---------- Layout ---------- */
.booth {
  display: grid; gap: 16px;
  padding: 16px clamp(12px, 3vw, 28px) 32px;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 300px) minmax(0, 1fr);
  grid-template-areas:
    "a mix b"
    "queue lib lib";
}
#deckA { grid-area: a; }
#deckB { grid-area: b; }
.mixer { grid-area: mix; }
.queue { grid-area: queue; }
.library { grid-area: lib; }
/* iPad portrait and mini: decks side by side, mixer spans the width */
@media (max-width: 1023.98px) {
  .booth {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "a b" "mix mix" "queue lib";
  }
  .booth .mixer { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px 24px; align-items: center; }
  .booth .mixer .levels { display: none; }
  .booth .mixer .xf-wrap, .booth .mixer .next, .booth .mixer .master { grid-column: 1 / -1; }
}
/* Split View, Slide Over, and phones */
@media (max-width: 699.98px) {
  .booth { grid-template-columns: minmax(0, 1fr); grid-template-areas: "a" "b" "mix" "queue" "lib"; gap: 12px; }
  .booth .mixer { grid-template-columns: minmax(0, 1fr); }
  .top { gap: 10px; }
  .brand { font-size: 1.6rem; }
  .master-toggle { min-width: 0; padding: 0 16px; }
  .hide-sm { display: none; }
  .show-sm { display: inline; }
  .top-actions .btn { padding: 0 10px; }
  .status-pill { padding: 6px 10px; }
}
@media (max-width: 480px) {
  .brand-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
@media (max-width: 380px) {
  .status-pill { font-size: 0; gap: 0; padding: 10px; }
}
/* Short landscape screens: tighter vertical rhythm so decks and mixer fit above the fold */
@media (min-width: 1024px) and (max-height: 860px) {
  .top { padding-block: 6px; }
  .booth { padding-top: 12px; }
  .deck, .mixer { padding: 12px; gap: 8px; }
  .levels { height: 48px; }
  .t-title { font-size: 1.2rem; }
}

/* ---------- Cards ---------- */
.deck, .mixer, .panel {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow); min-width: 0;
}

/* Decks */
.deck {
  --deck: var(--a);
  padding: 14px; display: flex; flex-direction: column; gap: 10px;
  transition: border-color 200ms var(--ease), box-shadow 200ms var(--ease);
}
.deck[data-deck="B"] { --deck: var(--b); }
.deck.on-air { border-color: color-mix(in srgb, var(--deck) 70%, transparent); box-shadow: var(--shadow), 0 0 0 1px color-mix(in srgb, var(--deck) 40%, transparent), 0 0 32px color-mix(in srgb, var(--deck) 14%, transparent); }
.deck-head { display: flex; align-items: center; gap: 10px; }
.deck-tag {
  font: 700 1.25rem/1 var(--display);
  width: 2rem; height: 2rem; display: grid; place-items: center; flex: none;
  border: 2px solid var(--deck); color: var(--deck); border-radius: 10px;
}
.deck.on-air .deck-tag { background: var(--deck); color: var(--on-deck); }
.deck-state {
  font: 600 .95rem/1 var(--body); color: var(--text-muted);
  padding: 5px 10px; border-radius: 999px; background: var(--surface-2);
}
.deck.on-air .deck-state { color: var(--on-live); background: var(--live); }
.screen { border-radius: var(--radius); overflow: hidden; background: #000; }
.screen iframe { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; min-height: 200px; border: 0; }
.track { min-height: 3.2em; }
.t-title {
  margin: 0; font: 600 1.35rem/1.15 var(--display);
  overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
}
.t-sub { margin: 2px 0 0; color: var(--text-muted); font-size: .92rem; }
.progress { position: relative; height: 10px; background: var(--surface-3); border-radius: 999px; overflow: hidden; }
.progress .bar { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--deck); border-radius: 999px; }
.progress .fade-zone {
  position: absolute; top: 0; bottom: 0; right: 0; width: 0;
  background: repeating-linear-gradient(135deg, transparent 0 4px, rgba(241, 245, 249, .35) 4px 7px);
}
.times { display: flex; justify-content: space-between; font-variant-numeric: tabular-nums; font-size: .88rem; color: var(--text-muted); }
.deck-btns { display: flex; gap: 8px; flex-wrap: wrap; }

/* Mixer */
.mixer { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.levels { display: flex; justify-content: center; gap: 12px; height: 64px; }
.level { width: 12px; background: var(--surface-3); border-radius: 999px; position: relative; overflow: hidden; }
.level .fill { position: absolute; left: 0; right: 0; bottom: 0; height: 0; border-radius: 999px; }
.level-a .fill { background: var(--a); }
.level-b .fill { background: var(--b); }
.xf-label { display: flex; justify-content: space-between; font: 600 1rem var(--display); margin-bottom: 4px; color: var(--text-muted); }
.xf-label span:first-child { color: var(--a); }
.xf-label span:last-child { color: var(--b); }
.xf { -webkit-appearance: none; appearance: none; width: 100%; height: 52px; background: transparent; cursor: grab; }
.xf::-webkit-slider-runnable-track { height: 10px; border-radius: 999px; background: linear-gradient(90deg, var(--a), var(--b)); }
.xf::-moz-range-track { height: 10px; border-radius: 999px; background: linear-gradient(90deg, var(--a), var(--b)); }
.xf::-webkit-slider-thumb {
  -webkit-appearance: none; width: 30px; height: 46px; margin-top: -18px; border-radius: 8px;
  border: 2px solid var(--text); background: repeating-linear-gradient(90deg, var(--surface-3) 0 5px, var(--border-strong) 5px 7px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, .4);
}
.xf::-moz-range-thumb {
  width: 26px; height: 42px; border-radius: 8px;
  border: 2px solid var(--text); background: repeating-linear-gradient(90deg, var(--surface-3) 0 5px, var(--border-strong) 5px 7px);
}
.mix-btns { display: grid; grid-template-columns: 2fr 1fr; gap: 8px; }
.field { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; font-weight: 500; }
.field output { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.field input[type="range"] { width: 100%; height: 32px; }
.field select { flex-basis: 100%; }
.check { display: flex; gap: 10px; align-items: flex-start; font-size: .95rem; }
.check input { margin-top: 3px; width: 18px; height: 18px; flex: none; }
.next { margin: 0; font-size: .95rem; color: var(--text-muted); overflow-wrap: anywhere; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; padding: 0 16px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--surface-2); color: var(--text);
  font-weight: 600; text-decoration: none; white-space: nowrap;
  transition: background-color 150ms var(--ease), border-color 150ms var(--ease), transform 100ms var(--ease);
}
.btn .i { width: 18px; height: 18px; }
@media (hover: hover) {
  .btn:hover:not(:disabled) { background: var(--surface-3); border-color: var(--text-faint); }
  .btn-primary:hover:not(:disabled) { background: var(--primary-hover); border-color: var(--primary-hover); }
  .btn-quiet:hover:not(:disabled) { background: var(--surface-2); }
  .row-btns button:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }
}
.btn:active:not(:disabled) { transform: scale(.97); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.btn-quiet { background: transparent; border-color: var(--border); color: var(--text-muted); }
.btn-quiet:not(:disabled) { color: var(--text); }
a.btn { color: var(--text); }
#sesNew, #devResetAll, #reqQueueAll { align-self: flex-start; }

/* ---------- Panels ---------- */
.panel { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.panel-head { display: flex; align-items: center; gap: 10px; }
.panel h2 { margin: 0; font: 600 1.5rem/1 var(--display); }
.count { color: var(--text-muted); font-size: .9rem; }
.show-played { align-self: flex-end; font-size: .9rem; color: var(--text-muted); }
.qtabs { flex: 1; }
.qtabs .count { font: 500 .85rem/1 var(--body); color: var(--text-faint); }
.qpanel:not([hidden]) { display: flex; flex-direction: column; gap: 10px; }
.yt-save:not([hidden]) { display: flex; flex-direction: column; gap: 10px; padding: 14px; border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--surface-2); }
.add { display: flex; gap: 8px; }
.add input, select {
  flex: 1; min-width: 0; padding: 9px 12px; min-height: 44px; font-size: 16px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--bg); color: var(--text);
  transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease);
}
.add input::placeholder { color: var(--text-faint); }
.add input:focus, select:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 30%, transparent); }
.add input:disabled { opacity: .5; }
select { width: 100%; }
.row { display: flex; gap: 8px; flex-wrap: wrap; }
.note { margin: 0; font-size: .88rem; color: var(--text-muted); }
.sub-head { margin: 4px 0 0; font: 600 1.15rem/1.1 var(--display); color: var(--text); }
.file-btn {
  display: inline-flex; align-items: center; align-self: flex-start; min-height: 44px;
  border: 1px dashed var(--border-strong); border-radius: var(--radius-sm); padding: 0 14px; font-weight: 600; color: var(--text-muted);
}
.file-btn input { position: absolute; width: 1px; height: 1px; opacity: 0; }
.file-btn:focus-within { outline: 2px solid var(--ring); outline-offset: 2px; }

/* YouTube account + testing tools */
.yt-account { display: flex; flex-direction: column; gap: 8px; padding-bottom: 14px; border-bottom: 1px solid var(--border); }
.yt-account > div:not([hidden]) { display: flex; flex-direction: column; gap: 8px; }
.yt-who { flex-direction: row !important; align-items: center; flex-wrap: wrap; }
.yt-who .note { flex: 1; min-width: 10rem; }
.dev-tools { border: 1px dashed var(--border-strong); border-radius: var(--radius); padding: 4px 14px; }
.dev-tools summary { font-weight: 700; color: var(--text-muted); min-height: 40px; display: flex; align-items: center; }
.dev-tools[open] { display: flex; flex-direction: column; gap: 8px; padding-bottom: 14px; }
.req-tools select { flex: 1 1 9rem; width: auto; }

/* ---------- Track lists ---------- */
.list {
  list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px;
  max-height: min(440px, 58dvh); overflow-y: auto; -webkit-overflow-scrolling: touch; scrollbar-width: thin;
}
.list li {
  display: grid; grid-template-columns: 64px minmax(0, 1fr) auto; gap: 12px; align-items: center;
  padding: 6px 6px 6px 6px; border-radius: var(--radius); background: var(--surface-2);
  border: 1px solid transparent; transition: background-color 150ms var(--ease), opacity 150ms var(--ease);
}
.list li.sec {
  display: block; background: none; padding: 8px 4px 0; border: 0;
  font: 600 .78rem/1 var(--body); letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint);
}
.list li.empty { display: block; padding: 16px; color: var(--text-muted); background: transparent; border: 1px dashed var(--border-strong); }
.list li.dragging { opacity: .4; }
.list li.drop-target { border-color: var(--b); }
.queue .list li.next-up { border-color: color-mix(in srgb, var(--b) 45%, transparent); }
.list li.played { opacity: .6; }
.list li.played:hover, .list li.played:focus-within { opacity: 1; }
.list li.now-playing { background: color-mix(in srgb, var(--live) 10%, var(--surface-2)); border-color: color-mix(in srgb, var(--live) 55%, transparent); }
.list li.fresh { border-color: color-mix(in srgb, var(--a) 55%, transparent); }
.list img { width: 64px; height: 36px; object-fit: cover; border-radius: 6px; background: var(--surface-3); }
.list .ttl { font-weight: 600; font-size: .95rem; line-height: 1.25; overflow: hidden; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.list .sub { font-size: .82rem; color: var(--text-muted); }
.row-btns { display: flex; gap: 4px; align-items: center; }
.row-btns button {
  display: inline-grid; place-items: center;
  border: 1px solid var(--border); background: transparent; color: var(--text-muted); border-radius: var(--radius-sm);
  min-width: 44px; height: 44px; padding: 0 10px; font-weight: 700;
  transition: background-color 150ms var(--ease), color 150ms var(--ease), transform 100ms var(--ease);
}
.row-btns button.text { color: var(--text); background: var(--surface-3); }
.row-btns button:active { transform: scale(.94); }
.row-btns .i { width: 18px; height: 18px; }
.queue, .library { container-type: inline-size; }
@container (max-width: 440px) {
  .list li { grid-template-columns: 56px minmax(0, 1fr); align-items: start; }
  .list img { width: 56px; height: 32px; }
  .list .row-btns { grid-column: 2; flex-wrap: wrap; }
}

/* Status pills (queue + requests) */
.pill {
  display: inline-flex; align-items: center; height: 24px; padding: 0 9px; border-radius: 999px;
  font-size: .78rem; font-weight: 700; white-space: nowrap;
  background: var(--surface-3); color: var(--text-muted);
}
.pill-new { background: color-mix(in srgb, var(--a) 22%, transparent); color: var(--a); }
.pill-info { background: color-mix(in srgb, var(--b) 18%, transparent); color: var(--b); }
.pill-live { background: var(--live); color: var(--on-live); }
.pill-warn { background: color-mix(in srgb, var(--warn) 18%, transparent); color: var(--warn); }
.pill-muted { color: var(--text-faint); }

/* ---------- Tabs: segmented control ---------- */
.tabs { display: flex; gap: 4px; padding: 4px; background: var(--bg); border: 1px solid var(--border); border-radius: var(--radius); }
.tab {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  border: 0; background: none; padding: 0 12px; min-height: 42px; border-radius: 9px;
  font: 600 1.15rem/1 var(--display); letter-spacing: .02em; color: var(--text-muted);
  transition: background-color 150ms var(--ease), color 150ms var(--ease);
}
.tab[aria-selected="true"] { background: var(--surface-3); color: var(--text); box-shadow: 0 1px 2px rgba(0, 0, 0, .3); }
@media (hover: hover) { .tab:hover:not([aria-selected="true"]) { color: var(--text); } }
.tab-badge {
  display: inline-grid; place-items: center; min-width: 1.5em; height: 1.5em; padding: 0 6px; border-radius: 999px;
  background: var(--primary); color: var(--on-primary); font: 700 .78rem/1 var(--body);
}
.tab-panel { display: flex; flex-direction: column; gap: 10px; }

/* ---------- Toast ---------- */
.toast {
  position: fixed; left: 50%; bottom: calc(20px + env(safe-area-inset-bottom, 0px)); transform: translateX(-50%) translateY(16px);
  background: var(--surface-3); color: var(--text); padding: 12px 18px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
  max-width: min(92vw, 34rem); font-size: .95rem; opacity: 0; pointer-events: none;
  transition: opacity 180ms var(--ease), transform 180ms var(--ease); z-index: 60;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

.deck.needs-arm .deck-state { color: var(--bg); background: var(--warn); }
.deck.needs-arm .screen { outline: 3px dashed var(--warn); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
    animation-delay: 0ms !important;   /* otherwise the entrance just holds the page blank */
  }
}

/* ---- Accounts screen (admin.php). No grid tricks: one column of panels, tables inside. */
.admin {
  display: flex; flex-direction: column; gap: 16px;
  width: 100%; max-width: 1100px; margin: 0 auto;
  padding: 16px clamp(12px, 3vw, 28px) 32px;
}
.btn-sm { min-height: 32px; padding: 0 10px; font-size: .85rem; gap: 5px; }

.admin-flash {
  margin: 0; padding: 12px 14px; border-radius: var(--radius);
  border: 1px solid var(--border-strong); background: var(--surface-2);
  font-weight: 500; overflow-wrap: anywhere;   /* password links are long */
}
.admin-flash.is-ok { border-color: var(--live); color: var(--text); }
.admin-flash.is-error { border-color: var(--accent-text); color: var(--text); }
.admin-danger { border-color: var(--accent-text); }

.admin-table { width: 100%; border-collapse: collapse; }
.admin-table th, .admin-table td {
  text-align: left; padding: 10px 8px; vertical-align: top;
  border-bottom: 1px solid var(--border);
}
.admin-table th {
  font: 600 .8rem/1 var(--display); text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-faint); white-space: nowrap;
}
.admin-table tbody tr:last-child td { border-bottom: 0; }
.admin-who { display: flex; flex-direction: column; gap: 2px; }
.admin-log { font-size: .88rem; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

.admin-acts { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; }
.admin-acts form { display: inline-flex; gap: 4px; align-items: center; margin: 0; }
.admin-acts select { width: auto; flex: 0 1 9rem; min-height: 32px; padding: 4px 8px; font-size: .85rem; }
.admin-num {
  width: 5.5rem; flex: 0 0 auto; min-height: 32px; padding: 4px 8px; font-size: .85rem;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--text); font-variant-numeric: tabular-nums;
}
.admin-num::placeholder { color: var(--text-faint); }
.admin-num:focus { outline: none; border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 30%, transparent); }

/* Phones: the tables become stacked cards, each cell labelled by its column. */
@media (max-width: 760px) {
  .admin-table thead { display: none; }
  .admin-table, .admin-table tbody, .admin-table tr, .admin-table td { display: block; width: 100%; }
  .admin-table tr {
    padding: 10px 0; border-bottom: 1px solid var(--border);
  }
  .admin-table tbody tr:last-child { border-bottom: 0; }
  .admin-table td { border-bottom: 0; padding: 4px 0; }
  .admin-table td[data-label]::before {
    content: attr(data-label);
    display: block; margin-bottom: 3px;
    font: 600 .72rem/1 var(--display); text-transform: uppercase; letter-spacing: .04em;
    color: var(--text-faint);
  }
  .admin-log { white-space: normal; }
}

/* ---- Request pages (pages.php): the QR beside its address and buttons. */
.pages-grid { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
.pages-qr {
  flex: 0 0 auto; width: min(216px, 56vw); padding: 10px;
  background: #FFFFFF; border-radius: var(--radius);   /* a QR needs a white quiet zone, not the dark surface */
}
.pages-qr svg { display: block; width: 100%; height: auto; }
.pages-side { flex: 1 1 16rem; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.pages-url { margin: 0; font: 600 1.05rem/1.25 var(--body); overflow-wrap: anywhere; }
.pages-url a { color: var(--accent-text); }
.pages-side .row { margin: 0; }

/* ---- Sign-in, registration and password forms.
   .add is a single-row layout meant for one input beside a button. These forms have several
   fields, so inside the sign-in card they stack instead. Scoped to .start-card, which the booth
   itself never uses, so the queue's add-a-track row keeps its original single-row shape. */
.start-card .add { flex-direction: column; align-items: stretch; gap: 10px; }
.start-card .add input { flex: 0 0 auto; width: 100%; }
.start-card .add button { width: 100%; }

.start-card .start-check {
  display: flex; align-items: center; gap: 8px;
  margin: 2px 0; text-align: left;
  font-size: .92rem; font-weight: 500; color: var(--text-muted);
}
.start-card .start-check input[type="checkbox"] {
  flex: 0 0 auto; width: 20px; height: 20px; min-height: 0; margin: 0;
  accent-color: var(--primary);
}

/* ---- Forms on the admin and request-page screens.
   The .add rule only styles inputs inside .add, so these were falling back to the browser's
   default width. Scoped to .stack so the narrow per-DJ allowance box keeps its own size. */
.admin .stack { display: flex; flex-direction: column; align-items: stretch; gap: 10px; }
.admin .stack input[type="text"] {
  width: 100%; min-height: 44px; padding: 9px 12px; font-size: 16px;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--bg); color: var(--text);
  transition: border-color 150ms var(--ease), box-shadow 150ms var(--ease);
}
.admin .stack input[type="text"]::placeholder { color: var(--text-faint); }
.admin .stack input[type="text"]:focus {
  outline: none; border-color: var(--ring);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 30%, transparent);
}
.admin .stack button { align-self: flex-start; }

/* ---- Sound board. Eight built-in effects plus each DJ's own samples. */
.pads { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 10px; }
.pad-wrap { position: relative; }
.pad {
  width: 100%; aspect-ratio: 1 / .8; cursor: pointer;
  display: flex; flex-direction: column; justify-content: space-between; align-items: flex-start; gap: 6px;
  padding: 8px 10px; text-align: left;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text);
  font: 600 1.05rem/1.1 var(--display);
  box-shadow: 0 3px 0 var(--border);
  transition: transform 60ms var(--ease), box-shadow 60ms var(--ease), background-color 120ms var(--ease);
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.pad kbd {
  font: 600 .78rem var(--body); color: var(--text-faint);
  border: 1px solid var(--border); border-radius: 4px; padding: 1px 6px;
}
.pad:active, .pad.hit { transform: translateY(3px); box-shadow: 0 0 0 var(--border); }
.pad.hit { border-color: var(--a); background: color-mix(in srgb, var(--a) 18%, var(--surface-2)); }
.pad.custom.hit { border-color: var(--b); background: color-mix(in srgb, var(--b) 18%, var(--surface-2)); }

/* The search allowance turns amber when it is nearly gone. */
.quota-low { color: var(--warn); font-weight: 600; }

/* ---- MIDI controller panel. midi.js builds the contents; these are the pieces it uses. */
#midiPanel { display: flex; flex-direction: column; gap: 12px; }
#midiPanel .admin-table td { padding: 6px 8px; }
#midiPanel details { border-top: 1px solid var(--border); padding-top: 8px; }
#midiPanel summary { padding: 4px 0; }
.midi-binding { font-variant-numeric: tabular-nums; color: var(--text-muted); white-space: nowrap; }
.midi-unset { color: var(--text-faint); font-style: italic; }
.midi-debug {
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  background: var(--bg); padding: 10px;
}
.midi-debug pre {
  margin: 6px 0 0; max-height: 14rem; overflow: auto;
  font: 500 .78rem/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--text-muted); white-space: pre-wrap; word-break: break-all;
}
.midi-help { margin: 6px 0 0; padding-left: 1.2rem; display: grid; gap: 6px; color: var(--text-muted); font-size: .92rem; }
.midi-help b { color: var(--text); }

/* ---- Manual pages: readable prose columns inside the standard panels. */
.manual .panel { max-width: 62rem; }
.manual-steps, .manual-list { margin: 6px 0 0; padding-left: 1.3rem; display: grid; gap: 8px; color: var(--text-muted); line-height: 1.5; }
.manual-list { list-style: disc; }
.manual-steps b, .manual-list b, .manual .note b { color: var(--text); }
.manual code {
  font: 500 .88em ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 4px; padding: 1px 5px; color: var(--text);
}

/* ---- A DJ's own sound samples, under the pads in the Effects tab. */
.fx-own { display: flex; flex-direction: column; gap: 8px; border-top: 1px solid var(--border); padding-top: 12px; }
.fx-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.fx-list li {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 10px; border-radius: var(--radius-sm); background: var(--surface-2);
}
.fx-list li.empty { justify-content: center; color: var(--text-faint); background: none; font-size: .9rem; }
.fx-name { flex: 1; min-width: 0; font-weight: 600; overflow-wrap: anywhere; }
.fx-own .file-btn input[type="file"] { max-width: 14rem; margin-left: 8px; font-size: .85rem; }
.fx-own .file-btn:has(input:disabled) { opacity: .5; }

/* ---- Sub-page overlay. The booth stays loaded underneath, so the music never stops. */
.sheet {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column;
  background: color-mix(in srgb, var(--bg) 92%, transparent);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
}
.sheet[hidden] { display: none; }
.sheet-bar {
  display: flex; align-items: center; gap: 8px;
  padding: 8px clamp(10px, 2vw, 18px);
  border-bottom: 1px solid var(--border); background: var(--surface);
}
.sheet-title { flex: 1; min-width: 0; font: 600 1.15rem/1.1 var(--display); color: var(--text); }
.sheet-frame { flex: 1; width: 100%; border: 0; background: var(--bg); }
body.sheet-open { overflow: hidden; }
/* A framed page drops its own header, so it needs a little breathing room back. */
.admin.in-sheet { padding-top: 16px; }

/* ---- Desktop queue panel.
   The list used to stop at a fixed height, which left dead space under a short queue and capped a
   long one well before the panel ran out of room. Now the list takes whatever height is left and
   scrolls inside it, and the buttons stay pinned to the bottom of the section however long the
   queue gets. Only on desktop: on a narrow screen the page scrolls as one, and a panel-height
   scroll area inside a page-height scroll is unpleasant on a touch screen. */
@media (min-width: 1024px) {
  .queue { min-height: 0; }
  .queue .qpanel:not([hidden]) { flex: 1 1 auto; min-height: 0; }
  /* The list is as tall as the queue needs, so the buttons under it move down as songs are
     added, until ten are showing. After that it scrolls and the buttons stay where they are.
     Change --queue-rows to show more or fewer. */
  .queue .qpanel > .list {
    --queue-rows: 10;
    flex: 0 1 auto; min-height: 0;
    max-height: calc(var(--queue-rows) * 64px);
  }
  .queue .qpanel > .row:last-child { flex: 0 0 auto; }
}

/* ---- Sign-in entrance.
   The logo drops in, the wordmark is then drawn from left to right — which, in a marker face,
   reads as it being written — and the form follows it in. All CSS: the page's own policy allows
   no inline scripts, and an animation is not worth a separate file. */
.start-card .login-logo {
  opacity: 0;
  transform: translateY(-18px) scale(.88) rotate(-5deg);
  /* Drops in, then keeps a slow beat. The pulse has no backwards fill, so during its delay the
     entrance still owns the transform; once it starts it is last in the list and wins. */
  animation:
    booth-logo-in 720ms cubic-bezier(.18, .9, .25, 1.12) 80ms both,
    booth-logo-jam 2600ms ease-in-out 900ms infinite;
}
@keyframes booth-logo-in {
  60% { opacity: 1; transform: translateY(4px) scale(1.03) rotate(1.5deg); }
  to  { opacity: 1; transform: none; }
}
/* About 23 beats a minute: a head-nod, not a heartbeat. The glow under the logo swells with it. */
@keyframes booth-logo-jam {
  0%, 100% { transform: scale(1);     filter: drop-shadow(0 10px 30px rgba(240, 0, 0, .25)); }
  50%      { transform: scale(1.035); filter: drop-shadow(0 14px 42px rgba(240, 0, 0, .48)); }
}

.start-card .brand {
  /* Reveal reaches past the glyph box: Permanent Marker's ink overshoots its own edges. */
  clip-path: inset(0 102% 0 -5%);
  animation: booth-write 950ms cubic-bezier(.5, .05, .25, 1) 640ms both;
}
@keyframes booth-write { to { clip-path: inset(0 -5% 0 -5%); } }

/* Everything under the wordmark: the greeting, the form, the links. */
.start-card > :not(.login-logo):not(.brand) {
  animation: booth-rise-in 520ms ease-out 1380ms both;
}
@keyframes booth-rise-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

/* ---- The red wash travels the top of the sign-in screen instead of sitting in one corner.
   It crosses the middle - over the logo - twice per lap, once every 2600ms, which is exactly
   booth-logo-jam's beat, and it leans down and brightens as it passes. The fixed corner wash in
   body is dropped here so there is only the one light. */
body:has(.start) { background: var(--bg); }
.start::before {
  content: "";
  position: fixed; left: 50%; top: 0; z-index: -1;
  width: 90vmax; height: 50vmax; margin: -25vmax 0 0 -45vmax;
  pointer-events: none; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(240, 0, 0, .34), rgba(240, 0, 0, .12) 55%, transparent 78%);
  animation: booth-glow-sweep 5200ms ease-in-out 900ms infinite;
}
@keyframes booth-glow-sweep {
  0%, 100% { transform: translate(-42vw, -2vmax) scale(.9);  opacity: .55; }
  25%      { transform: translate(0, 4vmax)      scale(1.08); opacity: 1; }
  50%      { transform: translate(42vw, -2vmax)  scale(.9);  opacity: .55; }
  75%      { transform: translate(0, 4vmax)      scale(1.08); opacity: 1; }
}

/* ---- The small-screen notice (mobile.php). Reuses the sign-in card, so only the extras. */
.gate-list { text-align: left; margin: 0 0 1.25rem; padding-left: 1.1rem; color: var(--text-muted); }
.gate-list li { margin: .35rem 0; }
.start-card .btn-wide { width: 100%; }
