* { margin: 0; padding: 0; box-sizing: border-box; }

:root {
  --cyan: #34d3ff;
  --orange: #ffab2e;
  --gold: #ffd75e;
  --red: #ff3b5c;
  --bg: #0a0a14;
}

html, body {
  width: 100%; height: 100%;
  overflow: hidden;
  background: var(--bg);
  font-family: "Avenir Next", "Segoe UI", system-ui, sans-serif;
  color: #fff;
  user-select: none;
  -webkit-user-select: none;
}

#game { position: fixed; inset: 0; display: block; }

.hidden { display: none !important; }

/* ------------------------------------------------------------------ HUD */
#hud {
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 5;
}
.hud-label {
  font-size: 11px; letter-spacing: 3px; opacity: 0.55; font-weight: 700;
}
#hud-left { position: absolute; top: 18px; left: 22px; display: flex; align-items: flex-start; gap: 18px; }
#score {
  font-size: 42px; font-weight: 800; font-variant-numeric: tabular-nums;
  text-shadow: 0 0 18px rgba(52, 211, 255, .5);
  transition: transform .08s;
}
#score.bump { transform: scale(1.12); }

#mult-box { margin-top: 4px; text-align: center; }
#mult {
  font-size: 30px; font-weight: 900; font-style: italic;
  color: var(--gold);
  text-shadow: 0 0 14px rgba(255, 215, 94, .6);
  transition: transform .15s cubic-bezier(.2, 2.5, .4, 1);
}
#mult.pump { transform: scale(1.5) rotate(-6deg); }
#mult.max {
  animation: fire-pulse .5s infinite alternate;
}
@keyframes fire-pulse {
  from { text-shadow: 0 0 12px #ffae00, 0 0 30px #ff6a00; color: #ffd75e; }
  to   { text-shadow: 0 0 22px #ffae00, 0 0 55px #ff2200; color: #fff3c4; }
}
#mult-meter {
  width: 64px; height: 6px; background: rgba(255,255,255,.15);
  border-radius: 3px; margin-top: 5px; overflow: hidden;
}
#mult-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--gold), #ff8a00);
  border-radius: 3px;
  transition: width .12s;
}

#hud-center {
  position: absolute; top: 12px; left: 50%; transform: translateX(-50%);
  text-align: center;
}
#combo {
  font-size: 54px; font-weight: 900; font-style: italic;
  color: #fff;
  text-shadow: 0 0 20px rgba(255,255,255,.45);
  transition: transform .07s;
  min-height: 60px;
}
#combo.bump { transform: scale(1.18); }
#combo.hot { color: var(--gold); text-shadow: 0 0 24px rgba(255, 180, 40, .8); }
#combo-wrap.shake { animation: combo-shake .45s; }
@keyframes combo-shake {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(-14px) rotate(-3deg); }
  35% { transform: translateX(11px) rotate(2deg); }
  55% { transform: translateX(-7px); }
  75% { transform: translateX(4px); }
}

#hud-right { position: absolute; top: 18px; right: 22px; display: flex; gap: 22px; text-align: right; }
#acc, #measure {
  font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums;
}

/* push HUD below the sheet-music panel when it's shown (height from JS) */
body.sheet-on #hud-left { top: calc(var(--sheet-h, 164px) + 32px); }
body.sheet-on #hud-center { top: calc(var(--sheet-h, 164px) + 26px); }
body.sheet-on #hud-right { top: calc(var(--sheet-h, 164px) + 32px); }

#progress {
  position: absolute; top: 0; left: 0; right: 0; height: 4px;
  background: rgba(255,255,255,.08);
}
/* replay scrubbing: the top bar grows and takes clicks to seek */
body.replay-scrub #progress {
  height: 14px; pointer-events: auto; cursor: pointer;
  border-bottom: 1px solid rgba(255,255,255,.18);
}
#replay-hint {
  position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
  z-index: 6; pointer-events: none;
  font-size: 12.5px; font-weight: 800; letter-spacing: 1px; color: #9fdcff;
  background: rgba(8,10,22,0.7); padding: 4px 14px; border-radius: 10px;
  border: 1px solid rgba(52,211,255,0.35);
}
body.sheet-on #replay-hint { top: calc(var(--sheet-h, 164px) + 64px); }
#replay-menu-btn {
  position: fixed; top: 18px; right: 18px; z-index: 7;
  width: 44px; height: 44px; border-radius: 12px; cursor: pointer;
  font-size: 20px; font-weight: 900; color: #cfe9ff;
  background: rgba(8,10,22,0.7); border: 1px solid rgba(52,211,255,0.35);
}
#replay-menu-btn:hover { background: rgba(52,211,255,0.2); }
/* keep the top-right HUD clear of the ☰ button when the sheet isn't pushing it down */
body:has(#replay-menu-btn:not(.hidden)):not(.sheet-on) #hud-right { right: 78px; }
/* floating controls fade out while playing until the mouse moves or the game pauses */
.autohide { transition: opacity .45s; }
body.controls-hidden .autohide { opacity: 0; pointer-events: none; }
#progress-fill {
  height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--cyan), var(--gold));
  box-shadow: 0 0 10px rgba(52,211,255,.7);
}

/* ------------------------------------------------------------- Overlays */
.overlay {
  position: fixed; inset: 0; z-index: 10;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(ellipse at 50% 30%, rgba(30,30,60,.92), rgba(5,5,12,.97));
  backdrop-filter: blur(6px);
  /* A panel taller than the window has to be reachable. Without this the
     overlay clipped it: centering pushed the overflow off BOTH edges, so the
     top of a long list (e.g. Free Play's 19 pieces) sat above the viewport
     with nothing able to scroll to it. `safe` keeps short panels centered but
     flushes tall ones to the start, so scrolling always begins at their top. */
  overflow-y: auto;
  align-items: safe center;
}
/* Safari < 15.4 doesn't understand `safe center` and drops the whole
   declaration, which would restore the clipping — fall back to a start-aligned
   overlay whose panel is centered by its own auto margins. */
@supports not (align-items: safe center) {
  .overlay { align-items: flex-start; }
  .overlay > .panel { margin: auto; }
}
.panel { text-align: center; max-width: 560px; padding: 24px; }

.title {
  font-size: 64px; font-weight: 900; font-style: italic; letter-spacing: 2px;
  background: linear-gradient(180deg, #fff, var(--cyan) 55%, #1f7fd0);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 22px rgba(52,211,255,.45));
}
.title.small { font-size: 44px; }
.subtitle { font-size: 18px; font-weight: 500; opacity: .8; margin: 6px 0 18px; }

.midi-status {
  margin: 10px auto 4px; padding: 8px 16px; border-radius: 20px;
  display: inline-block; font-size: 14px; font-weight: 600;
  background: rgba(255, 60, 90, .15); color: #ff8c9e;
  border: 1px solid rgba(255, 60, 90, .35);
}
.midi-status.ok {
  background: rgba(60, 255, 140, .12); color: #7dffb2;
  border-color: rgba(60, 255, 140, .35);
}

.opts { margin: 22px auto; width: 400px; max-width: 90vw; text-align: left; }
.opt-row {
  display: flex; align-items: center; justify-content: space-between;
  margin: 12px 0; font-size: 15px; font-weight: 600; opacity: .95;
}
.seg { display: flex; border-radius: 10px; overflow: hidden; border: 1px solid rgba(255,255,255,.2); }
.seg button {
  padding: 7px 16px; border: none; background: transparent; color: #ccc;
  font: inherit; font-size: 14px; cursor: pointer;
}
.seg button.on { background: var(--cyan); color: #003; font-weight: 800; }
#offset { width: 150px; accent-color: var(--cyan); }

.big-btn {
  display: block; margin: 18px auto 10px; padding: 16px 64px;
  font: inherit; font-size: 24px; font-weight: 900; letter-spacing: 2px;
  color: #002; background: linear-gradient(180deg, #7be2ff, var(--cyan));
  border: none; border-radius: 14px; cursor: pointer;
  box-shadow: 0 0 28px rgba(52,211,255,.45), 0 4px 0 #1585b8;
  transition: transform .1s, box-shadow .1s;
}
.big-btn:hover { transform: translateY(-2px) scale(1.03); box-shadow: 0 0 40px rgba(52,211,255,.7), 0 6px 0 #1585b8; }
.big-btn:active { transform: translateY(2px); box-shadow: 0 0 20px rgba(52,211,255,.4), 0 1px 0 #1585b8; }

.small-btn {
  display: block; margin: 8px auto; padding: 9px 26px;
  font: inherit; font-size: 15px; font-weight: 600; color: #ddd;
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.22);
  border-radius: 10px; cursor: pointer;
}
.small-btn:hover { background: rgba(255,255,255,.16); }

.hint { margin-top: 16px; font-size: 13px; line-height: 1.6; opacity: .55; }

/* --------------------------------------------------------- song selector */
.song-list {
  display: flex; flex-direction: column; gap: 10px;
  margin: 18px auto 8px; width: 430px; max-width: 92vw;
}
.song-card {
  display: flex; align-items: center; justify-content: space-between;
  padding: 13px 18px; border-radius: 12px; cursor: pointer;
  background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.14);
  text-align: left; font: inherit; color: #eee;
  transition: border-color .12s, background .12s, transform .12s;
}
.song-card:hover { background: rgba(255,255,255,0.11); transform: translateY(-1px); }
.song-card.on {
  border-color: var(--cyan);
  background: rgba(52,211,255,0.12);
  box-shadow: 0 0 18px rgba(52,211,255,0.25);
}
.song-card .sc-title { font-size: 17px; font-weight: 800; }
.song-card .sc-sub { font-size: 12.5px; opacity: .65; margin-top: 2px; }
.song-card .sc-right { font-size: 12.5px; opacity: .7; text-align: right; font-variant-numeric: tabular-nums; }
.song-card .sc-best { color: var(--gold); font-weight: 700; }

.mode-row {
  display: flex; gap: 12px; justify-content: center; margin: 4px 0 10px;
}
.mode-btn {
  padding: 12px 22px; font: inherit; font-size: 16px; font-weight: 800;
  letter-spacing: 1px; color: #eee; cursor: pointer; border-radius: 12px;
  background: rgba(255,255,255,0.08); border: 2px solid rgba(255,255,255,0.22);
  transition: background .12s, transform .12s, border-color .12s;
}
.mode-btn:hover:not(:disabled) {
  background: rgba(52,211,255,0.15); border-color: var(--cyan);
  transform: translateY(-2px);
}
/* an in-flight action (e.g. admin SAVE) — looks inert so the dead click reads
   as "already working" rather than "the button is broken" */
.mode-btn:disabled { opacity: .5; cursor: default; }

.current-song { font-size: 15px; opacity: .8; margin-top: 10px; font-weight: 600; }
.midi-select {
  font: inherit; font-size: 13px; padding: 6px 10px; border-radius: 8px;
  background: rgba(255,255,255,0.08); color: #eee;
  border: 1px solid rgba(255,255,255,0.25); max-width: 200px;
}
.midi-select option { background: #14142a; }
#sheetsize { width: 150px; accent-color: var(--cyan); }

/* difficulty + custom song bits on the song cards */
.diff-row { display: inline-flex; gap: 6px; margin-top: 7px; }
.diff-btn {
  padding: 3px 10px; font: inherit; font-size: 11.5px; font-weight: 700;
  color: #bbb; background: rgba(255,255,255,0.07); cursor: pointer;
  border: 1px solid rgba(255,255,255,0.2); border-radius: 20px;
}
.diff-btn.on { background: var(--gold); color: #221; border-color: transparent; }
.sc-custom {
  font-size: 9.5px; font-weight: 900; letter-spacing: 1px; color: #c79bff;
  border: 1px solid rgba(199,155,255,0.5); border-radius: 4px;
  padding: 1px 5px; margin-left: 8px; vertical-align: 2px;
}
.sc-del {
  font: inherit; font-size: 14px; background: none; border: none;
  cursor: pointer; opacity: .55;
}
.sc-del:hover { opacity: 1; }

.upload-box {
  width: 430px; max-width: 92vw; margin: 4px auto 14px; text-align: left;
  font-size: 14px;
}
.upload-box summary { cursor: pointer; font-weight: 700; opacity: .8; padding: 6px 0; }
.upload-form { display: flex; flex-direction: column; gap: 8px; padding: 10px 4px; }
.upload-form input[type=text] {
  font: inherit; font-size: 13.5px; padding: 8px 10px; border-radius: 8px;
  background: rgba(255,255,255,0.07); color: #eee;
  border: 1px solid rgba(255,255,255,0.22);
}
.upload-form .file-row { display: flex; justify-content: space-between; align-items: center; font-size: 13px; opacity: .9; }
.upload-form .tb-btn {
  padding: 9px 14px; font: inherit; font-weight: 700; border-radius: 8px;
  border: none; cursor: pointer; background: var(--cyan); color: #013;
}
.upload-form .tb-btn:disabled { opacity: .4; cursor: default; }
#up-status { font-size: 12.5px; opacity: .8; }

/* stats page */
.stats-content { text-align: left; max-height: 55vh; overflow-y: auto; margin-bottom: 12px; }
.stats-content h3 { margin: 14px 0 6px; font-size: 15px; letter-spacing: 1px; }
.stats-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.stats-table th {
  text-align: left; font-size: 11px; letter-spacing: 1px; opacity: .55;
  padding: 4px 8px; border-bottom: 1px solid rgba(255,255,255,0.2);
}
.stats-table td { padding: 5px 8px; border-bottom: 1px solid rgba(255,255,255,0.07); }

/* ------------------------------------------------------------ VS select */
.vs-cards { display: flex; gap: 14px; justify-content: center; margin: 20px 0; }
.vs-card {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: 150px; padding: 20px 10px; border-radius: 14px; cursor: pointer;
  font: inherit; color: #eee;
  background: rgba(255,255,255,0.06); border: 2px solid rgba(255,255,255,0.16);
  transition: border-color .12s, background .12s, transform .12s;
}
.vs-card:hover {
  border-color: var(--red); background: rgba(255,59,92,0.12);
  transform: translateY(-3px);
}
.vs-emoji { font-size: 40px; }
.vs-name { font-size: 18px; font-weight: 900; letter-spacing: 2px; }
.vs-desc { font-size: 12px; opacity: .6; }

.vs-result {
  font-size: 30px; font-weight: 900; letter-spacing: 1px; margin: 2px 0 10px;
}
.vs-result .win { color: #7dffb2; text-shadow: 0 0 18px rgba(60,255,140,.5); }
.vs-result .lose { color: var(--red); text-shadow: 0 0 18px rgba(255,59,92,.5); }
.vs-result .vs-scores { font-size: 16px; font-weight: 600; opacity: .85; margin-top: 6px; }

/* --------------------------------------------------------- practice bar */
#practice-bar {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(16vh + 14px); z-index: 6;
  display: flex; align-items: center; gap: 16px;
  padding: 8px 16px; border-radius: 12px;
  background: rgba(10,10,22,0.85); border: 1px solid rgba(255,255,255,0.2);
  backdrop-filter: blur(6px); font-size: 13px;
}
#practice-bar .pb-label {
  font-size: 11px; font-weight: 800; letter-spacing: 2px; color: var(--cyan);
}
#practice-bar label { display: flex; align-items: center; gap: 8px; font-weight: 600; }
#practice-bar input[type=range] { width: 130px; accent-color: var(--cyan); }
#practice-bar .seg button { padding: 5px 12px; font-size: 12.5px; }
#practice-bar .small-btn { margin: 0; padding: 6px 14px; font-size: 13px; }

/* -------------------------------------------------------------- Results */
#grade {
  font-size: 130px; font-weight: 900; font-style: italic; line-height: 1;
  background: linear-gradient(180deg, #fff8d0, var(--gold) 60%, #c8860a);
  -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 30px rgba(255,215,94,.55));
  animation: grade-in .6s cubic-bezier(.2, 2.2, .35, 1);
}
@keyframes grade-in {
  from { transform: scale(3.2) rotate(-14deg); opacity: 0; }
  to   { transform: scale(1) rotate(0); opacity: 1; }
}
.final-score { font-size: 52px; font-weight: 800; font-variant-numeric: tabular-nums; margin: 4px 0 14px; }
.result-stats {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px 26px;
  margin: 0 auto 14px; width: 460px; max-width: 92vw; font-size: 16px;
}
.result-stats .stat { display: flex; justify-content: space-between; }
.result-stats .stat b { font-variant-numeric: tabular-nums; }
.st-perfect b { color: var(--gold); }
.st-great b { color: var(--cyan); }
.st-good b { color: #7dff9b; }
.st-ok b { color: #d7e0ea; }
.st-almost b { color: #ffa94d; }
.st-miss b, .st-wrong b { color: var(--red); }
.st-drop b { color: #ff7b4d; }
.new-best {
  font-size: 22px; font-weight: 900; color: var(--gold); letter-spacing: 3px;
  margin-bottom: 8px; animation: fire-pulse .5s infinite alternate;
}
.score-legend { font-size: 12px; margin: 2px auto 8px; max-width: 440px; }
/* quick assist pills, top-left during play (the rival panel sits top-right) —
   50% transparent until hovered */
#play-toggles {
  position: fixed; top: 128px; left: 14px; z-index: 40;
  display: flex; flex-direction: column; gap: 6px; align-items: flex-start;
}
/* keep the pills under the score box when the sheet strip pushes the HUD down */
body.sheet-on #play-toggles { top: calc(var(--sheet-h, 164px) + 130px); }
#play-toggles button {
  opacity: .5; font: inherit; font-size: 12px; font-weight: 800;
  letter-spacing: .5px; color: #d7e0ea; cursor: pointer;
  background: rgba(8, 10, 22, 0.75); border: 1px solid rgba(215, 224, 234, 0.35);
  border-radius: 999px; padding: 6px 12px; text-align: left;
  transition: opacity .15s, border-color .15s, color .15s;
}
#play-toggles button:hover { opacity: 1; }
#play-toggles button.on {
  color: var(--gold); border-color: var(--gold);
}
#play-toggles button.on::after { content: " ·  ON"; }
#play-toggles button:not(.on)::after { content: " · OFF"; opacity: .6; }
body.controls-hidden #play-toggles { opacity: 0; pointer-events: none; transition: opacity .3s; }
#pause-toggles { display: flex; gap: 8px; justify-content: center; margin: 14px 0 10px; }
#pause-toggles button {
  font: inherit; font-size: 12px; font-weight: 800; letter-spacing: .5px;
  color: #d7e0ea; cursor: pointer; background: rgba(8, 10, 22, 0.75);
  border: 1px solid rgba(215, 224, 234, 0.35); border-radius: 999px; padding: 7px 13px;
}
#pause-toggles button.on { color: var(--gold); border-color: var(--gold); }
#pause-toggles button.on::after { content: " · ON"; }
#pause-toggles button:not(.on)::after { content: " · OFF"; opacity: .6; }
/* score multipliers under the final score (difficulty bonus, wait penalty) */
.score-mults { font-size: 12.5px; margin: 0 auto 6px; max-width: 460px; color: var(--gold); }
.signup-cta {
  display: flex; flex-direction: column; gap: 8px; align-items: center;
  margin: 4px auto 10px; padding: 10px 14px; max-width: 440px;
  background: rgba(80, 200, 255, .08); border: 1px solid rgba(80, 200, 255, .35);
  border-radius: 10px; font-size: 14px;
}
.signup-cta .mode-btn { margin: 0; }
/* --------------------------------------------------------------- teams */
.team-forms { display: flex; gap: 18px; justify-content: center; flex-wrap: wrap; }
.team-card {
  width: 260px;
  padding: 14px 16px;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 14px;
  background: rgba(255, 255, 255, .04);
}
.tp-input {
  width: 100%;
  box-sizing: border-box;
  margin: 8px 0;
  padding: 9px 10px;
  border-radius: 9px;
  border: 1px solid rgba(255, 255, 255, .2);
  background: rgba(0, 0, 0, .3);
  color: #fff;
  font: inherit;
}
.team-head {
  display: flex;
  gap: 14px;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 8px;
}
.team-name { font-size: 20px; }
.team-code { font-size: 13px; color: rgba(255, 255, 255, .8); }
.team-goal {
  max-width: 520px;
  margin: 0 auto 12px;
  padding: 10px 14px;
  border: 1px solid rgba(52, 211, 255, .3);
  border-radius: 12px;
  background: rgba(52, 211, 255, .07);
  font-size: 13.5px;
}
.tg-row { display: flex; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.tg-bar { display: block; width: 100%; margin: 2px 0 4px; }
.tg-done { color: var(--gold); font-weight: 800; margin-top: 4px; }
.tg-opts { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin-top: 8px; }
.team-members {
  max-width: 560px;
  margin: 0 auto 10px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.tm-row {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 7px 12px;
  border: 1px solid rgba(255, 255, 255, .12);
  border-radius: 10px;
  background: rgba(255, 255, 255, .04);
  font-size: 13.5px;
}
.tm-name { font-weight: 700; }
.tm-elo { color: rgba(255, 255, 255, .75); }
.tm-mins, .tm-notes { margin-left: auto; color: rgba(255, 255, 255, .75); }
.tm-mins { margin-left: auto; }
.tm-notes { margin-left: 0; }

/* --------------------------------------------------- live-duel spectate */
.spec-live { margin-bottom: 8px; }
.spec-live-list { display: flex; flex-direction: column; gap: 6px; }
.live-row {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 8px 12px;
  border: 1px solid rgba(255, 90, 90, .4);
  border-radius: 10px;
  background: rgba(255, 90, 90, .08);
  color: inherit;
  font: inherit;
  cursor: pointer;
  text-align: left;
}
.live-row:hover { border-color: #ff5a5a; }
.lr-live { color: #ff5a5a; font-size: 11px; font-weight: 800; animation: livepulse 1.6s infinite; }
.lr-song { margin-left: auto; font-size: 12px; color: rgba(255, 255, 255, .7); }
@keyframes livepulse { 50% { opacity: .45; } }

/* ------------------------------------------------------- piano galaxy */
/* the galaxy screen reuses the world-map node grammar (.wm-zone / .wm-bg /
   .wm-ic-wrap) over galaxy.jpg — see renderGalaxy() */
.galaxy-map {
  position: relative; width: 100%; aspect-ratio: 3 / 2; margin: 12px 0 6px;
  border-radius: 14px; overflow: hidden;
  background: linear-gradient(160deg, #10123a, #05060f);
  border: 1px solid rgba(255, 255, 255, .14);
  /* planet radii below are shares of the map's WIDTH; a container query unit
     resolves them against the map instead of against each node */
  container-type: inline-size;
}
/* the galaxy gets the same roomy panel as the zone boards */
#galaxy-screen .panel.wide { width: min(96vw, 1080px); max-width: 1080px; }
/* a node is an invisible round hit target sized to the planet painted beneath
   it, with the label hanging below the globe rather than across it */
/* The maps.json coordinate is the globe's CENTER, and the node is a column of
   [hit circle, label, blurb]. Anchoring the node's TOP at that coordinate and
   lifting it by exactly the circle's radius centers the circle on the globe
   while the label hangs clear below it — independent of how tall the label
   runs, which a translate(-50%,-50%) is not. */
/* .wm-zone (defined further down) centers the whole node on the coordinate;
   two classes here so this wins regardless of source order */
.gx-planet.gx-planet {
  transform: translate(-50%, calc(-1 * var(--gx-r)));
  justify-content: flex-start;
}
.gx-planet .gx-hit {
  display: block; border-radius: 50%;
  width: calc(var(--gx-r) * 2); aspect-ratio: 1;
  transition: box-shadow .15s;
}
.gx-planet:hover .gx-hit, .gx-planet:focus-visible .gx-hit {
  box-shadow: 0 0 0 3px rgba(52, 211, 255, .9), 0 0 26px rgba(52, 211, 255, .55);
}
/* --gx-r is each painted globe's radius, measured off galaxy.jpg */
.gx-world { --gx-r: 11.5cqw; }
.gx-tutorial { --gx-r: 7.2cqw; }
.gx-famous { --gx-r: 6.4cqw; }
.gx-composers { --gx-r: 6.8cqw; }
.gx-moon { --gx-r: 4.6cqw; }
.gx-planet .wm-name { margin-top: 6px; font-size: 14px; }
.gx-planet.locked .wm-name { opacity: .92; }
.gx-planet .gx-prem {
  background: linear-gradient(180deg, #ffd76a, #e8a820);
  color: #4a3000;
}
/* the blurb only unfolds on the planet you're pointing at — the map stays calm */
.gx-planet .gx-desc {
  display: block; max-width: 190px; margin-top: 3px;
  font-size: 11.5px; line-height: 1.4; color: rgba(255, 255, 255, .82);
  opacity: 0; transition: opacity .15s; pointer-events: none;
  text-shadow: 0 1px 4px #000, 0 0 10px #000;
}
.gx-planet:hover .gx-desc, .gx-planet:focus-visible .gx-desc { opacity: 1; }
#world-screen .small-btn + .small-btn { margin-left: 10px; }

/* the zone-boss node on the subzone select — golden and always open */
.wm-zone.boss .wm-ic-wrap {
  border-radius: 50%;
  box-shadow: 0 0 0 3px rgba(255, 200, 60, .85), 0 0 22px rgba(255, 200, 60, .5);
}

/* connectivity advisor — per-device "best setup" hint */
.conn-advice {
  max-width: 360px;
  margin: 6px auto 0;
  padding: 7px 12px;
  border-radius: 10px;
  font-size: 12.5px;
  line-height: 1.45;
  background: rgba(52, 211, 255, .1);
  border: 1px solid rgba(52, 211, 255, .3);
}
.conn-advice.warn {
  background: rgba(255, 196, 106, .1);
  border-color: rgba(255, 196, 106, .35);
}

/* zone lives — hearts row on the board title + duel confirm + results */
.zt-lives { margin-left: 12px; font-size: 14px; letter-spacing: 1px; }
.dc-lives { margin: 2px 0 6px; font-size: 16px; letter-spacing: 2px; }
.rw-life { display: block; margin-top: 6px; }
.rw-life.loss { color: #ff8484; }
.rw-life.out { color: #ffb84d; }

/* golden "this is premium" badge on gated buttons */
.prem-tag {
  background: linear-gradient(180deg, #ffd76a, #e8a820);
  color: #4a3000;
  border-radius: 8px;
  padding: 1px 6px;
  font-size: 11px;
  vertical-align: middle;
}

/* ------------------------------------------------------ career / avatars */
.panel.wide { max-width: 720px; max-height: 94vh; overflow-y: auto; }
/* zone boards get 1.5x the room of a standard wide panel */
#play-screen .panel.wide { width: min(96vw, 1080px); max-width: 1080px; }
/* the admin panel is a two-column workbench (boards + piece bench) plus wide
   analytics tables — it needs the whole window, not a dialog's width */
#admin-page .panel.wide { width: min(97vw, 1400px); max-width: 1400px; }
.sec-h {
  font-size: 15px; letter-spacing: 2px; font-weight: 800; opacity: .8;
  margin: 18px 0 4px;
}
.sec-h em { font-style: italic; opacity: .7; font-weight: 600; }

.player-card {
  display: flex; align-items: center; gap: 12px; margin: 8px auto 2px;
  padding: 8px 16px; border-radius: 14px; cursor: pointer; font: inherit;
  color: #eee; background: rgba(255,255,255,0.07);
  border: 2px solid rgba(255,255,255,0.18); min-width: 300px;
  transition: border-color .12s, background .12s;
}
.player-card:hover { border-color: var(--gold); background: rgba(255,215,94,0.08); }
.pc-avatar { font-size: 34px; }
.pc-info { flex: 1; text-align: left; }
.pc-name { display: block; font-size: 16px; font-weight: 800; }
.pc-level { display: block; font-size: 11.5px; font-weight: 700; color: var(--cyan); letter-spacing: 1px; }
.pc-xpbar {
  display: block; height: 5px; margin-top: 4px; border-radius: 3px;
  background: rgba(255,255,255,.14); overflow: hidden;
}
#pc-xpfill {
  display: block; height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--cyan), #7be2ff);
}
.pc-elo { display: block; font-size: 11px; font-weight: 700; color: #c79bff; letter-spacing: .5px; }
.pc-coins { font-size: 15px; font-weight: 800; color: var(--gold); white-space: nowrap; }
.pc-coins.big { font-size: 20px; margin: 4px 0 6px; }

/* The 🪙 emoji renders SILVER in Apple's font, which reads as the wrong
   currency next to gold prices — so coins are drawn in CSS instead. Sized in
   `em` so one class works from an 11px price chip up to the 20px wallet. */
.coin {
  display: inline-block; vertical-align: -.12em;
  width: 1em; height: 1em; border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, #fff6cf 0%, #ffd75e 42%, #e5a41c 78%, #a86e07 100%);
  box-shadow: inset 0 -.08em .1em rgba(120, 74, 4, .55),
              inset 0 .07em .09em rgba(255, 255, 255, .75);
}

/* the shop's wallet: "Your coins" + balance, so the number is labelled
   rather than a bare figure floating over the pianist art */
.wallet {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 8px auto 10px; padding: 7px 16px; border-radius: 999px;
  border: 1px solid rgba(255, 215, 94, .45);
  background: rgba(255, 215, 94, .12);
}
.wallet .w-label {
  font-size: 11px; font-weight: 800; letter-spacing: 1.4px;
  text-transform: uppercase; color: rgba(255, 255, 255, .62);
}
.wallet .w-amt {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 20px; font-weight: 800; color: var(--gold);
}

/* ------------------------------------------------------ shop tabs + pieces */
.shop-tabs { justify-content: center; margin: 4px 0 2px; }

.shop-filter {
  display: flex; align-items: center; justify-content: center;
  gap: 12px; flex-wrap: wrap; margin: 8px 0 4px;
}
.shop-filter input[type=search] {
  flex: 1 1 240px; max-width: 320px; padding: 7px 12px;
  border-radius: 999px; font: inherit; font-size: 13px; color: #eee;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .18);
}
.shop-filter input[type=search]:focus { outline: none; border-color: var(--cyan); }
.cp-only-buy {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: rgba(255, 255, 255, .68); cursor: pointer;
  white-space: nowrap;
}
.cp-only-buy input { accent-color: var(--cyan); }

.piece-shop { display: flex; flex-direction: column; gap: 8px; margin: 6px 0 2px; }
.piece-shop.busy { pointer-events: none; opacity: .6; }
.piece-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; flex-wrap: wrap; padding: 10px 14px; border-radius: 12px;
  background: rgba(255, 255, 255, .05);
  border: 1px solid rgba(255, 255, 255, .12);
  text-align: left;
}
/* a fully-owned piece recedes — the eye should land on what's still buyable */
.piece-row.all-owned { opacity: .62; }
.pr-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.pr-title { font-size: 14.5px; }
.pr-composer { font-size: 11.5px; color: rgba(255, 255, 255, .55); }
/* the campaign route stays visible, so buying reads as a shortcut not a toll */
.pr-hint { font-size: 11px; color: rgba(255, 255, 255, .5); margin-top: 4px; line-height: 1.5; }
.pr-hint b { color: rgba(255, 255, 255, .72); font-weight: 700; }
.pr-diffs { display: flex; gap: 6px; flex: 0 0 auto; }

/* one difficulty: a buy button when locked, a flat chip when owned */
.pz {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 76px; padding: 7px 10px; border-radius: 10px;
  font: inherit; font-size: 12px; color: #eee;
  border: 1px solid rgba(255, 255, 255, .16);
  background: rgba(255, 255, 255, .06);
}
.pz b { font-size: 12.5px; font-weight: 800; }
.pz-price { display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 800; color: var(--gold); }
.pz-state { font-size: 10.5px; font-weight: 700; letter-spacing: .3px; }
button.pz { cursor: pointer; transition: border-color .12s, transform .12s; }
button.pz:hover { transform: translateY(-2px); border-color: var(--gold); }
button.pz.cant { opacity: .45; }
button.pz.cant:hover { transform: none; border-color: rgba(255, 255, 255, .16); }
/* won on the map vs bought with coins — both owned, but worth telling apart */
.pz.won { border-color: rgba(52, 211, 255, .4); background: rgba(52, 211, 255, .1); }
.pz.won .pz-state { color: var(--cyan); }
.pz.bought { border-color: rgba(255, 215, 94, .4); background: rgba(255, 215, 94, .1); }
.pz.bought .pz-state { color: var(--gold); }
@media (max-width: 560px) {
  .piece-row { flex-direction: column; align-items: stretch; gap: 8px; }
  .pr-diffs { justify-content: space-between; }
  .pz { flex: 1 1 0; min-width: 0; }
}

.char-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  margin: 14px auto 6px; max-width: 460px;
}
.char-grid button {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 12px 6px; border-radius: 12px; cursor: pointer; font: inherit;
  color: #eee; background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.16);
  transition: border-color .12s, transform .12s;
}
.char-grid button:hover { transform: translateY(-2px); border-color: var(--cyan); }
.char-grid button.on {
  border-color: var(--gold); background: rgba(255,215,94,0.12);
  box-shadow: 0 0 16px rgba(255,215,94,0.3);
}
.char-grid .cg-emoji { font-size: 36px; }
.char-grid .cg-name { font-size: 12.5px; font-weight: 700; }
.char-grid.small .cg-emoji { font-size: 28px; }
/* locked pianists advertise their price; unlocked ones just say "switch" */
.char-grid .cg-price { font-size: 11px; font-weight: 800; color: var(--gold); }

/* selected-pianist spotlight: big hero art + backstory card */
.char-lore {
  display: flex;
  gap: 16px;
  align-items: center;
  text-align: left;
  max-width: 560px;
  margin: 10px auto 4px;
  padding: 12px 16px;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: 14px;
  background: rgba(255, 255, 255, .05);
}
.char-lore .cl-art { flex: 0 0 auto; }
.char-lore .cg-img { width: 148px; height: 148px; object-fit: contain;
  filter: drop-shadow(0 6px 14px rgba(0, 0, 0, .45)); }
.char-lore .cg-emoji { font-size: 96px; line-height: 148px; }
.char-lore .cl-name { font-size: 19px; }
.char-lore .cl-tag { display: block; color: var(--cyan); font-size: 12.5px;
  font-weight: 700; margin: 2px 0 6px; }
.char-lore .cl-story { margin: 0; font-size: 13px; line-height: 1.45;
  color: rgba(255, 255, 255, .82); }
@media (max-width: 640px) {
  .char-lore { flex-direction: column; text-align: center; gap: 8px; }
}
/* action row under the browsed pianist's profile — the ONLY place coins are
   spent, so browsing the grid stays free */
.cp-actions {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  margin: 10px 0 2px; min-height: 20px;
}
.cp-actions .big-btn { display: inline-flex; align-items: center; gap: 7px; }
.cp-actions .big-btn.cant { opacity: .5; }
.cp-hint { font-size: 12px; color: rgba(255, 255, 255, .62); }
.cp-hint b { color: var(--gold); }

.char-grid button:not(.locked) .cg-price { color: var(--cyan); }
.char-grid button.on .cg-price { color: var(--gold); opacity: .8; }
.char-grid button.cant { opacity: .45; }
/* the pianist whose profile is on screen — distinct from .on ("wearing"),
   since you can be reading about someone you haven't unlocked. Gold still
   wins on the pianist you're wearing, so "wearing" never turns cyan. */
.char-grid button.viewing:not(.on) {
  border-color: var(--cyan); background: rgba(52, 211, 255, .12);
}
.char-grid button.viewing.cant { opacity: .8; }
/* a purchase is settling on the server — don't let a second click through */
.char-grid.busy { pointer-events: none; opacity: .6; }

.skill-cards {
  display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px;
  margin: 12px auto 4px; max-width: 460px;
}
.skill-cards button {
  padding: 12px; border-radius: 12px; cursor: pointer; font: inherit;
  color: #eee; background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.16); text-align: center;
}
.skill-cards button b { display: block; font-size: 15px; }
.skill-cards button span { font-size: 11.5px; opacity: .6; }
.skill-cards button:hover { border-color: var(--cyan); }
.skill-cards button.on {
  border-color: var(--gold); background: rgba(255,215,94,0.12);
}

/* ------------------------------------------- connect your keyboard */
.ck-status {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  margin: 16px auto 4px; max-width: 460px; padding: 9px 14px;
  border-radius: 11px; font-size: 13px; font-weight: 800;
  border: 1px solid rgba(255,255,255,0.16); background: rgba(255,255,255,0.05);
}
.ck-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  background: var(--gold); box-shadow: 0 0 8px var(--gold);
}
.ck-status.searching .ck-dot { animation: zmPulse 1.4s infinite; }
.ck-status.found { border-color: #3cff8c; background: rgba(60,255,140,0.10); color: #a9ffcd; }
.ck-status.found .ck-dot { background: #3cff8c; box-shadow: 0 0 8px #3cff8c; animation: none; }
/* permission hard-denied: the player has to unblock it in site settings, so
   this is a call to action rather than a "still looking" state */
.ck-status.blocked {
  border-color: var(--red); background: rgba(255,59,92,0.10); color: #ffb3c0;
}
.ck-status.blocked .ck-dot { background: var(--red); box-shadow: 0 0 8px var(--red); animation: none; }
.ck-steps {
  list-style: none; margin: 14px auto 0; padding: 0; max-width: 520px;
  display: flex; flex-direction: column; gap: 10px; text-align: left;
}
.ck-steps li {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 11px 13px; border-radius: 12px;
  background: rgba(255,255,255,0.05); border: 1px solid rgba(255,255,255,0.12);
}
.ck-steps { counter-reset: ck; }
.ck-steps li { counter-increment: ck; }
.ck-num {
  flex: none; width: 25px; height: 25px; border-radius: 50%; display: grid;
  place-items: center; font-size: 13px; font-weight: 900; color: var(--gold);
  background: rgba(10,12,26,0.7); border: 2px solid var(--gold);
}
.ck-num::before { content: counter(ck); }
#ck-device { width: fit-content; margin: 10px auto 12px; }
.ck-buy { font-size: 12px; opacity: .85; }
.ck-buy a {
  display: inline-block; margin: 2px 4px 0 4px; color: var(--cyan);
  font-weight: 700; text-decoration: none; border-bottom: 1px dotted currentColor;
}
.ck-buy a.rec { color: var(--gold); }
.ck-buy a.rec::after { content: " ★ recommended"; font-size: 10px; }
.ck-body a { color: var(--cyan); }
.ck-body { display: flex; flex-direction: column; gap: 3px; }
.ck-body b { font-size: 13.5px; }
.ck-body > span { font-size: 12px; line-height: 1.55; opacity: .68; }
.ck-body em { color: var(--cyan); font-style: normal; font-weight: 700; }
.ck-actions {
  display: flex; gap: 10px; align-items: center; justify-content: center;
  margin-top: 16px; flex-wrap: wrap;
}

.cp-preview { font-size: 64px; margin: 6px 0 0; line-height: 1.2; }
.cp-preview .cp-gear { font-size: 30px; letter-spacing: 4px; display: block; }

.shop-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px;
  margin: 12px auto 14px; max-width: 520px;
}
.shop-grid button {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 4px; border-radius: 12px; cursor: pointer; font: inherit;
  color: #eee; background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.16);
}
.shop-grid button:hover { border-color: var(--cyan); }
.shop-grid button.equipped { border-color: var(--gold); background: rgba(255,215,94,0.12); }
.shop-grid button.cant { opacity: .45; }
.shop-grid .sg-emoji { font-size: 28px; }
.shop-grid .sg-name { font-size: 11px; font-weight: 700; }
.shop-grid .sg-price { font-size: 11px; color: var(--gold); font-weight: 800; }

/* ------------------------------------------------------------- zone map */
.zone-map {
  position: relative; width: 100%; aspect-ratio: 3 / 2; margin: 12px 0 6px;
  border-radius: 14px; overflow: hidden;
  background: linear-gradient(160deg, #1c2340, #0d1128);
  border: 1px solid rgba(255,255,255,0.14);
}
.zm-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* --------------------------------------------------------- route overlay
   The drawn route through a map's nodes (main.js pathOverlay), shared by the
   world map, the subzone select and the boards. It sits above the art but
   below every node, and never eats clicks. */
.map-path {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 1; pointer-events: none; overflow: visible;
}
.map-path path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
/* the viewBox is 0-100 on both axes and does NOT preserve aspect ratio, so
   scaled strokes would come out thicker horizontally than vertically —
   non-scaling-stroke pins every width to real pixels instead */
.map-path .mp-case, .map-path .mp-leg { vector-effect: non-scaling-stroke; }
.map-path .mp-case { stroke: rgba(6,8,20,0.55); stroke-width: 9; }
.map-path .mp-leg { stroke-width: 5; }
/* walked: solid gold. next: brighter, with dashes marching toward the node
   you're headed for. beyond: a faint dotted hint of where the road goes. */
.map-path .mp-done { stroke: rgba(255,215,94,0.92); }
.map-path .mp-next {
  stroke: #fff2c2; stroke-width: 5.5;
  stroke-dasharray: 7 9;
  filter: drop-shadow(0 0 4px rgba(255,215,94,0.9));
  animation: mpMarch 1.1s linear infinite;
}
.map-path .mp-todo {
  stroke: rgba(255,255,255,0.34); stroke-width: 4; stroke-dasharray: 1 10;
}
/* dashoffset counts down so the dashes travel FORWARD along the leg (toward
   the next node); one period is dasharray's total length */
@keyframes mpMarch { to { stroke-dashoffset: -16; } }
@media (prefers-reduced-motion: reduce) {
  .map-path .mp-next { animation: none; }
}
.zm-space {
  position: absolute; transform: translate(-50%, -50%); z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: none; border: none; cursor: pointer; font: inherit; padding: 0;
}
.zm-dot {
  width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
  font-size: 15px; font-weight: 900; color: var(--gold);
  background: rgba(10,12,26,0.78); border: 2.5px solid var(--gold);
  box-shadow: 0 2px 10px rgba(0,0,0,0.55);
  transition: transform .12s;
}
/* lift the whole space above the rivals so its tooltip isn't covered by a
   rival's name label — z-index on .zm-piece alone can't escape this
   stacking context */
.zm-space:hover, .zm-space:focus-visible { z-index: 8; }
.zm-space:hover .zm-dot { transform: scale(1.15); }
.zm-space.beaten .zm-dot { border-color: #7dffb2; color: #7dffb2; }
.zm-space.avail .zm-dot { animation: zmPulse 1.7s infinite; }
.zm-space.locked { cursor: default; opacity: .6; }
.zm-space.denied { animation: wmDeny .3s; }
.zm-space.locked:hover .zm-dot { transform: none; }
/* piece title is a tooltip: hidden until the space is hovered/focused */
.zm-piece {
  /* placeBio()-style nudging keeps long titles inside the map (margin-left) */
  position: absolute; top: calc(100% + 8px); left: 50%;
  transform: translate(-50%, -4px); z-index: 6; pointer-events: none;
  font-size: 10.5px; font-weight: 800; color: #fff; white-space: nowrap;
  background: rgba(8,10,22,0.92); padding: 3px 9px; border-radius: 8px;
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: 0 4px 14px rgba(0,0,0,0.55);
  opacity: 0; visibility: hidden; transition: opacity .12s, transform .12s;
}
.zm-space:hover .zm-piece,
.zm-space:focus-visible .zm-piece {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
.zm-enemy {
  /* rivals stand to the SIDE of their space, not stacked above it — stacking
     put two rivals in the same column wherever the path doubles back, and the
     taller (boss) figure covered its neighbour. The renderer picks a side and
     tags .side-left / .side-right. */
  position: absolute; z-index: 3;
  display: flex; flex-direction: column; align-items: center; gap: 0;
  background: none; border: none; padding: 0; font: inherit; color: inherit;
  cursor: pointer; transition: opacity .2s;
}
/* sit level with the dot, offset just clear of its 34px width */
.zm-enemy.side-left { transform: translate(-100%, -62%); margin-left: -14px; }
.zm-enemy.side-right { transform: translate(0, -62%); margin-left: 14px; }
.zm-enemy:hover, .zm-enemy:focus-visible { z-index: 7; outline: none; }
.zm-enemy:hover .zm-face-wrap, .zm-enemy:focus-visible .zm-face-wrap { transform: scale(1.08); }
.zm-face-wrap { font-size: 52px; line-height: 1; transition: transform .12s; }
.zm-face { width: 84px; height: 84px; object-fit: contain;
  filter: drop-shadow(0 4px 7px rgba(0,0,0,0.5)); }
.zm-enemy.boss .zm-face { width: 108px; height: 108px; }
.zm-enemy.boss .zm-face-wrap { font-size: 68px; }
.zm-enemy.defeated { opacity: .5; }
/* the rival whose spaces are currently in play glows; rivals further up the
   path wait greyed-out until the player reaches them */
.zm-enemy.next .zm-face-wrap {
  animation: rivalGlow 1.5s ease-in-out infinite alternate;
}
@keyframes rivalGlow {
  from { filter: drop-shadow(0 0 6px rgba(255,215,94,.85)) drop-shadow(0 0 16px rgba(255,215,94,.45)); }
  to   { filter: drop-shadow(0 0 12px rgba(255,215,94,1)) drop-shadow(0 0 30px rgba(255,171,46,.7)); }
}
.zm-enemy.next .zm-ename { color: var(--gold); }
.zm-enemy.waiting .zm-face-wrap { filter: grayscale(1) brightness(.55); opacity: .8; }
.zm-enemy.waiting .zm-ename { opacity: .55; }
.zm-enemy.defeated .zm-face { filter: grayscale(1) drop-shadow(0 4px 7px rgba(0,0,0,0.5)); }
.zm-enemy.defeated .zm-face-wrap { filter: grayscale(1); }
.zm-ename {
  font-size: 10px; font-weight: 900; letter-spacing: .6px; color: #fff;
  background: rgba(8,10,22,0.74); padding: 1px 7px; border-radius: 7px;
  margin-top: -4px;
}
.zm-enemy.boss .zm-ename { color: var(--red); }
.zm-enemy.defeated .zm-ename { color: #7dffb2; }
/* rival bio card — appears on hover/focus, click opens the full profile */
.zm-bio {
  /* placeBio() nudges this with margin-left / margin-top so the card always
     lands inside the map; margins reflow reliably where a calc() in transform
     does not re-resolve when only a custom property changes */
  position: absolute; bottom: calc(100% + 6px); left: 50%;
  transform: translate(-50%, 4px);
  z-index: 8; pointer-events: none;
  width: 212px; display: flex; flex-direction: column; gap: 4px;
  padding: 8px 10px; border-radius: 11px; text-align: left;
  background: rgba(8,10,22,0.95); border: 1px solid rgba(255,255,255,0.2);
  box-shadow: 0 8px 24px rgba(0,0,0,0.6);
  opacity: 0; visibility: hidden; transition: opacity .14s, transform .14s;
}
.zm-enemy:hover .zm-bio, .zm-enemy:focus-visible .zm-bio {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
.zm-bio-name { font-size: 12px; font-weight: 900; letter-spacing: .5px; color: var(--gold); }
.zm-bio-story { font-size: 10.5px; line-height: 1.45; color: #dfe3f5; white-space: normal; }
.zm-bio-trait {
  font-size: 9.5px; font-weight: 700; line-height: 1.35; white-space: normal;
  padding: 3px 6px; border-radius: 6px;
}
.zm-bio-trait.good { background: rgba(60,255,140,.10); color: #a9ffcd; }
.zm-bio-trait.bad { background: rgba(255,59,92,.10); color: #ffb3c0; }
.zm-bio-more { font-size: 9px; font-weight: 800; color: #8b93b8; letter-spacing: .4px; }
/* placeBio() adds .flip when the card would overflow the top of the map */
.zm-bio.flip { bottom: auto; top: calc(100% + 6px); }
.zm-player { position: absolute; transform: translate(-118%, -80%); z-index: 4; pointer-events: none; }
.zm-lock {
  position: absolute; inset: 0; z-index: 5; display: grid; place-items: center;
  background: rgba(5,6,14,0.55); backdrop-filter: blur(1.5px);
  font-weight: 900; color: var(--gold); font-size: 15px; text-align: center;
}
@keyframes zmPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(255,209,94,0.55); }
  50% { box-shadow: 0 0 0 10px rgba(255,209,94,0); }
}

/* ------------------------------------------------------------ world map */
/* ten labeled nodes need more room than the default wide panel — panels
   shrink to fit their content, so this one gets an explicit width */
#world-screen .panel { width: min(96vw, 1290px); max-width: 1290px; }
.world-map {
  position: relative; width: 100%; aspect-ratio: 3 / 2; margin: 12px 0 6px;
  border-radius: 14px; overflow: hidden;
  background: linear-gradient(160deg, #123, #0d1128);
  border: 1px solid rgba(255,255,255,0.14);
}
.wm-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.wm-zone {
  position: absolute; transform: translate(-50%, -50%); z-index: 2;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  background: none; border: none; cursor: pointer; font: inherit; padding: 0;
}
.wm-ic-wrap {
  position: relative; width: 64px; height: 64px; display: grid;
  place-items: center; transition: transform .12s;
  filter: drop-shadow(0 5px 9px rgba(0,0,0,0.55));
}
.wm-zone:hover .wm-ic-wrap, .wm-zone:focus-visible .wm-ic-wrap { transform: scale(1.14); }
.wm-icon { width: 100%; height: 100%; object-fit: contain; }
.wm-emoji { display: none; font-size: 40px; line-height: 1; }
.wm-ic-wrap.noart .wm-emoji { display: block; }
.wm-name {
  font-size: 10px; font-weight: 900; letter-spacing: .5px; color: #fff;
  background: rgba(8,10,22,0.78); padding: 2px 8px; border-radius: 8px;
  white-space: nowrap;
}
.wm-zone.here .wm-name { color: var(--gold); }
.wm-zone.here .wm-ic-wrap::after {
  content: ""; position: absolute; inset: -6px; border-radius: 50%;
  border: 2.5px solid var(--gold); animation: zmPulse 1.7s infinite;
}
.wm-check {
  position: absolute; top: -2px; right: -4px; width: 20px; height: 20px;
  border-radius: 50%; display: grid; place-items: center;
  font-size: 12px; font-weight: 900; color: #06331a;
  background: #7dffb2; border: 2px solid #06331a;
}
.wm-zone.locked { cursor: default; }
.wm-zone.locked .wm-icon, .wm-zone.locked .wm-emoji {
  filter: grayscale(1) brightness(.55);
}
.wm-zone.locked .wm-name { color: #8b93b8; }
.wm-lock-ic {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 22px; text-shadow: 0 2px 6px rgba(0,0,0,0.8);
}
/* unlock requirement is a hover tooltip, like the zone-map piece titles */
.wm-req {
  position: absolute; top: calc(100% + 6px); left: 50%;
  transform: translate(-50%, -4px); z-index: 6; pointer-events: none;
  font-size: 10.5px; font-weight: 800; color: #fff; white-space: nowrap;
  background: rgba(8,10,22,0.92); padding: 3px 9px; border-radius: 8px;
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: 0 4px 14px rgba(0,0,0,0.55);
  opacity: 0; visibility: hidden; transition: opacity .12s, transform .12s;
}
.wm-zone:hover .wm-req, .wm-zone:focus-visible .wm-req {
  opacity: 1; visibility: visible; transform: translate(-50%, 0);
}
.wm-zone.denied { animation: wmDeny .3s; }
/* gold "STARTER ZONE" tag under the level-1 node, and its title-bar twin */
.wm-starter {
  display: block; font-size: 8px; letter-spacing: 1.2px; color: var(--gold);
  margin-top: 1px;
}
.zt-starter { font-size: 12px; letter-spacing: 1.5px; color: var(--gold); }
/* subzone-select nodes reuse the world-map node look inside the zone map */
.zm-subzone { z-index: 3; }
.zm-subzone .wm-ic-wrap { width: 74px; height: 74px; }
@keyframes wmDeny {
  0%, 100% { translate: 0 0; } 25% { translate: -5px 0; }
  50% { translate: 5px 0; } 75% { translate: -3px 0; }
}
.wm-player { position: absolute; transform: translate(-125%, -95%); z-index: 4; pointer-events: none; }
/* big cartoon hand nudging the player toward the zone they should tap. Sits
   opposite the player token (which hangs off the node's left) and bobs toward
   the node so the gesture reads as "tap this one". */
.wm-hand {
  position: absolute; z-index: 6; pointer-events: none;
  font-size: 68px; line-height: 1;
  filter: drop-shadow(0 5px 12px rgba(0,0,0,0.8));
  transform-origin: center;
  /* line the finger up with the middle of the 64px zone icon, which sits
     above the name chip — not with the node's own anchor point */
  margin-top: -14px;
  animation: wmHandBob 1.15s ease-in-out infinite;
}
/* the emoji points right, so the default sits right-of-node pointing back
   at it via a horizontal flip; near the right edge it moves left and un-flips */
.wm-hand { margin-left: 46px; scale: -1 1; }
.wm-hand.flip { margin-left: -46px; scale: 1 1; }
@keyframes wmHandBob {
  0%, 100% { translate: 0 -50%; }
  50% { translate: -11px -50%; }
}
.wm-hand.flip { animation-name: wmHandBobFlip; }
@keyframes wmHandBobFlip {
  0%, 100% { translate: -100% -50%; }
  50% { translate: calc(-100% + 11px) -50%; }
}
@media (prefers-reduced-motion: reduce) {
  .wm-hand { animation: none; }
}

/* ---------------------------------------------------------------- arena */
.arena-roster {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
  margin: 14px 0 4px;
}
.opp-card {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 14px 8px 12px; border-radius: 14px; cursor: pointer; font: inherit;
  color: #eee; background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.16);
  transition: border-color .12s, transform .12s;
}
.opp-card:hover { border-color: var(--red); transform: translateY(-2px); }
.opp-card.locked { opacity: .38; cursor: default; }
.opp-card.locked:hover { border-color: rgba(255,255,255,0.16); transform: none; }
.opp-card.boss { border-color: rgba(255,59,92,0.55); }
.opp-card .oc-emoji { font-size: 38px; }
.opp-card .oc-name { font-size: 14.5px; font-weight: 900; letter-spacing: .5px; }
.opp-card .oc-piece { font-size: 11.5px; color: var(--cyan); font-weight: 700; }
.opp-card .oc-desc { font-size: 11px; opacity: .55; font-style: italic; }
.opp-card .oc-bounty { font-size: 12px; color: var(--gold); font-weight: 800; }
.opp-card .oc-beaten { color: #7dffb2; font-size: 12px; font-weight: 800; }
.opp-card .oc-boss-tag {
  position: absolute; top: -9px; left: 50%; transform: translateX(-50%);
  font-size: 9.5px; font-weight: 900; letter-spacing: 2px; color: #fff;
  background: var(--red); padding: 2px 8px; border-radius: 8px;
}
/* full 30-pianist roster: tighter grid, scrolls inside the panel */
.arena-roster.spec {
  grid-template-columns: repeat(5, 1fr); gap: 10px;
  max-height: 48vh; overflow-y: auto; padding-right: 6px;
}
.arena-roster.spec .opp-card.pick-a { border-color: var(--cyan); box-shadow: 0 0 14px rgba(52,211,255,.4); }
.arena-roster.spec .opp-card.pick-b { border-color: var(--orange); box-shadow: 0 0 14px rgba(255,171,46,.4); }

/* --------------------------------------------------------- song filters */
.filter-bar {
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
  margin: 12px auto 0; max-width: 500px;
}
.filter-bar.sub { margin-top: 8px; }
.filter-bar .chip {
  padding: 6px 16px; font: inherit; font-size: 13px; font-weight: 700;
  color: #ccc; background: rgba(255,255,255,0.07); cursor: pointer;
  border: 1px solid rgba(255,255,255,0.22); border-radius: 20px;
}
.filter-bar .chip.on { background: var(--cyan); color: #003; border-color: transparent; }
.diff-btn.locked { opacity: .4; }
/* locked pieces stay fully browsable — just visibly dimmed */
.song-card.locked { opacity: .78; }
.sc-locks {
  display: block;
  font-size: 11.5px;
  line-height: 1.55;
  color: #ffc46a;
  margin-top: 4px;
}
.sc-locks.flash { animation: lockflash .6s; }
@keyframes lockflash {
  0%, 100% { color: #ffc46a; }
  50% { color: #ff7a7a; }
}
.sc-pop { font-size: 11px; color: #c79bff; font-weight: 700; }

/* ------------------------------------------------------ rewards + flourish */
.rewards {
  font-size: 17px; font-weight: 800; color: var(--gold); margin: 0 0 10px;
  letter-spacing: .5px;
}
.rewards .rw-unlock { display: block; color: #7dffb2; margin-top: 4px; }
.rewards .rw-elo { display: block; color: #c79bff; margin-top: 4px; }
.rewards .rw-demote { display: block; color: #ff8c9e; margin-top: 4px; }
.rewards .rw-levelup {
  display: block; color: var(--cyan); margin-top: 4px;
  animation: fire-pulse .5s infinite alternate;
}

#flourish { z-index: 40; cursor: pointer; }
#flourish-stage { text-align: center; }
#flourish-avatar {
  font-size: 150px; line-height: 1.15;
  animation: flourish-bow 3s ease-in-out;
}
@keyframes flourish-bow {
  0%   { transform: scale(.4) translateY(60px); opacity: 0; }
  18%  { transform: scale(1.25) translateY(-14px) rotate(-8deg); opacity: 1; }
  32%  { transform: scale(1) rotate(6deg); }
  46%  { transform: scale(1.1) rotate(-4deg); }
  62%  { transform: scale(1) rotate(0); }
  78%  { transform: scale(1.05) translateY(-8px); }
  100% { transform: scale(1) translateY(0); }
}
#flourish-crowd {
  font-size: 40px; letter-spacing: 10px;
  animation: crowd-jump .45s infinite alternate ease-in-out;
}
@keyframes crowd-jump {
  from { transform: translateY(0); }
  to   { transform: translateY(-14px); }
}
#flourish-text {
  margin-top: 14px; font-size: 26px; font-weight: 900; letter-spacing: 4px;
  color: var(--gold); animation: fire-pulse .5s infinite alternate;
}

#vs-intro { z-index: 41; pointer-events: none; flex-direction: column; }
#vs-intro-row { display: flex; align-items: center; gap: 40px; }
.vi-side { font-size: 120px; }
#vi-you { animation: vi-in-left .5s cubic-bezier(.2,1.6,.4,1); }
#vi-opp { animation: vi-in-right .5s cubic-bezier(.2,1.6,.4,1); }
@keyframes vi-in-left { from { transform: translateX(-50vw); } to { transform: none; } }
@keyframes vi-in-right { from { transform: translateX(50vw); } to { transform: none; } }
.vi-vs {
  font-size: 64px; font-weight: 900; font-style: italic; color: var(--red);
  text-shadow: 0 0 26px rgba(255,59,92,.7);
}
#vs-intro-names { margin-top: 10px; font-size: 22px; font-weight: 800; letter-spacing: 1px; }

/* ------------------------------------------------------- menu + zones */
.menu-stack {
  display: flex; flex-direction: column; gap: 10px;
  width: 300px; margin: 4px auto 8px;
}
.menu-stack .mode-btn { width: 100%; }
.small-row { display: flex; gap: 10px; justify-content: center; }
.small-row .small-btn { margin: 8px 0; }

.ps-hero {
  display: flex; align-items: center; gap: 16px; justify-content: center;
  margin: 4px auto 10px; padding: 12px 22px; border-radius: 16px;
  background: rgba(255,255,255,0.06); border: 2px solid rgba(255,255,255,0.16);
  width: fit-content; min-width: 340px;
}
.ps-avatar { font-size: 56px; }
.ps-info { text-align: left; display: flex; flex-direction: column; gap: 3px; }
.ps-info b { font-size: 20px; }
.ps-level { font-size: 13px; font-weight: 800; color: var(--cyan); letter-spacing: 1px; }
.ps-xp { font-size: 12px; opacity: .75; font-weight: 600; }
.ps-hero .pc-xpbar { width: 200px; }
.ps-hero .pc-xpbar span {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--cyan), #7be2ff);
}

.zone-nav {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  margin: 10px 0 2px;
}
.zone-title { font-size: 20px; font-weight: 700; letter-spacing: .5px; min-width: 300px; }
.zone-title b { color: var(--gold); }
.zone-arrow {
  font: inherit; font-size: 18px; font-weight: 900; color: #eee;
  width: 42px; height: 42px; border-radius: 50%; cursor: pointer;
  background: rgba(255,255,255,0.08); border: 2px solid rgba(255,255,255,0.22);
}
.zone-arrow:hover:not(:disabled) { border-color: var(--cyan); background: rgba(52,211,255,0.15); }
.zone-arrow:disabled { opacity: .25; cursor: default; }

.spec-opts {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  margin: 12px 0 4px;
}
.spec-opts .midi-select { max-width: 320px; }
#zone-roster { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
#zone-roster .opp-card { width: 230px; }

/* ----------------------------------------------------------- leaderboard */
.lb-note { font-size: 12px; opacity: .6; margin: 2px 0 8px; }
.lb-av {
  width: 24px; height: 24px; object-fit: contain; vertical-align: -7px;
  margin-right: 6px;
}
/* layered human avatar in a table row — contain the bg layer's z-index */
.lb-av-wrap {
  display: inline-block; position: relative; z-index: 0;
  vertical-align: -8px; margin-right: 6px;
}
.bp-av { display: inline-block; position: relative; z-index: 0; }
.lb-div {
  font-size: 11px; font-weight: 800; letter-spacing: .5px;
  padding: 2px 8px; border-radius: 9px; white-space: nowrap;
  background: rgba(255,255,255,0.08);
}
.lb-div.bronze   { color: #e8a06c; background: rgba(205,127,50,0.15); }
.lb-div.silver   { color: #cdd3e0; background: rgba(200,210,230,0.13); }
.lb-div.gold     { color: var(--gold); background: rgba(255,215,94,0.14); }
.lb-div.platinum { color: #8fe6ff; background: rgba(52,211,255,0.14); }
.lb-div.diamond  { color: #c79bff; background: rgba(199,155,255,0.16); }
.lb-you td { background: rgba(52,211,255,0.10); }
.lb-youtag {
  font-size: 9px; font-weight: 900; letter-spacing: 1px; color: #013;
  background: var(--cyan); padding: 1px 6px; border-radius: 6px;
  vertical-align: 1px;
}
.stats-table tr[data-player] { cursor: pointer; }
.stats-table tr[data-player]:hover td { background: rgba(52,211,255,.07); }

/* rival profile card */
.bp-panel { max-width: 470px; }
.bp-img { width: 150px; height: 150px; object-fit: contain; }
.bp-hero { font-size: 96px; line-height: 1.2; }
.bp-name { font-size: 30px; font-weight: 900; margin: 2px 0; }
.bp-rank { margin-bottom: 8px; font-weight: 800; }
.bp-elo { color: #c79bff; margin-left: 6px; }
.bp-story {
  font-size: 14.5px; line-height: 1.65; opacity: .92;
  margin: 8px 0 12px; text-align: left;
}
.bp-trait {
  font-size: 13px; text-align: left; margin: 5px 0;
  padding: 7px 12px; border-radius: 10px;
}
.bp-trait.good { background: rgba(60,255,140,.08); color: #a9ffcd; border: 1px solid rgba(60,255,140,.25); }
.bp-trait.bad { background: rgba(255,59,92,.08); color: #ffb3c0; border: 1px solid rgba(255,59,92,.25); }
.bp-record { margin: 12px 0 4px; font-size: 14px; }
.bp-duels { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 8px; }
.bp-duel { font-size: 11px; font-weight: 800; padding: 2px 8px; border-radius: 8px; }
.bp-duel.w { background: rgba(60,255,140,.15); color: #7dffb2; }
.bp-duel.l { background: rgba(255,59,92,.15); color: #ff8c9e; }

/* --------------------------------------------------------- admin panel */
/* the save button sits mid-panel and #admin-status is way down at the bottom,
   so a save could look like it did nothing — this floats the outcome over the
   panel where the eye already is */
#admin-toast {
  position: fixed; left: 50%; bottom: 32px; z-index: 60;
  transform: translate(-50%, 12px);
  padding: 10px 18px; border-radius: 12px;
  font-size: 14px; letter-spacing: .5px; text-align: left; max-width: 80vw;
  background: rgba(10,10,20,0.95); color: #fff;
  border: 1px solid rgba(52,211,255,0.6);
  box-shadow: 0 6px 24px rgba(0,0,0,0.5);
  opacity: 0; pointer-events: none;
  transition: opacity .18s ease, transform .18s ease;
}
#admin-toast.show { opacity: 1; transform: translate(-50%, 0); }
#admin-toast.ok { border-color: rgba(52,211,255,0.6); }
#admin-toast.bad { border-color: var(--red); }
@media (prefers-reduced-motion: reduce) {
  #admin-toast { transition: opacity .18s ease; transform: translate(-50%, 0); }
}

.mode-btn.admin { border-color: rgba(255,171,46,0.5); }
.mode-btn.admin:hover { border-color: var(--orange); background: rgba(255,171,46,0.15); }
.admin-note { font-size: 11px; opacity: .45; margin-top: -4px; }

/* boards left, the Unassigned bench right — the bench is the drag source, so it
   scrolls with its own column instead of sitting above 15 boards of scrolling */
.admin-levels {
  text-align: left; margin: 10px 0;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 16px; align-items: start;
}
.admin-boards, .admin-bench {
  max-height: 62vh; overflow-y: auto; padding-right: 6px; min-width: 0;
}
.admin-bench {
  position: sticky; top: 0;
  border-left: 1px solid rgba(255,255,255,0.10); padding-left: 14px;
}
/* one chip per row in the narrow bench: the title takes the width it needs and
   the difficulty + tempo controls line up in a column of their own on the right */
.admin-bench .admin-drop { flex-direction: column; flex-wrap: nowrap; gap: 6px; }
.admin-bench .admin-chip { width: 100%; padding: 6px 10px; gap: 6px; }
.admin-bench .admin-chip b { flex: 1; min-width: 0; line-height: 1.25; }
.admin-bench .admin-chip label { white-space: nowrap; }
@media (max-width: 900px) {
  .admin-levels { grid-template-columns: minmax(0, 1fr); }
  .admin-bench { position: static; border-left: 0; padding-left: 0; max-height: none; }
  .admin-bench .admin-drop { flex-direction: row; flex-wrap: wrap; }
  .admin-bench .admin-chip { width: auto; }
}
.admin-zone h3 {
  font-size: 14px; letter-spacing: 1px; margin: 14px 0 6px;
  color: var(--gold);
}
.admin-drop {
  min-height: 44px; border-radius: 12px; padding: 8px;
  display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start;
  background: rgba(255,255,255,0.04);
  border: 2px dashed rgba(255,255,255,0.14);
}
.admin-drop.over { border-color: var(--cyan); background: rgba(52,211,255,0.10); }
.admin-chip {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 12px; border-radius: 10px; cursor: grab;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.25);
  font-size: 12.5px;
}
.admin-chip:active { cursor: grabbing; }
.admin-chip b { font-weight: 800; }
.admin-chip .ac-owner {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 10px; font-weight: 800; letter-spacing: 0.5px;
  padding: 2px 7px; border-radius: 8px; white-space: nowrap;
  background: rgba(52,211,255,0.12); color: var(--cyan);
  border: 1px solid rgba(52,211,255,0.25);
}
/* the rival picker sits inside the owner badge and inherits its look, so the
   chip reads as a label until you click it */
.admin-chip .ac-rival {
  font: inherit; font-size: 10px; font-weight: 800; letter-spacing: 0.5px;
  color: var(--cyan); background: transparent; border: 0;
  padding: 0 14px 0 0; cursor: pointer; max-width: 15ch;
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 5px center, right 1px center;
  background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat;
}
.admin-chip .ac-rival:hover { color: #fff; }
.admin-chip .ac-rival option { background: #16162a; color: #eee; }
/* the starter zone's five tutorial boards nest under one Level 1 heading */
.admin-zone.starter { margin-left: 14px; border-left: 2px solid rgba(255,215,94,0.18); padding-left: 12px; }
.admin-zone.starter h3 { font-size: 12.5px; opacity: .9; }
.admin-chip .ac-diff {
  font-size: 10px; font-weight: 900; letter-spacing: 1px; text-transform: uppercase;
  padding: 2px 7px; border-radius: 8px;
}
.admin-chip.easy .ac-diff { background: rgba(60,255,140,0.18); color: #7dffb2; }
.admin-chip.medium .ac-diff { background: rgba(255,215,94,0.18); color: var(--gold); }
.admin-chip.hard .ac-diff { background: rgba(255,59,92,0.18); color: #ff8c9e; }
.admin-chip label { display: flex; align-items: center; gap: 4px; font-size: 11.5px; opacity: .85; }
.admin-chip input {
  width: 52px; font: inherit; font-size: 12px; padding: 3px 5px;
  border-radius: 6px; background: rgba(255,255,255,0.1); color: #eee;
  border: 1px solid rgba(255,255,255,0.25); text-align: right;
}

/* menu PLAY button lines up with the stack below it */
#menu .big-btn { width: 300px; padding: 16px 0; }

/* two-column menu: your pianist stands tall on the left, actions on the
   right — the whole left column is the profile-edit button */
.panel.menu-panel { max-width: 760px; }
.menu-cols {
  display: flex; align-items: stretch; justify-content: center;
  gap: 34px; margin-top: 8px;
}
.menu-left {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  justify-content: center;
  min-width: 250px; padding: 18px 20px; border-radius: 18px; cursor: pointer;
  font: inherit; color: #eee; background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.16);
  transition: border-color .12s, background .12s;
}
.menu-left:hover { border-color: var(--gold); background: rgba(255,215,94,0.07); }
.pc-avatar-big { display: block; margin-bottom: 14px; }
.menu-left .pc-name { font-size: 20px; font-weight: 800; }
.menu-left .pc-level { font-size: 12.5px; }
.menu-left .pc-elo { font-size: 12px; }
.menu-left .pc-xpbar { width: 170px; margin-top: 6px; }
.menu-left .pc-coins { margin-top: 6px; }
.pc-edit {
  margin-top: 10px; font-size: 12px; font-weight: 700; color: #ccc;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.22);
  padding: 5px 14px; border-radius: 9px;
}
.menu-left:hover .pc-edit { color: var(--gold); border-color: rgba(255,215,94,0.5); }
.menu-right { display: flex; flex-direction: column; align-items: center; }
/* signed-out: no pianist yet — the right column simply centers itself */

/* wardrobe grouped by slot */
.slot-group { margin: 10px auto 2px; max-width: 520px; }
.slot-h {
  font-size: 12px; font-weight: 800; letter-spacing: 2px; opacity: .65;
  text-align: left; margin: 8px 0 6px; text-transform: uppercase;
}
.slot-items { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.slot-items button {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 4px; border-radius: 12px; cursor: pointer; font: inherit;
  color: #eee; background: rgba(255,255,255,0.06);
  border: 2px solid rgba(255,255,255,0.16);
}
.slot-items button:hover { border-color: var(--cyan); }
.slot-items button.equipped { border-color: var(--gold); background: rgba(255,215,94,0.12); }
.slot-items button.cant { opacity: .45; }
.slot-items .sg-emoji { font-size: 28px; }
.slot-items .sg-name { font-size: 11px; font-weight: 700; }
.slot-items .sg-price { font-size: 11px; color: var(--gold); font-weight: 800; }

/* ------------------------------------------------- layered avatar system */
.avatar {
  position: relative; display: inline-block;
  width: var(--sz, 64px); height: var(--sz, 64px);
  line-height: 1;
}
.avatar .av-base {
  position: absolute; inset: 0;
  font-size: calc(var(--sz, 64px) * 0.86);
  display: flex; align-items: center; justify-content: center;
}
.avatar .av-base img, .avatar .av-item img { width: 100%; height: 100%; object-fit: contain; }
.avatar .av-item { position: absolute; pointer-events: none; }
/* slot anchors (fractions of the avatar box) */
.avatar .av-hat    { top: -28%; left: 22%; width: 56%; height: 46%; font-size: calc(var(--sz) * 0.42); }
.avatar .av-face   { top: 18%; left: 26%; width: 48%; height: 34%; font-size: calc(var(--sz) * 0.34); }
.avatar .av-hands  { top: 38%; left: -16%; width: 46%; height: 46%; font-size: calc(var(--sz) * 0.34); }
.avatar .av-legs   { top: 64%; left: 22%; width: 56%; height: 42%; font-size: calc(var(--sz) * 0.34); }
.avatar .av-bg     {
  top: -12%; left: -12%; width: 124%; height: 124%;
  font-size: calc(var(--sz) * 1.0); opacity: .5; z-index: -1;
}
.avatar .av-item > span {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
}
.rp-btn {
  font: inherit; font-size: 12px; font-weight: 800; cursor: pointer;
  padding: 2px 10px; border-radius: 8px; color: #013;
  background: var(--cyan); border: none;
}
.rp-btn:hover { filter: brightness(1.15); }
.cg-img { width: 60px; height: 60px; object-fit: contain; }
.char-grid.small .cg-img { width: 46px; height: 46px; }
.sg-img { width: 44px; height: 44px; object-fit: contain; }
.oc-img { width: 74px; height: 74px; object-fit: contain; display: block; margin: 0 auto; }
.arena-roster.spec .oc-img { width: 56px; height: 56px; }
.vi-img { width: 130px; height: 130px; object-fit: contain; }
.fl-img { width: 170px; height: 170px; object-fit: contain; }

/* ------------------------------------------- duel confirm (map node tap) */
#duel-confirm .panel { max-width: 440px; }
.dc-opp { display: flex; align-items: center; gap: 14px; margin: 12px 0;
  padding: 12px 14px; text-align: left; border-radius: 14px;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.12); }
.dc-face { flex: 0 0 auto; font-size: 46px; line-height: 1; }
.dc-img { width: 76px; height: 76px; object-fit: contain; display: block;
  filter: drop-shadow(0 4px 7px rgba(0,0,0,.5)); }
.dc-info { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.dc-boss { color: var(--orange); font-weight: 800; font-size: 11px;
  text-transform: uppercase; letter-spacing: .06em; }
.dc-desc { opacity: .75; font-size: 13px; }
.dc-meta { opacity: .9; font-size: 12px; }
#dc-diff { width: fit-content; margin: 2px auto 4px; }
#dc-diff button { text-transform: capitalize; }

/* ------------------------------------------------ bug reports + invites */
.bug-link { opacity: .55; font-size: 12px; }
.bug-link:hover { opacity: 1; }
.bug-text, .bug-contact {
  width: 100%; box-sizing: border-box; margin-top: 10px; padding: 10px 12px;
  background: rgba(255,255,255,.07); color: #fff; font: inherit;
  border: 1px solid rgba(255,255,255,.22); border-radius: 10px; resize: vertical;
}
.bug-text:focus, .bug-contact:focus { outline: none; border-color: var(--cyan, #34d3ff); }
.signup-cta.invite { border-color: rgba(255,111,129,.5); }
.invite-link {
  margin-top: 12px; padding: 10px 12px; border-radius: 10px;
  background: rgba(255,255,255,.08); border: 1px dashed rgba(255,255,255,.3);
  font-size: 12px; word-break: break-all; user-select: all;
}

/* ------------------------------------------------------ admin analytics */
.adm-content { text-align: left; max-height: 62vh; overflow: auto; padding: 4px 2px; }
.adm-content h3 { margin: 16px 0 6px; font-size: 15px; }
.adm-content h4 { margin: 8px 0 4px; font-size: 13px; opacity: .8; }
.adm-kpis { display: flex; flex-wrap: wrap; gap: 8px; }
.adm-kpi {
  flex: 1 1 120px; min-width: 120px; padding: 10px 12px; border-radius: 12px;
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.14);
  display: flex; flex-direction: column; gap: 2px;
}
.adm-kpi b { font-size: 20px; }
.adm-kpi span { font-size: 11px; opacity: .6; text-transform: uppercase; letter-spacing: .05em; }
.adm-kpi em { font-size: 10.5px; opacity: .45; font-style: normal; }
.adm-cols { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
.adm-cols > div { flex: 1 1 220px; min-width: 0; }
.adm-table { width: 100%; }
.adm-row { cursor: pointer; }
.adm-row:hover td { background: rgba(255,255,255,.06); }
.adm-anon { opacity: .55; font-style: italic; }
.adm-bounce {
  background: rgba(255,90,110,.2); color: #ff8c9e; border-radius: 6px;
  padding: 1px 7px; font-size: 11px; font-weight: 700;
}
/* automation signals: amber = worth a look, red = near-certain crawler */
.adm-botflag {
  background: rgba(255,176,32,.2); color: #ffc65c; border-radius: 6px;
  padding: 1px 7px; font-size: 11px; font-weight: 700; cursor: help;
}
.adm-bot-lo td { background: rgba(255,176,32,.07); }
.adm-bot-hi td { background: rgba(255,90,110,.1); }
.adm-src { font-size: 11px; opacity: .7; max-width: 130px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.adm-clusters {
  border: 1px solid rgba(255,176,32,.35); background: rgba(255,176,32,.07);
  border-radius: 10px; padding: 10px 14px; margin: 10px 0;
}
.adm-cluster { font-size: 12px; padding: 3px 0; }
.adm-cluster-n {
  display: inline-block; min-width: 78px; font-weight: 700; color: #ffc65c;
}
.adm-detail td { background: rgba(0,0,0,.25); font-size: 12px; }
.adm-timeline { font-size: 12px; line-height: 1.9; max-height: 300px; overflow: auto; flex: 2 1 340px; }
.adm-t { display: inline-block; min-width: 52px; opacity: .5; font-variant-numeric: tabular-nums; }
.adm-repeat td { background: rgba(52,211,255,.07); }
.adm-user-head { display: flex; gap: 12px; align-items: center; margin: 10px 0; }
.adm-user-av { width: 64px; }
.adm-msg { max-width: 420px; white-space: pre-wrap; }
.adm-resolved { opacity: .45; }

/* ------------------------------------------------------------------ PvP */
.pvp-slots { display: flex; align-items: stretch; justify-content: center; gap: 14px; margin: 10px 0; }
.pvp-slot {
  width: 195px; min-height: 195px; padding: 12px 10px;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.14);
  border-radius: 12px; display: flex; flex-direction: column; align-items: center; gap: 5px;
}
.pvp-vs { align-self: center; font: 900 italic 26px system-ui; color: var(--red, #ff3b5c); text-shadow: 0 0 14px rgba(255,59,92,.7); }
.pvp-av { display: block; }
.pvp-elo { color: var(--cyan); font-size: 13px; font-weight: 700; }
.pvp-chk { font-size: 12.5px; color: rgba(255,255,255,.45); }
.pvp-chk.ok { color: #7dffb2; }
.pvp-empty { margin: auto; color: rgba(255,255,255,.4); text-align: center; font-size: 14px; line-height: 1.5; }
.pvp-count {
  font: 900 42px system-ui; color: var(--gold, #ffd75e);
  text-shadow: 0 0 16px rgba(255,215,94,.6); margin: 2px 0;
}
.pvp-count.urgent { color: var(--red, #ff3b5c); text-shadow: 0 0 16px rgba(255,59,92,.7); }
.pvp-invite { display: flex; flex-direction: column; gap: 8px; margin: 8px 0; }
.pvp-inv-row { display: flex; gap: 8px; align-items: center; justify-content: center; }
.pvp-input {
  flex: 0 1 220px; padding: 8px 10px; border-radius: 8px; font: inherit;
  background: rgba(0,0,0,.35); border: 1px solid rgba(255,255,255,.2); color: #fff;
}
.pvp-inv-row .invite-link { flex: 0 1 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#pvp-ready-btn.on { background: #1d8a4b; color: #eaffe9; }

/* ------------------------------------------------- first-time tour */
#tour { position: fixed; inset: 0; z-index: 60; }
#tour-ring {
  position: fixed; border: 3px solid var(--gold); border-radius: 18px;
  /* the giant shadow doubles as the dimmed scrim with a spotlight hole */
  box-shadow: 0 0 0 9999px rgba(4, 6, 14, 0.72), 0 0 24px rgba(255, 215, 94, 0.8);
  pointer-events: none; transition: all .25s ease;
}
#tour-card {
  position: fixed; width: 330px; padding: 16px 18px; text-align: left;
  background: #141a30; border: 1px solid rgba(255, 215, 94, 0.5);
  border-radius: 14px; box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6);
  transition: all .25s ease;
}
#tour-step {
  font-size: 11px; font-weight: 900; letter-spacing: 2px; color: var(--gold);
  margin-bottom: 6px;
}
#tour-text { font-size: 14px; line-height: 1.55; color: #e6ecf5; }
#tour-text b { color: var(--gold); }
#tour-actions { display: flex; gap: 10px; align-items: center; justify-content: flex-end; margin-top: 14px; }
#tour-actions button { font: inherit; cursor: pointer; border-radius: 10px; }
#tour-skip {
  font-size: 12px; color: #9aa3c0; background: none; border: none;
  text-decoration: underline; padding: 6px 2px;
}
#tour-skip:hover { color: #d7e0ea; }
#tour-next {
  font-size: 14px; font-weight: 900; letter-spacing: 1px; color: #002;
  background: linear-gradient(180deg, #ffe9a3, var(--gold));
  border: none; padding: 9px 20px;
  box-shadow: 0 3px 0 #b8922c;
}
#tour-next:active { transform: translateY(2px); box-shadow: 0 1px 0 #b8922c; }
