:root {
  --blue: #2e7dff;
  --orange: #ffa02c;
  --orange-deep: #ff5a1a;
  --green: #5dd97a;
  --green-bright: #8eff9c;
  --yellow: #ffec8a;
  --white: #f4f6fb;
  --ink: #0a1426;
  --ink-deep: #050a14;
  --panel: #0f1d36;
  --panel-edge: #1d3158;
  --accent: #6cc1ff;
  --pixel-font: "Press Start 2P", ui-monospace, "Cascadia Mono", Consolas, monospace;
}

* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; background: var(--ink-deep); color: var(--white);
  font-family: -apple-system, "Segoe UI", Inter, system-ui, sans-serif; overflow: hidden;
  image-rendering: pixelated; }

#app { position: relative; width: 100vw; height: 100vh; display: grid; place-items: center; }

/* Pixel-art tiled background used by all menu overlays — a navy field
   with a subtle dotted grid for that arcade feel. The radial vignette
   sits on top to keep the centre brighter where the logo lives. */
#mode-select,
.match-overlay {
  background-color: var(--ink);
  background-image:
    radial-gradient(ellipse at center, rgba(46,125,255,0.18) 0%, rgba(10,20,38,0.95) 60%, rgba(5,10,20,1) 100%),
    repeating-linear-gradient(0deg,  rgba(108,193,255,0.05) 0 2px, transparent 2px 8px),
    repeating-linear-gradient(90deg, rgba(108,193,255,0.05) 0 2px, transparent 2px 8px);
}

/* Mode-select overlay — title screen. Big logo on top, mode grid below.
   No opacity fade on hide — fading out reveals the live game canvas
   behind for ~280 ms which reads as a flash on every button click. We
   snap to display:none instead so the next overlay can take over with
   no gap. */
#mode-select {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 28px;
  padding: 32px;
  font-family: var(--pixel-font);
  color: var(--white);
}
#mode-select.hidden { display: none; }

#title-logo {
  display: block;
  width: min(720px, 70vw);
  height: auto;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  filter: drop-shadow(0 0 18px rgba(255,160,44,0.35)) drop-shadow(0 6px 0 rgba(0,0,0,0.45));
  animation: logo-bob 3.2s ease-in-out infinite;
}
@keyframes logo-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-4px); }
}

/* PLAY SPLAT (BETA) — hero CTA, biggest element on the title screen and first
   in the column so it sits above the logo. Pulsing orange = primary action;
   cyan BETA tag pinned to the corner. */
.play-splat-beta {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  width: min(560px, 84vw);
  padding: 22px 28px;
  font-family: var(--pixel-font);
  color: #fff;
  background: linear-gradient(180deg, #ff8a1e 0%, #ff6a00 60%, #e24f00 100%);
  border: 3px solid #ffd6a0;
  border-radius: 14px;
  cursor: pointer;
  text-shadow: 0 2px 0 rgba(0,0,0,0.45);
  animation: psb-pulse 1.8s ease-in-out infinite;
  transition: transform 0.08s ease, filter 0.08s ease;
}
.play-splat-beta:hover  { transform: translateY(-2px); filter: brightness(1.06); }
.play-splat-beta:active { transform: translateY(2px); }
.play-splat-beta .psb-label { font-size: 26px; letter-spacing: 0.12em; }
.play-splat-beta .psb-sub   { font-size: 9px;  letter-spacing: 0.18em; opacity: 0.92; }
.play-splat-beta .psb-beta {
  position: absolute; top: -12px; right: -12px;
  background: #11d6e0; color: #06202a;
  font-size: 11px; letter-spacing: 0.14em;
  padding: 5px 10px; border-radius: 8px;
  border: 2px solid #baf6fb;
  box-shadow: 0 0 14px rgba(17,214,224,0.7);
  transform: rotate(8deg);
}
@keyframes psb-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(0,0,0,0.5), 0 8px 0 #9c3600, 0 0 28px rgba(255,122,26,0.5); }
  50%      { box-shadow: 0 0 0 3px rgba(0,0,0,0.5), 0 8px 0 #9c3600, 0 0 48px rgba(255,122,26,0.9); }
}

#mode-select h1 {
  font-size: 14px;
  letter-spacing: 0.35em;
  margin: 0;
  color: var(--yellow);
  text-shadow:
    2px 2px 0 var(--orange-deep),
    4px 4px 0 rgba(0,0,0,0.6);
}

.mode-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 280px));
  gap: 14px;
  max-width: 920px;
  width: 100%;
  justify-content: center;
}

/* Pixel button: solid panel, hard 3px outline, chunky bottom shadow,
   inset highlight. No rounded corners. Hover bumps it up like a key
   press. */
.mode {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding: 16px 18px;
  background: var(--panel);
  border: 3px solid var(--panel-edge);
  border-radius: 0;
  color: var(--white);
  font: inherit;
  text-align: left;
  cursor: pointer;
  position: relative;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000;
  transition: transform 90ms steps(2), box-shadow 90ms, border-color 90ms, background 90ms;
  image-rendering: pixelated;
}
.mode:hover:not(.locked),
.mode:focus-visible:not(.locked) {
  outline: none;
  background: #1a2e54;
  border-color: var(--orange);
  transform: translateY(-3px);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.1),
    inset 0 -2px 0 rgba(0,0,0,0.5),
    0 7px 0 #000,
    0 0 18px rgba(255,160,44,0.45);
}
.mode:active:not(.locked) {
  transform: translateY(1px);
  box-shadow:
    inset 0 2px 0 rgba(0,0,0,0.4),
    0 0 0 #000,
    0 0 12px rgba(255,160,44,0.4);
}
.mode .mode-name {
  font-size: 16px;
  letter-spacing: 0.16em;
  color: var(--green-bright);
  text-shadow: 2px 2px 0 #000;
}
.mode:hover:not(.locked) .mode-name {
  color: var(--yellow);
}
.mode .mode-sub {
  font-size: 8px;
  line-height: 1.7;
  letter-spacing: 0.18em;
  color: rgba(244,246,251,0.65);
  text-shadow: 1px 1px 0 #000;
}
.mode.locked {
  cursor: not-allowed;
  background: #0c1830;
  border-color: #1a2645;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.02),
    inset 0 -2px 0 rgba(0,0,0,0.3),
    0 3px 0 #000;
  opacity: 0.7;
}
.mode.locked .mode-name {
  color: rgba(244,246,251,0.35);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(244,246,251,0.2);
}
.mode.locked .mode-sub {
  color: var(--orange-deep);
  letter-spacing: 0.32em;
}

/* Join-code tile — same chrome as the regular .mode buttons but it's a
   <div> instead of a <button> so we can nest a text input + Go button
   inside. The tile itself is non-interactive; the Go button drives the
   click handler in main.js (Enter inside the input does the same). */
.mode.mode-join { cursor: default; }
.mode.mode-join .join-row {
  display: flex; align-items: center; gap: 8px;
  margin-top: 4px;
  /* Span the tile's content box so positioning is anchored to the
     tile, not to the row's intrinsic content width. width:100% +
     box-sizing:border-box prevents the input + button from poking
     out past the tile's right edge on narrower viewports where the
     auto-fit grid drops each column toward its 240px min. */
  width: 100%;
  box-sizing: border-box;
  min-width: 0;
  justify-content: center;
}
#join-code-input {
  /* flex: 0 1 140px → starts at 140 wide, can shrink (min-width:0
     bypasses the input's intrinsic min) so the row never overflows
     a narrow tile. box-sizing:border-box folds padding+border into
     the width so the basis is the rendered size, not 140 + 20 + 4. */
  flex: 0 1 140px;
  min-width: 0;
  box-sizing: border-box;
  background: #050a14;
  border: 2px solid var(--panel-edge);
  color: var(--green-bright);
  font-family: var(--pixel-font);
  font-size: 14px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  padding: 8px 10px;
  outline: none;
  text-align: center;
  caret-color: var(--orange);
}
#join-code-input::placeholder {
  color: rgba(244,246,251,0.25);
  letter-spacing: 0.3em;
}
#join-code-input:focus {
  border-color: var(--orange);
  background: #0a1426;
}
.join-go-btn {
  flex: 0 0 auto;
  box-sizing: border-box;
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--ink-deep);
  background: var(--yellow);
  border: 2px solid var(--orange-deep);
  padding: 8px 12px;
  cursor: pointer;
  text-shadow: 1px 1px 0 rgba(255,255,255,0.4);
}
.join-go-btn:hover { background: #fff7c2; }
.join-go-btn:active { transform: translateY(1px); }

/* Room-code display inside the queue overlay — only visible after
   roomCreated; quick-match and joiners leave it hidden. */
#online-room-code {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 18px 22px;
  background: var(--panel);
  border: 3px solid var(--panel-edge);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000;
}
#online-room-code.hidden { display: none; }
#online-room-code .room-code-label {
  font-family: var(--pixel-font);
  font-size: 9px;
  letter-spacing: 0.4em;
  color: var(--accent);
}
#online-room-code .room-code-value {
  font-family: var(--pixel-font);
  font-size: 32px;
  letter-spacing: 0.3em;
  color: var(--green-bright);
  text-shadow: 2px 2px 0 var(--orange-deep), 4px 4px 0 rgba(0,0,0,0.6);
}
#online-room-code .copy-code-btn {
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--ink-deep);
  background: var(--yellow);
  border: 2px solid var(--orange-deep);
  padding: 6px 14px;
  cursor: pointer;
}
#online-room-code .copy-code-btn:hover { background: #fff7c2; }
#online-room-code .copy-code-btn:active { transform: translateY(1px); }

/* Public-rooms browser overlay — list of open public rooms with a
   create button. Live-refreshes every 2 s while open. */
.public-rooms-list {
  display: flex; flex-direction: column; gap: 8px;
  width: min(640px, 90vw);
  max-height: 50vh;
  overflow-y: auto;
  padding: 4px;
}
.public-rooms-empty {
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.2em;
  color: rgba(244,246,251,0.55);
  text-align: center;
  padding: 24px 8px;
}
.public-rooms-row {
  display: grid;
  grid-template-columns: 1fr auto auto auto auto;
  gap: 14px;
  align-items: center;
  padding: 12px 16px;
  background: var(--panel);
  border: 3px solid var(--panel-edge);
  color: var(--white);
  font-family: var(--pixel-font);
  font-size: 11px;
  letter-spacing: 0.16em;
  cursor: pointer;
  text-align: left;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 3px 0 #000;
  transition: transform 90ms steps(2), border-color 90ms, background 90ms;
}
.public-rooms-row:hover {
  background: #1a2e54;
  border-color: var(--orange);
  transform: translateY(-2px);
}
.public-rooms-row .pr-host { color: var(--green-bright); }
.public-rooms-row .pr-char { color: var(--accent); font-size: 9px; }
.public-rooms-row .pr-mode { color: var(--white); font-size: 9px; opacity: 0.85; }
.public-rooms-row .pr-code { color: var(--yellow); font-size: 14px; letter-spacing: 0.25em; }
.public-rooms-row .pr-join { color: var(--orange); font-size: 9px; }
.public-rooms-actions {
  display: flex; gap: 12px; margin-top: 4px;
}
.public-rooms-actions button {
  font-family: var(--pixel-font);
  font-size: 11px;
  letter-spacing: 0.2em;
  padding: 12px 18px;
  cursor: pointer;
  border: 3px solid var(--panel-edge);
  background: var(--panel);
  color: var(--green-bright);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 3px 0 #000;
}
.public-rooms-actions #public-rooms-create {
  background: var(--yellow);
  color: var(--ink-deep);
  border-color: var(--orange-deep);
}
.public-rooms-actions button:hover { transform: translateY(-2px); border-color: var(--orange); }
.public-rooms-actions button:active { transform: translateY(1px); box-shadow: 0 0 0 #000; }

#mode-select .footer-tag {
  margin: 4px 0 0;
  font-family: var(--pixel-font);
  font-size: 9px;
  letter-spacing: 0.4em;
  color: var(--orange);
  text-shadow: 2px 2px 0 #000, 0 0 12px rgba(255,160,44,0.6);
  animation: tag-blink 1.4s steps(2, end) infinite;
}
@keyframes tag-blink {
  0%, 70% { opacity: 1; }
  71%, 100% { opacity: 0.35; }
}

/* Match-flow overlays — map vote, char select, round end, match end.
   Same pixel-art visual family as #mode-select. */
.match-overlay {
  position: fixed; inset: 0; z-index: 40;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 18px;
  padding: 32px;
  font-family: var(--pixel-font);
  color: var(--white);
}
/* Snap-hide (display:none) instead of opacity-fade so the live canvas
   doesn't flash through during the cross-overlay handoff. */
.match-overlay.hidden { display: none; }
/* Kill-cam cinematic — the round-end overlay enters at opacity 0 and
   fades to 1 over 600 ms while the slow-mo death burst plays out. The
   .cinematic-fade class is added in showRoundEndFading; .cinematic-in
   is added a beat later by triggerRoundEndFadeIn to start the
   transition. Both are removed by hideRoundEnd. */
#round-end.cinematic-fade { opacity: 0; transition: opacity 600ms ease-out; }
#round-end.cinematic-fade.cinematic-in { opacity: 1; }
.match-overlay .overlay-logo {
  display: block;
  width: min(380px, 45vw);
  height: auto;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  filter: drop-shadow(0 0 12px rgba(255,160,44,0.3)) drop-shadow(0 4px 0 rgba(0,0,0,0.45));
  margin-bottom: 6px;
}
.match-overlay h2 {
  font-size: 14px; letter-spacing: 0.35em; margin: 0 0 8px;
  color: var(--yellow);
  text-shadow:
    2px 2px 0 var(--orange-deep),
    4px 4px 0 rgba(0,0,0,0.6);
}
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 280px));
  gap: 14px;
  max-width: 920px;
}
/* Character-select grid: keep all 7 character cards on a single row so
   Valeris the Wretched doesn't break onto a second row by itself. The
   columns shrink to fit; the per-card padding/portrait scales down via
   the rules below so the dense layout still reads cleanly. */
#char-select .card-grid {
  grid-template-columns: repeat(7, minmax(0, 1fr));
  max-width: 1480px;
  gap: 10px;
}
#char-select .card { padding: 12px 10px; gap: 6px; }
#char-select .card .card-portrait { width: 96px; height: 96px; }
#char-select .card .card-name { font-size: 12px; letter-spacing: 0.12em; }
#char-select .card .card-sub  { font-size: 7px; letter-spacing: 0.14em; }
#char-select .card .ability { height: 48px; padding: 3px 1px 3px; }
#char-select .card .ability-icon { height: 26px; }
#char-select .card .ability-label { font-size: 8px; letter-spacing: 0.06em; }
#char-select .card .card-abilities { gap: 4px; }
.card {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding: 16px 18px;
  background: var(--panel);
  border: 3px solid var(--panel-edge);
  border-radius: 0;
  color: var(--white);
  font: inherit;
  text-align: left;
  cursor: pointer;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000;
  transition: transform 90ms steps(2), box-shadow 90ms, border-color 90ms, background 90ms;
  image-rendering: pixelated;
}
.card:hover,
.card:focus-visible {
  outline: none;
  background: #1a2e54;
  border-color: var(--orange);
  transform: translateY(-3px);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.1),
    inset 0 -2px 0 rgba(0,0,0,0.5),
    0 7px 0 #000,
    0 0 18px rgba(255,160,44,0.45);
}
.card:active {
  transform: translateY(1px);
  box-shadow:
    inset 0 2px 0 rgba(0,0,0,0.4),
    0 0 0 #000,
    0 0 12px rgba(255,160,44,0.4);
}
.card .card-name {
  font-size: 14px; letter-spacing: 0.16em;
  color: var(--green-bright);
  text-shadow: 2px 2px 0 #000;
}
.card:hover .card-name { color: var(--yellow); }
.card .card-sub  {
  font-size: 8px; line-height: 1.7; letter-spacing: 0.18em;
  color: rgba(244,246,251,0.65);
  text-shadow: 1px 1px 0 #000;
}

/* Class chip — small uppercase role tag (WARDEN / REAVER / ROGUE /
   SWIFT / LANCE) sitting above the character name on each card.
   Per-class accent coloring via data-class so each role reads at a
   glance. The chip is self-sized so it doesn't push the layout. */
.card .card-class {
  align-self: center;
  font-size: 7px; letter-spacing: 0.22em;
  color: rgba(244,246,251,0.95);
  background: rgba(8,12,22,0.55);
  border: 1px solid rgba(108,193,255,0.4);
  padding: 2px 8px 1px;
  margin-bottom: 4px;
  border-radius: 2px;
  text-shadow: 1px 1px 0 #000;
}
.card .card-class[data-class="warden"] { color: #6cc1ff; border-color: rgba(108,193,255,0.6); }
.card .card-class[data-class="reaver"] { color: #caa6ff; border-color: rgba(202,166,255,0.6); }
.card .card-class[data-class="rogue"]  { color: #e34a4a; border-color: rgba(227,74,74,0.6); }
.card .card-class[data-class="swift"]  { color: #ffaa44; border-color: rgba(255,170,68,0.6); }
.card .card-class[data-class="lance"]  { color: #ffd86a; border-color: rgba(255,216,106,0.6); }

/* Team-pick cards (2v2 lobby). Blue + red tinted backgrounds so the
   choice reads at a glance; the count number sits in card-sub but at
   the larger card-name size so "1/2" is legible across the room. */
.card.team-card { align-items: center; min-width: 200px; }
.card.team-card .card-name { font-size: 18px; }
.card.team-card .team-count {
  font-size: 16px; letter-spacing: 0.2em; color: var(--white);
  text-shadow: 2px 2px 0 #000;
}
.card.team-blue {
  background: #1a2e54;
  border-color: #2e7dff;
}
.card.team-blue:hover, .card.team-blue:focus-visible {
  background: #244075;
  border-color: #5ea3ff;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.1),
    inset 0 -2px 0 rgba(0,0,0,0.5),
    0 7px 0 #000,
    0 0 18px rgba(94,163,255,0.55);
}
.card.team-red {
  background: #5e1818;
  border-color: #dc3a3a;
}
.card.team-red:hover, .card.team-red:focus-visible {
  background: #7c2222;
  border-color: #ff5d5d;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.1),
    inset 0 -2px 0 rgba(0,0,0,0.5),
    0 7px 0 #000,
    0 0 18px rgba(255,93,93,0.55);
}
/* Disable a team card when its side is full — the click handler will
   redirect the user, but the visual cue is important. */
.card.team-card.full {
  opacity: 0.55;
  cursor: not-allowed;
  filter: grayscale(0.4);
}
.card.team-card.full:hover { transform: none; }

/* Character-card portrait — procedural cube painted into a canvas by
   characterCard.js. Pixelated rendering keeps the cube crisp at upscale,
   and the dark inset frame matches the loadout-slot aesthetic. */
.card .card-portrait {
  align-self: center;
  /* Matches PORTRAIT_SCALE * PLAYER_W in characterCard.js so each canvas
     pixel maps 1:1 to a screen pixel — no nearest-neighbor blur. */
  width: 128px; height: 128px;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
  background: rgba(8,12,22,0.7);
  border: 2px solid rgba(108,193,255,0.25);
  box-shadow: inset 0 0 14px rgba(0,0,0,0.6);
  margin-bottom: 4px;
  transition: border-color 90ms, box-shadow 90ms;
}
.card:hover .card-portrait,
.card:focus-visible .card-portrait {
  border-color: var(--orange);
  box-shadow: inset 0 0 14px rgba(0,0,0,0.6),
              0 0 12px rgba(255,160,44,0.45);
}

/* Ability strip — one tile per non-empty slot, icon above its three-letter
   label. Mirrors the data-weapon palette logic used by the in-game HUD
   loadout so each kit reads as the same color in the menu and in play. */
.card .card-abilities {
  display: flex; gap: 6px;
  width: 100%;
  margin-top: 4px;
}
.card .ability {
  flex: 1 1 0;
  position: relative;
  height: 56px;
  background: rgba(26,34,54,0.85);
  border: 1px solid rgba(108,193,255,0.2);
  border-radius: 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  padding: 4px 2px 4px;
}
.card .ability-icon {
  width: 100%; height: 32px;
  display: flex; align-items: center; justify-content: center;
  filter: drop-shadow(1px 1px 0 rgba(0,0,0,0.55));
}
.card .ability-icon svg {
  width: 100%; height: 100%;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}
.card .ability-icon.ability-icon-multi { gap: 2px; }
.card .ability-icon.ability-icon-multi svg { width: 50%; height: 100%; }
.card .ability-label {
  font-size: 9px; letter-spacing: 0.1em;
  color: rgba(244,246,251,0.85);
  text-shadow: 1px 1px 0 #000;
  margin-top: auto;
}
/* Per-weapon tinting for the ability tiles — same palette as the HUD
   slots so menu reads match in-play reads. */
.card .ability[data-weapon="rocket"]    { background: rgba(255,122,26,0.16); border-color: rgba(255,122,26,0.4); }
.card .ability[data-weapon="rocket"] .ability-label    { color: var(--orange); }
.card .ability[data-weapon="hammer"]    { background: rgba(108,193,255,0.16); border-color: rgba(108,193,255,0.45); }
.card .ability[data-weapon="hammer"] .ability-label    { color: #6cc1ff; }
.card .ability[data-weapon="grapple"]   { background: rgba(179,120,255,0.16); border-color: rgba(179,120,255,0.45); }
.card .ability[data-weapon="grapple"] .ability-label   { color: #b378ff; }
.card .ability[data-weapon="laser"]     { background: rgba(255,119,255,0.14); border-color: rgba(255,119,255,0.5); }
.card .ability[data-weapon="laser"] .ability-label     { color: #ffbbff; }
.card .ability[data-weapon="rifle"]     { background: rgba(255,236,138,0.12); border-color: rgba(255,236,138,0.45); }
.card .ability[data-weapon="rifle"] .ability-label     { color: #ffec8a; }
.card .ability[data-weapon="shockwave"] { background: rgba(168,208,255,0.14); border-color: rgba(168,208,255,0.45); }
.card .ability[data-weapon="shockwave"] .ability-label { color: #a8d0ff; }
.card .ability[data-weapon="jetpack"]   { background: rgba(255,122,26,0.16); border-color: rgba(255,170,68,0.5); }
.card .ability[data-weapon="jetpack"] .ability-label   { color: #ffaa44; }
.card .ability[data-weapon="gasUlt"]    { background: rgba(74,209,122,0.16); border-color: rgba(74,209,122,0.5); }
.card .ability[data-weapon="gasUlt"] .ability-label    { color: #4ad17a; }
.card .ability[data-weapon="joust"]      { background: rgba(190,200,215,0.14); border-color: rgba(190,200,215,0.45); }
.card .ability[data-weapon="joust"] .ability-label      { color: #d6dde8; }
.card .ability[data-weapon="bulwark"]    { background: rgba(100,160,220,0.14); border-color: rgba(100,160,220,0.45); }
.card .ability[data-weapon="bulwark"] .ability-label    { color: #6cb4ff; }
.card .ability[data-weapon="crossbow"]   { background: rgba(150,90,40,0.14); border-color: rgba(195,140,80,0.45); }
.card .ability[data-weapon="crossbow"] .ability-label   { color: #d8a060; }
.card .ability[data-weapon="roundTable"] { background: rgba(180,140,60,0.16); border-color: rgba(220,180,80,0.5); }
.card .ability[data-weapon="roundTable"] .ability-label { color: #ffd86a; }

/* Wide map preview card — overrides the narrow column shape so a
   thumbnail of the level fits across the top. The :has() rule widens
   the surrounding card-grid when this layout is in use. With two map
   options (the jungle vs warehouse vote), the grid switches to a 2-col
   layout so they sit side-by-side instead of stacking. */
.card-grid:has(.card-map) {
  grid-template-columns: 1fr;
  max-width: 600px;
}
#map-vote .card-grid {
  grid-template-columns: 1fr 1fr;
  max-width: 1100px;
}
.card.card-map {
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  padding: 12px 12px 14px;
  width: 100%;
}
.card-map .map-thumb {
  display: block;
  width: 100%;
  height: auto;
  border: 3px solid var(--panel-edge);
  border-radius: 0;
  image-rendering: pixelated;
  background: #061018;
  transition: border-color 120ms, box-shadow 120ms;
}
.card-map:hover .map-thumb {
  border-color: var(--orange);
  box-shadow: 0 0 18px rgba(255,160,44,0.4) inset;
}
.card-map .card-name { font-size: 18px; letter-spacing: 0.2em; padding: 4px; }
.card-map .card-sub  { font-size: 9px; padding: 0 4px; }
.match-overlay .hint {
  font-size: 8px; letter-spacing: 0.3em;
  color: var(--accent);
  margin-top: 6px;
  text-shadow: 1px 1px 0 #000;
  animation: tag-blink 1.4s steps(2, end) infinite;
}
.match-overlay .round-winner,
.match-overlay .match-winner {
  font-size: 18px; letter-spacing: 0.2em;
  color: var(--orange);
  margin: 4px 0;
  text-shadow:
    2px 2px 0 var(--orange-deep),
    4px 4px 0 #000,
    0 0 14px rgba(255,160,44,0.6);
}
.match-overlay .round-score {
  font-size: 11px; letter-spacing: 0.3em;
  color: var(--green-bright);
  margin: 0;
  text-shadow: 2px 2px 0 #000;
}
#match-end-back {
  margin-top: 18px;
  padding: 12px 22px;
  background: var(--panel);
  border: 3px solid var(--orange);
  border-radius: 0;
  color: var(--yellow);
  font: inherit;
  font-family: var(--pixel-font);
  font-size: 11px;
  letter-spacing: 0.25em;
  cursor: pointer;
  text-shadow: 2px 2px 0 #000;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.08),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000;
  transition: transform 90ms steps(2), box-shadow 90ms, background 90ms;
}
#match-end-back:hover {
  background: #1a2e54;
  transform: translateY(-3px);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.1),
    inset 0 -2px 0 rgba(0,0,0,0.5),
    0 7px 0 #000,
    0 0 18px rgba(255,160,44,0.45);
}
#match-end-back:active {
  transform: translateY(1px);
  box-shadow: inset 0 2px 0 rgba(0,0,0,0.4), 0 0 0 #000;
}

/* ── Pause menu + bindings UI ──────────────────────────────────────
   The pause overlay reuses .match-overlay (full-screen panel) but sits
   on a higher z-index so it floats above round-end / match-end if
   either happens to be open. The mode-select aux button is the small
   "BINDINGS" pill that sits at the bottom of the main grid. */
/* Pause menu sits above round-end / match-end (which inherit z-index 40
   from .match-overlay). The bindings overlay opened from the main menu
   has to clear #mode-select (z-index 50) too. */
#pause-menu       { z-index: 60; }
#bindings-overlay { z-index: 60; }
.pause-actions {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  margin: 12px 0 24px;
}
#pause-resume,
#pause-leave,
#bindings-back {
  min-width: 320px;
  padding: 12px 22px;
  background: var(--panel);
  border: 3px solid var(--orange);
  border-radius: 0;
  color: var(--yellow);
  font-family: var(--pixel-font);
  font-size: 11px;
  letter-spacing: 0.25em;
  cursor: pointer;
  text-shadow: 2px 2px 0 #000;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.08),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000;
  transition: transform 90ms steps(2), box-shadow 90ms, background 90ms;
}
#pause-resume:hover,
#pause-leave:hover,
#bindings-back:hover {
  background: #1a2e54;
  transform: translateY(-3px);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.1),
    inset 0 -2px 0 rgba(0,0,0,0.5),
    0 7px 0 #000,
    0 0 18px rgba(255,160,44,0.45);
}
#pause-resume:active,
#pause-leave:active,
#bindings-back:active {
  transform: translateY(1px);
  box-shadow: inset 0 2px 0 rgba(0,0,0,0.4), 0 0 0 #000;
}
.pause-bindings-title {
  font-family: var(--pixel-font);
  font-size: 11px;
  letter-spacing: 0.35em;
  color: var(--accent);
  margin: 8px 0 12px;
}
#bindings-back { margin-top: 18px; }

.bindings-list {
  display: flex; flex-direction: column; gap: 8px;
  width: min(520px, 80vw);
  max-height: min(380px, 50vh);
  overflow-y: auto;
  padding: 12px 14px;
  background: rgba(5, 10, 20, 0.6);
  border: 2px solid var(--panel-edge);
}
.binding-note {
  font-family: var(--pixel-font);
  font-size: 8px;
  letter-spacing: 0.32em;
  color: var(--accent);
  text-align: center;
  margin: 0 0 6px;
}
.binding-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  background: var(--panel);
  border: 2px solid var(--panel-edge);
}
.binding-label {
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.3em;
  color: var(--green-bright);
  text-shadow: 1px 1px 0 #000;
}
.binding-chip {
  min-width: 92px;
  padding: 6px 10px;
  text-align: center;
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.2em;
  color: var(--yellow);
  background: #050a14;
  border: 2px solid var(--orange-deep);
  text-shadow: 1px 1px 0 #000;
}
.binding-chip.listening {
  color: var(--ink-deep);
  background: var(--yellow);
  border-color: var(--orange);
  animation: binding-blink 0.7s steps(2, end) infinite;
}
@keyframes binding-blink {
  0%, 100% { background: var(--yellow); }
  50%      { background: #fff7c2; }
}
.binding-rebind,
.binding-reset {
  font-family: var(--pixel-font);
  font-size: 9px;
  letter-spacing: 0.22em;
  color: var(--ink-deep);
  background: var(--yellow);
  border: 2px solid var(--orange-deep);
  padding: 6px 12px;
  cursor: pointer;
  text-shadow: 1px 1px 0 rgba(255,255,255,0.4);
}
.binding-rebind:hover,
.binding-reset:hover { background: #fff7c2; }
.binding-rebind:active,
.binding-reset:active { transform: translateY(1px); }
.binding-reset {
  margin-top: 4px;
  align-self: center;
  background: var(--panel);
  color: var(--accent);
  border-color: var(--panel-edge);
  text-shadow: 1px 1px 0 #000;
}
.binding-reset:hover { background: #1a2e54; color: var(--yellow); }

.mode-select-aux {
  display: block;
  margin: 8px auto 0;
  padding: 8px 18px;
  background: var(--panel);
  border: 2px solid var(--panel-edge);
  color: var(--accent);
  font-family: var(--pixel-font);
  font-size: 9px;
  letter-spacing: 0.3em;
  cursor: pointer;
  text-shadow: 1px 1px 0 #000;
  text-decoration: none; /* anchor-form aux button (DOWNLOAD DESKTOP) */
  transition: transform 90ms steps(2), background 90ms, border-color 90ms, color 90ms;
}
.mode-select-aux:hover {
  background: #1a2e54;
  border-color: var(--orange);
  color: var(--yellow);
  transform: translateY(-2px);
}
.mode-select-aux:active { transform: translateY(1px); }

/* Tiered main menu: 3 columns × 2 rows on wide viewports. Each tile
   carries a small uppercase tag chip in the corner so the user can
   scan the row by category (OFFLINE / ONLINE / RANKED / HOST / etc.). */
.mode-grid-main {
  grid-template-columns: repeat(auto-fit, minmax(240px, 280px));
  max-width: 920px;
}
.mode .mode-tag {
  align-self: flex-start;
  font-size: 7px; letter-spacing: 0.28em;
  color: rgba(244,246,251,0.85);
  background: rgba(8,12,22,0.55);
  border: 1px solid rgba(108,193,255,0.4);
  padding: 2px 8px 1px;
  border-radius: 2px;
  text-shadow: 1px 1px 0 #000;
}
.mode .mode-tag-ranked {
  color: #ffd86a;
  border-color: rgba(255,216,106,0.7);
  background: rgba(64,40,12,0.65);
}
/* Per-tile accent — competitive gets a gold-leaning edge, casual a
   green one, create the warm orange, training a cool blue. Hover still
   pushes everything to the shared orange highlight. */
.mode.mode-comp { border-color: rgba(255,216,106,0.55); }
.mode.mode-comp .mode-name { color: var(--yellow); }
.mode.mode-casual .mode-name { color: var(--green-bright); }
.mode.mode-create { border-color: rgba(255,160,44,0.45); }
.mode.mode-training { border-color: rgba(108,193,255,0.35); }
.mode.mode-browse  { border-color: rgba(108,193,255,0.35); }
.mode .mode-rating {
  align-self: flex-start;
  margin-top: 6px;
  font-size: 11px; letter-spacing: 0.24em;
  color: var(--green-bright);
  text-shadow: 1px 1px 0 #000;
}
.mode .mode-rating .mode-rating-tier {
  color: rgba(244,246,251,0.65);
  font-size: 8px;
  letter-spacing: 0.18em;
  margin-left: 8px;
}
/* WORLD CLASS — gold gradient text + faint glow so it visibly sits
   above the regular rank badges. Reserved for the top 500 players by
   progress globally (see server/ratings.js). */
.mode .mode-rating.mode-rating-world-class {
  color: var(--yellow);
  text-shadow: 2px 2px 0 var(--orange-deep), 0 0 12px rgba(255,236,138,0.5);
  letter-spacing: 0.3em;
}

/* Universal BACK button used by intermediate pickers (casual-mode-pick,
   create-visibility-pick, room-mode-pick). Sits below the .hint line. */
.overlay-back {
  margin-top: 6px;
  padding: 8px 18px;
  background: var(--panel);
  border: 2px solid var(--panel-edge);
  color: var(--accent);
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.3em;
  cursor: pointer;
  text-shadow: 1px 1px 0 #000;
  transition: transform 90ms steps(2), background 90ms, border-color 90ms, color 90ms;
}
.overlay-back:hover {
  background: #1a2e54;
  border-color: var(--orange);
  color: var(--yellow);
  transform: translateY(-2px);
}
.overlay-back:active { transform: translateY(1px); }

/* Warehouse-edit toolbar — pinned top-left when the WAREHOUSE EDIT
   entry point is active. Buttons mirror the T/B/P/O hotkeys; the
   active mode gets a coloured outline. PUBLISH POSTs the saved edits
   to /admin/2v2-canonical so every online 2v2 match picks them up. */
#editor-bar {
  position: absolute;
  top: 12px;
  left: 12px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px;
  background: rgba(15,29,54,0.92);
  border: 1px solid var(--panel-edge);
  border-radius: 6px;
  font-family: var(--pixel-font);
  font-size: 10px;
  letter-spacing: 0.12em;
  z-index: 50;
  pointer-events: auto;
}
#editor-bar.hidden { display: none; }
.editor-bar-title {
  color: var(--accent);
  text-align: center;
  padding: 2px 0 4px;
  border-bottom: 1px solid rgba(108,193,255,0.25);
  margin-bottom: 2px;
}
.editor-mode-btn {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px;
  padding: 6px 8px;
  background: rgba(26,34,54,0.6);
  color: rgba(244,246,251,0.6);
  border: 1px solid rgba(108,193,255,0.2);
  border-radius: 4px;
  font-family: inherit;
  font-size: 10px;
  letter-spacing: 0.12em;
  cursor: pointer;
  text-align: left;
}
.editor-mode-btn:hover {
  color: var(--white);
  border-color: rgba(108,193,255,0.5);
}
.editor-mode-btn.active {
  background: rgba(108,193,255,0.18);
  color: var(--accent);
  border-color: var(--accent);
}
.editor-mode-btn .key {
  display: inline-block;
  min-width: 14px;
  padding: 1px 4px;
  background: rgba(0,0,0,0.4);
  border: 1px solid rgba(108,193,255,0.3);
  border-radius: 2px;
  text-align: center;
  font-size: 9px;
}
#editor-undo, #editor-clear, #editor-publish {
  margin-top: 4px;
  padding: 5px 8px;
  background: rgba(108,193,255,0.12);
  color: var(--accent);
  border: 1px solid rgba(108,193,255,0.4);
  border-radius: 4px;
  font-family: inherit;
  font-size: 9px;
  letter-spacing: 0.12em;
  cursor: pointer;
}
#editor-undo:hover, #editor-clear:hover, #editor-publish:hover {
  background: rgba(108,193,255,0.25);
}
#editor-undo:disabled, #editor-clear:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
#editor-clear {
  background: rgba(255,90,26,0.15);
  color: var(--orange);
  border-color: rgba(255,90,26,0.4);
}
#editor-clear:hover { background: rgba(255,90,26,0.3); }
#editor-publish {
  background: rgba(95,180,114,0.18);
  color: #5fb472;
  border-color: rgba(95,180,114,0.55);
}
#editor-publish:hover { background: rgba(95,180,114,0.32); }

/* Match-end Elo block — shown only for ranked 1v1 matches. Centred
   under the winner text; the delta colour cues whether the user climbed
   (green) or dropped (red). */
.match-end-rating {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  margin: 6px 0 4px;
  padding: 12px 22px;
  background: var(--panel);
  border: 3px solid var(--panel-edge);
  font-family: var(--pixel-font);
  text-shadow: 1px 1px 0 #000;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000;
}
.match-end-rating.hidden { display: none; }
.match-end-rating .rating-row { display: flex; align-items: baseline; gap: 12px; }
.match-end-rating .rating-label {
  font-size: 9px; letter-spacing: 0.32em;
  color: var(--accent);
}
.match-end-rating .rating-value {
  font-size: 22px; letter-spacing: 0.2em;
  color: var(--green-bright);
}
.match-end-rating .rating-delta {
  font-size: 14px; letter-spacing: 0.18em;
}
.match-end-rating .rating-delta.delta-up    { color: var(--green-bright); }
.match-end-rating .rating-delta.delta-down  { color: var(--orange-deep); }
.match-end-rating .rating-progress {
  font-size: 9px; letter-spacing: 0.28em;
  color: rgba(244,246,251,0.65);
}
.match-end-rating .rating-value.rating-value-world-class {
  color: var(--yellow);
  text-shadow: 2px 2px 0 var(--orange-deep), 0 0 14px rgba(255,236,138,0.55);
}

/* Slow-motion replay badge — pulses in the top centre during the
   replay window between round-end and the next countdown. Hidden by
   default; opacity is animated for a soft fade in/out. */
#replay-badge {
  position: fixed;
  top: 24px; left: 50%;
  transform: translateX(-50%);
  padding: 10px 22px 10px 18px;
  font-family: var(--pixel-font);
  font-size: 12px;
  letter-spacing: 0.42em;
  color: var(--yellow);
  background: var(--panel);
  border: 3px solid var(--orange);
  border-radius: 0;
  text-shadow: 2px 2px 0 var(--orange-deep), 3px 3px 0 #000;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.08),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000,
    0 0 22px rgba(255,160,44,0.4);
  z-index: 50;
  pointer-events: none;
  animation: replay-pulse 1.4s ease-in-out infinite;
  transition: opacity 220ms;
}
/* display:none (not opacity:0) because the replay-pulse keyframe animation
   below overrides any opacity rule, leaving the badge visible at boot. */
#replay-badge.hidden { display: none; }
#replay-badge::before { content: '\25B8 '; color: var(--orange); }
@keyframes replay-pulse {
  0%, 100% { opacity: 0.85; }
  50%      { opacity: 1; }
}

/* Big countdown number — centred, semi-transparent bg behind it. */
#countdown {
  position: fixed; inset: 0; z-index: 30;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
  background: rgba(10,14,26,0.25);
  transition: opacity 180ms;
}
#countdown.hidden { opacity: 0; pointer-events: none; }
#countdown .num {
  font-family: var(--pixel-font);
  font-size: 120px;
  letter-spacing: 0.05em;
  color: var(--yellow);
  text-shadow:
    6px 6px 0 var(--orange-deep),
    10px 10px 0 #000,
    0 0 32px rgba(255,160,44,0.6),
    0 0 64px rgba(108,193,255,0.35);
  font-weight: 400;
}
#countdown .num.go {
  color: var(--green-bright);
  text-shadow:
    6px 6px 0 #1a8a2f,
    10px 10px 0 #000,
    0 0 32px rgba(93,217,122,0.7),
    0 0 64px rgba(93,217,122,0.4);
}

/* Score banner top-centre during play. */
#score-banner {
  position: fixed; top: 12px; left: 50%; transform: translateX(-50%);
  z-index: 4;
  display: flex; align-items: center; gap: 14px;
  padding: 8px 18px;
  background: var(--panel);
  border: 3px solid var(--panel-edge);
  border-radius: 0;
  font-family: var(--pixel-font);
  font-size: 11px;
  color: var(--white);
  letter-spacing: 0.18em;
  pointer-events: none;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.06),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 3px 0 #000;
}
#score-banner.hidden { display: none; }
#score-banner .score-side {
  min-width: 18px; text-align: center;
  font-size: 14px;
  text-shadow: 2px 2px 0 #000;
}
#score-banner .score-side.player { color: var(--accent); }
#score-banner .score-side.dummy  { color: var(--orange); }
#score-banner .score-sep { color: rgba(244,246,251,0.4); }

/* Zone-closing warning — large red pixel banner that pulses for the
   final 5 seconds of the round's grace window. Sits just below the
   score banner so the two read as a stack. */
#zone-warning {
  position: fixed;
  top: 56px; left: 50%; transform: translateX(-50%);
  z-index: 5;
  padding: 8px 22px;
  font-family: var(--pixel-font);
  font-size: 16px;
  letter-spacing: 0.32em;
  color: #ff3a3a;
  background: rgba(20, 8, 8, 0.6);
  border: 3px solid #ff3a3a;
  text-shadow: 2px 2px 0 #000, 0 0 18px rgba(255, 58, 58, 0.7);
  pointer-events: none;
  animation: zone-warning-pulse 0.7s ease-in-out infinite;
}
#zone-warning.hidden { display: none; }
#zone-warning .zone-warning-num {
  display: inline-block;
  min-width: 1.4em;
  text-align: center;
  margin-left: 0.4em;
  color: #ffd54a;
}
@keyframes zone-warning-pulse {
  0%, 100% { opacity: 0.85; transform: translateX(-50%) scale(1); }
  50%      { opacity: 1;    transform: translateX(-50%) scale(1.04); }
}

#stage {
  background: linear-gradient(180deg, #0a1f1a 0%, #102818 60%, #1a2a14 100%);
  image-rendering: pixelated;
  /* Stretch the canvas to fill the entire viewport so the cursor is
     geometrically over the play area no matter where it goes. The canvas's
     internal resolution stays 1600×880; the browser scales pixels to fit. */
  width: 100vw;
  height: 100vh;
  border: none;
  cursor: none;
}

#hud {
  position: absolute; inset: 0;
  pointer-events: none;
  display: grid;
  grid-template-columns: 1fr 2fr 1fr;
  align-items: end;
  padding: 16px;
  gap: 16px;
}

#hud-left { display: flex; flex-direction: column; gap: 6px; }
#hud-center { display: flex; flex-direction: column; align-items: center; gap: 8px; }

.status {
  font-size: 11px; letter-spacing: 0.18em;
  padding: 4px 8px; border-radius: 4px;
  background: rgba(26,34,54,0.7);
  color: rgba(244,246,251,0.4);
  border: 1px solid rgba(108,193,255,0.15);
  transition: color 80ms, border-color 80ms, background 80ms;
}
/* Hide a status pip entirely. Toggled per character — e.g. only Shadow
   shows the second JUMP indicator; for everyone else the element exists
   but is display:none so the column doesn't reserve space for it. */
.status.hidden { display: none; }

/* Status pip in its "ready" state — used by the DASH and JUMP indicators
   to flash yellow when the gating resource is full (elixir for dash,
   one or more jump charges available for jump). */
.status.ready {
  color: var(--yellow);
  border-color: var(--yellow);
  background: rgba(255,236,138,0.18);
}

/* Slot counter — currently used by Shadow's slots 2 & 3 to show the
   shared "ninja charges" pool ("3/5"). Sits in the upper-left of the
   slot, opposite the digit key on the upper-right. Hidden via .hidden
   for non-Shadow characters. */
.slot .counter {
  position: absolute; top: 4px; left: 6px;
  font-size: 10px; letter-spacing: 0.05em;
  color: var(--yellow);
  text-shadow: 0 1px 0 rgba(0,0,0,0.6);
  pointer-events: none;
}
.slot .counter.hidden { display: none; }

#elixir-wrap {
  width: 380px; height: 14px; border-radius: 8px;
  background: rgba(26,34,54,0.85);
  border: 1px solid rgba(108,193,255,0.25);
  overflow: hidden;
  position: relative;
}
#elixir-fill {
  height: 100%; width: 60%;
  background: linear-gradient(90deg, var(--blue), var(--accent));
  box-shadow: 0 0 12px rgba(108,193,255,0.6) inset;
  transition: width 120ms, background 200ms, box-shadow 200ms;
}
#loadout { display: flex; gap: 8px; }

/* Mech-ult control overlay. Mirrors the loadout's pill aesthetic but
   sits below it. .hidden cleanly drops it when the player isn't in
   mech form. The airstrike cooldown text sits centered over its pill
   when active. */
#mech-controls {
  display: flex; gap: 10px;
  justify-content: center;
  margin-top: 8px;
}
#mech-controls.hidden { display: none; }
.mech-slot {
  min-width: 96px; height: 38px;
  background: rgba(60,18,18,0.85);
  border: 1px solid rgba(255,90,90,0.55);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
  position: relative;
  box-shadow: 0 0 12px rgba(255,80,80,0.25) inset;
}
.mech-key {
  font: 600 11px ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 0.1em;
  color: rgba(255,230,200,0.85);
  margin-right: 8px;
  padding: 2px 6px;
  background: rgba(0,0,0,0.4);
  border-radius: 4px;
}
.mech-label {
  font: 700 13px ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 0.12em;
  color: #ffe6b0;
  text-shadow: 1px 1px 0 #000;
}
.mech-cd {
  position: absolute; right: 6px; bottom: 2px;
  font: 600 10px ui-monospace, "Cascadia Mono", Consolas, monospace;
  color: rgba(255,200,140,0.85);
}
.mech-slot.cd-active { opacity: 0.55; }
.slot {
  width: 56px; height: 56px;
  background: rgba(26,34,54,0.85);
  border: 1px solid rgba(108,193,255,0.2);
  border-radius: 8px;
  position: relative;
  transition: border-color 80ms, box-shadow 120ms, background 120ms;
}
.slot .key {
  position: absolute; top: 4px; right: 6px;
  font-size: 10px; letter-spacing: 0.1em;
  color: rgba(244,246,251,0.55);
}
.slot .label {
  position: absolute; bottom: 5px; left: 0; right: 0;
  text-align: center;
  font: 600 12px ui-monospace, "Cascadia Mono", Consolas, monospace;
  letter-spacing: 0.1em;
  color: rgba(244,246,251,0.85);
  text-shadow: 1px 1px 0 #000;
}

/* Pixel-art weapon icon — fills the slot's interior above the label. The
   inner SVG is rendered with shape-rendering="crispEdges" so each pixel
   stays sharp at the up-scaled display size. Stacking: icon below the
   cooldown overlay (so the overlay can dim it) but the .key + .label sit
   above the overlay so they stay legible while a cooldown is draining. */
.slot .icon {
  position: absolute;
  top: 4px; left: 4px; right: 4px;
  height: 36px;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none;
  filter: drop-shadow(1px 1px 0 rgba(0,0,0,0.55));
  z-index: 0;
}
.slot .icon svg {
  width: 100%; height: 100%;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}
/* Merged-ability slot — when a slot hosts more than one weapon kind
   (Shadow's slot 1: shuriken LMB + teleport orb RMB), the icon
   container lays the SVGs out side-by-side at half width. The label
   below the icon area still tells the player which kinds these are
   ("SHK·TLP"). */
.slot .icon.icon-multi {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
}
.slot .icon.icon-multi svg {
  width: 50%;
  height: 100%;
}
.slot .cd-overlay { z-index: 1; }
.slot .key,
.slot .label { z-index: 2; }

.slot[data-weapon="rocket"] {
  background: rgba(255,122,26,0.16);
  border-color: rgba(255,122,26,0.4);
}
.slot[data-weapon="rocket"] .label { color: var(--orange); }

.slot[data-weapon="shockwave"] {
  background: rgba(168,208,255,0.16);
  border-color: rgba(168,208,255,0.45);
}
.slot[data-weapon="shockwave"] .label { color: #a8d0ff; }

.slot[data-weapon="shockwave"].active {
  background: rgba(168,208,255,0.30);
  border-color: #a8d0ff;
  box-shadow: 0 0 14px rgba(168,208,255,0.55);
}

/* Pulsing "ready to cast" glow — applied via JS when the local player's
   elixir bar is full (the shockwave's gate). Same energy-cyan palette. */
.slot[data-weapon="shockwave"].shockwave-ready {
  border-color: #cfe6ff;
  box-shadow: 0 0 18px rgba(168,208,255,0.75), 0 0 28px rgba(207,230,255,0.55);
  animation: shockwave-pulse 1.4s ease-in-out infinite;
}
@keyframes shockwave-pulse {
  0%, 100% { box-shadow: 0 0 14px rgba(168,208,255,0.6), 0 0 22px rgba(207,230,255,0.4); }
  50%      { box-shadow: 0 0 22px rgba(168,208,255,0.9), 0 0 34px rgba(207,230,255,0.65); }
}

.slot[data-weapon="rifle"] {
  background: rgba(255,236,138,0.14);
  border-color: rgba(255,236,138,0.45);
}
.slot[data-weapon="rifle"] .label { color: #ffec8a; }
.slot[data-weapon="rifle"].active {
  background: rgba(255,236,138,0.28);
  border-color: #ffec8a;
  box-shadow: 0 0 14px rgba(255,236,138,0.55);
}

.slot[data-weapon="hammer"] {
  background: rgba(108,193,255,0.14);
  border-color: rgba(108,193,255,0.45);
}
.slot[data-weapon="hammer"] .label { color: #6cc1ff; }

.slot[data-weapon="hammer"].active {
  background: rgba(108,193,255,0.28);
  border-color: #6cc1ff;
  box-shadow: 0 0 14px rgba(108,193,255,0.55);
}

.slot[data-weapon="grapple"] {
  background: rgba(179,120,255,0.16);
  border-color: rgba(179,120,255,0.45);
}
.slot[data-weapon="grapple"] .label { color: #b378ff; }

.slot[data-weapon="grapple"].active {
  background: rgba(179,120,255,0.28);
  border-color: #b378ff;
  box-shadow: 0 0 14px rgba(179,120,255,0.55);
}

.slot[data-weapon="gasUlt"] {
  background: rgba(74,209,122,0.16);
  border-color: rgba(74,209,122,0.45);
  overflow: hidden;
}
.slot[data-weapon="gasUlt"] .label { color: #4ad17a; }

.slot[data-weapon="gasUlt"].active {
  background: rgba(74,209,122,0.30);
  border-color: #4ad17a;
  box-shadow: 0 0 14px rgba(74,209,122,0.55);
}
/* The gasUlt slot reuses the laser slot's `.ult-fill` element + the
   `ult-ready` class, so when ultCharge fills the bar pulses ready. */
.slot[data-weapon="gasUlt"] .ult-fill {
  background: linear-gradient(180deg, rgba(74,209,122,0.4), rgba(163,238,189,0.65));
}
.slot[data-weapon="gasUlt"].ult-ready .ult-fill {
  background: linear-gradient(180deg, rgba(74,209,122,0.6), rgba(207,255,224,0.75));
}
.slot[data-weapon="gasUlt"].ult-ready {
  border-color: #cfffe0;
  box-shadow: 0 0 18px rgba(74,209,122,0.7), 0 0 28px rgba(163,238,189,0.45);
  animation: ult-pulse 1.4s ease-in-out infinite;
}

/* Cloak (Shadow's slot 4) — purple palette to match the ping-ring colour.
   Same .ult-fill + .ult-ready glow contract as laser/gasUlt. */
.slot[data-weapon="cloak"] {
  background: rgba(106,58,160,0.18);
  border-color: rgba(106,58,160,0.5);
  overflow: hidden;
}
.slot[data-weapon="cloak"] .label { color: #caa6ff; }
.slot[data-weapon="cloak"].active {
  background: rgba(106,58,160,0.32);
  border-color: #caa6ff;
  box-shadow: 0 0 14px rgba(106,58,160,0.6);
}
.slot[data-weapon="cloak"] .ult-fill {
  background: linear-gradient(180deg, rgba(106,58,160,0.42), rgba(202,166,255,0.68));
}
.slot[data-weapon="cloak"].ult-ready .ult-fill {
  background: linear-gradient(180deg, rgba(150,90,220,0.65), rgba(220,190,255,0.80));
}
.slot[data-weapon="cloak"].ult-ready {
  border-color: #f0e0ff;
  box-shadow: 0 0 18px rgba(150,90,220,0.7), 0 0 28px rgba(202,166,255,0.5);
  animation: ult-pulse 1.4s ease-in-out infinite;
}

.slot[data-weapon="jetpack"] {
  background: rgba(255,170,90,0.16);
  border-color: rgba(255,170,90,0.45);
}
.slot[data-weapon="jetpack"] .label { color: #ffaa5a; }

.slot[data-weapon="jetpack"].active {
  background: rgba(255,170,90,0.30);
  border-color: #ffaa5a;
  box-shadow: 0 0 14px rgba(255,170,90,0.55);
}

/* Jetpack fuel bar — same well as ult-fill but warm orange to match the
   exhaust palette. Hidden unless the slot is currently the jetpack
   (driven by JS in updateHud, which leaves height at 0% otherwise). */
.slot .fuel-fill {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 0%;
  background: linear-gradient(180deg, rgba(255,170,90,0.35), rgba(255,210,140,0.65));
  transition: height 100ms;
  pointer-events: none;
}
.slot[data-weapon="jetpack"] .fuel-fill {
  background: linear-gradient(180deg, rgba(255,170,90,0.45), rgba(255,210,140,0.75));
}
/* Wretched's ball-fuel meter — red palette to match the dark-Valeris kit. */
.slot[data-weapon="sonicBall"] .fuel-fill {
  background: linear-gradient(180deg, rgba(180,20,20,0.45), rgba(255,80,80,0.85));
}

.slot[data-weapon="laser"] {
  background: rgba(255,119,255,0.16);
  border-color: rgba(255,119,255,0.4);
  overflow: hidden;
}
.slot[data-weapon="laser"] .label { color: #ff77ff; }

.slot .ult-fill {
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 0%;
  background: linear-gradient(180deg, rgba(255,210,80,0.3), rgba(255,210,80,0.55));
  transition: height 140ms;
  pointer-events: none;
}
.slot[data-weapon="laser"].ult-ready .ult-fill {
  background: linear-gradient(180deg, rgba(255,119,255,0.55), rgba(255,210,80,0.65));
}
.slot[data-weapon="laser"].ult-ready {
  border-color: #fff5b8;
  box-shadow: 0 0 18px rgba(255,210,80,0.7), 0 0 28px rgba(255,119,255,0.45);
  animation: ult-pulse 1.4s ease-in-out infinite;
}
@keyframes ult-pulse {
  0%, 100% { box-shadow: 0 0 14px rgba(255,210,80,0.6), 0 0 22px rgba(255,119,255,0.35); }
  50%      { box-shadow: 0 0 22px rgba(255,210,80,0.85), 0 0 34px rgba(255,119,255,0.55); }
}

/* Lancer — slate-steel kit. JST joust (slate-grey), BLW bulwark
   (lance-light blue), XBW crossbow (warm wood-brown), TBL Round Table
   ult (royal gold). Round Table reuses the .ult-fill + .ult-ready
   ult contract so the bar visualizes ultCharge progress. */
.slot[data-weapon="joust"] {
  background: rgba(190,200,215,0.14);
  border-color: rgba(190,200,215,0.4);
}
.slot[data-weapon="joust"] .label { color: #d6dde8; }
.slot[data-weapon="joust"].active {
  background: rgba(190,200,215,0.28);
  border-color: #f0f4fa;
  box-shadow: 0 0 14px rgba(190,200,215,0.55);
}

.slot[data-weapon="bulwark"] {
  background: rgba(100,160,220,0.14);
  border-color: rgba(100,160,220,0.4);
}
.slot[data-weapon="bulwark"] .label { color: #6cb4ff; }
.slot[data-weapon="bulwark"].active {
  background: rgba(100,160,220,0.28);
  border-color: #6cb4ff;
  box-shadow: 0 0 14px rgba(100,160,220,0.55);
}
/* Pulsing "ready to raise" glow — toggled by JS when the local
   player has full elixir AND at least one bulwark charge available
   (the full-bar gate is the dome's hard activation requirement). */
.slot[data-weapon="bulwark"].bulwark-ready {
  border-color: #cfe6ff;
  box-shadow: 0 0 18px rgba(108,180,255,0.7), 0 0 28px rgba(207,230,255,0.5);
  animation: shockwave-pulse 1.4s ease-in-out infinite;
}

.slot[data-weapon="crossbow"] {
  background: rgba(150,90,40,0.14);
  border-color: rgba(195,140,80,0.42);
}
.slot[data-weapon="crossbow"] .label { color: #d8a060; }
.slot[data-weapon="crossbow"].active {
  background: rgba(150,90,40,0.28);
  border-color: #d8a060;
  box-shadow: 0 0 14px rgba(195,140,80,0.55);
}
/* Crossbow stored indicator — slot pulses orange-gold while a bolt
   is loaded, so the player can glance at slot 3 and see "ready". */
.slot[data-weapon="crossbow"].crossbow-loaded {
  border-color: #fff0a0;
  box-shadow: 0 0 16px rgba(255,200,90,0.7), 0 0 24px rgba(255,170,60,0.4);
  animation: ult-pulse 1.4s ease-in-out infinite;
}

.slot[data-weapon="roundTable"] {
  background: rgba(180,140,60,0.18);
  border-color: rgba(220,180,80,0.5);
  overflow: hidden;
}
.slot[data-weapon="roundTable"] .label { color: #ffd86a; }
.slot[data-weapon="roundTable"].active {
  background: rgba(180,140,60,0.32);
  border-color: #ffd86a;
  box-shadow: 0 0 14px rgba(220,180,80,0.6);
}
.slot[data-weapon="roundTable"] .ult-fill {
  background: linear-gradient(180deg, rgba(180,140,60,0.42), rgba(255,216,106,0.68));
}
.slot[data-weapon="roundTable"].ult-ready .ult-fill {
  background: linear-gradient(180deg, rgba(220,180,80,0.65), rgba(255,235,150,0.80));
}
.slot[data-weapon="roundTable"].ult-ready {
  border-color: #fff5d0;
  box-shadow: 0 0 18px rgba(255,216,106,0.7), 0 0 28px rgba(255,235,150,0.5);
  animation: ult-pulse 1.4s ease-in-out infinite;
}

.slot.active {
  background: rgba(244,246,251,0.08);
  border-color: rgba(244,246,251,0.7);
  box-shadow: 0 0 14px rgba(244,246,251,0.25);
}

/* Cooldown overlay — height proportional to remaining cooldown.
   Sits below the key/label spans (DOM-order earlier = paints below).
   The 80ms ease softens the per-tick height jumps from updateHud. */
.cd-overlay {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 0%;
  background: linear-gradient(180deg, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.4) 100%);
  pointer-events: none;
  border-radius: 7px 7px 0 0;
  transition: height 80ms linear;
}
.slot[data-weapon="rocket"].active {
  background: rgba(255,122,26,0.28);
  border-color: var(--orange);
  box-shadow: 0 0 14px rgba(255,122,26,0.55);
}
.slot[data-weapon="laser"].active {
  background: rgba(255,119,255,0.28);
  border-color: #ff77ff;
  box-shadow: 0 0 14px rgba(255,119,255,0.55);
}

/* Pointer-lock hint — only surfaced during the round-start countdown
   (input.js gates `.show` on the #countdown overlay's visibility).
   Pinned to the top of the viewport so it never covers the countdown
   number in the middle of the screen. */
#lock-hint {
  position: fixed;
  top: 24px; left: 50%;
  transform: translateX(-50%);
  display: none; flex-direction: column;
  align-items: center;
  gap: 6px;
  color: var(--white);
  font-family: var(--pixel-font);
  font-size: 11px; letter-spacing: 0.22em; text-transform: uppercase;
  pointer-events: none;
  z-index: 60;
}
#lock-hint.show { display: flex; }
#lock-hint span {
  padding: 10px 18px;
  border: 3px solid var(--orange);
  border-radius: 0;
  background: var(--panel);
  color: var(--yellow);
  text-shadow: 2px 2px 0 #000;
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,0.08),
    inset 0 -2px 0 rgba(0,0,0,0.45),
    0 4px 0 #000,
    0 0 18px rgba(255,160,44,0.4);
  animation: tag-blink 1.2s steps(2, end) infinite;
}
#lock-hint small {
  font-size: 8px; letter-spacing: 0.28em;
  color: var(--accent);
  text-shadow: 1px 1px 0 #000;
}

/* Footer row holding the SIGN IN + BINDINGS aux buttons. Side-by-side
   so the menu's last line still reads as a horizontal toolbar. */
.mode-select-footer {
  display: flex; gap: 14px; align-items: center; justify-content: center;
  margin-top: 8px;
}
.mode-select-footer .mode-select-aux { margin: 0; }
.mode-select-aux.mode-select-aux-active {
  border-color: var(--green-bright);
  color: var(--green-bright);
}

/* Auth modal — log-in / sign-up form. Inherits .match-overlay so it
   gets the pixel-grid background; everything below is just form layout. */
.auth-tabs {
  display: flex; gap: 6px;
  margin-bottom: 6px;
}
.auth-tab {
  padding: 8px 18px;
  background: var(--panel);
  border: 2px solid var(--panel-edge);
  color: var(--accent);
  font-family: var(--pixel-font);
  font-size: 9px;
  letter-spacing: 0.3em;
  cursor: pointer;
  text-shadow: 1px 1px 0 #000;
}
.auth-tab:hover { background: #1a2e54; color: var(--yellow); border-color: var(--orange); }
.auth-tab.auth-tab-active {
  background: #1a2e54;
  border-color: var(--yellow);
  color: var(--yellow);
}
.auth-form {
  display: flex; flex-direction: column; gap: 10px;
  width: min(360px, 90vw);
  background: rgba(8,12,22,0.55);
  border: 3px solid var(--panel-edge);
  padding: 18px 20px 16px;
}
.auth-label {
  display: flex; flex-direction: column; gap: 6px;
  font-family: var(--pixel-font);
  font-size: 8px;
  letter-spacing: 0.28em;
  color: var(--accent);
  text-shadow: 1px 1px 0 #000;
}
.auth-label input {
  font-family: var(--pixel-font);
  font-size: 12px;
  letter-spacing: 0.18em;
  padding: 8px 10px;
  background: var(--ink-deep);
  border: 2px solid var(--panel-edge);
  color: var(--white);
}
.auth-label input:focus { outline: none; border-color: var(--orange); }
.auth-hint {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 7px;
  letter-spacing: 0.18em;
  color: rgba(108,193,255,0.7);
  text-shadow: 1px 1px 0 #000;
}
.auth-error {
  margin: 0;
  font-family: var(--pixel-font);
  font-size: 8px;
  letter-spacing: 0.18em;
  color: var(--orange);
  text-shadow: 1px 1px 0 #000;
}
.auth-error.hidden { display: none; }
.auth-actions {
  display: flex; gap: 10px; justify-content: flex-end;
  margin-top: 4px;
}
.auth-actions button {
  padding: 10px 18px;
  background: var(--panel);
  border: 2px solid var(--panel-edge);
  color: var(--accent);
  font-family: var(--pixel-font);
  font-size: 9px;
  letter-spacing: 0.3em;
  cursor: pointer;
  text-shadow: 1px 1px 0 #000;
}
.auth-actions #auth-submit {
  background: var(--yellow);
  color: var(--ink-deep);
  border-color: var(--orange-deep);
  text-shadow: none;
}
.auth-actions button:hover { transform: translateY(-2px); border-color: var(--orange); }
.auth-actions button:active { transform: translateY(1px); }

