/* ---------- Tokens ---------- */

:root {
  color-scheme: light dark;

  --font: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --bg: #f2f2f7;
  --surface: #ffffff;
  --fill: rgba(120, 120, 128, 0.12);
  --fill-strong: rgba(120, 120, 128, 0.2);
  --segment-active: #ffffff;
  --text: #1d1d1f;
  --text-secondary: #6e6e73;
  --separator: rgba(60, 60, 67, 0.14);
  --glass: rgba(242, 242, 247, 0.82);
  --floating: rgba(255, 255, 255, 0.86);
  --floating-shadow: 0 0.5rem 1.875rem rgba(0, 0, 0, 0.16);
  /* Grouped lists (Room Settings, Song Info): the sheet, and the cards on it. */
  --grouped-bg: #f2f2f7;
  --grouped-cell: #ffffff;

  --accent: #fa2d48;
  --accent-hover: #e8203b;
  --on-accent: #ffffff;

  --radius-xs: 0.25rem;
  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.625rem;

  --gutter: 1rem;
  --ease: cubic-bezier(0.25, 0.1, 0.25, 1);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000000;
    --surface: #1c1c1e;
    --fill: rgba(118, 118, 128, 0.24);
    --fill-strong: rgba(118, 118, 128, 0.36);
    --segment-active: #636366;
    --text: #f5f5f7;
    --text-secondary: #98989d;
    --separator: rgba(84, 84, 88, 0.55);
    --glass: rgba(0, 0, 0, 0.78);
    --floating: rgba(44, 44, 46, 0.88);
    --floating-shadow: 0 0.5rem 1.875rem rgba(0, 0, 0, 0.5);
    --grouped-bg: #1c1c1e;
    --grouped-cell: #2c2c2e;
  }
}

/* The host screen is always dark — it's meant for a projector or TV. */
.theme-dark {
  color-scheme: dark;
  --bg: #000000;
  --surface: #121213;
  --fill: rgba(118, 118, 128, 0.24);
  --fill-strong: rgba(118, 118, 128, 0.36);
  --segment-active: #636366;
  --text: #f5f5f7;
  --text-secondary: #8e8e93;
  --separator: rgba(84, 84, 88, 0.5);
  --glass: rgba(18, 18, 19, 0.85);
  --floating: rgba(44, 44, 46, 0.88);
  --floating-shadow: 0 0.5rem 1.875rem rgba(0, 0, 0, 0.5);
  --grouped-bg: #1c1c1e;
  --grouped-cell: #2c2c2e;
}

/* ---------- Base ---------- */

/* Sizes are in rem. Guests use the browser's 16px; the host view grows with the display (it's often a TV). */
.scale-with-screen {
  font-size: clamp(16px, 1vw, 32px);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 1.0625rem;
  line-height: 1.4;
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
}

h1,
h2,
h3,
p {
  margin: 0;
}

button,
input {
  font: inherit;
  color: inherit;
}

button {
  -webkit-user-select: none;
  user-select: none;
}

img {
  display: block;
}

[hidden] {
  display: none !important;
}

:focus-visible {
  outline: 0.125rem solid color-mix(in srgb, var(--accent) 60%, transparent);
  outline-offset: 0.125rem;
}

/* ---------- Typography ---------- */

.eyebrow {
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.error-text {
  font-size: 0.9375rem;
  color: var(--accent);
  text-align: center;
}

/* ---------- Buttons ---------- */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  height: 2.75rem;
  padding: 0 1.25rem;
  border: 0;
  border-radius: var(--radius-md);
  font-size: 1.0625rem;
  font-weight: 500;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s var(--ease), transform 0.15s var(--ease), opacity 0.2s var(--ease);
}

.button:active:not(:disabled) {
  transform: scale(0.98);
}

.button:disabled {
  opacity: 0.5;
  cursor: default;
}

.button-primary {
  background: var(--accent);
  color: var(--on-accent);
}

.button-primary:hover:not(:disabled) {
  background: var(--accent-hover);
}

.button-secondary {
  background: var(--fill);
  color: var(--text);
}

.button-secondary:hover:not(:disabled) {
  background: var(--fill-strong);
}

.button-large {
  height: 3.125rem;
  padding: 0 1.75rem;
}

.button-block {
  width: 100%;
}

.icon-button {
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 2.125rem;
  height: 2.125rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: var(--fill);
  color: var(--text);
  cursor: pointer;
  transition: background-color 0.2s var(--ease), color 0.2s var(--ease), transform 0.15s var(--ease);
}

.icon-button:hover:not(:disabled) {
  background: var(--fill-strong);
}

.icon-button:active:not(:disabled) {
  transform: scale(0.94);
}

.icon-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.icon-button svg {
  width: 1.125rem;
  height: 1.125rem;
}

.icon-button-plain {
  background: transparent;
  color: var(--text-secondary);
}

/* The everyday button: Settings, Leave, Home, Skip, Add a song. Filled, never just text.
   Add .is-destructive for ones that take you out (Leave). */
.pill-button {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  gap: 0.375rem;
  height: 2.25rem;
  padding: 0 0.875rem;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--fill);
  color: var(--text);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s var(--ease), transform 0.15s var(--ease);
}

.pill-button:hover {
  background: var(--fill-strong);
}

.pill-button:active {
  transform: scale(0.97);
}

/* Icons sit on the text's center line, not its baseline (which would push them up). */
.pill-button [data-icon] {
  display: grid;
  place-items: center;
}

.pill-button svg {
  display: block;
  width: 1rem;
  height: 1rem;
}

.pill-button.is-destructive {
  color: var(--accent);
}

/* ---------- Inputs ---------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}

.field-label {
  padding-left: 0.125rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.input {
  width: 100%;
  height: 3rem;
  padding: 0 0.875rem;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--fill);
  font-size: 1.0625rem;
  outline: none;
  transition: box-shadow 0.2s var(--ease);
}

.input::placeholder {
  color: var(--text-secondary);
}

.input:focus {
  box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--accent) 50%, transparent);
}

.input-code {
  font-weight: 600;
  letter-spacing: 0.3em;
  text-transform: uppercase;
}

.input-code::placeholder {
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
}

/* ---------- Tabs ---------- */

.tabs {
  position: sticky;
  top: 0;
  z-index: 10;
  padding: 0.625rem var(--gutter);
  background: var(--glass);
  border-bottom: 0.0625rem solid var(--separator);
  -webkit-backdrop-filter: saturate(180%) blur(1.25rem);
  backdrop-filter: saturate(180%) blur(1.25rem);
}

.segmented {
  display: grid;
  grid-auto-columns: 1fr;
  grid-auto-flow: column;
  padding: 0.125rem;
  border-radius: var(--radius-md);
  background: var(--fill);
}

.segment {
  height: 1.875rem;
  padding: 0 0.375rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  font-size: 0.875rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.segment.is-active {
  background: var(--segment-active);
  box-shadow: 0 0.125rem 0.375rem rgba(0, 0, 0, 0.12), 0 0.0625rem 0.0625rem rgba(0, 0, 0, 0.04);
  font-weight: 600;
}

.segment-count {
  margin-left: 0.25rem;
  color: var(--text-secondary);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.segment-count:empty {
  display: none;
}

/* With "Record songs" on, Clips is a fourth tab. Four labels don't fit in equal widths at this
   size, so each tab is its label plus an equal share of the space left over: the gaps between
   the labels stay even, at the same size, in the same space. */
.segmented:has(> [data-tab="clips"]:not([hidden])) {
  display: flex;
}

.segmented:has(> [data-tab="clips"]:not([hidden])) .segment {
  flex: 1 1 auto;
  padding: 0 0.125rem;
}

/* ---------- Lists ---------- */

.list {
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--surface);
}

.list:empty {
  display: none;
}

.row {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3.75rem;
  padding: 0.5rem var(--gutter);
}

.row + .row::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: var(--separator-inset, 6.25rem);
  height: 0.0625rem;
  background: var(--separator);
}

.row-art {
  flex: none;
  width: 4.5rem;
  height: 2.5rem;
  border-radius: var(--radius-xs);
  object-fit: cover;
  background: var(--fill);
}

.row-text {
  flex: 1;
  min-width: 0;
}

.row-title {
  display: -webkit-box;
  overflow: hidden;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.3;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.row-meta {
  margin-top: 0.125rem;
  overflow: hidden;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.row-actions {
  display: flex;
  gap: 0.25rem;
}

/* Row controls (queue and people) with a mouse: a small panel over the end of the row when you point at it. */
@media (hover: hover) and (pointer: fine) {
  .controls-list .row-actions {
    position: absolute;
    top: 50%;
    right: 0.5rem;
    gap: 0.125rem;
    padding: 0.1875rem;
    border: 0.0625rem solid var(--separator);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--surface), #ffffff 7%);
    box-shadow: -1rem 0 1rem var(--surface), 0 0.25rem 0.875rem rgba(0, 0, 0, 0.3);
    opacity: 0;
    transform: translateY(-50%);
    pointer-events: none;
    transition: opacity 0.15s var(--ease);
  }

  .controls-list .row:hover .row-actions,
  .controls-list .row:focus-within .row-actions,
  .controls-list .row.is-dragging .row-actions {
    opacity: 1;
    pointer-events: auto;
  }

  .controls-list .row-actions .icon-button,
  .controls-list .row-actions .drag-handle {
    width: 2rem;
    height: 2rem;
    color: var(--text);
  }

  .controls-list .row-actions .icon-button:hover {
    background: var(--fill);
  }

  .controls-list .row-actions [data-action="remove"]:hover,
  .controls-list .row-actions [data-action="ban"]:hover {
    color: #ff453a;
  }

  .controls-list .row-actions svg {
    width: 1rem;
    height: 1rem;
  }

  .controls-list [data-action="menu"] {
    display: none;
  }
}

/* Row controls on touch screens (phones, iPads): the ⋯ menu, plus the host's drag handle. */
@media not ((hover: hover) and (pointer: fine)) {
  .controls-list .row-actions > button:not([data-action="menu"]) {
    display: none;
  }
}

/* The host drags a queue row by this handle. It doesn't scroll the page while held. */
.drag-handle {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.125rem;
  height: 2.125rem;
  color: var(--text-secondary);
  cursor: grab;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
}

.drag-handle svg {
  width: 1.125rem;
  height: 1.125rem;
}

.row.is-dragging {
  z-index: 2;
  border-radius: var(--radius-md);
  background: var(--surface);
  box-shadow: var(--floating-shadow);
  cursor: grabbing;
}

.row.is-dragging::before,
.row.is-dragging + .row::before {
  display: none;
}

.row-mine .row-meta {
  color: var(--accent);
}

.queue-position {
  flex: none;
  width: 1.125rem;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--text-secondary);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.add-button {
  color: var(--accent);
}

.add-button.is-added {
  background: var(--accent);
  color: var(--on-accent);
}

.queue-list {
  --separator-inset: 8.125rem;
}

.people-list {
  --separator-inset: 4.25rem;
}

/* The host's Banned button at the end of People, and the list it opens. */
.banned-footer {
  display: flex;
  justify-content: center;
  padding: 1rem var(--gutter);
}

.banned-count {
  margin-left: 0.125rem;
  color: var(--text-secondary);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.banned-sheet .list {
  max-height: 50dvh;
  overflow-y: auto;
  background: transparent;
}

.banned-row .avatar {
  opacity: 0.5;
}

.banned-row .pill-button {
  height: 2rem;
}

.avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--avatar-color, var(--fill-strong));
  color: #ffffff;
  font-size: 1.0625rem;
  font-weight: 600;
  overflow: hidden;
}

.avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-large {
  width: 3.5rem;
  height: 3.5rem;
  font-size: 1.5rem;
}

.avatar-picker {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(2.75rem, 1fr));
  gap: 0.625rem;
  padding: 0.25rem 0.125rem;
}

.avatar-option {
  display: grid;
  place-items: center;
  width: 100%;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--fill);
  color: var(--text-secondary);
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow 0.15s var(--ease), transform 0.15s var(--ease);
}

.avatar-option:active {
  transform: scale(0.94);
}

.avatar-option img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.avatar-option svg {
  width: 1.25rem;
  height: 1.25rem;
}

/* The letter avatar choice fills its circle like the pictures do. */
.avatar-option .avatar {
  width: 100%;
  height: 100%;
}

.avatar svg {
  width: 55%;
  height: 55%;
}

.avatar-option.is-selected {
  box-shadow: 0 0 0 0.125rem var(--bg), 0 0 0 0.25rem var(--accent);
}

.empty {
  padding: 3rem 1.5rem;
  color: var(--text-secondary);
  text-align: center;
}

.empty .pill-button {
  margin-top: 0.875rem;
}

/* ---------- Search ---------- */

.search-controls {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.5rem 0.5rem 0.5rem var(--gutter);
}

.search-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  height: 2.375rem;
  padding: 0 0.625rem;
  border-radius: var(--radius-md);
  background: var(--fill);
  color: var(--text-secondary);
}

.search-bar svg {
  flex: none;
  width: 1.0625rem;
  height: 1.0625rem;
}

.search-bar input {
  flex: 1;
  min-width: 0;
  height: 100%;
  border: 0;
  background: none;
  font-size: 1.0625rem;
  color: var(--text);
  outline: none;
}

.search-bar input::placeholder {
  color: var(--text-secondary);
}

.hint {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.hint:empty {
  display: none;
}

.spinner {
  width: 1.375rem;
  height: 1.375rem;
  margin: 2rem auto;
  border: 0.1562rem solid var(--fill-strong);
  border-top-color: var(--text-secondary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/* ---------- Host crown ---------- */

.avatar-slot {
  position: relative;
  flex: none;
  display: inline-flex;
}

.crown {
  position: absolute;
  right: -0.1875rem;
  bottom: -0.1875rem;
  display: grid;
  place-items: center;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 50%;
  background: #ffd60a;
  color: #6b4f00;
  box-shadow: 0 0 0 0.125rem var(--surface);
}

.crown svg {
  width: 0.6875rem;
  height: 0.6875rem;
}

.host-line {
  overflow: hidden;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.host-line.is-away {
  color: var(--accent);
}

/* ---------- Banner ---------- */

.banner {
  position: fixed;
  top: calc(0.5rem + env(safe-area-inset-top));
  left: 50%;
  z-index: 60;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: min(25rem, calc(100% - 1rem));
  padding: 0.625rem 0.5rem 0.625rem 0.625rem;
  border-radius: 0.875rem;
  background: var(--floating);
  box-shadow: var(--floating-shadow);
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, calc(-100% - 1rem));
  transition: transform 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.1), opacity 0.3s var(--ease);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  backdrop-filter: saturate(180%) blur(24px);
}

.banner.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* The picture on the left: a person, an icon, or a spinner while something is in progress. */
.banner-media {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
}

.banner-media .avatar {
  width: 100%;
  height: 100%;
  font-size: 0.9375rem;
}

.banner-media.is-icon {
  background: var(--fill-strong);
  color: var(--text);
}

.banner-media.is-check {
  background: #30d158;
  color: #ffffff;
}

.banner-media.is-alert {
  background: #ff9f0a;
  color: #ffffff;
}

.banner-media svg {
  width: 1.25rem;
  height: 1.25rem;
}

.banner-media.is-loading {
  border: 0.1875rem solid var(--fill-strong);
  border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}

.banner-text {
  flex: 1;
  min-width: 0;
}

/* The banner lets taps pass through to the page; only its × can be tapped. */
.banner-close {
  display: grid;
  place-items: center;
  flex: none;
  width: 1.75rem;
  height: 1.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--fill);
  color: var(--text-secondary);
  cursor: pointer;
}

.banner.is-visible .banner-close {
  pointer-events: auto;
}

.banner-close svg {
  width: 0.875rem;
  height: 0.875rem;
}

/* Long titles (a long song name, say) wrap instead of being cut off, up to three lines. */
.banner-title {
  display: -webkit-box;
  overflow: hidden;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}

.banner-subtitle {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  line-height: 1.3;
}

.banner-subtitle:empty {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  .banner {
    transition: opacity 0.2s linear;
  }
}

/* ---------- Action sheet ---------- */

.sheet {
  width: min(100% - 1rem, 26rem);
  max-width: none;
  margin: auto auto calc(0.5rem + env(safe-area-inset-bottom));
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text);
}

.sheet[open] {
  animation: sheet-in 0.3s cubic-bezier(0.2, 0.9, 0.3, 1);
}

.sheet::backdrop {
  background: rgba(0, 0, 0, 0.35);
}

@keyframes sheet-in {
  from {
    transform: translateY(100%);
  }
}

.sheet-card,
.sheet-cancel {
  border-radius: 0.875rem;
  background: var(--floating);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  backdrop-filter: saturate(180%) blur(24px);
}

.sheet-card {
  overflow: hidden;
}

.sheet-header {
  padding: 1rem 1rem 0.875rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  text-align: center;
}

.sheet-body {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 0 1rem 1rem;
  text-align: left;
}

.sheet-title {
  margin-bottom: 0.25rem;
  font-weight: 600;
}

.sheet-action {
  display: block;
  width: 100%;
  padding: 1rem;
  border: 0;
  border-top: 0.0625rem solid var(--separator);
  background: transparent;
  color: var(--accent);
  font-size: 1.0625rem;
  cursor: pointer;
}

.sheet-action:active {
  background: var(--fill);
}

.sheet-action.is-destructive {
  color: #ff3b30;
}

.sheet .sheet-cancel {
  margin-top: 0.5rem;
  border-top: 0;
  background: var(--floating);
  font-weight: 600;
}

/* On wide screens the sheet sits in the middle like a dialog. */
@media (min-width: 760px) {
  .sheet {
    margin: auto;
  }
}

/* ---------- Landing screens (home, join, host start) ---------- */

.landing > .home-button {
  position: absolute;
  top: calc(0.5rem + env(safe-area-inset-top));
  left: 0.5rem;
}

.landing {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2.25rem;
  min-height: 100dvh;
  padding: 2.5rem 1.5rem calc(2.5rem + env(safe-area-inset-bottom));
  text-align: center;
}

.brand {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.app-icon {
  width: 5rem;
  height: 5rem;
  filter: drop-shadow(0 0.5rem 1.25rem rgba(250, 45, 72, 0.28));
}

.brand h1 {
  margin-top: 1.375rem;
  font-size: clamp(2.5rem, 9vw, 4rem);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.035em;
}

.tagline {
  margin-top: 0.625rem;
  font-size: clamp(1.1875rem, 3vw, 1.5rem);
  color: var(--text-secondary);
  letter-spacing: -0.015em;
}

.stack {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 100%;
  max-width: 22.5rem;
}

.stack-form {
  text-align: left;
}

.join-inline {
  display: flex;
  gap: 0.5rem;
}

.join-inline .input {
  flex: 1;
  min-width: 0;
  text-align: center;
}

.join-inline .button {
  height: 3rem;
}

.divider {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0.25rem 0;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.divider::before,
.divider::after {
  content: "";
  flex: 1;
  height: 0.0625rem;
  background: var(--separator);
}

.footnote {
  max-width: 20rem;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

/* ---------- Guest (phone) ---------- */

.guest {
  min-height: 100dvh;
  padding-right: env(safe-area-inset-right);
  padding-bottom: env(safe-area-inset-bottom);
  padding-left: env(safe-area-inset-left);
  background: var(--bg);
}

.guest-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(0.5rem + env(safe-area-inset-top)) var(--gutter) 0.5rem;
  background: var(--surface);
}

.guest-title {
  min-width: 0;
}

.guest-actions {
  display: flex;
  flex: none;
  gap: 0.5rem;
}

/* An admin's remote for the host's screen, under what's playing: ⏮ ⏯ ⏭ and the stacked sliders,
   like the host's bar. */
.remote {
  justify-content: center;
  padding: 0 var(--gutter) 0.875rem;
  background: var(--surface);
}

.remote .levels {
  flex: 1;
  max-width: 18rem;
}

.remote .level-slider {
  flex: 1;
  width: auto;
  min-width: 0;
}

.guest-header h1 {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.025em;
}

.room-badge {
  padding: 0.125rem 0.5rem;
  border-radius: var(--radius-sm);
  background: var(--fill);
  font-size: 0.875rem;
  font-weight: 600;
  letter-spacing: 0.08em;
}

.now-card {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem var(--gutter) 0.875rem;
  background: var(--surface);
}

.now-art {
  flex: none;
  width: 6rem;
  height: 3.375rem;
  border-radius: var(--radius-sm);
  object-fit: cover;
  background: var(--fill);
}

.now-text {
  flex: 1;
  min-width: 0;
}

.now-title {
  margin-top: 0.0625rem;
  overflow: hidden;
  font-size: 1.0625rem;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.now-meta {
  overflow: hidden;
  font-size: 0.875rem;
  color: var(--text-secondary);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.guest .search-controls {
  background: var(--surface);
  border-bottom: 0.0625rem solid var(--separator);
}

/* Full-bleed on phones; a centered column with edges on wide screens. */
@media (min-width: 760px) {
  .guest {
    max-width: 45rem;
    margin: 0 auto;
    border-right: 0.0625rem solid var(--separator);
    border-left: 0.0625rem solid var(--separator);
  }
}

/* ---------- Host view ---------- */

/* On a computer the host screen is three parts:
     ┌──────────────────────────┬─────────┐
     │ video                    │ sidebar │
     ├──────────────────────────┼─────────┤
     │ now playing + controls   │ join    │
     └──────────────────────────┴─────────┘
   The sidebar is a little over a fifth of the width and the bar a fixed, slim height;
   the video gets everything else (close to 16:9 on a TV). */
.host-mode {
  --side: clamp(19rem, 22vw, 28rem);
  --bar: clamp(6.5rem, 7.5vw, 10rem);
  --line: rgba(255, 255, 255, 0.07);

  overflow: hidden;
}

/* In the host view, banners sit over the video, not the sidebar. */
.host-mode .banner {
  left: calc((100% - var(--side)) / 2);
}

.host {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--side);
  grid-template-rows: minmax(0, 1fr) var(--bar);
  height: 100dvh;
  background: var(--surface);
}

.player-frame {
  position: relative;
  grid-row: 1;
  grid-column: 1;
  min-width: 0;
  min-height: 0;
  background: #000000;
  overflow: hidden;
  container-type: size;
}

/* The player scripts size each iframe in pixels to fill its frame (see player.js). */
.player-frame iframe,
.mv-frame iframe {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  border: 0;
}

.idle {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 1.5rem;
  background: radial-gradient(120% 100% at 50% 0%, #2a1015 0%, #0b0b0c 55%, #000000 100%);
  text-align: center;
}

.idle h2 {
  font-size: clamp(2rem, 3.6vw, 4rem);
  font-weight: 700;
  letter-spacing: -0.03em;
}

.idle p {
  font-size: clamp(1.125rem, 1.7vw, 1.75rem);
  color: var(--text-secondary);
}

.idle .qr {
  width: clamp(11.25rem, 20vw, 21.25rem);
  margin-top: 1.75rem;
  padding: clamp(0.75rem, 1.2vw, 1.25rem);
  border-radius: clamp(1rem, 1.7vw, 1.75rem);
}

/* Short frames, like a phone held upright: smaller text and a QR that fits the height. */
@container (max-height: 30rem) {
  .idle {
    gap: 0.375rem;
    padding: 1rem;
  }

  .idle h2 {
    font-size: 1.5rem;
  }

  .idle p {
    font-size: 0.9375rem;
  }

  .idle .qr {
    width: auto;
    height: 45cqh;
    aspect-ratio: 1;
    margin-top: 0.375rem;
    padding: 0.5rem;
    border-radius: var(--radius-lg);
  }
}

/* White, with rounded corners. Each QR's radius stays under about three times its white margin,
   so the rounding never reaches the code itself. */
.qr {
  flex: none;
  border-radius: var(--radius-lg);
  background: #ffffff;
  line-height: 0;
}

.qr svg {
  width: 100%;
  height: auto;
}

/* Shown when the browser won't start the video by itself (common on phones). */
/* Full screen, in the video's top right corner: shows while the pointer moves over the video
   (see setupVideoFrame in app.js), and the pointer hides with it in full screen. */
.fullscreen-button {
  position: absolute;
  top: 1rem;
  right: 1rem;
  z-index: 3;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--radius-md);
  background: rgba(20, 20, 22, 0.6);
  -webkit-backdrop-filter: blur(1rem);
  backdrop-filter: blur(1rem);
  color: #ffffff;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s var(--ease), background-color 0.2s var(--ease);
}

.fullscreen-button svg {
  width: 1.375rem;
  height: 1.375rem;
}

.player-frame.is-pointing .fullscreen-button,
.fullscreen-button:focus-visible {
  opacity: 1;
  pointer-events: auto;
}

.player-frame:fullscreen:not(.is-pointing),
.player-frame.is-fullscreen:not(.is-pointing) {
  cursor: none;
}

/* On iPhones, full screen fills the window instead (see toggleFullscreen in app.js), clear of
   the notch and the home indicator. */
.player-frame.is-fullscreen {
  position: fixed;
  inset: 0;
  z-index: 100;
  width: auto;
  height: auto;
  aspect-ratio: auto;
}

.player-frame.is-fullscreen .fullscreen-button {
  top: calc(1rem + env(safe-area-inset-top));
  right: calc(1rem + env(safe-area-inset-right));
}

.tap-to-play {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  border: 0;
  background: rgba(0, 0, 0, 0.6);
  color: #ffffff;
  font-size: 1.25rem;
  font-weight: 600;
  cursor: pointer;
  -webkit-backdrop-filter: blur(0.5rem);
  backdrop-filter: blur(0.5rem);
}

.tap-to-play-icon {
  display: grid;
  place-items: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background: var(--accent);
}

.tap-to-play-icon svg {
  width: 2rem;
  height: 2rem;
  margin-left: 0.25rem;
}

/* ---------- Host sidebar ---------- */

.sidebar {
  display: flex;
  flex-direction: column;
  grid-row: 1;
  grid-column: 2;
  min-width: 0;
  min-height: 0;
  border-left: 0.0625rem solid var(--line);
}

/* Settings and Leave, side by side at the top. */
.sidebar-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  padding: 0.75rem 0.75rem 0;
}

.sidebar-actions:has(> .page-fullscreen-button:not([hidden])) {
  grid-template-columns: auto 1fr 1fr;
}

.page-fullscreen-button {
  width: 2.25rem;
  padding: 0;
}

.page-fullscreen-button svg {
  width: 1.125rem;
  height: 1.125rem;
}

.host-panel-slot {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

/* The shared room panel fills the rest of the sidebar while you're the host. */
.sidebar .room-panel {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

.sidebar .tabs {
  position: static;
  padding: 0.75rem;
  border: 0;
  background: transparent;
}

.sidebar .panel {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  background: transparent;
}

.sidebar .list {
  background: transparent;
}

.sidebar .search-controls {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface);
  border-bottom: 0.0625rem solid var(--line);
}

/* Rows in the sidebar: compact, and highlighted when you point at one. */
.sidebar .row {
  padding-right: 0.75rem;
  padding-left: 0.75rem;
  border-bottom: 0.0625rem solid var(--line);
}

.sidebar .row:hover {
  background: var(--fill);
}

.sidebar .queue-position {
  display: none;
}

.next-label {
  margin-bottom: 0.0625rem;
  color: var(--accent);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.sidebar .empty {
  padding: 2.5rem 1.5rem;
  font-size: 0.9375rem;
}

/* ---------- Music video tile (bottom of the sidebar, computers only) ---------- */

.mv-tile {
  position: relative;
  flex: none;
}

.mv-frame {
  position: relative;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #000000;
}

/* It's for show: clicks go nowhere, so nobody pauses it by accident. */
.mv-frame iframe {
  pointer-events: none;
}

/* Label and controls. Over the bottom of the video when there is one; otherwise the whole tile. */
.mv-bar {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0.5rem 0.5rem 0.5rem 0.75rem;
  background: linear-gradient(transparent, rgba(0, 0, 0, 0.7));
  color: #ffffff;
  font-size: 0.8125rem;
  font-weight: 600;
}

.mv-dot {
  flex: none;
  width: 0.4375rem;
  height: 0.4375rem;
  border-radius: 50%;
  background: var(--accent);
}

.mv-status {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Mute and Turn off appear when you point at the tile. */
.mv-controls {
  display: flex;
  flex: none;
  gap: 0.375rem;
  opacity: 0;
  transition: opacity 0.15s var(--ease);
}

.mv-tile:hover .mv-controls,
.mv-tile:focus-within .mv-controls {
  opacity: 1;
}

.mv-control {
  display: grid;
  place-items: center;
  min-width: 1.875rem;
  height: 1.875rem;
  padding: 0 0.625rem;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  color: #ffffff;
  font-size: 0.75rem;
  font-weight: 600;
  cursor: pointer;
}

.mv-control:hover {
  background: rgba(255, 255, 255, 0.28);
}

.mv-control.is-icon {
  padding: 0;
}

.mv-control svg {
  width: 0.9375rem;
  height: 0.9375rem;
}

/* No music video to show: just the note, in place of the player. */
.mv-tile.is-collapsed .mv-frame {
  display: none;
}

.mv-tile.is-collapsed .mv-bar {
  position: static;
  border-top: 0.0625rem solid var(--line);
  background: none;
  color: var(--text-secondary);
  font-weight: 500;
}

.mv-tile.is-collapsed .mv-control {
  background: var(--fill);
  color: var(--text);
}

/* On a computer, with nothing playing, the welcome screen runs down behind the empty half of the
   bar. It's drawn over the bar, which also hides the bar's top line on that side. */
@media (min-width: 901px) {
  .host:has(#now-playing[hidden]) .player-frame {
    z-index: 1; /* the bar comes after it in the page, so it would be drawn on top */
    grid-row: 1 / -1;
  }
}

/* ---------- Host bar (bottom) ---------- */

/* Its two columns line up with the video and the sidebar above. */
.host-bar {
  display: grid;
  grid-row: 2;
  grid-column: 1 / -1;
  grid-template-columns: minmax(0, 1fr) var(--side);
  border-top: 0.0625rem solid var(--line);
}

.now-playing {
  display: flex;
  grid-column: 1;
  align-items: center;
  gap: 1rem;
  min-width: 0;
  padding: 0.75rem 1.25rem;
}

.now-playing-text {
  flex: 1;
  min-width: 0;
}

/* Long titles get two lines, then "…". The controls never move. */
.now-playing h2 {
  display: -webkit-box;
  overflow: hidden;
  font-size: clamp(1.25rem, 1.6vw, 2.25rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.now-playing-meta {
  margin-top: 0.25rem;
  overflow: hidden;
  font-size: clamp(0.875rem, 0.95vw, 1.125rem);
  color: var(--text-secondary);
  white-space: nowrap;
  text-overflow: ellipsis;
}

.requested-by {
  color: var(--accent);
}

.transport {
  display: flex;
  flex: none;
  gap: 0.5rem;
}

.transport .icon-button {
  width: 3.25rem;
  height: 3.25rem;
  border-radius: var(--radius-md);
}

.transport .icon-button svg {
  width: 1.5rem;
  height: 1.5rem;
}

/* Room code, then the QR code against the right edge, under the sidebar. */
.join-card {
  display: flex;
  grid-column: 2;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  min-width: 0;
  min-height: 0;
  padding: 0.75rem var(--gutter);
}

.join-details {
  flex: 1;
  min-width: 0;
}

/* It's a button: click it to show the code big (see .join-overlay). */
button.join-card {
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: zoom-in;
}

.join-card .room-code,
.join-card .join-url {
  display: block;
}

.join-url {
  font-size: 0.8125rem;
  color: var(--text-secondary);
  overflow-wrap: anywhere;
}

.room-code {
  margin-bottom: 0.125rem;
  font-size: clamp(2.5rem, 3.05vw, 4.5rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: 0.03em;
}

.join-card .qr {
  width: calc(var(--bar) - 1rem);
  aspect-ratio: 1;
  padding: 0.375rem;
  border-radius: var(--radius-md);
}

.join-card .qr svg {
  height: 100%;
}

/* The room code and QR code filling the screen, for people across the room. */
.join-overlay {
  width: 100%;
  max-width: none;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 2rem;
  border: 0;
  background: rgba(0, 0, 0, 0.96);
  color: var(--text);
  text-align: center;
  cursor: zoom-out;
}

.join-overlay[open] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  animation: overlay-in 0.25s var(--ease);
}

.join-overlay::backdrop {
  background: transparent;
}

@keyframes overlay-in {
  from {
    opacity: 0;
  }
}

.join-overlay-title {
  font-size: clamp(1.5rem, 2.4vw, 2.75rem);
  font-weight: 600;
  color: var(--text-secondary);
}

.join-overlay .qr {
  width: min(55vh, 80vw);
  padding: min(2.5vh, 1.5rem);
  border-radius: min(3.5vh, 2rem);
}

.join-overlay .room-code {
  margin-top: 0.5rem;
  font-size: min(16vh, 20vw);
  line-height: 1;
}

.join-overlay .join-url {
  font-size: clamp(1rem, 1.6vw, 1.75rem);
  color: var(--text-secondary);
}

/* ---------- Host view on phones and small screens ---------- */

/* Stacked: the video, then what's playing and how to join, then the room panel. */
/* ---------- Karaoke music videos (see karaoke-player.js) ---------- */

/* The music video: a muted YouTube embed that follows the karaoke sound. Clicks stop at its
   frame and never reach the embed (playing and pausing go through JamTube's own buttons). */
.karaoke-picture {
  position: absolute;
  inset: 0;
  background: #000000;
}

.karaoke-picture iframe {
  pointer-events: none;
}

/* The original video's player, hidden while a karaoke song (or its preparing screen) shows. */
.player-frame.is-karaoke #player {
  visibility: hidden;
}

.karaoke-picture[hidden] {
  display: none;
}

.karaoke-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
}

/* YouTube won't play the video here: its picture shows, a little dimmed, behind the lyrics. */
.karaoke-picture.is-poster .karaoke-poster {
  opacity: 0.55;
  filter: blur(0.25rem);
}

.karaoke-picture.is-poster iframe {
  visibility: hidden;
}

/* Lyrics sit on a dark glass panel just above the bottom of the video, so any scene behind
   them (bright skies, white walls) can't wash them out. The panel keeps one width, and the
   lines inside keep their places, so it doesn't jump around from line to line. */
/* --lyrics-scale is the room's Lyrics size (data-size, set by app.js): every line scales with it. */
.lyrics[data-size="small"] {
  --lyrics-scale: 0.8;
}

.lyrics[data-size="large"] {
  --lyrics-scale: 1.25;
}

.lyrics {
  --lyrics-scale: 1;

  position: absolute;
  bottom: 1.6cqh;
  left: 50%;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5cqh;
  width: min(90%, 68rem);
  padding: 1.8cqh 3cqw 2cqh;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: clamp(0.875rem, 2.6cqh, 1.75rem);
  background: rgba(12, 12, 14, 0.6);
  box-shadow: 0 0.75rem 2.5rem rgba(0, 0, 0, 0.3);
  -webkit-backdrop-filter: blur(1.25rem);
  backdrop-filter: blur(1.25rem);
  text-align: center;
  transform: translateX(-50%);
  pointer-events: none;
  transition: opacity 0.4s var(--ease);
}

.lyrics > * {
  width: 100%;
}

.lyrics > .lyrics-scene,
.lyrics > .lyrics-countdown {
  width: auto;
}

.lyrics.is-blank {
  opacity: 0;
}

.lyrics-line {
  max-width: 100%;
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.015em;
  line-height: 1.2;
  text-wrap: balance;
  transition: opacity 0.25s var(--ease);
}

/* Always room for at least one line, so the panel doesn't shrink between lines. */
.lyrics-now {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  min-height: calc(clamp(1.5rem, 6.2cqh, 5rem) * var(--lyrics-scale) * 1.2);
}

.lyrics-current {
  min-height: 1.2em;
  font-size: calc(clamp(1.5rem, 6.2cqh, 5rem) * var(--lyrics-scale));
  color: rgba(255, 255, 255, 0.5);
}

/* A line fades in once, when it first shows (as the one coming up), then stays put. */
.lyrics-current.is-entering {
  animation: lyric-in 0.3s var(--ease);
}

@keyframes lyric-in {
  from {
    opacity: 0;
  }
}


/* Backing vocals and ad-libs: smaller, with the line they go with. */
.lyrics-current.is-background {
  min-height: 0;
  font-size: clamp(1rem, 3.8cqh, 3rem);
}

/* Duets, like Apple Music: the first singer on the left, the second on the right, both
   together in the middle. */
.lyrics.is-duet .lyrics-now {
  align-items: stretch;
}

.lyrics.is-duet [data-singer="1"] {
  text-align: left;
}

.lyrics.is-duet [data-singer="2"] {
  text-align: right;
}

/* Each word fills in with white as it's sung, in reading order, with a soft leading edge. */
/* --sung is how much of the word has been sung, 0 to 1 (set by karaoke-player.js). The fill has
   a soft edge, 0.6em wide, that starts just before the word and ends just past it, so none of it
   shows on a word that isn't sung yet, and a sung word is white to its last letter. */
.lyric-word {
  --sung: 0;

  background: linear-gradient(90deg, #ffffff calc(var(--sung) * (100% + 0.6em) - 0.6em), rgba(255, 255, 255, 0.5) calc(var(--sung) * (100% + 0.6em)));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.lyrics-next {
  min-height: 1.2em;
  font-size: calc(clamp(1rem, 3.6cqh, 2.75rem) * var(--lyrics-scale));
  font-weight: 600;
  color: rgba(255, 255, 255, 0.55);
}

.lyrics-line.is-empty {
  opacity: 0;
}

.lyrics-scene {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1cqh;
  padding: 0.375rem 0.875rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  color: rgba(255, 255, 255, 0.85);
  font-size: clamp(0.8125rem, 2.2cqh, 1.5rem);
  font-weight: 600;
  -webkit-backdrop-filter: blur(0.75rem);
  backdrop-filter: blur(0.75rem);
}

.lyrics-scene[hidden],
.lyrics-countdown[hidden] {
  display: none;
}

.lyrics-scene-dot {
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1.4s var(--ease) infinite;
}

/* 3, 2, 1 before the singing starts. */
.lyrics-countdown {
  display: flex;
  gap: 0.75rem;
  margin-bottom: 0.5cqh;
}

.lyrics-countdown::before,
.lyrics-countdown::after,
.lyrics-countdown {
  --dot: clamp(0.625rem, 1.8cqh, 1.25rem);
}

.lyrics-countdown::before {
  content: "";
  width: calc(var(--dot) * 5);
  height: var(--dot);
  background:
    radial-gradient(circle closest-side, var(--accent) 98%, transparent) 0 0 / calc(var(--dot) * 2) var(--dot) repeat-x;
  -webkit-mask: linear-gradient(90deg, #000 var(--shown), transparent var(--shown));
  mask: linear-gradient(90deg, #000 var(--shown), transparent var(--shown));
}

.lyrics-countdown[data-count="3"] { --shown: 100%; }
.lyrics-countdown[data-count="2"] { --shown: 60%; }
.lyrics-countdown[data-count="1"] { --shown: 20%; }

@keyframes pulse {
  50% { opacity: 0.35; }
}

/* Shown on the host screen while a song's music video is still being made. */
.preparing {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  padding: 1.5rem;
  background: radial-gradient(120% 100% at 50% 0%, #2a1015 0%, #0b0b0c 55%, #000000 100%);
  text-align: center;
}

.preparing[hidden] {
  display: none;
}

.preparing-spinner {
  width: 2.75rem;
  height: 2.75rem;
  margin-bottom: 0.5rem;
  border: 0.25rem solid rgba(255, 255, 255, 0.14);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.9s linear infinite;
}

.preparing-title {
  max-width: 40rem;
  font-size: clamp(1.25rem, 2.4vw, 2.5rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.preparing-message {
  margin-bottom: 1rem;
  color: var(--text-secondary);
  font-size: clamp(1rem, 1.4vw, 1.5rem);
}

/* Queue rows: how far along each song's music video is. */
.prep-tag {
  color: var(--text-secondary);
}

.prep-tag.is-ready {
  color: #30d158;
}

.prep-tag.is-working {
  color: #ff9f0a;
}

/* Along the top of the bar under the video, on its dividing line. The track is taller than the
   rail it draws, so it's easy to grab. */
.host-bar {
  position: relative;
}

.seek {
  position: absolute;
  top: 0;
  left: 0;
  right: var(--side);
  z-index: 2;
}

.seek[hidden] {
  display: none;
}

.seek-track {
  display: flex;
  align-items: center;
  height: 1.5rem;
  margin-top: -0.75rem;
  cursor: pointer;
  touch-action: none;
}

.seek-rail {
  position: relative;
  width: 100%;
  height: 0.25rem;
  background: rgba(255, 255, 255, 0.16);
  overflow: hidden;
  transition: height 0.15s var(--ease);
}

.seek-track:hover .seek-rail,
.seek.is-seeking .seek-rail {
  height: 0.5rem;
}

.seek-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--accent);
}

.seek-scenes {
  position: absolute;
  inset: 0;
}

.seek-scene {
  position: absolute;
  top: 0;
  bottom: 0;
  background: repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.28) 0 0.1875rem, transparent 0.1875rem 0.375rem);
}

.now-playing-meta [data-elapsed],
.now-playing-meta [data-total] {
  font-variant-numeric: tabular-nums;
}

/* The volume and vocal sliders, next to the play controls: the same height and look as their
   buttons. --level is how far each is filled (set by app.js). */
.level {
  --level: 0%;

  display: flex;
  align-items: center;
  gap: 0.625rem;
  height: 3.25rem;
  padding: 0 1rem 0 0.875rem;
  border-radius: var(--radius-md);
  background: var(--fill);
}

/* Stacked, the two are as tall as one button, each a box of its own. Alone (the volume, for
   a YouTube video), the volume fills it. */
.levels {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  height: 3.25rem;
}

.levels:not(:has(> .level:not([hidden]))) {
  display: none;
}

.levels .level {
  flex: 1;
  height: auto;
  min-height: 0;
  padding: 0 0.875rem 0 0.75rem;
  gap: 0.5rem;
}

.levels .level-icon svg {
  width: 1.0625rem;
  height: 1.0625rem;
}

.level[hidden] {
  display: none;
}

/* On a computer the bar is as tall as the room code and QR code beside it, so the buttons and
   sliders can be a little taller (and the stacked sliders roomier) without it growing. */
@media (min-width: 901px) {
  .transport .icon-button,
  .level,
  .levels {
    height: 3.75rem;
  }
}

.level-icon {
  display: inline-grid;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text-secondary);
}

button.level-icon {
  cursor: pointer;
}

button.level-icon:hover {
  color: var(--text);
}

.level-icon svg {
  width: 1.375rem;
  height: 1.375rem;
}

.level-slider {
  width: clamp(6rem, 8vw, 10rem);
  height: 1.5rem;
  margin: 0;
  background: transparent;
  cursor: pointer;
  appearance: none;
  -webkit-appearance: none;
}

.level-slider::-webkit-slider-runnable-track {
  height: 0.3125rem;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--text) var(--level), var(--fill-strong) var(--level));
}

.level-slider::-moz-range-track {
  height: 0.3125rem;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--text) var(--level), var(--fill-strong) var(--level));
}

.level-slider::-webkit-slider-thumb {
  width: 1rem;
  height: 1rem;
  margin-top: -0.34375rem;
  border: 0;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 0.0625rem 0.25rem rgba(0, 0, 0, 0.35);
  -webkit-appearance: none;
}

.level-slider::-moz-range-thumb {
  width: 1rem;
  height: 1rem;
  border: 0;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 0.0625rem 0.25rem rgba(0, 0, 0, 0.35);
}

.level-slider:focus-visible {
  outline: none;
}

.level:has(.level-slider:focus-visible) {
  box-shadow: 0 0 0 0.125rem color-mix(in srgb, var(--accent) 60%, transparent);
}

/* Phones: the buttons on one row, and the sliders under them, as wide as the buttons. */
@media (max-width: 600px) {
  .transport {
    display: grid;
    grid-template-columns: repeat(4, 3.25rem);
    justify-content: center;
    gap: 0.5rem;
  }

  /* The remote has three buttons. */
  .transport.remote {
    grid-template-columns: repeat(3, 3.25rem);
  }

  .remote .levels {
    max-width: none;
  }

  .transport .levels {
    grid-column: 1 / -1;
    grid-row: 2;
    height: auto;
  }

  /* As far apart as they are from the buttons, in the same height as before. */
  .transport .levels {
    gap: 0.5rem;
  }

  .levels .level {
    flex: none;
    height: 2.375rem;
  }

  .transport .level-slider {
    flex: 1;
    width: auto;
    min-width: 0;
  }
}

/* In Room Settings, when the music video worker isn't set up. */
.setting-hint.setup-problem {
  margin-top: 0.25rem;
  color: #ff9f0a;
}

@media (max-width: 900px) {
  .seek {
    right: 0;
  }
}

@media (max-width: 900px) {
  .host-mode {
    overflow: auto;
  }

  .host-mode .banner {
    left: 50%;
  }

  .host {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto auto;
    height: auto;
    min-height: 100dvh;
  }

  .player-frame {
    aspect-ratio: 16 / 9;
  }

  .host-bar {
    grid-row: 2;
    grid-column: 1;
    grid-template-columns: minmax(0, 1fr);
  }

  .now-playing {
    flex-wrap: wrap;
    padding: 0.875rem 1rem;
  }

  .now-playing h2 {
    font-size: 1.25rem;
  }

  /* The title gets the whole row; the controls go centered on the line below. */
  .now-playing-text {
    flex-basis: calc(100% - 4.5rem);
  }

  .transport {
    width: 100%;
    justify-content: center;
  }

  .join-card {
    grid-column: 1;
    padding: 0.75rem 1rem;
    border-top: 0.0625rem solid var(--line);
  }

  .join-card .qr {
    width: 6rem;
  }

  .sidebar {
    grid-row: 3;
    grid-column: 1;
    min-height: 70dvh;
    border-top: 0.0625rem solid var(--line);
    border-left: 0;
  }
}

/* ---------- Recording ---------- */

/* Shown to everyone while songs are being recorded. */
.rec-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  margin-right: 0.5rem;
  padding: 0.0625rem 0.375rem;
  border-radius: var(--radius-xs);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  vertical-align: 0.0625rem;
  text-transform: uppercase;
}

.rec-badge::before {
  content: "";
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 50%;
  background: currentColor;
  animation: rec-blink 1.4s steps(1) infinite;
}

.eyebrow .rec-badge {
  margin: 0 0 0 0.375rem;
}

@keyframes rec-blink {
  50% {
    opacity: 0.3;
  }
}

/* ---------- Clips (recordings) ---------- */

/* The host's Download All, centered above the list, with room before the first clip. */
.clips-actions {
  display: flex;
  justify-content: center;
  padding: 0.75rem var(--gutter);
}

/* Rows like the song rows, with a still from the recording where the song's picture would be. */
.clips-list {
  --separator-inset: 9.5rem;
}

.clip-thumb {
  position: relative;
  flex: none;
  width: 7.5rem;
  aspect-ratio: 16 / 9;
  padding: 0;
  border: 0;
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: #000000;
  cursor: pointer;
}

.clip-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.clip-play {
  position: absolute;
  top: 50%;
  left: 50%;
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.55);
  color: #ffffff;
  transform: translate(-50%, -50%);
  transition: transform 0.15s var(--ease);
}

.clip-thumb:hover .clip-play {
  transform: translate(-50%, -50%) scale(1.1);
}

.clip-play svg {
  width: 0.75rem;
  height: 0.75rem;
  margin-left: 0.0625rem;
}

.clip-length {
  position: absolute;
  right: 0.25rem;
  bottom: 0.25rem;
  padding: 0 0.25rem;
  border-radius: var(--radius-xs);
  background: rgba(0, 0, 0, 0.75);
  color: #ffffff;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
}

.clip-meta {
  display: flex;
  align-items: center;
  gap: 0.3125rem;
}

.clip-meta .avatar {
  width: 1rem;
  height: 1rem;
  font-size: 0.5rem;
}

/* The clip player: the video, then the song and the buttons. */
.clip-player {
  width: min(100% - 1rem, 56rem);
  max-width: none;
  padding: 0;
  border: 0;
  border-radius: 0.875rem;
  overflow: hidden;
  background: var(--floating);
  color: var(--text);
  -webkit-backdrop-filter: saturate(180%) blur(24px);
  backdrop-filter: saturate(180%) blur(24px);
}

.clip-player::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

.clip-player video {
  display: block;
  width: 100%;
  max-height: 70dvh;
  background: #000000;
}

.clip-player-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1rem;
}

.clip-player-text {
  flex: 1;
  min-width: 0;
}

.clip-player-title {
  overflow: hidden;
  font-weight: 600;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.clip-player-meta {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.clip-player-download {
  color: var(--accent);
}

/* ---------- Page sheets (Room Settings, Song Info) ----------
   Like iOS's page sheets: a bar with the title and Done, then grouped lists that scroll under
   it, so a sheet can hold as much as it needs. Up from the bottom on phones, nearly the whole
   screen tall; in the middle on bigger screens. */

.page-sheet {
  flex-direction: column;
  width: 100%;
  max-width: none;
  height: calc(100dvh - 2.5rem - env(safe-area-inset-top));
  max-height: none;
  margin: auto auto 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 0.875rem 0.875rem 0 0;
  background: var(--grouped-bg);
  color: var(--text);
}

.page-sheet[open] {
  display: flex;
  animation: sheet-in 0.3s cubic-bezier(0.2, 0.9, 0.3, 1);
}

.page-sheet::backdrop {
  background: rgba(0, 0, 0, 0.35);
}

@media (min-width: 760px) {
  .page-sheet {
    width: min(100% - 2rem, 34rem);
    height: min(46rem, 100dvh - 4rem);
    margin: auto;
    border: 0.0625rem solid var(--separator);
    border-radius: 0.875rem;
    box-shadow: var(--floating-shadow);
  }
}

/* The title in the middle, Done on the right, like a navigation bar. */
.page-sheet-bar {
  display: grid;
  flex: none;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 0.875rem 1rem;
  border-bottom: 0.0625rem solid var(--separator);
}

.page-sheet-title {
  grid-column: 2;
  font-size: 1.0625rem;
  font-weight: 600;
  text-align: center;
}

.page-sheet-done {
  grid-column: 3;
  justify-self: end;
  padding: 0;
  border: 0;
  background: none;
  color: var(--accent);
  font-size: 1.0625rem;
  font-weight: 600;
  cursor: pointer;
}

.page-sheet-body {
  flex: 1;
  min-height: 0;
  padding: 0 1rem calc(1.5rem + env(safe-area-inset-bottom));
  overflow-y: auto;
  overscroll-behavior: contain;
}

.group-note {
  padding: 1rem 1rem 0;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.group {
  margin-top: 1.5rem;
}

.group-title {
  padding: 0 1rem 0.375rem;
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--text-secondary);
  text-transform: uppercase;
}

/* A group's rows, on one rounded card, with a hairline between them that starts at the text. */
.group-card {
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--grouped-cell);
}

.group-card > :not([hidden]) ~ :not([hidden]) {
  position: relative;
}

.group-card > :not([hidden]) ~ :not([hidden])::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: 1rem;
  height: 0.0625rem;
  background: var(--separator);
}

/* A button that's a whole row: Copy Info, Regenerate Song. */
.group-action {
  display: block;
  width: 100%;
  padding: 0.75rem 1rem;
  border: 0;
  background: transparent;
  color: var(--accent);
  font-size: 1.0625rem;
  text-align: left;
  cursor: pointer;
}

.group-action:active:not(:disabled) {
  background: var(--fill);
}

.group-action:disabled {
  color: var(--text-secondary);
  cursor: default;
}

/* Song Info: each detail's name, then what it is, side by side, or the name above on narrow
   screens. The text can be selected, to copy by hand. */
.info-row {
  display: grid;
  grid-template-columns: 9rem minmax(0, 1fr);
  gap: 1rem;
  padding: 0.6875rem 1rem;
  font-size: 0.9375rem;
  line-height: 1.35;
  -webkit-user-select: text;
  user-select: text;
}

.info-row dt {
  color: var(--text-secondary);
}

.info-row dd {
  margin: 0;
  overflow-wrap: anywhere;
}

@media (max-width: 520px) {
  .info-row {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.125rem;
  }

  .info-row dt {
    font-size: 0.8125rem;
  }
}

/* Where the text goes for a moment to be copied, when the clipboard API isn't available. */
.info-copy-text {
  position: fixed;
  opacity: 0;
  pointer-events: none;
}

/* ---------- Room Settings ---------- */

.setting-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1rem;
}

.setting-text {
  flex: 1;
  min-width: 0;
}

.setting-title {
  font-size: 1.0625rem;
}

.setting-hint {
  margin-top: 0.125rem;
  text-wrap: pretty; /* no single word left on a line of its own */
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

/* Grayed out: the music video on a phone or tablet. */
.setting-row.is-disabled .setting-title {
  color: var(--text-secondary);
}

.choice {
  display: flex;
  padding: 0.125rem;
  border-radius: var(--radius-md);
  background: var(--fill);
}

.choice-option {
  height: 1.875rem;
  padding: 0 0.75rem;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  font-size: 0.875rem;
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
}

.choice-option[aria-checked="true"] {
  background: var(--segment-active);
  box-shadow: 0 0.125rem 0.375rem rgba(0, 0, 0, 0.12);
  font-weight: 600;
}

/* The recorder's card (guest view): what the camera sees, how it's doing, and its buttons. */
.recorder-card {
  margin: 0.75rem var(--gutter);
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--surface);
}

.recorder-preview {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #000000;
  object-fit: contain; /* the whole frame, exactly as it's recorded */
}

.recorder-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.25rem;
  padding: 0.75rem 1rem;
}

/* The dot before the status: red and blinking while recording, green when all is well, gray
   and blinking while waiting, orange when something needs fixing. */
.camera-status {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  font-weight: 600;
}

.camera-status::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: #30d158;
}

.camera-status[data-tone="live"]::before {
  background: #ff3b30;
  animation: rec-blink 1.4s steps(1) infinite;
}

.camera-status[data-tone="waiting"]::before {
  background: var(--text-secondary);
  animation: rec-blink 1.4s steps(1) infinite;
}

.camera-status[data-tone="problem"]::before {
  background: #ff9f0a;
}

.camera-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.25rem;
}

.camera-actions:not(:has(:not([hidden]))) {
  display: none;
}

.camera-actions .pill-button {
  height: 2rem;
  font-size: 0.875rem;
}

/* iOS-style switch. */
.switch {
  position: relative;
  flex: none;
  width: 3.1875rem;
  height: 1.9375rem;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--fill-strong);
  cursor: pointer;
  transition: background-color 0.2s var(--ease);
}

.switch::after {
  content: "";
  position: absolute;
  top: 0.125rem;
  left: 0.125rem;
  width: 1.6875rem;
  height: 1.6875rem;
  border-radius: 50%;
  background: #ffffff;
  box-shadow: 0 0.1875rem 0.5rem rgba(0, 0, 0, 0.15), 0 0.0625rem 0.0625rem rgba(0, 0, 0, 0.16);
  transition: transform 0.25s var(--ease);
}

.switch[aria-checked="true"] {
  background: #30d158;
}

.switch[aria-checked="true"]::after {
  transform: translateX(1.25rem);
}

.switch:disabled {
  opacity: 0.4;
  cursor: default;
}

/* − 3 + */
.stepper {
  display: flex;
  flex: none;
  align-items: center;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--fill);
}

.stepper-button {
  width: 2.5rem;
  height: 2rem;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 1.25rem;
  cursor: pointer;
}

/* The stepper clips its corners, so its focus ring is drawn inside the button. */
.stepper-button:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 0.125rem color-mix(in srgb, var(--accent) 60%, transparent);
}

.stepper-button:disabled {
  opacity: 0.3;
  cursor: default;
}

.stepper-value {
  min-width: 4.5rem;
  font-size: 0.9375rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* Narrower on phones, so the setting's name keeps to one line. */
@media (max-width: 520px) {
  .stepper-button {
    width: 2.125rem;
  }

  .stepper-value {
    min-width: 3.75rem;
  }
}
