/* Singaroo - phone-first for singers, wide and legible for the desk. */

:root {
  --bg: #12101c;
  --panel: #1b1830;
  --panel-2: #241f3f;
  --ink: #f2eefc;
  --ink-dim: #a49cc4;
  --line: #322b52;
  --hot: #ff3d81;
  --hot-2: #ff8a3d;
  --go: #2fd18a;
  --warn: #ffbe4d;
  --danger: #ff5d5d;
  --radius: 12px;

  /* Form fields are light on purpose, even though the page is dark. Browsers
     and password managers repaint a field they autofill -- always to something
     near-white, often with inline !important that no stylesheet can outrank.
     Dark fields lose that fight and go white-on-white; light fields are already
     the colour the filler wants, so filled and empty look the same. */
  --field-bg: #fbfaff;
  --field-ink: #1a1024;
  --field-line: #b9b2d4;
  --field-ph: #6b6486;
}

* { box-sizing: border-box; }

/* The hidden attribute has to beat any display rule we set elsewhere. Without
   this, .stage { display: flex } silently overrode it and every panel on the
   player screen rendered at once, stacked. */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: radial-gradient(1200px 600px at 50% -10%, #2a1f47 0%, var(--bg) 60%) fixed;
  color: var(--ink);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

a { color: var(--hot); }
a:hover { color: var(--hot-2); }

h1 { font-size: 1.6rem; margin: 0 0 .3em; }
h2 { font-size: 1.1rem; margin: 0 0 .6em; letter-spacing: .02em; text-transform: uppercase; color: var(--ink-dim); }

.muted { color: var(--ink-dim); }
.small { font-size: .85rem; }
.err-text { color: var(--danger); }
.hint { color: var(--ink-dim); font-weight: 400; font-size: .8rem; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

/* ---------------------------------------------------------- chrome */

.topbar {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .7rem 1rem; border-bottom: 1px solid var(--line);
  background: rgba(18, 16, 28, .85); backdrop-filter: blur(6px);
  position: sticky; top: 0; z-index: 10;
}
.brand { font-weight: 800; font-size: 1.15rem; text-decoration: none; letter-spacing: -.02em; }
.brand-sing { color: var(--ink); }
.brand-a { color: var(--hot); }
.brand-roo { color: var(--hot-2); }
.topbar nav { display: flex; align-items: center; gap: .8rem; font-size: .9rem; }
.admin-bar {
  border-bottom: 1px solid var(--line);
  background: rgba(27, 24, 48, .6);
  position: sticky; top: 3rem; z-index: 8;
}
.admin-bar-inner {
  max-width: 1200px; margin: 0 auto; padding: 0 1rem;
  display: flex; gap: .15rem; flex-wrap: wrap;
}
.admin-tab {
  flex: 0 0 auto; padding: .6rem .8rem; text-decoration: none; color: var(--ink-dim);
  font-size: .9rem; font-weight: 600; white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.admin-tab:hover { color: var(--ink); }
.admin-tab-on { color: var(--ink); border-bottom-color: var(--hot); }
.admin-tab-sub { color: var(--ink-dim); font-weight: 500; }

/* A group in the bar is a dropdown. It borrows the tab's look, not the header
   menu's pink link colour, and opens under its own label. */
.admin-group > summary.admin-tab { color: var(--ink-dim); padding: .6rem .8rem; }
.admin-group > summary.admin-tab:hover,
.admin-group[open] > summary.admin-tab,
.admin-group > summary.admin-tab-on { color: var(--ink); }
.admin-group > .nav-menu-items { left: 0; right: auto; top: 100%; }
.nav-menu-head {
  display: block; padding: .55rem .6rem .2rem; font-size: .7rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--ink-dim);
}

.user-actions { display: flex; gap: .3rem; flex-wrap: wrap; }

.nav-menu { position: relative; }
.nav-menu > summary {
  list-style: none; cursor: pointer; color: var(--hot); user-select: none;
  padding: .15rem .1rem; display: inline-flex; align-items: center; gap: .3rem;
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::after {
  content: ''; width: .4rem; height: .4rem; margin-top: -.2rem;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg); transition: transform .12s ease;
}
.nav-menu[open] > summary::after { transform: rotate(-135deg); margin-top: .15rem; }
.nav-menu > summary:hover { color: var(--hot-2); }
.nav-menu > summary.nav-here { color: var(--ink); font-weight: 700; }

.nav-menu-items {
  position: absolute; right: 0; top: calc(100% + .5rem); z-index: 30;
  min-width: 16rem; padding: .35rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: 0 14px 40px rgba(0, 0, 0, .5);
  display: flex; flex-direction: column;
}
.nav-item {
  display: block; padding: .45rem .6rem; border-radius: 8px; text-decoration: none; color: var(--ink);
}
.nav-item:hover { background: var(--panel-2); color: var(--ink); }
.nav-item-on { background: var(--panel-2); box-shadow: inset 2px 0 0 var(--hot); }
.nav-item-label { display: block; font-size: .92rem; font-weight: 600; }
.nav-item-note { display: block; font-size: .76rem; color: var(--ink-dim); }
/* Admin groups in the phone menu, folded. */
.nav-fold > summary { list-style: none; cursor: pointer; display: flex; justify-content: space-between; align-items: center; }
.nav-fold > summary::-webkit-details-marker { display: none; }
.nav-fold > summary::after { content: '+'; color: var(--ink-dim); font-weight: 700; }
.nav-fold[open] > summary::after { content: '\2212'; }
.nav-sub { padding-left: 1.4rem; }
/* "What you have sung": a rated song slides out of the list. */
.hist { transition: opacity .35s ease, max-height .45s ease, padding .45s ease, margin .45s ease; max-height: 30rem; }
.hist.hist-going { opacity: 0; max-height: 0; padding-top: 0; padding-bottom: 0; margin: 0; overflow: hidden; }

@media (max-width: 720px) {
  /* dvh, not vh: on a phone vh counts the space behind the browser's own bars,
     so the bottom of the menu -- Sign out -- was off the screen and could not
     be scrolled to. */
  .nav-menu-items { position: fixed; left: .6rem; right: .6rem; top: 3.4rem; min-width: 0;
                    max-height: calc(100vh - 4rem); max-height: calc(100dvh - 4.5rem);
                    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
  /* Five words have to fit one line on a phone, so the bar tightens and the
     "· Review" beside a group waits for a wider screen. */
  .admin-bar-inner { padding: 0 .4rem; gap: 0; justify-content: space-between; flex-wrap: nowrap; }
  .admin-tab, .admin-group > summary.admin-tab { padding: .55rem .45rem; font-size: .85rem; }
  .admin-tab-sub { display: none; }
  .admin-group > .nav-menu-items { left: .6rem; right: .6rem; top: 5.7rem; }
}

.topbar .who { color: var(--ink-dim); text-decoration: none; }
.narrow-only { display: none; }
.nav-item-button { width: 100%; text-align: left; background: none; border: 0; font: inherit; cursor: pointer; }
@media (max-width: 560px) {
  .wide-only { display: none !important; }
  .narrow-only { display: block; }
  .topbar nav { gap: .7rem; }
}
.topbar a.who:hover { color: var(--ink); text-decoration: underline; }

.wrap { max-width: 820px; margin: 0 auto; padding: 1rem 1rem 4rem; }
body:has(#desk-queue) .wrap { max-width: 1200px; }

.foot { border-top: 1px solid var(--line); padding: 1rem; color: var(--ink-dim); font-size: .8rem; text-align: center; }
.foot-links a { color: var(--ink-dim); }
.panel-danger { border-color: rgba(255, 93, 93, .45); }

/* Terms and privacy: long reading, so a measure a person can follow. */
.legal { max-width: 46rem; margin-inline: auto; line-height: 1.6; }
.legal h2 { margin-top: 1.6rem; }
.legal ul { padding-left: 1.2rem; }
.legal li { margin-bottom: .45rem; }

.flashes { max-width: 820px; margin: .8rem auto 0; padding: 0 1rem; }
.flash { border-radius: var(--radius); padding: .7rem .9rem; margin: 0 0 .5rem; }
.flash-ok { background: rgba(47, 209, 138, .15); border: 1px solid rgba(47, 209, 138, .4); }
.flash-err { background: rgba(255, 93, 93, .15); border: 1px solid rgba(255, 93, 93, .4); }

/* ---------------------------------------------------------- blocks */

.panel {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1rem; margin: 0 0 1rem;
}
.panel-dim { opacity: .65; }
.panel.narrow { max-width: 440px; margin-inline: auto; }
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

.hero { text-align: center; padding: 2rem 0 1rem; }
.hero h1 { font-size: 2.2rem; }
.lede { color: var(--ink-dim); margin-bottom: 1.4rem; }

/* ---------------------------------------------------------- forms */

input, select, button, textarea { font: inherit; }
input[type=text], input[type=email], input[type=password], input[type=url], input[type=search],
input[type=datetime-local], select, textarea {
  width: 100%; padding: .65rem .8rem; border-radius: 10px;
  border: 1px solid var(--field-line); background: var(--field-bg); color: var(--field-ink);
}
input::placeholder, textarea::placeholder { color: var(--field-ph); opacity: 1; }
input:focus, select:focus, button:focus-visible { outline: 2px solid var(--hot); outline-offset: 1px; }

/* Belt and braces on top of the light field: pin the text colour for the
   autofilled state too, so it cannot inherit something unreadable. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
input:-webkit-autofill:active,
input:autofill {
  -webkit-text-fill-color: var(--field-ink) !important;
  color: var(--field-ink) !important;
  -webkit-box-shadow: 0 0 0 100px var(--field-bg) inset;
  box-shadow: 0 0 0 100px var(--field-bg) inset;
  caret-color: var(--field-ink);
}

::selection { background: var(--hot); color: #1a1024; }

.stack { display: flex; flex-direction: column; gap: .9rem; }
.stack label { display: flex; flex-direction: column; gap: .3rem; font-size: .9rem; color: var(--ink-dim); }
.stack label input, .stack label select { color: var(--field-ink); }
.row { display: flex; gap: .8rem; flex-wrap: wrap; }
.row label { flex: 1 1 180px; display: flex; flex-direction: column; gap: .3rem; font-size: .9rem; color: var(--ink-dim); }
.check { flex-direction: row !important; align-items: center; gap: .5rem !important; }
.check input { width: auto; }
.inline { display: inline; }

.btn {
  display: inline-flex; align-items: center; gap: .4rem; justify-content: center;
  background: linear-gradient(135deg, var(--hot), var(--hot-2));
  color: #1a1024; border: 0; border-radius: 999px; padding: .6rem 1.1rem;
  font-weight: 700; cursor: pointer; text-decoration: none;
}
.btn:hover { filter: brightness(1.08); color: #1a1024; }
.btn[disabled] { opacity: .4; cursor: default; filter: none; }
.btn-big { padding: .85rem 1.4rem; font-size: 1.05rem; width: 100%; }
.btn-small { padding: .35rem .8rem; font-size: .85rem; }
.btn-tiny { padding: .25rem .6rem; font-size: .78rem; border-radius: 8px; }
/* A ghost button still has to look like a button. Transparent on a panel that
   is itself a shade of the page background left these reading as text with a
   faint box round them -- fine next to a solid button that anchors the row,
   invisible when a row is nothing but ghosts. So: a surface of its own, a
   border with some contrast in it, and a lift on hover. */
.btn-ghost {
  background: var(--panel-2); border: 1px solid #4b4270; color: var(--ink);
}
.btn-ghost:hover { background: #302a52; border-color: var(--hot); color: var(--ink); }
.btn-danger:hover { border-color: var(--danger); background: rgba(255, 93, 93, .12); }
.btn-go { background: linear-gradient(135deg, var(--go), #63e0b0); }
.btn-danger { background: transparent; border: 1px solid rgba(255, 93, 93, .5); color: var(--danger); }
.btn-any { background: transparent; border: 1px dashed var(--line); color: var(--ink-dim); }
.linkish { background: none; border: 0; color: var(--hot); cursor: pointer; padding: 0 .2rem; font-size: .85rem; }

.code-form { display: flex; flex-direction: column; gap: .7rem; max-width: 380px; margin: 0 auto; }
.code-input {
  text-align: center; letter-spacing: .35em; font-size: 1.6rem; font-weight: 800;
  text-transform: uppercase; padding: .8rem !important;
}

/* ---------------------------------------------------------- bits */

.code-pill {
  display: inline-block; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .18em; background: var(--panel-2); border: 1px solid var(--line);
  border-radius: 8px; padding: .15rem .5rem; font-weight: 700;
}
.code-pill-big { font-size: 1.4rem; padding: .3rem .8rem; }
.badge {
  display: inline-block; font-size: .75rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; padding: .18rem .5rem; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-dim);
}
.badge-now { background: var(--go); color: #10241b; border-color: transparent; }
.badge-open { background: rgba(47, 209, 138, .2); color: var(--go); }
.badge-closed { background: rgba(255, 93, 93, .18); color: var(--danger); }
.chip {
  display: inline-block; font-size: .72rem; padding: .1rem .45rem; border-radius: 6px;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-dim); margin-left: .35rem;
}
.chip-warn { color: var(--warn); border-color: rgba(255, 190, 77, .4); }
.chip-any { border-style: dashed; }

.table { width: 100%; border-collapse: collapse; }
.table th { text-align: left; font-size: .75rem; text-transform: uppercase; color: var(--ink-dim); padding: .4rem .5rem; }
.table td { padding: .55rem .5rem; border-top: 1px solid var(--line); vertical-align: top; }
.row-dim { opacity: .5; }

.night-list { list-style: none; padding: 0; margin: 0 0 1rem; }
.night-list li { padding: .5rem 0; border-bottom: 1px solid var(--line); display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }

/* ---------------------------------------------------------- singer */

.night-head { padding: .5rem 0 1rem; }
.search-input { font-size: 1.1rem; }
.results { margin-top: .8rem; display: flex; flex-direction: column; gap: .6rem; }
.song { border: 1px solid var(--line); border-radius: 10px; padding: .7rem; background: var(--panel-2); }
.song-head { margin-bottom: .5rem; }
.picks { display: flex; flex-direction: column; gap: .4rem; }
.pick {
  display: grid; grid-template-columns: auto 1fr auto; gap: .6rem; align-items: center;
  padding: .45rem; border: 1px solid var(--line); border-radius: 10px; background: var(--panel);
}
.pick-any { border-style: dashed; }
.pick-thumb { border-radius: 6px; object-fit: cover; display: block; }
.pick-main { min-width: 0; }
.pick-channel { font-weight: 600; font-size: .92rem; }
.pick-title {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; overflow-wrap: anywhere;
}
.pick-actions { display: flex; gap: .3rem; align-items: center; }

@media (max-width: 520px) {
  .pick { grid-template-columns: auto 1fr; }
  .pick-actions { grid-column: 1 / -1; justify-content: flex-end; }
}

.practice-list, .hist-list { list-style: none; padding: 0; margin: 0; }
.practice, .hist {
  display: flex; justify-content: space-between; align-items: center; gap: .8rem;
  padding: .6rem 0; border-bottom: 1px solid var(--line); flex-wrap: wrap;
}
.practice:last-child, .hist:last-child { border-bottom: 0; }
.practice-what, .hist-what, .fav-what { min-width: 0; flex: 1 1 14rem; }
.hist-rate { display: flex; gap: .3rem; flex-wrap: wrap; }
.hist-cancelled, .hist-skipped { opacity: .55; }
.night-list li { justify-content: space-between; }
.nav-here { color: var(--ink) !important; font-weight: 700; }

@media (max-width: 520px) {
  .stat { flex: 1 1 45%; }
  .stat-n { font-size: 1.4rem; }
  .practice, .hist { align-items: flex-start; }
  .hist-rate { width: 100%; }
}

.fav-list { list-style: none; padding: 0; margin: 0; }
.fav {
  display: flex; justify-content: space-between; align-items: center; gap: .8rem;
  padding: .55rem 0; border-bottom: 1px solid var(--line); flex-wrap: wrap;
}
.fav:last-child { border-bottom: 0; }
.fav-out { opacity: .5; }
.fav-actions { display: flex; align-items: center; gap: .4rem; }
.star {
  background: none; border: 0; cursor: pointer; font-size: 1.3rem; line-height: 1;
  color: var(--ink-dim); padding: 0 .3rem 0 0;
}
.star-on { color: var(--warn); }
.star:hover { color: var(--warn); }

.mine-list { list-style: none; padding: 0; margin: 0; }
.mine {
  display: flex; justify-content: space-between; align-items: center; gap: .8rem;
  padding: .6rem 0; border-bottom: 1px solid var(--line); flex-wrap: wrap;
}
.mine-status { display: flex; align-items: center; gap: .4rem; }
.mine-done, .mine-cancelled, .mine-skipped { opacity: .55; }

.queue { list-style: none; counter-reset: q; padding: 0; margin: 0; }
.q {
  counter-increment: q; display: grid; grid-template-columns: auto 1fr auto; gap: .6rem;
  align-items: baseline; padding: .55rem 0; border-bottom: 1px solid var(--line);
}
.q::before { content: counter(q); color: var(--ink-dim); font-variant-numeric: tabular-nums; font-size: .85rem; }
.q-name { font-weight: 700; }
.q-song { color: var(--ink-dim); }
.q-mine { background: rgba(255, 61, 129, .08); border-radius: 8px; }
.q-now { background: rgba(47, 209, 138, .1); border-radius: 8px; }

/* ---------------------------------------------------------- desk */

.desk-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; flex-wrap: wrap; padding: .5rem 0 1rem; }
.desk-head-right { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.desk-bar {
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  padding: .8rem; margin-bottom: 1rem; border: 1px solid var(--line);
  border-radius: var(--radius); background: var(--panel);
}
.desk-bar .btn-big { width: auto; }

/* The screens, in one row under the title: open each, or get walked through. */
.desk-screens { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; margin: -.2rem 0 1rem; }
.desk-group-label { font-size: .75rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-dim); margin-right: .2rem; }
.desk-screens-gap { flex: 1; }
.desk-settings { margin-left: .4rem; }

/* The night's controls: one size, a picture each. */
.desk-bar { flex-direction: column; flex-wrap: nowrap; align-items: stretch; }
.desk-ctls { display: grid; grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr)); grid-auto-rows: 3.4rem; align-items: stretch; gap: .6rem; }
.desk-ctls form { margin: 0; display: flex; }
.desk-ctl { width: 100%; height: 3.4rem; min-height: 0; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  font-size: 1rem; font-weight: 800; padding: .4rem .7rem; line-height: 1.15; text-align: center; }
.desk-ctl.is-on { border-color: var(--go); color: var(--go); background: rgba(47, 209, 138, .12); }
.desk-ctl-warn { border-color: rgba(255, 61, 129, .6); }
.desk-status-row { display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }

.desk-rows { display: flex; flex-direction: column; gap: .5rem; }
.desk-row {
  display: grid; gap: .5rem 1rem; align-items: center;
  grid-template-columns: minmax(140px, 1fr) minmax(220px, 2fr) auto;
  padding: .6rem .7rem; border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
}
.desk-row-live { border-color: var(--go); background: rgba(47, 209, 138, .09); }
.desk-who { display: flex; flex-direction: column; gap: .2rem; }
.desk-name { font-weight: 800; font-size: 1.15rem; }
.desk-note { color: var(--ink-dim); font-size: .82rem; }
.desk-song { font-weight: 600; }
.desk-version { font-size: .85rem; margin-top: .15rem; }
.version-link { text-decoration: none; border-bottom: 1px dotted currentColor; }
.desk-controls { display: flex; gap: .35rem; flex-wrap: wrap; justify-content: flex-end; }

.version-panel { grid-column: 1 / -1; border-top: 1px solid var(--line); padding-top: .6rem; margin-top: .3rem; }
.version-line { display: flex; align-items: center; gap: .5rem; padding: .25rem 0; flex-wrap: wrap; }
.version-chosen .version-label { color: var(--go); font-weight: 700; }
.version-add { display: flex; gap: .4rem; margin-top: .5rem; flex-wrap: wrap; }
.version-url { flex: 3 1 260px; }
.version-label-in { flex: 1 1 140px; }

.block-list { list-style: none; padding: 0; margin: 0; }
.block-list li { padding: .4rem 0; border-bottom: 1px solid var(--line); display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }

/* ---------------------------------------------------------- admin */

.stat-row { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: 1rem; }
.stat {
  flex: 1 1 120px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: .7rem .9rem;
}
.stat-n { display: block; font-size: 1.7rem; font-weight: 800; line-height: 1.1; }
.stat-l { display: block; font-size: .75rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-dim); }
.table-scroll { overflow-x: auto; }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }
/* Model ids are hyphens all the way down, and the browser breaks at every one:
   z-ai-glm-5-3- on one line, flash on the next. The table scrolls instead. */
.model-table code, .model-table .badge { white-space: nowrap; }
.dedication { padding: .6rem 0; border-top: 1px solid var(--line); }
.dedication:first-of-type { border-top: 0; }
.dedication-text { font-size: 1.1rem; margin: 0 0 .2rem; overflow-wrap: anywhere; }
.warn-text { color: var(--warn); }
code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .85em;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 6px; padding: .05rem .35rem;
}

/* ---------------------------------------------------------- catalog review */

.filter-row { display: flex; gap: .4rem; flex-wrap: wrap; margin-bottom: .8rem; }
.chip-link {
  display: inline-flex; align-items: center; gap: .35rem; text-decoration: none;
  font-size: .85rem; padding: .3rem .7rem; border-radius: 999px;
  background: var(--panel-2); border: 1px solid var(--line); color: var(--ink-dim);
}
.chip-link:hover { border-color: var(--hot); color: var(--ink); }
.chip-on { background: var(--hot); border-color: transparent; color: #1a1024; font-weight: 700; }
.chip-n { font-variant-numeric: tabular-nums; opacity: .8; }

/* ---------------------------------------------------------- catalog builder */

.lookup-card {
  display: flex; gap: .8rem; align-items: center; margin: .8rem 0;
  padding: .6rem; border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
}
.lookup-card img { border-radius: 8px; object-fit: cover; }
.ai-modes { display: flex; gap: 1.2rem; margin-bottom: .8rem; }
.ai-modes .check { color: var(--ink); font-size: .95rem; }
.ai-msg { margin: .8rem 0 0; }
#ai-save-bar {
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap;
  margin-top: 1rem; padding-top: .8rem; border-top: 1px solid var(--line);
}
#ai-save-bar .btn-big { width: auto; }

.cand-song { margin-top: 1rem; padding-top: .6rem; border-top: 1px solid var(--line); }
.cand-head { margin-bottom: .4rem; font-size: 1.05rem; }
.cand-row {
  display: grid; grid-template-columns: auto 120px 1fr auto; gap: .7rem;
  align-items: center; padding: .45rem .5rem; border-radius: 8px; margin-bottom: .35rem;
  background: var(--panel-2); border: 1px solid var(--line);
}
.cand-checking { opacity: .6; }
.cand-live { border-color: rgba(47, 209, 138, .45); }
.cand-dead { border-color: rgba(255, 93, 93, .4); opacity: .55; }
.cand-doubt { border-color: rgba(255, 190, 77, .5); }
.cand-check { width: auto; }
.cand-thumb img { border-radius: 6px; display: block; object-fit: cover; }
.cand-main { min-width: 0; overflow-wrap: anywhere; }
.cand-label { font-size: .9rem; }

@media (max-width: 720px) {
  .cand-row { grid-template-columns: auto 1fr; }
  .cand-thumb { grid-column: 2; }
}

.badge-pending { background: rgba(255, 190, 77, .16); color: var(--warn); }
.badge-running { background: rgba(47, 209, 138, .2); color: var(--go); }
.badge-done    { color: var(--ink-dim); }
.badge-failed  { background: rgba(255, 93, 93, .2); color: var(--danger); }
.badge-skipped { color: var(--ink-dim); opacity: .7; }
.cron-line {
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
  padding: .6rem .8rem; overflow-x: auto; font-size: .8rem; white-space: pre;
}

.schema-warn { border-color: rgba(255, 190, 77, .5); background: rgba(255, 190, 77, .07); }
.schema-warn h3 { margin: .8rem 0 .3rem; color: var(--ink-dim); }

/* The coverage bar is gone: a catalog that is nearly all real videos does not
   need a progress bar telling it so, and the one line that replaced it says
   the only thing left worth acting on. */
.gap-line { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; }
.row-gap td { opacity: .75; }
.row-gap td:first-child { border-left: 2px solid rgba(255, 190, 77, .5); padding-left: .4rem; }

.task-head { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.task-head h2 { margin: 0; }

.setting { padding: .7rem 0; border-bottom: 1px solid var(--line); }
.setting:last-child { border-bottom: 0; }
.setting > label { display: flex; flex-direction: column; gap: .3rem; max-width: 420px; }
.setting > label.check { flex-direction: row; align-items: center; gap: .5rem; max-width: none; }
.setting strong { color: var(--ink); font-weight: 600; }
.setting-help { margin: .35rem 0 0; max-width: 60ch; }


.prune-note {
  margin: .8rem 0 0; padding: .6rem .8rem; border-radius: 10px;
  background: rgba(255, 190, 77, .1); border: 1px solid rgba(255, 190, 77, .35);
  display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; font-size: .9rem;
}
.review-list { display: flex; flex-direction: column; gap: .5rem; }
.review-row {
  display: grid; gap: .6rem 1rem; align-items: start;
  grid-template-columns: 160px minmax(220px, 1fr) auto;
  padding: .6rem; border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2);
}
.review-dead { border-color: rgba(255, 93, 93, .55); background: rgba(255, 93, 93, .07); }
.review-live { border-color: rgba(47, 209, 138, .35); }
.review-thumb img { display: block; border-radius: 8px; width: 160px; height: 90px; object-fit: cover; }
.thumb-none {
  display: flex; align-items: center; justify-content: center; text-align: center;
  width: 160px; height: 90px; border-radius: 8px; border: 1px dashed var(--line);
  color: var(--ink-dim); font-size: .75rem; text-transform: uppercase; letter-spacing: .05em;
}
.review-main { min-width: 0; overflow-wrap: anywhere; }
.review-label { font-size: .88rem; color: var(--ink); margin: .15rem 0; }
.review-status { display: flex; flex-direction: column; gap: .25rem; align-items: flex-end; text-align: right; }
.review-actions { grid-column: 1 / -1; display: flex; gap: .35rem; flex-wrap: wrap; align-items: center; }
.review-actions .relabel { display: flex; gap: .3rem; flex: 1 1 260px; }
.review-actions .relabel input { flex: 1 1 auto; padding: .25rem .5rem; font-size: .8rem; }
.review-advanced { margin: .6rem 0 0; }
.review-advanced > summary { cursor: pointer; color: var(--ink-dim); font-size: .85rem; }
.review-advanced[open] > summary { margin-bottom: .4rem; }
.review-more { position: relative; }
.review-more > summary {
  list-style: none; cursor: pointer; user-select: none;
  padding: .2rem .55rem; border-radius: 999px; border: 1px solid var(--line);
  font-size: .8rem; color: var(--ink-dim);
}
.review-more > summary::-webkit-details-marker { display: none; }
.review-more > summary:hover { color: var(--ink); }
.review-more-items {
  position: absolute; left: 0; top: calc(100% + .35rem); z-index: 20;
  min-width: 16rem; padding: .45rem; display: flex; flex-wrap: wrap; gap: .35rem;
  background: var(--panel); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 10px 28px rgba(0, 0, 0, .45);
}
.channel-find { display: flex; gap: .4rem; align-items: center; margin: .4rem 0; }
.channel-find input[type="search"] { max-width: 16rem; padding: .25rem .5rem; }
.chip-n-warn { background: rgba(255, 190, 77, .2); color: var(--warn); }
.choice { border: 1px solid var(--line); border-radius: 10px; padding: .7rem .9rem; margin: 0; }
.choice legend { font-size: .9rem; color: var(--ink-dim); padding: 0 .3rem; }
.choice .check { margin: .2rem 0; color: var(--ink); }
.choice p { margin: .5rem 0 0; }

.rating-select { width: auto !important; padding: .25rem .4rem !important; font-size: .8rem; }
.badge-live { background: rgba(47, 209, 138, .2); color: var(--go); }
.badge-dead { background: rgba(255, 93, 93, .2); color: var(--danger); }
.badge-unknown { color: var(--ink-dim); }
.badge-unreachable { background: rgba(255, 190, 77, .18); color: var(--warn); }
.pager { display: flex; align-items: center; gap: .8rem; margin-top: 1rem; }

@media (max-width: 720px) {
  .review-row { grid-template-columns: 1fr; }
  .review-status { align-items: flex-start; text-align: left; flex-direction: row; }
}

/* ---------------------------------------------------------- join card */

.join-card { text-align: center; padding: 1rem; }
.join-venue { color: var(--ink-dim); margin-top: -.4rem; }
.qr { display: flex; justify-content: center; padding: 1.2rem 0; }
.qr img, .qr canvas { background: #fff; padding: 10px; border-radius: 10px; }
.join-url { font-size: 1.05rem; color: var(--ink-dim); margin: .2rem 0; }
.join-code-big {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 3rem; font-weight: 800; letter-spacing: .3em; margin: .2rem 0 .4rem; color: var(--hot);
}
.join-how { max-width: 380px; margin: 0 auto; color: var(--ink-dim); font-size: .9rem; }
.join-social { margin: .9rem auto 0; color: var(--ink-dim); font-size: .95rem; }
.join-social strong { color: var(--ink); font-size: 1.15rem; }
.join-social span { font-size: .85rem; }
.foot-social { margin-bottom: .2rem; }

@media print {
  body { background: #fff; color: #000; }
  .topbar, .foot, .no-print, .flashes { display: none; }
  .panel { border: 0; background: #fff; }
  .join-code-big { color: #000; }
  .join-venue, .join-url, .join-how, .join-social { color: #333; }
  .join-social strong { color: #000; }
}

@media (max-width: 640px) {
  .desk-row { grid-template-columns: 1fr; }
  .desk-controls { justify-content: flex-start; }
}


/* ---------------------------------------------------------- player screen */

body.bare { background: #05040a; }
.bare-wrap { max-width: none; margin: 0; padding: 0; height: 100vh; }
#player-root { height: 100vh; position: relative; }

.stage {
  height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 3vh 4vw; gap: .6rem;
}
.chip-key { color: var(--go); border-color: rgba(47, 209, 138, .45); }
.idle-clock-wrap { display: flex; flex-direction: column; align-items: center; margin-bottom: 2vh; }
.idle-clock { font-size: clamp(2rem, 7vw, 6rem); font-weight: 800; line-height: 1; letter-spacing: -.02em; }
.idle-date { color: var(--ink-dim); font-size: clamp(.9rem, 1.6vw, 1.4rem); }

.stage-kicker {
  margin: 0; text-transform: uppercase; letter-spacing: .3em; font-size: 1.1vw;
  color: var(--ink-dim); min-font-size: 12px;
}
.stage-title { margin: 0; font-size: clamp(1.8rem, 5vw, 4.5rem); line-height: 1.05; }
.stage-singer {
  margin: 0; font-size: clamp(2.5rem, 11vw, 11rem); line-height: 1; font-weight: 800;
  background: linear-gradient(135deg, var(--hot), var(--hot-2));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.stage-song { margin: .4rem 0 0; font-size: clamp(1.1rem, 3vw, 2.6rem); color: var(--ink-dim); }
/* The countdown to a song the night started on its own. Big enough to read
   from the back of the room, which is where the singer probably is. */
.stage-count {
  margin: 1.4rem 0 0; font-size: clamp(1.6rem, 5vw, 4.4rem); font-weight: 800;
  color: var(--hot-2); font-variant-numeric: tabular-nums;
}
/* "Not here": in a corner, readable, and out of the way of the words. */
.player-noshow {
  position: fixed; left: 1.2vw; top: 1.2vh; z-index: 50;
  padding: .6rem 1.1rem; border-radius: 999px; border: 1px solid rgba(255, 255, 255, .35);
  background: rgba(18, 16, 28, .8); color: #fff; font: inherit; font-weight: 700;
  font-size: clamp(.9rem, 1.4vw, 1.3rem); cursor: pointer;
}
.player-noshow:hover { background: rgba(255, 61, 129, .35); }
.stage-sub { margin: 0; font-size: clamp(1rem, 1.8vw, 1.6rem); color: var(--ink-dim); }
.stage-start { width: auto; font-size: clamp(1rem, 2vw, 1.6rem); padding: 1rem 2.4rem; margin-top: 1rem; }
.stage-note { max-width: 46ch; color: var(--ink-dim); font-size: .95rem; margin-top: 1rem; }

.stage-join {
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; justify-content: center;
  margin-top: 2rem; padding: .8rem 1.2rem; border: 1px solid var(--line); border-radius: var(--radius);
}
.stage-join-label { text-transform: uppercase; letter-spacing: .2em; font-size: .8rem; color: var(--ink-dim); }
.stage-join-url { color: var(--ink-dim); }
.stage-list { list-style: decimal; margin: 1.4rem 0 0; padding-left: 1.4rem; text-align: left;
  color: var(--ink-dim); font-size: clamp(.95rem, 1.5vw, 1.3rem); }
.stage-list li { padding: .15rem 0; }

#player-stage { position: absolute; inset: 0; background: #000; }
#player-video { position: absolute; inset: 0; }
#player-stage iframe, #yt { width: 100%; height: 100%; border: 0; display: block; }

/* ------------------------------------------------- the rail on the room screen
   A strip beside the video with the QR, the code and who is next, so somebody
   walking in during a song can join without waiting for a gap. It costs about
   a fifth of the width -- nothing on a big television across a living room,
   worth switching off on a small screen at the back of a bar. */
#player-stage.has-rail #player-video { right: 22%; }
#player-rail {
  position: absolute; top: 0; right: 0; bottom: 0; width: 22%;
  display: flex; flex-direction: column; align-items: center; gap: .8rem;
  padding: 2vh 1.2vw; background: var(--bg); border-left: 1px solid var(--line);
  overflow: hidden;
}
.rail-qr { background: #fff; padding: .5rem; border-radius: 12px; line-height: 0; }
.rail-join { display: flex; flex-direction: column; align-items: center; gap: .15rem; text-align: center; }
.rail-code {
  font-size: clamp(1.1rem, 2.1vw, 2rem); font-weight: 700; letter-spacing: .16em;
}
.rail-url { font-size: clamp(.6rem, 1vw, .95rem); color: var(--ink-dim); }
.rail-kicker {
  margin: .4rem 0 0; text-transform: uppercase; letter-spacing: .08em;
  font-size: clamp(.6rem, .9vw, .9rem); color: var(--ink-dim);
}
.rail-list {
  list-style: none; margin: 0; padding: 0; width: 100%;
  display: flex; flex-direction: column; gap: .5rem; overflow: hidden;
}
.rail-list li { display: flex; flex-direction: column; line-height: 1.2; }
.rail-list strong { font-size: clamp(.75rem, 1.3vw, 1.3rem); }
.rail-list span {
  font-size: clamp(.6rem, 1vw, 1rem); color: var(--ink-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rail-none { color: var(--ink-dim); font-size: clamp(.65rem, 1vw, 1rem); }
#player-nowbar {
  position: absolute; left: 0; right: 0; bottom: 0; padding: .6rem 1.2rem;
  background: linear-gradient(to top, rgba(0,0,0,.85), rgba(0,0,0,0));
  font-size: clamp(1rem, 2vw, 1.8rem); font-weight: 700; pointer-events: none;
}
/* The rail carries who we are: the wordmark over the QR, the mic at its foot. */
.rail-brand { font-size: clamp(.9rem, 1.6vw, 1.6rem); }
.rail-brand .wordmark-sm { font-size: inherit; }
.rail-mic { margin-top: auto; width: clamp(2rem, 3.4vw, 3.4rem); height: auto; opacity: .9; }

.player-status {
  position: absolute; bottom: 4.2rem; left: 1.2vw; font-size: .8rem; color: var(--ink-dim);
  pointer-events: none; z-index: 5;
}

/* ---------------------------------------------------------------- reports
   "Something wrong with that video?" -- folded shut, quiet, and out of the
   way, because almost always nothing is. */
.report { width: 100%; margin-top: .4rem; }
.report > summary {
  cursor: pointer; font-size: .8rem; color: var(--ink-dim); list-style: none;
}
.report > summary::-webkit-details-marker { display: none; }
.report > summary::before { content: "\2691\00a0"; }
.report > summary:hover { color: var(--ink); }
.report-form {
  display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin: .5rem 0 .3rem;
}
.report-form select { flex: 2 1 220px; }
.report-form input[type="text"] { flex: 3 1 200px; }

/* ---------------------------------------------------------- switch panels
   The per-night feature switches. Whole-row labels, so the tap target on a
   phone is the row and not a 16px box. */
.switch-list { display: flex; flex-direction: column; gap: .2rem; }
.switch {
  display: flex; gap: .7rem; align-items: flex-start; padding: .7rem .6rem;
  border-radius: var(--radius); cursor: pointer;
}
.switch:hover { background: rgba(255,255,255,.03); }
.switch input { margin-top: .25rem; flex: 0 0 auto; width: 1.1rem; height: 1.1rem; }
.switch-body { display: flex; flex-direction: column; gap: .15rem; }
.switch-label { font-weight: 600; }
.switch-note { color: var(--ink-dim); font-size: .85rem; }

/* ------------------------------------------------------- audience screen
   Built to be read across a room, not from a desk: everything scales with
   the viewport, and the join code is always on screen because somebody is
   always arriving. */
#room-root { height: 100vh; }
.room {
  height: 100vh; display: grid; grid-template-rows: auto 1fr auto;
  padding: 2.5vh 3vw; gap: 2vh;
}
.room-head { display: flex; justify-content: space-between; align-items: baseline; color: var(--ink-dim); }
.room-night { font-size: clamp(1rem, 2vw, 1.8rem); font-weight: 700; }
.room-clock { font-size: clamp(1rem, 2vw, 1.8rem); font-variant-numeric: tabular-nums; }

.room-main { display: flex; flex-direction: column; justify-content: center; gap: 3vh; min-height: 0; }
.room-singer {
  margin: 0; font-size: clamp(2.4rem, 9vw, 8rem); font-weight: 800; line-height: 1;
  letter-spacing: -.02em;
}
.room-song { margin: 0; font-size: clamp(1.1rem, 3.2vw, 3rem); color: var(--ink-dim); }

.room-next { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .4vh; }
.room-next li {
  display: flex; gap: 1rem; align-items: baseline; padding: .5vh 0;
  border-top: 1px solid var(--line); font-size: clamp(.95rem, 2vw, 1.9rem);
}
.room-next-name { font-weight: 700; flex: 0 0 auto; }
.room-next-song { color: var(--ink-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.room-join { display: flex; align-items: center; gap: 2vw; }
.room-qr { background: #fff; padding: .6rem; border-radius: var(--radius); line-height: 0; }
.room-qr img, .room-qr canvas { display: block; width: clamp(90px, 11vw, 190px); height: auto; }
.room-join-text { display: flex; flex-direction: column; gap: .3rem; }
.room-join-url { font-size: clamp(1rem, 2.2vw, 2rem); color: var(--ink-dim); }
.room-join.is-closed { opacity: .85; }
.room-join.is-closed .room-qr { padding: .35rem; }
.room-join.is-closed .room-qr img,
.room-join.is-closed .room-qr canvas { width: clamp(56px, 6vw, 100px); }
.room-join.is-closed .code-pill { display: none; }
.room-join.is-closed .room-join-url { font-size: clamp(.8rem, 1.4vw, 1.3rem); }
.room-now .stage-lastcall { display: inline-block; }

/* Yes / no / not sure, on the kids page. */
.kid-buttons { display: flex; gap: .3rem; flex-wrap: wrap; justify-content: flex-end; }

/* ------------------------------------------------------------- the lockup
   The wordmark, wherever it appears. The topbar version is small and quiet;
   these are the ones on the screens people look at from across a room, or
   while they wait for something. Same three colours, same weight, same tight
   tracking -- only the scale changes. */
.wordmark {
  display: inline-flex; align-items: center; gap: .45em;
  font-weight: 800; letter-spacing: -.03em; line-height: 1; white-space: nowrap;
}
.wordmark-mic { width: 1.15em; height: 1.15em; display: block; }
.wordmark-text { display: inline-block; }

.wordmark-sm { font-size: 1.15rem; }
.wordmark-md { font-size: clamp(1.4rem, 3vw, 2rem); }
.wordmark-lg { font-size: clamp(1.8rem, 5vw, 3.2rem); }
.wordmark-xl { font-size: clamp(2.2rem, 7vw, 5rem); }

/* On the stage screens the lockup sits above everything else and should read
   as a sign, not as a heading: spaced out, dimmed slightly, out of the way of
   the name that matters. */
.stage-brand { position: absolute; top: 3vh; left: 0; right: 0; text-align: center; opacity: .9; }
.room-brand { opacity: .95; }

/* Printed join cards keep their colour. A table card in greyscale looks like a
   photocopy of a table card. */
.join-brand { margin-bottom: .6rem; }
@media print {
  .wordmark { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
  .brand-sing { color: #12101c !important; }
}

/* ------------------------------------------------------------- preview bar
   Twenty seconds of a track, without leaving the page. The player stays
   visible: hiding it and treating YouTube as an audio service is against
   their terms, and seeing the words is half of recognising a karaoke take. */
.preview-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  display: flex; align-items: center; gap: 1rem; padding: .6rem 1rem;
  background: rgba(27, 24, 48, .97); border-top: 1px solid var(--line);
  backdrop-filter: blur(8px);
}
.preview-frame { flex: 0 0 auto; width: 160px; height: 90px; background: #000; border-radius: 8px; overflow: hidden; }
.preview-frame iframe { width: 160px; height: 90px; border: 0; display: block; }
.preview-what { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .15rem; }
.preview-kicker { text-transform: uppercase; letter-spacing: .18em; font-size: .7rem; color: var(--ink-dim); }
.preview-label { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.btn-listen { white-space: nowrap; }

@media (max-width: 560px) {
  .preview-frame, .preview-frame iframe { width: 108px; height: 61px; }
}

/* ------------------------------------------------------------------ tiles
   How a film looks to somebody who cannot read its name. The preview here is
   the same shape the kiosk will use, so what an admin sets is what a child
   sees. */
.tile-list { display: flex; flex-direction: column; gap: .5rem; }
.tile-row {
  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
  padding: .5rem; border-radius: var(--radius);
}
.tile-row:hover { background: rgba(255,255,255,.03); }
.tile-preview {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .2rem; width: 130px; height: 84px; border-radius: 14px; padding: .4rem;
  text-align: center; line-height: 1.1;
}
.tile-emoji { font-size: 1.9rem; line-height: 1; }
.tile-name {
  font-size: .72rem; font-weight: 700; letter-spacing: .01em;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Typed as input.x rather than .x: the base input[type=text] rule is an
   attribute selector, so a bare class loses to it and these went full width. */
input.tile-emoji-input { flex: 0 0 auto; width: 5.5rem; text-align: center; font-size: 1.3rem; }
select.tile-colour { flex: 0 0 auto; width: 8rem; }
kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8em;
  border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 5px; padding: 0 .3em;
}

/* The soft wait next to a singer's place in line. Quiet on purpose: it is an
   estimate, and it should not look like a countdown. */
.wait { color: var(--ink-dim); font-size: .85rem; white-space: nowrap; }

/* ------------------------------------------------------------------ duets
   Want ads for a singing partner. Matched ones dim rather than disappear, so
   the pair can see it worked and either of them can pull it back out. */
.duet-list { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .5rem; }
.duet {
  display: flex; gap: 1rem; align-items: flex-start; justify-content: space-between;
  padding: .7rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel-2);
}
.duet-matched { opacity: .62; }
.duet-what { min-width: 0; }
.duet-part { display: flex; gap: .3rem; flex-wrap: wrap; margin-top: .45rem; }
.duet-actions { display: flex; gap: .5rem; align-items: center; flex: 0 0 auto; }
.pick-duet { border-top: 1px dashed var(--line); }

/* Past nights: present, but folded away. The code column is gone from these
   entirely -- a dead join code on screen only invites somebody to try it. */
.past-nights { margin-top: 1.2rem; }
.past-nights > summary { cursor: pointer; color: var(--ink-dim); font-size: .9rem; }
.past-nights > summary:hover { color: var(--ink); }
.past-nights .table { margin-top: .6rem; }

/* ------------------------------------------------------------- the tip jar
   Never in front of somebody waiting for their turn. Quiet in the footer,
   slightly warmer on a singer's own list, and absent entirely when no handle
   is configured. */
.tip { display: flex; align-items: center; justify-content: center; gap: .6rem; flex-wrap: wrap; }
.tip-why { color: var(--ink-dim); font-size: .85rem; }
.tip-links { display: flex; gap: .4rem; flex-wrap: wrap; }
.tip-quiet { margin-top: .6rem; opacity: .8; }
.tip-panel {
  margin: 1.2rem 0; padding: .9rem 1rem; border: 1px dashed var(--line);
  border-radius: var(--radius); justify-content: space-between;
}
.tip-panel .tip-why { color: var(--ink); }

/* Sub-tabs inside an admin section, for a page that is really two jobs. */
.sub-tabs { margin: 0 0 1rem; }

/* ------------------------------------------------------- staying in a night
   One tap back, on every page that is not the night. Quiet, but always in the
   same place, because the alternative is remembering a six-character code. */
.back-to-night {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .45rem 1rem; background: var(--panel-2); border-bottom: 1px solid var(--line);
  font-size: .9rem;
}
.back-to-night a { font-weight: 600; text-decoration: none; }

/* Sections that fold: finished songs, the duet board. */
.finished { margin-top: .6rem; }
.finished > summary, .duet-fold > summary { cursor: pointer; color: var(--ink-dim); }
.finished > summary:hover, .duet-fold > summary:hover { color: var(--ink); }
.duet-fold > summary {
  display: flex; align-items: baseline; gap: .6rem; flex-wrap: wrap; list-style: none;
}
.duet-fold > summary::-webkit-details-marker { display: none; }
.duet-fold > summary::before { content: "\25B8"; color: var(--ink-dim); }
.duet-fold[open] > summary::before { content: "\25BE"; }
.duet-fold-title {
  font-weight: 700; text-transform: uppercase; letter-spacing: .02em; font-size: 1.1rem;
  color: var(--ink);
}

/* Who made a call, on the row where they made it. */
.chip-who { text-decoration: none; }
.chip-who:hover { border-color: var(--hot); color: var(--ink); }

/* Auditing one reviewer's run: the numbers that would give away a bad one. */
.review-audit {
  border-left: 3px solid var(--hot); padding: .1rem 0 .1rem .9rem; margin: .2rem 0 .9rem;
}
.review-audit p { margin: .3rem 0; }

/* Killed channels: history, folded away until asked for. */
.blocked-fold { margin-top: .8rem; }
.blocked-fold > summary {
  cursor: pointer; color: var(--ink-dim); font-size: .85rem; width: fit-content;
}
.blocked-fold > summary:hover { color: var(--ink); }
.blocked-fold .block-list { margin-top: .4rem; }

/* What a channel's already-watched videos turned out to be. */
.order-row { margin-top: .5rem; align-items: center; }
.chip-chan { border-color: rgba(255, 255, 255, .18); }
.chip-chan-good  { border-color: var(--go); color: var(--go); }
.chip-chan-mixed { border-color: rgba(255, 190, 77, .55); color: var(--warn); }
.chip-chan-low   { border-color: var(--danger); color: var(--danger); background: rgba(255, 93, 93, .1); }
/* "All good + tracks" on a channel that mostly does not track: still there,
   but outlined, so it is not the thing a quick thumb lands on. */
.btn.btn-unlikely { background: transparent; color: var(--go); box-shadow: inset 0 0 0 1px rgba(47, 209, 138, .5); }

/* ----------------------------------------------- the desk, in one hand
   A karaoke master runs the night from a phone while the laptop drives the
   room's screen. That makes these the buttons of the whole product, pressed
   in a dark room, one-handed, often holding something else. Apple and Google
   both put a comfortable target at 44px; the desk was shipping 34. */
@media (max-width: 640px) {
  .desk-row .btn, .desk-controls .btn { min-height: 44px; padding-inline: .9rem; }
  .desk-controls { gap: .5rem; }
  .desk-bar .btn { min-height: 48px; }
}

/* The page a venue reads before saying yes. */
.hero-tight { padding-bottom: .5rem; }
/* The front page, for somebody deciding whether to run a night. */
.hero-kj h1 { font-size: clamp(2rem, 6vw, 3rem); line-height: 1.1; }
.hero-kj .lede { max-width: 36rem; margin-inline: auto; font-size: 1.1rem; }
.kj-steps { margin: 0; padding-left: 1.3rem; display: flex; flex-direction: column; gap: .8rem; }
.kj-steps li::marker { color: var(--hot); font-weight: 800; }
.panel-join { text-align: center; scroll-margin-top: 1rem; }
html { scroll-behavior: smooth; }
.sing-jump {
  display: inline-block; margin-bottom: 1.2rem; padding: .45rem 1rem; border-radius: 999px;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--ink); text-decoration: none; font-size: .95rem;
}
.sing-jump strong { color: var(--hot); }
.sing-jump:hover { border-color: var(--hot); }
.kj-grid .need h3 {
  background: linear-gradient(90deg, var(--hot), var(--hot-2)); -webkit-background-clip: text; background-clip: text;
  color: transparent; font-size: 1.15rem;
}
.need-grid.kj-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 640px) { .need-grid.kj-grid { grid-template-columns: 1fr; } }
/* Sign-up: which account, as two big choices. */
.role-pick { border: 0; padding: 0; margin: 0 0 .4rem; display: grid; gap: .6rem; }
.role-pick legend { font-weight: 700; margin-bottom: .5rem; }
.stack .role-card, .role-card { display: grid; grid-template-columns: auto 1fr; gap: .2rem .7rem; align-items: start; cursor: pointer;
             padding: .8rem .9rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--panel-2); }
.stack .role-card input, .role-card input { margin-top: .25rem; grid-row: span 2; width: auto; }
.role-card:has(input:checked) { border-color: var(--hot); box-shadow: 0 0 0 1px var(--hot) inset; }
.role-title { font-weight: 700; }
.role-note { color: var(--ink-dim); font-size: .9rem; }
.need-grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.need { border: 1px solid var(--line); border-radius: 12px; padding: .9rem 1rem; }
.need h3 { margin: 0 0 .4rem; font-size: 1rem; }
.need p { margin: 0 0 .5rem; }
.how-list { margin: 0; padding-left: 1.2rem; display: flex; flex-direction: column; gap: .55rem; }

/* The gear page: a short list where each line is a thing, then a caveat. */
.gear-list { margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: .7rem; }
.gear-list strong { display: block; }

/* ------------------------------------------------- the singer's status bar
   Three things somebody glances at a phone to learn: how long the line is,
   where they are in it, how to get into it. Everything else on that page is
   something you do once; this is what you keep checking, so it sits above
   everything and stays the same shape all night. */
.now-bar {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: .5rem;
  margin: .2rem 0 1rem;
}
.now-cell {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .1rem; padding: .7rem .4rem; min-height: 68px; text-align: center;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px;
}
.now-cell strong { font-size: 1.45rem; line-height: 1.1; }
.now-cell .small { font-size: .72rem; }
.now-you.now-up { border-color: var(--go); color: var(--go); }
.now-you.now-up strong { color: var(--go); }
.now-add { cursor: pointer; font: inherit; color: inherit; border-color: var(--hot); }
.now-add strong { color: var(--hot); font-size: 1.6rem; }
.now-add:hover { background: #302a52; }

/* Find a song: a fold on a desktop, a full-screen sheet on a phone. No
   JavaScript in either case -- details does the work, and the one thing a
   modal must never do is trap somebody who has scripting off. */
.search-fold > summary { cursor: pointer; list-style: none; }
.search-fold > summary::-webkit-details-marker { display: none; }
.search-fold > summary h2 { display: inline; }
.search-fold > summary::after { content: " +"; color: var(--hot); font-weight: 700; }
.search-fold[open] > summary::after { content: " \00d7"; }

@media (max-width: 720px) {
  .search-fold[open] {
    position: fixed; inset: 0; z-index: 40; margin: 0; border-radius: 0;
    overflow-y: auto; -webkit-overflow-scrolling: touch;
    background: var(--bg); padding: 1rem;
  }
  .search-fold[open] > summary {
    position: sticky; top: -1rem; z-index: 1; margin: -1rem -1rem .6rem;
    padding: 1rem; background: var(--bg); border-bottom: 1px solid var(--line);
    display: flex; justify-content: space-between; align-items: center;
  }
  .search-fold[open] > summary::after { font-size: 1.6rem; }
}

/* The join code, big enough to read across a table, with something to scan. */
.code-pill-btn { cursor: pointer; font: inherit; letter-spacing: inherit; }
.code-pill-btn:hover { border-color: var(--hot); }
.code-share { display: flex; gap: 1rem; align-items: center; flex-wrap: wrap; }
.code-qr { background: #fff; padding: .5rem; border-radius: 10px; line-height: 0; }
.code-big {
  font-size: 2rem; font-weight: 700; letter-spacing: .18em; margin: .2rem 0 0;
}

/* The join block on the room's screen: something to scan, beside something to
   read. People at the back read the code; people at the front point a camera. */
.stage-join { display: flex; align-items: center; gap: 1.6rem; flex-wrap: wrap;
              justify-content: center; }
.stage-join-words { display: flex; flex-direction: column; align-items: center; gap: .4rem; }
.stage-qr { background: #fff; padding: .6rem; border-radius: 14px; line-height: 0; }

/* After last call. The banner says so before anything else on the screen, and
   the join block shrinks to what it still does: a way to send cheers. The code
   pill goes -- it reads as "type this to get in line". */
.stage-lastcall {
  margin: 0 0 1.2vh; padding: .5rem 1.5rem; border-radius: 999px;
  border: 2px solid var(--hot); background: rgba(255, 61, 129, .14); color: #ff9cbf;
  text-transform: uppercase; letter-spacing: .22em; font-weight: 800;
  font-size: clamp(.95rem, 1.8vw, 1.7rem);
}
.stage-join.is-closed { margin-top: 1.4rem; padding: .5rem .9rem; gap: .9rem; opacity: .85; }
.stage-join.is-closed .stage-qr { padding: .35rem; border-radius: 10px; }
.stage-join.is-closed .stage-qr img,
.stage-join.is-closed .stage-qr canvas { width: clamp(88px, 7.5vw, 140px); height: auto; }
.stage-join.is-closed .code-pill { display: none; }
.stage-join.is-closed .stage-join-words { align-items: flex-start; }
/* "New code every minute", under a code that does. */
.stage-join-note { font-size: clamp(.75rem, 1.1vw, 1rem); color: var(--ink-dim); font-style: italic; }
.stage-join.is-closed .stage-join-note { display: none; }

/* The rail during the last songs: the same banner, a smaller code. */
.rail-lastcall {
  margin: 0; padding: .3rem .9rem; border-radius: 999px; border: 2px solid var(--hot);
  background: rgba(255, 61, 129, .14); color: #ff9cbf; font-weight: 800;
  text-transform: uppercase; letter-spacing: .16em; font-size: clamp(.65rem, 1.1vw, 1.1rem);
}
#player-rail.is-closed .rail-qr { padding: .3rem; }
#player-rail.is-closed .rail-qr img,
#player-rail.is-closed .rail-qr canvas { width: clamp(56px, 5.5vw, 96px); height: auto; }
#player-rail.is-closed .rail-code { display: none; }
#player-rail.no-cheers .rail-qr,
#player-rail.no-cheers .rail-join { display: none; }

/* ------------------------------------------------------- the room cheering
   A row of emoji on the phone, and the same emoji drifting up the sides of
   the big screen. The only two properties animated are transform and opacity,
   which is what a cheap television can composite without dropping the video
   frame behind it. */
.react-bar { padding-block: .7rem; }
.react-who { margin: 0 0 .5rem; text-align: center; }
/* Between songs: still there, plainly not live. */
.react-bar.react-off .react { opacity: .35; filter: grayscale(1); cursor: default; }
/* Two rows of five, however wide the phone. */
.react-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: .4rem; max-width: 22rem; margin: 0 auto; }
.react-row .react { min-width: 0; width: 100%; }
/* Comes with the cheer pack: visible, plainly not yours yet. */
.react.react-locked { opacity: .5; filter: grayscale(.9); cursor: default; position: relative; }
.react.react-locked::after { content: '🔒'; position: absolute; right: 2px; bottom: 0; font-size: .7rem; filter: none; }
/* The free three on their own: one centred row, complete, nothing locked. */
.react-row.react-row-free { grid-template-columns: repeat(3, minmax(0, 4.4rem)); justify-content: center; }
/* Silver, said quietly: one line under the row, opening to the details. */
.react-silver { margin-top: .6rem; text-align: center; }
.react-silver > summary {
  list-style: none; cursor: pointer; display: inline-block; font-size: .82rem; color: var(--ink-dim);
}
.react-silver > summary::-webkit-details-marker { display: none; }
.react-silver > summary:hover { color: var(--ink); }
.react-silver[open] > summary { color: var(--ink); }
.react-silver-preview { font-size: 1.5rem; letter-spacing: .15em; margin: .5rem 0 .2rem; }
.react-silver form { margin-top: .5rem; }
/* The one nudge a party. */
.react-nudge {
  margin-top: .7rem; padding: .7rem .9rem; border-radius: var(--radius); text-align: center;
  border: 1px solid rgba(220, 228, 245, .45); background: rgba(220, 228, 245, .06);
}
.react-nudge[hidden] { display: none; }
.react-nudge p { margin: 0 0 .5rem; }
.react-nudge-actions { display: flex; gap: .5rem; justify-content: center; flex-wrap: wrap; }
.react-pack-note { text-align: center; margin: .6rem 0 0; }

/* ------------------------------------------------- badges */
.badge-strip {
  display: flex; align-items: center; gap: .7rem; flex-wrap: wrap; margin: .2rem 0 1rem;
  padding: .7rem .9rem; border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--panel); text-decoration: none; color: var(--ink);
}
.badge-strip:hover { border-color: var(--hot); }
.badge-strip-label { font-weight: 800; text-transform: uppercase; letter-spacing: .06em; font-size: .8rem; color: var(--ink-dim); }
.badge-strip-icons { display: flex; gap: .2rem; flex-wrap: wrap; font-size: 1.4rem; }
.badge-strip-more { margin-left: auto; font-size: .85rem; color: var(--hot); }

.badge-grid { display: grid; gap: .8rem; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); margin-bottom: 1.2rem; }
.badge-card {
  display: flex; gap: .8rem; align-items: flex-start; padding: .9rem; border-radius: var(--radius);
  background: var(--panel); border: 1px solid var(--line);
}
.badge-icon { font-size: 2.2rem; line-height: 1; filter: grayscale(1); opacity: .4; }
.badge-earned .badge-icon { filter: none; opacity: 1; }
.badge-earned { border-color: rgba(255, 190, 77, .45); }
.badge-maxed { border-color: var(--hot-2); box-shadow: 0 0 18px rgba(255, 138, 61, .18); }
.badge-body { flex: 1; min-width: 0; }
.badge-name { margin: 0; font-size: 1rem; display: flex; align-items: center; gap: .4rem; }
.badge-level {
  font-size: .72rem; font-weight: 800; padding: .05rem .45rem; border-radius: 999px;
  background: var(--warn); color: #1b1d24;
}
.badge-what { margin: .2rem 0 .45rem; }
.badge-bar { height: 7px; border-radius: 999px; background: var(--panel-2); overflow: hidden; }
.badge-bar span { display: block; height: 100%; background: linear-gradient(90deg, var(--hot), var(--hot-2)); }
.badge-steps { display: flex; gap: .55rem; flex-wrap: wrap; margin: .45rem 0 0; font-size: .72rem; }
.badge-step-on { color: var(--warn); font-weight: 700; }

/* ------------------------------------------------- members
   A member's top bar is not like everybody else's: a metallic sheen across
   it, a line of the metal along its foot, and the tag by their name. Silver
   for Silver, gold for Gold. Enough that the person beside them asks why
   theirs looks different -- and only the bar, so the rest of the page is the
   party, not the membership. */
:root {
  --silver-1: #f4f6fb; --silver-2: #aeb6c6; --silver-3: #6f7889;
  --gold-1: #fff3c4; --gold-2: #e0b44a; --gold-3: #8a6417;
}
body.tier-silver .topbar {
  background: linear-gradient(100deg, rgba(220, 228, 245, .26), rgba(18, 16, 28, .9) 32%,
              rgba(18, 16, 28, .9) 68%, rgba(220, 228, 245, .26));
  border-bottom: 2px solid transparent;
  border-image: linear-gradient(90deg, var(--silver-3), var(--silver-1) 30%, var(--silver-2) 60%,
                var(--silver-1) 85%, var(--silver-3)) 1;
}
body.tier-gold .topbar {
  background: linear-gradient(100deg, rgba(224, 180, 74, .32), rgba(18, 16, 28, .9) 32%,
              rgba(18, 16, 28, .9) 68%, rgba(224, 180, 74, .32));
  border-bottom: 2px solid transparent;
  border-image: linear-gradient(90deg, var(--gold-3), var(--gold-1) 30%, var(--gold-2) 60%,
                var(--gold-1) 85%, var(--gold-3)) 1;
}
.tier-pill {
  display: inline-block; margin-left: .35rem; padding: .05rem .45rem; border-radius: 999px;
  font-size: .62rem; font-weight: 800; letter-spacing: .08em; vertical-align: middle;
}
.tier-pill-silver {
  color: #1b1d24; background: linear-gradient(135deg, var(--silver-1), var(--silver-2) 60%, var(--silver-1));
  box-shadow: 0 0 8px rgba(220, 228, 245, .35);
}
.tier-pill-gold {
  color: #2a1d04; background: linear-gradient(135deg, var(--gold-1), var(--gold-2) 60%, var(--gold-1));
  box-shadow: 0 0 8px rgba(224, 180, 74, .4);
}
.btn.btn-silver {
  color: #1b1d24; background: linear-gradient(135deg, var(--silver-1), var(--silver-2) 55%, var(--silver-1));
}
.btn.btn-gold {
  color: #2a1d04; background: linear-gradient(135deg, var(--gold-1), var(--gold-2) 55%, var(--gold-1));
}
.react {
  font-size: 1.7rem; line-height: 1; padding: .45rem .55rem; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px;
  min-width: 52px; min-height: 52px;
}
.react:hover { border-color: var(--hot); }
.react-pop { animation: react-pop .28s ease-out; }
.react-wait { opacity: .4; }
@keyframes react-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.35); }
  100% { transform: scale(1); }
}

/* Over the video, never in its way: the iframe still takes every click. */
.react-sky { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 30; }
.react-fly {
  position: absolute; bottom: -2em; font-size: clamp(1.8rem, 3.4vw, 3.4rem);
  will-change: transform, opacity;
  animation-name: react-rise; animation-timing-function: ease-out;
  animation-fill-mode: forwards;
}
/* Sent with the cheer pack: about twice the size, so it is worth having. */
.react-fly.react-fly-big { font-size: clamp(3.4rem, 6.6vw, 6.4rem); z-index: 1; }
@keyframes react-rise {
  0%   { transform: translate3d(0, 0, 0) scale(.7) rotate(0deg); opacity: 0; }
  12%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { transform: translate3d(var(--drift), -78vh, 0) scale(1.25) rotate(var(--spin));
         opacity: 0; }
}

/* How the song that just finished went down. */
.react-tally {
  position: absolute; left: 50%; bottom: 12%; transform: translateX(-50%);
  display: flex; gap: 1.4rem; z-index: 4; pointer-events: none;
  padding: .7rem 1.4rem; border-radius: 999px;
  background: rgba(18, 16, 28, .82); border: 1px solid var(--line);
}
.react-tally-item { font-size: clamp(1.2rem, 2.4vw, 2.2rem); font-weight: 700; }

@media (prefers-reduced-motion: reduce) {
  .react-fly { animation-duration: .01s; opacity: 0; }
  .react-pop { animation: none; }
}

/* ------------------------------------------------------- the paid effects
   Fire, confetti and dedications wait for the gap between songs, when there
   are no lyrics on the screen to cover. Nothing plays mid-song. */
.big-stage { position: fixed; inset: 0; pointer-events: none; z-index: 40; overflow: hidden; }
.big-from {
  font-size: clamp(1rem, 1.9vw, 1.8rem); color: #fff; text-shadow: 0 2px 10px #000;
  opacity: .92; margin-top: .4rem;
}
@keyframes big-in { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; } }

.big-flame {
  position: absolute; bottom: -1vh; font-size: clamp(2rem, 4.6vw, 4.6rem);
  animation: big-lick 1.5s ease-in-out infinite alternate;
}
@keyframes big-lick {
  from { transform: translateY(0) scale(1); opacity: .85; }
  to   { transform: translateY(-2.4vh) scale(1.14); opacity: 1; }
}

.big-bit {
  position: absolute; bottom: 2vh; width: 12px; height: 18px; border-radius: 2px;
  animation: big-pop 2.6s cubic-bezier(.2,.7,.3,1) forwards;
}
@keyframes big-pop {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 1; }
  100% { transform: translate(var(--dx), var(--dy)) rotate(540deg); opacity: 0; }
}

/* A dedication plays between songs, so it may take the whole screen: the words
   in the middle, big enough to read across a bar, and the chosen emoji rising
   behind them from the bottom edge. */
.big-ded-wall {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: radial-gradient(ellipse at center, rgba(18, 16, 28, .55), rgba(10, 8, 18, .9));
  animation: big-fade .6s ease-out both;
}
.big-ded-wall.big-out { animation: big-fade-out .8s ease-in both; }
@keyframes big-fade     { from { opacity: 0; } to { opacity: 1; } }
@keyframes big-fade-out { from { opacity: 1; } to { opacity: 0; } }
.big-flood {
  position: absolute; bottom: -12vh; line-height: 1; opacity: 0;
  animation-name: big-rise; animation-timing-function: linear; animation-iteration-count: infinite;
}
@keyframes big-rise {
  0%   { transform: translate(0, 0) rotate(-8deg); opacity: 0; }
  10%  { opacity: .95; }
  85%  { opacity: .85; }
  100% { transform: translate(var(--sway), -125vh) rotate(8deg); opacity: 0; }
}
.big-ded-card {
  position: relative; z-index: 1; max-width: 80vw; text-align: center;
  padding: 2.2vw 3.4vw; border-radius: 24px;
  background: rgba(18, 16, 28, .82); border: 1px solid var(--line);
  box-shadow: 0 1.5vw 5vw rgba(0, 0, 0, .55);
  animation: big-in .7s ease-out .3s both;
}
.big-ded-text {
  color: #fff; font-weight: 800; line-height: 1.15; overflow-wrap: anywhere;
  font-size: clamp(2rem, 5.2vw, 6rem); text-shadow: 0 3px 18px #000;
}
.big-ded-card .big-from { font-size: clamp(1.1rem, 2.4vw, 2.4rem); margin-top: 1.2vw; }

/* Somebody went Gold: the same stage as a dedication, in gold. */
.big-gold-wall {
  background: radial-gradient(ellipse at center, rgba(60, 44, 6, .6), rgba(12, 9, 2, .92));
}
.big-gold-card { border: 2px solid #f5c542; box-shadow: 0 0 4vw rgba(245, 197, 66, .35), 0 1.5vw 5vw rgba(0, 0, 0, .55); }
.big-gold-kicker {
  color: #f5c542; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
  font-size: clamp(1rem, 2.2vw, 2.2rem); margin-bottom: .8vw;
}
.big-gold-name {
  background: linear-gradient(180deg, #fff3c4 0%, #f5c542 45%, #c9921a 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  text-shadow: none; filter: drop-shadow(0 3px 14px rgba(0, 0, 0, .8));
}
.big-gold-went { color: #fff; font-weight: 700; font-size: clamp(1.4rem, 3.4vw, 3.6rem); margin-top: .4vw; }
.big-gold-perks { color: #f3e3b0; font-size: clamp(.9rem, 1.7vw, 1.8rem); margin-top: 1.4vw; opacity: .9; }

/* Buying and spending, on the phone. */
.super-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.super-go { position: relative; }
.super-left {
  /* Read across a dark room on a phone: white, bold, and saying what it is. */
  display: inline-block; margin-left: .5rem; padding: .1rem .55rem; border-radius: 999px;
  background: rgba(0, 0, 0, .45); color: #fff; font-size: .95rem; font-weight: 800;
}
/* Queued: plainly not to be pressed again until it has played. */
.super-go.super-waiting { filter: grayscale(.85); opacity: .55; }
/* Between songs: nobody to send it to yet. */
.super-go.super-idle { filter: grayscale(1); opacity: .4; }
.super-idle-note { margin: 0 0 .5rem; }
.super-idle-note[hidden] { display: none; }
/* The celebrations to choose from: one compact row of five, one tap each. */
.super-row:has(.super-grid) { display: block; }
.super-sub { margin: .2rem 0 .2rem; font-size: .95rem; color: var(--ink); }
.super-count { margin: 0 0 .5rem; font-size: .9rem; color: var(--ink-dim); }
.super-count strong { color: #fff; }
.super-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .35rem; margin-bottom: .7rem; }
.btn.super-pick {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .15rem;
  width: 100%; min-width: 0; padding: .45rem .15rem; min-height: 0; border-radius: 12px;
}
.super-pick-emoji { font-size: 1.45rem; line-height: 1; }
.super-pick .super-name { font-size: .66rem; line-height: 1.1; white-space: normal; text-align: center; }
.super-notice {
  margin: .7rem 0 0; padding: .7rem .9rem; border-radius: var(--radius);
  font-weight: 700; line-height: 1.35; border: 1px solid var(--line);
}
.super-notice[hidden] { display: none; }
.super-notice-good { border-color: var(--go); background: rgba(47, 209, 138, .12); color: var(--ink); }
.super-notice-bad  { border-color: var(--danger); background: rgba(255, 93, 93, .1); color: var(--ink); }
.super-shop { display: grid; gap: .7rem; }
.super-buy { margin: 0; }
.super-buy button { width: 100%; display: flex; gap: .6rem; align-items: baseline;
                    justify-content: flex-start; }
.super-buy p { margin: .25rem 0 0; }
.super-price { font-weight: 800; }
.super-more { margin-top: .6rem; }
.super-more > summary { cursor: pointer; color: var(--ink-dim); font-size: .85rem; }
.super-ded { margin-top: .7rem; }
.super-themes { border: 0; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: .4rem; }
.super-themes legend { margin-bottom: .3rem; }
.super-theme { display: inline-flex; cursor: pointer; }
.super-theme input { position: absolute; opacity: 0; pointer-events: none; }
.super-theme span {
  padding: .35rem .7rem; border-radius: 999px; border: 1px solid var(--line); font-size: .9rem;
}
.super-theme input:checked + span { border-color: var(--hot); background: rgba(255, 61, 129, .15); }
.super-theme input:focus-visible + span { outline: 2px solid var(--hot); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .big-flame { animation: none; }
  .big-bit, .big-flood { display: none; }
}

/* The "database changes waiting" strip on admin pages: one line, one button. */
.migrate-strip { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; }

/* "You are up" with the night running itself: the one thing on the phone that
   matters for the next fifteen seconds, so it is big. */
.startnow {
  display: flex; flex-direction: column; align-items: center; gap: .4rem; text-align: center;
  margin: .6rem 0; padding: 1rem; border-radius: var(--radius);
  border: 1px solid var(--hot); background: rgba(255, 61, 129, .12);
}
.startnow[hidden] { display: none; }
.startnow strong { font-size: 1.4rem; }
.startnow .btn { width: 100%; }

/* The desk-from-a-phone QR on party settings. */
.desk-pass-row { display: flex; gap: 1.2rem; align-items: flex-start; flex-wrap: wrap; }
.desk-qr { flex: 0 0 auto; padding: .6rem; background: #fff; border-radius: 10px; line-height: 0; }
.desk-pass-row > div:last-child { flex: 1 1 16rem; }

/* The paid fire: a canvas across the whole screen, flames drawn up from the
   bottom, and who it is for on top of them. */
.big-firewall { position: absolute; inset: 0; pointer-events: none; }
.big-firewall canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.big-fire-from {
  position: absolute; left: 0; right: 0; bottom: 9vh; text-align: center;
  font-size: clamp(1.4rem, 3.2vw, 3.4rem); font-weight: 800; color: #fff;
  text-shadow: 0 2px 6px #000, 0 0 24px rgba(0, 0, 0, .8);
  animation: big-in .8s ease-out 1s both;
}

/* Admin: duplicate songs. One card per shared title, the show kept at the top. */
/* The party is over: slides that take turns. */
.now-add:disabled { opacity: .35; }
/* The four big switches at the top of a party's settings: lit when on. */
.big-switches { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .8rem; margin: 0 0 1rem; }
@media (max-width: 820px) { .big-switches { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.big-switch {
  position: relative; display: flex; flex-direction: column; gap: .3rem; cursor: pointer;
  padding: 1rem 1rem .9rem; border-radius: var(--radius); border: 1px solid var(--line); background: var(--panel);
  transition: border-color .15s ease, box-shadow .15s ease, background .15s ease;
}
.big-switch input { position: absolute; opacity: 0; pointer-events: none; }
.big-switch-icon { font-size: 1.6rem; filter: grayscale(1); opacity: .55; }
.big-switch-label { font-weight: 800; font-size: 1.05rem; color: var(--ink-dim); }
.big-switch-short { font-size: .85rem; color: var(--ink-dim); }
.big-switch-state::before { content: 'Off'; position: absolute; top: .8rem; right: .9rem; font-size: .72rem; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-dim); }
.big-switch:has(input:checked) { border-color: var(--hot); background: linear-gradient(160deg, rgba(255, 61, 129, .16), rgba(255, 138, 61, .08));
  box-shadow: 0 0 0 1px var(--hot) inset, 0 6px 24px rgba(255, 61, 129, .18); }
.big-switch:has(input:checked) .big-switch-icon { filter: none; opacity: 1; }
.big-switch:has(input:checked) .big-switch-label { color: var(--ink); }
.big-switch:has(input:checked) .big-switch-state::before { content: 'On'; color: var(--hot); }
.big-switch:has(input:focus-visible) { outline: 2px solid var(--hot-2); outline-offset: 2px; }
.tab-row { display: flex; gap: .4rem; flex-wrap: wrap; }
.badge-private { background: rgba(164, 156, 196, .16); color: var(--ink-dim); text-decoration: none; }
.badge-public { background: rgba(47, 209, 138, .16); color: var(--go); text-decoration: none; }
/* The same big cards as a pick-one: Private or Public. Lit when chosen, no On/Off tag. */
.big-choice { grid-template-columns: repeat(2, 1fr); margin-bottom: .4rem; }
@media (max-width: 520px) { .big-choice { grid-template-columns: 1fr; } }
.big-choice .big-switch-state { display: none; }
.label-like { margin: 0 0 .4rem; font-weight: 700; }
/* The questions page: one fold per question, each linkable by its id. */
.faq-jump { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; margin-top: .2rem; }
.faq-jump a { padding: .35rem .8rem; border: 1px solid var(--line); border-radius: 999px; background: var(--panel);
  color: var(--ink); text-decoration: none; font-size: .9rem; font-weight: 700; }
.faq-jump a:hover { border-color: var(--hot); }
.faq-section { scroll-margin-top: 1rem; }
.faq-q { border-top: 1px solid var(--line); scroll-margin-top: 1rem; }
.faq-q:first-of-type { border-top: 0; }
.faq-q > summary { cursor: pointer; list-style: none; padding: .8rem 2rem .8rem 0; font-weight: 700; position: relative; }
.faq-q > summary::-webkit-details-marker { display: none; }
.faq-q > summary::after { content: "+"; position: absolute; right: .2rem; top: .65rem; color: var(--hot); font-size: 1.3rem; font-weight: 800; }
.faq-q[open] > summary::after { content: "\2212"; }
.faq-q > summary:hover { color: var(--hot); }
.faq-a { padding: 0 0 .9rem; color: var(--ink-dim); }
.faq-a p, .faq-a ul { margin: 0 0 .6rem; }
.faq-a strong, .faq-a em { color: var(--ink); }
/* Setup pictures: boxes for the gear, lines for what connects them. */
.dg { width: 100%; height: auto; display: block; margin: .4rem 0 .8rem; }
.dg-dev rect { fill: var(--panel-2); stroke: var(--line); stroke-width: 1.5; }
.dg-icon { font-size: 26px; }
.dg-title { fill: var(--ink); font-size: 15px; font-weight: 800; }
.dg-sub { fill: var(--ink-dim); font-size: 12.5px; }
.dg-cloud rect { fill: rgba(196, 162, 255, .1); stroke: #c4a2ff; stroke-dasharray: 4 3; }
.dg-cloud text { fill: var(--ink); font-size: 14px; font-weight: 700; }
.dg-wire { stroke-width: 3; fill: none; }
.dg-video { stroke: var(--hot); }
.dg-sound { stroke: var(--go); }
.dg-net { stroke: #c4a2ff; stroke-width: 2; stroke-dasharray: 6 5; }
.dg-head-video { fill: var(--hot); }
.dg-head-sound { fill: var(--go); }
.dg-head-net { fill: #c4a2ff; }
.dg-label { font-size: 12px; font-weight: 700; paint-order: stroke; stroke: var(--panel); stroke-width: 5px; stroke-linejoin: round; }
.dg-label-video { fill: var(--hot); }
.dg-label-sound { fill: var(--go); }
.dg-label-net { fill: #c4a2ff; }
.dg-legend { display: flex; flex-wrap: wrap; justify-content: center; gap: .4rem 1.2rem; font-size: .9rem; color: var(--ink-dim); }
.dg-key { display: inline-block; width: 26px; height: 0; border-top: 3px solid; vertical-align: middle; margin-right: .3rem; }
.dg-key-video { border-color: var(--hot); }
.dg-key-sound { border-color: var(--go); }
.dg-key-net { border-color: #c4a2ff; border-top-style: dashed; }
.dg-need { margin: 0; padding-left: 1.2rem; }
.dg-need li { margin: .2rem 0; }
.dg-setup { scroll-margin-top: 1rem; }
.chip-locked { border-color: var(--go); color: var(--go); }
button.chip-pin { cursor: pointer; background: transparent; color: var(--ink); }
/* A closed night's desk: everything but "Reopen night" rests. */
.desk-bar .btn:disabled, .desk-head .btn.is-off { opacity: .35; filter: grayscale(.6); pointer-events: none; cursor: default; }
.desk-off button, .desk-off a.btn, .desk-off select, .desk-off input { opacity: .35; pointer-events: none; }
.last-call-note { margin: .5rem 0; }
.wrap-stage { position: fixed; inset: 0; z-index: 25; background: var(--bg); overflow: hidden; }
.wrap-slide {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 6vh 6vw; opacity: 0; transform: scale(.98);
  transition: opacity 1s ease, transform 1s ease;
}
.wrap-slide.on { opacity: 1; transform: none; }
.wrap-big { margin: .2em 0; font-size: clamp(2.4rem, 8vw, 8rem); font-weight: 800; line-height: 1.05; letter-spacing: -.02em; }
.wrap-sub { margin: .3em 0 0; font-size: clamp(1.2rem, 3.4vw, 3.2rem); color: var(--ink-dim); }
.wrap-time { margin: 0; font-size: clamp(2rem, 6vw, 6rem); font-weight: 800; color: var(--hot); line-height: 1.1; }
.wrap-note { margin: .5em 0 0; font-size: clamp(1rem, 2.2vw, 2rem); color: var(--ink-dim); }
.wrap-cheers { margin: .8em 0 0; font-size: clamp(1.4rem, 4vw, 3.8rem); font-weight: 800; color: #f5c542; }
.wrap-tiles { display: flex; gap: 4vw; margin-top: 3vh; flex-wrap: wrap; justify-content: center; }
.wrap-tile { min-width: 16vw; }
.wrap-num {
  font-size: clamp(3rem, 11vw, 11rem); font-weight: 800; line-height: 1;
  background: linear-gradient(180deg, #fff, #ff8ab8); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.wrap-label { font-size: clamp(1rem, 2.4vw, 2.4rem); color: var(--ink-dim); margin-top: .4em; }
.wrap-shouts p { margin: .5em 0; font-size: clamp(1.4rem, 4vw, 4rem); font-weight: 700; }
.wrap-dots { position: absolute; left: 0; right: 0; bottom: 4vh; display: flex; gap: .8vw; justify-content: center; }
.wrap-dot { width: 1vw; height: 1vw; min-width: 8px; min-height: 8px; border-radius: 50%; background: var(--line); }
.wrap-dot.on { background: var(--hot); }
/* The frame round the slides: the logo up top, the invitation along the
   bottom, the dots just above it. The slides keep clear of both. */
.wrap-brand { position: absolute; top: 5vh; left: 0; right: 0; display: flex; justify-content: center; z-index: 1; }
.wrap-ad {
  position: absolute; left: 0; right: 0; bottom: 4vh; margin: 0; padding: 0 4vw; z-index: 1;
  text-align: center; font-size: clamp(1rem, 2.2vw, 2.1rem); color: var(--ink-dim);
}
.wrap-ad strong {
  font-weight: 800; background: linear-gradient(90deg, var(--hot), var(--hot-2));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.wrap-slides .wrap-slide { padding: 16vh 6vw; }
.wrap-slides .wrap-dots { bottom: 11vh; }

/* A TV waiting to be paired: the code, readable from the sofa. */
.tv-code {
  font-size: clamp(3rem, 12vw, 11rem); font-weight: 800; letter-spacing: .12em; margin: 2vh 0;
  font-variant-numeric: tabular-nums; color: #fff;
}
.tv-how { display: flex; align-items: center; gap: 3vw; justify-content: center; max-width: 80vw; text-align: left; }
.tv-code-input { font-size: 1.6rem; letter-spacing: .15em; text-transform: uppercase; }
.tv-screens { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .5rem; }
.tv-list { list-style: none; padding: 0; margin: .5rem 0 0; }
.tv-list li { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; padding: .4rem 0;
              border-top: 1px solid var(--line); }

/* Badges in the moment: on the name card, on the room screen, between songs,
   and on the singer's own phone. */
.stage-earns, .room-earns {
  color: #f5c542; font-weight: 700; margin: .6em 0 0;
  font-size: clamp(1rem, 2.4vw, 2.2rem);
}
.big-badge-wall { background: radial-gradient(ellipse at center, rgba(40, 28, 70, .6), rgba(10, 8, 18, .92)); }
.big-badge-card { border: 2px solid #f5c542; }
.big-badge-name { margin-bottom: .6vw; }
.big-badge-row { margin-top: .9vw; }
.big-badge-title { color: #f5c542; font-weight: 800; font-size: clamp(1.3rem, 3.2vw, 3.4rem); }
.big-badge-line { color: #fff; font-size: clamp(1rem, 2.2vw, 2.2rem); opacity: .9; }
.badge-toast {
  position: fixed; left: 50%; bottom: 1rem; transform: translateX(-50%); z-index: 100;
  width: min(92vw, 420px); padding: .9rem 1.1rem; border-radius: 16px;
  background: var(--panel-2); border: 2px solid #f5c542; box-shadow: 0 10px 30px rgba(0, 0, 0, .5);
  animation: badge-toast-in .35s ease-out both;
}
.badge-toast strong { color: #f5c542; display: block; margin-bottom: .25rem; }
.badge-toast-row { font-weight: 600; margin: .15rem 0; }
.badge-toast a { display: inline-block; margin-top: .4rem; }
.badge-toast-out { animation: badge-toast-out .6s ease-in both; }
@keyframes badge-toast-in  { from { opacity: 0; transform: translate(-50%, 20px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes badge-toast-out { from { opacity: 1; } to { opacity: 0; transform: translate(-50%, 20px); } }
a.q-name { color: inherit; text-decoration: none; border-bottom: 1px dotted var(--ink-dim); }

/* Quick picks at the top of the song search: go-to songs and artists. */
.picks-head { font-size: .85rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-dim); margin: .2rem 0 .4rem; }
.pick-list { list-style: none; margin: 0 0 .9rem; padding: 0; }
.pick { display: flex; align-items: center; justify-content: space-between; gap: .75rem;
        padding: .55rem 0; border-bottom: 1px solid var(--line); }
.pick:last-child { border-bottom: 0; }
.pick-what { min-width: 0; }
.pick-sung .pick-what strong { opacity: .7; }
.pick-warn { color: var(--warn); }
.pick-artists { display: flex; flex-wrap: wrap; gap: .4rem; margin: 0 0 .9rem; }
.pick-more { margin: -.5rem 0 .9rem; }
.picks-save { margin: -.4rem 0 .9rem; color: var(--ink-dim); }

/* Gold, called up: the name in gold, with their emoji and title. */
#player-card.card-gold { background: radial-gradient(1100px 600px at 50% 40%, rgba(224, 180, 74, .22), transparent 70%); }
#player-card.card-gold .stage-singer {
  background: linear-gradient(100deg, #d9a33a 0%, #ffd66b 22%, #fff6d6 42%, #ffd66b 62%, #d9a33a 82%, #ffd66b 100%);
  background-size: 250% 100%; -webkit-background-clip: text; background-clip: text; color: transparent;
  animation: gold-shine 3.2s linear infinite; filter: drop-shadow(0 4px 24px rgba(224, 180, 74, .35));
}
@keyframes gold-shine { to { background-position: -250% 0; } }
.stage-walkup { margin: 0; font-size: clamp(4rem, 12vw, 10rem); line-height: 1; animation: walkup-pop .8s cubic-bezier(.2, 1.6, .4, 1) both; }
.stage-walkup-title { margin: .1em 0 .2em; font-size: clamp(1.4rem, 3.6vw, 3.2rem); font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: #e0b44a; animation: walkup-pop .8s .25s cubic-bezier(.2, 1.6, .4, 1) both; }
@keyframes walkup-pop { from { opacity: 0; transform: scale(.4); } to { opacity: 1; transform: none; } }

/* The account page's walk-up picker. */
.walkup-emojis { display: flex; flex-wrap: wrap; gap: .35rem; border: 0; padding: 0; margin: 0; }
.walkup-emojis legend { font-weight: 700; margin-bottom: .4rem; }
.walkup-emoji input { position: absolute; opacity: 0; pointer-events: none; }
.walkup-emoji span { display: grid; place-items: center; min-width: 2.8rem; height: 2.8rem; padding: 0 .5rem; font-size: 1.5rem;
  border: 2px solid var(--line); border-radius: .8rem; background: var(--panel-2); cursor: pointer; }
.walkup-emoji span:not(:only-child) { font-size: .85rem; }
.walkup-emoji input:checked + span { border-color: #e0b44a; background: rgba(224, 180, 74, .18); }
.walkup-emoji input:focus-visible + span { outline: 2px solid var(--hot-2); }
.walkup-sound-row { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.pick-more > summary { cursor: pointer; list-style: none; color: var(--hot); font-weight: 700; font-size: .92rem; padding: .3rem 0; }
.pick-more > summary::-webkit-details-marker { display: none; }
.pick-more > summary::after { content: " +"; }
.pick-more[open] > summary::after { content: " \2212"; }
.pick-more[open] > summary { margin-bottom: .4rem; }
.pick-more .pick-list { margin-bottom: 0; }

.dupes-group { border-top: 1px solid var(--line); padding: 1rem 0 .6rem; }
.dupes-group h3 { margin: 0 0 .4rem; display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.dupes-target { margin: 0 0 .5rem; }
.dupes-others { list-style: none; margin: 0 0 .6rem; padding: 0; }
.dupes-others li {
  display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .5rem 0 .5rem 1rem; border-left: 2px solid var(--line);
}
.dupes-likely .dupes-others li { border-left-color: #f5c542; }
.pill { display: inline-block; font-size: .75rem; font-weight: 700; padding: .1rem .55rem; border-radius: 999px;
        border: 1px solid var(--line); }
.pill-likely { color: #1a1406; background: #f5c542; border-color: #f5c542; }

/* ---------------------------------------------------------------- the kids tablet
   Bright tiles (the palette's light colour as the fill, its dark one as the
   words), targets a small hand cannot miss, and nothing to select or drag. */
.kiosk {
  height: 100dvh; display: flex; flex-direction: column; gap: 1rem; padding: 1rem 1rem 1.2rem;
  background: radial-gradient(circle at 20% 0%, #2a2160, #12101c 70%); color: var(--ink);
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; touch-action: manipulation;
  overflow: hidden; font-size: clamp(16px, 2.2vw, 22px);
}
.kiosk.is-busy { opacity: .6; pointer-events: none; }
:where(.kiosk) button { font: inherit; color: inherit; border: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }
.kiosk-bar { display: flex; align-items: center; gap: .8rem; min-height: 4.2rem; }
.kiosk-title { flex: 1; margin: 0; font-size: clamp(1.6rem, 4.5vw, 2.8rem); font-weight: 900; letter-spacing: -.01em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kiosk-back, .kiosk-home { width: 4.2rem; height: 4.2rem; border-radius: 50%; background: var(--panel-2);
  font-size: 2rem; display: grid; place-items: center; flex: none; }
.kiosk-back:active, .kiosk-home:active { transform: scale(.94); }
.kiosk-paged-outer { flex: 1; display: flex; flex-direction: column; gap: .6rem; min-height: 0; }
.kiosk-paged { flex: 1; display: flex; align-items: stretch; gap: .8rem; min-height: 0; }
.kiosk-arrow { width: clamp(3.6rem, 8vw, 5.5rem); border-radius: 1.4rem; background: var(--panel-2);
  font-size: clamp(2rem, 5vw, 3rem); display: grid; place-items: center; flex: none; }
.kiosk-arrow.is-off { visibility: hidden; }
.kiosk-arrow:active { transform: scale(.94); background: var(--hot); }
.kiosk-dots { display: flex; justify-content: center; gap: .5rem; }
.kiosk-dots span { width: .8rem; height: .8rem; border-radius: 50%; background: var(--line); }
.kiosk-dots span.on { background: var(--hot); }
.kiosk-grid { flex: 1; display: grid; gap: clamp(.6rem, 1.6vw, 1.2rem); min-height: 0; }
.kiosk-grid-shows { grid-template-columns: repeat(3, 1fr); grid-auto-rows: 1fr; }
.kiosk-grid-songs { grid-template-columns: repeat(2, 1fr); grid-auto-rows: 1fr; }
.kiosk-grid-faces { grid-template-columns: repeat(4, 1fr); grid-auto-rows: 1fr; }
@media (orientation: portrait) {
  .kiosk-grid-shows { grid-template-columns: repeat(2, 1fr); }
  .kiosk-grid-songs { grid-template-columns: 1fr; }
  .kiosk-grid-faces { grid-template-columns: repeat(2, 1fr); }
}
.kiosk-tile, .kiosk-song, .kiosk-face {
  background: var(--tile-ink, #a49cc4); color: var(--tile-bg, #1b1830); border-radius: 1.6rem;
  box-shadow: 0 .5rem 0 rgba(0, 0, 0, .28); min-height: 0; overflow: hidden;
}
.kiosk-tile, .kiosk-face { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .3rem; padding: .6rem; position: relative; text-align: center; }
.kiosk-tile:active, .kiosk-face:active, .kiosk-song-pick:active { transform: translateY(.3rem); box-shadow: 0 .2rem 0 rgba(0, 0, 0, .28); }
.kiosk-tile-emoji { font-size: clamp(3rem, 9vw, 6rem); line-height: 1; }
.kiosk-tile-name { font-weight: 900; font-size: clamp(1rem, 2.4vw, 1.5rem); line-height: 1.15;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.kiosk-song { display: flex; flex-direction: column; }
.kiosk-song-pick { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .3rem;
  padding: .8rem; background: transparent; color: inherit !important; text-align: center; min-height: 0; }
.kiosk-song-emoji { font-size: clamp(2.2rem, 6vw, 3.6rem); line-height: 1; }
.kiosk-song-title { font-weight: 900; font-size: clamp(1.15rem, 3vw, 1.9rem); line-height: 1.15;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.kiosk-song-go { font-weight: 800; font-size: .9em; background: rgba(0, 0, 0, .14); padding: .25rem .9rem; border-radius: 99px; }
.kiosk-listen { background: rgba(0, 0, 0, .22) !important; color: #fff !important; font-weight: 800; padding: .8rem;
  font-size: 1.1em; }
.kiosk-listen:active { background: rgba(0, 0, 0, .4) !important; }
.kiosk-picked { margin: -.4rem 0 0; font-size: 1.2em; font-weight: 800; color: var(--ink-dim); }
.kiosk-face-emoji { font-size: clamp(3rem, 8vw, 5rem); line-height: 1; }
.kiosk-face-name { font-weight: 900; font-size: clamp(1.1rem, 2.8vw, 1.7rem); }
.kiosk-face-count { position: absolute; top: .6rem; right: .7rem; background: rgba(0, 0, 0, .2); border-radius: 99px;
  padding: .1rem .55rem; font-weight: 800; font-size: .85em; }
.kiosk-add { background: var(--panel-2); color: var(--ink); border: 3px dashed var(--line); box-shadow: none; }
.kiosk-add-hint { font-size: .8em; color: var(--ink-dim); }
.kiosk-add-ring { position: absolute; inset: 0; border-radius: inherit; background: var(--hot); opacity: .35;
  transform: scaleX(0); transform-origin: left; pointer-events: none; }
.kiosk-add.is-holding .kiosk-add-ring { transform: scaleX(1); transition: transform 2s linear; }
.kiosk-add.is-nudged { animation: kiosk-shake .5s; }
@keyframes kiosk-shake { 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.kiosk-done { flex: 1; position: relative; overflow: hidden; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: .6rem; text-align: center; border-radius: 2rem; padding: 1.5rem;
  background: var(--tile-ink, #a49cc4) !important; color: var(--tile-bg, #1b1830) !important; }
.kiosk-done-burst { font-size: clamp(3rem, 8vw, 5rem); line-height: 1; }
.kiosk-done-face { font-size: clamp(6rem, 18vw, 11rem); line-height: 1; animation: kiosk-bounce 1s ease-in-out infinite; }
.kiosk-done-head { font-size: clamp(2.2rem, 6vw, 4rem); font-weight: 900; }
.kiosk-done-sub { font-size: clamp(1.1rem, 2.6vw, 1.6rem); font-weight: 700; max-width: 32ch; }
.kiosk-oops .kiosk-done-face { animation: none; }
@keyframes kiosk-bounce { 50% { transform: translateY(-.6rem) scale(1.05); } }
.kiosk-confetti { position: absolute; top: -3rem; font-size: 2.2rem; animation: kiosk-fall linear forwards; pointer-events: none; }
@keyframes kiosk-fall { to { transform: translateY(110vh) rotate(540deg); } }
.kiosk-msg { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: .4rem; }
.kiosk-msg-icon { font-size: clamp(5rem, 14vw, 8rem); line-height: 1; }
.kiosk-msg h2 { margin: 0; font-size: clamp(1.8rem, 5vw, 3rem); font-weight: 900; }
.kiosk-msg p { margin: 0; color: var(--ink-dim); font-size: 1.2em; }
.kiosk-shade { position: fixed; inset: 0; z-index: 60; background: rgba(5, 4, 10, .75); display: grid; place-items: center; padding: 1rem; }
.kiosk-form { background: var(--panel); border: 1px solid var(--line); border-radius: 1.4rem; padding: 1.4rem;
  width: min(30rem, 100%); display: flex; flex-direction: column; gap: .7rem; font-size: 1.15rem; }
.kiosk-form h2 { margin: 0; }
.kiosk-form-note { margin: 0; color: var(--ink-dim); font-size: .9em; }
.kiosk-form input { font-size: 1.5rem; padding: .7rem .9rem; border-radius: .8rem; }
.kiosk-form-err { margin: 0; color: var(--danger); min-height: 1.2em; font-size: .9em; }
.kiosk-form-row { display: flex; gap: .7rem; justify-content: flex-end; }
.kiosk-btn { font: inherit; font-weight: 800; padding: .8rem 1.6rem; border-radius: .9rem; border: 0; background: var(--hot); color: #fff; }
.kiosk-btn-ghost { background: var(--panel-2); color: var(--ink); }
body.bare .preview-bar { font-size: 1.1rem; }

/* ---------------------------------------------------------------- setting up the room
   A big box with big answers: four questions, then the plan as numbered steps. */
.setup {
  width: min(46rem, calc(100vw - 1.5rem)); max-height: calc(100dvh - 1.5rem); padding: 0;
  border: 1px solid var(--line); border-radius: 1.2rem; background: var(--panel); color: var(--ink);
  box-shadow: 0 20px 80px rgba(0, 0, 0, .6); overflow: hidden;
}
.setup[open] { display: flex; flex-direction: column; }
.setup::backdrop { background: rgba(5, 4, 10, .78); backdrop-filter: blur(3px); }
.setup-top { display: flex; align-items: center; justify-content: space-between; padding: .8rem 1rem 0 1.4rem; }
.setup-dots { display: flex; gap: .4rem; }
.setup-dots span { width: .6rem; height: .6rem; border-radius: 50%; background: var(--line); }
.setup-dots span.done { background: var(--hot-2); }
.setup-dots span.on { background: var(--hot); width: 1.4rem; border-radius: 99px; }
.setup-x { background: none; border: 0; color: var(--ink-dim); font-size: 2rem; line-height: 1; cursor: pointer; padding: .2rem .5rem; }
.setup-x:hover { color: var(--ink); }
.setup-body { padding: .4rem 1.4rem 1.4rem; overflow-y: auto; }
.setup .setup-title { margin: .2rem 0 .3rem; font-size: clamp(1.4rem, 4vw, 1.9rem); text-transform: none; letter-spacing: normal; color: var(--ink); }
.setup-x:focus:not(:focus-visible) { outline: none; }
.setup-sub { margin: 0 0 1rem; color: var(--ink-dim); }
.setup-options { display: grid; gap: .7rem; }
.setup-option {
  display: flex; align-items: center; gap: 1rem; width: 100%; text-align: left; cursor: pointer;
  padding: 1rem 1.1rem; border-radius: 1rem; border: 2px solid var(--line); background: var(--panel-2);
  color: var(--ink); font: inherit; transition: border-color .12s ease, transform .12s ease;
}
.setup-option:hover, .setup-option:focus-visible { border-color: var(--hot); outline: none; }
.setup-option:active { transform: scale(.99); }
.setup-option.is-chosen { border-color: var(--hot); background: linear-gradient(160deg, rgba(255, 61, 129, .16), rgba(255, 138, 61, .06)); }
.setup-option-icon { font-size: 2.2rem; line-height: 1; flex: none; width: 2.8rem; text-align: center; }
.setup-option-words { display: flex; flex-direction: column; gap: .15rem; }
.setup-option-words strong { font-size: 1.15rem; }
.setup-option-note { color: var(--ink-dim); font-size: .9rem; }
.setup-nav { display: flex; justify-content: space-between; align-items: center; margin-top: 1.2rem; gap: 1rem; }
.setup-skip { color: var(--ink-dim); font-size: .9rem; }
.setup-steps { list-style: none; counter-reset: step; margin: 0; padding: 0; display: grid; gap: .8rem; }
.setup-step { counter-increment: step; display: flex; gap: 1rem; padding: 1rem; border-radius: 1rem;
  background: var(--panel-2); border: 1px solid var(--line); }
.setup-step-icon { font-size: 1.8rem; line-height: 1; flex: none; width: 2.6rem; text-align: center; position: relative; }
.setup-step-icon::after { content: counter(step); position: absolute; left: -.3rem; top: 1.6rem; width: 1.4rem; height: 1.4rem;
  border-radius: 50%; background: var(--hot); color: #fff; font-size: .8rem; font-weight: 800; display: grid; place-items: center; }
.setup-step-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .5rem; align-items: flex-start; }
.setup-step-main h3 { margin: 0; font-size: 1.1rem; }
.setup-step-main p { margin: 0; }
.setup-hint { color: var(--ink-dim); font-size: .9rem; }
.setup-qr { background: #fff; padding: .5rem; border-radius: 10px; line-height: 0; }
.setup-pair { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.setup-pair input { width: 9rem; font-size: 1.3rem; letter-spacing: .12em; text-transform: uppercase; padding: .5rem .7rem; }
.setup-pair-said { flex-basis: 100%; margin: 0; font-size: .9rem; color: var(--ink-dim); min-height: 1.1em; }
.setup-pair-said.is-ok { color: var(--go); font-weight: 700; }
.setup-pair-said.is-err { color: var(--danger); }
@media (max-width: 560px) {
  .setup-body { padding: .4rem 1rem 1rem; }
  .setup-step { flex-direction: column; gap: .5rem; }
  .setup-step-icon { text-align: left; }
  .setup-step-icon::after { left: 2rem; top: .2rem; }
}

/* The desk saying, loudly, that nothing can play: no singer screen is open. */
.no-screen { border: 2px solid var(--warn); background: linear-gradient(160deg, rgba(255, 190, 77, .14), rgba(255, 190, 77, .03)); }
.no-screen h2 { color: var(--warn); }
.no-screen p { margin: .3rem 0 .8rem; max-width: 60ch; }
.no-screen-row { display: flex; gap: .6rem; flex-wrap: wrap; }
