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

html, body, #app {
  width: 100%;
  height: 100%;
  overflow: hidden;
  background: #111;
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
}

canvas {
  display: block;
}

#hud {
  position: fixed;
  inset: 0;
  pointer-events: none;
  color: #fff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.8);
  user-select: none;
}

#hud .panel {
  position: absolute;
  pointer-events: auto;
}

#hud-aim {
  bottom: 16px;
  left: 16px;
  background: rgba(20, 20, 25, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 10px;
  padding: 12px 16px;
  min-width: 240px;
  backdrop-filter: blur(4px);
}

#hud-aim h3 {
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
  margin-bottom: 8px;
}

.aim-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
  font-size: 13px;
}

.aim-row .label {
  width: 72px;
  opacity: 0.85;
}

.aim-row .bar {
  flex: 1;
  height: 8px;
  background: rgba(255, 255, 255, 0.15);
  border-radius: 4px;
  overflow: hidden;
}

.aim-row .bar-fill {
  height: 100%;
  background: linear-gradient(90deg, #ffb347, #ff5e3a);
}

.aim-row .value {
  width: 46px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

#launch-btn {
  margin-top: 8px;
  width: 100%;
  padding: 8px;
  border: none;
  border-radius: 6px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  background: #ff5e3a;
  color: #fff;
  transition: opacity 0.15s, transform 0.1s;
}

#launch-btn:disabled {
  background: #555;
  cursor: not-allowed;
  opacity: 0.6;
}

#launch-btn:not(:disabled):active {
  transform: scale(0.97);
}

#hud-wind {
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(20, 20, 25, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 10px;
  padding: 8px 18px;
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13px;
}

#wind-arrow {
  display: inline-block;
  font-size: 18px;
  transition: transform 0.3s ease-out;
}

#hud-status {
  top: 16px;
  right: 16px;
  background: rgba(20, 20, 25, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 10px;
  padding: 10px 16px;
  font-size: 13px;
  min-width: 200px;
}

#hud-status .row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

#hud-status .row-eliminated {
  opacity: 0.45;
  text-decoration: line-through;
}

.swatch {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 6px;
}

#respawn-banner {
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  font-size: 22px;
  font-weight: 700;
  background: rgba(120, 10, 10, 0.55);
  border-radius: 10px;
  padding: 16px 28px;
  display: none;
}

#observer-banner {
  top: 70px;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  font-size: 14px;
  font-weight: 600;
  background: rgba(20, 20, 25, 0.6);
  border-radius: 10px;
  padding: 8px 18px;
  display: none;
}

#freelook-banner {
  top: 58%;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: rgba(20, 20, 25, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 8px;
  padding: 6px 16px;
  opacity: 0.9;
  display: none;
}

#hud-help {
  bottom: 16px;
  right: 16px;
  background: rgba(20, 20, 25, 0.45);
  border-radius: 10px;
  padding: 10px 14px;
  font-size: 12px;
  line-height: 1.6;
  opacity: 0.85;
}

#crosshair {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 10px;
  height: 10px;
  border: 2px solid rgba(255, 255, 255, 0.7);
  border-radius: 50%;
  background: transparent;
  transition: background 0.15s ease-out;
}

#crosshair.crosshair-ready {
  background: rgba(255, 255, 255, 0.85);
}

/* Keyboard/mouse-only instructions don't apply once on-screen touch
   controls are active - see MobileControls.js. */
body.mobile-controls-active #hud-help {
  display: none;
}

/* The aim readout panel stays, but its own inline Launch button is
   redundant with the dedicated Fire button in #mc-buttons below, and its
   default bottom-left position would otherwise sit right under the
   joystick. */
body.mobile-controls-active #hud-aim {
  bottom: 172px;
}

body.mobile-controls-active #launch-btn {
  display: none;
}

/* Best-effort landscape lock (see main.js) only actually works on some
   browsers/install states - screen.orientation.lock() has no effect at all
   on iOS Safari, and needs a standalone/installed PWA on many others. This
   CSS overlay is the reliable fallback: a touch-primary device left in
   portrait always gets a clear prompt instead of a squeezed, half-broken
   layout. Never triggers on a desktop window that just happens to be
   narrow/tall, since that's gated on pointer:coarse too, not just aspect.
   #app itself sits underneath (not display:none'd) so the WebGL canvas and
   game loop stay running normally - this is purely a visual blocker. */
#rotate-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: #0c0f14;
  color: #fff;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 16px;
  padding: 24px;
  font-size: 16px;
}

#rotate-icon {
  font-size: 64px;
  animation: rotate-hint 1.6s ease-in-out infinite;
}

@keyframes rotate-hint {
  0%, 100% {
    transform: rotate(0deg);
  }
  50% {
    transform: rotate(90deg);
  }
}

@media (pointer: coarse) and (orientation: portrait) {
  #rotate-overlay {
    display: flex;
  }
}

#mobile-controls {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 40;
  user-select: none;
  -webkit-user-select: none;
}

#mc-joystick {
  position: absolute;
  left: 24px;
  bottom: 24px;
  width: 130px;
  height: 130px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.12);
  border: 2px solid rgba(255, 255, 255, 0.3);
  pointer-events: auto;
  touch-action: none;
}

#mc-joystick-thumb {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.32);
  border: 2px solid rgba(255, 255, 255, 0.5);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

#mc-buttons {
  position: absolute;
  right: 20px;
  bottom: 20px;
  display: grid;
  grid-template-columns: repeat(2, 64px);
  grid-template-rows: repeat(2, 64px);
  gap: 10px;
  pointer-events: none;
}

.mc-btn {
  pointer-events: auto;
  touch-action: none;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35);
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 24px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  -webkit-tap-highlight-color: transparent;
}

.mc-btn:active {
  background: rgba(255, 255, 255, 0.28);
}

.mc-btn-active {
  background: rgba(255, 179, 71, 0.45);
  border-color: rgba(255, 179, 71, 0.85);
}

.mc-btn-launch {
  background: rgba(255, 94, 58, 0.35);
  border-color: rgba(255, 94, 58, 0.65);
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

#loading {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 18px;
  letter-spacing: 0.05em;
  background: #0a0e14;
  z-index: 10;
}

/* ---------- Menu / flow screens ---------- */

.screen {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  text-align: center;
  background: linear-gradient(160deg, #274a6b 0%, #16283d 55%, #0c141f 100%);
}

.screen.hidden {
  display: none;
}

/* Generic visibility utility - unlike .screen.hidden above (which only ever
   applied to a top-level screen), this is reused for toggling sub-views
   within a single screen (see MultiplayerLobby's host/join/lobby views).
   !important because it's combined with other classes that set their own
   `display` (e.g. .menu-btn-group's `display: flex`) later in this same
   stylesheet - equal specificity would otherwise let source order pick
   whichever rule happens to come last, instead of "hidden" always winning. */
.hidden {
  display: none !important;
}

.has-bg-art {
  /* x-only - the shorthand also reset .screen's own overflow-y:auto back to
     hidden (same specificity, later in source order), silently blocking the
     vertical scrolling that content taller than the viewport needs (see
     .screen's own comment). The full-bleed backdrop itself doesn't actually
     need clipping either way - it's absolutely positioned with inset:0, so
     it can't overflow its parent's box regardless. */
  overflow-x: hidden;
}

/* Full-bleed backdrop, absolutely positioned and painted first - every other
   child stays in normal flex flow on top of it, so the logo/panel/text never
   have to coordinate positioning with it to avoid overlapping each other. */
.title-bg-art {
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: linear-gradient(180deg, rgba(10, 14, 20, 0.35) 0%, rgba(10, 14, 20, 0.55) 55%, rgba(6, 9, 14, 0.88) 100%),
    url("../assets/title-art.png");
  background-size: cover;
  background-position: center;
}

.has-bg-art > *:not(.title-bg-art) {
  position: relative;
  z-index: 1;
}

/* Sized off viewport units with a px cap - grows/shrinks with the window but
   never larger than the source art needs, and object-fit keeps it from
   ever stretching into neighboring elements' space. */
.title-logo {
  width: min(70vw, 720px);
  max-height: 34vh;
  object-fit: contain;
  filter: drop-shadow(0 8px 20px rgba(0, 0, 0, 0.6));
  margin-bottom: 28px;
}

.title-logo-small {
  width: min(50vw, 460px);
  max-height: 20vh;
  margin-bottom: 24px;
}

/* Title screen only - the studio splash (TN_logo_Me.png) and the game's
   own logo sit stacked in the exact same spot so they can crossfade into
   each other (see TitleScreen.js) instead of each taking up their own flow
   space. Sizing lives on the wrapper now; the two images just fill it. */
.title-logo-stack {
  position: relative;
  width: min(70vw, 720px);
  /* Absolutely-positioned children (below) don't contribute to a parent's
     height the way normal-flow content would, so without an explicit
     height here the wrapper collapsed to 0px and both logos silently
     vanished - aspect-ratio matching title-logo.png's own 1536x1024 gives
     it a real height derived from the width cap above, same effective
     sizing the single un-stacked .title-logo had before. */
  aspect-ratio: 1536 / 1024;
  max-height: 34vh;
  margin-bottom: 28px;
}

.title-logo-stack .title-logo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin-bottom: 0;
  transition: opacity 0.9s ease-in-out;
}

.title-logo-stack .title-logo-studio {
  opacity: 1;
}

.title-logo-stack .title-logo-game {
  opacity: 0;
}

.title-logo-stack.swapped .title-logo-studio {
  opacity: 0;
}

.title-logo-stack.swapped .title-logo-game {
  opacity: 1;
}

.screen-title .subtitle {
  font-size: 16px;
  opacity: 0.75;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-bottom: 60px;
}

.screen-title .prompt {
  font-size: 14px;
  opacity: 0.6;
  animation: pulse 1.8s ease-in-out infinite;
}

/* Only ever shown reactively once the browser actually fires
   beforeinstallprompt (see main.js) - no way to know in advance whether
   that'll happen, so it starts hidden via the shared .hidden utility. */
.title-install-btn {
  margin-top: 22px;
  padding: 10px 22px;
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 8px;
  background: rgba(255, 94, 58, 0.22);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s ease-out, transform 0.1s;
}

.title-install-btn:hover {
  background: rgba(255, 94, 58, 0.38);
}

.title-install-btn:active {
  transform: scale(0.97);
}

/* Pinned to the viewport edge rather than the centered flex stack above -
   stays clear of the logo/subtitle/prompt group at any screen size instead
   of competing with them for vertical space. */
.screen-title .title-footer {
  position: absolute;
  bottom: 14px;
  left: 0;
  right: 0;
  font-size: 12px;
  letter-spacing: 0.02em;
  opacity: 0.55;
}

.title-footer a {
  margin-left: 10px;
  color: #ffb347;
  opacity: 1;
  text-decoration: none;
  letter-spacing: 0.08em;
  font-weight: 700;
}

.title-footer a:hover {
  text-decoration: underline;
}

.title-version {
  margin-left: 10px;
  font-variant-numeric: tabular-nums;
}

@keyframes pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 0.85; }
}

.menu-panel {
  background: rgba(15, 22, 32, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 14px;
  padding: 36px 44px;
  min-width: 340px;
  backdrop-filter: blur(6px);
  /* Capped so the panel always fits within .screen's centered flex layout,
     with its own independent scrollbar for anything that still doesn't fit
     (e.g. How to Play's control list on a short phone-landscape viewport) -
     tried making .screen itself the scroll container instead (with the
     panel sized by its content), but centered flex content that overflows
     its container is a well-known trap: the browser clips equal, genuinely
     unreachable amounts off both ends rather than resolving to a scrollable
     "start" position, even with the various documented workarounds (auto
     margins, justify-content:safe). Bounding the panel's own height instead
     sidesteps that entirely - the outer centering only ever centers a box
     guaranteed to fit, and overflow is handled by a plain, ordinary,
     non-centered scroll area nested inside it. */
  max-height: 92vh;
  overflow-y: auto;
}

/* margin-top used to be -12px, meant to tuck this closer under a heading's
   own bottom margin - but the global `* { margin: 0 }` reset (see top of
   file) leaves every heading with none, so that negative value pulled this
   straight up into the heading's text instead of just tightening the gap
   (see #mp-error/#mp-room-code-display below for the same bug, patched
   there per-instance before this was fixed at the source). */
.menu-panel p.desc {
  font-size: 13px;
  opacity: 0.7;
  margin: 4px 0 22px;
  line-height: 1.5;
}

.menu-btn-group {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.menu-btn {
  padding: 14px 20px;
  border: none;
  border-radius: 8px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.03em;
  cursor: pointer;
  background: #ff5e3a;
  color: #fff;
  transition: transform 0.1s, opacity 0.15s;
}

.menu-btn:hover {
  opacity: 0.92;
}

.menu-btn:active {
  transform: scale(0.98);
}

.menu-btn.secondary {
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.menu-btn.selected {
  background: #ffb347;
  box-shadow: 0 0 0 2px #fff inset;
}

.menu-btn:disabled {
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.4);
  cursor: not-allowed;
}

.menu-btn-row {
  display: flex;
  gap: 10px;
}

.menu-btn-row .menu-btn {
  flex: 1;
}

.menu-slider {
  width: 180px;
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.15);
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
}

.menu-slider::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: linear-gradient(180deg, #ffb347, #ff5e3a);
  border: 2px solid #fff;
  cursor: pointer;
}

.menu-slider::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: linear-gradient(180deg, #ffb347, #ff5e3a);
  border: 2px solid #fff;
  cursor: pointer;
}

.menu-slider::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.15);
}

.back-link {
  margin-top: 22px;
  font-size: 13px;
  opacity: 0.6;
  cursor: pointer;
  text-decoration: underline;
}

.back-link:hover {
  opacity: 0.9;
}

.how-to-play-body {
  max-width: 560px;
  text-align: left;
  font-size: 14px;
  line-height: 1.8;
  opacity: 0.9;
}

.how-to-play-body strong {
  color: #ffb347;
}

.how-to-play-body p + p {
  margin-top: 12px;
}

.how-to-play-body p.how-to-play-section {
  margin-top: 18px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #ffb347;
  opacity: 1;
}

.stats-table {
  border-collapse: collapse;
  margin: 20px 0;
  font-size: 13px;
}

.stats-table th, .stats-table td {
  padding: 8px 16px;
  text-align: right;
  border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.stats-table th:first-child, .stats-table td:first-child {
  text-align: left;
}

.stats-table thead th {
  opacity: 0.6;
  font-weight: 600;
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.05em;
}

.stats-table tbody tr.winner-row {
  background: rgba(255, 179, 71, 0.12);
  font-weight: 700;
}

.stats-table tbody tr.eliminated-row {
  opacity: 0.55;
}

/* ---------- Multiplayer lobby ---------- */

.text-input {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 12px 14px;
  margin-bottom: 12px;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.2);
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
  font-size: 15px;
  font-family: inherit;
}

.text-input::placeholder {
  color: rgba(255, 255, 255, 0.4);
}

.text-input:focus {
  outline: none;
  border-color: #ffb347;
  background: rgba(255, 255, 255, 0.12);
}

.mp-code-input {
  text-transform: uppercase;
  letter-spacing: 0.3em;
  text-align: center;
  font-weight: 700;
}

.mp-player-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 16px 0;
  text-align: left;
}

.mp-player-row {
  padding: 10px 14px;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.06);
  font-size: 14px;
}

.mp-player-tag {
  opacity: 0.6;
  font-size: 12px;
}

/* An unclaimed corner - see MultiplayerLobby._renderPlayerList - reads as
   a dashed, dimmer placeholder instead of a solid row, so it's clearly
   distinct from an actual joined player at a glance. */
.mp-player-row-open {
  background: transparent;
  border: 1px dashed rgba(255, 255, 255, 0.18);
  opacity: 0.6;
}

.mp-player-row-open .swatch {
  opacity: 0.5;
}

/* Overrides .menu-panel p.desc's negative top margin (meant for a desc
   line directly under an <h2>) - #mp-error sits below a form/back-link
   instead, where that negative margin pulled it up into an overlap. */
#mp-error {
  margin-top: 14px;
  min-height: 16px;
  color: #ff8f8f;
  font-size: 12px;
}

/* .menu-panel p.desc's -12px top margin assumes the h2 above it still has
   some default bottom margin to eat into - but the global `* { margin: 0 }`
   reset (see top of file) leaves h2 with none, so that negative margin
   pulled the room code line up directly into the "Lobby" heading's text
   instead of just tightening the gap. */
#mp-room-code-display {
  margin-top: 6px;
}
