/* Dark, audio-first theme. Accent: violet. */
:root {
  --bg: #0e0f13;
  --bg-raised: #16181f;
  --bg-hover: #1c1f28;
  --border: #262a35;
  --text: #e8eaf0;
  --text-muted: #9aa1b0;
  --accent: #8b5cf6;
  /* Round 22 typography: bold display face for headings/big moments,
     clean readable face for body/UI. Loaded from Google Fonts (see HTML
     heads — documented CDN exception, same pattern as the Daily.co SDK). */
  --font-display: "Archivo Black", "Arial Black", "Helvetica Neue", Helvetica, sans-serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --accent-soft: rgba(139, 92, 246, 0.16);
  --accent-strong: #a78bfa;
  --win: #34d399;
  --danger: #f87171;
  --radius: 16px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  line-height: 1.5;
}

a { color: var(--accent-strong); text-decoration: none; }
a:hover { text-decoration: underline; }

.container { max-width: 960px; margin: 0 auto; padding: 0 20px 64px; }

/* ------------------------------- nav ------------------------------- */
.nav {
  display: flex; align-items: center; gap: 20px;
  padding: 18px 20px; max-width: 960px; margin: 0 auto;
}
.nav .brand {
  font-weight: 800; font-size: 1.15rem; color: var(--text);
  letter-spacing: -0.02em; display: flex; align-items: center; gap: 9px;
}
.nav .brand:hover { text-decoration: none; }
.nav .brand .dot {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
}
/* Round 54: soft-launch beta badge, injected next to the brand in every nav
   by app.js (App.renderBetaBadge) — one JS change reaches all 25 pages
   instead of editing each page's nav markup. Small and quiet on purpose:
   signals "early, expect rough edges" without competing with the brand. */
.nav .beta-badge {
  font-family: var(--font-body, inherit); font-weight: 700; font-size: 0.66rem;
  letter-spacing: 0.04em; text-transform: uppercase; color: var(--accent-strong);
  background: var(--accent-soft); border-radius: 999px; padding: 3px 8px;
  line-height: 1; white-space: nowrap;
}
.nav .links { display: flex; gap: 4px; margin-left: auto; flex-wrap: wrap; }
.nav .links a {
  color: var(--text-muted); padding: 7px 13px; border-radius: 999px;
  font-size: 0.92rem; font-weight: 500;
}
.nav .links a:hover { color: var(--text); background: var(--bg-hover); text-decoration: none; }
.nav .links a.active { color: var(--text); background: var(--accent-soft); }

/* Persistent nav status: round-26 token chips + sign-in state (every page).
   (The old .nav-points chip is gone — points now live on the profile page,
   plus unchanged on the leaderboard / artists directory.) */
.nav-status { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.nav-tokens { display: inline-flex; align-items: center; gap: 5px; }
.nav-token {
  display: inline-block; padding: 5px 10px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-strong);
  font-size: 0.82rem; font-weight: 700; white-space: nowrap; cursor: default;
}
.nav-token b { font-weight: 700; }
.nav-user { color: var(--text-muted); font-size: 0.88rem; font-weight: 600; white-space: nowrap; }
.nav-user:hover { color: var(--text); text-decoration: none; }
/* Round 39: the nav Sign out button is gone (sign-out now lives on your own
   profile page, artist.js). This class is still used by the independent Sign
   out on the /verify-email holding page — keep it. */
.nav-signout {
  background: transparent; border: 1px solid var(--border); color: var(--text-muted);
  border-radius: 999px; padding: 4px 11px; font-size: 0.78rem; cursor: pointer;
  font-family: inherit;
}
.nav-signout:hover { color: var(--text); background: var(--bg-hover); }
@media (max-width: 760px) {
  .nav { flex-wrap: wrap; }
  .nav-status { margin-left: auto; }
  .nav-token { padding: 4px 8px; font-size: 0.76rem; }
}

/* ------------------------------ common ----------------------------- */
h1 { font-size: 1.7rem; margin: 26px 0 6px; }
.subtitle { color: var(--text-muted); margin: 0 0 26px; }

/* Page heading + top-right action (e.g. the live room's Share button).
   Same flex spirit as .battle-footer: space-between + wrap, so on narrow
   screens the button drops below the title instead of colliding with it. */
.page-head-row {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px 12px; flex-wrap: wrap; margin: 26px 0 6px;
}
.page-head-row h1 { margin: 0; }
.page-head-row .btn { margin-top: 4px; flex-shrink: 0; }

.card {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 22px;
}

.btn {
  display: inline-block; border: none; cursor: pointer;
  background: var(--accent); color: #fff; font-weight: 600;
  font-size: 1rem; padding: 12px 22px; border-radius: 999px;
  transition: transform 0.06s ease, filter 0.15s ease;
  font-family: inherit;
}
.btn:hover { filter: brightness(1.12); }
.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn.secondary {
  background: transparent; color: var(--text-muted);
  border: 1px solid var(--border);
}
.btn.secondary:hover { color: var(--text); background: var(--bg-hover); }

.badge-chip {
  display: inline-block; padding: 4px 11px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-strong);
  font-size: 0.8rem; font-weight: 600; margin: 2px 4px 2px 0;
}

/* Round 28: Voter Token store cosmetics.
   .listener-badge — the bought listener title, shown beside the username on
   battle comments and the profile page. Cosmetic only, like everything the
   tokens buy (non-monetary, permanently — see config.js). */
.listener-badge {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent-strong);
  border: 1px solid var(--accent);
  font-size: 0.74rem; font-weight: 700; white-space: nowrap;
}

/* Round 29: the EARNED badges — deliberately distinct from the BOUGHT
   round-28 .listener-badge title chip above.
   .verified-listener — the permanent Verified Listener badge: a small filled
   circular check beside the username (earned by crossing the lifetime vote
   AND rating thresholds in config.js VERIFIED_LISTENER; never sold). */
.verified-listener {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; border-radius: 50%;
  background: #22c55e; color: #071108;
  font-size: 0.64rem; font-weight: 900; line-height: 1;
  vertical-align: middle; margin-left: 3px; flex: none;
}

/* Round 29: membership of TODAY'S Top 5 Fans board (daily reset) — the same
   gold achievement treatment as the round-20 Battle Card badges, since both
   are earned-status callouts rather than bought cosmetics. */
.badge-chip.top-fan-chip {
  background: rgba(240, 180, 41, 0.12); color: #f0b429;
  border: 1px solid rgba(240, 180, 41, 0.55);
}

/* Round 28: unlockable profile accent themes (config.js VOTER_STORE.THEMES).
   Applied as a body class on the profile page of the owning account —
   swapping the accent variables restyles every chip/button/link on the page
   while the rest of the site keeps the default violet. */
body.profile-theme-crimson {
  --accent: #ef4444;
  --accent-soft: rgba(239, 68, 68, 0.16);
  --accent-strong: #f87171;
}
body.profile-theme-neon {
  --accent: #06b6d4;
  --accent-soft: rgba(6, 182, 212, 0.16);
  --accent-strong: #22d3ee;
}
body.profile-theme-gold {
  --accent: #d97706;
  --accent-soft: rgba(217, 119, 6, 0.18);
  --accent-strong: #fbbf24;
}

.muted { color: var(--text-muted); }
.small { font-size: 0.85rem; }

.avatar {
  border-radius: 50%; background: var(--accent-soft); color: var(--accent-strong);
  display: inline-flex; align-items: center; justify-content: center;
  font-weight: 700; overflow: hidden; flex-shrink: 0;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }

.notice {
  border: 1px solid #7c5c1e; background: rgba(250, 204, 21, 0.08);
  color: #fbd77a; border-radius: 12px; padding: 12px 16px;
  font-size: 0.9rem; margin: 18px 0;
}

.error-box {
  border: 1px solid #7f2f2f; background: rgba(248, 113, 113, 0.08);
  color: var(--danger); border-radius: 12px; padding: 12px 16px; margin: 14px 0;
}
.success-box {
  border: 1px solid #1f6a4c; background: rgba(52, 211, 153, 0.08);
  color: var(--win); border-radius: 12px; padding: 12px 16px; margin: 14px 0;
}

/* ------------------------------ battle ----------------------------- */
.battle-grid {
  display: grid; grid-template-columns: 1fr 56px 1fr;
  gap: 14px; align-items: stretch; margin-top: 10px;
}
.vs-divider {
  display: flex; align-items: center; justify-content: center;
  color: var(--text-muted); font-weight: 800; font-size: 1.05rem;
  letter-spacing: 0.06em;
}
@media (max-width: 760px) {
  .battle-grid { grid-template-columns: 1fr; }
  .vs-divider { padding: 2px 0; }
}

.song-card { display: flex; flex-direction: column; gap: 14px; }
.song-head { display: flex; align-items: center; gap: 12px; }
.song-head .avatar { width: 44px; height: 44px; font-size: 1rem; }
.song-title { font-weight: 700; font-size: 1.08rem; line-height: 1.3; }
.song-artist { font-size: 0.88rem; }
.song-record { margin-left: auto; text-align: right; font-size: 0.8rem; color: var(--text-muted); white-space: nowrap; }

/* Round 43: blurred artist-photo backdrop — event "Now Battling" cards only.
   battle.js adds .song-card--photo + a .song-card-bg layer when the event
   panel passes { blurredBg: true } AND the artist has an avatar; regular
   battle pages never get these classes. The photo is a separate absolutely-
   positioned layer (so the blur never touches the real content), scaled up
   to push its soft edges outside the card's overflow clip, with a dark
   ::after scrim between it and the content so titles, records and the vote
   button keep their normal contrast on any photo. Content children are
   lifted to z-index 1; the vote button's internal gate-fill/label stack is
   untouched (it only positions within the button itself). */
.song-card--photo { position: relative; overflow: hidden; }
.song-card--photo .song-card-bg {
  position: absolute; inset: 0; z-index: 0;
  background-size: cover; background-position: center;
  filter: blur(12px) saturate(1.15);
  transform: scale(1.2);
  pointer-events: none;
}
.song-card--photo::after {
  /* Scrim: --bg-raised (#16181f) at ~78% — the photo glows through the
     card's own surface color instead of fighting the text. Paints above
     the bg layer (same stacking level, later in paint order), below the
     z-index:1 content. */
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: rgba(22, 24, 31, 0.78);
  pointer-events: none;
}
.song-card--photo > :not(.song-card-bg) { position: relative; z-index: 1; }

.player-wrap { border-radius: 12px; overflow: hidden; background: #000; }
.player-wrap iframe { display: block; width: 100%; border: 0; }
audio { width: 100%; display: block; }

.vote-btn { width: 100%; margin-top: auto; position: relative; overflow: hidden; }
/* Listen-before-vote gate: while a vote button is disabled it shows a
   countdown label plus a progress fill that tracks listening time. */
.vote-btn .gate-fill {
  position: absolute; top: 0; left: 0; bottom: 0; width: 0%;
  background: rgba(255, 255, 255, 0.18);
  transition: width 0.3s linear;
  pointer-events: none;
}
.vote-btn .gate-label { position: relative; }

/* -------------------- star ratings (round 5) -------------------- */
/* Optional, collapsed-by-default panel under every vote button. Completely
   separate from voting — no gate, no effect on the battle result. */
.rating-summary { font-size: 0.8rem; line-height: 1.6; }
.rating-summary b { color: var(--accent-strong); }
.rating-summary .star { color: #fbbf24; }

.rate-widget { border-top: 1px dashed var(--border); padding-top: 10px; }
/* Owner request: make this read as a real second button, close in weight to
   the vote button right above it — full-width pill, bold — but in the
   softer accent tone (not the solid accent fill the vote button uses) so
   the two stay visually distinct as separate actions. */
.rate-toggle {
  background: var(--accent-soft); color: var(--accent-strong);
  border: 1px solid var(--accent); border-radius: 999px;
  font-family: inherit; font-size: 0.95rem; font-weight: 700; cursor: pointer;
  padding: 10px 20px; width: 100%; margin-top: 10px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  transition: filter 0.15s ease, transform 0.06s ease;
}
.rate-toggle:hover { filter: brightness(1.1); color: var(--accent-strong); }
.rate-toggle:active { transform: scale(0.97); }
/* Round 47: the rating panel now sits behind the same per-song listen gate
   as the vote button (battle.js gateCard disables the toggle until that
   song's own gate completes). Same disabled treatment as .btn:disabled;
   placed after :hover/:active so, at equal specificity, a locked toggle
   never brightens or presses. */
.rate-toggle:disabled { opacity: 0.45; cursor: not-allowed; filter: none; transform: none; }
.rate-caret { transition: transform 0.15s ease; display: inline-block; }
.rate-widget.open .rate-caret { transform: rotate(180deg); }
.rate-body { margin-top: 8px; }
.rate-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 4px 0;
}
.rate-cat { font-size: 0.85rem; color: var(--text-muted); font-weight: 600; }
.rate-stars { display: inline-flex; gap: 2px; }
.rate-star {
  background: transparent; border: none; cursor: pointer; padding: 2px;
  font-size: 1.15rem; line-height: 1; color: var(--border);
  transition: color 0.1s ease, transform 0.06s ease;
}
.rate-star:hover { transform: scale(1.15); color: #fbbf24; }
.rate-star.on { color: #fbbf24; }
.rate-submit { margin-top: 8px; }

/* Round 6: "they accepted — pick YOUR track" rows must not be missable. */
.challenge-row.needs-action {
  border: 1px solid var(--accent); border-radius: 12px;
  padding: 12px 14px; margin: 8px 0; background: var(--accent-soft);
}
.challenge-row.needs-action:first-child { padding-top: 12px; }
.action-chip { background: var(--accent); color: #fff; }

.battle-footer {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 22px; gap: 12px; flex-wrap: wrap;
}
.voter-status { font-size: 0.86rem; color: var(--text-muted); }
.voter-status b { color: var(--accent-strong); }

.result-flash { text-align: center; padding: 30px 10px; }
.result-flash .headline { font-size: 1.3rem; font-weight: 800; margin-bottom: 6px; }
.result-bar {
  height: 12px; border-radius: 999px; background: var(--bg-hover);
  overflow: hidden; max-width: 420px; margin: 16px auto 8px;
}
.result-bar .fill { height: 100%; background: var(--win); border-radius: 999px; transition: width 0.6s ease; }

/* ---------------------------- leaderboard --------------------------- */
.tabs { display: flex; gap: 8px; margin: 18px 0; }
.tab {
  padding: 8px 18px; border-radius: 999px; cursor: pointer; border: 1px solid var(--border);
  background: transparent; color: var(--text-muted); font-weight: 600; font-size: 0.92rem;
  font-family: inherit;
}
.tab.active { background: var(--accent-soft); color: var(--accent-strong); border-color: transparent; }

table.board { width: 100%; border-collapse: collapse; }
table.board th {
  text-align: left; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--text-muted); padding: 10px 12px; border-bottom: 1px solid var(--border);
}
table.board td { padding: 12px; border-bottom: 1px solid var(--border); font-size: 0.95rem; }
table.board tr:last-child td { border-bottom: none; }
table.board .rank { color: var(--text-muted); width: 40px; }
table.board .points { font-weight: 700; color: var(--accent-strong); }

/* ------------------------------- forms ------------------------------ */
label.field-label { display: block; font-weight: 600; font-size: 0.9rem; margin: 18px 0 6px; }
input[type="text"], input[type="url"], input[type="password"], textarea, select {
  width: 100%; background: var(--bg); border: 1px solid var(--border);
  color: var(--text); border-radius: 10px; padding: 11px 14px; font-size: 0.98rem;
  font-family: inherit;
}
input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: transparent; }
textarea { resize: vertical; min-height: 90px; }

.mode-toggle { display: flex; gap: 10px; margin: 6px 0 4px; }
.mode-option {
  flex: 1; border: 1px solid var(--border); border-radius: 12px; padding: 14px;
  cursor: pointer; text-align: center; font-weight: 600; color: var(--text-muted);
}
.mode-option input { display: none; }
.mode-option.selected { border-color: var(--accent); color: var(--text); background: var(--accent-soft); }
.mode-option .sub { display: block; font-weight: 400; font-size: 0.8rem; margin-top: 3px; }

.rights-row {
  display: flex; gap: 10px; align-items: flex-start; margin: 18px 0;
  padding: 14px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg);
}
.rights-row input[type="checkbox"] { margin-top: 4px; width: 17px; height: 17px; accent-color: var(--accent); }
.rights-row label { font-size: 0.9rem; }

input[type="file"] { color: var(--text-muted); font-size: 0.9rem; }
input[type="file"]::file-selector-button {
  background: var(--bg-hover); color: var(--text); border: 1px solid var(--border);
  border-radius: 999px; padding: 8px 16px; margin-right: 12px; cursor: pointer; font-family: inherit;
}

/* ------------------------------ profile ----------------------------- */
.profile-head { display: flex; gap: 18px; align-items: center; margin: 26px 0 18px; }
.profile-head .avatar { width: 84px; height: 84px; font-size: 1.7rem; }
.profile-head h1 { margin: 0 0 2px; }
.stats-row { display: flex; gap: 12px; flex-wrap: wrap; margin: 18px 0; }
.stat-box {
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: 12px;
  padding: 12px 20px; text-align: center; min-width: 92px;
}
.stat-box .num { font-size: 1.35rem; font-weight: 800; color: var(--accent-strong); }
.stat-box .lbl { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); }
/* Round 26: the cosmetic points total's prominent home is now the artist
   profile page (the nav shows token balances instead) — accent-bordered so
   it stands out in the stats row. */
.stat-box-points { border-color: var(--accent); }
.stat-box-points .lbl { color: var(--accent-strong); }

.link-list { list-style: none; padding: 0; margin: 8px 0; }
.link-list li { margin: 6px 0; overflow-wrap: anywhere; }
.link-list li::before { content: "↗ "; color: var(--text-muted); }

.song-row {
  display: flex; flex-direction: column; gap: 10px;
  padding: 16px 0; border-bottom: 1px solid var(--border);
}
.song-row:last-child { border-bottom: none; }
.song-row .meta { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }

/* ------------------------------ hallway ----------------------------- */
.room-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  gap: 14px; margin-top: 10px;
}
.room-card {
  display: flex; align-items: center; gap: 14px; color: var(--text);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.room-card:hover { text-decoration: none; border-color: var(--accent); background: var(--bg-hover); }
.room-card.locked { opacity: 0.65; }
.room-card.locked:hover { border-color: var(--border); background: var(--bg-raised); }
.room-door {
  width: 46px; height: 46px; border-radius: 12px; flex-shrink: 0;
  background: var(--accent-soft); color: var(--accent-strong);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.3rem; font-weight: 800;
}
.room-info { min-width: 0; }
.room-name { font-weight: 700; font-size: 1.05rem; letter-spacing: -0.01em; }
.room-action { margin-left: auto; text-align: right; flex-shrink: 0; }
.room-enter { padding: 8px 16px; font-size: 0.85rem; }

/* -------------------- rooms + challenges (round 3) ------------------- */
.room-chips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 2px 0; }
.room-type {
  display: inline-block; padding: 2px 9px; border-radius: 999px;
  font-size: 0.68rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  background: var(--accent-soft); color: var(--accent-strong);
}
.room-type.auto { background: rgba(52, 211, 153, 0.14); color: var(--win); }

.home-rooms-heading, .room-section-heading {
  font-size: 1.15rem; letter-spacing: -0.01em; margin: 34px 0 6px;
}
.room-section-heading { margin-top: 30px; }

.battle-block { margin: 14px 0 24px; }
.battle-block-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px;
}
.tally { font-weight: 800; color: var(--accent-strong); }

.challenge-row {
  display: flex; justify-content: space-between; align-items: center;
  gap: 12px; padding: 12px 0; border-top: 1px solid var(--border); flex-wrap: wrap;
}
.challenge-row:first-child { border-top: none; padding-top: 4px; }
.challenge-row .actions { flex-shrink: 0; display: flex; gap: 8px; }

/* -------------------------- artists directory ----------------------- */
.artist-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr));
  gap: 14px; margin-top: 10px;
}
.artist-card {
  display: flex; flex-direction: column; gap: 10px; color: var(--text);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.artist-card:hover { text-decoration: none; border-color: var(--accent); background: var(--bg-hover); }
.artist-card-head { display: flex; align-items: center; gap: 12px; }
.artist-card-head .avatar { width: 46px; height: 46px; font-size: 1rem; }
.artist-bio { margin: 0; }

/* ------------------------------ comments ---------------------------- */
.comments-card { margin-top: 6px; }
.comment-list { margin: 14px 0 4px; }
.comment { padding: 14px 0; border-top: 1px solid var(--border); }
.comment:first-child { border-top: none; padding-top: 6px; }
.comment-head { display: flex; align-items: center; gap: 9px; }
.comment-head .avatar { width: 28px; height: 28px; font-size: 0.7rem; }
.comment-user { font-weight: 700; font-size: 0.9rem; }
.comment-body { margin: 8px 0 0; font-size: 0.95rem; white-space: pre-wrap; overflow-wrap: anywhere; }
.comment-voice { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; max-width: 420px; }
.comment-voice.preview { padding: 12px; border: 1px dashed var(--border); border-radius: 12px; }
.comment-voice .badge-chip { align-self: flex-start; }
.comment-form { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 16px; }
.comment-form textarea { min-height: 70px; }
.comment-signin { border-top: 1px solid var(--border); padding-top: 14px; margin: 14px 0 0; }
.voice-row { display: flex; align-items: center; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
.small-btn { padding: 8px 16px; font-size: 0.85rem; }
.btn.recording {
  color: var(--danger); border-color: #7f2f2f;
  animation: rec-pulse 1.2s ease-in-out infinite;
}
@keyframes rec-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(248, 113, 113, 0.35); }
  50% { box-shadow: 0 0 0 6px rgba(248, 113, 113, 0); }
}

/* ------------------------------- auth ------------------------------- */
.auth-container { max-width: 560px; }
.auth-card { margin-top: 10px; }

/* ------------------------------ legal ------------------------------- */
.legal h2 { font-size: 1.1rem; margin-top: 28px; }
.legal p, .legal li { color: #c6cad4; font-size: 0.95rem; }

footer.site {
  max-width: 960px; margin: 0 auto; padding: 26px 20px 40px;
  color: var(--text-muted); font-size: 0.8rem; border-top: 1px solid var(--border);
}
footer.site a { color: var(--text-muted); text-decoration: underline; }

/* ------------------- round 7: series + song reports ------------------- */
.series-chip { background: #2b2440; border-color: #4c3d78; }
.challenge-row .actions { flex-wrap: wrap; align-items: center; }
.pick-slot { display: inline-flex; align-items: center; gap: 6px; }

/* "Report track" — deliberately quiet; reporting is notify-only. */
.report-wrap { margin-top: 8px; }
.report-link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--text-muted); font-size: 0.78rem; text-decoration: underline;
}
.report-link:hover { color: #c6cad4; }
.report-form {
  margin-top: 6px; padding: 10px 12px;
  border: 1px dashed var(--border); border-radius: 10px;
}
.report-form input.report-reason { width: 100%; }
.report-done { margin-top: 4px; }

/* ------------------- round 8: live audio rooms (Daily) ------------------- */
.live-door { background: rgba(52, 211, 153, 0.14); }
.room-type.live-chip { background: rgba(52, 211, 153, 0.14); color: var(--win); }
.live-call-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.live-roster { margin: 14px 0 4px; }

/* Round 44: Clubhouse/Spaces-style roster — each participant is a circular
   bubble (photo or initials) with their name underneath, laid out in a
   wrapping grid. auto-fill + minmax gives ~3 bubbles across on phones and
   ~5 across at the full 960px container (the media query below widens the
   minimum so desktop doesn't crowd 7-8 tiny bubbles into a row). */
.live-bubbles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 18px 10px;
  padding: 12px 0 6px;
}
@media (min-width: 700px) {
  .live-bubbles { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
}
.live-part {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 6px; min-width: 0;
}
.live-bubble-pic { position: relative; display: inline-flex; }
.live-part .avatar { width: 64px; height: 64px; font-size: 1.25rem; }
/* Small muted-mic badge pinned to the avatar's corner (replaces the old
   full-width "muted" text label from the row layout). */
.live-mic-badge {
  position: absolute; right: -3px; bottom: -3px;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--bg-raised); border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 0.68rem; line-height: 1;
}
.live-part-name {
  font-weight: 600; font-size: 0.85rem; max-width: 100%;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.live-part-tags {
  display: flex; align-items: center; justify-content: center;
  gap: 5px; max-width: 100%;
}
.live-mod-chip { margin-left: 0; }
/* Moderator-only remote mute, shrunk to fit under a bubble. Always visible
   (hover-only would strand touch screens), just very small. */
.live-part .live-mute-other { padding: 3px 12px; font-size: 0.72rem; }

/* Round 9 (reshaped in round 44): speaking indicator — the soft violet
   ring now pulses as a full glowing halo around the circular bubble avatar
   of whoever is currently talking, driven by daily-js's audio-level
   observers. Same .speaking class + box-shadow technique as always; the
   circle shape is what turns it into a Clubhouse-style ring. */
.live-part .avatar { transition: box-shadow 0.18s ease; }
.live-part.speaking .avatar {
  box-shadow: 0 0 0 2px var(--accent), 0 0 10px rgba(139, 92, 246, 0.45);
  animation: speak-pulse 1.3s ease-in-out infinite;
}
@keyframes speak-pulse {
  0%, 100% { box-shadow: 0 0 0 2px var(--accent), 0 0 6px rgba(139, 92, 246, 0.3); }
  50% { box-shadow: 0 0 0 3px var(--accent-strong), 0 0 14px rgba(139, 92, 246, 0.6); }
}
.live-controls {
  display: flex; gap: 10px; flex-wrap: wrap;
  margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border);
}
#live-audio-sink { display: none; }

/* ------ round 10: top-5 tier chips, marquee spotlight, hot streaks ------ */

/* "Top 5 · Pop" — a badge-chip with a lifted accent outline so top-tier
   status reads at a glance next to plain badges/genre chips. */
.top-tier-chip {
  border: 1px solid var(--accent);
  box-shadow: 0 0 6px rgba(139, 92, 246, 0.35);
  font-weight: 700;
}

/* Compact inline hot-streak marker (flame + win count) for name lines and
   battle cards where full badge chips wouldn't fit. */
.streak-flame {
  font-size: 0.78rem; font-weight: 800; color: #fb923c; white-space: nowrap;
}

/* Marquee battle card: one live battle featuring a top-5 artist. A slow
   accent glow in the same spirit as round 9's speak-pulse — spotlight,
   not alarm. The whole card links into the battle's room. */
.marquee-card {
  display: block; color: var(--text); margin: 22px 0 6px;
  border-color: var(--accent);
  animation: marquee-glow 2.4s ease-in-out infinite;
  transition: background 0.15s ease;
}
.marquee-card:hover { text-decoration: none; background: var(--bg-hover); }
@keyframes marquee-glow {
  0%, 100% { box-shadow: 0 0 0 1px var(--accent-soft), 0 0 12px rgba(139, 92, 246, 0.22); }
  50% { box-shadow: 0 0 0 2px var(--accent), 0 0 24px rgba(139, 92, 246, 0.5); }
}
.marquee-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 14px;
}
.marquee-chip { background: var(--accent); color: #fff; font-weight: 700; }
.marquee-grid {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 14px; align-items: center;
}
.marquee-side { display: flex; align-items: center; gap: 12px; min-width: 0; }
.marquee-side .avatar { width: 52px; height: 52px; font-size: 1.05rem; }
.marquee-side-info { min-width: 0; }
.marquee-artist { font-weight: 800; font-size: 1.05rem; letter-spacing: -0.01em; }
.marquee-chips { margin-top: 4px; }
.marquee-cta { margin-top: 16px; text-align: center; }
@media (max-width: 640px) {
  .marquee-grid { grid-template-columns: 1fr; }
  .marquee-grid .vs-divider { justify-self: center; }
}

/* ------- Round 18: judges' table, the reveal, Stage roster tiers ---------- */

/* The judges' private verdict box (event-panel.js renderJudgeBox). */
.judge-box {
  margin-top: 16px; padding: 14px 16px; border-radius: 12px;
  border: 1px dashed var(--accent-strong); background: var(--accent-soft);
}
.judge-box-head { margin: 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.judge-pick-row { display: flex; gap: 10px; flex-wrap: wrap; margin: 10px 0; }
.judge-pick {
  padding: 10px 14px; border-radius: 10px; cursor: pointer; text-align: left;
  border: 1px solid var(--border); background: transparent; color: var(--text);
  font-weight: 600; font-size: 0.92rem;
}
.judge-pick:hover { border-color: var(--accent-strong); }
.judge-pick.picked {
  border-color: var(--accent); background: var(--bg-hover);
  color: var(--accent-strong); box-shadow: 0 0 0 1px var(--accent);
}
.judge-box textarea { min-height: 60px; }

/* The reveal (event-panel.js revealHtml) — meant to feel like a moment. */
.reveal-card {
  margin: 12px 0 4px; padding: 14px 16px; border-radius: 12px;
  border: 1px solid var(--accent); background: var(--bg-hover);
  animation: reveal-in 0.6s ease-out;
}
@keyframes reveal-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}
.reveal-head {
  font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase;
  font-size: 0.78rem; color: var(--accent-strong); margin-bottom: 8px;
}
.reveal-judge { display: flex; gap: 10px; align-items: flex-start; padding: 6px 0; }
.reveal-comment { font-style: italic; margin-top: 2px; }
.reveal-crowd { margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--border); }
.reveal-official {
  margin-top: 10px; padding: 8px 12px; border-radius: 8px;
  background: var(--accent-soft); color: var(--accent-strong); font-weight: 700;
}
.reveal-official.draw {
  background: transparent; border: 1px dashed var(--border);
  color: var(--text-muted); font-weight: 600;
}

/* Round 18: tiered Host / Judges / Crowd roster — Battle Card Stage room
   only, and only while an event is live (live-room.js stageTiers). */
.live-tier { margin-bottom: 10px; }
.live-tier-head {
  font-size: 0.75rem; font-weight: 800; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted);
  padding: 6px 0 4px; border-bottom: 1px solid var(--border); margin-bottom: 4px;
}
.live-tier-host .live-tier-head { color: var(--accent-strong); }
.live-tier-count { font-weight: 600; }
.live-tier-empty { margin: 4px 0 8px; }

/* Round 20: Battle Card win badges — gold treatment (via the badge's cls
   field from the server) so an official event-night win stands out from the
   regular accent-colored chips. */
.badge-chip.badge-event {
  background: rgba(240, 180, 41, 0.12);
  color: #f0b429;
  border: 1px solid rgba(240, 180, 41, 0.55);
  box-shadow: 0 0 6px rgba(240, 180, 41, 0.22);
}

/* Round 20: the profile page's dedicated Battle Card wins callout — same
   gold treatment as the badge, so the two read as one achievement. */
.event-wins-callout { border: 1px solid rgba(240, 180, 41, 0.55); }
.event-wins-callout .event-wins-head { color: #f0b429; font-weight: 800; }
.event-win-row { padding: 8px 0; border-bottom: 1px solid var(--border); }
.event-win-row:last-child { border-bottom: none; padding-bottom: 0; }

/* Round 20: the "upset" flag inside a reveal — the crowd's favorite differed
   from the judges' official winner. */
.upset-flag {
  margin-top: 8px; padding: 6px 12px; border-radius: 8px;
  border: 1px dashed rgba(240, 180, 41, 0.55);
  color: #f0b429; font-weight: 600; font-size: 0.85rem;
}

/* ------------- Round 22: nav reorganization + typography ------------- */

/* Display face (Archivo Black ships ONE weight, 400 — never fake-bold it)
   for headings and the big "moment" numbers/callouts. Body/UI text stays
   on Inter for readability. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.25;
}
.nav .brand { font-family: var(--font-display); font-weight: 400; letter-spacing: 0.01em; }
.vs-divider { font-family: var(--font-display); font-weight: 400; }
.stat-box .num { font-family: var(--font-display); font-weight: 400; }
.tally { font-family: var(--font-display); font-weight: 400; font-size: 1.02em; }
.result-flash .headline { font-family: var(--font-display); font-weight: 400; }
.room-door { font-family: var(--font-display); font-weight: 400; }
.reveal-head { font-family: var(--font-display); font-weight: 400; letter-spacing: 0.1em; }

/* "More" dropdown: native <details>/<summary> — keyboard-accessible with
   zero dependencies. app.js closes it on outside click / Escape. */
.nav-more { position: relative; }
.nav-more summary {
  list-style: none; cursor: pointer; user-select: none;
  color: var(--text-muted); padding: 7px 13px; border-radius: 999px;
  font-size: 0.92rem; font-weight: 500;
  display: inline-flex; align-items: center; gap: 5px;
}
.nav-more summary::-webkit-details-marker { display: none; }
.nav-more summary:hover, .nav-more[open] summary {
  color: var(--text); background: var(--bg-hover);
}
/* If the current page lives inside the menu, tint the trigger like an
   active link (progressive enhancement — :has() is cosmetic only). */
.nav-more:has(a.active) summary { color: var(--text); background: var(--accent-soft); }
.nav-more .caret { font-size: 0.7em; transition: transform 0.15s ease; }
.nav-more[open] .caret { transform: rotate(180deg); }
.nav .nav-more-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
  min-width: 170px; display: flex; flex-direction: column; gap: 2px;
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: 12px; padding: 6px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
}
.nav .nav-more-menu a {
  color: var(--text-muted); padding: 8px 12px; border-radius: 8px;
  font-size: 0.92rem; font-weight: 500; white-space: nowrap;
}
.nav .nav-more-menu a:hover { color: var(--text); background: var(--bg-hover); text-decoration: none; }
.nav .nav-more-menu a.active { color: var(--text); background: var(--accent-soft); }
/* Round 45: the admin-only tools section app.js appends to the More menu
   for admin accounts (renderNavAdminLinks) — a ruled-off sub-group with a
   quiet uppercase caption, same voice as .live-tier-head. Non-admins never
   get this markup at all, so there is no display:none variant to style. */
.nav .nav-more-menu .nav-admin-label {
  margin-top: 4px; padding: 8px 12px 2px;
  border-top: 1px solid var(--border);
  color: var(--text-muted); font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.09em; text-transform: uppercase;
}

/* Submit: a real call-to-action pill, docked next to the user's identity
   (rendered by app.js renderNavStatus for signed-in users). */
.nav-submit {
  background: var(--accent); color: #fff; font-weight: 700;
  font-size: 0.85rem; padding: 6px 14px; border-radius: 999px;
  white-space: nowrap;
}
.nav-submit:hover { text-decoration: none; filter: brightness(1.12); }

/* Round 27: the Token Store's nav pill — Submit's quieter sibling. */
.nav-store {
  border: 1px solid var(--accent); color: var(--accent-strong); font-weight: 700;
  font-size: 0.85rem; padding: 5px 13px; border-radius: 999px;
  white-space: nowrap;
}
.nav-store:hover { text-decoration: none; background: var(--accent-soft); }

@media (max-width: 760px) {
  /* Small screens: the menu expands in flow instead of floating, so it
     can never hang off the viewport edge. */
  .nav .nav-more-menu {
    position: static; box-shadow: none; margin-top: 4px; min-width: 0;
  }
}

/* ---- Round 23: profile edit polish + email-verification pages ---- */

/* The profile editor, restyled to the round-22 design language: a display-
   face heading, grouped sections with quiet uppercase captions (same voice
   as .live-tier-head / table.board th), and breathing room — no more
   afterthought form. */
.edit-card { margin-top: 18px; }
.edit-card .edit-title { margin: 0 0 6px; font-size: 1.3rem; }
.edit-sub { color: var(--text-muted); font-size: 0.88rem; margin: 0 0 6px; }
.edit-section {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border);
}
.edit-section-head {
  font-size: 0.75rem; font-weight: 800; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted); margin-bottom: 4px;
}
/* Round 42: the deactivate-account "danger zone" card at the bottom of the
   edit-profile area. Reuses the app's existing destructive palette (the
   --danger red and the .error-box border tone) — no new color scheme. */
.danger-card { border-color: #7f2f2f; }
.danger-card .edit-section-head { color: var(--danger); }
.btn.danger-btn {
  background: transparent; color: var(--danger); border: 1px solid #7f2f2f;
}
.btn.danger-btn:hover:not(:disabled) {
  background: rgba(248, 113, 113, 0.1); filter: none;
}

.edit-avatar-row {
  display: flex; gap: 16px; align-items: center; margin-top: 10px;
  padding: 14px; border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg);
}
.edit-avatar-row .avatar { width: 72px; height: 72px; font-size: 1.45rem; }
.edit-avatar-controls { min-width: 0; }
.edit-actions {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--border);
}
@media (max-width: 560px) {
  .edit-avatar-row { flex-direction: column; align-items: flex-start; }
}

/* The /verify-email page (holding view + emailed-link landing). */
.verify-card { text-align: left; }
.verify-card .verify-icon { font-size: 2.2rem; line-height: 1; margin-bottom: 12px; }

/* --------- Round 24: musical flourish (landing / signup / home) --------- */
/* Pure CSS + inline SVG decoration only — zero image files, zero new
   dependencies. Everything below is aria-hidden eye candy drawn from the
   existing accent palette: animated equalizer bars, static waveform line
   art, a slow-spinning vinyl and soft radial glows. It all degrades
   gracefully: reduced-motion turns the animation off, and the vinyl hides
   on small screens instead of crowding the text. */

/* Animated equalizer bars — a small "audio is alive" pulse docked next to
   page headings. Staggered durations/delays so the bounce feels organic;
   scaleY-only animation, so it never costs layout work. */
.eq-bars {
  display: inline-flex; align-items: flex-end; gap: 3px;
  height: 0.8em; margin-left: 12px;
}
.eq-bars span {
  width: 5px; border-radius: 3px; height: 100%;
  background: linear-gradient(to top, var(--accent), var(--accent-strong));
  transform-origin: bottom; transform: scaleY(0.35);
  animation: eq-bounce 1.1s ease-in-out infinite;
}
.eq-bars span:nth-child(1) { animation-duration: 1.0s; }
.eq-bars span:nth-child(2) { animation-duration: 1.35s; animation-delay: 0.15s; }
.eq-bars span:nth-child(3) { animation-duration: 0.9s; animation-delay: 0.32s; }
.eq-bars span:nth-child(4) { animation-duration: 1.2s; animation-delay: 0.08s; }
.eq-bars span:nth-child(5) { animation-duration: 1.05s; animation-delay: 0.24s; }
@keyframes eq-bounce {
  0%, 100% { transform: scaleY(0.25); }
  50% { transform: scaleY(1); }
}

/* Static waveform strips (inline SVGs in the HTML; stroke = currentColor). */
.sound-wave {
  display: block; width: 100%; height: 44px;
  color: var(--accent); opacity: 0.4; pointer-events: none;
}
.wave-divider { height: 30px; margin: 40px 0 -20px; opacity: 0.22; } /* home: above "The rooms" */

/* Landing hero: soft accent glow + a slow-spinning vinyl bleeding off the
   right edge, both stacked UNDER the pitch text. overflow:hidden keeps the
   bleed from ever creating a horizontal scrollbar. */
.hero { position: relative; overflow: hidden; padding-bottom: 6px; }
.hero > :not(.hero-glow, .vinyl) { position: relative; z-index: 1; }
.hero-glow, .vinyl { position: absolute; z-index: 0; pointer-events: none; }
.hero-glow {
  top: 0; left: -140px; width: 560px; height: 360px;
  background: radial-gradient(closest-side, var(--accent-soft), transparent 72%);
}
.hero-title { font-size: clamp(2rem, 6vw, 2.75rem); margin-top: 34px; }
.vinyl {
  top: 6px; right: -70px; width: 270px; height: 270px; border-radius: 50%;
  background:
    conic-gradient(rgba(255, 255, 255, 0.055) 0 32deg, transparent 32deg 178deg,
                   rgba(255, 255, 255, 0.045) 178deg 214deg, transparent 214deg),
    radial-gradient(circle, var(--accent) 0 9%, #10121a 9.5% 13.5%, transparent 14%),
    repeating-radial-gradient(circle, #12141b 0 4px, #1a1d26 4px 8px);
  border: 1px solid var(--border);
  box-shadow: 0 0 40px rgba(139, 92, 246, 0.18);
  opacity: 0.5;
  animation: vinyl-spin 30s linear infinite; /* transform-only: cheap */
}
.vinyl::after { /* spindle hole */
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 9px; height: 9px; border-radius: 50%; background: var(--bg);
}
@keyframes vinyl-spin { to { transform: rotate(360deg); } }

/* Signup: radial glow behind the card, a waveform strip under the heading,
   and an accent "level meter" edge along the top of the form card
   (.wave-card — scoped so the login page's auth-card stays untouched). */
.auth-container { position: relative; }
.auth-container > :not(.auth-glow) { position: relative; z-index: 1; }
.auth-glow {
  position: absolute; z-index: 0; pointer-events: none;
  top: 40px; left: 50%; transform: translateX(-50%);
  width: 640px; max-width: calc(100vw - 24px); height: 430px;
  background: radial-gradient(closest-side, var(--accent-soft), transparent 70%);
}
.auth-wave { height: 34px; margin: -8px 0 2px; opacity: 0.3; }
.wave-card { position: relative; overflow: hidden; }
.wave-card::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent-strong) 45%, transparent 92%);
}

@media (prefers-reduced-motion: reduce) {
  .eq-bars span { animation: none; transform: scaleY(0.55); }
  .vinyl { animation: none; }
}
@media (max-width: 760px) {
  .vinyl { display: none; } /* would crowd the pitch text on phones */
  .hero-glow { left: -100px; width: 400px; }
}

/* ------ Round 32: crossed-mics Battle Token icon (replaces the swords) ------ */
/* Emitted by App.iconMics (app.js) wherever a Battle Token amount shows.
   em-sized so the single snippet scales with its surroundings: ~13px inside
   the 0.82rem nav chip, larger in the /store balance numbers and the
   "For Artists" heading. currentColor keeps it on-palette everywhere
   (accent-strong in the chip, heading/text color elsewhere). */
.icon-mics {
  width: 1.1em; height: 1.1em; display: inline-block;
  vertical-align: -0.18em; flex: none;
}
