/* ============ FRUIT SLASH — Neon Dojo Design System ============ */
:root {
  --bg: #0b0f14;
  --ink: #f4f7f5;
  --ink-dim: rgba(244, 247, 245, 0.62);
  --accent: #a3e635;
  --accent-2: #ff3b5c;
  --gold: #ffcf4d;
  --danger: #ff2d4a;
  --glass: rgba(255, 255, 255, 0.06);
  --glass-border: rgba(255, 255, 255, 0.12);
  --radius: 24px;
  --font-display: 'Arial Black', 'Avenir Next Heavy', system-ui, sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, system-ui, sans-serif;
  /* Chrome that should track the play column rather than the window edges.
     --pf-w is overwritten every resize() with the real playfield width in px;
     the 100vw default keeps everything full-bleed until the first frame. */
  --content-max: 560px;
  --pf-w: 100vw;
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --sar: env(safe-area-inset-right, 0px);
}

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  height: 100%;
  overflow: hidden;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  overscroll-behavior: none;
  position: fixed;
  inset: 0;
  width: 100%;
  user-select: none;
  -webkit-user-select: none;
}

#game {
  position: fixed;
  inset: 0;
  display: block;
  touch-action: none;
  transition: filter 0.7s ease;
}
#game.dead { filter: saturate(0.25) brightness(0.55) blur(1px); }

/* ---------- generic screen overlays ---------- */
.screen {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  padding: calc(16px + var(--sat)) calc(16px + var(--sar)) calc(16px + var(--sab)) calc(16px + var(--sal));
  z-index: 10;
  opacity: 1;
  transition: opacity 0.35s ease;
}
.screen.hidden { opacity: 0; visibility: hidden; }
.screen button, .screen a { pointer-events: auto; }

button {
  font-family: var(--font-body);
  font-weight: 700;
  border: none;
  cursor: pointer;
  color: var(--ink);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 999px;
  padding: 14px 28px;
  font-size: 17px;
  letter-spacing: 0.4px;
  transition: transform 0.15s ease, background 0.2s ease, box-shadow 0.2s ease;
}
button:active { transform: scale(0.94); }
button.primary {
  background: linear-gradient(135deg, var(--accent), #65c916);
  color: #10230a;
  box-shadow: 0 8px 32px rgba(163, 230, 53, 0.35), inset 0 1px 0 rgba(255,255,255,.4);
  font-size: 19px;
  padding: 18px 44px;
}
button.icon-btn {
  width: 52px; height: 52px;
  padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 22px;
}

/* ---------- splash / loading ---------- */
#splash {
  background: var(--bg);
  z-index: 100;
  transition: opacity 0.5s ease;
}
#load-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 22px;
  transition: opacity 0.3s ease;
}
#load-stage.hidden { display: none; }
.load-fruit {
  font-size: 64px;
  animation: load-bounce 0.9s cubic-bezier(.3,0,.4,1) infinite;
  filter: drop-shadow(0 10px 24px rgba(163,230,53,0.25));
}
@keyframes load-bounce {
  0%, 100% { transform: translateY(0) rotate(-6deg); }
  50% { transform: translateY(-22px) rotate(8deg); }
}
#load-bar {
  width: min(64vw, 300px);
  height: 10px;
  border-radius: 6px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.1);
  overflow: hidden;
}
#load-bar i {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--accent), #65c916);
  box-shadow: 0 0 16px rgba(163,230,53,0.6);
  transition: width 0.25s ease;
}
#load-tip {
  font-size: 14px;
  color: var(--ink-dim);
  text-align: center;
  max-width: 80vw;
  min-height: 20px;
}
#load-stage-label {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.6px;
  color: var(--accent);
  text-align: center;
  min-height: 16px;
  margin-top: -12px;
}
.splash-logo.hidden { display: none; }
.splash-logo {
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(44px, 11vw, 110px);
  letter-spacing: 0.02em;
  line-height: 0.95;
  text-align: center;
}
.splash-logo .top, .splash-logo .bot { display: block; }
.splash-logo .top {
  background: linear-gradient(180deg, #d8ffb0, var(--accent));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: slice-top 1.5s cubic-bezier(.7,0,.3,1) forwards;
}
.splash-logo .bot {
  background: linear-gradient(180deg, var(--accent-2), #b3123a);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: slice-bot 1.5s cubic-bezier(.7,0,.3,1) forwards;
}
.splash-blade {
  position: absolute;
  top: 50%; left: -30%;
  width: 160%; height: 3px;
  background: linear-gradient(90deg, transparent, #fff, transparent);
  box-shadow: 0 0 24px 4px rgba(255,255,255,0.8);
  transform: translateX(-120%) rotate(-4deg);
  animation: blade-sweep 0.55s cubic-bezier(.5,0,.2,1) 0.35s forwards;
}
@keyframes blade-sweep {
  0% { transform: translateX(-120%) rotate(-4deg); opacity: 1; }
  80% { opacity: 1; }
  100% { transform: translateX(60%) rotate(-4deg); opacity: 0; }
}
@keyframes slice-top {
  0%, 55% { transform: translate(0, 0) rotate(0); }
  75% { transform: translate(-10px, -14px) rotate(-2.5deg); }
  100% { transform: translate(-4px, -6px) rotate(-1.2deg); }
}
@keyframes slice-bot {
  0%, 55% { transform: translate(0, 0) rotate(0); }
  75% { transform: translate(10px, 12px) rotate(2deg); }
  100% { transform: translate(4px, 5px) rotate(1deg); }
}

/* ---------- menu ---------- */
#menu { justify-content: flex-start; }
.menu-top {
  width: 100%;
  max-width: 560px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.menu-top-btns { display: flex; gap: 8px; }
/* four icons plus the profile chip on a 420px viewport: shrink the icons so
   the player's name gets the room instead of being ellipsised away */
.menu-top .icon-btn { width: 44px; height: 44px; font-size: 19px; }
#lang-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  width: 100%;
  max-height: 52vh;
  overflow-y: auto;
}
#lang-list button {
  padding: 12px 10px;
  font-size: 15px;
  border-radius: 14px;
}
#lang-list button.active {
  background: linear-gradient(135deg, rgba(163,230,53,0.25), rgba(101,201,22,0.2));
  border-color: rgba(163,230,53,0.5);
}

/* ---------- leaderboard ---------- */
.net-only.hidden { display: none !important; }
.board-tabs { display: flex; gap: 8px; width: 100%; }
.board-tabs button { flex: 1; padding: 10px; font-size: 13px; border-radius: 12px; }
.board-tabs button.active {
  background: linear-gradient(135deg, rgba(163,230,53,0.25), rgba(101,201,22,0.2));
  border-color: rgba(163,230,53,0.5);
}
#board-list {
  width: 100%;
  max-height: 46vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.board-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 12px;
  padding: 9px 14px;
  font-size: 15px;
}
.board-row .rk {
  width: 34px; flex: 0 0 auto;
  font-family: var(--font-display); font-size: 13px; color: var(--ink-dim);
}
.board-row:nth-child(1) .rk { color: var(--gold); }
.board-row:nth-child(2) .rk { color: #cfd8dc; }
.board-row:nth-child(3) .rk { color: #d29b6c; }
.board-row .nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.board-row .tm {
  flex: 0 0 auto;
  font-size: 10.5px; font-weight: 600; color: var(--ink-dim);
  white-space: nowrap;
}
.board-row .sc { flex: 0 0 auto; font-family: var(--font-display); color: var(--accent); }
.board-row.me {
  background: linear-gradient(135deg, rgba(var(--accent-rgb),0.2), rgba(var(--accent-rgb),0.09));
  border-color: rgba(var(--accent-rgb), 0.55);
}
.board-row.me .nm { font-weight: 800; }
#board-meta {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--ink-dim);
  padding: 0 4px;
}
#board-meta .bm-rank { color: var(--accent); }
/* Grids, not flex-wrap: four region chips would otherwise wrap to four rows and
   push the list off the panel. */
#board-regions {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px;
}
#board-windows {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 5px;
}
#board-regions .seg-btn, #board-windows .seg-btn {
  min-width: 0; font-size: 10.5px; padding: 8px 2px;
  overflow: hidden; text-overflow: ellipsis;
}
.region-btn { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.rb-ic { font-size: 15px; line-height: 1; }
.rb-nm {
  font-size: 9.5px; line-height: 1.1;
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#boardpanel .panel { padding: 22px 18px; gap: 10px; }
#boardpanel h2 { font-size: 26px; }
#board-list { max-height: 40vh; }
.board-tabs button { font-size: 12px; padding: 8px; }
.board-loading, .board-empty { text-align: center; color: var(--ink-dim); padding: 18px 0; }
#go-submit { display: flex; gap: 8px; width: 100%; }
#go-name {
  flex: 1;
  min-width: 0;
  background: rgba(255,255,255,0.07);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  color: var(--ink);
  font-size: 15px;
  padding: 12px 18px;
  outline: none;
}
#go-name:focus { border-color: rgba(163,230,53,0.5); }
#btn-submit-score { white-space: nowrap; font-size: 14px; padding: 12px 18px; }
/* The hero owns the space between the top bar and the mode rail and centres
   its contents in it. Before, the logo hung off a fixed margin-top and the
   record badge sat alone above several hundred pixels of nothing. */
.menu-hero {
  position: relative;
  flex: 1;
  min-height: 0;
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 22px;
  /* The sliceable melon sits at 60% of the screen height. Centring in the full
     box put the stat chips straight on top of it on a tall desktop window, so
     the hero reserves that zone and centres in what is left. */
  padding-bottom: clamp(96px, 24vh, 230px);
  pointer-events: none;
}
/* A slow aurora behind the wordmark. Sits under the canvas fruit and over the
   background, so the logo has something to sit ON rather than floating in the
   middle of an empty screen. */
.hero-glow {
  position: absolute;
  top: 50%; left: 50%;
  width: min(120vw, 720px);
  aspect-ratio: 1;
  transform: translate(-50%, -62%);
  border-radius: 50%;
  background:
    radial-gradient(circle at 38% 40%, rgba(163,230,53,0.20), transparent 58%),
    radial-gradient(circle at 66% 58%, rgba(255,59,92,0.16), transparent 60%);
  filter: blur(28px);
  animation: hero-drift 14s ease-in-out infinite;
}
@keyframes hero-drift {
  0%, 100% { transform: translate(-50%, -62%) scale(1) rotate(0deg); opacity: 0.9; }
  50% { transform: translate(-50%, -58%) scale(1.12) rotate(8deg); opacity: 1; }
}

/* Three numbers, one glance. */
.menu-stats {
  display: flex;
  gap: 10px;
  pointer-events: none;
}
.ms-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1px;
  min-width: 76px;
  padding: 9px 14px 8px;
  border-radius: 16px;
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}
.ms-chip .ms-ic { font-size: 14px; line-height: 1; }
.ms-chip b {
  font-family: var(--font-display);
  font-size: 20px;
  line-height: 1.05;
  color: var(--gold);
}
.ms-chip small {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--ink-dim);
}
.ms-chip:nth-child(2) b { color: var(--accent); }
.ms-chip:nth-child(3) b { color: var(--accent-2); }

.logo {
  /* fit-content + overflow:hidden are what keep the ::after shine ON the
     wordmark. As a full-width block the sweep rendered as a loose white bar
     off at the left edge of the window. */
  position: relative;
  width: fit-content;
  overflow: hidden;
  font-family: var(--font-display);
  font-size: clamp(48px, 12vw, 104px);
  line-height: 0.92;
  text-align: center;
  letter-spacing: 0.01em;
  filter: drop-shadow(0 12px 40px rgba(163,230,53,0.25));
  animation: logo-float 4s ease-in-out infinite;
}
.logo span { display: block; }
.logo .l1 {
  background: linear-gradient(180deg, #eaffd0, var(--accent) 70%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
}
.logo .l2 {
  background: linear-gradient(180deg, #ff8fa3, var(--accent-2) 70%);
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  transform: translateY(-2px);
}
@keyframes logo-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}
.menu-hint {
  position: absolute;
  bottom: calc(166px + var(--sab));
  left: 0; right: 0;
  text-align: center;
  color: var(--ink-dim);
  font-size: 15px;
  letter-spacing: 0.3px;
  animation: hint-pulse 2s ease-in-out infinite;
  pointer-events: none;
}
@keyframes hint-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 1; }
}
/* ---------- profile chip ---------- */
#profile-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px 8px 10px;
  border-radius: 999px;
  font-size: 14px;
  position: relative;
  overflow: hidden;
  text-align: start;
}
#chip-avatar { font-size: 24px; line-height: 1; flex: 0 0 auto; }
.chip-txt {
  display: flex; flex-direction: column; gap: 1px;
  min-width: 0; max-width: 146px;
}
.chip-txt b, #chip-rank {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chip-txt b { font-size: 14px; }
#chip-rank { font-size: 10px; color: var(--ink-dim); font-weight: 600; }
#chip-xp {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: rgba(255,255,255,0.08);
}
#chip-xp b {
  display: block; height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--accent), var(--gold));
  transition: width 0.6s cubic-bezier(.2,1,.3,1);
}

/* ---------- mode rail ---------- */
#mode-rail {
  position: absolute;
  bottom: calc(20px + var(--sab));
  left: 0; right: 0;
  display: flex;
  gap: 12px;
  /* right inset on the right, left inset on the left — these were swapped,
     which only shows up in landscape on a notched phone. */
  padding: 6px calc(16px + var(--sar)) 10px calc(16px + var(--sal));
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
#mode-rail::-webkit-scrollbar { display: none; }
.mode-card {
  flex: 0 0 auto;
  scroll-snap-align: center;
  width: 118px;
  min-height: 126px;
  border-radius: 20px;
  padding: 14px 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  text-align: center;
  font-size: 15px;
}
.mode-card .mc-ic { font-size: 28px; line-height: 1; margin-bottom: 2px; }
.mode-card b { font-size: 14px; white-space: nowrap; }
.mode-card small {
  font-size: 10px;
  font-weight: 600;
  color: var(--ink-dim);
  letter-spacing: 0.3px;
  line-height: 1.3;
}
.mode-card .mc-stat {
  font-style: normal;
  font-size: 11px;
  font-family: var(--font-display);
  color: var(--gold);
  margin-top: 2px;
  min-height: 13px;
}
.mode-card.locked { opacity: 0.45; }

/* ---------- settings ---------- */
.set-list {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-height: 56vh;
  overflow-y: auto;
}
.set-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 14px;
  padding: 12px 16px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.set-row.set-sub { flex-direction: column; align-items: stretch; gap: 10px; }

/* Section headings. The list used to be flat: audio, display, profile and the
   destructive reset all in one column, with nothing telling you which was
   which. */
.set-head {
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin: 10px 0 -2px 4px;
}
.set-head:first-child { margin-top: 0; }

/* Volume: a level, not a switch. The mix already had separate bus gains, so
   the slider only had to scale what was there. */
.set-row.set-slider { gap: 16px; }
input[type="range"] {
  appearance: none; -webkit-appearance: none;
  flex: 1 1 auto;
  min-width: 0;
  height: 6px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  cursor: pointer;
}
input[type="range"]::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid rgba(0,0,0,0.35);
  box-shadow: 0 2px 10px rgba(var(--accent-rgb), 0.5);
}
input[type="range"]::-moz-range-thumb {
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--accent);
  border: 2px solid rgba(0,0,0,0.35);
}

/* Statistics rows */
.set-stats { display: flex; flex-direction: column; gap: 6px; width: 100%; }
.stat-row {
  display: flex; align-items: center; gap: 10px;
  background: rgba(255,255,255,0.04);
  border: 1px solid rgba(255,255,255,0.06);
  border-radius: 12px;
  padding: 9px 14px;
  font-size: 13.5px;
}
.st-ic { font-size: 16px; line-height: 1; }
.st-lb { flex: 1; color: var(--ink-dim); font-weight: 600; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stat-row b { font-family: var(--font-display); font-size: 15px; color: var(--gold); }

/* Panel search box — worth having once a list has fifteen entries */
.panel-search {
  width: 100%;
  padding: 11px 16px;
  border-radius: 14px;
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--glass-border);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 600;
}
.panel-search::placeholder { color: var(--ink-dim); }
.panel-search:focus { outline: none; border-color: rgba(var(--accent-rgb), 0.5); }
.set-link {
  width: 100%;
  padding: 12px 16px;
  border-radius: 14px;
  font-size: 15px;
  text-align: start;
}
.set-link.danger { color: var(--accent-2); }
.set-link.armed {
  background: rgba(var(--accent-2-rgb), 0.18);
  border-color: rgba(var(--accent-2-rgb), 0.5);
}

/* switch: a checkbox restyled as a track + knob */
input.switch {
  appearance: none; -webkit-appearance: none;
  flex: 0 0 auto;
  width: 46px; height: 27px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid var(--glass-border);
  position: relative;
  cursor: pointer;
  transition: background 0.2s ease, border-color 0.2s ease;
}
input.switch::after {
  content: '';
  position: absolute;
  top: 2px; inset-inline-start: 2px;
  width: 21px; height: 21px;
  border-radius: 50%;
  background: var(--ink);
  transition: transform 0.2s cubic-bezier(.3,1.4,.5,1);
}
input.switch:checked {
  background: linear-gradient(135deg, var(--accent), #65c916);
  border-color: rgba(var(--accent-rgb), 0.6);
}
input.switch:checked::after { transform: translateX(19px); }
[dir="rtl"] input.switch:checked::after { transform: translateX(-19px); }

/* segmented control (themes, regions) */
.seg { display: flex; flex-wrap: wrap; gap: 6px; width: 100%; }
/* `.panel button { width: 100% }` outranks a bare `.seg-btn` on specificity,
   so every segment was stacking into its own row — harmless with three themes,
   a very tall column with five blades. Scoped selector to win it back. */
.seg .seg-btn { width: auto; }
.seg-btn {
  flex: 1 1 auto;
  min-width: 76px;
  padding: 9px 8px;
  font-size: 11.5px;
  border-radius: 12px;
  white-space: nowrap;
}
.seg-btn.active {
  background: linear-gradient(135deg, rgba(var(--accent-rgb),0.25), rgba(var(--accent-rgb),0.14));
  border-color: rgba(var(--accent-rgb), 0.5);
}
.seg-btn.locked { opacity: 0.45; }

/* ---------- profile panel ---------- */
#prof-name {
  width: 100%;
  background: rgba(255,255,255,0.07);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  color: var(--ink);
  font-size: 16px;
  font-weight: 700;
  padding: 13px 20px;
  outline: none;
  text-align: center;
  font-family: var(--font-body);
}
#prof-name:focus { border-color: rgba(var(--accent-rgb), 0.5); }
.prof-label {
  width: 100%;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-dim);
  margin-top: 2px;
}
#prof-avatars {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
  width: 100%;
}
.av-btn {
  padding: 0;
  aspect-ratio: 1;
  font-size: 21px;
  border-radius: 12px;
  display: flex; align-items: center; justify-content: center;
}
.av-btn.active {
  background: linear-gradient(135deg, rgba(var(--accent-rgb),0.3), rgba(var(--accent-rgb),0.16));
  border-color: rgba(var(--accent-rgb), 0.6);
}
.av-btn.locked { opacity: 0.35; font-size: 14px; }
#prof-preview { width: 100%; margin-top: 4px; }
.board-row .fl, .board-row .av { font-size: 17px; line-height: 1; }

/* ---------- rivals / challenges ---------- */
.mp-code-row { display: flex; gap: 8px; width: 100%; }
#mp-code {
  flex: 1; min-width: 0;
  background: rgba(255,255,255,0.07);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 15px; font-weight: 700;
  letter-spacing: 2px;
  padding: 12px 18px;
  outline: none;
  text-align: center;
  text-transform: lowercase;
}
#mp-code:focus { border-color: rgba(var(--accent-rgb), 0.5); }
#btn-mp-join { white-space: nowrap; font-size: 14px; padding: 12px 20px; }
#btn-mp-online { width: 100%; font-size: 15px; }
#mp-status {
  width: 100%;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  color: var(--accent);
  min-height: 18px;
}
#mp-status.bad { color: var(--accent-2); }
#mp-status.hidden { display: none; }
#mp-list {
  width: 100%;
  max-height: 36vh;
  overflow-y: auto;
  display: flex; flex-direction: column; gap: 6px;
}
.rival-row { gap: 8px; }
.rv-rec {
  font-family: var(--font-display);
  font-size: 14px;
  color: var(--ink-dim);
  flex: 0 0 auto;
}
.rv-rec.win { color: var(--accent); }
.rv-rec.loss { color: var(--accent-2); }
.rv-btn {
  flex: 0 0 auto;
  padding: 7px 13px;
  font-size: 11.5px;
  border-radius: 10px;
}

/* ---------- live rival bar (async ghost race) ---------- */
#ghost-bar {
  position: fixed;
  /* clears the score panel + streak meter above it */
  top: calc(116px + var(--sat));
  left: 12px; right: 12px;
  z-index: 12;
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: none;
}
#ghost-bar.hidden { display: none; }
.gb-side { display: flex; flex-direction: column; align-items: center; min-width: 54px; }
.gb-side b { font-family: var(--font-display); font-size: 17px; line-height: 1; }
.gb-side span {
  font-size: 8.5px; font-weight: 700; letter-spacing: 0.8px;
  color: var(--ink-dim);
  max-width: 62px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.gb-me b { color: var(--accent); }
.gb-them b { color: var(--accent-2); }
.gb-track {
  flex: 1;
  height: 8px;
  border-radius: 5px;
  background: rgba(var(--accent-2-rgb), 0.35);
  border: 1px solid var(--glass-border);
  overflow: hidden;
}
.gb-track i {
  display: block; height: 100%; width: 50%;
  background: linear-gradient(90deg, var(--accent), #65c916);
  transition: width 0.35s cubic-bezier(.3,1,.4,1);
}
#ghost-bar.ahead .gb-me b { text-shadow: 0 0 14px rgba(var(--accent-rgb), 0.8); }
#ghost-bar.behind .gb-them b { text-shadow: 0 0 14px rgba(var(--accent-2-rgb), 0.8); }

/* ---------- boss melon armour ---------- */
#boss-bar {
  position: fixed;
  top: calc(116px + var(--sat));
  left: 12px; right: 12px;
  z-index: 12;
  display: flex;
  align-items: center;
  gap: 10px;
  pointer-events: none;
}
#boss-bar.hidden { display: none; }
.bb-ic { font-size: 19px; line-height: 1; }
.bb-track {
  flex: 1;
  height: 10px;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.38);
  overflow: hidden;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.12);
}
.bb-track i {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 6px;
  background: linear-gradient(90deg, #ff8fa0, #ff3b5c);
  transition: width 0.16s ease-out;
}
#boss-bar b {
  font-family: var(--font-display);
  font-size: 16px;
  min-width: 22px;
  text-align: right;
  color: #ff8fa0;
}

/* ---------- achievements ---------- */
#ach-summary {
  font-size: 14px;
  color: var(--ink-dim);
  font-weight: 700;
}
#ach-summary b { color: var(--gold); font-family: var(--font-display); font-size: 17px; }
#ach-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  width: 100%;
  max-height: 48vh;
  overflow-y: auto;
}

.ach-tile {
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.07);
  border-radius: 14px;
  padding: 10px 5px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-align: center;
  min-height: 78px;
}
.at-ic { font-size: 24px; line-height: 1; filter: grayscale(1); opacity: 0.45; }
.ach-tile.done .at-ic { filter: none; opacity: 1; }
.ach-tile b {
  font-size: 9.5px;
  line-height: 1.2;
  color: var(--ink-dim);
  overflow: hidden;
}
.ach-tile.done b { color: var(--ink); }
/* tier tints only once earned — a wall of coloured locks reads as noise */
.ach-tile.done.tier1 { border-color: rgba(205,127,50,0.45); }
.ach-tile.done.tier2 { border-color: rgba(200,208,214,0.45); }
.ach-tile.done.tier3 { border-color: rgba(var(--gold-rgb),0.55); }
.ach-tile.done.tier4 {
  border-color: rgba(var(--accent-rgb),0.6);
  background: linear-gradient(160deg, rgba(var(--accent-rgb),0.14), rgba(255,255,255,0.04));
}
.at-bar {
  width: 80%; height: 3px;
  border-radius: 2px;
  background: rgba(255,255,255,0.12);
  margin-top: auto;
}
.at-bar b { display: block; height: 100%; border-radius: 2px; background: var(--accent); }

/* ---------- achievement toast ---------- */
#ach-toast {
  position: fixed;
  top: calc(12px + var(--sat));
  left: 50%;
  transform: translateX(-50%);
  z-index: 80;
  display: flex;
  flex-direction: column;
  gap: 8px;
  pointer-events: none;
  width: min(92vw, 340px);
}
.ach-card {
  display: flex;
  align-items: center;
  gap: 11px;
  background: rgba(19,26,35,0.94);
  border: 1px solid rgba(var(--gold-rgb), 0.4);
  border-radius: 16px;
  padding: 10px 14px;
  box-shadow: 0 14px 40px rgba(0,0,0,0.5);
  animation: ach-in 0.42s cubic-bezier(.2,1.5,.4,1);
}
.ach-card.out { animation: ach-out 0.3s ease forwards; }
.ac-ic { font-size: 26px; line-height: 1; }
.ac-tx { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.ac-tx b { font-size: 14px; }
.ac-tx small { font-size: 10.5px; color: var(--ink-dim); font-weight: 600; }
.ac-xp {
  font-style: normal;
  font-family: var(--font-display);
  font-size: 13px;
  color: var(--gold);
}
/* Same card, different job: the language toast reports a switch the player
   did not ask for, so unlike the achievement cards it has to be clickable —
   #ach-toast is pointer-events:none, hence the override on the button. */
.lang-toast { border-color: rgba(var(--accent-rgb), 0.45); }
.lang-toast .ac-tx b { font-size: 13px; font-weight: 700; }
.ac-act {
  pointer-events: auto;
  flex: 0 0 auto;
  padding: 6px 12px;
  font-size: 12px;
  border-radius: 999px;
  background: rgba(var(--accent-rgb), 0.16);
  border: 1px solid rgba(var(--accent-rgb), 0.45);
  color: var(--ink);
}
@keyframes ach-in {
  0% { opacity: 0; transform: translateY(-22px) scale(0.94); }
  100% { opacity: 1; transform: none; }
}
@keyframes ach-out {
  to { opacity: 0; transform: translateY(-14px) scale(0.97); }
}

/* ---------- explainer cards ---------- */
#obc-stage {
  min-height: 190px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
}
#obc-stage.in { animation: obc-in 0.35s cubic-bezier(.2,1.3,.4,1); }
@keyframes obc-in {
  from { opacity: 0; transform: translateX(24px); }
  to { opacity: 1; transform: none; }
}
.obc-ic {
  font-size: 62px;
  line-height: 1;
  filter: drop-shadow(0 10px 26px rgba(var(--accent-rgb), 0.3));
}
#obc-stage h3 { font-family: var(--font-display); font-size: 25px; }
#obc-stage p {
  font-size: 15px;
  color: var(--ink-dim);
  line-height: 1.45;
  max-width: 30ch;
}
#obc-dots { display: flex; gap: 7px; }
#obc-dots i {
  width: 7px; height: 7px;
  border-radius: 50%;
  background: rgba(255,255,255,0.2);
  transition: background 0.25s ease, transform 0.25s ease;
}
#obc-dots i.on { background: var(--accent); transform: scale(1.25); }

/* ---------- screen transitions ---------- */
.screen.entering .panel { animation: panel-in 0.4s cubic-bezier(.2,1.4,.4,1); }
#wipe {
  position: fixed;
  inset: -20% -40%;
  z-index: 90;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(105deg,
    transparent 42%,
    rgba(var(--accent-rgb), 0.16) 48%,
    rgba(255,255,255,0.9) 50%,
    rgba(var(--accent-rgb), 0.16) 52%,
    transparent 58%);
}
#wipe.on { animation: wipe-sweep 0.45s cubic-bezier(.5,0,.2,1); }
@keyframes wipe-sweep {
  0% { opacity: 1; transform: translateX(-70%); }
  100% { opacity: 0; transform: translateX(70%); }
}

/* ---------- HUD ---------- */
#hud {
  position: fixed;
  top: calc(12px + var(--sat));
  left: calc(14px + var(--sal));
  right: calc(14px + var(--sar));
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  z-index: 8;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
#hud.hidden { opacity: 0; visibility: hidden; }
#score-wrap {
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 18px;
  padding: 8px 18px 10px;
  min-width: 108px;
  text-align: center;
}
#score {
  font-family: var(--font-display);
  font-size: 32px;
  line-height: 1.05;
  color: var(--ink);
}
#score.punch { animation: score-punch 0.28s cubic-bezier(.2,2.2,.4,1); }
@keyframes score-punch {
  0% { transform: scale(1); }
  35% { transform: scale(1.22); color: var(--accent); }
  100% { transform: scale(1); }
}
#score-label {
  font-size: 10px;
  letter-spacing: 2.5px;
  color: var(--ink-dim);
  font-weight: 700;
}
#streak-meter {
  margin-top: 6px;
  height: 5px;
  border-radius: 3px;
  background: rgba(255,255,255,0.1);
  overflow: hidden;
}
#streak-meter i {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--gold), #ff8a3c);
  transition: width 0.2s ease;
}
#streak-meter.fever i {
  background: linear-gradient(90deg, #ff3b5c, #ffcf4d, #a3e635, #4dc4ff, #b06bff);
  background-size: 300%;
  animation: shine 1s linear infinite;
}
#fever-glow {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 6;
  opacity: 0;
  transition: opacity 0.5s ease;
  box-shadow: inset 0 0 90px 10px rgba(255, 100, 180, 0.35), inset 0 0 40px 4px rgba(163, 230, 53, 0.25);
}
#fever-glow.on { opacity: 1; animation: fever-hue 2s linear infinite; }
@keyframes fever-hue { to { filter: hue-rotate(360deg); } }
.hud-right { display: flex; align-items: center; gap: 12px; pointer-events: none; }
#lives { display: flex; gap: 6px; font-size: 24px; }
#lives .life { transition: transform 0.3s ease, opacity 0.3s ease, filter 0.3s; }
#lives .life.lost {
  transform: scale(0.7) rotate(20deg);
  opacity: 0.28;
  filter: grayscale(1);
}
#lives .life.pop { animation: life-pop 0.5s ease; }
@keyframes life-pop {
  0% { transform: scale(1); }
  30% { transform: scale(1.6) rotate(-14deg); filter: drop-shadow(0 0 12px var(--danger)); }
  100% { transform: scale(0.7) rotate(20deg); }
}
#btn-pause { pointer-events: auto; width: 46px; height: 46px; font-size: 18px; padding: 0; }
#lives.hidden, #timer.hidden { display: none; }
#timer {
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 999px;
  padding: 10px 18px;
  font-family: var(--font-display);
  font-size: 20px;
  color: var(--ink);
}
#timer.danger {
  color: var(--danger);
  border-color: rgba(255,45,74,0.5);
  animation: danger-pulse 0.6s ease-in-out infinite;
}
#camp-goal {
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 999px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-dim);
  align-self: center;
}
#camp-goal.hidden { display: none; }
#camp-goal b { color: var(--accent); font-family: var(--font-display); font-size: 15px; }
#camp-goal.reached b { color: var(--gold); }

/* ---------- campaign level grid ---------- */
#camp-list {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  width: 100%;
  max-height: 52vh;
  overflow-y: auto;
}
#camp-list button {
  aspect-ratio: 1;
  padding: 0;
  font-family: var(--font-display);
  font-size: 20px;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
#camp-list button.locked { opacity: 0.4; font-size: 16px; }
#camp-list button.done {
  background: linear-gradient(135deg, rgba(163,230,53,0.22), rgba(101,201,22,0.16));
  border-color: rgba(163,230,53,0.45);
}
#camp-list button .stars { font-size: 9px; letter-spacing: 1px; color: var(--gold); height: 10px; }

/* ---------- combo banner / center messages ---------- */
#combo-banner {
  position: fixed;
  top: 26%;
  left: 0; right: 0;
  text-align: center;
  z-index: 9;
  pointer-events: none;
  font-family: var(--font-display);
  font-size: clamp(30px, 8vw, 58px);
  color: var(--gold);
  text-shadow: 0 0 30px rgba(255, 207, 77, 0.55), 0 4px 0 rgba(0,0,0,0.35);
  opacity: 0;
}
#combo-banner.show { animation: combo-in 1.1s cubic-bezier(.2,1.6,.35,1) forwards; }
@keyframes combo-in {
  0% { opacity: 0; transform: scale(0.4) rotate(-6deg); }
  18% { opacity: 1; transform: scale(1.12) rotate(2deg); }
  30% { transform: scale(1) rotate(0); }
  75% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.15) translateY(-24px); }
}
#center-msg {
  position: fixed;
  top: 34%;
  left: 24px; right: 24px;
  text-align: center;
  z-index: 9;
  pointer-events: none;
  transition: opacity 0.3s ease;
}
#center-msg.hidden { opacity: 0; }
#center-msg .big {
  font-family: var(--font-display);
  font-size: clamp(30px, 9vw, 64px);
  color: var(--ink);
  text-shadow: 0 6px 30px rgba(0,0,0,0.6);
}
#center-msg .big.accent { color: var(--accent); text-shadow: 0 0 36px rgba(163,230,53,0.5); }
#center-msg .big.danger { color: var(--danger); text-shadow: 0 0 36px rgba(255,45,74,0.6); animation: danger-pulse 0.7s ease-in-out infinite; }
#center-msg .sub { margin-top: 10px; font-size: 16px; color: var(--ink-dim); }
@keyframes danger-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.07); }
}
#center-msg .countdown {
  font-family: var(--font-display);
  font-size: clamp(80px, 22vw, 160px);
  color: var(--accent);
  text-shadow: 0 0 60px rgba(163,230,53,0.6);
  animation: count-zoom 0.9s cubic-bezier(.2,1.4,.4,1);
  display: inline-block;
}
@keyframes count-zoom {
  0% { transform: scale(2.2); opacity: 0; }
  30% { transform: scale(1); opacity: 1; }
  85% { opacity: 1; }
  100% { transform: scale(0.85); opacity: 0; }
}

/* ---------- onboarding ---------- */
#ob-skip {
  position: fixed;
  top: calc(14px + var(--sat));
  right: calc(14px + var(--sar));
  z-index: 11;
  font-size: 14px;
  padding: 10px 20px;
  color: var(--ink-dim);
}
#ob-skip.hidden, #ob-progress.hidden { display: none; }
#ob-hand {
  position: fixed;
  z-index: 9;
  font-size: 52px;
  pointer-events: none;
  filter: drop-shadow(0 4px 12px rgba(0,0,0,0.5));
  opacity: 0;
}
#ob-hand.show { animation: hand-swipe 1.5s cubic-bezier(.45,0,.4,1) infinite; }
@keyframes hand-swipe {
  0% { transform: translate(-70px, 70px) rotate(-18deg); opacity: 0; }
  15% { opacity: 1; }
  60% { transform: translate(70px, -70px) rotate(8deg); opacity: 1; }
  80%, 100% { transform: translate(90px, -90px) rotate(10deg); opacity: 0; }
}
.ob-progress {
  position: fixed;
  top: calc(22px + var(--sat));
  left: 0; right: 0;
  display: flex;
  justify-content: center;
  gap: 8px;
  z-index: 9;
  pointer-events: none;
}
.ob-progress i {
  width: 26px; height: 5px;
  border-radius: 3px;
  background: rgba(255,255,255,0.18);
  transition: background 0.3s;
}
.ob-progress i.on { background: var(--accent); box-shadow: 0 0 10px rgba(163,230,53,0.6); }

/* ---------- pause ---------- */
#pause { background: rgba(6, 9, 13, 0.72); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }
.panel {
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-radius: var(--radius);
  padding: 32px 30px;
  width: min(92vw, 400px);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  box-shadow: 0 24px 80px rgba(0,0,0,0.5);
  animation: panel-in 0.4s cubic-bezier(.2,1.4,.4,1);
}
@keyframes panel-in {
  0% { transform: scale(0.85) translateY(24px); opacity: 0; }
  100% { transform: scale(1) translateY(0); opacity: 1; }
}
.panel h2 {
  font-family: var(--font-display);
  font-size: 30px;
  letter-spacing: 0.5px;
  margin-bottom: 6px;
  /* the title stays put while the list under it scrolls; the panel's own glass
     backdrop shows through, so no separate background is needed */
  position: sticky;
  top: 0;
  z-index: 1;
}
.panel button { width: 100%; }

/* ---------- duel ---------- */
#duel-hud {
  position: fixed;
  inset: 0;
  z-index: 8;
  pointer-events: none;
}
#duel-hud.hidden { display: none; }
.duel-score {
  position: fixed;
  left: calc(14px + var(--sal));
  background: var(--glass);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-radius: 16px;
  padding: 8px 16px;
}
.duel-score b { font-family: var(--font-display); font-size: 26px; display: block; line-height: 1; }
.duel-score span { font-size: 9px; letter-spacing: 2px; color: var(--ink-dim); font-weight: 700; }
.duel-score.p1 { bottom: calc(14px + var(--sab)); border-color: rgba(163,230,53,0.4); }
.duel-score.p1 b { color: var(--accent); }
.duel-score.p2 { top: calc(14px + var(--sat)); transform: rotate(180deg); border-color: rgba(77,196,255,0.4); }
.duel-score.p2 b { color: #4dc4ff; }
#duel-timer {
  position: fixed;
  top: 50%; right: calc(10px + var(--sar));
  transform: translateY(-50%);
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--ink);
  background: var(--glass);
  border: 1px solid var(--glass-border);
  border-radius: 999px;
  padding: 8px 12px;
}
#duel-divider { /* drawn on canvas, class kept for future */ }

/* ---------- game over ---------- */
#gameover { background: rgba(6, 9, 13, 0.55); }
#go-rank {
  position: absolute;
  top: -26px;
  right: -14px;
  width: 76px; height: 76px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 40px;
  color: #10230a;
  background: radial-gradient(circle at 30% 30%, #ffe9a8, var(--gold));
  box-shadow: 0 10px 30px rgba(255,207,77,0.4), inset 0 2px 0 rgba(255,255,255,0.6);
  transform: rotate(12deg) scale(0);
  border: 3px solid rgba(255,255,255,0.5);
}
#go-rank.hidden { display: none; }
#go-rank.stamp { animation: rank-stamp 0.5s cubic-bezier(.2,1.8,.4,1) 0.35s forwards; }
@keyframes rank-stamp {
  0% { transform: rotate(-20deg) scale(2.4); opacity: 0; }
  60% { transform: rotate(14deg) scale(0.92); opacity: 1; }
  100% { transform: rotate(12deg) scale(1); opacity: 1; }
}
.panel { position: relative; }
#go-title {
  font-family: var(--font-display);
  font-size: clamp(30px, 8vw, 46px);
  margin-bottom: 2px;
}
#go-title.record {
  background: linear-gradient(90deg, var(--gold), #fff3c4, var(--gold));
  background-size: 200%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: shine 1.6s linear infinite;
}
@keyframes shine { to { background-position: 200%; } }
#go-mode {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 2px;
  color: var(--ink-dim);
  margin-bottom: 2px;
}
#go-score {
  font-family: var(--font-display);
  font-size: clamp(56px, 16vw, 92px);
  line-height: 1;
  color: var(--accent);
  text-shadow: 0 0 44px rgba(163,230,53,0.4);
}
#go-best { color: var(--ink-dim); font-size: 15px; margin-bottom: 6px; }
#go-best b { color: var(--gold); }
.go-stats {
  display: flex;
  gap: 10px;
  width: 100%;
  margin: 4px 0 10px;
}
.go-stat {
  flex: 1;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 16px;
  padding: 12px 6px;
  text-align: center;
}
.go-stat b { display: block; font-size: 22px; font-family: var(--font-display); }
.go-stat span { font-size: 11px; color: var(--ink-dim); letter-spacing: 0.6px; }

/* ---------- fx overlays ---------- */
#flash {
  position: fixed;
  inset: 0;
  background: #fff;
  opacity: 0;
  pointer-events: none;
  z-index: 50;
}
#vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 5;
  background: radial-gradient(ellipse at center, transparent 58%, rgba(0,0,0,0.42) 100%);
}
#vignette.hurt { animation: hurt 0.55s ease; }
/* Final life: the vignette stops being scenery and starts breathing. Paired
   with an 8% slower clock in game.js, so the run feels heavier on both
   channels at once rather than just looking different. */
:root.last-life #vignette { animation: last-life 1.6s ease-in-out infinite; }
@keyframes last-life {
  0%, 100% { background: radial-gradient(ellipse at center, transparent 56%, rgba(180,20,45,0.34) 100%); }
  50% { background: radial-gradient(ellipse at center, transparent 44%, rgba(255,40,70,0.5) 100%); }
}
@keyframes hurt {
  0% { box-shadow: inset 0 0 0 0 transparent; background: radial-gradient(ellipse at center, transparent 58%, rgba(0,0,0,0.42) 100%); }
  30% { background: radial-gradient(ellipse at center, transparent 40%, rgba(255,30,60,0.5) 100%); }
  100% { background: radial-gradient(ellipse at center, transparent 58%, rgba(0,0,0,0.42) 100%); }
}

/* ============================================================
   DESKTOP
   Until now this stylesheet had exactly one media query
   (prefers-reduced-motion), so every layout was the phone layout stretched
   across the window. Two things go wrong at width: chrome that is pinned to
   both window edges drifts metres apart, and #mode-rail — a flex row with
   left:0;right:0 and no justify-content — hugs the left edge.

   820px is the gate: above it the rail is re-sized to 7x98 + 6x10 = 746px plus
   32px padding, so it fits without scrolling at the breakpoint itself. Below
   the breakpoint nothing here applies and the phone layout is untouched, byte
   for byte — there the rail keeps its 118px cards and scrolls, as designed.

   --pf-w is written by resize() in game.js and holds the real playfield
   width, so the HUD sits over the play column instead of the window.
   ============================================================ */
@media (min-width: 820px) {
  /* The bug. Above the breakpoint the rail always fits, so centring it can
     never make a card unreachable by scrolling. */
  #mode-rail {
    justify-content: center;
    width: min(100% - 32px, var(--pf-w));
    margin-inline: auto;
    gap: 10px;
  }
  /* Seven modes at the phone's 118px would be 930px of cards and the rail
     would scroll again — which is the one thing centring must not allow, since
     a centred scroll box hides its first card. 98px keeps all seven on one row
     down to the breakpoint itself: 7x98 + 6x10 + 32 = 778px, inside the 788px
     a 820px window leaves. */
  .mode-card { width: 98px; }

  /* Chrome that tracked the window edges now tracks the play column. */
  #hud {
    left: 0; right: 0;
    width: min(100vw - 28px, var(--pf-w));
    margin-inline: auto;
  }
  #ghost-bar, #boss-bar {
    left: 0; right: 0;
    width: min(100vw - 24px, var(--pf-w));
    margin-inline: auto;
  }
  .menu-hint {
    width: min(100vw - 32px, var(--content-max));
    margin-inline: auto;
  }
  /* These two are shrink-to-fit badges, so they get pinned to the playfield
     edges rather than stretched to its width. */
  .duel-score { left: calc((100vw - min(100vw, var(--pf-w))) / 2 + 14px); }
  #duel-timer { right: calc((100vw - min(100vw, var(--pf-w))) / 2 + 10px); }

  /* Panels get room to breathe, and the lists get room to be read: the vh
     caps were tuned for a tall phone and leave a wide desktop window mostly
     empty. */
  .panel { width: min(92vw, 520px); padding: 34px 34px; }
  #ach-grid { grid-template-columns: repeat(6, 1fr); max-height: 56vh; }
  #camp-list { grid-template-columns: repeat(5, 1fr); max-height: 60vh; }
  #lang-list { grid-template-columns: repeat(3, 1fr); max-height: 60vh; }
  .set-list { max-height: 64vh; }
  #board-list { max-height: 52vh; }
  #mp-list { max-height: 44vh; }
}

/* Hover only where a pointer can actually hover — on touch these would stick
   after a tap and read as a stuck selection. Before this the only feedback of
   any kind was button:active. */
@media (hover: hover) and (pointer: fine) {
  button:hover { background: rgba(255,255,255,0.13); }
  button.primary:hover {
    box-shadow: 0 10px 38px rgba(var(--accent-rgb), 0.5), inset 0 1px 0 rgba(255,255,255,.45);
    filter: brightness(1.06);
  }
  .mode-card:hover {
    transform: translateY(-4px);
    border-color: rgba(var(--accent-rgb), 0.5);
    box-shadow: 0 14px 34px rgba(0,0,0,0.4);
  }
  .mode-card.locked:hover { transform: none; border-color: var(--glass-border); box-shadow: none; }
  .board-row:hover, .ach-tile:hover { background: rgba(255,255,255,0.09); }
  .set-row:hover, .set-link:hover { background: rgba(255,255,255,0.07); }
  #lang-list button:hover, #camp-list button:hover, .seg-btn:hover, .av-btn:hover, .rv-btn:hover {
    background: rgba(255,255,255,0.13);
  }
  #profile-chip:hover { border-color: rgba(var(--accent-rgb), 0.45); }
}

/* Keyboard focus. There was no focus ring anywhere, which made the game
   unusable without a pointer. :focus-visible keeps it off mouse clicks. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 999px;
}
.mode-card:focus-visible, .ach-tile:focus-visible, .panel:focus-visible { border-radius: 18px; }
input:focus-visible, .set-row:focus-visible { border-radius: 14px; }

/* Reduced motion comes from two sources: the OS preference and the in-game
   settings switch, which stamps data-motion="reduced" on <html>. Both must kill
   the same set, so the rules live in one place and are applied by two selectors.
   Ambient loops stop entirely; one-shot feedback (score punch, combo banner)
   is only shortened, because removing it would leave actions unacknowledged. */
@media (prefers-reduced-motion: reduce) {
  .logo, .menu-hint, #ob-hand, .load-fruit { animation: none !important; }
  :root.last-life #vignette { animation: none !important; background: radial-gradient(ellipse at center, transparent 52%, rgba(200,30,55,0.4) 100%) !important; }
  #wipe, .splash-blade { display: none !important; }
  #obc-stage.in, .screen.entering .panel, .panel { animation: none !important; }
  * { transition-duration: 0.01ms !important; }
}
:root[data-motion="reduced"] .logo,
:root[data-motion="reduced"] .menu-hint,
:root[data-motion="reduced"] #ob-hand,
:root[data-motion="reduced"] .load-fruit { animation: none !important; }
:root[data-motion="reduced"].last-life #vignette {
  animation: none !important;
  background: radial-gradient(ellipse at center, transparent 52%, rgba(200,30,55,0.4) 100%) !important;
}
:root[data-motion="reduced"] #wipe,
:root[data-motion="reduced"] .splash-blade { display: none !important; }
:root[data-motion="reduced"] #obc-stage.in,
:root[data-motion="reduced"] .screen.entering .panel,
:root[data-motion="reduced"] .panel { animation: none !important; }
:root[data-motion="reduced"] * { transition-duration: 0.01ms !important; }

/* browsers without backdrop-filter: solid panels instead of near-invisible glass */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  button, .panel, #score-wrap, #best-badge, #timer {
    background: rgba(19, 26, 35, 0.92);
  }
  button.primary {
    background: linear-gradient(135deg, var(--accent), #65c916);
  }
  #pause { background: rgba(6, 9, 13, 0.9); }
}

/* ---------- daily quests ---------- */
.panel-note {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.4px;
  color: var(--ink-dim);
  margin-bottom: 10px;
}
#quest-list {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.quest-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 14px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.07);
  text-align: left;
}
.qr-ic { font-size: 22px; line-height: 1; filter: grayscale(1); opacity: 0.55; }
.quest-row.done .qr-ic { filter: none; opacity: 1; }
.qr-mid { flex: 1; display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.qr-mid b { font-size: 12px; line-height: 1.25; color: var(--ink-dim); }
.quest-row.done .qr-mid b { color: var(--ink); }
.qr-mid small {
  font-size: 10px;
  font-weight: 700;
  color: var(--ink-dim);
  font-family: var(--font-display);
}
.qr-bar {
  display: block;
  height: 6px;
  border-radius: 4px;
  background: rgba(0,0,0,0.35);
  overflow: hidden;
}
.qr-bar b {
  display: block;
  height: 100%;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width 0.3s ease-out;
}
.qr-xp {
  font-style: normal;
  font-family: var(--font-display);
  font-size: 12px;
  color: var(--gold);
  min-width: 40px;
  text-align: right;
}
.quest-row.done { border-color: rgba(var(--accent-rgb), 0.4); }
.quest-row.done .qr-xp { color: var(--accent); }

/* count on the menu button — small enough not to fight the icon */
#btn-quests { position: relative; }
#quest-badge {
  position: absolute;
  right: -2px;
  bottom: -2px;
  font-style: normal;
  font-family: var(--font-display);
  font-size: 9px;
  line-height: 1;
  padding: 2px 4px;
  border-radius: 7px;
  background: var(--accent-2);
  color: #0b0f14;
}
#quest-badge.full { background: var(--accent); }
#quest-badge.hidden { display: none; }

/* the achievements filter sits under the count, above the grid */
#ach-filter { margin-bottom: 10px; }

/* ============================================================
   Start screen, round 4.

   What was wrong, from the screenshots rather than from taste:
   the record sat alone above ~350px of nothing, the mode cards
   wrapped their sub-lines onto two ragged lines at uneven
   heights, the profile chip ellipsised both the name AND the
   belt ("Melon…", "Lv 1 · Wh…"), and a decoration melon flew
   straight through the wordmark. The spawner fix lives in
   game.js; the rest is here.
   ============================================================ */

/* The hero flexes into the gap, so the rail needs to reserve its own room
   rather than overlapping it. 142px of cards + hint + breathing space. */
#menu { justify-content: flex-start; padding-bottom: calc(196px + var(--sab)); }

/* Entrance. The menu is the first thing anyone sees; it should assemble
   rather than appear. Staggered so the eye lands top-down. */
#menu:not(.hidden) .menu-top { animation: rise-in 0.5s cubic-bezier(.2,.7,.3,1) both; }
#menu:not(.hidden) .logo { animation: logo-float 4s ease-in-out infinite, rise-in 0.6s cubic-bezier(.2,.7,.3,1) 0.06s both; }
#menu:not(.hidden) .menu-stats { animation: rise-in 0.5s cubic-bezier(.2,.7,.3,1) 0.16s both; }
#menu:not(.hidden) .menu-hint { animation: hint-pulse 2s ease-in-out infinite, rise-in 0.5s ease 0.3s both; }
@keyframes rise-in {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: translateY(0); }
}

/* A blade-shine that sweeps the wordmark every few seconds — the one moment
   of motion that says "slicing game" without a single extra element. */
.logo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg, transparent 42%, rgba(255,255,255,0.55) 50%, transparent 58%);
  transform: translateX(-120%);
  animation: logo-shine 6.5s ease-in-out 1.2s infinite;
  pointer-events: none;
  mix-blend-mode: overlay;
}
@keyframes logo-shine {
  0%, 62% { transform: translateX(-120%); }
  78%, 100% { transform: translateX(120%); }
}

/* Cards: uniform height, no more two-line sub-copy ragged against one-line. */
#mode-rail { align-items: stretch; }
.mode-card {
  justify-content: flex-start;
  gap: 3px;
  position: relative;
  overflow: hidden;
  animation: card-in 0.45s cubic-bezier(.2,.7,.3,1) both;
}
.mode-card small { display: block; min-height: 26px; }
.mode-card:nth-child(1) { animation-delay: 0.20s; }
.mode-card:nth-child(2) { animation-delay: 0.26s; }
.mode-card:nth-child(3) { animation-delay: 0.32s; }
.mode-card:nth-child(4) { animation-delay: 0.38s; }
.mode-card:nth-child(5) { animation-delay: 0.44s; }
.mode-card:nth-child(6) { animation-delay: 0.50s; }
.mode-card:nth-child(7) { animation-delay: 0.56s; }
/* Vertical only, deliberately. A scale() in here also scales the box that
   getBoundingClientRect() reports, so while the last card was still easing in
   it measured ~5px narrow and threw the rail's centring off by 2.2px — enough
   to fail tests/desktop.js, and enough to be a real sub-pixel wobble on screen.
   translateY moves nothing horizontally, so the geometry stays measurable. */
@keyframes card-in {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

/* The first card is where a new player should go, so it reads as the primary
   action instead of one of seven identical tiles. */
.mode-card:first-child {
  background: linear-gradient(160deg, rgba(163,230,53,0.16), rgba(163,230,53,0.05));
  border-color: rgba(163,230,53,0.34);
}
.mode-card:first-child b { color: var(--ink); }

/* Today's challenge pulses until it has been played — a quiet nudge that
   stops the moment it would become nagging. */
#btn-daily .mc-stat { animation: daily-pulse 2.4s ease-in-out infinite; }
@keyframes daily-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

/* Profile chip: it was ellipsising the name AND the belt on a 420px screen —
   "Roni…" over "Lv 1 · …" tells the player neither. Five icon buttons plus a
   chip simply do not fit, so the chip takes the leftover width instead of a
   fixed 146px, and below 460px the belt name drops. The belt is the expendable
   half; the name is who you are. */
#profile-chip { flex: 1 1 auto; min-width: 0; }
.menu-top-btns { flex: 0 0 auto; }
.chip-txt { max-width: none; min-width: 0; }
#chip-rank { white-space: nowrap; }
@media (max-width: 460px) {
  .menu-top .icon-btn { width: 40px; height: 40px; font-size: 17px; }
  .menu-top-btns { gap: 6px; }
  #chip-rank .belt { display: none; }
}
