  :root {
    --bg:          #323539;
    --card-bg:     rgba(32, 46, 82, 0.72);
    --card-border: rgba(180, 200, 240, 0.22);
    --text:        #f4f6fb;
    --text-dim:    #c6cee0;   /* WCAG AA on card-bg */
    --gold:        #ffd36e;
    --teal:        #5dd6c8;
    --coral:       #ff8a8a;
    --lilac:       #b89bff;
    --amber:       #ffa866;
    --radius-sm:   10px;
    --radius-md:   16px;
    --radius-lg:   22px;
    --radius-pill: 999px;
  }

  * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
  button, a, [role="button"] { -webkit-tap-highlight-color: transparent; }
  button:focus, button:focus-visible, button::-moz-focus-inner { outline: none; }
  button { -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
  body {
    background: var(--bg); overflow: hidden;
    font-family: 'Outfit', ui-rounded, 'SF Pro Rounded', system-ui, sans-serif;
    color: var(--text);
    -webkit-font-smoothing: antialiased;
  }
  #canvas { display: block; }

  #hud {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    pointer-events: none; z-index: 10;
  }
  /* Gameplay HUD is invisible until the run starts — otherwise the stat pills,
     health/XP bars, ability bar and minimap all leak through the transparent
     landing overlay and make the title screen look like a paused game. The
     .playing class is toggled by playSelectedStage / restartGame / endGame. */
  body:not(.playing) #hud,
  body:not(.playing) #minimap,
  body:not(.playing) #top-bar,
  body:not(.playing) #ability-bar,
  body:not(.playing) #health-bar-wrap,
  body:not(.playing) #combo-counter,
  body:not(.playing) #wave-modifier {
    display: none !important;
  }

  #top-bar {
    position: fixed; top: 14px; left: 50%; transform: translateX(-50%);
    display: flex; gap: 10px; align-items: center; pointer-events: none;
  }
  .stat-block {
    background: rgba(22, 26, 36, 0.28);
    backdrop-filter: blur(3px) saturate(1.1);
    -webkit-backdrop-filter: blur(3px) saturate(1.1);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-pill);
    padding: 4px 14px; color: var(--text); font-size: 12px;
    text-align: center; min-width: 64px;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.75);
    display: flex; align-items: baseline; gap: 8px;
  }
  .stat-block .label {
    color: var(--text-dim); font-size: 9.5px;
    text-transform: uppercase; letter-spacing: 1.3px; font-weight: 600;
  }
  .stat-block .value { font-size: 16px; font-weight: 700; letter-spacing: 0.3px; }
  /* Enraged state — "☠ ENRAGED" is ~2.5× wider than a normal 3:21 timer.
     Hide the "Time" label so the full phrase fits the pill and neighboring
     stat-blocks aren't pushed sideways. Compact letter-spacing keeps the
     content readable inside the block's natural width. */
  .stat-block.enraged .label { display: none; }
  .stat-block.enraged .value { font-size: 13px; letter-spacing: 0.4px; white-space: nowrap; }
  #score-val { color: var(--gold); }
  #level-val { color: var(--teal); }
  #kills-val { color: var(--coral); }

  #health-bar-wrap {
    position: fixed; bottom: 72px; left: 50%; transform: translateX(-50%);
    width: 320px; pointer-events: none;
  }
  .bar-label {
    color: var(--text); font-size: 11px; text-transform: uppercase;
    letter-spacing: 1.2px; margin-bottom: 5px; font-weight: 600;
    display: flex; justify-content: space-between;
  }
  .bar-bg {
    background: rgba(18, 24, 44, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-pill); height: 14px; overflow: hidden;
  }
  .bar-fill {
    height: 100%; border-radius: var(--radius-pill);
    transition: width 0.25s cubic-bezier(0.2, 0.8, 0.2, 1);
  }
  #health-fill { background: #4bd66a; width: 100%; transition: width 0.25s cubic-bezier(0.2, 0.8, 0.2, 1), background-color 0.35s ease; }
  #xp-fill     { background: linear-gradient(90deg, #6ec1ff 0%, #b89bff 55%, #ff9ec4 100%); width: 0%; box-shadow: 0 0 0 rgba(255,215,110,0); transition: width 0.25s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 0.35s ease; }
  #xp-fill.ding { animation: xpDing 520ms cubic-bezier(0.3, 0.8, 0.2, 1); }
  @keyframes xpDing {
    0%   { filter: brightness(1); box-shadow: 0 0 0 rgba(255,215,110,0); }
    25%  { filter: brightness(1.7) saturate(1.3); box-shadow: 0 0 18px 4px rgba(255,215,110,0.75); }
    100% { filter: brightness(1); box-shadow: 0 0 0 rgba(255,215,110,0); }
  }
  #level-val.level-pop { animation: levelPop 620ms cubic-bezier(0.34, 1.56, 0.64, 1); }
  @keyframes levelPop {
    0%   { transform: scale(1); color: var(--teal); text-shadow: 0 0 0 rgba(255,215,110,0); }
    35%  { transform: scale(1.55); color: #ffe088; text-shadow: 0 0 18px rgba(255,215,110,0.95), 0 0 4px rgba(255,255,255,0.9); }
    100% { transform: scale(1); color: var(--teal); text-shadow: 0 0 0 rgba(255,215,110,0); }
  }

  #xp-bar-wrap {
    position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%);
    width: 320px; pointer-events: none;
  }

  #wave-notice {
    position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
    color: var(--text); font-size: 40px; font-weight: 700; text-align: center;
    letter-spacing: 0.5px;
    text-shadow: 0 0 32px rgba(184, 155, 255, 0.55), 0 2px 12px rgba(0,0,0,0.4);
    pointer-events: none;
    opacity: 0; transition: opacity 0.5s;
  }

  /* Boss-name banner — persistent HUD label while a boss is alive. Pinned
     top-center; --boss-color is set by spawnBoss to the current boss's rally
     color so the label reads as an identity card for the boss. */
  #boss-banner {
    position: fixed; top: 16px; left: 50%; transform: translateX(-50%);
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    padding: 8px 22px 10px;
    background: rgba(8, 10, 22, 0.55);
    border: 1px solid var(--boss-color, rgba(255, 46, 165, 0.85));
    border-radius: 10px;
    color: var(--text);
    box-shadow: 0 0 18px var(--boss-color, rgba(255, 46, 165, 0.35));
    pointer-events: none;
    opacity: 0; transition: opacity 0.35s;
    z-index: 90;
  }
  #boss-banner.visible { opacity: 1; }
  #boss-banner .boss-banner-label {
    font-size: 10px; letter-spacing: 2.5px; font-weight: 600;
    color: var(--boss-color, #ff2ea5);
    text-transform: uppercase;
  }
  #boss-banner .boss-banner-name {
    font-size: 20px; font-weight: 700; letter-spacing: 0.5px;
    text-shadow: 0 0 12px var(--boss-color, rgba(255, 46, 165, 0.6));
  }

  /* Stage-unlock banner — celebratory popup when a new stage is unlocked.
     Uses the .visible class to drive entrance/exit; confetti are dropped
     into the root host by _spawnVictoryConfetti. */
  #stage-unlock {
    position: fixed; inset: 0;
    display: flex; align-items: center; justify-content: center;
    pointer-events: none; z-index: 140;
    opacity: 0;
    transition: opacity 0.32s ease-out;
  }
  #stage-unlock.visible { opacity: 1; }
  #stage-unlock .stage-unlock-panel {
    position: relative;
    width: min(420px, 88vw);
    padding: 20px 22px 22px;
    border-radius: 18px;
    background: linear-gradient(180deg, rgba(38, 30, 72, 0.96), rgba(14, 18, 34, 0.97));
    border: 2px solid rgba(126, 226, 255, 0.85);
    box-shadow:
      0 0 60px rgba(126, 226, 255, 0.45),
      0 0 120px rgba(184, 155, 255, 0.25),
      0 12px 40px rgba(0, 0, 0, 0.55);
    text-align: center;
    color: #f6f8fe;
    transform: scale(0.82) translateY(14px);
    transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  #stage-unlock.visible .stage-unlock-panel {
    animation: stageUnlockPop 0.7s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  }
  @keyframes stageUnlockPop {
    0%   { transform: scale(0.7) translateY(18px); }
    55%  { transform: scale(1.06) translateY(-2px); }
    100% { transform: scale(1) translateY(0); }
  }
  #stage-unlock .stage-unlock-eyebrow {
    font-size: 13px; font-weight: 800; letter-spacing: 2.4px;
    color: #ffd36e;
    text-shadow: 0 0 14px rgba(255, 211, 110, 0.6);
    margin-bottom: 12px;
  }
  #stage-unlock .stage-unlock-thumb {
    width: 100%; aspect-ratio: 16 / 9;
    background-size: cover; background-position: center;
    border-radius: 10px;
    box-shadow: 0 0 24px rgba(126, 226, 255, 0.35), inset 0 0 0 1px rgba(255,255,255,0.08);
    margin-bottom: 12px;
  }
  #stage-unlock .stage-unlock-name {
    font-size: 26px; font-weight: 800; letter-spacing: 1.4px;
    color: #f6f8fe;
    text-shadow: 0 0 18px rgba(126, 226, 255, 0.55);
    margin-bottom: 4px;
  }
  #stage-unlock .stage-unlock-hint {
    font-size: 12px; color: rgba(246, 248, 254, 0.6);
    letter-spacing: 0.6px;
  }

  #tonic-popup {
    position: fixed; top: 45%; left: 50%;
    transform: translate(-50%, -50%) scale(0.6);
    padding: 28px 40px; border-radius: 16px;
    background: linear-gradient(180deg, rgba(40,30,70,0.96), rgba(14,18,34,0.96));
    border: 2px solid #ffd700;
    box-shadow: 0 0 48px rgba(255,215,0,0.35), 0 8px 32px rgba(0,0,0,0.5);
    color: #f6f8fe; text-align: center;
    opacity: 0; pointer-events: none;
    transition: opacity 0.3s, transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
    z-index: 120;
  }
  #tonic-popup.visible { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  #tonic-popup .ti-icon { font-size: 56px; margin-bottom: 8px; line-height: 1; }
  #tonic-popup .ti-name { font-size: 22px; font-weight: 700; color: #ffd700; letter-spacing: 2px; margin-bottom: 6px; }
  #tonic-popup .ti-desc { font-size: 14px; color: rgba(246,248,254,0.8); }

  #powerup-screen {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: radial-gradient(ellipse at center, rgba(60, 40, 100, 0.9), rgba(14, 18, 34, 0.96));
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; z-index: 100;
    display: none;
    overflow: hidden;
  }
  /* Soft rotating nebula behind the cards for depth. */
  #powerup-screen::before {
    content: ''; position: absolute; inset: -25%;
    background:
      radial-gradient(circle at 30% 40%, rgba(255, 211, 110, 0.18), transparent 45%),
      radial-gradient(circle at 70% 65%, rgba(184, 155, 255, 0.22), transparent 50%),
      radial-gradient(circle at 50% 50%, rgba(126, 226, 255, 0.12), transparent 55%);
    pointer-events: none;
    animation: nebulaSpin 32s linear infinite;
  }
  @keyframes nebulaSpin {
    0%   { transform: rotate(0deg)   scale(1); }
    50%  { transform: rotate(180deg) scale(1.08); }
    100% { transform: rotate(360deg) scale(1); }
  }
  #powerup-screen > * { position: relative; z-index: 1; }
  #powerup-screen h2 {
    font-size: 34px; margin-bottom: 10px; letter-spacing: 1px; font-weight: 700;
    background: linear-gradient(120deg, #ffd36e, #ff9ec4 35%, #b89bff 65%, #ffd36e);
    background-size: 220% 100%;
    -webkit-background-clip: text; background-clip: text; color: transparent;
    animation: titleSweep 2.4s ease-in-out infinite;
    filter: drop-shadow(0 4px 24px rgba(255, 211, 110, 0.35));
  }
  /* Replay entrance animations every time the screen opens by toggling
     .entering on #powerup-screen — the class restart gives us a fresh keyframe
     run instead of the one-shot animation on mount. */
  #powerup-screen.entering h2 {
    animation: titleSweep 2.4s ease-in-out infinite,
               titleEnter 620ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
  }
  #powerup-screen.entering p {
    animation: subEnter 520ms ease-out both; animation-delay: 180ms;
  }
  @keyframes titleSweep {
    0%, 100% { background-position: 0% 50%; }
    50%      { background-position: 100% 50%; }
  }
  @keyframes titleEnter {
    0%   { transform: translateY(-18px) scale(0.8); opacity: 0; }
    100% { transform: translateY(0)      scale(1);   opacity: 1; }
  }
  #powerup-screen p {
    color: var(--text-dim); font-size: 15px; margin-bottom: 32px;
  }
  @keyframes subEnter {
    0%   { transform: translateY(-8px); opacity: 0; }
    100% { transform: translateY(0);    opacity: 0.8; }
  }
  #powerup-choices {
    display: flex; gap: 22px; flex-wrap: wrap; justify-content: center;
    max-width: 940px;
    perspective: 900px;
  }
  .powerup-card {
    position: relative;
    background: linear-gradient(155deg, rgba(45, 40, 80, 0.92), rgba(24, 28, 54, 0.92));
    border: 1.5px solid rgba(184, 155, 255, 0.32);
    border-radius: var(--radius-lg);
    padding: 26px 22px; width: 210px; cursor: pointer;
    transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1),
                border-color 0.2s, box-shadow 0.28s, background 0.28s;
    text-align: center; pointer-events: all;
    transform-style: preserve-3d;
    animation: cardIn 520ms cubic-bezier(0.34, 1.56, 0.64, 1) both;
    overflow: hidden;
  }
  .powerup-card:nth-child(1) { animation-delay: 140ms; }
  .powerup-card:nth-child(2) { animation-delay: 240ms; }
  .powerup-card:nth-child(3) { animation-delay: 340ms; }
  @keyframes cardIn {
    0%   { opacity: 0; transform: translateY(40px) rotateX(-18deg) scale(0.88); }
    70%  { opacity: 1; transform: translateY(-6px) rotateX(4deg)   scale(1.04); }
    100% { opacity: 1; transform: translateY(0)    rotateX(0)      scale(1); }
  }
  /* Shimmering highlight sweep on hover. */
  .powerup-card::before {
    content: ''; position: absolute; inset: 0;
    background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.12) 50%, transparent 70%);
    transform: translateX(-120%);
    transition: transform 0.6s ease;
    pointer-events: none;
  }
  .powerup-card:hover, .powerup-card:focus-visible {
    border-color: var(--lilac);
    transform: translateY(-8px) rotateX(6deg) scale(1.03);
    box-shadow: 0 20px 48px rgba(184, 155, 255, 0.38), 0 0 0 1px rgba(255, 211, 110, 0.35) inset;
    background: linear-gradient(155deg, rgba(60, 50, 100, 0.96), rgba(30, 34, 66, 0.96));
    outline: none;
  }
  .powerup-card:hover::before { transform: translateX(120%); }
  .powerup-card .icon {
    font-size: 38px; margin-bottom: 12px;
    transition: transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1), filter 0.28s;
    display: inline-block;
  }
  .powerup-card:hover .icon {
    transform: scale(1.18) rotate(-6deg);
    filter: drop-shadow(0 4px 14px rgba(255, 211, 110, 0.55));
  }
  .powerup-card .name { color: var(--text); font-size: 15px; font-weight: 700; margin-bottom: 6px; }
  .powerup-card .desc { color: var(--text-dim); font-size: 12.5px; line-height: 1.55; }
  .powerup-card .tier {
    font-size: 10.5px; color: var(--lilac); margin-top: 10px;
    text-transform: uppercase; letter-spacing: 1.2px; font-weight: 600;
  }
  /* Per-tier hover accent — hint at what the card does through color. */
  .powerup-card[data-tier="Offense"]:hover  { box-shadow: 0 20px 48px rgba(255, 107, 107, 0.35), 0 0 0 1px rgba(255, 107, 107, 0.45) inset; border-color: #ff9e7a; }
  .powerup-card[data-tier="Defense"]:hover  { box-shadow: 0 20px 48px rgba(93, 214, 200, 0.35), 0 0 0 1px rgba(93, 214, 200, 0.45) inset; border-color: #7ee2d0; }
  .powerup-card[data-tier="Mobility"]:hover { box-shadow: 0 20px 48px rgba(126, 226, 255, 0.35), 0 0 0 1px rgba(126, 226, 255, 0.45) inset; border-color: #9fdfff; }
  .powerup-card[data-tier="Utility"]:hover  { box-shadow: 0 20px 48px rgba(255, 211, 110, 0.35), 0 0 0 1px rgba(255, 211, 110, 0.45) inset; border-color: #ffd36e; }

  @keyframes card-burst {
    0%   { transform: scale(1); box-shadow: 0 0 0 rgba(255,215,0,0); filter: brightness(1); }
    30%  { transform: scale(1.18); box-shadow: 0 0 56px 8px rgba(255,215,0,0.7); filter: brightness(1.45) saturate(1.3); }
    75%  { transform: scale(1.08); box-shadow: 0 0 80px 12px rgba(255,215,0,0.5); filter: brightness(1.2); }
    100% { transform: scale(0); opacity: 0; filter: brightness(1); }
  }
  .powerup-card.card-picked, .shop-card.card-picked,
  .stage-hero-card.card-picked,
  #overlay #start-btn.card-picked,
  #overlay #relic-bar.card-picked,
  #overlay #rankings-bar.card-picked {
    animation: card-burst 380ms cubic-bezier(0.5, 0, 0.2, 1) forwards;
    pointer-events: none; z-index: 2;
  }
  .powerup-card.card-dismissed, .shop-card.card-dismissed,
  .stage-hero-card.card-dismissed {
    transition: opacity 200ms ease, transform 200ms ease, filter 200ms ease;
    opacity: 0.08; transform: scale(0.82) translateY(12px); filter: blur(2px); pointer-events: none;
  }

  /* Daily challenge button — sits below PLAY on the landing, smaller + more
     restrained. Icon-first so the "same run for everyone today" affordance
     reads at a glance. Amber accent contrasts with PLAY's pink. */
  #daily-btn {
    margin-top: 10px;
    display: inline-flex; align-items: center; gap: 8px;
    padding: 9px 22px;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 14px; font-weight: 700; letter-spacing: 2px;
    color: #1a1209;
    background: linear-gradient(135deg, #ffd166, #ff9040);
    border: 1px solid rgba(255,200,120,0.75);
    border-radius: 999px;
    box-shadow: 0 4px 14px rgba(255,144,64,0.28), 0 0 20px rgba(255,209,102,0.2);
    cursor: pointer;
    transition: transform 0.15s, box-shadow 0.15s, filter 0.15s;
  }
  #daily-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 18px rgba(255,144,64,0.4), 0 0 28px rgba(255,209,102,0.3);
    filter: brightness(1.06);
  }
  #daily-btn .daily-ico { font-size: 16px; line-height: 1; }
  /* HUD badge — only renders while in an active daily run. Populated +
     shown via JS based on isDailyRun() + getDailyKey(). */
  #daily-badge {
    position: fixed; top: 96px; right: 20px;
    display: none;
    padding: 6px 12px;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 11px; font-weight: 700; letter-spacing: 1.5px;
    color: #ffd166;
    background: rgba(26, 18, 9, 0.78);
    border: 1px solid rgba(255,200,120,0.45);
    border-radius: 999px;
    pointer-events: none;
    z-index: 10;
  }
  body.playing.daily-run #daily-badge { display: inline-block; }
  @media (max-width: 720px) {
    #daily-badge { top: 70px; right: 14px; font-size: 10px; padding: 4px 10px; }
  }

  /* Full-screen gold flash when level-up opens. Pinned to the overlay root. */
  #level-up-flash {
    position: fixed; inset: 0; z-index: 150;
    background: radial-gradient(ellipse at center, rgba(255, 225, 140, 0.55), rgba(255, 180, 80, 0.2) 45%, transparent 70%);
    pointer-events: none; opacity: 0;
  }
  #level-up-flash.fire { animation: levelUpFlash 700ms ease-out; }
  @keyframes levelUpFlash {
    0%   { opacity: 0; }
    15%  { opacity: 1; }
    100% { opacity: 0; }
  }

  /* LVL chip sitting above the modal title — replaces the old floating banner
     that used to overlap the card grid. Populated from showPowerupScreen and
     replayed each open via the #powerup-screen.entering class. */
  #level-up-chip {
    display: inline-flex; align-items: baseline; gap: 10px;
    margin-bottom: 14px;
    padding: 6px 18px 7px;
    border-radius: 999px;
    background: linear-gradient(135deg, rgba(255, 211, 110, 0.24), rgba(184, 155, 255, 0.22));
    border: 1px solid rgba(255, 211, 110, 0.55);
    box-shadow: 0 6px 24px rgba(255, 211, 110, 0.22), inset 0 0 0 1px rgba(255, 255, 255, 0.08);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    font-weight: 800; letter-spacing: 2.4px; text-transform: uppercase;
    color: #ffe7a8;
    transform-origin: center;
    opacity: 0;
  }
  #level-up-chip .lvl-word { font-size: 12px; color: rgba(255, 231, 168, 0.85); }
  #level-up-chip .lvl-num {
    font-size: 22px;
    background: linear-gradient(120deg, #fff3c8, #ffd36e 45%, #ff9ec4);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    filter: drop-shadow(0 2px 8px rgba(255, 211, 110, 0.55));
  }
  #powerup-screen.entering #level-up-chip {
    animation: levelChipPop 720ms cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
  }
  @keyframes levelChipPop {
    0%   { opacity: 0; transform: translateY(10px) scale(0.7); }
    55%  { opacity: 1; transform: translateY(0)    scale(1.15); }
    100% { opacity: 1; transform: translateY(0)    scale(1);   }
  }

  /* Orbital stars dropped into the picked card's center. */
  .pick-spark {
    position: fixed; pointer-events: none; z-index: 160;
    width: 10px; height: 10px; margin: -5px 0 0 -5px;
    background: radial-gradient(circle, #fff 0%, #ffd36e 45%, transparent 70%);
    border-radius: 50%;
    animation: sparkFly 620ms cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
  }
  @keyframes sparkFly {
    0%   { transform: translate(0,0) scale(0.6); opacity: 1; }
    100% { transform: translate(var(--dx), var(--dy)) scale(0.2); opacity: 0; }
  }

  #overlay {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center; z-index: 200;
    isolation: isolate;
  }
  /* Background image layer — hero art is generated procedurally and set via JS */
  #overlay-bg {
    position: absolute; inset: 0; z-index: -2;
    background: #0a0810 center/cover no-repeat;
  }
  /* Subtle animated torch flicker over the image */
  #overlay-bg::after {
    content: ''; position: absolute; inset: 0;
    background: radial-gradient(ellipse 60% 40% at 50% 85%, rgba(255,160,80,0.18), transparent 70%);
    mix-blend-mode: screen;
    animation: torchFlicker 2.8s ease-in-out infinite;
  }
  @keyframes torchFlicker {
    0%, 100% { opacity: 0.8; }
    50%      { opacity: 1.0; }
    23%      { opacity: 0.65; }
    72%      { opacity: 0.9; }
  }
  #overlay-content {
    display: flex; flex-direction: column; align-items: center;
    padding: 32px;
    max-width: 560px; text-align: center;
  }
  #overlay h1 {
    font-size: clamp(44px, 7vw, 68px);
    margin-bottom: 12px; font-weight: 800; letter-spacing: 1px; line-height: 1;
    background: linear-gradient(120deg, #ffd36e, #ff9ec4 50%, #b89bff);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    filter: drop-shadow(0 4px 24px rgba(255, 180, 120, 0.35));
  }
  #overlay p  { color: var(--text-dim); font-size: 15px; margin-bottom: 24px; text-align: center; line-height: 1.7; }

  /* Requirement badge — clear, iconographic, not alarming */
  #requirements, #touch-requirements {
    display: inline-flex; align-items: center; gap: 14px;
    background: var(--card-bg);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-md);
    padding: 12px 18px; margin-bottom: 28px;
    color: var(--text);
    box-shadow: 0 4px 18px rgba(10, 14, 30, 0.35);
  }
  #touch-requirements { display: none; }
  #requirements .req-icons {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--amber); flex-shrink: 0;
  }
  #requirements .req-plus { opacity: 0.55; font-weight: 600; }
  #requirements .req-text {
    text-align: left; font-size: 13.5px; line-height: 1.45;
  }
  #requirements .req-text strong { font-weight: 700; }
  #requirements .req-hint {
    display: block; color: var(--text-dim);
    font-size: 11.5px; margin-top: 3px; letter-spacing: 0.2px;
  }
  /* Relic bar — the whole pill is a clickable button that opens the shop.
     Cyan palette so it reads distinct from rankings (violet) and PLAY (warm).
     Double-id beats the blanket `#overlay button` gradient. */
  #overlay #relic-bar {
    display: inline-flex; align-items: center; gap: 14px;
    margin: 0 0 18px;
    padding: 10px 18px;
    border-radius: var(--radius-pill);
    background: rgba(10, 20, 30, 0.44);
    border: 1px solid rgba(126, 226, 255, 0.3);
    backdrop-filter: blur(10px) saturate(1.1);
    -webkit-backdrop-filter: blur(10px) saturate(1.1);
    color: inherit; font-family: inherit; font-weight: 400;
    font-size: 13px; letter-spacing: 0.5px;
    box-shadow: none;
    cursor: pointer;
    transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1),
                box-shadow 0.22s, border-color 0.22s, background 0.22s;
  }
  #overlay #relic-bar:hover,
  #overlay #relic-bar:focus-visible {
    transform: translateY(-1px);
    border-color: rgba(126, 226, 255, 0.55);
    background: rgba(14, 32, 48, 0.6);
    box-shadow: 0 6px 20px rgba(126, 226, 255, 0.3);
    outline: none;
  }
  #relic-bar .relic-label {
    color: #7ee2ff; font-weight: 800; letter-spacing: 0.8px;
  }
  #relic-bar .relic-count {
    color: var(--text); font-weight: 700; font-size: 15px;
    min-width: 32px; text-align: left;
  }

  /* Rankings pill — shared format used on the landing screen and at the end
     of a run. Whole pill is a single clickable button; the chevron is a
     visual affordance, not a separate control. Warm-violet palette so it
     reads distinct from relics (cyan) and PLAY (warm-amber). ID-selector
     specificity (#overlay, #gameover) beats the blanket button gradient
     defined above (`#overlay button { background: linear-gradient(...) }`). */
  #overlay .rankings-pill,
  #gameover .rankings-pill {
    display: inline-flex; align-items: center; gap: 12px;
    padding: 10px 18px;
    border-radius: var(--radius-pill);
    background: rgba(36, 22, 48, 0.44);
    border: 1px solid rgba(209, 174, 255, 0.3);
    backdrop-filter: blur(10px) saturate(1.1);
    -webkit-backdrop-filter: blur(10px) saturate(1.1);
    color: inherit; font-family: inherit; font-weight: 400;
    font-size: 13px; letter-spacing: 0.5px;
    box-shadow: none;
    cursor: pointer;
    transition: transform 0.18s cubic-bezier(0.2, 0.8, 0.2, 1),
                box-shadow 0.22s, border-color 0.22s, background 0.22s;
  }
  #overlay .rankings-pill:hover,
  #gameover .rankings-pill:hover,
  #overlay .rankings-pill:focus-visible,
  #gameover .rankings-pill:focus-visible {
    transform: translateY(-1px);
    border-color: rgba(209, 174, 255, 0.55);
    background: rgba(48, 30, 64, 0.56);
    box-shadow: 0 6px 20px rgba(155, 123, 255, 0.32);
    outline: none;
  }
  .rankings-pill .rankings-label {
    color: #d1aeff; font-weight: 800; letter-spacing: 0.8px;
  }

  /* Landing placement — pill sits between the relic bar and PLAY button. */
  #rankings-bar {
    margin: 0 0 18px;
  }
  /* Sync icon — floats in the overlay's top-right corner so it reads as a
     tucked-away utility instead of competing with SHOP/PLAY. Double-id
     specificity beats the blanket `#overlay button` gradient below. */
  #overlay #progress-sync-btn {
    position: absolute; top: 14px; right: 14px;
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; padding: 0;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 50%;
    box-shadow: none;
    cursor: pointer;
    font-family: inherit;
    transition: color 0.18s, border-color 0.18s, background 0.18s, transform 0.18s;
    z-index: 1;
  }
  #overlay #progress-sync-btn svg { display: block; }
  #overlay #progress-sync-btn:hover,
  #overlay #progress-sync-btn:focus-visible {
    color: var(--text);
    border-color: rgba(255, 255, 255, 0.28);
    background: rgba(255, 255, 255, 0.08);
    transform: translateY(-1px);
    box-shadow: none;
  }
  @media (max-width: 600px) {
    #overlay #progress-sync-btn { top: 10px; right: 10px; width: 36px; height: 36px; }
    #overlay #progress-sync-btn svg { width: 16px; height: 16px; }
  }

  /* Sync-progress nudge. Floats directly below the sync button (top-right
     corner of the overlay) with an up-pointing arrow so the connection to
     the icon reads at a glance. Hidden by default — the boot/landing-visible
     handler flips `.visible` on only when syncNudge.shouldShow() returns
     true. Dismissal permanence lives in localStorage via syncNudge.dismiss().
     Animation: slide-down entrance + gentle bob + slow border glow pulse. */
  #sync-nudge {
    position: absolute; top: 62px; right: 14px;
    display: none; align-items: flex-start; gap: 10px;
    width: 250px; padding: 12px 12px 12px 14px;
    background: linear-gradient(135deg, rgba(18, 32, 64, 0.96), rgba(12, 22, 48, 0.96));
    border: 1px solid rgba(126, 226, 255, 0.45);
    border-radius: 14px;
    box-shadow:
      0 10px 28px rgba(0, 0, 0, 0.45),
      0 0 0 1px rgba(126, 226, 255, 0.12) inset,
      0 0 22px rgba(126, 226, 255, 0.22);
    color: var(--text);
    font-family: inherit;
    pointer-events: auto;
    transform-origin: top right;
    z-index: 2;
  }
  #sync-nudge.visible {
    display: flex;
    animation:
      sync-nudge-in 0.52s cubic-bezier(0.18, 0.9, 0.32, 1.2) both,
      sync-nudge-bob 3.6s ease-in-out 0.55s infinite,
      sync-nudge-glow 2.4s ease-in-out 0.55s infinite;
  }
  #sync-nudge.dismissing {
    animation: sync-nudge-out 0.28s ease-in forwards !important;
    pointer-events: none;
  }
  .sync-nudge-arrow {
    position: absolute; top: -7px; right: 18px;
    width: 14px; height: 14px;
    background: linear-gradient(135deg, rgba(18, 32, 64, 0.96), rgba(12, 22, 48, 0.96));
    border-top: 1px solid rgba(126, 226, 255, 0.45);
    border-left: 1px solid rgba(126, 226, 255, 0.45);
    transform: rotate(45deg);
  }
  .sync-nudge-body {
    flex: 1 1 auto;
    min-width: 0;
  }
  .sync-nudge-title {
    font-size: 13px; font-weight: 800;
    letter-spacing: 0.6px; text-transform: uppercase;
    color: #cfeeff;
    margin-bottom: 3px;
  }
  .sync-nudge-msg {
    font-size: 12px;
    line-height: 1.35;
    color: var(--text-dim);
  }
  #overlay #sync-nudge-close {
    flex: 0 0 auto;
    display: inline-flex; align-items: center; justify-content: center;
    width: 22px; height: 22px; padding: 0;
    background: rgba(255, 255, 255, 0.06);
    color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 50%;
    cursor: pointer;
    box-shadow: none;
    transition: color 0.18s, border-color 0.18s, background 0.18s, transform 0.18s;
  }
  #overlay #sync-nudge-close:hover,
  #overlay #sync-nudge-close:focus-visible {
    color: var(--text);
    border-color: rgba(255, 255, 255, 0.32);
    background: rgba(255, 255, 255, 0.12);
    transform: scale(1.08);
  }
  /* Entrance: drops from above the sync button with a tiny overshoot. */
  @keyframes sync-nudge-in {
    0%   { opacity: 0; transform: translateY(-18px) scale(0.92); }
    60%  { opacity: 1; transform: translateY(4px)  scale(1.02); }
    100% { opacity: 1; transform: translateY(0)    scale(1); }
  }
  @keyframes sync-nudge-out {
    0%   { opacity: 1; transform: translateY(0)    scale(1); }
    100% { opacity: 0; transform: translateY(-10px) scale(0.94); }
  }
  /* Gentle vertical bob so the pill reads as alive without feeling nervous. */
  @keyframes sync-nudge-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-3px); }
  }
  /* Slow border-glow pulse that loops with the bob — draws the eye to the
     arrow pointing at the sync icon. */
  @keyframes sync-nudge-glow {
    0%, 100% {
      border-color: rgba(126, 226, 255, 0.45);
      box-shadow:
        0 10px 28px rgba(0, 0, 0, 0.45),
        0 0 0 1px rgba(126, 226, 255, 0.12) inset,
        0 0 22px rgba(126, 226, 255, 0.22);
    }
    50% {
      border-color: rgba(170, 238, 255, 0.8);
      box-shadow:
        0 10px 28px rgba(0, 0, 0, 0.5),
        0 0 0 1px rgba(170, 238, 255, 0.22) inset,
        0 0 36px rgba(126, 226, 255, 0.45);
    }
  }
  @media (max-width: 600px) {
    #sync-nudge {
      top: 54px; right: 10px;
      width: min(calc(100vw - 20px), 250px);
    }
    .sync-nudge-arrow { right: 14px; }
  }
  @media (prefers-reduced-motion: reduce) {
    #sync-nudge.visible {
      animation: sync-nudge-in 0.2s ease-out both;
    }
  }

  /* Progress sync modal — same overlay chrome as the relic shop, but with a
     two-section body (export + import) instead of a grid of cards. */
  #progress-sync {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    z-index: 260;  /* above relic-shop so Export/Import can be opened on top */
    background: rgba(6, 8, 18, 0.82);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  #progress-sync.visible { display: flex; }
  #progress-sync-panel {
    width: min(620px, 92vw);
    max-height: 88vh;
    display: flex; flex-direction: column;
    background: linear-gradient(160deg, rgba(30, 36, 60, 0.96), rgba(22, 18, 40, 0.96));
    border: 1px solid rgba(126, 226, 255, 0.25);
    border-radius: 18px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
    overflow: hidden;
  }
  #progress-sync-header {
    display: flex; align-items: center; gap: 18px;
    padding: 18px 22px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  }
  #progress-sync-title { font-size: 20px; font-weight: 800; letter-spacing: 1.2px; color: var(--text); }
  #progress-sync-subtitle { font-size: 12px; color: var(--text-dim); margin-top: 2px; }
  #progress-sync-close {
    margin-left: auto;
    background: none; border: none; color: var(--text-dim);
    font-size: 28px; line-height: 1; cursor: pointer;
    padding: 0 4px; font-family: inherit;
    transition: color 0.15s, transform 0.15s;
  }
  #progress-sync-close:hover { color: var(--text); transform: scale(1.1); }
  #progress-sync-body {
    padding: 18px 22px 22px;
    overflow-y: auto;
    display: flex; flex-direction: column; gap: 20px;
  }
  .sync-section {
    display: flex; flex-direction: column; gap: 10px;
    padding: 14px;
    background: rgba(16, 22, 40, 0.7);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: var(--radius-md);
  }
  .sync-section-head { display: flex; flex-direction: column; gap: 2px; }
  .sync-section-head h3 {
    margin: 0; font-size: 14px; letter-spacing: 1px; font-weight: 800;
    color: #d8f4ff;
  }
  .sync-hint { font-size: 12px; color: var(--text-dim); }
  #progress-sync-export-code,
  #progress-sync-import-code {
    width: 100%;
    resize: vertical;
    padding: 10px 12px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px; line-height: 1.45;
    color: var(--text);
    background: rgba(8, 10, 20, 0.8);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: var(--radius-md);
    word-break: break-all;
    box-sizing: border-box;
  }
  #progress-sync-export-code:focus,
  #progress-sync-import-code:focus {
    outline: none;
    border-color: rgba(126, 226, 255, 0.45);
  }
  .sync-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
  #progress-sync-copy-btn,
  #progress-sync-import-btn {
    background: rgba(126, 226, 255, 0.16);
    color: #d8f4ff;
    border: 1px solid rgba(126, 226, 255, 0.45);
    border-radius: var(--radius-pill);
    padding: 8px 18px; font-size: 12px; font-weight: 700;
    letter-spacing: 0.6px; cursor: pointer;
    font-family: inherit;
    transition: background 0.18s, transform 0.18s;
  }
  #progress-sync-copy-btn:hover,
  #progress-sync-import-btn:hover { background: rgba(126, 226, 255, 0.28); transform: translateY(-1px); }
  .sync-status { font-size: 12px; color: var(--text-dim); }
  .sync-status.ok   { color: #9fe870; }
  .sync-status.warn { color: #ffd36e; }
  .sync-status.err  { color: #ff7a7a; }

  /* Shop modal — full-screen overlay with a grid of upgrade cards. Each
     card shows icon, name, per-tier effect, current tier / max, cost, and a
     BUY button. Disabled states keep the same size so the grid doesn't
     reflow between purchases. */
  #relic-shop {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    z-index: 250;
    background: rgba(6, 8, 18, 0.82);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  #relic-shop.visible { display: flex; }
  #relic-shop-panel {
    width: min(920px, 92vw);
    max-height: 88vh;
    display: flex; flex-direction: column;
    background: linear-gradient(160deg, rgba(30, 36, 60, 0.96), rgba(22, 18, 40, 0.96));
    border: 1px solid rgba(126, 226, 255, 0.25);
    border-radius: 18px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
    overflow: hidden;
  }
  #relic-shop-header {
    display: flex; align-items: center; gap: 18px;
    padding: 18px 22px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  }
  #relic-shop-title { font-size: 22px; font-weight: 800; letter-spacing: 1.2px; color: var(--text); }
  #relic-shop-subtitle { font-size: 12px; color: var(--text-dim); margin-top: 2px; }
  #relic-shop-balance {
    margin-left: auto;
    display: flex; align-items: center; gap: 8px;
    padding: 6px 14px;
    border-radius: var(--radius-pill);
    background: rgba(126, 226, 255, 0.12);
    border: 1px solid rgba(126, 226, 255, 0.35);
    font-weight: 700; font-size: 15px;
    color: #d8f4ff;
  }
  #relic-shop-close {
    background: none; border: none; color: var(--text-dim);
    font-size: 28px; line-height: 1; cursor: pointer;
    padding: 0 4px; font-family: inherit;
    transition: color 0.15s, transform 0.15s;
  }
  #relic-shop-close:hover { color: var(--text); transform: scale(1.1); }
  #relic-shop-grid {
    display: grid; gap: 12px;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    padding: 20px 22px 22px;
    overflow-y: auto;
  }
  .relic-card {
    background: rgba(16, 22, 40, 0.7);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: var(--radius-md);
    padding: 14px 14px 12px;
    display: flex; flex-direction: column; gap: 8px;
    transition: border-color 0.18s, transform 0.18s;
  }
  .relic-card.maxed { border-color: rgba(159, 232, 112, 0.4); }
  .relic-card.affordable:not(.maxed) { border-color: rgba(126, 226, 255, 0.35); }
  .relic-card-head {
    display: flex; align-items: center; gap: 10px;
  }
  .relic-card-icon {
    font-size: 24px; line-height: 1;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.45));
  }
  .relic-card-name { font-weight: 700; font-size: 14px; letter-spacing: 0.3px; color: var(--text); }
  .relic-card-desc { font-size: 11.5px; color: var(--text-dim); line-height: 1.45; }
  .relic-card-tier {
    display: flex; align-items: center; gap: 8px;
    font-size: 11px; color: var(--text-dim); letter-spacing: 0.4px;
  }
  .relic-card-bar {
    flex: 1; height: 4px; border-radius: 2px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
  }
  .relic-card-bar-fill {
    height: 100%;
    background: linear-gradient(90deg, #7ee2ff, #b89bff);
    transition: width 0.25s;
  }
  .relic-card-buy {
    margin-top: auto;
    display: flex; align-items: center; justify-content: space-between;
    padding: 8px 12px;
    background: rgba(126, 226, 255, 0.14);
    color: #d8f4ff;
    border: 1px solid rgba(126, 226, 255, 0.4);
    border-radius: var(--radius-pill);
    font-family: inherit; font-size: 12px; font-weight: 700;
    letter-spacing: 0.5px; cursor: pointer;
    transition: background 0.15s, transform 0.15s;
  }
  .relic-card-buy:hover:not([disabled]) { background: rgba(126, 226, 255, 0.26); transform: translateY(-1px); }
  .relic-card-buy[disabled] { opacity: 0.45; cursor: not-allowed; }
  .relic-card.maxed .relic-card-buy {
    background: rgba(159, 232, 112, 0.14);
    color: #9fe870; border-color: rgba(159, 232, 112, 0.4);
  }
  .relic-card-cost { font-weight: 700; }

  /* Stage picker — 5 cards on the landing screen. Cards wrap to two rows on
     narrow viewports. Selected card pulses the gradient border; locked
     cards dim their contents and show a padlock + the gate-wave hint. */
  #stage-select {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    z-index: 250;
    background: rgba(6, 8, 18, 0.86);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  #stage-select.visible { display: flex; }
  #stage-select.visible #stage-select-panel {
    animation: stageSelectPanelIn 0.42s cubic-bezier(0.34, 1.4, 0.64, 1) both;
  }
  @keyframes stageSelectPanelIn {
    0%   { transform: scale(0.88) translateY(12px); opacity: 0; }
    100% { transform: scale(1) translateY(0);        opacity: 1; }
  }
  #stage-select-panel {
    width: min(1080px, 94vw);
    max-height: 92vh;
    display: flex; flex-direction: column;
    background: linear-gradient(160deg, rgba(30, 36, 60, 0.96), rgba(22, 18, 40, 0.96));
    border: 1px solid rgba(255, 215, 110, 0.25);
    border-radius: 20px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6),
                0 0 120px rgba(184, 155, 255, 0.08);
    overflow: hidden;
  }
  #stage-select-header {
    display: flex; align-items: center; gap: 18px;
    padding: 20px 24px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  }
  #stage-select-title { font-size: 22px; font-weight: 800; letter-spacing: 1.4px; color: var(--text); }
  #stage-select-subtitle { font-size: 12px; color: var(--text-dim); margin-top: 3px; }
  #stage-select-close {
    margin-left: auto;
    background: none; border: none; color: var(--text-dim);
    font-size: 28px; line-height: 1; cursor: pointer;
    padding: 0 4px; font-family: inherit;
    transition: color 0.15s, transform 0.15s;
  }
  #stage-select-close:hover { color: var(--text); transform: scale(1.1); }

  /* First-run tutorial modal. Shown once — between PLAY and stage-select —
     for players with no prior bestRun. Layout is a compact panel with four
     icon+hint rows and one CTA. Desktop and touch copy both live in the DOM;
     body.touch flips which hint is visible so we don't need JS to pick. */
  #tutorial {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    z-index: 260;
    background: rgba(6, 8, 18, 0.86);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  #tutorial.visible { display: flex; }
  #tutorial.visible #tutorial-panel {
    animation: tutorialPanelIn 0.42s cubic-bezier(0.34, 1.4, 0.64, 1) both;
  }
  @keyframes tutorialPanelIn {
    0%   { transform: scale(0.9) translateY(14px); opacity: 0; }
    100% { transform: scale(1) translateY(0);      opacity: 1; }
  }
  #tutorial-panel {
    width: min(520px, 92vw);
    max-height: 92vh;
    padding: 26px 26px 22px;
    background: linear-gradient(160deg, rgba(30, 36, 60, 0.96), rgba(22, 18, 40, 0.96));
    border: 1px solid rgba(184, 155, 255, 0.3);
    border-radius: 18px;
    box-shadow: 0 26px 70px rgba(0, 0, 0, 0.6),
                0 0 100px rgba(184, 155, 255, 0.08);
    overflow-y: auto;
  }
  #tutorial-title {
    font-size: 22px; font-weight: 800; letter-spacing: 1.4px;
    color: var(--text);
    text-align: center;
    margin-bottom: 20px;
  }
  #tutorial-body {
    display: flex; flex-direction: column; gap: 14px;
    margin-bottom: 22px;
  }
  #tutorial .tu-row {
    display: flex; align-items: flex-start; gap: 14px;
    padding: 12px 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 12px;
  }
  #tutorial .tu-icon {
    flex: 0 0 auto;
    width: 38px; height: 38px;
    display: inline-flex; align-items: center; justify-content: center;
    color: #b89bff;
    background: rgba(184, 155, 255, 0.1);
    border: 1px solid rgba(184, 155, 255, 0.25);
    border-radius: 10px;
  }
  #tutorial .tu-text { flex: 1 1 auto; min-width: 0; }
  #tutorial .tu-name {
    font-size: 13px; font-weight: 700;
    color: var(--text);
    letter-spacing: 0.6px;
    text-transform: uppercase;
    margin-bottom: 4px;
  }
  #tutorial .tu-hint {
    font-size: 13px; line-height: 1.45;
    color: var(--text-dim);
  }
  #tutorial .tu-hint b {
    color: var(--text);
    background: rgba(184, 155, 255, 0.14);
    padding: 1px 6px;
    border-radius: 4px;
    font-weight: 700;
  }
  /* Show the desktop copy by default; body.touch flips to the touch copy. */
  #tutorial .tu-touch { display: none; }
  body.touch #tutorial .tu-desktop { display: none; }
  body.touch #tutorial .tu-touch   { display: block; }

  #tutorial-got-it {
    display: block;
    width: 100%;
    padding: 14px 0;
    font-family: inherit; font-size: 15px; font-weight: 800;
    letter-spacing: 1.4px;
    color: #0b0e17;
    background: linear-gradient(135deg, #7ee2ff 0%, #b89bff 100%);
    border: 1.5px solid rgba(255, 255, 255, 0.35);
    border-radius: 12px;
    cursor: pointer;
    box-shadow: 0 10px 28px rgba(126, 226, 255, 0.45);
    transition: transform 0.15s ease, box-shadow 0.2s ease, filter 0.15s ease;
  }
  #tutorial-got-it:hover,
  #tutorial-got-it:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 14px 32px rgba(126, 226, 255, 0.6), 0 0 24px rgba(184, 155, 255, 0.6);
    outline: none;
  }
  #tutorial-got-it:active { transform: translateY(0) scale(0.99); }
  #stage-select-grid {
    display: grid; gap: 16px;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    padding: 22px 24px 26px;
    overflow-y: auto;
  }
  /* Hero card — desktop: media (image + lock/CTA) on top, footer (name + diff)
     below. Unlocked images render at full colour; locked images are greyscaled
     so the lock affordance reads clearly without an extra dark gradient.
     Mobile (≤520px): card flips to a compact horizontal row with a small
     thumbnail on the left and text + CTA on the right. */
  .stage-hero-card {
    position: relative;
    display: block;
    border-radius: 14px;
    overflow: hidden;
    cursor: pointer;
    background: #111622;
    border: 1px solid rgba(255, 255, 255, 0.08);
    padding: 0;
    font-family: inherit;
    color: var(--text);
    transition: transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),
                border-color 0.2s, box-shadow 0.25s;
    -webkit-tap-highlight-color: transparent;
    /* Staggered entrance — --stage-card-i is set per-card in JS. */
    opacity: 0;
    animation: stageCardIn 0.42s cubic-bezier(0.34, 1.4, 0.64, 1) forwards;
    animation-delay: calc(180ms + var(--stage-card-i, 0) * 55ms);
  }
  @keyframes stageCardIn {
    0%   { opacity: 0; transform: translateY(18px) scale(0.96); }
    100% { opacity: 1; transform: translateY(0)     scale(1);    }
  }
  /* Newest-unlock border — set by renderStageSelect on the highest unlocked
     card. Layered effect: ::before is a blurred conic-gradient aura behind
     the card (big halo), and the card itself paints a sharp conic-gradient
     border via padding-box/border-box compositing. Both gradients share the
     same --stage-card-angle and spin together so the "moving light" reads
     as one continuous sweep with a soft bleed. Browsers without @property
     support still see the same gradient, just static. */
  @property --stage-card-angle {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
  }
  .stage-hero-card.is-newest {
    --stage-card-angle: 0deg;
    border: 3px solid transparent;
    background:
      linear-gradient(#111622, #111622) padding-box,
      conic-gradient(from var(--stage-card-angle),
        #7ee2ff 0deg,
        #ffd36e 90deg,
        #ff9ec4 180deg,
        #b89bff 270deg,
        #7ee2ff 360deg) border-box;
    /* Layered ambient glow. Can't use a blurred pseudo-element behind the
       card because the card sets overflow:hidden for its image clip — the
       pseudo would be cropped. Stacked box-shadows aren't clipped by
       overflow so they're the cheapest way to make the card feel lit. */
    box-shadow: 0 0 18px rgba(126, 226, 255, 0.55),
                0 0 36px rgba(255, 215, 110, 0.35),
                0 0 64px rgba(184, 155, 255, 0.28);
    animation: stageCardIn 0.42s cubic-bezier(0.34, 1.4, 0.64, 1) forwards,
               stageCardBorderSpin 3.6s linear infinite;
  }
  @keyframes stageCardBorderSpin {
    to { --stage-card-angle: 360deg; }
  }
  .stage-hero-card .stage-hero-badge {
    position: absolute; top: 10px; left: 10px;
    padding: 4px 10px;
    border-radius: var(--radius-pill);
    background: linear-gradient(135deg, #ffd36e, #7ee2ff);
    color: #1a1530;
    font-size: 10px; font-weight: 800; letter-spacing: 1.4px;
    box-shadow: 0 6px 18px rgba(126, 226, 255, 0.35);
    pointer-events: none;
  }
  .stage-hero-card .stage-hero-media {
    position: relative;
    aspect-ratio: 16 / 10;
    overflow: hidden;
  }
  .stage-hero-card .stage-hero-image {
    position: absolute; inset: 0;
    background-size: cover; background-position: center bottom;
    transition: transform 0.45s ease, filter 0.25s;
  }
  /* Name + difficulty overlay over the image — absolute-positioned against the
     card (not the media) so the dark scrim paints over the bottom of the
     thumbnail without any separate body block that could be clipped by the
     grid's row track. */
  .stage-hero-card .stage-hero-body {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 22px 16px 14px;
    display: flex; flex-direction: column; gap: 3px;
    text-align: left;
    background: linear-gradient(180deg,
      rgba(10, 8, 22, 0) 0%,
      rgba(10, 8, 22, 0.55) 45%,
      rgba(6, 4, 14, 0.92) 100%);
    pointer-events: none;
  }
  .stage-hero-card .stage-hero-name {
    font-size: 17px; font-weight: 800; letter-spacing: 0.6px; color: #ffffff;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.65);
  }
  .stage-hero-card .stage-hero-diff {
    font-size: 10.5px; letter-spacing: 1px; color: #ffd36e;
    font-weight: 700; text-transform: uppercase;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    text-shadow: 0 1px 4px rgba(0, 0, 0, 0.7);
  }
  .stage-hero-card.locked .stage-hero-diff {
    color: rgba(216, 208, 184, 0.75);
    text-transform: none; letter-spacing: 0.3px; font-weight: 600;
  }
  .stage-hero-card .stage-hero-cta {
    position: absolute; top: 12px; right: 12px;
    padding: 6px 13px;
    border-radius: var(--radius-pill);
    background: rgba(10, 14, 30, 0.78);
    backdrop-filter: blur(6px);
    border: 1px solid rgba(255, 215, 110, 0.55);
    color: #ffd36e;
    font-size: 11px; font-weight: 800; letter-spacing: 1.2px;
    transition: background 0.15s, transform 0.15s;
  }
  .stage-hero-card:hover:not(.locked) { transform: translateY(-3px); border-color: rgba(255, 215, 110, 0.55); box-shadow: 0 14px 34px rgba(255, 155, 196, 0.24); }
  /* Newest card keeps its transparent border on hover so the gradient ring
     stays visible; hover layers additional lift onto the ambient glow. */
  .stage-hero-card.is-newest:hover:not(.locked) {
    border-color: transparent;
    box-shadow: 0 14px 34px rgba(255, 155, 196, 0.28),
                0 0 24px rgba(126, 226, 255, 0.7),
                0 0 48px rgba(255, 215, 110, 0.45),
                0 0 72px rgba(184, 155, 255, 0.32);
  }
  .stage-hero-card:hover:not(.locked) .stage-hero-image { transform: scale(1.05); }
  .stage-hero-card:hover:not(.locked) .stage-hero-cta { background: linear-gradient(135deg, #ffd36e, #ff9ec4 55%, #b89bff); color: #1a1530; border-color: transparent; }
  .stage-hero-card.locked { cursor: not-allowed; }
  .stage-hero-card.locked .stage-hero-image { filter: grayscale(0.85) brightness(0.35); }
  .stage-hero-card.locked .stage-hero-cta { display: none; }
  .stage-hero-card .stage-hero-lock {
    position: absolute; inset: 0;
    display: none;
    align-items: center; justify-content: center;
    color: #d8d0b8;
  }
  .stage-hero-card.locked .stage-hero-lock { display: flex; }
  .stage-hero-card .stage-hero-lock svg {
    width: 30px; height: 30px; opacity: 0.85;
    filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.6));
  }
  /* "Coming soon" placeholder cards — same shape as a locked stage card but
     with a subtle animated aurora instead of a stage thumbnail so it reads as
     a teaser rather than a grayed-out stage the player could have unlocked. */
  .stage-hero-card.coming-soon { cursor: not-allowed; }
  .stage-hero-card.coming-soon .stage-hero-image {
    background: linear-gradient(135deg, #2a1a4a 0%, #3a2060 50%, #4a2870 100%);
    filter: none; opacity: 0.95;
  }
  .stage-hero-card.coming-soon .stage-hero-media::after {
    content: '';
    position: absolute; inset: 0;
    background:
      radial-gradient(ellipse 55% 40% at 30% 30%, rgba(126, 226, 255, 0.28), transparent 70%),
      radial-gradient(ellipse 50% 35% at 70% 70%, rgba(255, 158, 196, 0.22), transparent 70%);
    mix-blend-mode: screen;
    animation: comingSoonAurora 6s ease-in-out infinite alternate;
    pointer-events: none;
  }
  @keyframes comingSoonAurora {
    0%   { transform: translate(-4%, -2%) scale(1.02); }
    100% { transform: translate(4%,  2%) scale(1.08); }
  }
  .stage-hero-card.coming-soon .stage-hero-lock { display: none; }
  .stage-hero-card.coming-soon .stage-hero-cta { display: none; }
  .stage-hero-card.coming-soon .stage-hero-name { color: #d6c7ff; }
  .stage-hero-card.coming-soon .stage-hero-diff {
    color: #7ee2ff; font-weight: 700; letter-spacing: 0.6px; text-transform: uppercase;
  }
  .stage-hero-card.coming-soon .stage-hero-badge {
    background: rgba(126, 226, 255, 0.18); color: #7ee2ff;
    border: 1px solid rgba(126, 226, 255, 0.55);
  }
  .stage-hero-card.coming-soon:hover {
    transform: none;
    border-color: rgba(126, 226, 255, 0.35);
    box-shadow: 0 6px 18px rgba(126, 226, 255, 0.12);
  }

  @media (max-width: 520px) {
    #stage-select-panel {
      width: 100vw; height: 100vh; height: 100dvh;
      max-height: 100vh; max-height: 100dvh;
      border-radius: 0; border: none;
    }
    #stage-select-header { padding: 14px 18px 10px; }
    #stage-select-title { font-size: 17px; }
    #stage-select-subtitle { font-size: 11px; }
    /* Flex column (not grid) on mobile so rows size to content — avoids the
       grid's default row stretching when the panel fills the viewport. */
    #stage-select-grid {
      display: flex; flex-direction: column;
      grid-template-columns: none;
      gap: 8px;
      padding: 10px 14px 18px;
      flex: 1 1 auto; min-height: 0; overflow-y: auto;
    }

    /* Compact row: fixed-size thumbnail on the left, body fills the rest.
       Lock/CTA stay absolute-positioned against the card — in the row layout
       they read as "right side of the row". */
    .stage-hero-card {
      display: flex; flex-direction: row; align-items: stretch;
      border-radius: 10px;
      flex-shrink: 0;
    }
    .stage-hero-card .stage-hero-media {
      width: 96px; aspect-ratio: 4 / 3;
      flex-shrink: 0;
    }
    .stage-hero-card .stage-hero-body {
      position: static;
      padding: 10px 64px 10px 14px; /* right padding reserves space for CTA/lock */
      justify-content: center;
      border-top: none;
      background: linear-gradient(90deg, rgba(28, 24, 52, 0.95), rgba(18, 16, 36, 0.98));
      flex: 1 1 auto; min-width: 0;
    }
    .stage-hero-card .stage-hero-name { font-size: 14.5px; }
    .stage-hero-card .stage-hero-diff { font-size: 10.5px; }
    .stage-hero-card .stage-hero-cta {
      top: 50%; right: 12px; transform: translateY(-50%);
      padding: 6px 13px; font-size: 10.5px;
      background: linear-gradient(135deg, #ffd36e, #ff9ec4 55%, #b89bff);
      color: #1a1530;
      border-color: transparent;
    }
    .stage-hero-card:hover:not(.locked) { transform: none; }
    .stage-hero-card:hover:not(.locked) .stage-hero-image { transform: none; }
    .stage-hero-card .stage-hero-lock svg { width: 22px; height: 22px; }
  }

  /* Touch-only warning — becomes visible via JS detection */
  #requirements.unsupported {
    border-color: rgba(255, 168, 102, 0.55);
    background: linear-gradient(145deg, rgba(80, 40, 30, 0.85), rgba(40, 22, 30, 0.85));
  }
  #touch-warning {
    margin-top: 16px;
    color: var(--amber);
    font-size: 13px; max-width: 360px; line-height: 1.5;
    font-weight: 500;
  }
  #overlay button, #gameover button {
    color: #1a1530; border: none; border-radius: var(--radius-pill);
    padding: 15px 44px; font-size: 16px; cursor: pointer;
    font-family: inherit; letter-spacing: 0.5px; font-weight: 700;
    transition: transform 0.2s cubic-bezier(0.2, 0.8, 0.2, 1),
                box-shadow 0.25s;
  }
  #overlay button {
    background: linear-gradient(135deg, #ffd36e, #ff9ec4 55%, #b89bff);
    box-shadow: 0 8px 26px rgba(184, 155, 255, 0.35);
  }
  #overlay button:hover, #overlay button:focus-visible {
    transform: translateY(-2px) scale(1.02);
    box-shadow: 0 12px 34px rgba(184, 155, 255, 0.5);
    outline: none;
  }

  #gameover {
    position: fixed; top: 0; left: 0; width: 100%; height: 100%;
    background: radial-gradient(ellipse at center, rgba(80, 30, 50, 0.9), rgba(14, 18, 34, 0.96));
    display: none; flex-direction: column;
    align-items: center; justify-content: center; z-index: 200;
    overflow: hidden;
    opacity: 0;
  }
  /* Survived (victory) — gold/green radial with a nebula shimmer. */
  #gameover.survived {
    background:
      radial-gradient(ellipse at center, rgba(255, 211, 110, 0.18), transparent 55%),
      radial-gradient(ellipse at 40% 30%, rgba(159, 232, 112, 0.20), transparent 50%),
      radial-gradient(ellipse at center, rgba(28, 38, 30, 0.92), rgba(10, 14, 22, 0.96));
  }
  /* Defeated — crimson-on-black with a subtle vignette. */
  #gameover.defeated {
    background:
      radial-gradient(ellipse at center, rgba(255, 60, 80, 0.14), transparent 50%),
      radial-gradient(ellipse at center, rgba(60, 20, 28, 0.94), rgba(10, 14, 22, 0.98));
  }
  /* One-shot container reveal — scale-pop for victory, impact-shake for loss.
     Each child block gets its own delay so the reveal cascades top-down:
     title → hero score → stat chips → earned row → CTAs → secondary links. */
  #gameover.revealing { animation: goFadeIn 280ms ease-out forwards; }
  #gameover.survived.revealing > h1,
  #gameover.survived.revealing > #gameover-hero,
  #gameover.survived.revealing > #gameover-stats,
  #gameover.survived.revealing > #gameover-earned,
  #gameover.survived.revealing > #gameover-card-preview,
  #gameover.survived.revealing > #gameover-actions,
  #gameover.survived.revealing > #gameover-secondary { animation-name: goChildPopIn; }
  #gameover.defeated.revealing > h1 { animation: goTitleSlam 620ms cubic-bezier(0.3, 0.1, 0.2, 1) both; }
  #gameover.defeated.revealing > #gameover-hero,
  #gameover.defeated.revealing > #gameover-stats,
  #gameover.defeated.revealing > #gameover-earned,
  #gameover.defeated.revealing > #gameover-card-preview,
  #gameover.defeated.revealing > #gameover-actions,
  #gameover.defeated.revealing > #gameover-secondary { animation-name: goChildFadeUp; }
  #gameover.revealing > h1                       { animation-duration: 620ms; animation-fill-mode: both; }
  #gameover.revealing > #gameover-hero           { animation-duration: 560ms; animation-fill-mode: both; animation-delay: 180ms; }
  #gameover.revealing > #gameover-stats          { animation-duration: 520ms; animation-fill-mode: both; animation-delay: 320ms; }
  #gameover.revealing > #gameover-earned         { animation-duration: 500ms; animation-fill-mode: both; animation-delay: 440ms; }
  #gameover.revealing > #gameover-card-preview   { animation-duration: 520ms; animation-fill-mode: both; animation-delay: 560ms; }
  #gameover.revealing > #gameover-actions        { animation-duration: 520ms; animation-fill-mode: both; animation-delay: 720ms; }
  #gameover.revealing > #gameover-secondary      { animation-duration: 480ms; animation-fill-mode: both; animation-delay: 860ms; }

  @keyframes goFadeIn   { from { opacity: 0; } to { opacity: 1; } }
  @keyframes goChildPopIn {
    0%   { opacity: 0; transform: translateY(22px) scale(0.82); }
    60%  { opacity: 1; transform: translateY(-4px) scale(1.06); }
    100% { opacity: 1; transform: translateY(0)    scale(1);    }
  }
  @keyframes goChildFadeUp {
    0%   { opacity: 0; transform: translateY(14px); }
    100% { opacity: 1; transform: translateY(0);    }
  }
  @keyframes goTitleSlam {
    0%   { opacity: 0; transform: scale(1.8); letter-spacing: 14px; filter: blur(6px); }
    55%  { opacity: 1; transform: scale(0.96); letter-spacing: 0px;  filter: blur(0);    }
    62%  { transform: translateX(-8px); }
    68%  { transform: translateX(8px);  }
    74%  { transform: translateX(-4px); }
    80%  { transform: translateX(4px);  }
    100% { transform: scale(1) translateX(0); filter: blur(0); }
  }
  /* Keep content above the confetti layer (position:absolute shards). */
  #gameover > h1,
  #gameover > #gameover-hero,
  #gameover > #gameover-stats,
  #gameover > #gameover-earned,
  #gameover > #gameover-card-preview,
  #gameover > #gameover-actions,
  #gameover > #gameover-secondary { position: relative; z-index: 2; }

  /* Auto-rendered share-card preview slot. Sits between the earned row and
     the action buttons — the player sees the artifact they can share before
     they see SHARE/PLAY AGAIN. Fixed aspect ratio matches the 1200×630 the
     card is rendered at so the card never distorts when the image resolves.
     Empty state collapses; filled state constrains by width. */
  #gameover-card-preview {
    width: min(420px, 80vw);
    aspect-ratio: 1200 / 630;
    margin: 0 auto 18px;
    border-radius: 14px;
    overflow: hidden;
    background: rgba(12, 16, 32, 0.55);
    border: 1px solid rgba(184, 155, 255, 0.22);
    box-shadow: 0 18px 44px rgba(10, 12, 26, 0.6), inset 0 1px 0 rgba(255, 255, 255, 0.08);
    display: none;
  }
  #gameover-card-preview.has-card,
  #gameover-card-preview.rendering { display: block; }
  #gameover-card-preview img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 320ms ease-out;
  }
  #gameover-card-preview.has-card img { opacity: 1; }
  /* Shimmer placeholder while the canvas renders. */
  #gameover-card-preview.rendering:not(.has-card) {
    background:
      linear-gradient(110deg,
        rgba(184, 155, 255, 0.06) 0%,
        rgba(184, 155, 255, 0.18) 45%,
        rgba(184, 155, 255, 0.06) 70%) 0 0 / 220% 100% no-repeat,
      rgba(12, 16, 32, 0.55);
    animation: cardPreviewShimmer 1.2s linear infinite;
  }
  @keyframes cardPreviewShimmer {
    from { background-position: 120% 0, 0 0; }
    to   { background-position: -20% 0,  0 0; }
  }
  @media (prefers-reduced-motion: reduce) {
    #gameover-card-preview.rendering:not(.has-card) { animation: none; }
    #gameover-card-preview img { transition: none; }
  }
  #gameover h1 {
    font-size: 60px; margin-bottom: 18px; font-weight: 800; letter-spacing: 1px;
    background: linear-gradient(120deg, #ff8a8a, #ffa866);
    -webkit-background-clip: text; background-clip: text; color: transparent;
  }
  #gameover.survived h1 {
    background: linear-gradient(120deg, #ffd36e, #9fe870 55%, #7ee2ff);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    filter: drop-shadow(0 6px 28px rgba(255, 211, 110, 0.5));
  }
  #gameover.defeated h1 {
    background: linear-gradient(120deg, #ff6b6b, #ff9e7a);
    -webkit-background-clip: text; background-clip: text; color: transparent;
    filter: drop-shadow(0 4px 22px rgba(255, 60, 80, 0.45));
  }
  /* Hero — single big score right under the title. The score is the one
     saturated number on the card; every other stat is neutral-text dim. */
  #gameover-hero {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    margin: 0 0 20px;
  }
  #gameover-hero .go-score-label {
    font-size: 10.5px; letter-spacing: 2.4px; text-transform: uppercase;
    color: var(--text-dim);
  }
  #gameover-hero .go-score {
    font-size: 64px; font-weight: 800; letter-spacing: 0.5px;
    line-height: 1; font-variant-numeric: tabular-nums;
    color: #ffd36e;
    filter: drop-shadow(0 6px 26px rgba(255, 211, 110, 0.32));
  }
  #gameover.defeated #gameover-hero .go-score {
    color: #ffa866;
    filter: drop-shadow(0 6px 26px rgba(255, 138, 138, 0.32));
  }
  #gameover-hero .go-badges {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
    margin-top: 4px;
  }
  /* #gameover scoping beats the blanket `#gameover button { ... }` rule so
     the badges don't inherit the PLAY AGAIN gradient / padding / font-size. */
  #gameover .go-badge {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 12px; border-radius: var(--radius-pill);
    font-family: inherit;
    font-size: 11px; font-weight: 800; letter-spacing: 1.3px;
    color: var(--text-dim);
    background: rgba(36, 22, 48, 0.44);
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: none;
    /* Button-cancel: undo the blanket #gameover button transform/hover. */
    transform: none;
  }
  #gameover .go-badge.best {
    color: #ffd36e;
    border-color: rgba(255, 211, 110, 0.55);
    background: rgba(60, 44, 14, 0.55);
  }
  #gameover button.go-badge.rank {
    color: #d1aeff;
    border-color: rgba(209, 174, 255, 0.45);
    background: rgba(48, 30, 64, 0.55);
    cursor: pointer;
    transition: background 0.18s, border-color 0.18s, transform 0.18s;
  }
  #gameover button.go-badge.rank:hover,
  #gameover button.go-badge.rank:focus-visible {
    background: rgba(68, 46, 88, 0.7);
    border-color: rgba(209, 174, 255, 0.8);
    transform: translateY(-1px);
    box-shadow: none;
    outline: none;
  }
  /* Ensure [hidden] wins against any other rule (defensive — the blanket
     #gameover button styling has burned us on similar overrides before). */
  #gameover .go-badge[hidden] { display: none; }
  /* Hide the whole badges row when it has no visible children so it doesn't
     eat vertical space. Uses :has() where available, harmless otherwise. */
  #gameover-hero .go-badges:not(:has(> :not([hidden]))) { display: none; }

  /* Chip strip — three compact stats (Wave / Kills / Time) stacked as
     label-under-value. Overrides the previous text-block styling of
     #gameover-stats. */
  #gameover-stats {
    color: var(--text-dim); margin: 0 0 16px;
    text-align: center; line-height: 1.2;
  }
  .go-stat-strip {
    display: flex; justify-content: center; gap: 24px; flex-wrap: wrap;
  }
  .go-chip {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    min-width: 64px;
  }
  .go-chip .go-chip-v {
    font-size: 22px; font-weight: 700; color: var(--text);
    font-variant-numeric: tabular-nums; line-height: 1;
  }
  .go-chip .go-chip-l {
    font-size: 10px; letter-spacing: 1.8px; text-transform: uppercase;
    color: var(--text-dim);
  }

  /* Earned meta — quiet single row: LVL, combo (≥3 only), relics/prev-best. */
  #gameover-earned {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 14px;
    font-size: 12px; letter-spacing: 0.5px; color: var(--text-dim);
    margin: 0 0 24px;
  }
  #gameover-earned:empty { display: none; }
  #gameover-earned .go-earned-relic { color: #7ee2ff; font-weight: 700; }
  #gameover-earned .go-earned-combo { color: #ffd36e; font-weight: 700; }

  #gameover button {
    background: linear-gradient(135deg, #ff8a8a, #ffa866);
    color: #2a1010;
    box-shadow: 0 8px 26px rgba(255, 138, 138, 0.35);
  }
  #gameover button:hover, #gameover button:focus-visible {
    transform: translateY(-2px) scale(1.02);
    box-shadow: 0 12px 34px rgba(255, 138, 138, 0.5);
    outline: none;
  }
  /* PLAY AGAIN is demoted to a ghost button — translucent fill, bordered in
     the survived/defeated accent colour. Keeps it obviously clickable without
     competing with SHARE for attention. */
  #gameover #restart-btn {
    background: rgba(255, 168, 102, 0.08) !important;
    color: #ffc9a8 !important;
    border: 1.5px solid rgba(255, 138, 138, 0.55) !important;
    box-shadow: none !important;
  }
  #gameover #restart-btn:hover,
  #gameover #restart-btn:focus-visible {
    background: rgba(255, 168, 102, 0.16) !important;
    border-color: rgba(255, 138, 138, 0.85) !important;
  }
  #gameover.survived #restart-btn {
    background: rgba(159, 232, 112, 0.08) !important;
    color: #c4eea8 !important;
    border: 1.5px solid rgba(159, 232, 112, 0.55) !important;
    box-shadow: none !important;
  }
  #gameover.survived #restart-btn:hover,
  #gameover.survived #restart-btn:focus-visible {
    background: rgba(159, 232, 112, 0.16) !important;
    border-color: rgba(159, 232, 112, 0.85) !important;
  }
  /* Primary CTAs — SHARE (solid) + PLAY AGAIN (ghost), equal width, side by
     side. SHARE leads visually so the social loop is the loud call. On mobile
     they stack vertically and SHARE sits on top. */
  #gameover-actions {
    display: flex; gap: 24px; flex-wrap: wrap; justify-content: center;
    width: min(440px, 92vw); margin: 0 auto 14px;
    position: relative; z-index: 2;
  }
  #gameover-actions > button {
    flex: 1 1 160px; min-width: 150px;
    display: inline-flex; align-items: center; justify-content: center;
    gap: 8px;
  }

  /* Secondary row — text-only links for View Rankings + Title Screen. Demoted
     from full buttons so they recede behind the two primary CTAs. */
  #gameover-secondary {
    display: flex; justify-content: center; gap: 18px; flex-wrap: wrap;
  }
  #gameover-secondary button {
    background: transparent !important;
    border: none !important;
    color: var(--text-dim) !important;
    font-size: 12px; font-weight: 600; letter-spacing: 0.8px;
    padding: 6px 10px !important;
    box-shadow: none !important;
    cursor: pointer;
    transition: color 0.15s ease;
  }
  #gameover-secondary button:hover,
  #gameover-secondary button:focus-visible {
    color: #d1aeff !important;
    transform: none !important;
    box-shadow: none !important;
    outline: none;
  }

  /* SHARE button on game-over. Primary CTA — solid gradient, pulsing aura,
     stronger shadow than PLAY AGAIN (which is a ghost) so the visual weight
     unambiguously favours the social loop. The .busy state dims the button
     while navigator.share is open, and .share-flash is a transient "SHARED"
     pill that fades in when the share resolves OK. */
  #share-run-btn {
    position: relative; overflow: visible;
    background: linear-gradient(135deg, #7ee2ff 0%, #b89bff 100%) !important;
    color: #0b0e17 !important;
    border: 1.5px solid rgba(255, 255, 255, 0.4) !important;
    box-shadow: 0 10px 30px rgba(126, 226, 255, 0.5), 0 0 0 0 rgba(126, 226, 255, 0);
    font-weight: 800;
    letter-spacing: 0.8px;
    transition: transform 0.15s ease, box-shadow 0.25s ease, filter 0.15s ease;
    animation: shareIdlePulse 2.4s ease-in-out infinite;
  }
  #share-run-btn:hover,
  #share-run-btn:focus-visible {
    transform: translateY(-1px);
    box-shadow: 0 12px 36px rgba(126, 226, 255, 0.65), 0 0 28px rgba(184, 155, 255, 0.7);
  }
  #share-run-btn.busy { filter: saturate(0.85) brightness(0.95); pointer-events: none; animation: none; }
  #share-run-btn .share-btn-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 20px; height: 20px; color: currentColor;
  }
  /* Busy/idle label swap — the button always reserves the idle label's space
     (so it doesn't collapse while rendering), and CSS toggles which label is
     visible based on .busy. Keeps a single button box without layout thrash. */
  #share-run-btn .share-btn-content,
  #share-run-btn .share-btn-busy {
    display: inline-flex; align-items: center; justify-content: center;
    gap: 8px;
  }
  #share-run-btn .share-btn-busy { display: none; }
  #share-run-btn.busy .share-btn-content { display: none; }
  #share-run-btn.busy .share-btn-busy { display: inline-flex; }
  #share-run-btn .share-btn-spinner {
    width: 14px; height: 14px; border-radius: 50%;
    border: 2px solid rgba(11, 14, 23, 0.25);
    border-top-color: #0b0e17;
    animation: shareBtnSpin 0.75s linear infinite;
  }
  @keyframes shareBtnSpin { to { transform: rotate(360deg); } }
  .share-flash {
    position: absolute; left: 50%; top: -14px;
    transform: translate(-50%, -4px);
    font-size: 11px; font-weight: 700; letter-spacing: 1.2px;
    color: #0b0e17;
    background: #ffd36e;
    padding: 3px 10px; border-radius: 999px;
    box-shadow: 0 4px 12px rgba(255, 211, 110, 0.55);
    animation: shareFlashIn 1.6s ease forwards;
    pointer-events: none;
  }
  @keyframes shareIdlePulse {
    0%, 100% { box-shadow: 0 10px 30px rgba(126, 226, 255, 0.5),  0 0 0 0 rgba(126, 226, 255, 0); }
    50%      { box-shadow: 0 10px 30px rgba(126, 226, 255, 0.62), 0 0 0 8px rgba(126, 226, 255, 0.18); }
  }
  @keyframes shareFlashIn {
    0%   { opacity: 0; transform: translate(-50%, 4px); }
    15%  { opacity: 1; transform: translate(-50%, -14px); }
    80%  { opacity: 1; transform: translate(-50%, -14px); }
    100% { opacity: 0; transform: translate(-50%, -22px); }
  }

  /* Taunt banner — rendered on the landing page when ?s=… query params are
     present (shared-run link). Floats over the top of the landing overlay
     and dismisses either via the × button or by clicking PLAY. */
  #taunt-banner {
    position: fixed; top: 16px; left: 50%;
    transform: translate(-50%, -110%);
    max-width: min(540px, 92vw);
    padding: 10px 16px 10px 20px;
    background: linear-gradient(135deg, rgba(126, 226, 255, 0.18), rgba(184, 155, 255, 0.18));
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 14px;
    box-shadow: 0 10px 30px rgba(10, 14, 30, 0.55);
    color: #e8ecff;
    font-size: 14px;
    letter-spacing: 0.2px;
    z-index: 250;
    transition: transform 0.42s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.32s ease;
    opacity: 0;
  }
  #taunt-banner.visible { transform: translate(-50%, 0); opacity: 1; }
  #taunt-banner.hiding  { transform: translate(-50%, -110%); opacity: 0; }
  #taunt-banner .taunt-inner {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  }
  #taunt-banner .taunt-who   { font-weight: 700; color: #ffd36e; }
  #taunt-banner .taunt-score { color: #7ee2ff; font-variant-numeric: tabular-nums; }
  #taunt-banner .taunt-stage { color: #b89bff; }
  #taunt-banner .taunt-cta   { color: #9fe870; font-weight: 700; margin-left: 4px; }
  #taunt-banner .taunt-dismiss {
    margin-left: auto;
    background: transparent; border: none; color: #808a9d;
    font-size: 20px; line-height: 1; width: 24px; height: 24px;
    cursor: pointer; padding: 0;
    transition: color 0.15s ease;
  }
  #taunt-banner .taunt-dismiss:hover { color: #fff; }
  @media (max-width: 520px) {
    #taunt-banner { top: 10px; font-size: 13px; padding: 9px 12px 9px 14px; }
    #taunt-banner .taunt-inner { gap: 6px; }
  }

  /* Victory confetti — spawned by _spawnVictoryConfetti. Purely decorative,
     pointer-events disabled so clicks still pass through to the buttons. */
  .gameover-confetti {
    position: absolute; top: -28px;
    width: 10px; height: 14px; border-radius: 2px;
    opacity: 0.9; pointer-events: none; z-index: 1;
    animation-name: confettiFall;
    animation-timing-function: cubic-bezier(0.3, 0.7, 0.4, 1);
    animation-fill-mode: forwards;
    will-change: transform, opacity;
  }
  @keyframes confettiFall {
    0%   { transform: translateY(-12vh) rotate(0deg);  opacity: 0; }
    12%  { opacity: 0.95; }
    100% { transform: translateY(112vh) rotate(720deg); opacity: 0; }
  }

  #minimap {
    position: fixed; bottom: 84px; right: 22px;
    width: 128px; height: 128px;
    background: rgba(18, 24, 44, 0.55);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--card-border);
    border-radius: var(--radius-lg); overflow: hidden; pointer-events: none;
    box-shadow: 0 4px 18px rgba(10, 14, 30, 0.35);
  }
  #minimap canvas { width: 100%; height: 100%; }

  .active-pu {
    display: grid;
    grid-template-columns: 1fr auto auto;
    align-items: baseline;
    gap: 10px;
    min-width: 180px;
    background: var(--card-bg);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border: 1px solid rgba(184, 155, 255, 0.35);
    border-radius: var(--radius-pill);
    padding: 5px 14px; color: var(--lilac);
    font-size: 11.5px; font-weight: 600; letter-spacing: 0.4px;
    text-align: left;
  }
  .active-pu .pu-label { color: rgba(230, 224, 255, 0.7); font-weight: 500; text-transform: uppercase; font-size: 10px; letter-spacing: 0.8px; }
  .active-pu .pu-val   { color: var(--lilac); }
  .active-pu .pu-n     { color: rgba(184, 155, 255, 0.65); font-size: 10.5px; }
  .active-pu.maxed {
    border-color: rgba(255, 215, 0, 0.65);
    background: rgba(255, 215, 0, 0.08);
  }
  .active-pu.maxed .pu-label { color: rgba(255, 215, 0, 0.75); }
  .active-pu.maxed .pu-val,
  .active-pu.maxed .pu-n { color: #ffd700; }

  /* Pause — sits in the ability bar alongside Dash / Overdrive / Shield.
     Clickable even on desktop (overrides #ability-bar's pointer-events:none). */
  #pause-btn {
    pointer-events: auto;
    cursor: pointer;
    touch-action: manipulation;
    transition: background 0.15s, border-color 0.15s, transform 0.08s;
    display: none;
    font: inherit;
  }
  #pause-btn:hover  { background: rgba(255,255,255,0.06); border-color: rgba(184, 155, 255, 0.6); }
  #pause-btn:active { transform: scale(0.96); }
  body.playing #pause-btn { display: flex; }

  /* Pause-screen controls panel — replaces the always-on #controls-hint */
  #pause-controls {
    margin: 0 -4px 18px;
    padding: 12px 14px;
    background: rgba(10, 14, 30, 0.35);
    border: 1px solid rgba(184, 155, 255, 0.2);
    border-radius: var(--radius-md);
    color: rgba(246, 248, 254, 0.82);
    font-size: 12px; line-height: 1.7; text-align: left;
  }
  #pause-controls .pc-title {
    text-transform: uppercase; letter-spacing: 1.2px;
    font-size: 10px; color: rgba(246, 248, 254, 0.55);
    margin-bottom: 6px;
  }
  #pause-controls kbd {
    display: inline-block; padding: 1px 6px; margin: 0 2px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(184, 155, 255, 0.3);
    border-radius: 4px; font-family: inherit; font-size: 11px;
    color: var(--lilac);
  }
  .pc-desktop { display: block; }
  .pc-touch   { display: none; }
  body.touch .pc-desktop { display: none; }
  body.touch .pc-touch   { display: block; }

  /* Stage loading overlay — shown during the synchronous teardown + rebuild
     of setSelectedStage / restartGame. Uses z-index above every other overlay
     so it covers the old scene while the new one builds. z-index must beat
     the landing #overlay (200), leaderboard modals (270), and the progress-
     sync card (280) — this loader is the topmost thing in the app. */
  #stage-loading {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    background: rgba(6, 4, 20, 0.88);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
    z-index: 9999;
    padding: 24px;
  }
  #stage-loading.visible { display: flex; }
  #stage-loading .sl-card {
    max-width: 340px; width: 100%;
    background: rgba(20, 18, 46, 0.9);
    border: 1px solid rgba(184, 155, 255, 0.35);
    border-radius: 18px;
    padding: 30px 28px;
    color: var(--lilac);
    text-align: center;
    display: flex; flex-direction: column; align-items: center; gap: 14px;
  }
  #stage-loading .sl-spinner {
    width: 44px; height: 44px; border-radius: 50%;
    border: 3px solid rgba(184, 155, 255, 0.25);
    border-top-color: var(--lilac);
    animation: sl-spin 0.9s linear infinite;
  }
  @keyframes sl-spin { to { transform: rotate(360deg); } }
  #stage-loading .sl-title {
    font-size: 11px; letter-spacing: 2.2px;
    text-transform: uppercase;
    color: rgba(246, 248, 254, 0.62);
  }
  #stage-loading .sl-stage {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 22px; font-weight: 800;
    letter-spacing: 1.2px;
    color: #f6f8fe;
  }

  /* Pause overlay — PAUSED card with acquired powerups */
  #pause-screen {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    background: rgba(8, 6, 24, 0.82);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    z-index: 90;
    padding: 24px;
  }
  #pause-screen.visible { display: flex; }
  #pause-screen .pause-card {
    max-width: 400px; width: 100%;
    max-height: 82vh; overflow-y: auto;
    background: rgba(20, 18, 46, 0.82);
    border: 1px solid rgba(184, 155, 255, 0.35);
    border-radius: 18px;
    padding: 26px 28px; color: var(--lilac);
    text-align: center;
  }
  #pause-screen h2 {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 32px; margin: 0 0 4px; letter-spacing: 2px;
    color: #f6f8fe;
  }
  #pause-screen .pause-sub {
    color: rgba(246,248,254,0.64);
    font-size: 11px; margin-bottom: 18px;
    letter-spacing: 1.5px; text-transform: uppercase;
  }
  #pause-audio {
    display: flex; align-items: center; gap: 12px;
    margin-bottom: 18px;
    padding: 10px 14px;
    border-radius: 12px;
    background: rgba(255,255,255,0.03);
    border: 1px solid rgba(255,255,255,0.06);
  }
  #pause-audio #mute-btn {
    background: transparent; color: var(--text); border: none;
    font-size: 18px; cursor: pointer; width: 34px; height: 34px;
    border-radius: 50%; display: flex; align-items: center; justify-content: center;
    transition: background 0.15s;
  }
  #pause-audio #mute-btn:hover { background: rgba(255,255,255,0.08); }
  #pause-audio #mute-btn[aria-pressed="true"] { color: #808a9d; }
  #pause-audio #volume-slider {
    flex: 1; accent-color: #5dd6c8;
  }
  #pause-audio #volume-readout {
    min-width: 42px; text-align: right; color: var(--text-dim);
    font-variant-numeric: tabular-nums; font-size: 12px;
  }
  #pause-powerups { display: flex; flex-direction: column; gap: 7px; margin-bottom: 22px; }
  #pause-powerups:empty::before {
    content: 'No powerups yet.';
    color: rgba(246,248,254,0.5);
    font-size: 13px; letter-spacing: 0.5px;
  }
  #pause-powerups .active-pu { min-width: 0; }
  #pause-resume {
    background: var(--lilac); color: #120e2a;
    border: none; border-radius: 999px;
    padding: 10px 32px; font-weight: 700; letter-spacing: 1.2px;
    text-transform: uppercase; cursor: pointer; font-size: 13px;
    touch-action: manipulation;
  }
  #pause-resume:hover { filter: brightness(1.1); }

  /* Ability bar — bottom-left, tucked under controls hint */
  #ability-bar {
    position: fixed; bottom: 18px; left: 18px;
    display: flex; gap: 10px; pointer-events: none;
  }
  /* Ability tiles — per-skill accent color drives the gradient, icon hue,
     border glow and pressed-state ripple. Each tile is a small "game card":
     dark translucent base, subtle inner-bevel highlight, accent-colored
     top sheen, and a cooldown wedge that sweeps clockwise. The :active
     ripple feeds back on click/tap so the button feels clicky even when
     its action isn't available yet (greyed out via .cd class). */
  .ability {
    --acc:        var(--lilac);
    --acc-rgb:    184, 155, 255;
    --acc-tint:   rgba(var(--acc-rgb), 0.22);
    position: relative; width: 72px; height: 72px;
    background:
      radial-gradient(120% 90% at 50% -20%, rgba(var(--acc-rgb), 0.28) 0%, rgba(var(--acc-rgb), 0) 55%),
      linear-gradient(180deg, rgba(26, 32, 54, 0.82) 0%, rgba(14, 18, 34, 0.88) 100%);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    border: 1px solid rgba(var(--acc-rgb), 0.55);
    border-radius: var(--radius-md);
    box-shadow:
      0 6px 18px rgba(0, 0, 0, 0.35),
      0 0 0 0 rgba(var(--acc-rgb), 0),
      inset 0 1px 0 rgba(255, 255, 255, 0.14),
      inset 0 -12px 24px rgba(0, 0, 0, 0.28);
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    color: rgba(246, 248, 254, 0.92); font-weight: 700; font-size: 10px; letter-spacing: 0.6px;
    text-transform: uppercase;
    overflow: hidden;
    transition: transform 0.12s ease, box-shadow 0.2s ease, border-color 0.2s ease, filter 0.15s ease;
    cursor: pointer;
  }
  /* Glossy sheen across the top edge — fakes the beveled plastic look of
     classic RPG hotbar icons without an extra element. */
  .ability::before {
    content: '';
    position: absolute; left: 6%; right: 6%; top: 4px; height: 26%;
    border-radius: 12px 12px 22px 22px;
    background: linear-gradient(180deg, rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0) 100%);
    pointer-events: none;
    opacity: 0.8;
  }
  .ability:hover {
    transform: translateY(-1px);
    border-color: rgba(var(--acc-rgb), 0.8);
    box-shadow:
      0 10px 24px rgba(0, 0, 0, 0.45),
      0 0 22px rgba(var(--acc-rgb), 0.35),
      inset 0 1px 0 rgba(255, 255, 255, 0.18),
      inset 0 -12px 24px rgba(0, 0, 0, 0.25);
    filter: brightness(1.08);
  }
  .ability:active { transform: translateY(0) scale(0.96); filter: brightness(1.15); }
  .ability .ab-ico  {
    color: var(--acc); line-height: 1;
    font-size: 24px; margin-bottom: 2px;
    display: inline-flex; align-items: center; justify-content: center;
    filter:
      drop-shadow(0 0 8px rgba(var(--acc-rgb), 0.65))
      drop-shadow(0 2px 0 rgba(0, 0, 0, 0.35));
  }
  .ability .ab-name {
    font-size: 9.5px; opacity: 0.92;
    color: rgba(255, 255, 255, 0.94);
    text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
  }
  .ability .ab-key {
    position: absolute; top: 5px; right: 6px;
    font-size: 9px; font-weight: 700; letter-spacing: 0.5px;
    padding: 1px 5px; border-radius: 6px;
    color: rgba(255, 255, 255, 0.78);
    background: rgba(0, 0, 0, 0.35);
    border: 1px solid rgba(var(--acc-rgb), 0.28);
    text-shadow: 0 1px 0 rgba(0, 0, 0, 0.4);
  }

  /* Per-ability accent palette. --acc drives the color-related vars above. */
  .ability.ability-dash   { --acc: #5de3ff; --acc-rgb: 93, 227, 255; }  /* motion cyan */
  .ability.ability-over   { --acc: #ffb454; --acc-rgb: 255, 180, 84; }  /* fire amber */
  .ability.ability-shield { --acc: #b89bff; --acc-rgb: 184, 155, 255; } /* defense lilac */
  .ability.ability-pause  { --acc: #c6cee0; --acc-rgb: 198, 206, 224; } /* neutral */
  /* Radial cooldown indicator — conic-gradient sweeps from 0° (12 o'clock)
     clockwise, covering the ability icon with a darkened wedge that shrinks
     as --cd-frac ticks from 1 → 0. Numeric countdown stays centred on top. */
  .ability .ab-cd   {
    --cd-frac: 0;
    position: absolute; inset: 0;
    background: conic-gradient(from 0deg, rgba(10,14,30,0.68) calc(var(--cd-frac) * 360deg), transparent 0);
    border-radius: inherit;
    display: none; align-items: center; justify-content: center;
    font-size: 18px; font-weight: 700; color: #fff;
    pointer-events: none;
  }
  .ability.cooldown .ab-cd { display: flex; }
  /* Active = ability is firing right now (brief flash). Pulse uses the tile's
     own accent color so each ability glows its own hue. */
  .ability.active {
    border-color: var(--acc);
    box-shadow:
      0 0 0 2px var(--acc),
      0 0 22px rgba(var(--acc-rgb), 0.7),
      inset 0 1px 0 rgba(255, 255, 255, 0.22);
    filter: brightness(1.2);
  }
  /* Faded state while on cooldown — the wedge itself is drawn by .ab-cd. */
  .ability.cooldown { filter: saturate(0.55) brightness(0.85); }
  /* Ready = off-cooldown and idle. Subtle accent outline so the player can
     read "this is usable" at a glance without three strobing HUD tiles. */
  .ability.ready {
    border-color: rgba(var(--acc-rgb), 0.55);
    box-shadow:
      0 0 10px rgba(var(--acc-rgb), 0.25),
      inset 0 1px 0 rgba(255, 255, 255, 0.18);
  }
  /* Triggered once when a cooldown finishes — replays via class toggle in
     updateAbilityCooldowns. Keep it short so it doesn't compete with the
     'active' pulse fired the moment the player spends it. */
  @keyframes ab-just-ready {
    0%   { box-shadow: 0 0 0 0 rgba(var(--acc-rgb), 0.9),  0 0 22px rgba(var(--acc-rgb), 0.85); }
    70%  { box-shadow: 0 0 0 10px rgba(var(--acc-rgb), 0), 0 0 22px rgba(var(--acc-rgb), 0.35); }
    100% { box-shadow: 0 0 0 0 rgba(var(--acc-rgb), 0),    0 0 10px rgba(var(--acc-rgb), 0.25); }
  }
  .ability.ready.just-ready { animation: ab-just-ready 0.65s ease-out 1; }
  @media (prefers-reduced-motion: reduce) {
    .ability.ready.just-ready { animation: none; }
  }

  /* CSS-drawn pause glyph — avoids emoji presentation of U+23F8. Inherits
     ab-ico's lilac via currentColor, scales with ab-ico font-size via em. */
  .ab-ico-pause { display: inline-flex; gap: 0.16em; align-items: center; justify-content: center; }
  .ab-ico-pause span { width: 0.22em; height: 0.7em; background: currentColor; border-radius: 1px; }

  /* Pause is a system control, not an ability — separate it from the cluster. */
  #ability-bar #pause-btn { margin-left: 18px; }

  /* Combo counter — top-right under minimap ceiling */
  #combo-counter {
    position: fixed; top: 84px; left: 50%; transform: translateX(-50%);
    font-family: 'Space Grotesk', sans-serif;
    font-size: 28px; font-weight: 700;
    color: #ffd700; text-shadow: 0 0 12px rgba(255,215,0,0.6);
    pointer-events: none; opacity: 0; transition: opacity 0.2s;
    letter-spacing: 1.5px;
  }
  #combo-counter.visible { opacity: 1; }

  /* Wave modifier — small tag under wave notice */
  #wave-modifier {
    position: fixed; top: 128px; left: 50%; transform: translateX(-50%);
    font-size: 13px; font-weight: 600; letter-spacing: 1.2px; text-transform: uppercase;
    color: #ff88cc;
    background: rgba(255,46,165,0.12);
    border: 1px solid rgba(255,46,165,0.45);
    border-radius: var(--radius-pill);
    padding: 4px 14px;
    pointer-events: none; opacity: 0; transition: opacity 0.3s;
  }
  #wave-modifier.visible { opacity: 1; }

  /* Stack toast — fires when a powerup is picked for the Nth time (N>=2).
     Sits above the HUD center, flashes in with a scale overshoot, holds,
     slides down and away. Re-triggered by toggling .visible. */
  #stack-toast {
    position: fixed; top: 18%; left: 50%; transform: translate(-50%, -40%) scale(0.6);
    display: flex; align-items: center; gap: 10px;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 22px; font-weight: 700; letter-spacing: 1px;
    color: #fff;
    background: linear-gradient(135deg, rgba(24,28,54,0.92), rgba(64,42,96,0.92));
    border: 1px solid rgba(255,215,102,0.55);
    border-radius: 999px;
    padding: 10px 22px;
    box-shadow: 0 8px 28px rgba(0,0,0,0.4), 0 0 24px rgba(255,215,102,0.28);
    pointer-events: none;
    opacity: 0;
    z-index: 38;
    white-space: nowrap;
  }
  #stack-toast .st-icon { font-size: 26px; line-height: 1; }
  #stack-toast .st-count {
    color: #ffd166;
    font-size: 28px;
    text-shadow: 0 0 10px rgba(255,215,102,0.65);
    margin-left: 2px;
  }
  #stack-toast.visible {
    animation: st-pop 1.6s cubic-bezier(.2,.9,.25,1.15) forwards;
  }
  @keyframes st-pop {
    0%   { transform: translate(-50%, -70%) scale(0.4); opacity: 0; }
    14%  { transform: translate(-50%, -40%) scale(1.08); opacity: 1; }
    24%  { transform: translate(-50%, -40%) scale(1);    opacity: 1; }
    80%  { transform: translate(-50%, -40%) scale(1);    opacity: 1; }
    100% { transform: translate(-50%, 0%)   scale(0.9);  opacity: 0; }
  }
  @media (max-width: 720px) {
    #stack-toast { font-size: 17px; padding: 8px 16px; top: 16%; }
    #stack-toast .st-icon { font-size: 20px; }
    #stack-toast .st-count { font-size: 22px; }
  }

  /* Death ceremony — overlays on top of the game-over card for the first
     ~1.8s of a failed run. Canvas desaturates during the ceremony (see
     body.dying filter), overlay fades in black with "YOU DIED" letter-
     by-letter, then fades out to reveal the existing game-over card. */
  #death-ceremony {
    position: fixed;
    top: 0; left: 0;
    width: 100vw; height: 100vh;
    display: flex; align-items: center; justify-content: center;
    background: radial-gradient(ellipse at center, rgba(0,0,0,0.72), rgba(0,0,0,0.96));
    backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
    opacity: 0;
    pointer-events: none;
    /* Above everything — the game-over card (z:200), leaderboard name
       prompt (z:260-280), and stage-select overlays all sit below this
       during the 2.8s ceremony window. */
    z-index: 400;
  }
  #death-ceremony.active { animation: dc-fade 2.8s ease-out forwards; }
  @keyframes dc-fade {
    0%   { opacity: 0; }
    12%  { opacity: 1; }
    78%  { opacity: 1; }
    100% { opacity: 0; }
  }
  #death-ceremony .dc-title {
    display: flex;
    gap: 6px;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 96px;
    font-weight: 800;
    letter-spacing: 12px;
    color: #ff3344;
    text-shadow:
      0 0 30px rgba(255,51,68,0.6),
      0 6px 0 rgba(0,0,0,0.45);
  }
  #death-ceremony .dc-gap { width: 34px; }
  #death-ceremony .dc-title span {
    display: inline-block;
    opacity: 0;
    transform: translateY(18px) scale(0.9);
  }
  #death-ceremony.active .dc-title span {
    animation: dc-letter 0.55s cubic-bezier(.2,.9,.25,1.1) forwards;
  }
  #death-ceremony.active .dc-title span:nth-child(1) { animation-delay: 0.20s; }
  #death-ceremony.active .dc-title span:nth-child(2) { animation-delay: 0.30s; }
  #death-ceremony.active .dc-title span:nth-child(3) { animation-delay: 0.40s; }
  #death-ceremony.active .dc-title span:nth-child(5) { animation-delay: 0.58s; }
  #death-ceremony.active .dc-title span:nth-child(6) { animation-delay: 0.68s; }
  #death-ceremony.active .dc-title span:nth-child(7) { animation-delay: 0.78s; }
  #death-ceremony.active .dc-title span:nth-child(8) { animation-delay: 0.88s; }
  @keyframes dc-letter {
    0%   { opacity: 0; transform: translateY(30px) scale(0.6) rotate(-4deg); }
    60%  { opacity: 1; transform: translateY(-4px) scale(1.05) rotate(0.6deg); }
    100% { opacity: 1; transform: translateY(0)    scale(1)    rotate(0deg); }
  }
  /* Canvas desaturates while death ceremony runs. Applied via body.dying. */
  body.dying #canvas {
    filter: saturate(0.1) brightness(0.55) contrast(1.08);
    transition: filter 1.2s ease-out;
  }
  @media (max-width: 720px) {
    #death-ceremony .dc-title { font-size: 52px; letter-spacing: 6px; }
    #death-ceremony .dc-gap { width: 18px; }
  }

  /* Shop screen */
  #shop-screen {
    position: fixed; inset: 0; z-index: 50;
    display: none; flex-direction: column; align-items: center; justify-content: center;
    background: rgba(10,14,30,0.88);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  }
  #shop-screen.visible { display: flex; }
  #shop-screen h2 { font-family: 'Space Grotesk', sans-serif; font-size: 42px; color: #ffd700; margin: 0; letter-spacing: 2px; }
  #shop-screen p { color: rgba(246,248,254,0.72); margin: 6px 0 22px; font-size: 14px; }
  #shop-screen #shop-score { color: #ffd700; font-weight: 700; }
  #shop-choices {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px;
    max-width: 820px; padding: 0 24px;
  }
  .shop-card {
    background: var(--card-bg);
    border: 1px solid rgba(255,215,0,0.4);
    border-radius: var(--radius-lg);
    padding: 18px; min-width: 220px;
    cursor: pointer; transition: transform 0.12s, border-color 0.12s, box-shadow 0.12s;
    color: var(--fg);
  }
  .shop-card:hover { transform: translateY(-3px); border-color: #ffd700; box-shadow: 0 10px 30px rgba(255,215,0,0.2); }
  .shop-card.locked { opacity: 0.4; cursor: not-allowed; }
  .shop-card .sc-icon  { font-size: 32px; margin-bottom: 6px; }
  .shop-card .sc-name  { font-weight: 700; font-size: 15px; letter-spacing: 0.6px; }
  .shop-card .sc-desc  { font-size: 12px; opacity: 0.75; margin: 4px 0 10px; line-height: 1.4; }
  .shop-card .sc-cost  { color: #ffd700; font-weight: 700; font-size: 13px; }
  #shop-skip {
    margin-top: 22px;
    background: transparent; border: 1px solid var(--card-border); color: var(--fg);
    padding: 10px 22px; border-radius: var(--radius-pill);
    font-family: inherit; font-size: 13px; font-weight: 600; letter-spacing: 1.2px;
    cursor: pointer;
  }
  #shop-skip:hover { background: var(--card-bg); }

  /* Reroll button inside powerup screen */
  #reroll-btn {
    margin-top: 14px; background: transparent;
    border: 1px solid rgba(184,155,255,0.5); color: var(--lilac);
    padding: 8px 18px; border-radius: var(--radius-pill);
    font-family: inherit; font-size: 12px; font-weight: 600; letter-spacing: 1.2px;
    cursor: pointer;
  }
  #reroll-btn:disabled { opacity: 0.4; cursor: not-allowed; }
  #reroll-btn:hover:not(:disabled) { background: rgba(184,155,255,0.1); }

  /* Pickup orbs pulse (applied via CSS custom prop on pickups — actually 3D, no-op here) */

  /* ─── TOUCH / MOBILE ─────────────────────────────────────────────────── */
  #joystick, #cam-pad { display: none; }

  body.touch #joystick {
    display: block;
    position: fixed; left: 0; top: 0; width: 50vw; height: 100%;
    touch-action: none; pointer-events: auto; z-index: 15;
    user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  }
  body.touch #joystick .j-base {
    position: absolute; width: 120px; height: 120px; border-radius: 50%;
    background: rgba(18, 24, 44, 0.35);
    border: 1.5px solid rgba(184, 155, 255, 0.55);
    box-shadow: 0 4px 18px rgba(10, 14, 30, 0.35);
    display: none; pointer-events: none;
    transform: translate(-50%, -50%);
  }
  body.touch #joystick.active .j-base { display: block; }
  body.touch #joystick .j-knob {
    position: absolute; left: 50%; top: 50%;
    width: 52px; height: 52px; border-radius: 50%;
    background: rgba(184, 155, 255, 0.85);
    box-shadow: 0 2px 12px rgba(184, 155, 255, 0.5);
    transform: translate(-50%, -50%);
  }

  body.touch #cam-pad {
    display: block;
    position: fixed; right: 0; top: 0; width: 50vw; height: 100%;
    touch-action: none; pointer-events: auto; z-index: 14;
    user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  }

  body.touch #minimap { display: none; }

  body.touch #pause-screen .pause-card { padding: 22px 20px; max-height: 80vh; }
  body.touch #pause-screen h2 { font-size: 26px; }

  body.touch #top-bar { gap: 4px; top: calc(8px + env(safe-area-inset-top)); }
  body.touch .stat-block { padding: 3px 8px; min-width: 0; gap: 5px; }
  body.touch #kills-block { display: none; }
  body.touch .stat-block .value { font-size: 13px; }
  body.touch .stat-block .label { font-size: 8.5px; letter-spacing: 0.9px; }
  /* Extra-tight enraged pill on mobile — the top-bar's 4-block row leaves
     only ~90px per pill on a 375px screen, and "☠ ENRAGED" clips/overflows
     at the desktop 13px size. Drop to 10.5px + 0 letter-spacing so the
     skull and text stay inside the pill. */
  body.touch .stat-block.enraged .value {
    font-size: 10.5px; letter-spacing: 0;
  }

  /* HP + XP bars split the top row on mobile — HP left, XP right */
  body.touch #health-bar-wrap,
  body.touch #xp-bar-wrap {
    top: calc(40px + env(safe-area-inset-top));
    bottom: auto; transform: none;
    width: calc(50vw - 12px);
  }
  body.touch #health-bar-wrap { left: 8px;  right: auto; }
  body.touch #xp-bar-wrap     { left: auto; right: 8px; }
  body.touch .bar-label { font-size: 9.5px; letter-spacing: 0.9px; margin-bottom: 3px; }
  body.touch .bar-bg    { height: 10px; }

  body.touch #ability-bar {
    pointer-events: none; z-index: 16;
    bottom: calc(16px + env(safe-area-inset-bottom));
    top: auto; left: 50%; right: auto;
    transform: translateX(-50%);
    flex-direction: row; gap: 12px;
  }
  body.touch .ability { width: 56px; height: 56px; pointer-events: auto; touch-action: manipulation; padding: 0 4px; box-sizing: border-box; }
  body.touch .ability .ab-key  { display: none; }
  body.touch .ability .ab-ico  { font-size: 20px; }
  body.touch .ability .ab-name { font-size: 7.5px; letter-spacing: 0; text-transform: none; white-space: nowrap; }

  body.touch #requirements       { display: none; }
  body.touch #touch-requirements { display: inline-flex; }

  /* Level-up modal — portrait */
  body.touch #powerup-screen h2  { font-size: 24px; margin-bottom: 6px; }
  body.touch #powerup-screen p   { font-size: 12px; margin-bottom: 16px; padding: 0 18px; }
  body.touch #powerup-choices    { gap: 10px; max-width: 100vw; padding: 0 10px; }
  body.touch .powerup-card       { width: 46vw; max-width: 170px; padding: 14px 12px; }
  body.touch .powerup-card .icon { font-size: 28px; margin-bottom: 6px; }
  body.touch .powerup-card .name { font-size: 13px; }
  body.touch .powerup-card .desc { font-size: 11px; }
  body.touch #reroll-btn         { padding: 8px 14px; font-size: 11px; }

  /* Shop — portrait */
  body.touch #shop-screen h2 { font-size: 26px; }
  body.touch #shop-screen p  { font-size: 12px; margin-bottom: 12px; }
  body.touch #shop-choices   { grid-template-columns: 1fr; gap: 10px; max-width: 100vw; padding: 0 16px; }
  body.touch .shop-card      { min-width: 0; padding: 12px 14px; }
  body.touch .shop-card .sc-icon { font-size: 24px; }
  body.touch .shop-card .sc-name { font-size: 13px; }
  body.touch .shop-card .sc-desc { font-size: 11px; margin: 2px 0 6px; }
  body.touch #shop-skip      { margin-top: 14px; padding: 10px 18px; }

  /* Gameover — portrait */
  body.touch #gameover h1    { font-size: 40px; margin-bottom: 12px; }
  body.touch #gameover-stats { margin-bottom: 14px; padding: 0 18px; }

  /* Phones / narrow windows — shrink hero typography and stack the primary
     CTAs vertically so SHARE + PLAY AGAIN both sit above the fold. */
  @media (max-width: 520px) {
    #gameover h1 { font-size: 34px; letter-spacing: 0.5px; margin-bottom: 10px; }
    #gameover-hero { margin-bottom: 14px; gap: 4px; }
    #gameover-hero .go-score { font-size: 44px; }
    #gameover-hero .go-score-label { font-size: 9.5px; letter-spacing: 2px; }
    #gameover .go-badge { font-size: 10px; padding: 4px 10px; letter-spacing: 1.1px; }
    .go-stat-strip { gap: 16px; }
    .go-chip { min-width: 54px; }
    .go-chip .go-chip-v { font-size: 19px; }
    .go-chip .go-chip-l { font-size: 9.5px; letter-spacing: 1.4px; }
    #gameover-earned { gap: 10px; font-size: 11.5px; margin-bottom: 18px; }
    #gameover-actions {
      flex-direction: column; gap: 20px;
      width: min(360px, 86vw); margin-bottom: 12px;
    }
    /* Column flex — reset basis to auto so buttons size to content height
       instead of claiming 160px of vertical space each. */
    #gameover-actions > button {
      flex: 0 0 auto;
      width: 100%; min-width: 0;
      padding: 13px 22px; font-size: 15px;
    }
    #gameover-secondary { gap: 10px; }
  }

  /* ─── Leaderboard modal ──────────────────────────────────────────────────
     Full-screen overlay with a single rounded card: title + period tabs +
     stage filter pills + top-10 list. Opens from the landing RANKINGS pill
     or the game-over "View Rankings" link. Purely client-side; fetches
     /api/leaderboard in src/leaderboard.js. */
  #leaderboard-modal {
    position: fixed; inset: 0;
    display: none; align-items: center; justify-content: center;
    z-index: 270;  /* above relic-shop (250) + progress-sync (260) */
    background: rgba(6, 8, 18, 0.82);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  #leaderboard-modal.visible { display: flex; }
  #leaderboard-modal .lb-backdrop { position: absolute; inset: 0; cursor: pointer; }
  #leaderboard-modal .lb-card {
    position: relative;
    width: min(760px, 92vw);
    max-height: 88vh;
    display: flex; flex-direction: column;
    background: linear-gradient(160deg, rgba(30, 36, 60, 0.96), rgba(22, 18, 40, 0.96));
    border: 1px solid rgba(209, 174, 255, 0.25);
    border-radius: 18px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
    overflow: hidden;
  }
  .lb-head {
    display: flex; align-items: center;
    padding: 18px 22px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  }
  .lb-head h2 {
    font-size: 22px; font-weight: 800; letter-spacing: 1.2px; color: var(--text);
    flex: 1;
  }
  .lb-close {
    background: transparent; color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 50%;
    width: 32px; height: 32px;
    font-size: 18px; font-family: inherit;
    cursor: pointer; line-height: 1;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
  }
  .lb-close:hover {
    color: var(--text); border-color: rgba(255, 255, 255, 0.28);
    background: rgba(255, 255, 255, 0.06);
  }
  .lb-period-tabs {
    display: flex; gap: 8px;
    padding: 14px 22px 6px;
  }
  .lb-period {
    flex: 1;
    padding: 9px 12px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-pill);
    font-size: 11px; font-weight: 700; letter-spacing: 0.9px;
    font-family: inherit; cursor: pointer;
    transition: color 0.15s, background 0.15s, border-color 0.15s, transform 0.15s;
  }
  .lb-period:hover { color: var(--text); background: rgba(255, 255, 255, 0.08); }
  .lb-period.active {
    color: #1a0a2a;
    background: linear-gradient(135deg, #9b7bff 0%, #d1aeff 100%);
    border-color: transparent;
    box-shadow: 0 3px 10px rgba(155, 123, 255, 0.35);
  }
  .lb-stage-pills {
    display: flex; flex-wrap: wrap; gap: 6px;
    padding: 10px 22px 6px;
    max-height: 86px; overflow-y: auto;
  }
  .lb-stage {
    padding: 5px 12px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-pill);
    font-size: 11px; font-weight: 600; letter-spacing: 0.5px;
    font-family: inherit; cursor: pointer;
    transition: color 0.15s, background 0.15s, border-color 0.15s;
  }
  .lb-stage:hover { color: var(--text); background: rgba(255, 255, 255, 0.08); }
  .lb-stage.active {
    color: var(--text);
    background: rgba(126, 226, 255, 0.16);
    border-color: rgba(126, 226, 255, 0.45);
  }
  .lb-list {
    list-style: none;
    margin: 10px 0 0;
    padding: 6px 14px 14px;
    overflow-y: auto;
    flex: 1;
  }
  .lb-row {
    display: grid;
    grid-template-columns: 34px 1fr auto;
    grid-template-areas: "rank name score" "rank meta meta";
    align-items: center; column-gap: 12px; row-gap: 2px;
    padding: 10px 14px;
    border-radius: 12px;
    border: 1px solid transparent;
    transition: background 0.15s;
  }
  .lb-row:hover { background: rgba(255, 255, 255, 0.03); }
  .lb-row + .lb-row { margin-top: 4px; }
  .lb-row:nth-child(1) .lb-rank { color: #ffd36e; }
  .lb-row:nth-child(2) .lb-rank { color: #d1d5e2; }
  .lb-row:nth-child(3) .lb-rank { color: #cd8a5f; }
  .lb-rank {
    grid-area: rank;
    font-size: 18px; font-weight: 800;
    color: var(--text-dim);
    text-align: center;
  }
  .lb-name {
    grid-area: name;
    font-size: 14px; font-weight: 700;
    color: var(--text);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .lb-score {
    grid-area: score;
    font-size: 15px; font-weight: 800;
    color: var(--gold);
    letter-spacing: 0.3px;
  }
  .lb-meta {
    grid-area: meta;
    font-size: 11px; color: var(--text-dim);
    letter-spacing: 0.2px;
  }
  .lb-loading, .lb-empty, .lb-error {
    list-style: none;
    text-align: center; padding: 24px 12px;
    color: var(--text-dim);
    font-size: 13px;
  }
  .lb-error { color: #ff9a9a; }
  .lb-skeleton .lb-rank,
  .lb-skeleton .lb-name,
  .lb-skeleton .lb-score,
  .lb-skeleton .lb-meta {
    background: linear-gradient(90deg,
      rgba(255, 255, 255, 0.04) 0%,
      rgba(255, 255, 255, 0.09) 50%,
      rgba(255, 255, 255, 0.04) 100%);
    background-size: 200% 100%;
    border-radius: 6px;
    color: transparent;
    min-height: 1em;
    animation: lb-shimmer 1.2s ease-in-out infinite;
  }
  .lb-skeleton .lb-rank  { width: 22px; margin: 0 auto; height: 16px; }
  .lb-skeleton .lb-name  { width: 55%;  height: 14px; }
  .lb-skeleton .lb-score { width: 64px; height: 15px; justify-self: end; }
  .lb-skeleton .lb-meta  { width: 70%;  height: 11px; margin-top: 2px; }
  .lb-skeleton:hover { background: transparent; }
  @keyframes lb-shimmer {
    0%   { background-position:  100% 0; }
    100% { background-position: -100% 0; }
  }
  @media (prefers-reduced-motion: reduce) {
    .lb-skeleton .lb-rank,
    .lb-skeleton .lb-name,
    .lb-skeleton .lb-score,
    .lb-skeleton .lb-meta { animation: none; }
  }
  .lb-foot {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 22px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
    font-size: 12px; color: var(--text-dim);
  }
  .lb-foot .lb-identity { flex: 1; }
  .lb-foot .lb-my-name { color: var(--text); font-weight: 700; }
  .lb-change-name {
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: var(--radius-pill);
    padding: 6px 14px; font-size: 11px; font-weight: 600;
    letter-spacing: 0.5px; cursor: pointer;
    font-family: inherit;
    transition: color 0.15s, background 0.15s, border-color 0.15s;
  }
  .lb-change-name:hover {
    color: var(--text);
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.24);
  }

  /* Inline name-entry dialog — presented once on the first submission, and
     again from the leaderboard footer's "Change name" button. Styled to
     match the leaderboard card's dark-violet palette. */
  .lb-name-modal {
    position: fixed; inset: 0;
    display: flex; align-items: center; justify-content: center;
    z-index: 280;  /* above #leaderboard-modal (270) */
  }
  .lb-name-backdrop {
    position: absolute; inset: 0;
    background: rgba(6, 8, 18, 0.82);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    cursor: pointer;
  }
  .lb-name-card {
    position: relative;
    width: min(420px, 92vw);
    background: linear-gradient(160deg, rgba(30, 36, 60, 0.98), rgba(22, 18, 40, 0.98));
    border: 1px solid rgba(209, 174, 255, 0.3);
    border-radius: 16px;
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
    padding: 22px 24px;
  }
  .lb-name-card h3 {
    font-size: 16px; font-weight: 800; letter-spacing: 1px;
    color: var(--text); margin-bottom: 6px;
  }
  .lb-name-help {
    font-size: 12px; color: var(--text-dim);
    margin-bottom: 14px; line-height: 1.5;
  }
  .lb-name-input {
    width: 100%;
    background: rgba(0, 0, 0, 0.3);
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 10px;
    color: var(--text);
    font-family: inherit;
    font-size: 16px; font-weight: 600;
    padding: 10px 12px;
    outline: none;
    transition: border-color 0.15s, background 0.15s;
  }
  .lb-name-input:focus {
    border-color: rgba(209, 174, 255, 0.55);
    background: rgba(0, 0, 0, 0.42);
  }
  .lb-name-actions {
    display: flex; justify-content: flex-end; gap: 10px;
    margin-top: 16px;
  }
  .lb-name-cancel, .lb-name-save {
    font-family: inherit; font-weight: 700; letter-spacing: 0.6px;
    font-size: 12px; padding: 9px 18px;
    border-radius: var(--radius-pill);
    cursor: pointer;
  }
  .lb-name-cancel {
    background: transparent; color: var(--text-dim);
    border: 1px solid rgba(255, 255, 255, 0.14);
    transition: color 0.15s, border-color 0.15s;
  }
  .lb-name-cancel:hover { color: var(--text); border-color: rgba(255, 255, 255, 0.3); }
  .lb-name-save {
    background: linear-gradient(135deg, #9b7bff 0%, #d1aeff 100%);
    color: #1a0a2a;
    border: none;
    box-shadow: 0 4px 14px rgba(155, 123, 255, 0.38);
    transition: transform 0.15s, box-shadow 0.18s, filter 0.15s;
  }
  .lb-name-save:hover {
    transform: translateY(-1px);
    box-shadow: 0 8px 22px rgba(155, 123, 255, 0.55);
    filter: brightness(1.08);
  }

  /* Leaderboard — portrait */
  @media (max-width: 600px) {
    #leaderboard-modal .lb-card { width: 94vw; max-height: 92vh; border-radius: 14px; }
    .lb-head { padding: 14px 16px; }
    .lb-head h2 { font-size: 18px; letter-spacing: 0.9px; }
    .lb-period-tabs { padding: 10px 14px 4px; gap: 6px; }
    .lb-period { font-size: 10px; padding: 8px 6px; letter-spacing: 0.6px; }
    .lb-stage-pills { padding: 8px 14px 4px; max-height: 74px; }
    .lb-stage { font-size: 10.5px; padding: 4px 10px; }
    .lb-list { padding: 4px 10px 10px; }
    .lb-row { grid-template-columns: 28px 1fr auto; padding: 8px 10px; column-gap: 10px; }
    .lb-name { font-size: 13px; }
    .lb-score { font-size: 14px; }
    .lb-meta { font-size: 10px; }
    .lb-foot { padding: 10px 16px; gap: 8px; }
    .lb-foot .lb-identity { font-size: 11px; }
    .lb-change-name { padding: 5px 10px; font-size: 10.5px; }
  }

  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      transition-duration: 0.01ms !important;
      animation-duration: 0.01ms !important;
    }
  }
