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

html,
body {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #10141a;
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  color: #f0f2f5;
}

#app {
  position: relative;
  width: 100vw;
  height: 100vh;
  /* On mobile, 100vh includes the area behind the retractable toolbars, which
     pushes the canvas centre (and the truck) below the visible middle. dvh
     tracks the actually-visible viewport instead. */
  height: 100dvh;
}

#game-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* Steering is a press-and-drag on the canvas, so suppress the browser's own
     touch gestures (scroll/zoom) here - but only here, so the menu screens can
     still scroll on small viewports. */
  touch-action: none;
}

.screen {
  position: absolute;
  inset: 0;
  display: flex;
  /* Scroll when the panel is taller than the viewport (small/mobile screens).
     Centering is done with margin:auto on the panel rather than
     align-items/justify-content:center, because a flex item centered that way
     gets clipped and can't be scrolled to its top when it overflows. */
  overflow-y: auto;
  padding: 16px;
  background: rgba(10, 13, 18, 0.72);
  backdrop-filter: blur(3px);
  z-index: 10;
}

.screen.hidden {
  display: none;
}

.panel {
  margin: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 28px 32px;
  background: #1c222b;
  border: 1px solid #2c3542;
  border-radius: 14px;
  max-width: 420px;
  width: 100%;
  text-align: center;
}

/* Titles on the results and help panels (the home panel uses a compact
   wordmark instead of an h1). */
.panel h1 {
  font-size: 1.6rem;
  letter-spacing: 0.02em;
}

.hidden {
  display: none;
}

#results-medal {
  font-size: 1.15rem;
  font-weight: 700;
  margin-top: -4px;
}

.muted {
  color: #9aa4b2;
  font-size: 0.9rem;
}

#retry-hint {
  font-size: 0.75rem;
  margin-top: -8px;
}

#thumbnail-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  /* Let the browser keep vertical page scroll, but reserve horizontal drags
     for our swipe-to-navigate handler. */
  touch-action: pan-y;
}

.nav-arrow {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  line-height: 1;
  color: #f0f2f5;
  background: #2c3542;
  border: none;
  border-radius: 50%;
  cursor: pointer;
}

.nav-arrow:hover:not(:disabled) {
  background: #3a4554;
}

.nav-arrow:disabled {
  opacity: 0.3;
  cursor: default;
}

/* Element-specific override: .nav-arrow sets display:flex, which would beat the
   shared .hidden rule on source order alone. Hidden for brand-new players. */
.nav-arrow.hidden {
  display: none;
}

/* The map thumbnail is a mini carousel: a fixed-size viewport that clips a
   wider track of three side-by-side maps (previous / current / next). Only the
   middle one shows at rest; dragging slides the track so the neighbour peeks in,
   then it snaps to the chosen map. */
#minimap-viewport {
  flex: 1;
  min-width: 0;
  max-width: 300px;
  border-radius: 8px;
  border: 1px solid #2c3542;
  overflow: hidden;
  background: #1c222b;
  cursor: pointer;
  /* Reserve horizontal drags for the carousel while leaving vertical page
     scroll to the browser. */
  touch-action: pan-y;
}

#minimap-viewport:hover,
#minimap-viewport:focus-within {
  border-color: #4a5566;
}

#minimap-track {
  display: flex;
  width: 300%;
  /* Gutter between adjacent maps, revealed as one slides in during a swipe.
     Keep in sync with CAROUSEL_GAP in main.ts. */
  gap: 10px;
  /* At rest the middle of the three maps fills the viewport - shifted an extra
     gap's width so the gutter sits off-screen and the current map is flush. */
  transform: translateX(calc(-33.3333% - 10px));
  will-change: transform;
  touch-action: pan-y;
}

/* Only animate when snapping to a map after a drag - live dragging tracks the
   finger with no transition. */
#minimap-track.snapping {
  transition: transform 260ms ease-out;
}

.minimap-thumb {
  flex: 0 0 33.3333%;
  width: 33.3333%;
  height: auto;
  display: block;
}

.minimap-thumb:hover,
.minimap-thumb:focus-visible {
  opacity: 0.92;
}

/* Header row: the title stays centered across the full panel width while the
   round "?" help button rides at the right edge, vertically centered on the
   title (absolute so it doesn't shove the title down or off-center). */
#home-header {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
}

#profile-btn {
  position: absolute;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
}

/* Centered game title in the display face, with generous tracking. Sized with
   clamp so it fills desktop but never overflows the narrow mobile panel. */
.wordmark {
  font-family: "Righteous", system-ui, sans-serif;
  font-size: clamp(1.15rem, 6vw, 1.85rem);
  font-weight: 400;
  letter-spacing: 0.1em;
  padding-left: 0.1em;
  /* balance the trailing letter-spacing so it stays centered */
  color: #f0f2f5;
  text-align: center;
}

#profile-btn {
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 50%;
  font-size: 1rem;
  font-weight: 400;
  line-height: 1;
}

.profile-panel {
  max-width: 420px;
}

.settings-section {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.section-header {
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #9aa4b2;
}

.section-divider {
  width: 100%;
  border: none;
  border-top: 1px solid #2c3542;
  margin: 6px 0;
}

.sound-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}

.sound-label {
  font-size: 0.85rem;
  min-width: 70px;
}

.sound-row input[type="range"] {
  flex: 1;
  min-width: 0;
}

.sound-value {
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  min-width: 36px;
  text-align: right;
  color: #9aa4b2;
}

/* Diagnostic line: says whether the browser actually let the audio engine
   start, so "no sound" can be told apart from "everything muted". */
.sound-status {
  font-size: 0.75rem;
  color: #6b7482;
  margin-top: 6px;
}

.sound-status.blocked {
  color: #f2a541;
}

.sound-mute-btn {
  background: none;
  border: none;
  padding: 0;
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.15s;
  flex-shrink: 0;
  width: 24px;
  text-align: center;
}

.sound-mute-btn:hover {
  opacity: 1;
}

.sound-mute-btn.muted {
  opacity: 0.35;
}

.stats-grid {
  width: 100%;
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  font-size: 0.88rem;
}

.stats-grid .stat-label {
  color: #9aa4b2;
  text-align: left;
}

.stats-grid .stat-value {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.stats-grid .stat-medals {
  grid-column: 1 / -1;
  display: flex;
  justify-content: center;
  gap: 10px;
  padding-top: 2px;
}

.stats-grid .stat-medals .medal-count {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 0.85rem;
}

#stats-difficulty-switch {
  margin-top: 4px;
}



.sync-desc {
  font-size: 0.82rem;
  margin-top: -4px;
}

#sync-unlinked {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
}

#sync-link-row {
  display: flex;
  gap: 8px;
  width: 100%;
  max-width: 260px;
}

#sync-link-input {
  flex: 1;
  min-width: 0;
  padding: 6px 10px;
  font-size: 0.9rem;
  font-family: monospace;
  letter-spacing: 0.12em;
  text-align: center;
  color: #f0f2f5;
  background: #10141a;
  border: 1px solid #2c3542;
  border-radius: 6px;
}

#sync-link-input:focus {
  outline: none;
  border-color: #4a5566;
}

#sync-linked {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  width: 100%;
}

#sync-linked.hidden {
  display: none;
}

#sync-code-display {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 16px;
  background: #10141a;
  border: 1px solid #2c3542;
  border-radius: 8px;
}

.sync-label {
  font-size: 0.78rem;
}

#sync-code-value {
  font-family: monospace;
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.18em;
  color: #55e08a;
}

#sync-copy-btn {
  padding: 4px 12px;
  font-size: 0.78rem;
}

#sync-status {
  font-size: 0.8rem;
}

#sync-now-btn {
  width: 100%;
  max-width: 200px;
}

.sync-unlink {
  font-size: 0.78rem;
  padding: 4px 14px;
  color: #9aa4b2;
  background: transparent;
}

.sync-unlink:hover {
  color: #ff6f6f;
}

.sync-error {
  font-size: 0.82rem;
  color: #ff6f6f;
}

.sync-error.hidden {
  display: none;
}

/* Daily/Weekly switch, revealed at the very bottom only once the player has
   earned gold (see updateModeSwitchVisibility) - a "bigger challenge" unlock. */
#mode-switch {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin-top: 4px;
}

#mode-switch.hidden {
  display: none;
}

#mode-cta {
  font-size: 0.85rem;
  color: #c3cad4;
}

/* Shared pill-toggle look: the Daily/Weekly switch (#mode-toggle) and the
   Easy/Hard switch (.mode-toggle, under the Tutorial/How To buttons) render
   identically - same shape, same active/inactive button styling below. */
#mode-toggle,
.mode-toggle {
  display: flex;
  gap: 4px;
  padding: 4px;
  background: #10141a;
  border: 1px solid #2c3542;
  border-radius: 999px;
}

.mode-btn {
  padding: 6px 20px;
  font-size: 0.85rem;
  font-weight: 600;
  color: #9aa4b2;
  background: transparent;
  border-radius: 999px;
}

.mode-btn.active {
  color: #10141a;
  background: #f0f2f5;
}

#progress-strip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
}

#progress-strip.hidden {
  display: none;
}

/* Medal + personal-best times as a row of small rounded tiles (fastest first). */
#medal-track {
  display: flex;
  flex-direction: row;
  justify-content: center;
  gap: 6px;
  width: 100%;
}

.medal-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  flex: 1 1 0;
  min-width: 0;
  max-width: 72px;
  padding: 6px 4px;
  background: #10141a;
  border: 1px solid #2c3542;
  border-radius: 8px;
  position: relative; /* anchors the PB chip's inner-glow ::after */
  /* Resting colour glow, same "r,g,b"-triple system as the streak dots; --glow
       is set per chip in renderMedalTrack. */
    box-shadow: 0 0 4px 1px rgba(var(--glow), 0.55);
  }
  
  /* A PB slower than every medal: a fainter bluish-grey glow (colour from --glow),
     overriding the standard resting intensity above. */
  .medal-chip.glow-faint {
    box-shadow: 0 0 4px 1px rgba(var(--glow), 0.55);
  }
  
  /* Single pulse on hover - same flourish and timing as the streak dots. Toggled
     from JS (see renderMedalTrack) so it always completes. The faint chips pulse
     at their lower intensity so there's no brightness jump. */
  .medal-chip.pulsing {
    animation: medal-pulse 0.9s ease-out;
  }
  
  .medal-chip.glow-faint.pulsing {
    animation: medal-pulse-faint 0.9s ease-out;
  }
  
  @keyframes medal-pulse-faint {
    0% {
      box-shadow: 0 0 4px 1px rgba(var(--glow), 0.32);
    }
  
    35% {
      box-shadow: 0 0 9px 3px rgba(var(--glow), 0.6);
    }
  
    100% {
      box-shadow: 0 0 4px 1px rgba(var(--glow), 0.32);
    }
}

.medal-chip-icon {
  font-size: 1.1rem;
  line-height: 1;
}

.medal-chip-name {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #9aa4b2;
}

.medal-chip-time {
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  color: #c3cad4;
}

/* The PB chip doubles as the "race my PB ghost" switch, so it's clickable. */
.medal-chip.pb-chip {
  cursor: pointer;
}

/* While the PB ghost is on, a fixed whitish-gold inner glow marks it selected.
   It's on a pseudo-element (not the chip's own box-shadow) so the hover pulse -
   which animates that box-shadow - can't wipe it. */
.medal-chip.pb-chip.active::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 10px 1px rgba(255, 238, 195, 0.9);
  pointer-events: none;
}

.medal-chip.pb-chip:focus-visible {
  outline: 2px solid #4a5566;
  outline-offset: 2px;
}

/* Transient "Ghost enabled/disabled" message shown inside the PB chip on toggle
   (in place of the icon/name/time, vertically centred). */
.medal-chip.flashing {
  justify-content: center;
}

.medal-chip-flash {
  font-size: 0.62rem;
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  color: #f0e6c8;
}

#streak-badge {
  font-size: 0.85rem;
  font-weight: 700;
  color: #f0a24a;
  white-space: nowrap;
}

#streak-badge:empty {
  display: none;
}

#day-dots {
  display: flex;
  gap: 5px;
}

.day-dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: #2c3542;
  border: 1px solid #3a4554;
}

/* Each dot is tinted by the best medal earned that day; no medal stays gray.
   Every medal carries a small resting glow in its own colour (via --glow, an
   "r, g, b" triple) and pulses once, brighter, on hover - a light, replayable
   flourish rather than a constant animation. */
.day-dot.medal-bronze,
.day-dot.medal-silver,
.day-dot.medal-gold,
.day-dot.medal-champion {
  box-shadow: 0 0 4px 1px rgba(var(--glow), 0.55);
}

.day-dot.medal-bronze {
  background: #c17a3f;
  border-color: #d99457;
  --glow: 217, 148, 87;
}

.day-dot.medal-silver {
  background: #c3ccd6;
  border-color: #e2e8ef;
  --glow: 226, 232, 239;
}

.day-dot.medal-gold {
  background: #f2c14e;
  border-color: #ffd873;
  --glow: 255, 216, 115;
}

/* Champion: rose-gold, a touch stronger resting glow than the others. */
.day-dot.medal-champion {
  background: #e7a7a0;
  border-color: #f4cabb;
  box-shadow: 0 0 5px 1px rgba(231, 167, 160, 0.75);
  --glow: 244, 202, 187;
}

/* A single pulse (ending back at the resting glow), driven by JS: mouse-enter
   adds .pulsing, and it's removed on animationend so the pulse always runs to
   completion even if the pointer has already left, and can fire again next
   entry. --glow is on the same element (the medal class), so one rule covers
   every colour. */
.day-dot.pulsing {
  animation: medal-pulse 0.9s ease-out;
}

@keyframes medal-pulse {
  0% {
    box-shadow: 0 0 4px 1px rgba(var(--glow), 0.55);
  }

  35% {
    box-shadow: 0 0 10px 4px rgba(var(--glow), 0.95);
  }

  100% {
    box-shadow: 0 0 4px 1px rgba(var(--glow), 0.55);
  }
}

@media (prefers-reduced-motion: reduce) {
.day-dot.pulsing,
  .medal-chip.pulsing {
    animation: none;
  }
}

.hint {
  font-size: 0.85rem;
  line-height: 1.5;
  color: #c3cad4;
}

.help-panel {
  max-width: 460px;
}

.help-body {
  width: 100%;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 0.9rem;
  line-height: 1.5;
  color: #c3cad4;
}

/* .help-body's display:flex would otherwise beat the shared .hidden rule
   (same specificity, defined later), so the hidden body still showed. */
.help-body.hidden {
  display: none;
}

/* Summary/Full switch above the help body. */
.detail-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
  user-select: none;
  font-size: 0.85rem;
}

.detail-switch input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.detail-switch-label {
  color: #8b95a3;
  transition: color 0.15s;
}

/* Emphasise whichever side is active: left (Summary) when unchecked, right
   (Full) when checked. */
.detail-switch:has(input:not(:checked)) .detail-switch-label:first-of-type,
.detail-switch:has(input:checked) .detail-switch-label:last-of-type {
  color: #f0f2f5;
  font-weight: 600;
}

.detail-switch-track {
  position: relative;
  flex: none;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  background: #2c3542;
  border: 1px solid #3a4453;
  transition: background 0.15s;
}

.detail-switch-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: #c3cad4;
  transition: transform 0.15s;
}

.detail-switch input:checked~.detail-switch-track {
  background: #3a4a63;
}

.detail-switch input:checked~.detail-switch-track .detail-switch-knob {
  transform: translateX(18px);
  background: #f0f2f5;
}

.detail-switch input:focus-visible~.detail-switch-track {
  border-color: #4a5566;
  box-shadow: 0 0 0 2px rgba(74, 85, 102, 0.6);
}

.help-body strong {
  color: #f0f2f5;
}

.help-body ul {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.tag {
  display: inline-block;
  padding: 0 6px;
  border-radius: 4px;
  font-weight: 700;
  color: white;
}

.tag-pickup {
  background: hsl(2 72% 50%);
}

.tag-destination {
  background: hsl(140 55% 38%);
}

/* Background + text color are set inline via JS from today's actual palette
 * (road/grass/mud/rock hues are seeded per day), so only shared box styling
 * lives here. */
.terrain-tag {
  display: inline-block;
  padding: 0 6px;
  border-radius: 4px;
  font-weight: 700;
}

#nickname-row {
  width: 100%;
}

#nickname-input {
  flex: 1;
  min-width: 0;
  padding: 6px 10px;
  font-size: 0.9rem;
  color: #f0f2f5;
  background: #10141a;
  border: 1px solid #2c3542;
  border-radius: 6px;
}

#nickname-input:focus {
  outline: none;
  border-color: #4a5566;
}

#leaderboard {
  width: 100%;
}

.leaderboard-header {
  font-size: 0.75rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #9aa4b2;
  margin-bottom: 6px;
  text-align: left;
}

#leaderboard-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  list-style: none;
  max-height: 180px;
  overflow-y: auto;
}

.leaderboard-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 8px;
  border-radius: 6px;
  font-size: 0.85rem;
  cursor: pointer;
}

.leaderboard-row:hover {
  background: rgba(255, 255, 255, 0.06);
}

.leaderboard-row.self {
  background: rgba(255, 255, 255, 0.08);
  font-weight: 700;
}

.leaderboard-row.selected {
  outline: 1px solid #4a5566;
}

/* The solver's pinned "Optimal" row: a faint gold tint + glow so it reads as the
   benchmark target time rather than an ordinary competitor. */
.leaderboard-row.optimal {
  background: linear-gradient(90deg, rgba(255, 216, 115, 0.16), rgba(255, 216, 115, 0.04));
  outline: 1px solid rgba(255, 216, 115, 0.4);
  font-weight: 700;
  cursor: default;
}

/* In watch mode the Optimal row is a pickable racer, so it takes a pointer. */
.leaderboard-row.optimal.pickable {
  cursor: pointer;
}

.leaderboard-row.optimal .leaderboard-rank,
.leaderboard-row.optimal .leaderboard-time {
  color: #ffd873;
}

.leaderboard-rank {
  width: 1.6em;
  color: #9aa4b2;
  text-align: right;
}

.leaderboard-nickname {
  flex: 1;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.leaderboard-time {
  font-variant-numeric: tabular-nums;
  color: #c3cad4;
}

.leaderboard-empty {
  font-size: 0.8rem;
  color: #6b7480;
}

/* Small checkbox on each leaderboard row while in "Watch" pick mode. */
.leaderboard-check {
  flex: none;
  width: 16px;
  height: 16px;
  border: 1.5px solid #6b7480;
  border-radius: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  line-height: 1;
  color: #12161c;
}

.leaderboard-row.picked .leaderboard-check {
  background: #55e08a;
  border-color: #55e08a;
}

.leaderboard-row.picked {
  background: rgba(85, 224, 138, 0.12);
}

/* A row that can't be picked (the 5-racer cap is reached and it isn't already
   selected) reads as inert. */
.leaderboard-row.pick-disabled {
  opacity: 0.45;
  cursor: default;
}

/* --- Replay selection controls (under the leaderboard) -------------------- */
#replay-controls {
  margin-top: 10px;
}

#watch-btn {
  width: 100%;
}

#watch-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

#replay-select-bar {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* id specificity would otherwise beat the shared .hidden rule. */
#replay-select-bar.hidden {
  display: none;
}

#replay-select-count {
  font-size: 0.8rem;
  color: #9aa4b2;
  text-align: right;
}

#replay-select-actions {
  display: flex;
  gap: 10px;
}

#replay-select-actions button {
  flex: 1;
  padding: 8px 0;
}

/* --- Replay player (video-style bar over the canvas) --------------------- */
#replay-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9;
  display: flex;
  justify-content: center;
  padding: 14px;
  pointer-events: none;
}

#replay-overlay.hidden {
  display: none;
}

#replay-bar {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  max-width: 640px;
  padding: 10px 14px;
  background: rgba(22, 27, 34, 0.92);
  border: 1px solid #4a5566;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
}

#replay-play-btn {
  flex: none;
  width: 42px;
  height: 38px;
  padding: 0;
  font-size: 0.85rem;
  line-height: 1;
}

.replay-time {
  flex: none;
  font-size: 0.8rem;
  font-variant-numeric: tabular-nums;
  color: #c3cad4;
  min-width: 84px;
  text-align: center;
}

#replay-progress {
  flex: 1;
  /* Without this, the range keeps its intrinsic ~130px min-width (flex items
     default to min-width:auto) and can't shrink, overflowing the bar on narrow
     phones and pushing the Stop button off-screen. */
  min-width: 0;
  height: 6px;
  cursor: pointer;
  accent-color: #55e08a;
}

/* Keep Stop compact so the whole bar fits a phone width. */
#replay-stop-btn {
  flex: none;
  padding: 9px 16px;
}

/* Tighten the bar further on small screens. */
@media (max-width: 420px) {
  #replay-overlay {
    padding: 10px;
  }

  #replay-bar {
    gap: 8px;
    padding: 8px 10px;
  }

  .replay-time {
    min-width: 0;
    font-size: 0.72rem;
  }

  #replay-stop-btn {
    padding: 9px 12px;
  }
}

button {
  padding: 10px 28px;
  font-size: 1rem;
  font-weight: 600;
  color: #10141a;
  background: #f0f2f5;
  border: none;
  border-radius: 8px;
  cursor: pointer;
}

button:active {
  transform: scale(0.97);
}

#results-actions {
  display: flex;
  gap: 10px;
}

.btn-secondary {
  color: #f0f2f5;
  background: #2c3542;
}

#countdown-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 8;
  pointer-events: none;
}

#countdown-overlay.hidden {
  display: none;
}

#countdown-text {
  font-size: 6rem;
  font-weight: 800;
  color: #f0f2f5;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.7);
  /* Nudged down from dead-center so it doesn't sit on top of the truck,
     which is centered on screen and needs to stay visible (heading/direction
     matters even while frozen during the countdown). */
  margin-top: 18vh;
}

#hud {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 14px 18px;
  pointer-events: none;
  z-index: 5;
  font-variant-numeric: tabular-nums;
}

#hud.hidden {
  display: none;
}

#hud-left {
  display: flex;
  flex-direction: column;
  gap: 2px;
  /* Clear the absolutely-positioned menu button in the top-left corner. */
  margin-left: 46px;
}

/* Hamburger menu (mainly for touch devices, which have no Backspace/Esc). Same
   light-on-dark contrast as the bottom timer. */
#menu-btn {
  position: absolute;
  top: 12px;
  left: 12px;
  width: 40px;
  height: 40px;
  padding: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  background: rgba(255, 255, 255, 0.75);
  border-radius: 8px;
  pointer-events: auto;
  z-index: 6;
}

#menu-btn span {
  display: block;
  width: 20px;
  height: 2.5px;
  border-radius: 2px;
  background: #000;
}

#menu-overlay {
  position: absolute;
  top: 58px;
  left: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 8px;
  background: rgba(255, 255, 255, 0.85);
  border-radius: 8px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  pointer-events: auto;
  z-index: 6;
}

#menu-overlay.hidden {
  display: none;
}

#menu-overlay button {
  padding: 8px 22px;
  font-size: 0.9rem;
  color: #000;
  background: rgba(0, 0, 0, 0.06);
  border-radius: 6px;
}

#menu-overlay button:hover {
  background: rgba(0, 0, 0, 0.12);
}

#hud-pb {
  font-size: 0.8rem;
  color: #c3cad4;
  text-shadow: 0 1px 4px rgba(0, 0, 0, 0.6);
}

#hud-objective {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.95rem;
  font-weight: 600;
  background: rgba(0, 0, 0, 0.4);
  padding: 4px 12px;
  border-radius: 6px;
}

/* "Paused" status banner, shown near the top-center under the objective while
   the game is frozen. Purely informational (the bottom timer is the control). */
#pause-indicator {
  position: absolute;
  top: 52px;
  left: 50%;
  transform: translateX(-50%);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #12161c;
  background: rgba(255, 214, 91, 0.92);
  padding: 6px 18px;
  border-radius: 8px;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.4);
  z-index: 6;
}

#pause-indicator.hidden {
  display: none;
}

#hud-timer-wrap {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
}

/* The timer doubles as the pause/resume button. It's a real <button> so tap
   (mobile) and keyboard both work; these resets keep it looking like the old
   readout rather than a native button. */
#hud-timer {
  font-family: inherit;
  font-size: 1.4rem;
  font-weight: 700;
  color: #000;
  background: rgba(255, 255, 255, 0.75);
  padding: 4px 14px;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  pointer-events: auto;
  /* Keep a tap from selecting the digits or flashing a tap-highlight on mobile. */
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Paused look: amber to match the top banner, so the control reads as "engaged". */
#hud-timer.paused {
  background: rgba(255, 214, 91, 0.92);
}

/* Live split time vs the raced ghost. Empty (no class) when there's no ghost or
   no checkpoint reached yet - padding lives on the state classes so the empty
   element takes no space. */
#hud-delta {
  font-size: 1rem;
  font-weight: 700;
}

#hud-delta.ahead,
#hud-delta.behind {
  padding: 2px 10px;
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.5);
}

#hud-delta.ahead {
  color: #55e08a;
}

#hud-delta.behind {
  color: #ff6f6f;
}

/* Tutorial + How-to-play sit side by side under the medal track. */
/* Primary call-to-action: full-width so it reads as the obvious way to start a
   run (reviewers didn't realise tapping the map starts the game). */
#play-btn {
  width: 100%;
  padding: 12px;
  font-size: 1.05rem;
}

/* Easy/Hard switch, directly under the Tutorial/How To row - hidden until the
   player has finished a run in either mode (see updateDifficultySwitchVisibility),
   and hidden outright in weekly mode (Weekly is Hard-only). */
#difficulty-switch {
  display: flex;
  justify-content: center;
  width: 100%;
  margin-top: 4px;
}

#difficulty-switch.hidden {
  display: none;
}

/* Tutorial + How To sit side by side, directly under Play. */
#home-actions {
  display: flex;
  gap: 8px;
  width: 100%;
}

#home-actions .btn-secondary {
  flex: 1 1 0;
}

/* The nickname field at the bottom, separated from the leaderboard by a
   hairline. */
#home-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  width: 100%;
  margin-top: 4px;
  padding-top: 16px;
  border-top: 1px solid #2c3542;
}

/* --- New-player tutorial coach overlay ------------------------------------
   Full-screen, but transparent to pointer events so pressing/holding anywhere
   still steers the truck through the canvas beneath; only the action buttons
   opt back into being clickable. */
#tutorial-overlay {
  position: absolute;
  inset: 0;
  z-index: 9;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  padding: 16px;
  pointer-events: none;
}

#tutorial-overlay.hidden {
  display: none;
}

#tutorial-banner {
  width: 100%;
  max-width: 540px;
  margin-top: 10px;
  padding: 15px 20px 18px;
  text-align: center;
  background: rgba(22, 27, 34, 0.92);
  border: 1px solid #4a5566;
  border-radius: 12px;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(4px);
  /* The card is see-through to pointers so holds over it still reach the canvas;
     the buttons below re-enable their own pointer events. */
  pointer-events: none;
}

#tutorial-badge {
  display: inline-block;
  margin-bottom: 9px;
  padding: 3px 11px;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #10141a;
  background: #55e08a;
  border-radius: 999px;
}

/* The coach text is one string with a newline between paragraphs, so pre-line
   turns those into visible paragraph breaks without building any DOM.
   Text past 40% of the viewport height scrolls inside this element rather than
   growing the card: that keeps the game visible below it on a phone, and keeps
   the buttons (which sit outside this box, so they never count towards the 40%)
   on screen no matter how long an explanation runs. */
#tutorial-prompt {
  max-height: 40vh;
  overflow-y: auto;
  overscroll-behavior: contain;
  font-size: 1.05rem;
  line-height: 1.45;
  white-space: pre-line;
  color: #f0f2f5;
}

/* While an 'explain' part is up the game is paused, so nothing is being steered
   through the card and it can take pointer events - which is what lets a long
   explanation be scrolled on a short screen. */
#tutorial-overlay.explaining #tutorial-banner {
  pointer-events: auto;
}

/* Seconds left in a timed section, shown only while one is being played. */
#tutorial-timer {
  margin-top: 10px;
  font-size: 0.95rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: #ffd166;
}

#tutorial-timer.hidden {
  display: none;
}

#tutorial-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 15px;
}

#tutorial-actions button {
  padding: 9px 22px;
  pointer-events: auto;
}