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

html, body {
  width: 100%;
  height: 100%;
  background: #0a0a0f;
  overflow: hidden;
  touch-action: none;
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}

/* SDK-driven platform pause (ytgame.system.onPause) — locks out every
   button and the canvas itself so nothing behind the pause overlay is
   reachable, regardless of z-index/overlap. isPaused guards in JS back
   this up defense-in-depth for input handlers and the game loop. */
body.paused button,
body.paused #gameCanvas {
  pointer-events: none !important;
}

#pause-overlay {
  z-index: 40; /* above every other overlay (max otherwise used is 30) */
}

#game-container {
  position: relative;
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
}

#gameCanvas {
  display: block;
  background: #3a2a1a;
  max-width: 100vw;
  max-height: 100vh;
  touch-action: none;
}

#hud {
  position: absolute;
  /* env(safe-area-inset-top) is 0 on anything without a notch/dynamic
     island (desktop browsers, older phones) so this is a no-op there —
     it only matters on the iOS native build, where the WebView renders
     full-screen behind the status bar/dynamic island by default. */
  top: calc(10px + env(safe-area-inset-top));
  left: calc(10px + env(safe-area-inset-left));
  right: calc(10px + env(safe-area-inset-right));
  display: flex;
  flex-direction: column;
  gap: 3px;
  color: #fff;
  text-shadow: 0 2px 4px rgba(0,0,0,0.8);
  font-weight: bold;
  pointer-events: none;
  z-index: 10;
}

/* Currency pills reuse the same dark-rounded-badge language as the main
   menu's #start-gold-pill/#start-diamond-pill, so the HUD reads as "the
   same game" rather than a separate debug-style readout. */
#hud-currency-row {
  display: flex;
  gap: 6px;
}

/* display:inline-flex + align-items:center, not vertical-align:middle — the
   latter aligns to the middle of the parent's font x-height/baseline (not
   the actual visual line box), which is a well-known source of an icon
   sitting subtly off-center next to bold+text-shadowed text. Flex gives a
   real, robust center regardless of font metrics. Same treatment applied
   to every icon+text badge below (currency pills, streak pill, HUD
   displays) so nothing in this family is left relying on the fragile
   approach. */
#gold-display, #diamond-display {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(0, 0, 0, 0.4);
  border-radius: 12px;
  padding: 2px 9px;
  font-size: 14px;
  width: fit-content;
}

#gold-display {
  color: #ffd700;
}

/* A real gold-colored icon instead of the 🪙 emoji — confirmed from a real
   device screenshot that Apple's coin emoji renders closer to silver/pewter
   than gold at this size, which is exactly backwards for a currency meant
   to read as "gold" at a glance. Color emoji glyphs ignore CSS `color`
   entirely, so no text-based fix exists — this is a real drawn element
   instead, matching the same radial-gradient gold look already used for
   the terrain Gold ore blocks. */
.coin-icon {
  display: inline-block;
  flex-shrink: 0;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #fff9c4, #ffd700 45%, #b8860b 100%);
  border: 1px solid rgba(0, 0, 0, 0.35);
  box-shadow: 0 0 3px rgba(255, 215, 0, 0.55);
  vertical-align: middle; /* no-op inside the flex badges above (flex items ignore vertical-align) — only matters for the tutorial screen's plain-inline-text usage */
}

#diamond-display {
  color: #4fd8ff;
}

#hud-stats-row {
  display: flex;
  gap: 12px;
  font-size: 14px;
  margin-top: 1px;
}

#score-display {
  color: #64b5f6;
}

#combo-display {
  font-size: 12px;
  color: #ff7043;
  width: fit-content;
}

#biome-display {
  font-size: 12px;
  opacity: 0.8;
  letter-spacing: 0.5px;
  transition: color 0.3s ease;
}

#magnet-display {
  font-size: 12px;
  color: #4dd0e1;
}

#shield-display {
  font-size: 12px;
  color: #64b5f6;
}

#score-boost-display {
  font-size: 12px;
  color: #ffd700;
}

#health-bar-outer {
  width: 140px;
  height: 12px;
  background: rgba(0,0,0,0.5);
  border: 2px solid #fff;
  border-radius: 6px;
  overflow: hidden;
  margin-top: 3px;
}

#health-bar-inner {
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, #4caf50, #8bc34a);
  transition: width 0.15s ease, background 0.3s ease;
}

#overdrive-bar-outer {
  width: 140px;
  height: 7px;
  background: rgba(0,0,0,0.5);
  border: 2px solid #ffd54f;
  border-radius: 5px;
  overflow: hidden;
  margin-top: 3px;
}

#overdrive-bar-inner {
  width: 0%;
  height: 100%;
  background: linear-gradient(90deg, #ff9800, #ffeb3b);
  transition: width 0.15s ease;
}

#overdrive-bar-outer.active #overdrive-bar-inner {
  background: linear-gradient(90deg, #fff176, #ffffff);
  animation: overdriveBarPulse 0.3s ease-in-out infinite alternate;
}

@keyframes overdriveBarPulse {
  from { opacity: 1; }
  to { opacity: 0.55; }
}

/* Core Overdrive: pulsing border flash signaling invincibility. Purely
   decorative — pointer-events:none so it never intercepts input, matching
   how #pause-overlay/#toast already stay out of the way of real controls. */
#overdrive-flash {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 15;
  opacity: 0;
  transition: opacity 0.15s ease;
}

#overdrive-flash.active {
  opacity: 1;
  animation: overdrivePulse 0.4s ease-in-out infinite alternate;
}

@keyframes overdrivePulse {
  from { box-shadow: inset 0 0 30px 10px rgba(255, 235, 59, 0.9); }
  to   { box-shadow: inset 0 0 60px 20px rgba(255, 255, 255, 0.95); }
}

#pause-btn {
  position: absolute;
  top: calc(12px + env(safe-area-inset-top));
  right: calc(12px + env(safe-area-inset-right));
  z-index: 11; /* above the HUD (10), below any overlay (20) which covers/blocks it automatically */
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(0, 0, 0, 0.5);
  color: #fff;
  font-size: 14px;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Same corner/size/style as #pause-btn (menu vs. gameplay share the
   convention) — this one lives on the start screen instead, so it's a
   sibling of #start-hud rather than #hud, and needs its own z-index since
   #start-screen's other children are laid out via flex, not absolute. */
#settings-btn {
  position: absolute;
  top: calc(12px + env(safe-area-inset-top));
  right: calc(12px + env(safe-area-inset-right));
  z-index: 2;
  min-width: 0; /* .overlay button's own min-width:260px would otherwise stretch this into an oval, not a circle */
  width: 40px;
  height: 40px;
  padding: 0; /* .overlay button's own 15px/20px padding would otherwise crowd out the 40px box entirely */
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.25);
  background: rgba(0, 0, 0, 0.5);
  color: #fff;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: center;
}

#settings-btn:active {
  transform: scale(0.92);
}

.overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(10, 10, 15, 1);
  color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* flex-start + overflow-y:auto, not center: on short viewports (iPhone
     SE/8-height devices) overlay content can exceed the screen height, and
     justify-content:center + overflow:visible has no way to reach the
     clipped bottom (body has overflow:hidden/touch-action:none — there's no
     page-level scroll to fall back on). Without this, a tall overlay's own
     Close button can be pushed off-screen with literally no way back out.
     touch-action:pan-y re-enables vertical touch-scroll here specifically,
     since it's blocked globally for the drilling drag controls. */
  justify-content: flex-start;
  overflow-y: auto;
  touch-action: pan-y;
  gap: 12px;
  text-align: center;
  /* Top padding alone gets env(safe-area-inset-top) added — flat 20px on
     every side worked fine in browser testing (which reports 0 for the
     inset unless a notched device is specifically emulated), but on a real
     Dynamic Island device with a larger reserved area than that, an H1
     sitting on plain 20px can render crowding right up against/under it.
     Confirmed on a real iPhone 17 Pro Max — the Trails/Loadout/Supply
     Cache/Paused titles all sat too close to the island. */
  padding: calc(20px + env(safe-area-inset-top)) 20px 20px 20px;
  z-index: 20;
}

#toast {
  position: absolute;
  top: env(safe-area-inset-top);
  left: 50%;
  max-width: 85%;
  transform: translate(-50%, -120%);
  background: linear-gradient(90deg, #43a047, #7cb342);
  color: #fff;
  font-weight: bold;
  font-size: 14px;
  padding: 12px 20px;
  border-radius: 0 0 12px 12px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  text-align: center;
  z-index: 30;
  pointer-events: none;
  transition: transform 0.4s ease;
  white-space: normal;
}

#toast.show {
  transform: translate(-50%, 0);
}

.overlay.hidden, .hidden {
  display: none;
}

#start-highscore, #highscore-display {
  font-size: 15px;
  color: #64b5f6;
  font-weight: bold;
}

#start-highscore {
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(100, 181, 246, 0.35);
  border-radius: 20px;
  padding: 6px 18px;
  display: inline-block;
}

#final-score {
  font-size: 18px;
  font-weight: bold;
  color: #64b5f6;
}

#new-highscore-badge {
  font-size: 17px;
  font-weight: bold;
  color: #ffd700;
  text-shadow: 0 0 10px rgba(255, 215, 0, 0.7);
  letter-spacing: 1px;
}

.contract-bonus-line {
  font-size: 14px;
  font-weight: bold;
  color: #81c784;
  min-height: 1em;
}

.overlay h1 {
  font-size: 32px;
  letter-spacing: 2px;
  margin-bottom: 8px;
  color: #ffd700;
}

/* Mid-screen section header (Base Skins) — same gold color as a real <h1>
   but scaled down so it reads as "a section of this screen," not a second
   page title competing with "THE BASE" above it. */
.base-skins-heading {
  font-size: 18px;
  letter-spacing: 1px;
  margin-top: 14px;
  margin-bottom: 0;
}

/* "Kicker" line above the real title — carries the brand name (Endless
   Core) without competing with MINING RUSH, which is the name players
   actually recognize from the App Store listing ("Endless Core: Mining
   Rush"). Warm pale-gold instead of dim white — same gold family as the
   title below so it reads as related branding, not a stray gray label,
   while staying clearly smaller/lighter than MINING RUSH's own gold-foil
   fill so the hierarchy is still obvious. */
.menu-title-eyebrow {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: 6px;
  text-transform: uppercase;
  color: #ffe9b3;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8), 0 0 14px rgba(255, 193, 7, 0.4);
  margin-bottom: 4px;
}

/* Gold-foil engraved look (gradient text fill + glow) instead of a flat
   color — reads as a rich metal plaque rather than plain UI text. Needs
   the -webkit- prefix for iOS WKWebView (the native app's actual engine). */
.menu-title h1 {
  font-size: 46px;
  letter-spacing: 3px;
  margin-bottom: 4px;
  font-weight: 800;
  background: linear-gradient(180deg, #fff6d8 0%, #ffd700 45%, #c9910b 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  text-shadow: 0 0 26px rgba(255, 193, 7, 0.4);
  filter: drop-shadow(0 3px 6px rgba(0, 0, 0, 0.6));
}

.menu-title-underline {
  width: 90px;
  height: 3px;
  margin: 2px auto 8px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, #ffd700 25%, #ffe9a8 50%, #ffd700 75%, transparent);
  box-shadow: 0 0 10px rgba(255, 215, 0, 0.55);
}

/* Start screen is the one place with a real illustrated backdrop (rather
   than every overlay's flat dark fill) — a painted mine-cave scene matching
   the app icon's exact identity (silver drill, amber glow, gold veins).
   The scrim gradient is deliberately light near the top (let the art show)
   and thickens toward the bottom where the button stack sits, blending
   into the image's own naturally dark lower third. Functional menus
   (Upgrades, Museum, etc.) stay on the plain flat fill — lower-key, easier
   to read, not competing with this screen's hero treatment. */
#start-screen {
  background-image:
    linear-gradient(180deg, rgba(8, 6, 16, 0.30) 0%, rgba(8, 6, 16, 0.55) 55%, rgba(5, 4, 10, 0.94) 100%),
    url('menu-bg.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  /* Subtle background drift instead of a dead-still screenshot — small
     enough it reads as "alive," not distracting from the buttons on top.
     background-position (not transform) deliberately, so it only moves the
     paint, never the title/buttons stacked as normal children on top of it. */
  animation: startBgDrift 22s ease-in-out infinite;
  /* #start-hud is absolutely positioned (out of flow) in the top-left, so
     it never pushes this flex column's content down on its own — on a
     short viewport, justify-content:center centers everything (including
     the title) in the FULL height, which can push the title up into the
     HUD's fixed spot regardless of how small the HUD is. Reserving real
     top padding guarantees clearance on any screen height, rather than
     depending on exactly how tall the HUD happens to be. */
  /* env(safe-area-inset-top) added on top of the flat 96px: #start-hud's
     own position (top: 10px + the same inset) grows on a device with a
     bigger notch/Dynamic Island reserve than whatever this 96px was
     measured against, but a flat number here doesn't grow with it — so on
     a real iPhone 17 Pro Max the Day Streak badge (the taller of the two
     stacked HUD rows) ended up sitting low enough to overlap "ENDLESS
     CORE". This keeps the same 96px clearance on a no-inset device (this
     session's browser testing) while adding real headroom on hardware
     with a bigger island. */
  padding-top: calc(96px + env(safe-area-inset-top));
  /* On short viewports (iPhone SE/8-height devices) the menu button grid
     is now taller than the screen (Leaderboard row pushed it over) — same
     overflow + justify-content:flex-start + touch-action:pan-y fix already
     used on #base-screen, so the bottom buttons stay reachable instead of
     being silently clipped by body's overflow:hidden/touch-action:none. */
  overflow-y: auto;
  touch-action: pan-y;
  justify-content: flex-start;
}

@keyframes startBgDrift {
  0%, 100% { background-position: 50% 50%; }
  50% { background-position: 53% 46%; }
}

/* The Base's hero art — same treatment as #start-screen (gradient scrim +
   cover image), but the actual url() is set from JS in renderBaseScreen()
   since it swaps between 4 tiered scene images (base-scene-tier0..3.jpg) as
   state.offlineRigUpgradeLevel/diamondSieveUpgradeLevel grow, so upgrading
   visibly changes the base rather than just changing numbers on cards. */
/* Grown past a single screenful once Camp Skins was added (title, subtitle,
   diamond count, Descend, ad button, 2 upgrade cards, skins heading + list,
   Close) — scoped to this screen alone rather than the shared .overlay rule,
   since most other overlays don't need/want scrolling. touch-action must be
   set explicitly — the global `touch-action: none` on body is non-inherited
   and would otherwise silently block touch-scrolling this screen on the iOS
   build specifically (desktop/mouse-driven testing never surfaces this;
   mouse wheel and programmatic scrollTop both ignore touch-action entirely
   — same reasoning already applied to .pass-tier-list/.achievement-list,
   missed here when this screen was first made scrollable). */
#base-screen {
  overflow-y: auto;
  touch-action: pan-y;
  /* .overlay's justify-content:center is the actual remaining bug: when a
     centered flex container's content overflows, the scrollable range gets
     computed around that centering rather than the content's real start/
     end, so the screen can open showing a MIDDLE slice of content (not the
     title) with both the true top and true bottom only partially reachable
     via scroll — this is a well-known flex-center-plus-overflow gotcha, not
     something touch-action could ever have fixed. flex-start makes the
     scrollable range unambiguous: content always starts at the real top,
     and the real bottom (Close button) is always reachable by scrolling
     all the way down. */
  justify-content: flex-start;
}

/* The hero scene lives on its own pseudo-element layer, not directly on
   #base-screen — a Base Skin's CSS filter (see BASE_SKIN_DEFS in game.js)
   needs to tint only the background art, never the real children (upgrade
   card text, buttons) stacked on top of it, and `filter` always applies to
   an element's whole rendered subtree, so it has to be isolated here.
   position:absolute + inset:0 pins it to the viewport-sized box even while
   #base-screen's own content scrolls internally, so the art reads as a
   fixed backdrop rather than scrolling away. --base-scene-bg/--base-skin-
   filter are set from JS in renderBaseScreen(). */
#base-screen::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--base-scene-bg);
  background-size: cover;
  background-position: center 80%;
  filter: var(--base-skin-filter, none);
}

/* Rising ember particles — cheap, pure-CSS "living scene" cue (Clash Royale-
   style menus lean hard on ambient motion; this was the one thing our menu
   had none of). pointer-events:none so they can never intercept a tap even
   if a particle happens to drift over a button. */
#ember-field {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.ember {
  position: absolute;
  bottom: -10px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffe082 0%, #ffa000 60%, rgba(255, 160, 0, 0) 100%);
  opacity: 0;
  animation: emberRise 9s ease-in infinite;
}

.ember:nth-child(1) { left: 10%; animation-delay: 0s; animation-duration: 8s; }
.ember:nth-child(2) { left: 22%; animation-delay: 1.5s; animation-duration: 10s; }
.ember:nth-child(3) { left: 35%; animation-delay: 3s; animation-duration: 7s; }
.ember:nth-child(4) { left: 48%; animation-delay: 0.7s; animation-duration: 11s; }
.ember:nth-child(5) { left: 61%; animation-delay: 2.2s; animation-duration: 9s; }
.ember:nth-child(6) { left: 74%; animation-delay: 4s; animation-duration: 8.5s; }
.ember:nth-child(7) { left: 85%; animation-delay: 1s; animation-duration: 10.5s; }
.ember:nth-child(8) { left: 93%; animation-delay: 3.5s; animation-duration: 7.5s; }

@keyframes emberRise {
  0% { transform: translate(0, 0); opacity: 0; }
  10% { opacity: 0.8; }
  90% { opacity: 0.3; }
  100% { transform: translate(12px, -620px); opacity: 0; }
}

/* Persistent Gold (+ streak, when active) readout — top-left, matching the
   in-game HUD's own positioning so the two feel like the same system rather
   than menu vs. gameplay having unrelated conventions. Previously Gold was
   invisible on this screen entirely; a player had to open a sub-screen just
   to see what they had. */
#start-hud {
  position: absolute;
  top: calc(10px + env(safe-area-inset-top));
  left: calc(10px + env(safe-area-inset-left));
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 2;
  pointer-events: none;
}

/* Gold + Diamond side by side rather than stacked — with a Streak pill
   added below this row, three fully-stacked pills grew tall enough to
   overlap the centered title text on shorter screens. Two rows fits
   comfortably above the title everywhere the old two-pill layout did. */
#start-currency-row {
  display: flex;
  gap: 5px;
}

#start-gold-pill, #start-diamond-pill, #start-streak-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 215, 0, 0.4);
  border-radius: 16px;
  padding: 4px 10px;
  font-size: 12px;
  font-weight: bold;
  color: #ffd700;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
  width: fit-content;
}

#start-diamond-pill {
  border-color: rgba(79, 216, 255, 0.5);
  color: #4fd8ff;
}

#start-streak-pill {
  border-color: rgba(255, 111, 0, 0.5);
  color: #ffb74d;
}

.overlay p {
  font-size: 16px;
  opacity: 0.9;
}

.overlay .hint {
  font-size: 13px;
  opacity: 0.6;
  margin-bottom: 8px;
}

.tutorial-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: 300px;
  text-align: left;
  margin: 6px 0 4px;
}

.tutorial-list p {
  font-size: 14px;
  opacity: 1;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 10px;
  padding: 10px 12px;
  line-height: 1.4;
}

/* Every overlay button shares this "glossy" build by default: a soft
   white highlight over the base color (light catching a curved glass
   surface), an inset top-highlight/bottom-shadow for physical depth, and a
   real drop shadow lifting it off the background — set --btn-grad per
   button/screen below instead of overriding background wholesale, so every
   button in the game gets the same premium treatment automatically. */
.overlay button {
  --btn-grad: linear-gradient(135deg, #9c8163 0%, #5c4830 55%, #3a2c1c 100%);
  pointer-events: auto;
  min-width: 260px;
  padding: 15px 20px;
  font-size: 15px;
  font-weight: bold;
  border-radius: 12px;
  border: 1px solid rgba(255, 213, 130, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 5px 16px rgba(0, 0, 0, 0.4),
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -2px 5px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  color: #fff;
  cursor: pointer;
  margin-top: 6px;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.overlay button:active {
  transform: scale(0.96);
  filter: brightness(0.92);
}

.overlay button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
  transform: none;
}

/* Start-screen hierarchy: one large primary Play action, five smaller
   secondary actions in a grid beneath it — replaces the old flat stack of
   six identically-sized buttons. Every button here shares a "glossy" build:
   a soft white highlight layered over the base color gradient (light
   catching a curved glass/glossy surface), an inset top highlight + bottom
   shadow for physical depth, and a real drop shadow lifting it off the
   background — the standard premium-mobile-game button treatment, replacing
   the earlier flat single-color fills. */
.overlay .menu-primary-btn {
  --btn-grad: linear-gradient(135deg, #7ed67f 0%, #43a047 55%, #2e7d32 100%);
  min-width: 260px;
  padding: 20px 24px;
  font-size: 19px;
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 8px 24px rgba(46, 125, 50, 0.55),
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -3px 6px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
  margin-top: 4px;
}

.menu-secondary-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  width: 100%;
  max-width: 280px;
  margin-top: 12px;
}

/* Clash Royale-style nav: every secondary action shares ONE color family
   (weathered bronze/leather, matching the drill's own metal + the cave's
   rock) instead of a different hue per button. A six-color rainbow in a
   tight 2x3 grid reads as busy rather than expensive; a real premium nav
   uses one consistent panel color and lets icons + labels do the
   differentiating, with the gold rim (kept from before) as the one
   unifying accent. */
.overlay .menu-secondary-btn {
  --btn-grad: linear-gradient(135deg, #9c8163, #5c4830 55%, #3a2c1c);
  position: relative; /* anchors .claim-badge */
  min-width: 0;
  padding: 13px 10px;
  font-size: 13px;
  border-radius: 12px;
  margin-top: 0;
  border-width: 1px;
  border-style: solid;
  border-color: rgba(255, 213, 130, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.32) 0%, rgba(255, 255, 255, 0) 45%),
    var(--btn-grad);
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.45),
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -2px 4px rgba(0, 0, 0, 0.3);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* "Something's here" badge — the Season Pass button gets a pulsing dot when
   a tier is claimable and unclaimed, the same "come back and see" cue
   Clash Royale/Brawl Stars use on their chest/shop icons instead of making
   players discover rewards by chance. */
.claim-badge {
  position: absolute;
  top: -5px;
  right: -5px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ff8a65, #e53935 70%);
  border: 2px solid rgba(255, 255, 255, 0.85);
  box-shadow: 0 0 6px rgba(229, 57, 53, 0.7);
  animation: badgePulse 1.6s ease-in-out infinite;
}

@keyframes badgePulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.15); }
}

.overlay .menu-secondary-btn:active {
  transform: scale(0.95);
  filter: brightness(0.92);
}

/* Base gets a deliberately more prominent slot than the other secondary
   nav buttons (it's a whole new progression system, not a single utility
   screen) — full-width (spans both grid columns) with slightly larger
   type, but keeps the same bronze/leather family as the rest of the grid
   rather than a one-off color, matching this menu's "one accent color"
   rule (see the comment above .overlay .menu-secondary-btn). */
.overlay .menu-base-btn {
  grid-column: span 2;
  padding: 15px 14px;
  font-size: 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

/* .menu-base-btn's justify-content:space-between was tuned for My Base's
   label+progress pair — with a single plain-text child (Leaderboard has no
   second element to space against), space-between collapses to flex-start,
   sitting the text off to the left instead of centered like every other
   single-content button. */
.overlay #start-leaderboard-btn {
  justify-content: center;
}

.menu-base-btn-label {
  font-size: 15px;
}

.menu-base-btn-progress {
  font-size: 12px;
  font-weight: normal;
  opacity: 0.85;
  background: rgba(0, 0, 0, 0.35);
  padding: 3px 8px;
  border-radius: 8px;
}

/* "Main Menu" nav buttons (pause screen, Game Over) are a distinct action
   type from the primary actions around them — leaving the run — so they
   get a neutral outlined glass treatment instead of a bright fill color. */
.overlay .menu-nav-btn {
  --btn-grad: rgba(255, 255, 255, 0.06);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.18) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  border: 1px solid rgba(255, 255, 255, 0.4);
  color: #fff;
}

/* Every plain .overlay button (Resume, Revive, 2x Gold, Upgrades, Restart,
   Museum, every screen's Close button, Chest's ad/skip buttons, and
   anything else without its own override below) now gets its color from
   the base ".overlay button" rule above — bronze/leather, same family as
   the start screen's secondary nav. Per-feature accent colors (blue
   Upgrades, purple Museum, teal Loadout, green Contracts, etc.) are gone
   app-wide, not just on the two screens that prompted this — full
   consistency was the explicit ask. .menu-primary-btn (Start Drilling)
   is the one deliberate exception: it's the single most important action
   in the whole app, and staying green keeps it readable as "the thing to
   tap" rather than blending into the now-uniform secondary/utility set —
   same principle top mobile games use for their one hero CTA. */

.upgrade-card {
  width: 100%;
  max-width: 280px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-radius: 12px;
  padding: 14px 16px;
  margin-top: 4px;
  /* #base-screen's hero art is a fixed (non-scrolling) backdrop, so as the
     card list grows taller, more cards inevitably scroll through its busiest
     part (tent/drill/crate shapes) — under the Camp Skins' saturated hue-
     rotate filters those hard edges read as ugly, illegible artifacts right
     behind card text (confirmed on Frost: the crates' grid pattern turned
     into harsh neon-blue squares stacked under "Diamond Sieve"). A real
     frosted-glass blur, not just alpha, fixes it at the source regardless of
     scroll position, skin, or how many cards get added later. */
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.upgrade-name {
  font-size: 17px;
  font-weight: bold;
  color: #64b5f6;
}

.upgrade-desc {
  font-size: 13px;
  opacity: 0.8;
  margin: 6px 0 10px;
}

.upgrade-card button {
  --btn-grad: linear-gradient(135deg, #9c8163, #5c4830 60%, #3a2c1c);
  pointer-events: auto;
  width: 100%;
  min-width: 0;
  padding: 12px 16px;
  font-size: 14px;
  font-weight: bold;
  border-radius: 10px;
  border: 1px solid rgba(255, 213, 130, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -2px 4px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  color: #fff;
  cursor: pointer;
  margin-top: 0;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.upgrade-card button:active {
  transform: scale(0.96);
  filter: brightness(0.92);
}

.upgrade-card button:disabled {
  --btn-grad: #555;
  border-color: rgba(255, 255, 255, 0.15);
  box-shadow: none;
  text-shadow: none;
  color: #999;
  cursor: not-allowed;
}

#museum-count {
  font-size: 16px;
  font-weight: bold;
  color: #ce93d8;
}

.relic-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  width: 100%;
  max-width: 320px;
  margin-top: 4px;
}

.relic-slot {
  width: 84px;
  padding: 10px 6px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
}

.relic-slot.locked {
  opacity: 0.55;
}

.relic-icon {
  width: 28px;
  height: 28px;
  border-radius: 50%;
}

.relic-slot.found .relic-icon {
  box-shadow: 0 0 10px 2px currentColor;
}

.relic-name {
  font-size: 11px;
  line-height: 1.3;
  text-align: center;
  word-break: break-word;
}

.contract-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 300px;
  max-height: 48vh;
  overflow-y: auto;
  touch-action: pan-y; /* same reasoning as .achievement-list/.pass-tier-list */
  margin-top: 4px;
}

.contract-item {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-left: 4px solid #388e3c;
  border-radius: 10px;
  padding: 12px 14px;
  text-align: left;
}

.contract-item.completed {
  border-left-color: #ffd700;
  background: rgba(255, 215, 0, 0.08);
}

.contract-desc {
  font-size: 14px;
  font-weight: bold;
}

.contract-bonus {
  font-size: 12px;
  opacity: 0.8;
  margin-top: 4px;
  color: #81c784;
}

.contract-item.completed .contract-bonus {
  color: #ffd700;
  opacity: 1;
}

.class-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 300px;
  margin-top: 4px;
}

.class-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-left: 4px solid #00838f;
  border-radius: 10px;
  padding: 12px 14px;
  text-align: left;
}

.class-card.locked {
  opacity: 0.55;
}

.class-card.active {
  border-left-color: #ffd700;
  background: rgba(255, 215, 0, 0.08);
}

.class-name {
  font-size: 16px;
  font-weight: bold;
  margin-bottom: 6px;
}

.class-perk {
  font-size: 12px;
  color: #81c784;
}

.class-drawback {
  font-size: 12px;
  color: #ef9a9a;
}

.class-locked {
  font-size: 12px;
  font-weight: bold;
  opacity: 0.7;
  margin-top: 8px;
}

/* .overlay prefix isn't decorative here — it raises specificity above the
   shared ".overlay button" default-green rule (class+element beats a bare
   class), which otherwise silently wins and overrides --btn-grad's own
   color. Same fix applied to .trail-select-btn and .pass-claim-btn below;
   found by actually looking at the rendered Loadout screen, not just
   reading the CSS. */
.overlay .class-select-btn {
  --btn-grad: linear-gradient(135deg, #9c8163, #5c4830 60%, #3a2c1c);
  pointer-events: auto;
  width: 100%;
  min-width: 0;
  margin-top: 8px;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: bold;
  border-radius: 10px;
  border: 1px solid rgba(255, 213, 130, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -2px 4px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  color: #fff;
  cursor: pointer;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.class-select-btn:active {
  transform: scale(0.96);
  filter: brightness(0.92);
}

.class-select-btn:disabled {
  --btn-grad: linear-gradient(135deg, #fff59d, #ffd700 60%, #ffa000);
  color: #222;
  text-shadow: none;
  cursor: default;
  opacity: 1;
}


.trail-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  width: 100%;
  max-width: 300px;
  margin-top: 4px;
}

.trail-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-left: 4px solid #ec407a;
  border-radius: 10px;
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 12px;
  text-align: left;
}

.trail-card.active {
  border-left-color: #ffd700;
  background: rgba(255, 215, 0, 0.08);
}

.trail-card.pass-exclusive {
  border-left-color: #ffb300;
}

.pass-badge {
  display: inline-block;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.5px;
  color: #2b1c00;
  background: linear-gradient(135deg, #ffe082, #ffb300);
  border-radius: 4px;
  padding: 2px 5px;
  margin-left: 4px;
  vertical-align: middle;
}

.trail-swatch {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 8px 1px currentColor;
}

.trail-name {
  flex: 1;
  font-size: 14px;
  font-weight: bold;
}

.overlay .trail-select-btn {
  --btn-grad: linear-gradient(135deg, #9c8163, #5c4830 60%, #3a2c1c);
  pointer-events: auto;
  min-width: 0;
  padding: 10px 14px;
  font-size: 12px;
  font-weight: bold;
  border-radius: 10px;
  border: 1px solid rgba(255, 213, 130, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -2px 4px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  color: #fff;
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.trail-select-btn:active {
  transform: scale(0.96);
  filter: brightness(0.92);
}

.trail-select-btn:disabled {
  --btn-grad: linear-gradient(135deg, #fff59d, #ffd700 60%, #ffa000);
  color: #222;
  text-shadow: none;
  cursor: default;
  opacity: 1;
}

/* Locked Season Pass trails must NOT look like the gold "Selected" state
   above (that reads as "this is active," not "you don't own this yet") —
   muted gray instead, matching the Loadout screen's locked class-card look. */
.trail-select-btn.pass-locked:disabled {
  --btn-grad: linear-gradient(135deg, #6b6b6b, #3a3a3a);
  color: rgba(255, 255, 255, 0.7);
  opacity: 0.85;
}

/* ---------- Season Pass overlay ---------- */
#pass-season-info {
  color: #ffd54f;
  font-weight: bold;
}

#pass-progress-summary {
  font-size: 18px;
  font-weight: bold;
  color: #ffd700;
  letter-spacing: 0.5px;
}

/* Same visual language as the in-run health/overdrive bars (dark pill,
   bright border, gradient fill) so the Pass's gold progress bar reads as
   part of the same UI system instead of a bolted-on new widget. */
#pass-progress-bar-outer {
  width: 100%;
  max-width: 300px;
  height: 14px;
  background: rgba(0, 0, 0, 0.5);
  border: 2px solid #ffd54f;
  border-radius: 8px;
  overflow: hidden;
}

#pass-progress-bar-inner {
  width: 0%;
  height: 100%;
  background: linear-gradient(90deg, #ffb300, #ffe082);
  transition: width 0.3s ease;
}

#pass-progress-label {
  font-size: 12px;
  opacity: 0.75;
  margin-top: -6px;
}

/* The one overlay with genuinely more content than a phone screen fits (25
   tiers) — every other overlay in the game relies on content just fitting,
   this is the one place that needs a real scroll container. touch-action
   must be set explicitly here since the global `touch-action: none` on body
   is non-inherited and would otherwise block touch-scrolling this list on
   the iOS build. */
.pass-tier-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  max-width: 320px;
  max-height: 42vh;
  overflow-y: auto;
  touch-action: pan-y;
  padding-right: 2px;
  margin-top: 2px;
}

.pass-tier-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  border-left: 4px solid #6b6b6b;
  border-radius: 10px;
  padding: 8px 12px;
  text-align: left;
}

.pass-tier-row.claimable {
  border-left-color: #ffd700;
  background: rgba(255, 215, 0, 0.10);
}

.pass-tier-row.claimed {
  border-left-color: #4caf50;
  opacity: 0.7;
}

/* Unused until a tier actually has premiumReward content (see game.js) —
   styled now so it doesn't need revisiting later. Indented + violet accent
   visually nests it under its free-tier row and marks it as the "other
   track" at a glance. */
.pass-tier-row-premium {
  margin-left: 16px;
  border-left-color: #ab47bc;
  background: linear-gradient(180deg, rgba(171, 71, 188, 0.12) 0%, rgba(171, 71, 188, 0.04) 100%);
}

.pass-tier-row-premium.claimed {
  border-left-color: #4caf50;
}

.pass-tier-icon {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  flex-shrink: 0;
  box-shadow: 0 0 8px 1px currentColor;
}

.pass-tier-reward-label {
  flex: 1;
  font-size: 13px;
  font-weight: bold;
}

.pass-tier-locked {
  font-size: 12px;
  opacity: 0.6;
  font-weight: bold;
  white-space: nowrap;
}

.pass-tier-claimed {
  font-size: 12px;
  color: #81c784;
  font-weight: bold;
  white-space: nowrap;
}

/* Bronze like every other button now — the "this tier is ready" signal
   already lives on the row itself (.pass-tier-row.claimable's gold
   border/background a few rules up), so the button doesn't need to repeat
   it to stay legible as "claimable." */
.overlay .pass-claim-btn {
  --btn-grad: linear-gradient(135deg, #9c8163, #5c4830 60%, #3a2c1c);
  pointer-events: auto;
  min-width: 0;
  padding: 8px 14px;
  font-size: 12px;
  font-weight: bold;
  border-radius: 10px;
  border: 1px solid rgba(255, 213, 130, 0.45);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.32) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 4px 12px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.45),
    inset 0 -2px 4px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
  color: #fff;
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.pass-claim-btn:active {
  transform: scale(0.95);
  filter: brightness(0.92);
}

/* ---------- Settings overlay ---------- */
.settings-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  max-width: 300px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 14px 16px;
}

.settings-label {
  font-size: 15px;
  font-weight: bold;
}

/* .overlay prefix required — a bare class loses to the shared
   ".overlay button" default (class+element beats a bare class), the same
   specificity bug already found and fixed on .class-select-btn/
   .trail-select-btn/.pass-claim-btn earlier this project. */
.overlay .settings-toggle {
  --btn-grad: linear-gradient(135deg, #7ed67f, #43a047 60%, #2e7d32);
  pointer-events: auto;
  min-width: 64px;
  padding: 8px 18px;
  font-size: 13px;
  font-weight: bold;
  border-radius: 20px;
  margin-top: 0;
  border: 1px solid rgba(255, 255, 255, 0.4);
  background:
    linear-gradient(180deg, rgba(255, 255, 255, 0.35) 0%, rgba(255, 255, 255, 0) 50%),
    var(--btn-grad);
  box-shadow:
    0 3px 8px rgba(0, 0, 0, 0.35),
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 -2px 4px rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
  color: #fff;
  cursor: pointer;
  transition: transform 0.1s ease, filter 0.15s ease;
}

.settings-toggle:active {
  transform: scale(0.94);
}

/* "Off" state gets its own muted gray rather than reusing green/red — this
   is a neutral preference toggle, not a success/danger state. */
.settings-toggle.is-off {
  --btn-grad: linear-gradient(135deg, #6b6b6b, #3a3a3a);
}

/* ---------- Achievements overlay ---------- */
.achievement-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  max-width: 320px;
  max-height: 48vh;
  overflow-y: auto;
  touch-action: pan-y; /* same reasoning as .pass-tier-list — the one other overlay with more content than reliably fits */
  margin-top: 2px;
}

.achievement-item {
  display: flex;
  align-items: center;
  gap: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-left: 4px solid #6b6b6b;
  border-radius: 10px;
  padding: 10px 14px;
  text-align: left;
}

.achievement-item.unlocked {
  border-left-color: #ffd700;
  background: rgba(255, 215, 0, 0.08);
}

.achievement-item.locked {
  opacity: 0.6;
}

.achievement-icon {
  font-size: 22px;
  width: 30px;
  text-align: center;
  flex-shrink: 0;
}

.achievement-text {
  flex: 1;
}

.achievement-name {
  font-size: 14px;
  font-weight: bold;
}

.achievement-desc {
  font-size: 12px;
  opacity: 0.75;
  margin-top: 2px;
}

.achievement-check {
  font-size: 16px;
  color: #81c784;
  font-weight: bold;
  flex-shrink: 0;
}

.leaderboard-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 100%;
  max-width: 320px;
  max-height: 48vh;
  overflow-y: auto;
  touch-action: pan-y; /* same reasoning as .achievement-list/.pass-tier-list */
  margin-top: 2px;
}

.leaderboard-row {
  display: flex;
  align-items: center;
  gap: 12px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10) 0%, rgba(255, 255, 255, 0.04) 100%);
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3), inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-radius: 10px;
  padding: 10px 14px;
  text-align: left;
}

.leaderboard-rank {
  font-size: 14px;
  font-weight: bold;
  color: #ffd700;
  width: 34px;
  flex-shrink: 0;
}

.leaderboard-photo {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
}

.leaderboard-photo-placeholder {
  background: rgba(255, 255, 255, 0.15);
}

.leaderboard-name {
  flex: 1;
  font-size: 14px;
  font-weight: bold;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.leaderboard-score {
  font-size: 14px;
  font-weight: bold;
  color: #81c784;
  flex-shrink: 0;
}

.leaderboard-empty {
  opacity: 0.7;
  font-size: 14px;
  text-align: center;
  padding: 20px 0;
}
