* {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #0c0f14;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: #f1f4f8;
}

.hidden {
  display: none !important;
}

#back-link {
  position: fixed;
  top: 0.75rem;
  left: 0.75rem;
  z-index: 30;
  background: rgba(10, 12, 16, 0.65);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 999px;
  padding: 0.45rem 0.9rem;
  font-size: 0.85rem;
  color: #f1f4f8;
  text-decoration: none;
}

#back-link:hover {
  background: rgba(10, 12, 16, 0.85);
}

#game-canvas {
  display: block;
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100vh;
  background: #0c0f14;
  touch-action: none;
}

#menu, #leaderboard-overlay, #matchend-overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at center, rgba(40, 30, 30, 0.6), rgba(6, 8, 12, 0.92));
}

.panel {
  background: rgba(14, 16, 22, 0.78);
  backdrop-filter: blur(16px);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 2rem 2.5rem;
  border-radius: 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
  text-align: center;
  max-width: 440px;
  width: min(90vw, 440px);
  max-height: 90vh;
  overflow-y: auto;
}

.panel h1 {
  margin: 0 0 0.25rem;
  background: linear-gradient(90deg, #ff5a3c, #ffb020);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.tagline {
  margin: 0 0 1.25rem;
  color: #b9c2ce;
  font-size: 0.9rem;
}

#join-status {
  margin-bottom: 1rem;
  font-size: 0.9rem;
  color: #ffcf7a;
}

.controls-list {
  list-style: none;
  margin: 1.25rem 0 0;
  padding: 0;
  text-align: left;
  font-size: 0.8rem;
  color: #c7cfda;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

button.primary {
  width: 100%;
  padding: 0.7rem 1.5rem;
  border: none;
  border-radius: 8px;
  background: linear-gradient(135deg, #ff5a3c, #ffb020);
  color: #17110a;
  font-weight: 700;
  font-size: 1rem;
  cursor: pointer;
  margin-top: 0.5rem;
}

button.primary:hover {
  filter: brightness(1.08);
}

button.primary:disabled {
  opacity: 0.5;
  cursor: default;
  filter: none;
}

/* Big green pill "Play" button — matches the CTA on a Roblox-Rivals-style lobby screen. */
.play-btn {
  width: 100%;
  padding: 0.85rem 1.5rem;
  margin-top: 0.6rem;
  border: none;
  border-radius: 999px;
  background: linear-gradient(180deg, #7bec5a, #35b83a);
  color: #0d2a0a;
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: 0.02em;
  cursor: pointer;
  box-shadow: 0 4px 0 #1f7a22, 0 6px 14px rgba(53, 184, 58, 0.4);
}

.play-btn:hover {
  filter: brightness(1.06);
}

.play-btn:disabled {
  opacity: 0.5;
  cursor: default;
  filter: none;
  box-shadow: none;
}

/* Compact always-visible ranking panel, styled like a lobby's live win-streak/leaderboard widget
   rather than the full-screen leaderboard modal (#leaderboard-overlay), which stays for the
   complete view. */
#top-players-panel {
  margin: 0 0 0.75rem;
  padding: 0.5rem 0.7rem;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  text-align: left;
}

#top-players-title {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: #cfe0f7;
  margin-bottom: 0.3rem;
}

.live-dot {
  font-size: 0.6rem;
  font-weight: 800;
  color: #ff5a5a;
  background: rgba(255, 90, 90, 0.15);
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  letter-spacing: 0.05em;
}

#top-players-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

#top-players-list li {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  color: #e7edf5;
}

#top-players-list .rank {
  color: #a9b4c2;
  margin-right: 0.4rem;
}

/* Progress callout toward the next locked weapon — the screenshot's "Unlock your new weapon!"
   banner, wired to the real fg unlock system rather than a shop prompt. */
#unlock-banner {
  margin: 0 0 0.6rem;
  padding: 0.5rem 0.8rem;
  border-radius: 10px;
  background: linear-gradient(90deg, #ff5a5a, #ff8a3c);
  color: #2a0a04;
  font-weight: 700;
  font-size: 0.85rem;
  text-align: center;
}

.panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}

.panel-header h2 {
  margin: 0;
  font-size: 1.05rem;
  text-align: left;
}

#leaderboard-list {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}

#leaderboard-list li {
  display: flex;
  justify-content: space-between;
  background: rgba(255, 255, 255, 0.05);
  border-radius: 8px;
  padding: 0.4rem 0.7rem;
  font-size: 0.9rem;
}

/* Weapon picker — same button treatment whether it's the menu panel (mouse) or the touch HUD
   strip (fixed, thumb-reachable), so weaponBtnEl() below can build both from one template. */
.weapon-btn {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  padding: 0.5rem 0.8rem;
  margin: 0.2rem;
  border-radius: 10px;
  border: 2px solid rgba(255, 255, 255, 0.18);
  background: rgba(255, 255, 255, 0.06);
  color: #f1f4f8;
  font-size: 0.8rem;
  cursor: pointer;
}

.weapon-btn.active {
  border-color: #ffb020;
  background: rgba(255, 176, 32, 0.18);
  box-shadow: 0 0 12px rgba(255, 176, 32, 0.35);
}

.weapon-btn.locked {
  opacity: 0.5;
  cursor: default;
  border-style: dashed;
}

#spectator-banner {
  position: fixed;
  top: 0.85rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 15;
  background: rgba(10, 12, 16, 0.7);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  padding: 0.4rem 0.9rem;
  font-size: 0.82rem;
  color: #cfe0f7;
}

#hud {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
}

#hud-top {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.8rem;
  padding: 0.75rem 1rem;
}

#scoreboard {
  display: flex;
  align-items: baseline;
  gap: 0.35rem;
  background: rgba(10, 12, 16, 0.6);
  backdrop-filter: blur(8px);
  padding: 0.35rem 0.9rem;
  border-radius: 999px;
  font-weight: 700;
  font-size: 1rem;
}

#score-name-a, #score-name-b {
  font-size: 0.75rem;
  font-weight: 500;
  color: #a9b4c2;
  max-width: 8ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#score-a, #score-b {
  font-size: 1.15rem;
}

#score-sep {
  color: #a9b4c2;
}

#round-timer {
  background: rgba(10, 12, 16, 0.6);
  backdrop-filter: blur(8px);
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  min-width: 3rem;
  text-align: center;
}

#leaderboard-btn {
  pointer-events: auto;
  position: absolute;
  right: 1rem;
}

#health-wrap {
  position: fixed;
  bottom: 6.4rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

#health-bar {
  width: min(46vw, 280px);
  height: 14px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.22);
  overflow: hidden;
}

#health-fill {
  height: 100%;
  width: 100%;
  background: linear-gradient(90deg, #35d07f, #9dffc9);
  transition: width 0.15s ease-out, background 0.2s;
}

#health-fill.low {
  background: linear-gradient(90deg, #e0263f, #ff8a5c);
}

#health-num {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  min-width: 2.4rem;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.6);
}

#weapon-hud {
  position: fixed;
  bottom: 1.1rem;
  right: 1.1rem;
  z-index: 10;
  background: rgba(10, 12, 16, 0.6);
  backdrop-filter: blur(8px);
  padding: 0.4rem 0.8rem;
  border-radius: 10px;
  font-size: 0.85rem;
}

#kill-feed {
  position: fixed;
  top: 4.2rem;
  right: 1rem;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.3rem;
  max-width: 60vw;
}

.kill-feed-entry {
  background: rgba(10, 12, 16, 0.6);
  padding: 0.3rem 0.7rem;
  border-radius: 8px;
  font-size: 0.78rem;
  animation: kf-fade 3.5s ease-out forwards;
}

@keyframes kf-fade {
  0% { opacity: 0; transform: translateY(-6px); }
  10% { opacity: 1; transform: translateY(0); }
  80% { opacity: 1; }
  100% { opacity: 0; }
}

#round-banner {
  position: fixed;
  top: 34%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 16;
  font-size: 1.6rem;
  font-weight: 800;
  text-align: center;
  text-shadow: 0 2px 10px rgba(0, 0, 0, 0.8);
  pointer-events: none;
  animation: round-banner-fade 2.2s ease-out forwards;
}

@keyframes round-banner-fade {
  0% { opacity: 0; transform: translate(-50%, -60%); }
  15% { opacity: 1; transform: translate(-50%, -50%); }
  80% { opacity: 1; }
  100% { opacity: 0; }
}

#damage-flash {
  position: fixed;
  inset: 0;
  z-index: 15;
  pointer-events: none;
  background: radial-gradient(circle, rgba(224, 30, 30, 0) 55%, rgba(224, 30, 30, 0.45) 100%);
  opacity: 0;
}

#damage-flash.show {
  animation: damage-pulse 0.5s ease-out;
}

@keyframes damage-pulse {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

/* Held (not one-shot like #damage-flash above) urgency cue while health is low — toggled by
   renderHealth() in firefight.js at the same 30% threshold the health bar itself already turns
   red at, so the two read as one consistent "you're in danger" signal rather than two thresholds
   a player would have to learn separately. */
#low-health-vignette {
  position: fixed;
  inset: 0;
  z-index: 14;
  pointer-events: none;
  background: radial-gradient(circle, rgba(190, 20, 20, 0) 60%, rgba(190, 20, 20, 0.5) 100%);
  opacity: 0;
}

#low-health-vignette.show {
  animation: low-health-pulse 1.4s ease-in-out infinite;
}

@keyframes low-health-pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.75; }
}

.icon-btn {
  background: rgba(255, 255, 255, 0.1);
  border: none;
  color: inherit;
  font-size: 1.1rem;
  min-width: 44px;
  min-height: 44px;
  padding: 0.3rem 0.6rem;
  border-radius: 8px;
  cursor: pointer;
}

.icon-btn:hover {
  background: rgba(255, 255, 255, 0.2);
}

#crosshair {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 12px;
  margin: -6px 0 0 -6px;
  z-index: 9;
  pointer-events: none;
}

#crosshair::before, #crosshair::after {
  content: '';
  position: absolute;
  background: rgba(255, 255, 255, 0.9);
  box-shadow: 0 0 3px rgba(0, 0, 0, 0.8);
}

#crosshair::before {
  left: 50%;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
}

#crosshair::after {
  top: 50%;
  left: 0;
  right: 0;
  height: 2px;
  margin-top: -1px;
}

#crosshair.fired {
  animation: crosshair-kick 0.12s ease-out;
}

@keyframes crosshair-kick {
  0% { transform: scale(1.6); opacity: 0.6; }
  100% { transform: scale(1); opacity: 1; }
}

/* Found by the Firefight client-correctness audit: a shot attempt blocked by the weapon's own
   cooldown returned silently -- no sound, no crosshair change, nothing -- reading as unresponsive
   input rather than "still reloading," most noticeable on the grenade's 3.2s cooldown. Animates
   (rather than a plain color swap left in place) so it self-resolves back to normal the same way
   .fired's kick above does, without needing JS to remove the class again afterward. */
#crosshair.denied::before, #crosshair.denied::after {
  animation: crosshair-denied 0.35s ease-out;
}

@keyframes crosshair-denied {
  0% { background: rgba(255, 70, 70, 0.95); }
  100% { background: rgba(255, 255, 255, 0.9); }
}

/* Confirmed-hit feedback — separate from #crosshair's fire-kick above, which fires on every shot
   regardless of whether it lands. This only shows once fg-hit/fg-death actually confirms the
   shooter's own shot connected, so it needed its own element rather than reusing the crosshair's. */
#hit-marker {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  z-index: 9;
  pointer-events: none;
  opacity: 0;
}

#hit-marker::before, #hit-marker::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 0;
  right: 0;
  height: 3px;
  margin-top: -1.5px;
  background: #fff;
  box-shadow: 0 0 4px rgba(0, 0, 0, 0.9);
}

#hit-marker::before { transform: rotate(45deg); }
#hit-marker::after { transform: rotate(-45deg); }

#hit-marker.show {
  animation: hit-marker-pop 0.28s ease-out;
}

#hit-marker.headshot::before, #hit-marker.headshot.show::before,
#hit-marker.headshot::after, #hit-marker.headshot.show::after {
  background: #ff5a3c;
}

@keyframes hit-marker-pop {
  0% { opacity: 1; transform: scale(1.5); }
  60% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1); }
}

/* Sniper aim-down-sights vignette — the FOV zoom (see updateFov in firefight.js) already narrows
   the view; this adds the scope's actual visual read: a hard-edged dark ring around a clear
   center circle, with the scope's own crosshair drawn on top since the normal #crosshair reads
   as too small/plain once zoomed in this far. */
#scope-overlay {
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  background: radial-gradient(circle at center, transparent 0, transparent 29vh, #05060a 29.6vh);
}

#scope-overlay::before, #scope-overlay::after {
  content: '';
  position: fixed;
  top: 50%;
  left: 50%;
  background: rgba(20, 24, 20, 0.85);
}

#scope-overlay::before {
  width: 1px;
  height: 60vh;
  margin-left: -0.5px;
  margin-top: -30vh;
}

#scope-overlay::after {
  width: 60vh;
  height: 1px;
  margin-top: -0.5px;
  margin-left: -30vh;
}

/* Touch controls (mobile) */
#touch-controls {
  position: fixed;
  inset: 0;
  z-index: 12;
  pointer-events: none;
}

#touch-controls.hidden {
  display: none;
}

#touch-joystick {
  position: absolute;
  left: 22px;
  bottom: 22px;
  width: 110px;
  height: 110px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  border: 2px solid rgba(255, 255, 255, 0.25);
  pointer-events: auto;
  touch-action: none;
}

#touch-joystick-knob {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 46px;
  height: 46px;
  margin: -23px 0 0 -23px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.35);
  border: 2px solid rgba(255, 255, 255, 0.55);
}

#touch-jump {
  position: absolute;
  left: 148px;
  bottom: 96px;
  pointer-events: auto;
}

#touch-weapon-buttons {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  gap: 8px;
  pointer-events: auto;
}

#touch-fire-buttons {
  position: absolute;
  right: 18px;
  bottom: 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  pointer-events: auto;
}

.touch-btn {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 2px solid rgba(255, 255, 255, 0.25);
  color: #f1f4f8;
  font-size: 1.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  padding: 0;
}

#touch-fire {
  width: 76px;
  height: 76px;
  background: rgba(255, 90, 60, 0.3);
  border-color: rgba(255, 90, 60, 0.6);
}

.touch-btn:active {
  background: rgba(255, 255, 255, 0.3);
}

/* Fists/grenade have no ADS at all (see ADS_FOV in firefight.js) — pressing the aim button while
   either is equipped does nothing, which on a touch screen (no cursor/right-click affordance to
   make that obvious the way desktop's mouse button does) reads as broken rather than "this weapon
   just doesn't aim". Dimmed rather than hidden so the button doesn't jump around the layout on
   every weapon switch. */
#touch-aim.unavailable {
  opacity: 0.35;
}
