/* pages.css — page-specific layouts for Song of the Week.
 * Rules here only layout page grids and page-scoped adjustments. Shared
 * component styling lives in components.css; tokens live in tokens.css. */

/* The .page__main element is a <main>, and some browser defaults +
 * user-agent stylesheets apply a max-width via legacy rules. Neutralise
 * the cascade here so new layouts inherit the full .page width. */
.page__main {
  max-width: none;
  margin: 0;
  padding: 0;
  padding-bottom: var(--sp-10);
}

/* ─── Small compat utilities ────────────────────────────────────
 * A few still-live partials (listen_links, mb_search_results) use the
 * pre-redesign class names `.muted` and `.art-sm`. They map cleanly to
 * the handoff palette — aliased here so those partials keep rendering
 * correctly without another template pass. `.flash` + `.cta-fab` +
 * `.readonly-input` are also used in the wild. */
.muted {
  color: var(--dim);
  font-size: var(--fs-body-sm);
}
.art-sm {
  width: 48px;
  height: 48px;
  background: var(--paper-hi);
  border: 1px solid var(--ink);
  object-fit: cover;
  flex-shrink: 0;
}
.art-box {
  background: var(--paper-hi);
  border: 1px solid var(--ink);
  aspect-ratio: 1 / 1;
  overflow: hidden;
}
.art-box img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.flash {
  padding: 10px 14px;
  border: var(--border-width) solid var(--ink);
  background: var(--paper-hi);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
  margin: var(--sp-3) 0;
}
.flash-ok    { background: var(--soft); color: var(--on-fill); }
.flash-error { background: var(--accent); color: var(--paper); }

/* Mobile floating CTA — visible on group detail when the viewer owes
 * an action. Big circular pink blob bottom-right. */
.cta-fab {
  position: fixed;
  right: var(--sp-5);
  bottom: var(--sp-5);
  display: none;
  align-items: center;
  gap: var(--sp-2);
  padding: 12px 16px;
  background: var(--accent);
  color: var(--paper);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-card);
  text-decoration: none;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: var(--fs-body);
  z-index: 50;
}
.cta-fab:hover { color: var(--paper); text-decoration: none; }
.cta-fab-label { display: inline; }
.cta-fab-arrow { font-weight: 400; }

@media (max-width: 900px) {
  .cta-fab { display: inline-flex; }
  /* Reserve the FAB's height at the end of the page. Being fixed, it sits
     over whatever the last section happens to be — on the group page that
     was the theme-ideas form's submit button. */
  .page__main { padding-bottom: 84px; }
}

/* Short inline forms without page-level padding — the old
 * `class="inline"` was a flex shim in app.css. Keep the affordance. */
.inline {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
}

/* Listen-link partial leftovers — the partial is still used by vote
 * cards, results cards, and listen lists. Keep a minimal baseline so
 * its <details class="listen-other"> summary + icon stay usable in
 * places we haven't bespokely restyled. */
.listen-group {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: flex-start;
  margin-top: 6px;
}
.listen-group .listen-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--accent-2);
  color: var(--paper);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-sm);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: var(--fs-body-sm);
  text-decoration: none;
  border-radius: 0;
}
.listen-group .listen-btn:hover { color: var(--paper); }
.listen-group .listen-btn .svc-icon { width: 14px; height: 14px; }
.listen-other {
  font-family: var(--font-mono);
  font-size: var(--fs-micro-sm);
}
.listen-other > summary {
  list-style: none;
  cursor: pointer;
  color: var(--dim);
}
.listen-other > summary::-webkit-details-marker { display: none; }
.listen-other > summary::marker { content: ""; }
.listen-other[open] > summary { color: var(--accent); }
.listen-other ul {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.listen-other a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--ink);
  text-decoration: underline;
}
.listen-note {
  color: var(--dim);
}

/* MusicBrainz search pick list. */
.mb-search-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.mb-search-list li {
  border: 1px dotted var(--line);
  padding: var(--sp-2) var(--sp-3);
}
.mb-pick {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  cursor: pointer;
  color: var(--ink);
}
.mb-pick:hover { color: var(--accent); }
.mb-search-results .muted { color: var(--dim); padding: var(--sp-2); }

.spinner {
  display: inline-block;
  width: 14px;
  height: 14px;
  border: 2px solid var(--line);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: sotw-spin 0.8s linear infinite;
  vertical-align: middle;
}
.spinner.htmx-indicator { opacity: 0; transition: opacity 150ms; }
.spinner.htmx-request.htmx-indicator,
.htmx-request .spinner.htmx-indicator { opacity: 1; }
@keyframes sotw-spin {
  to { transform: rotate(360deg); }
}

/* The brand logo and the bell are anchors, so base.css's global
 * `a { text-decoration: underline }` lands on them. The handoff
 * strips it from `.nav__item` only; do the same for the other nav
 * anchors and the legacy header brand. Same problem for any anchor
 * styled as a button — both the handoff `.btn` family and the legacy
 * `.btn-primary` / `.btn-secondary` should never carry link underline. */
.nav__brand,
.nav__brand:hover,
.nav__bell,
.nav__bell:hover,
.brand,
.brand:hover,
.btn,
.btn:hover,
.btn-primary,
.btn-primary:hover,
.btn-secondary,
.btn-secondary:hover,
.btn-88x31,
.btn-88x31:hover,
.group-card,
.group-card:hover {
  text-decoration: none;
}

/* Base.css's `a:hover { color: var(--accent) }` is right for body links
 * but turns the text of anchor-styled buttons / cards / brand chrome
 * pink on hover, which against a pink CTA reads as "the button just
 * vanished". Pin each anchored component's hover colour to whatever
 * its base style uses so the hover state keeps contrast. */
.nav__brand:hover .nav__logo { color: var(--accent); } /* brand logo is already accent; keep it */
.nav__brand:hover .nav__tag  { color: var(--dim); }
.nav__bell:hover             { color: var(--accent); }
.btn:hover                   { color: var(--ink); }
.btn--primary:hover,
.btn--secondary:hover        { color: var(--paper); }
.btn--waiting:hover          { color: var(--dim); }
.btn-primary:hover           { color: #0b0e16; }     /* legacy app.css */
.btn-secondary:hover         { color: var(--text); } /* legacy app.css */
.group-card:hover            { color: var(--ink); }
.win-pill:hover              { color: var(--ink); }
.past-round-card:hover       { color: var(--ink); }

/* Disabled button state — keep the visual present but drop the
 * interactive affordance so the user knows it's not ready yet. */
.btn[disabled],
.btn[disabled]:hover {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
  box-shadow: var(--shadow-btn);
  color: var(--ink);
}

/* ─── Dashboard ──────────────────────────────────────────────── */

.masthead {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-6);
  align-items: end;
  padding: var(--sp-6) 0 var(--sp-3);
  border-top: var(--border-width) solid var(--ink);
}
.masthead__stamp-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
/* Chip row that follows the member/started stamp on the group masthead.
 * Gives the round-state chip-marquee a little vertical breathing room so
 * it doesn't crowd the member count above it. */
.masthead__chip-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: var(--sp-2);
}
.masthead__title {
  font-size: 64px;
  line-height: 1;
  letter-spacing: var(--ls-display-tight);
  margin: 0;
}
.masthead__subcopy {
  margin-top: 6px;
}
.masthead__right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  text-align: right;
}
.masthead__right .countdown {
  letter-spacing: -0.5px;
}
.masthead__countdown-sub {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 2px;
  margin-top: 4px;
}
.masthead__countdown-sub .stamp { font-size: var(--fs-micro-xs); }

/* When a group has a custom avatar, the left column becomes a two-cell
   row (avatar + text). Collapses back to column on narrow screens so
   the image doesn't squish the title. */
/* Inline group avatar — shown next to the H1 group name in the
   masthead title row. Smaller + inline so the title itself stays the
   primary visual hook; the avatar is a familiarity anchor, not a hero. */
.masthead__title-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.masthead__title-row .avatar {
  flex-shrink: 0;
}

/* Account page — profile picture card. Lays out the current avatar
   preview on the left with the upload/remove form stack on the right. */
.account-avatar-card__body {
  display: flex;
  gap: var(--sp-4);
  align-items: flex-start;
  flex-wrap: wrap;
}
.account-avatar-card__forms {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  flex: 1 1 240px;
}
.avatar-upload-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.avatar-upload-form__file {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.avatar-upload-form__remove {
  align-self: flex-start;
}

.group-list {
  padding-top: var(--sp-4);
}
.group-list__header {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--sp-3);
}
.group-list__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
.group-list__empty {
  padding: var(--sp-6);
  text-align: center;
}
.group-list__empty p + p {
  margin-top: var(--sp-4);
}

.group-card__actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
}
.group-card__actions .btn {
  padding: 6px 12px;
  font-size: var(--fs-body-sm);
  box-shadow: var(--shadow-btn);
}
/* Time-remaining stamp next to the CTA is the only way a viewer knows
   how long they have — make it readable on phones. */
@media (max-width: 560px) {
  .group-card__actions .stamp--sm {
    font-size: 12px;
    font-weight: 700;
  }
}

/* Collapsible "more" drawer on the group page. Hides past rounds,
   shared playlist, and owner management by default so the round
   itself stays centre-stage. Owners get it open pre-expanded. */
.group-body__more { margin-top: var(--sp-5); }
.group-body__more > summary {
  cursor: pointer;
  list-style: none;
  padding: var(--sp-3) 0;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  text-transform: uppercase;
  color: var(--dim);
}
.group-body__more > summary::-webkit-details-marker { display: none; }
.group-body__more > summary::marker { content: ""; }
.group-body__more > summary::before { content: "▸ "; }
.group-body__more[open] > summary::before { content: "▾ "; }
.group-body__more[open] > summary { color: var(--accent); }
.group-card__progress {
  margin-left: auto;
}

/* Whole-card hit area — the name anchor stretches its ::after to fill
 * the card so clicking anywhere (except the CTA button) opens the
 * group page. The CTA and the deadline/progress spans bump themselves
 * to z-index: 2 so their own clicks land distinctly. Pattern keeps
 * semantic markup simple (one main link, one action link). */
.group-card { position: relative; }
.group-card__link {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  line-height: 1.05;
  text-decoration: none;
  color: inherit;
}
.group-card__link:hover { color: var(--ink); }
.group-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}
.group-card:hover .group-card__link { color: var(--accent); }
.group-card__cta,
.group-card__actions [data-countdown],
.group-card__progress {
  position: relative;
  z-index: 2;
}

@media (max-width: 720px) {
  .masthead {
    grid-template-columns: 1fr;
    align-items: start;
  }
  .masthead__right {
    align-items: flex-start;
    text-align: left;
  }
  .masthead__title {
    font-size: 44px;
  }
  .group-list__grid {
    grid-template-columns: 1fr;
  }
}

/* ─── Group detail ───────────────────────────────────────────── */

.masthead--group .masthead__title {
  font-size: var(--fs-display-xl);
}

.group-body__section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--sp-3);
  gap: var(--sp-4);
  flex-wrap: wrap;
}
/* Right-side cluster inside a section head — groups the "> N tracks"
 * stamp with secondary action buttons (e.g. "listen to all") so they
 * stay aligned to the right of the h2 and wrap as a unit on mobile. */
.group-body__section-head__right {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  min-width: 0;
}
.group-body__section-head__right > .stamp {
  min-width: 0;
  overflow-wrap: break-word;
}

/* Prominent "your turn" banner — the viewer's state is the most
 * important thing on the page, so it sits just below the masthead
 * and takes the full width at card weight. The variant classes
 * tune the colour: urgent=pink, done=soft teal, finalised=teal,
 * idle=paper-hi. */
.status-banner {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--sp-4);
  align-items: center;
  padding: var(--sp-4) var(--sp-5);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
  margin: var(--sp-3) 0;
}
.status-banner__body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.status-banner__copy {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  line-height: 1.1;
}
.status-banner__sub {
  color: var(--ink);
  opacity: 0.8;
}
.status-banner--urgent    { background: var(--accent);   color: var(--paper); }
.status-banner--urgent .status-banner__label,
.status-banner--urgent .status-banner__sub { color: var(--paper); opacity: 0.85; }
.status-banner--done      { background: var(--soft);     color: var(--on-fill); }
.status-banner--finalised { background: var(--accent-2); color: var(--paper); }
.status-banner--finalised .status-banner__label,
.status-banner--finalised .status-banner__sub { color: var(--paper); opacity: 0.85; }
.status-banner--idle      { background: var(--paper-hi); color: var(--ink); }

.status-banner__cta .btn { white-space: nowrap; }

/* Section wrapper for the current round — when voting is live we
 * pair the bracket grid with a voters/status aside; other states are
 * full-width. */
.round-section {
  padding-top: var(--sp-4);
}
.round-section__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: var(--sp-8);
  align-items: start;
}
/* Grid and flex children default to min-width: auto, so a single
   unbreakable run of text sets the column's floor. Without this the
   "anonymous until the round closes" stamp forced the candidate column to
   405px and the whole page scrolled sideways on a phone. */
.round-section__grid > * { min-width: 0; }
.round-section__aside {
  padding-left: var(--sp-6);
  border-left: var(--border-width) solid var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.bracket-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}
.bracket-grid__cell {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.bracket-grid__cell .art-tile {
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
}
.bracket-grid__cell.is-pending {
  opacity: 0.55;
}
.bracket-grid__cell .display-sm {
  font-size: var(--fs-display-sm);
  line-height: 1.05;
  margin-top: 4px;
  /* keep long titles from breaking the grid */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bracket-grid__cell.is-you .display-sm { color: var(--accent); }
.bracket-empty {
  padding: var(--sp-6);
  text-align: center;
}
.bracket-empty p + p {
  margin-top: var(--sp-4);
}

/* ─── Right-column phase + standings ─── */

.phase-aside {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.phase-aside__head {
  display: flex;
  justify-content: flex-start;
}
.phase-aside__head-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: var(--sp-2);
}
.phase-aside__block {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.phase-aside__chip--finalised {
  background: var(--accent);
  color: var(--paper);
}
.phase-aside__chip--idle,
.phase-aside__chip--closed {
  background: var(--soft);
  color: var(--on-fill);
}

.phase-aside__winner {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.winner-card {
  display: flex;
  align-items: stretch;
  gap: var(--sp-3);
  padding: var(--sp-3);
  background: var(--paper);
  border: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
  transition: border-color 120ms ease, transform 120ms ease;
}
.winner-card:hover,
.winner-card:focus-visible {
  border-color: var(--accent);
  transform: translateY(-1px);
}
.winner-card__art {
  flex: 0 0 auto;
}
.winner-card__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  flex: 1 1 auto;
}
.winner-card__theme {
  font-style: italic;
}
.winner-card__title {
  word-break: break-word;
}
.winner-card__by {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}


.voters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.voter {
  width: 44px;
}
.voter .avatar--md {
  width: 36px;
  height: 36px;
  font-size: var(--fs-micro-xs);
}
.voter__name {
  display: block;
  text-align: center;
  font-size: var(--fs-micro-xs);
  line-height: 1.15;
  word-break: break-word;
  margin-top: 2px;
}

/* .voters--lg is the prominent open-state roster in the main column:
   bigger avatars so identity reads at a glance, wider cells so names
   fit without wrapping, and a readable micro-sm label underneath. */
.voters--lg {
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}
.voters--lg .voter { width: 76px; }
.voters--lg .voter .avatar--lg {
  width: 56px;
  height: 56px;
  font-size: var(--fs-body-sm);
}
.voters--lg .voter__name {
  font-size: var(--fs-micro-sm);
  margin-top: 4px;
}
.voters--lg .voter__voted-badge {
  width: 20px;
  height: 20px;
  font-size: 12px;
  bottom: -4px;
  right: -4px;
}

/* Submissions strip: voting-state preview. One compact horizontal
   card per submitted track (art on the left, title/artist on the
   right). Submitter identity stays hidden; the viewer's own track
   is flagged with an accent border + "YOURS" corner tag so it's
   findable at a glance. Replaces the old placeholder bracket-grid
   of anonymous colored squares. */
.submissions-strip {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}
/* The one vote CTA on the group page, placed where a reader arrives
   after scanning the candidates. Wraps rather than overflowing: the
   participation chip is nowrap by design, so on a narrow column the two
   need separate lines. */
.submissions-strip__cta {
  margin-top: var(--sp-4);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
}
.submissions-strip__cta .chip-marquee { flex: 0 0 auto; }

/* Aside empty state — a first-week group has no winner to show. */
.phase-aside__empty {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.phase-aside__empty p { margin: 0; }
.submission-card {
  position: relative;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-3);
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
}
.submission-card.is-mine {
  border-color: var(--accent);
  box-shadow: var(--shadow-card-accent);
}
.submission-card__art {
  width: 64px;
  height: 64px;
}
.submission-card__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.submission-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
  line-height: 1.1;
  word-break: break-word;
}
.submission-card__tag {
  position: absolute;
  top: -8px;
  right: 12px;
  background: var(--accent);
  color: var(--paper);
  border: var(--border-width) solid var(--ink);
  padding: 2px 6px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro-xs);
  letter-spacing: var(--ls-mono-lg);
  font-weight: 700;
  text-transform: uppercase;
}
@media (min-width: 720px) {
  .submissions-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ─── Bracket strip: per-round vertical list of submission cards
   grouped into matchup pairs. Each round has a header + a list of
   matchup-groups; each group wraps the two competing cards under a
   "matchup N" stamp with an accent rail so the pairing reads at a
   glance. The whole pair is a single deep link to /vote?m=<index>
   for the viewer's votable matchups; past rounds, byes, and
   self-matchups render as static groups. */
.bracket-strip__explainer {
  margin-top: var(--sp-3);
  margin-bottom: var(--sp-2);
  line-height: 1.4;
}
.bracket-strip {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}
.bracket-strip__rule {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: var(--sp-4) 0 var(--sp-2);
}
.bracket-strip__rule::before,
.bracket-strip__rule::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--ink);
  image-rendering: pixelated;
}
.bracket-strip__rule-ornament {
  font-family: var(--font-mono);
  font-size: var(--fs-micro-sm);
  letter-spacing: var(--ls-mono-lg);
  color: var(--dim);
}
.bracket-round {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-4) var(--sp-4) var(--sp-5);
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
}
.bracket-round.is-pending {
  opacity: 0.7;
  background: var(--paper);
  border-style: dashed;
  box-shadow: none;
}
.bracket-round.is-closed {
  background: var(--paper);
}
.bracket-round.is-current {
  border-color: var(--accent);
  box-shadow: var(--shadow-card-accent);
}
details.bracket-round > summary { cursor: pointer; }
details.bracket-round > summary::-webkit-details-marker { display: none; }
details.bracket-round > summary::marker { content: ""; }
details.bracket-round:not([open]) > summary {
  padding-bottom: 0;
  border-bottom: none;
}
details.bracket-round:not([open]) {
  gap: 0;
  padding-bottom: var(--sp-4);
}
.bracket-round__chevron {
  font-family: var(--font-mono);
  color: var(--dim);
  flex-shrink: 0;
}
.bracket-round__chevron::before { content: "▸"; }
.bracket-round[open] .bracket-round__chevron::before { content: "▾"; }
.bracket-round.is-current .bracket-round__chevron { color: var(--accent); }
.bracket-round__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-3);
  padding-bottom: var(--sp-3);
  border-bottom: var(--border-width) solid var(--ink);
}
.bracket-round.is-pending .bracket-round__head {
  border-bottom-style: dashed;
}
.bracket-round__title {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  min-width: 0;
}
.bracket-round__num {
  margin: 0;
  color: var(--ink);
  text-transform: lowercase;
}
.bracket-round.is-current .bracket-round__num { color: var(--accent); }
.bracket-round.is-closed .bracket-round__num { color: var(--accent-2); }
.bracket-round.is-pending .bracket-round__num { color: var(--dim); }
.bracket-round__status {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
  flex-shrink: 0;
}
.bracket-round__state {
  text-transform: uppercase;
  letter-spacing: var(--ls-mono-sm);
  flex-shrink: 0;
}
.bracket-round.is-closed .bracket-round__state {
  background: var(--accent-2);
  color: var(--paper);
}
.bracket-round__closes {
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
  font-weight: 700;
  color: var(--accent);
  text-transform: uppercase;
  letter-spacing: var(--ls-mono-sm);
  white-space: nowrap;
}
.bracket-round__closes [data-countdown] {
  font-variant-numeric: tabular-nums;
}
.bracket-round__placeholder {
  padding: var(--sp-4);
  text-align: center;
  color: var(--dim);
}
.bracket-round__groups {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.matchup-group {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding-left: var(--sp-3);
  border-left: 3px solid var(--accent-2);
}
.matchup-group.is-self { border-left-color: var(--tertiary); }
.bracket-round.is-closed .matchup-group { border-left-color: var(--ink); opacity: 0.85; }
.matchup-group__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-2);
}
.matchup-group__label {
  color: var(--accent-2);
}
.matchup-group.is-self .matchup-group__label { color: var(--ink); }
.bracket-round.is-closed .matchup-group__label { color: var(--ink); }
.matchup-group__cta {
  text-decoration: none;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--ls-mono-sm);
}
.matchup-group__cta:hover { text-decoration: underline; }
.matchup-group__pair {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

/* Per-card emphasis carried over from the flat submissions strip;
   plus the new winner / pick / eliminated states for closed rounds
   and saved votes. */
.submission-card { position: relative; }
.submission-card.is-mine .submission-card__title { color: var(--accent); }
.submission-card.is-my-pick {
  border-color: var(--accent-2);
  box-shadow: 3px 3px 0 var(--accent-2);
}
.submission-card.is-winner {
  border-color: var(--accent);
  box-shadow: var(--shadow-card-accent);
}
.submission-card.is-eliminated {
  opacity: 0.5;
  filter: saturate(0.55);
}
.submission-card.is-eliminated .submission-card__title {
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}
.submission-card__tags {
  position: absolute;
  top: -10px;
  right: 10px;
  display: flex;
  gap: 4px;
  z-index: 1;
}
.submission-card__tags > .submission-card__tag {
  position: static;
  top: auto;
  right: auto;
}
.submission-card__tag--pick { background: var(--accent-2); color: var(--paper); }
.submission-card__tag--won  { background: var(--ink); color: var(--paper); }
.submission-card__tag--bye {
  background: var(--paper);
  color: var(--dim);
  border-style: dashed;
}

/* Auto-advance group: byes for the round collected at the bottom under
   a small heading, rendered as a compact single-card list so they
   don't visually compete with the head-to-head matchups above. */
.bracket-round__byes {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.bracket-round__byes-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.bracket-round__byes-label {
  background: var(--paper);
  color: var(--dim);
  border-style: dashed;
}
.bracket-round__byes-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}
.bye-card {
  position: relative;
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-1) var(--sp-2);
  background: var(--paper);
  border-left: 3px solid var(--line);
  opacity: 0.9;
}
.bye-card.is-mine { border-left-color: var(--accent); }
.bye-card__art {
  width: 36px;
  height: 36px;
  background: repeating-linear-gradient(
    45deg,
    var(--paper),
    var(--paper) 6px,
    var(--paper-hi) 6px,
    var(--paper-hi) 12px
  );
}
.bye-card__meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.bye-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-body);
  line-height: 1.1;
  color: var(--dim);
  word-break: break-word;
}
.bye-card.is-mine .bye-card__title { color: var(--accent); }
.bye-card__tags {
  display: flex;
  gap: 4px;
  flex-shrink: 0;
}
.bye-card__tags > .submission-card__tag {
  position: static;
}

/* Non-voter strip: condensed avatar cluster beneath each closed bracket
   round listing members who cast zero votes that round. Mirrors the
   structure of the byes section so the round body has a consistent
   "footer" rhythm; uses dimmer treatment to feel less prominent than
   byes (auto-advance is procedural, non-voters is informational). */
.bracket-round__nonvoters {
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
  border-top: 1px dashed var(--line);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.bracket-round__nonvoters-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.bracket-round__nonvoters-label {
  background: var(--paper);
  color: var(--dim);
  border-style: dashed;
}
.bracket-round__nonvoters-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.nonvoter-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 56px;
  opacity: 0.8;
}
.nonvoter-chip__name {
  max-width: 64px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--dim);
}

@media (max-width: 600px) {
  .matchup-group {
    padding-left: var(--sp-2);
  }
}

/* Your-pick card: compact "you're set" callout at the top of the
   round body when the viewer has already submitted. Album art on the
   left (64px square), track metadata + change link on the right. The
   empty variant is the reverse nudge: no art, just a "submit now" CTA. */
.your-pick-card {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-3) var(--sp-4);
  margin-bottom: var(--sp-4);
}
/* Accent banner spanning the full card width when the viewer's track
 * still needs a YouTube match. Full-bleed (negative margins) so it reads
 * as a band attached to the card, not a button floating inside it. */
.your-pick-card__nudge {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin: var(--sp-3) calc(-1 * var(--sp-4)) calc(-1 * var(--sp-3));
  padding: var(--sp-2) var(--sp-4);
  background: var(--accent-2);
  color: var(--paper);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: var(--fs-micro-sm);
  letter-spacing: var(--ls-mono-sm);
  text-transform: uppercase;
  border-top: var(--border-width) solid var(--ink);
}
.your-pick-card__nudge:hover { background: var(--accent); color: var(--paper); }
.your-pick-card__nudge-label { min-width: 0; }
.your-pick-card__nudge-cta { white-space: nowrap; opacity: 0.9; }
.your-pick-card__art {
  width: 72px;
  height: 72px;
  flex-shrink: 0;
}
.your-pick-card__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.your-pick-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
  line-height: 1.1;
  word-break: break-word;
}
.your-pick-card__change {
  align-self: flex-start;
  margin-top: 6px;
}
.your-pick-card--empty {
  grid-template-columns: 1fr;
  padding: var(--sp-4);
  text-align: left;
}
.your-pick-card--empty .btn { align-self: flex-start; margin-top: 6px; }
.voter__voted-badge {
  width: 14px;
  height: 14px;
  font-size: 10px;
  bottom: -3px;
  right: -3px;
}

/* Standings is promoted to its own full-width section below the current
 * round on the group page. One roomy row per member with avatar, rank,
 * name, and score — the rank now gets display-md weight so the column
 * pops. A collapsible drawer below holds per-member win history. */
.standings-section {
  padding-top: var(--sp-6);
}
.standings { display: flex; flex-direction: column; gap: var(--sp-3); }
.standings__head { margin-bottom: 0; }
.standings__list {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
  row-gap: var(--sp-2);
}
.standings__row {
  display: grid;
  grid-template-columns: 36px 64px 1fr auto;
  gap: var(--sp-3);
  padding: var(--sp-3) 0;
  border-bottom: 1px dotted var(--line);
  align-items: center;
  min-width: 0;
}
/* Pending members read as "not done yet" via a dimmed avatar — but
   keep the rank/name/score fully legible so the leaderboard stays
   readable at a glance. */
/* A member who still owes something reads as pending via a desaturated
   avatar. saturate() drops the colour without dropping luminance, so the
   initials keep their contrast against their own tile — opacity blended
   both toward the page background and landed at 1.9:1. */
.standings__row:not(.is-done) .standings__avatar { filter: saturate(0.25); }
.standings__rank {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  color: var(--dim);
  line-height: 1;
  letter-spacing: 0;
}
.standings__rank.accent { color: var(--accent); }
.standings__avatar {
  /* Inherits voter__avatar-wrap positioning so the badge sits on the
     bottom-right of the avatar. justify-self centers the avatar in
     the dedicated 64px column. */
  justify-self: center;
  display: inline-flex;
}
.standings__who {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.standings__name {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: var(--fs-body);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.standings__row.is-you .standings__name { font-weight: 800; color: var(--accent); }
.standings__score {
  color: var(--dim);
  letter-spacing: var(--ls-mono-sm);
  white-space: nowrap;
}
.standings__wins {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.standings__status {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}
.status-chip {
  display: inline-flex;
  align-items: center;
  padding: 2px 6px;
  border: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-xs);
  letter-spacing: var(--ls-mono-sm);
  background: var(--paper);
  color: var(--dim);
  white-space: nowrap;
}
.status-chip.is-on {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--ink);
}
.status-chip.is-partial {
  background: var(--accent);
  color: var(--paper);
  border-color: var(--ink);
}
.status-chip.is-off {
  background: var(--paper);
  color: var(--dim);
  border-style: dashed;
}
.win-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 2px 6px;
  background: var(--paper);
  border: 1px solid var(--line);
  text-decoration: none;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-xs);
  letter-spacing: var(--ls-mono-sm);
}
.win-pill:hover {
  color: var(--ink);
  border-color: var(--ink);
  box-shadow: var(--shadow-sm);
}
.win-pill__art {
  width: 14px;
  height: 14px;
  background-size: cover;
  background-position: center;
  border: 1px solid var(--ink);
  flex-shrink: 0;
}
.win-pill__art--blank { background: var(--accent-2); }

/* ─── Past rounds carousel ─── */

.past-rounds-strip {
  padding-top: var(--sp-4);
}
.past-rounds-strip__scroll {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: var(--sp-2);
  scroll-snap-type: x proximity;
}
.past-round-card {
  flex: 0 0 160px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 10px;
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-btn);
  text-decoration: none;
  color: inherit;
  scroll-snap-align: start;
}
.past-round-card:hover { color: var(--ink); box-shadow: var(--shadow-card); transform: translate(-1px, -1px); }
.past-round-card__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.past-round-card .display-sm {
  font-size: var(--fs-display-sm);
  line-height: 1.05;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ─── Owner management cluster ─── */

.group-management__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-4);
}
.group-management__body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin-top: var(--sp-2);
}
.kv {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px var(--sp-3);
  margin: 0;
}
.kv dt { font-family: var(--font-mono); color: var(--dim); font-size: var(--fs-micro-sm); }
.kv dd { margin: 0; font-family: var(--font-mono); font-size: var(--fs-micro-sm); }
.readonly-input {
  width: 100%;
  padding: 6px 10px;
  border: var(--border-width) solid var(--ink);
  background: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
}

@media (max-width: 900px) {
  .round-section__grid {
    grid-template-columns: 1fr;
  }
  .round-section__aside {
    border-left: none;
    padding-left: 0;
    border-top: var(--border-width) solid var(--line);
    padding-top: var(--sp-4);
  }
  .bracket-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .status-banner {
    grid-template-columns: 1fr;
  }
  .status-banner__cta { justify-self: start; }
  /* Tighter avatar column + smaller avatar inside the merged
     standings row on narrow screens. The badge already shrinks
     via the .voter__voted-badge mobile override above. */
  .standings__row {
    grid-template-columns: 28px 44px 1fr auto;
    gap: var(--sp-2);
  }
  .standings__avatar .avatar--lg {
    width: 40px;
    height: 40px;
    font-size: 12px;
  }
}
@media (max-width: 560px) {
  .bracket-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }
}

/* ─── Vote (tournament, single matchup) ─────────────────────── */

.masthead--vote .masthead__title {
  font-size: 40px;
}

.vote-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.vote-mini-head { display: none; }  /* desktop: hidden; mobile: shown via breakpoint */
.ab-tabs__cta   { display: none; }  /* desktop: hidden; mobile: shown via breakpoint */

.vote-card-pair {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 48px minmax(0, 1fr);
  gap: var(--sp-4);
  align-items: stretch;
  margin-top: var(--sp-6);
}
.vote-card-pair .vs {
  align-self: center;
  padding-top: var(--sp-6);
  font-size: 44px;
}

.vote-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 20px;
  position: relative;
  min-width: 0;
}
/* Corner tag pokes above the card border, exactly like the mockup's
 * "◆ TRACK A" notch — a thin paper-coloured pill punching through. */
.vote-card__tag {
  position: absolute;
  top: -11px;
  left: 16px;
  padding: 0 8px;
  background: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  color: var(--ink);
  font-weight: 700;
  line-height: 1;
}

.vote-card__head {
  display: grid;
  grid-template-columns: 130px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}
.vote-card__head .art-tile {
  width: 130px;
  height: 130px;
  flex-shrink: 0;
}
.vote-card__info {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.vote-card__title {
  font-family: var(--font-display);
  font-size: 28px;
  line-height: 1.05;
  /* Wrap at natural spaces; only break mid-word if a single word
   * genuinely overflows (rare — the card is 500-600px wide on
   * desktop so most titles fit on one line). */
  overflow-wrap: break-word;
}
.vote-card__artist { margin-top: 2px; }
.vote-card__listen-row {
  margin-top: 10px;
  display: flex;
  gap: 6px;
  align-items: stretch;
}
.vote-card__also-on { margin-top: 6px; }
.vote-card__divider {
  border-top: 1px dotted var(--ink);
  margin: 2px 0;
}

/* Listen button: teal square, Nunito bold — replaces the legacy
 * rounded .listen-btn from app.css within the vote context. */
.vote-card__listen-row {
  display: flex;
  gap: 6px;
  align-items: stretch;
  flex-wrap: wrap;
}
.vote-card__listen-row .listen-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: var(--accent-2);
  color: var(--paper);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-btn);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: var(--fs-body-sm);
  text-decoration: none;
  border-radius: 0;
  white-space: nowrap;
  /* Don't shrink below the button's natural width — titles and
   * artist lines wrap to make room instead. */
  flex: 0 0 auto;
}
.vote-card__listen-row .listen-btn:hover { color: var(--paper); }
.vote-card__listen-row .listen-btn .svc-icon {
  width: 14px;
  height: 14px;
}
.listen-caret {
  position: relative;
}
.listen-caret > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 100%;
  min-height: 36px;
  padding: 0 10px;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-width) solid var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
}
.listen-caret > summary::-webkit-details-marker { display: none; }
.listen-caret > summary::marker { content: ""; }
.listen-caret[open] > summary { background: var(--accent-2); color: var(--paper); }
.listen-caret > ul {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 5;
  background: var(--paper);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-btn);
  min-width: 160px;
  padding: 6px 0;
  margin: 0;
  list-style: none;
}
.listen-caret > ul li { margin: 0; }
.listen-caret > ul a {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  color: var(--ink);
  text-decoration: none;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
}
.listen-caret > ul a:hover { color: var(--ink); background: var(--paper-hi); }

/* Live pick state via CSS :has() — falls back to `.is-picked` for
 * browsers without :has() support. */
.vote-card:has(input[name="pick"]:checked),
.vote-card.is-picked {
  box-shadow: var(--shadow-card-lg-accent);
}
.vote-card:has(input[name="pick"]:checked) .vote-card__tag,
.vote-card.is-picked .vote-card__tag {
  color: var(--accent);
}

/* Pick CTA fills the card width; accent background when selected. */
.pick-cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 12px 16px;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-btn);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
}
.pick-cta:hover { color: var(--ink); }
.pick-cta:has(input:checked),
.pick-cta.is-picked {
  background: var(--accent);
  color: var(--paper);
}
.pick-cta:has(input:checked):hover,
.pick-cta.is-picked:hover { color: var(--paper); }
.pick-cta__bullet {
  display: inline-block;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: transparent;
  box-shadow: inset 0 0 0 2px var(--ink);
  flex-shrink: 0;
}
.pick-cta:has(input:checked) .pick-cta__bullet,
.pick-cta.is-picked .pick-cta__bullet {
  background: var(--paper);
  box-shadow: inset 0 0 0 2px var(--accent);
}
.pick-cta__ext { display: none; }  /* desktop: short label; mobile enables the " : Track X" extension */

/* Rate + comment live on one row under the pick CTA on desktop. */
.vote-card__optional-label {
  margin: 6px 0 4px;
}
.vote-card__rate-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: stretch;
}

.rating {
  display: flex;
  gap: 4px;
  align-items: center;
  flex-wrap: nowrap;
}
.rating__btn {
  cursor: pointer;
  user-select: none;
  min-width: 22px;
  height: 22px;
  padding: 0 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-width) solid var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-micro-sm);
  font-weight: 700;
  line-height: 1;
}
.rating__btn.is-on { background: var(--ink); color: var(--paper); }

.rating:has(.rating__btn input[value="5"]:checked) .rating__btn { background: var(--ink); color: var(--paper); }
.rating:has(.rating__btn input[value="4"]:checked) .rating__btn:nth-of-type(1),
.rating:has(.rating__btn input[value="4"]:checked) .rating__btn:nth-of-type(2),
.rating:has(.rating__btn input[value="4"]:checked) .rating__btn:nth-of-type(3),
.rating:has(.rating__btn input[value="4"]:checked) .rating__btn:nth-of-type(4) { background: var(--ink); color: var(--paper); }
.rating:has(.rating__btn input[value="3"]:checked) .rating__btn:nth-of-type(1),
.rating:has(.rating__btn input[value="3"]:checked) .rating__btn:nth-of-type(2),
.rating:has(.rating__btn input[value="3"]:checked) .rating__btn:nth-of-type(3) { background: var(--ink); color: var(--paper); }
.rating:has(.rating__btn input[value="2"]:checked) .rating__btn:nth-of-type(1),
.rating:has(.rating__btn input[value="2"]:checked) .rating__btn:nth-of-type(2) { background: var(--ink); color: var(--paper); }
.rating:has(.rating__btn input[value="1"]:checked) .rating__btn:nth-of-type(1) { background: var(--ink); color: var(--paper); }

.comment-chip {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px 10px;
  border: 1px dashed var(--line);
  cursor: text;
  min-width: 0;
}
.comment-chip textarea {
  width: 100%;
  border: none;
  background: transparent;
  padding: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--ink);
  resize: vertical;
  min-height: 0;
  max-height: 6em;
}
.comment-chip textarea:focus { outline: none; }
.comment-chip:focus-within { border-color: var(--accent); border-style: solid; }
/* Collapse textarea into a dashed chip until the user focuses it — matches
 * the mockup's single-line "+ add a comment (optional)" look. */
.comment-chip textarea {
  height: 0;
  padding: 0;
  display: block;
  overflow: hidden;
}
.comment-chip:focus-within textarea,
.comment-chip:has(textarea:not(:placeholder-shown)) textarea {
  height: 4em;
  padding-top: 4px;
}

/* Sticky submit bar. Status pill on the left tells the viewer at a
 * glance whether the current matchup is voted; three-button row on
 * the right provides explicit prev/save/next so users never have to
 * lean on the browser back button.                                  */
.vote-submit-bar {
  position: sticky;
  bottom: 0;
  z-index: 10;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--paper);
  border-top: var(--border-width) solid var(--ink);
  margin: var(--sp-4) calc(var(--sp-8) * -1) 0;
}
.vote-submit-bar__status {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.vote-submit-bar__pos { letter-spacing: var(--ls-mono-sm); }
.vote-submit-bar__buttons {
  display: flex;
  gap: 8px;
  align-items: center;
}
.vote-submit-bar__nav { white-space: nowrap; }
.vote-submit-bar__nav[aria-disabled="true"] {
  pointer-events: none;
  opacity: 0.4;
}

.status-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: var(--ls-mono-lg);
  border: var(--border-width) solid var(--ink);
  align-self: flex-start;
}
.status-pill--done    { background: var(--ink); color: var(--paper); }
.status-pill--pending { background: var(--paper-hi); color: var(--ink); }

.vote-empty {
  padding: var(--sp-8);
  text-align: center;
}
.vote-empty p + p { margin-top: var(--sp-4); }

/* ─── Auth / welcome — centered paper card ───────────────────── */

.auth-shell {
  max-width: 480px;
  margin: var(--sp-8) auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: 0;
}
.auth-shell--wide { max-width: 560px; }
.auth-card {
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
  padding: var(--sp-6) var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  /* reset legacy app.css rules on the same class */
  border-radius: 0;
  max-width: none;
  margin: 0;
}
.auth-card__chip-row {
  display: flex;
  justify-content: flex-start;
}
.auth-card__title {
  font-family: var(--font-display);
  font-size: 40px;
  line-height: 1;
  letter-spacing: var(--ls-display);
  margin: 0;
}
.auth-card__sub {
  font-family: var(--font-hand);
  font-size: var(--fs-hand-md);
  color: var(--accent-2);
  margin: -6px 0 0;
  line-height: 1.1;
}
.auth-card__body {
  font-size: var(--fs-body);
}
.auth-card form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.auth-card label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
  color: var(--dim);
  text-transform: uppercase;
}
.auth-card label > small {
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  color: var(--dim);
  text-transform: none;
  letter-spacing: 0;
  margin-top: 2px;
}
.auth-card input[type="email"],
.auth-card input[type="password"],
.auth-card input[type="text"],
.auth-card input[type="file"],
.auth-card textarea,
.auth-card select {
  padding: 10px 12px;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-btn);
  font-family: var(--font-sans);
  font-size: var(--fs-body-lg);
  border-radius: 0;
  text-transform: none;
  letter-spacing: 0;
}
.auth-card textarea {
  width: 100%;
  min-height: 140px;
  line-height: 1.45;
  resize: vertical;
}
.auth-card input[type="file"] {
  font-size: var(--fs-body-sm);
  padding: 8px 10px;
}
.auth-card input:focus,
.auth-card textarea:focus,
.auth-card select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 2px 2px 0 var(--accent);
}
.auth-card button[type="submit"] {
  margin-top: var(--sp-2);
  align-self: flex-start;
}
.auth-card .error {
  background: var(--accent);
  color: var(--paper);
  padding: 8px 12px;
  border: var(--border-width) solid var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
}
.auth-card__footer {
  border-top: 1px dotted var(--ink);
  padding-top: var(--sp-3);
  margin-top: var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
  color: var(--dim);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: baseline;
}
.auth-card__footer a { color: var(--accent-2); text-decoration: underline; }
.auth-card__footer a:hover { color: var(--accent); }

.bug-form__honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}
.bug-form__reply {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
  color: var(--dim);
  margin: 0;
}
.bug-form__reply strong { color: var(--ink); }

.form-actions {
  display: flex;
  gap: var(--sp-3);
  align-items: center;
  flex-wrap: wrap;
  margin-top: var(--sp-2);
}
.form-actions .btn-link,
.btn-link {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
  color: var(--accent-2);
  text-decoration: underline;
}
.btn-link:hover { color: var(--accent); }

/* ─── Group create / settings — shared pickers ──────────────── */

.scheme-picker {
  border: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.scheme-picker legend {
  padding: 0 0 6px;
}
.scheme-picker__option {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
  padding: var(--sp-3);
  border: var(--border-width) solid var(--ink);
  background: var(--paper);
  cursor: pointer;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
}
.scheme-picker__option:hover { background: var(--paper-hi); }
.scheme-picker__option > span {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.scheme-picker__option input[type="radio"] {
  margin-top: 6px;
  accent-color: var(--accent);
  transform: scale(1.15);
}
.scheme-picker__option:has(input:checked) {
  border-color: var(--accent);
  box-shadow: var(--shadow-btn);
  background: var(--paper-hi);
}

.toggle-label {
  display: grid !important;
  grid-template-columns: auto 1fr !important;
  gap: var(--sp-3);
  align-items: start;
  padding: var(--sp-3);
  border: 1px dashed var(--line);
  cursor: pointer;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ink);
}
.toggle-label input[type="checkbox"] {
  margin-top: 4px;
  accent-color: var(--accent);
  transform: scale(1.25);
}
.toggle-label > span {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.toggle-label:has(input:checked) {
  border-color: var(--accent);
  background: var(--paper-hi);
}

.invite-code-input {
  text-transform: uppercase;
  letter-spacing: 4px !important;
  font-family: var(--font-mono) !important;
  font-size: 20px !important;
  text-align: center;
}

/* ─── Group settings ─────────────────────────────────────────── */

.settings-shell {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-top: var(--sp-4);
}
.settings-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.settings-card {
  max-width: none;
  padding: var(--sp-5);
  margin: 0;
}
.settings-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
}
.settings-footer {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
}

@media (max-width: 560px) {
  .settings-row { grid-template-columns: 1fr; }
}

/* ─── Start-round picker (group show page) ─────────────────────
 * Owner-only CTA. The <summary> keeps the .btn--primary pill; when the
 * details are open, the form below lives in a matching paper card that
 * mirrors the theme-ideas input treatment so the two panels feel like
 * siblings. Pills let the owner one-tap a popular pitch into the input;
 * "Surprise me" submits with mode=random so the server picks from the
 * pool. */

.start-round-picker { display: inline-block; }
.start-round-picker[open] > summary { margin-bottom: var(--sp-3); }
.start-round-picker__form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  min-width: min(420px, 100%);
  max-width: 520px;
}
.start-round-picker__field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.start-round-picker__input {
  width: 100%;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.35;
  color: var(--ink);
  background: var(--paper-hi);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-btn);
  padding: var(--sp-3);
}
.start-round-picker__input::placeholder {
  color: var(--dim);
  font-style: italic;
}
.start-round-picker__input:focus {
  outline: none;
  border-color: var(--accent-2);
  box-shadow: 3px 3px 0 var(--accent-2);
}
.start-round-picker__pool {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.start-round-picker__pills {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
}
.start-round-picker__pill {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  max-width: 100%;
  padding: 4px 10px;
  background: var(--paper);
  color: var(--ink);
  border: var(--border-width) solid var(--ink);
  box-shadow: 2px 2px 0 var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  cursor: pointer;
  transition: transform 80ms ease, box-shadow 80ms ease, background 80ms ease, color 80ms ease;
}
.start-round-picker__pill:hover {
  background: var(--accent-2);
  color: var(--paper);
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 var(--ink);
}
.start-round-picker__pill:active { transform: translate(1px, 1px); box-shadow: 1px 1px 0 var(--ink); }
.start-round-picker__pill-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 18em;
}
.start-round-picker__pill-count {
  font-variant-numeric: tabular-nums;
  color: var(--dim);
}
.start-round-picker__pill:hover .start-round-picker__pill-count { color: var(--paper); }
.start-round-picker__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
}

@media (max-width: 560px) {
  .start-round-picker__form { min-width: 0; }
  .start-round-picker__actions { justify-content: stretch; }
  .start-round-picker__actions .btn { flex: 1; }
}

/* ─── Theme ideas pool (group show page) ───────────────────────
 * The opt-in theme idea board. Members pitch round themes into a
 * shared pool; the owner picks one when starting a round. The form
 * sits at the top of the card with a live char counter, and each
 * idea renders below as a small index-card-style chit. */

.theme-ideas {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: var(--sp-4);
}
.theme-ideas__form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.theme-ideas__field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.theme-ideas__field-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.theme-ideas__input {
  width: 100%;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.35;
  color: var(--ink);
  background: var(--paper-hi);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-btn);
  padding: var(--sp-3);
  resize: vertical;
  min-height: 5em;
}
.theme-ideas__input::placeholder {
  color: var(--dim);
  font-style: italic;
}
.theme-ideas__input:focus {
  outline: none;
  border-color: var(--accent-2);
  box-shadow: 3px 3px 0 var(--accent-2);
}
.theme-ideas__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.theme-ideas__count { font-variant-numeric: tabular-nums; }

.theme-ideas__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--sp-3);
}
.theme-idea {
  position: relative;
  display: flex;
  gap: var(--sp-2);
  padding: var(--sp-3);
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-sm);
}
.theme-idea__body {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
  min-width: 0;
}
.theme-idea__text {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--fs-body-sm);
  line-height: 1.4;
  color: var(--ink);
  word-break: break-word;
}
.theme-idea__author {
  color: var(--dim);
  letter-spacing: var(--ls-mono-sm);
}
.theme-idea__delete {
  margin: 0;
  flex-shrink: 0;
}
.theme-idea__delete-btn {
  padding: 2px 8px;
  min-width: 0;
  font-size: 16px;
  line-height: 1;
  color: var(--dim);
}
.theme-idea__delete-btn:hover { color: var(--accent); }

/* Upvote pill sits to the left of the body. Stacked arrow + count so the
 * column stays narrow regardless of vote total. */
.theme-idea__vote {
  margin: 0;
  flex-shrink: 0;
}
.theme-idea__vote-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-width: 36px;
  padding: 4px 6px;
  background: var(--paper);
  color: var(--dim);
  border: var(--border-width) solid var(--ink);
  box-shadow: 2px 2px 0 var(--ink);
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
  line-height: 1;
  cursor: pointer;
  transition: transform 80ms ease, box-shadow 80ms ease, color 80ms ease, background 80ms ease;
}
.theme-idea__vote-btn:hover {
  color: var(--accent-2);
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 var(--ink);
}
.theme-idea__vote-btn:active { transform: translate(1px, 1px); box-shadow: 1px 1px 0 var(--ink); }
.theme-idea__vote-btn.is-voted {
  background: var(--accent-2);
  color: var(--paper);
}
.theme-idea__vote-arrow { font-size: 12px; }
.theme-idea__vote-count { font-variant-numeric: tabular-nums; font-weight: 700; }

.theme-ideas__empty {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-4);
  border: 1px dashed var(--line);
  text-align: center;
}
.theme-ideas__empty p { margin: 0; }
/* HTMX prepends new ideas above the server-rendered empty state
 * rather than replacing the list, so hide the empty stamp once a
 * real idea lands in the same list. */
.theme-ideas__list:has(.theme-idea) .theme-ideas__empty { display: none; }

@media (max-width: 560px) {
  .theme-ideas__list { grid-template-columns: 1fr; }
  .theme-ideas__footer { justify-content: flex-end; }
  .theme-ideas__footer .theme-ideas__count { margin-right: auto; }
}

/* ─── Ranked ballot ─────────────────────────────────────────── */

.ranked-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-top: var(--sp-4);
}
.ballot-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.ballot-item {
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.ballot-item--dragging { opacity: 0.6; }
.ballot-item__head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: center;
}
.ballot-item__controls {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding-right: var(--sp-3);
  border-right: 1px dotted var(--ink);
}
.ballot-item__controls .btn {
  min-width: 36px;
  padding: 4px 8px;
  font-size: 12px;
}
.ballot-item__controls .drag-handle {
  margin-top: 2px;
}
.drag-handle {
  font-family: var(--font-mono);
  font-size: 18px;
  color: var(--dim);
  cursor: grab;
  user-select: none;
  line-height: 1;
}
.drag-handle:active { cursor: grabbing; color: var(--accent); }
.ballot-rank {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  color: var(--accent);
  line-height: 1;
}
.ballot-item__track {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: var(--sp-3);
  min-width: 0;
}
.ballot-item__track .art-tile {
  width: 64px;
  height: 64px;
}
.ballot-item__meta { min-width: 0; }
.ballot-item__meta .display-sm {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
  line-height: 1.05;
}

.ballot-item__optional {
  margin-top: var(--sp-1);
  padding: var(--sp-2) var(--sp-3);
  border: 1px dashed var(--ink);
  background: var(--paper);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.ballot-item__optional-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.ballot-optional-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  padding: 2px 8px;
  background: var(--ink);
  color: var(--paper);
  font-weight: 700;
  text-transform: uppercase;
  border-radius: 2px;
}
.ballot-item__optional-body {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: center;
}
.ballot-item__optional-body .comment-chip { margin: 0; }

@media (max-width: 640px) {
  .ballot-item__head { grid-template-columns: 1fr; }
  .ballot-item__controls {
    flex-direction: row;
    border-right: none;
    border-bottom: 1px dotted var(--ink);
    padding: 0 0 var(--sp-2);
    gap: var(--sp-3);
    justify-content: space-between;
    align-items: center;
  }
  .ballot-item__controls .drag-handle { margin-top: 0; }
  .ballot-item__optional-body { grid-template-columns: 1fr; }
}

/* Ballot confirm modal — appears on submit so users see the final
   ranked order before it's committed. */
.ballot-confirm[hidden] { display: none; }
.ballot-confirm {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
}
.ballot-confirm__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(42, 26, 42, 0.55);
}
.ballot-confirm__panel {
  position: relative;
  width: min(560px, 100%);
  max-height: 88vh;
  overflow: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.ballot-confirm__head {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.ballot-confirm__head .display-sm { margin: 0; }
.ballot-confirm__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.ballot-confirm__row {
  display: grid;
  grid-template-columns: 2.5rem 56px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-2);
  border: 1px solid var(--ink);
  background: var(--paper);
}
.ballot-confirm__rank {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
  color: var(--accent);
  line-height: 1;
  text-align: center;
}
.ballot-confirm__row .art-tile { width: 56px; height: 56px; }
.ballot-confirm__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.ballot-confirm__meta .display-sm,
.ballot-confirm__meta .mono-sm {
  display: block;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ballot-confirm__foot {
  display: flex;
  justify-content: flex-end;
  gap: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: 1px dotted var(--ink);
}
body.modal-open { overflow: hidden; }

@media (max-width: 640px) {
  .ballot-confirm { padding: var(--sp-2); }
  .ballot-confirm__panel { width: 100%; max-height: 92vh; }
  .ballot-confirm__row { grid-template-columns: 2rem 48px minmax(0, 1fr); gap: var(--sp-2); }
  .ballot-confirm__row .art-tile { width: 48px; height: 48px; }
}

/* ─── Submit a song ──────────────────────────────────────────── */

.submit-shell {
  max-width: 640px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-top: var(--sp-4);
}
.submit-shell__footer {
  justify-content: center;
  text-align: center;
}
.submit-form-card {
  /* use auth-card styling but don't centre its container */
  max-width: none;
}
.submit-current {
  padding: var(--sp-4);
}
.submit-current__body {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--sp-3);
  margin-top: var(--sp-2);
  align-items: center;
}
.submit-current__body .art-tile { width: 56px; height: 56px; }

.mb-search-primary .mb-search-results {
  margin-top: var(--sp-3);
  max-height: 40vh;
  overflow-y: auto;
  border: 1px dotted var(--ink);
  padding: var(--sp-2);
}
.mb-search-primary .mb-search-results:empty {
  display: none;
}
.manual-entry {
  margin-top: var(--sp-2);
  border: 1px dashed var(--line);
  padding: var(--sp-3);
}
.manual-entry > summary {
  cursor: pointer;
  list-style: none;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-sm);
  color: var(--dim);
  text-transform: uppercase;
}
.manual-entry > summary::-webkit-details-marker { display: none; }
.manual-entry > summary::marker { content: ""; }
.manual-entry[open] > summary { color: var(--accent); margin-bottom: var(--sp-3); }
.manual-entry-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

/* ─── YouTube match-confirm step ─────────────────────────────── */

.yt-match-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: var(--sp-3);
}
.yt-match-card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
}
.yt-match-card__thumb {
  margin: calc(-1 * var(--sp-3)) calc(-1 * var(--sp-3)) 0;
  background: var(--ink);
  aspect-ratio: 16 / 9;
  overflow: hidden;
}
.yt-match-card__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.yt-match-card__body { min-width: 0; }
.yt-match-card__body .display-sm {
  font-size: var(--fs-display-sm);
  line-height: 1.15;
  word-break: break-word;
}
.yt-match-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-2);
  align-items: center;
}
.yt-match-card__actions .yt-pick-form { margin: 0; }
.yt-match-card__preview:empty { display: none; }
.yt-match-card__preview iframe {
  border: 0;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
}
.yt-match-card.is-official {
  box-shadow: var(--shadow-card-accent);
}
.yt-match-card__tag {
  align-self: flex-start;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  font-weight: 700;
  color: var(--accent);
  text-transform: uppercase;
  margin-bottom: var(--sp-1);
}
.yt-skip {
  display: flex;
  justify-content: center;
}

/* ─── Account ────────────────────────────────────────────────── */

.account-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  max-width: 720px;
  margin: 0 auto;
  padding-top: var(--sp-4);
}
.account-card {
  max-width: none;
  padding: var(--sp-5);
}
.account-card__body {
  margin-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

/* ─── API tokens (account page) ──────────────────────────────── */

/* One-time plaintext reveal. Loud on purpose: this is the only render
   of a credential the user can never get back. */
.token-reveal {
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  margin: var(--sp-4) 0;
  padding: var(--sp-3);
  border: var(--border-width-thick) solid var(--accent);
  box-shadow: var(--shadow-card-accent);
  background: var(--paper-hi);
}
.token-reveal__value {
  font-family: var(--font-mono);
  font-size: var(--fs-body-sm);
  /* Tokens are one long unbreakable run; wrap rather than overflow the
     card, and let a double-click select the whole thing. */
  word-break: break-all;
  user-select: all;
}

.token-list {
  list-style: none;
  margin: var(--sp-4) 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.token-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3);
  border: var(--border-width) solid var(--line);
}
.token-row__meta {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}
/* ─── Notifications / inbox ──────────────────────────────────── */

.inbox-body {
  max-width: 720px;
  margin: 0 auto;
  padding-top: var(--sp-4);
}
.inbox-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
/* Inbox rows mirror the .group-card shape: a leading tile on the left,
 * meta in the middle, timestamp on the right. Unread rows get the accent
 * left-border and the full card shadow so they read as louder than
 * already-seen items. */
.inbox-row {
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
}
.inbox-row.is-unread {
  border-left: 4px solid var(--accent);
}
.inbox-row__link {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  gap: var(--sp-3);
  align-items: center;
  padding: var(--sp-3) var(--sp-4);
  text-decoration: none;
  color: var(--ink);
}
.inbox-row__link:hover { color: var(--ink); background: var(--paper); }
.inbox-row__icon {
  width: 40px;
  height: 40px;
  background: var(--accent-2);
  color: var(--paper);
  border: var(--border-width) solid var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 22px;
  line-height: 1;
}
.inbox-row.is-unread .inbox-row__icon { background: var(--accent); }
.inbox-row__meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.inbox-row__title {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
}
.inbox-row__body {
  font-size: var(--fs-body-sm);
  color: var(--dim);
}
.inbox-row__stamp {
  white-space: nowrap;
  align-self: center;
}
@media (max-width: 560px) {
  .inbox-row__link {
    grid-template-columns: 36px minmax(0, 1fr);
    row-gap: 4px;
  }
  .inbox-row__icon { width: 36px; height: 36px; font-size: 20px; }
  .inbox-row__stamp { grid-column: 2 / -1; }
}
.inbox-empty {
  padding: var(--sp-8);
  text-align: center;
}
.inbox-empty p + p { margin-top: var(--sp-3); }

/* ─── Landing (unauthenticated) ───────────────────────────────
   Elevator-pitch hero: giant display headline, one-line premise,
   one big primary CTA. No feature enumeration — the landing is
   advertising, not documentation. */
.landing-hero {
  min-height: calc(100vh - 220px);
  max-width: 780px;
  margin: 0 auto;
  padding: var(--sp-8) var(--sp-4);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--sp-4);
}
.landing-hero__chip {
  margin-bottom: var(--sp-4);
}
.landing-hero__headline {
  font-family: var(--font-display);
  font-size: clamp(68px, 14vw, 132px);
  line-height: 0.88;
  letter-spacing: var(--ls-display-tight);
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0;
}
.landing-hero__headline-row { display: block; }
.landing-hero__headline-kicker {
  display: block;
  text-shadow: 4px 4px 0 var(--ink);
}
.landing-hero__pitch {
  font-family: var(--font-sans);
  font-size: var(--fs-body-lg);
  line-height: 1.5;
  max-width: 44ch;
  margin: var(--sp-4) 0 0;
}
.landing-hero__pitch em {
  font-family: var(--font-hand);
  font-style: normal;
  font-size: 1.5em;
  line-height: 0.9;
  color: var(--accent);
  letter-spacing: 0;
}
.landing-hero__cta {
  margin-top: var(--sp-5);
  font-size: 20px;
  padding: 14px 28px;
}
.landing-hero__alt {
  margin-top: var(--sp-3);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  text-transform: uppercase;
  color: var(--dim);
}
.landing-hero__alt a {
  color: var(--accent-2);
  font-weight: 700;
  text-decoration: underline;
}
.landing-hero__alt a:hover { color: var(--accent); }

@media (max-width: 560px) {
  .landing-hero {
    min-height: calc(100vh - 260px);
    padding: var(--sp-6) var(--sp-3);
  }
  .landing-hero__headline { font-size: clamp(56px, 18vw, 104px); }
  .landing-hero__pitch { font-size: var(--fs-body); }
  .landing-hero__headline-kicker { text-shadow: 3px 3px 0 var(--ink); }
}

/* ─── Listen page ────────────────────────────────────────────── */

.listen-body {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding-top: var(--sp-4);
  max-width: 960px;
  margin: 0 auto;
}
.listen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--sp-4);
  align-items: center;
  padding: var(--sp-4) var(--sp-5);
}
.listen-card--ok { background: var(--soft); color: var(--on-fill); }
.listen-card .display-sm {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
  line-height: 1.1;
  margin-top: 4px;
}
.listen-card .svc-icon { width: 16px; height: 16px; }
.listen-missing {
  list-style: none;
  margin: var(--sp-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.listen-missing li {
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: flex-start;
}
.listen-missing .art-tile { width: 56px; height: 56px; }
.listen-missing__meta { min-width: 0; }
.listen-missing-card {
  padding: var(--sp-4) var(--sp-5);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}

@media (max-width: 640px) {
  .listen-card { grid-template-columns: 1fr; align-items: flex-start; }
  .listen-card form, .listen-card .btn { width: 100%; }
}

/* ─── Round results ──────────────────────────────────────────── */

.masthead--results .masthead__title {
  font-size: 44px;
}
/* Results masthead byline: avatar + "submitted by" stamp on one line. */
.masthead__byline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: var(--sp-2);
  flex-wrap: wrap;
}
.masthead--results .masthead__right {
  gap: 8px;
}
.masthead--results .masthead__right .btn { white-space: nowrap; }

.results-body {
  display: grid;
  grid-template-columns: 0.9fr 1.3fr;
  gap: var(--sp-8);
  align-items: start;
  padding-top: var(--sp-4);
}
.results-body__left {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}
.results-body__right {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

/* Winner spotlight — inverse (accent) card with art, title, submitter,
 * listen CTA. Cheer-y centrepiece of the results page.
 *
 * Scoped to .results-body: group_phase.html uses the same .winner-card
 * class for a compact horizontal row in the aside, and these rules —
 * being later in the file — were silently overriding it into a tall
 * centred column with 180px art. */
.results-body .winner-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 10px;
  padding: var(--sp-5);
}
.results-body .winner-card__art {
  width: 180px;
  height: 180px;
}
.winner-card__title {
  font-family: var(--font-display);
  font-size: var(--fs-display-lg);
  line-height: 1;
  margin-top: 6px;
}
.winner-card__artist { opacity: 0.9; }
.winner-card__submitter {
  opacity: 0.95;
  margin-top: var(--sp-2);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
}
.winner-card__submitter .submitted-by {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  text-transform: uppercase;
  opacity: 0.85;
}
.ranking-thread__submitter {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 2px;
}
/* Celebratory "WINNER" heading — display-xl with an ink drop-shadow so
   the word itself feels like a victory stamp. Dropped one notch on
   mobile so it doesn't clip the 375px viewport. */
.winner-heading {
  font-family: var(--font-display);
  font-size: var(--fs-display-xl);
  line-height: 0.95;
  color: var(--accent);
  letter-spacing: var(--ls-display-tight);
  margin: 0 0 var(--sp-3);
  text-shadow: 3px 3px 0 var(--ink);
}
@media (max-width: 560px) {
  .winner-heading { font-size: 44px; text-shadow: 2px 2px 0 var(--ink); }
}
.winner-card__listen {
  margin-top: var(--sp-3);
  background: var(--paper);
  color: var(--ink);
  border-color: var(--ink);
}
.winner-card__listen:hover { color: var(--ink); }
.winner-card__also-on { opacity: 0.9; margin-top: 6px; }

.results-stats .stats-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}
.stats-grid__cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  align-items: flex-start;
}
.stats-grid__num {
  font-family: var(--font-display);
  font-size: 28px;
  line-height: 1;
  color: var(--accent);
}
.stats-grid__num small {
  font-size: 16px;
  margin-left: 2px;
}

.winner-rating__stars {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  margin-top: 6px;
}

/* Ranking thread cards — one per submission, rank + track + comments. */
.ranking-threads {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
  padding: 0;
  margin: 0;
  list-style: none;
}
.ranking-thread {
  background: var(--paper-hi);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
  padding: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.ranking-thread.is-winner { box-shadow: var(--shadow-card-accent); }
.ranking-thread__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-3);
}
.ranking-thread__track {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: start;
}
.ranking-thread__track .art-tile {
  width: 80px;
  height: 80px;
}
.ranking-thread__meta { min-width: 0; }
.ranking-thread__meta .display-sm {
  font-family: var(--font-display);
  font-size: var(--fs-display-sm);
  line-height: 1.05;
}
.ranking-thread__listen {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 6px 10px;
  background: var(--accent-2);
  color: var(--paper);
  border: var(--border-width-thick) solid var(--ink);
  box-shadow: var(--shadow-btn);
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: var(--fs-micro);
  text-decoration: none;
  border-radius: 0;
  margin-top: 6px;
}
.ranking-thread__listen:hover { color: var(--paper); }
.ranking-thread__comments {
  border-top: 1px dotted var(--ink);
  padding-top: var(--sp-3);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.ranking-thread__comments ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.thread__comment {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  gap: var(--sp-3);
  align-items: start;
}
.thread__comment-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.thread__comment-name { font-weight: 700; }
.thread__text {
  font-size: var(--fs-body-sm);
  line-height: 1.35;
}
.ranking-thread__empty {
  border-top: 1px dotted var(--ink);
  padding-top: var(--sp-3);
}

/* Bottom actions — matches the handoff footer pattern on results. */
.results-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--sp-4);
  padding-top: var(--sp-4);
  flex-wrap: wrap;
}
.results-actions__buttons {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

@media (max-width: 900px) {
  .results-body {
    grid-template-columns: 1fr;
  }
  .masthead--results .masthead__right {
    flex-direction: row;
    flex-wrap: wrap;
  }
}

/* Done-state card — rendered after the viewer submits their last
 * matchup. Soft teal background so it reads as "done / peaceful" and
 * not as another action. The progress bar above stays interactive
 * so voters can jump back into any matchup to review. */
.vote-done {
  padding: var(--sp-8) var(--sp-6);
  text-align: center;
  background: var(--soft);
  color: var(--on-fill);
  margin-top: var(--sp-6);
}
/* Everything inside inherits the fixed-fill ink, including the tokens
   that would otherwise flip with the theme. */
.vote-done .stamp,
.vote-done__hint,
.vote-done .dim { color: var(--on-fill-dim); }
.vote-done .btn--ghost { color: var(--on-fill); border-color: var(--on-fill); }
.vote-done__title {
  font-family: var(--font-display);
  font-size: 44px;
  line-height: 1;
  margin-top: var(--sp-3);
}
.vote-done__sub {
  margin-top: var(--sp-3);
  color: var(--ink);
  opacity: 0.85;
  max-width: 48ch;
  margin-left: auto;
  margin-right: auto;
}
.vote-done__buttons {
  margin-top: var(--sp-5);
  display: flex;
  justify-content: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
}
.vote-done__hint {
  margin-top: var(--sp-5);
}

/* A/B tabs: hidden on desktop, shown on mobile — clicking toggles
 * which card is visible via data-ab-active on .vote-card-pair.
 * !important is belt-and-braces against components.css which defines
 * its own unconditional `.ab-tabs { display: flex }`. */
.ab-tabs { display: none !important; }
@media (max-width: 600px) {
  .ab-tabs { display: flex !important; }
}

@media (max-width: 600px) {
  /* Hide the big masthead and replace with the compact mini-head.
   * Two rows: context (back link · round info · countdown), then a
   * prominent "listen to all" button so engaging with the tracks is
   * one tap away on mobile. */
  .masthead--vote { display: none; }
  .vote-mini-head {
    display: grid;
    grid-template-columns: auto 1fr auto;
    grid-template-areas:
      "back meta countdown"
      "listen listen listen";
    align-items: center;
    padding: var(--sp-2) var(--page-pad);
    /* Bleed to the page edge. Must track --page-pad exactly: a hardcoded
       --sp-4 here was wider than the gutter on a phone and pushed the
       whole vote page sideways. */
    margin-inline: calc(var(--page-pad) * -1);
    border-bottom: var(--border-width) solid var(--ink);
    gap: var(--sp-2) var(--sp-3);
  }
  .vote-mini-head__back     { grid-area: back; }
  .vote-mini-head__meta     { grid-area: meta; text-align: center; }
  .vote-mini-head__countdown { grid-area: countdown; }
  .vote-mini-head__listen {
    grid-area: listen;
    justify-self: stretch;
    margin-top: var(--sp-2);
  }

  .ab-tabs__cta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: var(--sp-3);
  }
  .ab-tabs__cta .stamp { font-size: var(--fs-micro); }

  .ab-tabs {
    display: flex;
    gap: 8px;
    margin-top: var(--sp-2);
  }
  .ab-tabs__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    flex: 1;
    padding: 10px 12px;
    background: var(--paper-hi);
    color: var(--ink);
    border: var(--border-width-thick) solid var(--ink);
    box-shadow: var(--shadow-btn);
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-mono-lg);
    font-weight: 700;
    cursor: pointer;
  }
  .ab-tabs__btn.is-active {
    background: var(--accent);
    color: var(--paper);
    box-shadow: none;
  }
  .ab-tabs__pick-pill {
    background: var(--ink);
    color: var(--paper);
    padding: 2px 6px;
    font-size: var(--fs-micro-xs);
    letter-spacing: var(--ls-mono-sm);
    border: 1px solid var(--ink);
  }
  /* On the active (pink) tab, swap the pill to paper-on-ink-border so
   * "PICK" stays legible without merging into the accent background. */
  .ab-tabs__btn.is-active .ab-tabs__pick-pill {
    background: var(--paper);
    color: var(--ink);
  }

  .vote-card-pair {
    grid-template-columns: 1fr;
    margin-top: var(--sp-3);
  }
  .vote-card-pair .vs { display: none; }
  .vote-card-pair[data-ab-active="a"] .vote-card--b,
  .vote-card-pair[data-ab-active="b"] .vote-card--a {
    display: none;
  }

  /* Stack card contents vertically, centred, like the mockup.
   * The corner tag is redundant on mobile — the active A/B tab
   * already labels which track is showing. */
  .vote-card__tag { display: none; }
  .vote-card {
    gap: 12px;
    padding: 16px 14px;
  }
  .vote-card__head {
    grid-template-columns: 1fr;
    gap: 12px;
    justify-items: center;
    text-align: center;
  }
  .vote-card__head .art-tile {
    width: 190px;
    height: 190px;
  }
  .vote-card__info {
    align-items: center;
    text-align: center;
    width: 100%;
  }
  .vote-card__title {
    font-size: 26px;
  }
  .vote-card__listen-row {
    width: 100%;
    justify-content: stretch;
  }
  .vote-card__listen-row .listen-btn { flex: 1; justify-content: center; }

  .pick-cta { padding: 14px 12px; font-size: 15px; }
  .pick-cta__ext { display: inline; }

  /* RATE buttons stretch full-width like the mockup. */
  .vote-card__rate-row {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .rating { width: 100%; }
  .rating__btn {
    flex: 1;
    min-width: 0;
    height: 32px;
    font-size: 13px;
  }

  /* Mobile submit bar: status pill on top, prev/save/next as a row of
   * equal-width buttons underneath so the user can always navigate. */
  .vote-submit-bar {
    flex-direction: column;
    align-items: stretch;
    gap: var(--sp-2);
    margin: var(--sp-4) calc(var(--sp-4) * -1) 0;
  }
  .vote-submit-bar__buttons {
    width: 100%;
    gap: 6px;
  }
  .vote-submit-bar__buttons .btn {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    padding-left: 8px;
    padding-right: 8px;
  }
  .vote-submit-bar__save { flex: 1.4 !important; }  /* save is the primary; nudge it wider */
}

/* ─── Prose pages (privacy, terms, contact, unsubscribe) ────────────────── */

.prose-page {
  max-width: 780px;
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  font-family: var(--font-sans);
  line-height: 1.6;
}
.prose-page h1,
.prose-page h2 {
  font-family: var(--font-display);
  letter-spacing: var(--ls-display-tight);
  margin: 0;
}
.prose-page__title {
  font-size: clamp(44px, 8vw, 72px);
  line-height: 0.95;
}
.prose-page h2 {
  font-size: clamp(22px, 3vw, 28px);
  margin-top: var(--sp-4);
}
.prose-page__sub {
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--ls-mono-lg);
  text-transform: uppercase;
  color: var(--dim);
  margin: 0;
}
.prose-page p,
.prose-page ul {
  margin: 0;
}
.prose-page ul {
  padding-left: var(--sp-4);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}
.prose-page a {
  color: var(--accent-2);
  text-decoration: underline;
}
.prose-page a:hover { color: var(--accent); }
.prose-page__contact {
  font-family: var(--font-mono);
  font-size: var(--fs-body-lg);
  padding: var(--sp-3) 0;
}
.consent-row {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  margin: var(--sp-3) 0;
  line-height: 1.4;
}
.consent-row input[type="checkbox"] {
  margin-top: 3px;
}
.footer__legal {
  display: inline;
}
.footer__legal a {
  color: inherit;
  text-decoration: underline;
}

/* ═══════════════════════════════════════════════════════════════════
 * VOTE PAGE — candidate grid
 *
 * The single-pick rework shipped vote.html with .candidate-grid,
 * .pick-form and .theme-ribbon unstyled, so the page rendered as a bare
 * <ol>: one 570px card per row, five rows, a 1300px-wide "Pick this
 * one" button on each. Picking a favourite is a *comparison* task, and
 * comparison needs the options on screen together — a 3594px single
 * column makes you hold four tracks in your head while you scroll to
 * the fifth.
 * ═══════════════════════════════════════════════════════════════════ */

/* The grid sits outside .pick-form (forms can't nest, and each card holds a
   rate/comment form), so it owns the spacing the form used to provide. */
.pick-form { margin: 0; }

.candidate-grid {
  list-style: none;
  margin: var(--sp-5) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6) var(--sp-5);
}
.candidate-grid__item { min-width: 0; display: flex; }
/* Cards stretch to the tallest in their row so the pick buttons line up
   across a row — a ragged button line reads as "these are different
   kinds of thing" rather than "these are five equal options". */
.candidate-grid__item > .vote-card {
  flex: 1 1 auto;
  border: var(--border-width) solid var(--ink);
  background: var(--paper-hi);
  box-shadow: var(--shadow-card);
}
.candidate-grid__item > .vote-card.is-picked {
  border-color: var(--accent);
  box-shadow: var(--shadow-card-accent);
}
@media (min-width: 700px) {
  .candidate-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 1180px) {
  .candidate-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* In a grid the card is ~380px wide, not ~1200px: the art and title need
   to come down with it or one long title blows the row height out. */
.candidate-grid .vote-card__head {
  grid-template-columns: 96px minmax(0, 1fr);
  gap: var(--sp-3);
}
.candidate-grid .vote-card__head .art-tile { width: 96px; height: 96px; }
.candidate-grid .vote-card__title {
  font-size: var(--fs-display-md);
  text-wrap: balance;
}
/* Push the pick control to the bottom of the card regardless of how many
   lines the title took. */
.candidate-grid .vote-card__divider { margin-top: auto; }

/* Optional rate/comment block — a disclosure so the default card is
   "listen, then pick" and nothing else. */
.vote-card__extras > summary {
  cursor: pointer;
  padding-block: 4px;
  min-height: 24px;
  list-style: none;
}
.vote-card__extras > summary::-webkit-details-marker { display: none; }
.vote-card__extras > summary::before {
  content: "▸ ";
  display: inline-block;
  transition: transform 120ms ease;
}
.vote-card__extras[open] > summary::before { content: "▾ "; }
.vote-card__extras[open] { margin-top: var(--sp-2); }

/* ─── Sticky submit bar ───
   With six candidates the submit button sat 3500px down the page: you
   chose in the first screen and then scrolled four more to commit. */
.pick-form__actions {
  position: sticky;
  bottom: 0;
  z-index: 5;
  margin-top: var(--sp-6);
  padding: var(--sp-3) var(--page-pad);
  margin-inline: calc(var(--page-pad) * -1);
  background: var(--paper);
  border-top: var(--border-width) solid var(--ink);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  flex-wrap: wrap;
}
.pick-form__actions p { margin: 0; max-width: 46ch; }
@media (max-width: 620px) {
  .pick-form__actions {
    flex-direction: column-reverse;
    align-items: stretch;
    text-align: center;
  }
  .pick-form__actions .btn { width: 100%; justify-content: center; }
}

/* ─── Theme ribbon ───
   Rendered as bare inline text ("THEME songs under two minutes") because
   the class had no rules at all. */
.theme-ribbon {
  display: flex;
  align-items: baseline;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-top: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  background: var(--accent);
  color: var(--paper);
  border: var(--border-width) solid var(--ink);
  box-shadow: var(--shadow-card);
}
.theme-ribbon__label {
  font-family: var(--font-mono);
  font-size: var(--fs-micro-sm);
  letter-spacing: var(--ls-mono-lg);
  flex: 0 0 auto;
}
.theme-ribbon__body {
  font-family: var(--font-display);
  font-size: var(--fs-display-md);
  line-height: 1.1;
  min-width: 0;
}
