:root {
  color-scheme: dark;
  --bg: #070b16;
  --panel: #04060f;
  --ink: #e2e8f0;
  --muted: #94a3b8;
  --p1: #7dd3fc;
  --p2: #f472b6;
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 24px;
  background:
    radial-gradient(circle at 20% 0%, rgba(125, 211, 252, 0.12), transparent 40%),
    radial-gradient(circle at 80% 100%, rgba(244, 114, 182, 0.12), transparent 40%),
    var(--bg);
  color: var(--ink);
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  user-select: none;
}

.game-shell {
  width: min(100%, 880px);
  display: grid;
  gap: 14px;
}

.hud {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

/* The title lives in the field now; keep the h1 for screen readers only. */
.hud h1 {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.hud .touch-controls {
  margin-left: auto;
}

/* Keyboard help: bottom edge of the field, just above the panel. */
.hint {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 8px;
  margin: 0;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-align: center;
  color: var(--muted);
  opacity: 0.7;
  pointer-events: none;
}

/* While a match is running, game.js paints this line on the canvas under the
   dishes and the ball. The DOM copy stays for the menus. */
.hint.is-field {
  opacity: 0;
}

.canvas-wrap {
  position: relative;
  overflow: hidden;
  border-radius: 16px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  background: var(--panel);
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.45),
    inset 0 0 0 1px rgba(255, 255, 255, 0.02);
}

canvas {
  display: block;
  width: 100%;
  height: auto;
  cursor: crosshair;
  touch-action: none;
  -webkit-touch-callout: none;
  user-select: none;
}

.overlay {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  justify-items: center;
  gap: 8px;
  text-align: center;
  background: rgba(7, 11, 22, 0.55);
  backdrop-filter: blur(4px);
  pointer-events: none;
  transition: opacity 160ms ease, visibility 160ms ease;
}

[hidden] {
  display: none !important;
}

/* The versus win screen is a celebration on the open field: no dim, no blur. */
.overlay.clear {
  background: none;
  backdrop-filter: none;
}

.overlay.hidden {
  opacity: 0;
  visibility: hidden;
}

.overlay p {
  margin: 0;
}

/* Title: a signal on a screen. Glow, faint flicker and slow scan lines. */
#overlay-title {
  position: relative;
  font-size: clamp(28px, 6vw, 44px);
  font-weight: 800;
  letter-spacing: 0.08em;
  color: #e0f2fe;
  text-shadow: 0 0 6px rgba(125, 211, 252, 0.85), 0 0 22px rgba(125, 211, 252, 0.45);
  text-wrap: balance;
}

#overlay-title::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(4, 6, 14, 0.4) 0 1px, transparent 1px 3px);
  background-size: 100% 6px;
}

/* The home title is steady: no flicker, only faint scan lines. */
.overlay[data-screen="select"] #overlay-title::after {
  background: repeating-linear-gradient(0deg, rgba(4, 6, 14, 0.22) 0 1px, transparent 1px 3px);
  background-size: 100% 6px;
}

@keyframes sig-flicker {
  0%, 40%, 44%, 76%, 79%, 100% { opacity: 1; }
  41% { opacity: 0.78; }
  42% { opacity: 0.95; }
  43% { opacity: 0.7; }
  77% { opacity: 0.85; }
  78% { opacity: 0.6; }
}

/* Static burst (class set by game.js every 5-15 s on the home screen, 1.2 s):
   the letters fade down while a patch of SIGNAL LOST style static (dense
   noise, jumping grain, a couple of tear lines) fades in over the title box
   and fades out as the letters return. The patch is a little larger than the
   title and has soft edges. Nothing runs between bursts. */
.overlay[data-screen="select"] #overlay-title::before {
  content: "";
  position: absolute;
  inset: -16px -30px;
  pointer-events: none;
  opacity: 0;
  background-image:
    var(--noise, none),
    linear-gradient(transparent 28%, rgba(224, 242, 254, 0.7) 28%, rgba(224, 242, 254, 0.7) 32%, transparent 32%, transparent 66%, rgba(224, 242, 254, 0.5) 66%, rgba(224, 242, 254, 0.5) 69%, transparent 69%),
    linear-gradient(rgba(2, 4, 10, 0.6), rgba(2, 4, 10, 0.6));
  background-size: 320px 200px, 100% 100%, 100% 100%;
  background-repeat: repeat, repeat-y, no-repeat;
  image-rendering: pixelated;
  -webkit-mask-image:
    linear-gradient(to right, transparent, #000 22%, #000 78%, transparent),
    linear-gradient(to bottom, transparent, #000 38%, #000 62%, transparent);
  mask-image:
    linear-gradient(to right, transparent, #000 22%, #000 78%, transparent),
    linear-gradient(to bottom, transparent, #000 38%, #000 62%, transparent);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

.overlay[data-screen="select"] #overlay-title.burst {
  animation: title-burst-text 1.2s ease-in-out both;
}

.overlay[data-screen="select"] #overlay-title.burst::before {
  animation: title-burst-fade 1.2s ease-in-out both, title-burst-jitter 1.2s steps(1, end) both;
}

@keyframes title-burst-text {
  0%, 100% {
    color: rgba(224, 242, 254, 1);
    text-shadow: 0 0 6px rgba(125, 211, 252, 0.85), 0 0 22px rgba(125, 211, 252, 0.45);
  }
  30%, 62% {
    color: rgba(224, 242, 254, 0.06);
    text-shadow: 0 0 6px rgba(125, 211, 252, 0.05), 0 0 22px rgba(125, 211, 252, 0.03);
  }
}

/* Eased ramps in and out (ease-in-out per leg), never a pop. */
@keyframes title-burst-fade {
  0% { opacity: 0; animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); }
  30%, 62% { opacity: 1; animation-timing-function: cubic-bezier(0.45, 0, 0.55, 1); }
  100% { opacity: 0; }
}

@keyframes title-burst-jitter {
  0% { background-position: 0 0, 0 0, 0 0; }
  8% { background-position: -83px 41px, 0 -14px, 0 0; }
  16% { background-position: 47px -29px, 0 21px, 0 0; }
  25% { background-position: -21px 67px, 0 -6px, 0 0; }
  33% { background-position: 95px 12px, 0 33px, 0 0; }
  41% { background-position: -58px -44px, 0 -25px, 0 0; }
  50% { background-position: 30px 58px, 0 9px, 0 0; }
  58% { background-position: -102px 9px, 0 -31px, 0 0; }
  66% { background-position: 66px -61px, 0 17px, 0 0; }
  75% { background-position: -35px 23px, 0 -9px, 0 0; }
  83% { background-position: 12px -50px, 0 27px, 0 0; }
  91% { background-position: -70px 36px, 0 -19px, 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .overlay[data-screen="select"] #overlay-title.burst,
  .overlay[data-screen="select"] #overlay-title.burst::before {
    animation: none;
  }

  .overlay[data-screen="select"] #overlay-title::before {
    display: none;
  }
}

/* Home screen: title at the top, the mode tiles dead center, the info card
   just below them, the key help on the bottom edge. */
.overlay[data-screen="select"] {
  grid-template-rows: 1fr auto 1fr;
  place-content: stretch center;
  gap: 0;
}

.overlay[data-screen="select"] #overlay-title {
  grid-row: 1;
  align-self: start;
  margin-top: 7%;
  padding: 0 16px;
}

.overlay[data-screen="select"] .mode-picker {
  grid-row: 2;
  margin-top: 0;
  gap: 14px;
}

.overlay[data-screen="select"] .overlay-detail {
  grid-row: 3;
  align-self: start;
  margin-top: 16px;
  max-width: 300px;
  padding: 12px 14px;
  font-size: 13px;
  line-height: 1.45;
  white-space: normal;
  border-radius: 12px;
  border: 1px solid rgba(125, 211, 252, 0.28);
  background: rgba(15, 23, 42, 0.72);
  box-shadow: 0 0 18px rgba(125, 211, 252, 0.08);
}

.overlay[data-screen="select"] .overlay-actions {
  grid-row: 3;
  align-self: end;
  margin: 0 0 30px;
}

/* A mode tile: icon above the mode name. */
.overlay .mode-tile {
  width: 124px;
  height: 124px;
  padding: 10px 8px;
  display: grid;
  grid-template-rows: 1fr auto;
  justify-items: center;
  align-items: center;
  gap: 4px;
  border-radius: 14px;
  border-color: rgba(148, 163, 184, 0.3);
  background: rgba(15, 23, 42, 0.72);
  font-size: 13px;
}

.mode-tile svg {
  width: 100px;
  height: 52px;
  fill: none;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.overlay .mode-tile.active {
  border-color: var(--tint, var(--p1));
  background: rgba(125, 211, 252, 0.1);
  box-shadow: 0 0 16px color-mix(in srgb, var(--tint, #7dd3fc) 45%, transparent);
}

.mode-tile[data-mode="coop"] {
  --tint: #6ee7b7;
}

@media (pointer: coarse) and (max-height: 520px) and (orientation: landscape) {
  .overlay .mode-tile {
    width: 92px;
    height: 92px;
  }

  .mode-tile svg {
    width: 72px;
    height: 38px;
  }

  .overlay[data-screen="select"] .overlay-detail {
    max-width: 420px;
    margin-top: 10px;
    padding: 8px 12px;
    font-size: 12px;
  }

  .overlay[data-screen="select"] .overlay-actions {
    margin-bottom: 8px;
  }
}

#overlay-sub {
  font-size: 14px;
  color: var(--muted);
}

.overlay-detail {
  white-space: pre-line;
  font-size: 13px;
  color: var(--ink);
  max-width: 34em;
  padding: 0 16px;
}

/* Versus winner: the batteries the winner has left, plus the count. */
.overlay-batt {
  display: grid;
  justify-items: center;
  gap: 6px;
  margin-top: 2px;
  color: var(--c, #6ee7b7);
}

.batt-row {
  display: flex;
  gap: 8px;
}

.batt {
  width: 38px;
  height: 19px;
  overflow: visible;
}

.batt .cell {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
}

.batt .nub,
.batt .fill {
  fill: currentColor;
}

.batt.spent {
  color: rgba(148, 163, 184, 0.5);
}

.batt .low {
  fill: #f87171;
}

.batt-count {
  font-size: 13px;
  letter-spacing: 0.1em;
  color: var(--ink);
}

/* Co-op game over: the session tallied like a receipt. */
.receipt {
  width: min(300px, 88%);
  margin: 4px 0 2px;
  padding: 10px 14px;
  border-radius: 8px;
  background: rgba(3, 7, 18, 0.5);
  border: 1px solid rgba(148, 163, 184, 0.22);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 13px;
  text-align: left;
}

.receipt .r-line {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 3px 0;
  color: var(--ink);
  white-space: nowrap; /* a row stays on its one line */
}

.receipt .r-line span:last-child {
  font-variant-numeric: tabular-nums;
}

.receipt .r-line.off,
.receipt .r-rule.off {
  visibility: hidden;
}

.receipt .r-rule {
  height: 0;
  margin: 4px 0;
  border-top: 1px dashed rgba(148, 163, 184, 0.55);
}

.receipt .r-total {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #6ee7b7;
}

.overlay-hint {
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--muted);
  opacity: 0.8;
}

.mode-picker,
.overlay-actions {
  display: flex;
  gap: 10px;
  justify-content: center;
  margin-top: 6px;
}

.overlay button,
.overlay output {
  font: inherit;
}

/* The overlay lets clicks through to the canvas; only its buttons are live. */
.overlay button {
  pointer-events: auto;
  cursor: pointer;
  color: var(--ink);
  background: rgba(15, 23, 42, 0.8);
  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 8px;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.14em;
}

.overlay button:hover,
.overlay button:focus-visible {
  border-color: var(--p1);
  outline: none;
}

.overlay button.active,
.overlay button.primary {
  border-color: var(--p1);
  background: rgba(125, 211, 252, 0.16);
}

.overlay button:disabled {
  opacity: 0.35;
  cursor: default;
}

/* On-screen controls (pause now, fullscreen later). They are real buttons next
   to the canvas, never part of it, so using them cannot steer the dish. */
.touch-controls {
  display: flex;
  gap: 8px;
  flex: none;
}

.ctl {
  width: 40px;
  height: 40px;
  padding: 0;
  display: grid;
  place-items: center;
  color: var(--ink);
  background: rgba(15, 23, 42, 0.8);
  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 10px;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

.ctl:hover,
.ctl:focus-visible {
  border-color: var(--p1);
  outline: none;
}

.ctl:disabled {
  opacity: 0.35;
  cursor: default;
}

.ctl svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}

#btn-pause .i-play,
#btn-pause[data-state="paused"] .i-pause {
  display: none;
}

#btn-pause[data-state="paused"] .i-play {
  display: block;
}

#btn-fullscreen .i-exit,
#btn-fullscreen[data-state="on"] .i-enter {
  display: none;
}

#btn-fullscreen[data-state="on"] .i-exit {
  display: block;
}

/* Short note on iOS, where element fullscreen does not exist on iPhone. */
.fs-hint {
  position: fixed;
  left: 50%;
  bottom: max(12px, env(safe-area-inset-bottom));
  transform: translateX(-50%);
  margin: 0;
  max-width: 90vw;
  padding: 8px 14px;
  font-size: 12px;
  text-align: center;
  color: var(--ink);
  background: rgba(15, 23, 42, 0.92);
  border: 1px solid rgba(148, 163, 184, 0.35);
  border-radius: 8px;
  z-index: 6;
  pointer-events: none;
}

/* Touch screens: the page is a fixed game surface, so nothing may scroll,
   bounce, zoom or select under a finger. Scoped to coarse pointers so a small
   desktop window can still scroll. */
@media (pointer: coarse) {
  html,
  body {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: none;
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }

  body {
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
  }
}

/* Phone held sideways: the page is only ~390 px tall, so drop the header and
   fit the whole 800x500 canvas inside the visible height. */
@media (pointer: coarse) and (max-height: 520px) and (orientation: landscape) {
  body {
    padding: max(6px, env(safe-area-inset-top)) max(6px, env(safe-area-inset-right))
      max(6px, env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-left));
  }

  .game-shell {
    width: min(100%, calc((100vh - 14px) * 1.6 + 2px));
    width: min(100%, calc((100dvh - 14px) * 1.6 + 2px));
    gap: 0;
  }

  .hud h1,
  .hint {
    display: none;
  }

  .canvas-wrap {
    border-radius: 10px;
  }

  /* Park the buttons in the free strip beside the canvas, in the corner of the
     screen, where they cannot cover the play field. */
  .touch-controls {
    position: fixed;
    top: max(8px, env(safe-area-inset-top));
    right: max(8px, env(safe-area-inset-right));
    flex-direction: column;
    z-index: 5;
  }
}

/* Phone held upright (game.js matches this same query and rotates the field):
   the canvas fills the full width, edge to edge, with no card frame, radius,
   padding or body margin (only the safe-area insets). It is 500x800 logical,
   field only. Under it: the HUD panel (stats and meters), then one slim row: pause, the steering strip, fullscreen.
   If the viewport is too short for full width, the width shrinks so the aspect
   stays exact (nothing is cropped or stretched). */
.thumb {
  display: none;
}

@media (orientation: portrait) and (pointer: coarse) {
  body {
    --safe-y: calc(env(safe-area-inset-top) + env(safe-area-inset-bottom));
    --bar-h: 92px; /* the stats and meters panel above the control row */
    display: block;
    padding: env(safe-area-inset-top) env(safe-area-inset-right)
      env(safe-area-inset-bottom) env(safe-area-inset-left);
  }

  .game-shell {
    /* 100dvh minus the safe areas, the panel and a 52 px control row, at 500:800. */
    width: min(100%, calc((100vh - var(--safe-y) - var(--bar-h) - 52px) * 0.625));
    width: min(100%, calc((100dvh - var(--safe-y) - var(--bar-h) - 52px) * 0.625));
    height: calc(100vh - var(--safe-y));
    height: calc(100dvh - var(--safe-y));
    margin: 0 auto;
    grid-template-columns: auto 1fr auto;
    grid-template-rows: auto 1fr 52px;
    grid-template-areas:
      "field field field"
      "bar bar bar"
      "pause pad full";
    gap: 0 8px;
    align-content: start;
    align-items: center;
  }

  /* The header only holds the title, a keyboard hint and the two buttons.
     Dissolve it so the buttons become cells of the grid above. */
  .hud,
  .touch-controls {
    display: contents;
  }

  .hud h1,
  .hint {
    display: none;
  }

  .canvas-wrap {
    grid-area: field;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }

  #btn-pause {
    grid-area: pause;
    margin-left: 8px;
  }

  #btn-fullscreen {
    grid-area: full;
    margin-right: 8px;
  }

  .ctl {
    width: 44px;
    height: 44px;
  }

  .thumb {
    grid-area: pad;
    display: block;
    position: relative;
    align-self: center;
    height: 44px; /* same as the pause button beside it */
    border-radius: 22px;
    border: 1px dashed rgba(148, 163, 184, 0.35);
    background: rgba(15, 23, 42, 0.5);
    touch-action: none;
    -webkit-tap-highlight-color: transparent;
  }

  .thumb-label {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    font-size: 11px;
    letter-spacing: 0.2em;
    color: var(--muted);
    opacity: 0.7;
    pointer-events: none;
  }

  /* Follows the dish across the strip. */
  .thumb-knob {
    position: absolute;
    top: 50%;
    /* --f (0..1) is set by game.js: where the dish is along the field. */
    left: calc((100% - 30px) * var(--f, 0.5) + 15px);
    width: 30px;
    height: 30px;
    margin: -15px 0 0 -15px;
    border-radius: 50%;
    background: rgba(125, 211, 252, 0.28);
    border: 2px solid var(--p1);
    box-shadow: 0 0 12px rgba(125, 211, 252, 0.45);
    pointer-events: none;
  }
}

/* Upright phone: the HUD readouts live in the panel under the field (DOM, so
   they stay sharp and are never covered by the static). */
.pbar {
  display: none;
}

@media (orientation: portrait) and (pointer: coarse) {
  .pbar {
    grid-area: bar;
    display: flex;
    flex-direction: column;
    justify-content: flex-end; /* stats and meters sit just above the control row */
    gap: 6px;
    height: 100%;
    min-height: var(--bar-h);
    padding: 0 8px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    pointer-events: none;
  }

  .pbar[data-phase="select"] {
    visibility: hidden;
  }

  .pbar-stats,
  .pbar-meters {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
  }

  .pbar-stats {
    height: 24px;
  }

  .pbar-meters {
    height: 40px;
  }

  .pst {
    display: none;
    width: 100%;
    align-items: center;
    justify-content: space-between;
  }

  .pbar[data-mode="coop"] .pst-coop,
  .pbar[data-mode="versus"] .pst-versus {
    display: flex;
  }

  .pst-pair {
    display: flex;
    align-items: center;
    gap: 6px;
  }

  .pst b,
  .pm b {
    font-size: 11px;
    font-weight: 600;
    color: rgba(148, 163, 184, 0.8);
  }

  .pst em {
    font-style: normal;
    font-size: 17px;
    font-weight: 700;
    color: var(--ink);
  }

  .pst u {
    text-decoration: none;
    font-size: 11px;
    font-weight: 600;
    color: rgba(148, 163, 184, 0.8);
  }

  .pb-row {
    display: inline-flex;
    gap: 7px;
    margin-right: 4px;
  }

  /* One battery: --c is its tint, --lv how full it is (0..1). A spent cell is
     a dim outline with a red low tick. */
  .pb {
    --c: #6ee7b7;
    --lv: 1;
    position: relative;
    width: 21px;
    height: 11px;
    border: 1.2px solid var(--c);
    border-radius: 3px;
  }

  .pb::after {
    content: "";
    position: absolute;
    right: -4px;
    top: 2.5px;
    width: 2px;
    height: 4px;
    border-radius: 0 1px 1px 0;
    background: var(--c);
  }

  .pb i {
    position: absolute;
    left: 2px;
    top: 2px;
    bottom: 2px;
    width: calc((100% - 4px) * var(--lv));
    background: var(--c);
  }

  .pb.low i {
    background: #f87171;
  }

  .pb.spent {
    --c: rgba(148, 163, 184, 0.42);
  }

  .pb.spent i {
    width: 2px;
    background: rgba(248, 113, 113, 0.85);
  }

  /* Label row on top (label, weapon placeholders, state), bar underneath. */
  .pm {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    height: 40px;
    padding: 0 8px;
    border-radius: 8px;
    border: 1px solid rgba(125, 211, 252, 0.16);
    background: rgba(3, 7, 18, 0.6);
  }

  .pm-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 5px;
    min-width: 0;
  }

  .pm-head b {
    font-size: 10px;
    letter-spacing: 0.02em;
    white-space: nowrap;
  }

  /* Versus weapon chips, one set per dish. Locked is the dashed default.
     game.js adds .armed while that weapon is charged and .firing while it
     spends. Versus hides the row (the charges live in the meters). Co-op
     keeps the row for the shared GROUND tool. */
  .pbar-slots {
    display: flex;
    gap: 8px;
    height: 16px;
    flex: none;
  }

  .pbar[data-mode="coop"] .pm-slots {
    display: none;
  }

  .pbar[data-mode="coop"] .pbar-slots {
    justify-content: center;
  }

  .pbar[data-mode="versus"] .pbar-slots {
    display: none; /* the three charges live in the meter */
  }

  .pbar[data-mode="versus"] .pbar-meters,
  .pbar[data-mode="versus"] .pm {
    height: auto;
  }

  .pm-slots {
    --c: #7dd3fc;
    flex: 1 1 0;
    display: flex;
    justify-content: flex-start;
    gap: 4px;
    min-width: 0;
    padding: 0 2px;
  }

  .pm-slots[data-dish="1"] {
    --c: #f472b6;
    justify-content: flex-end;
  }

  .pm-slots u {
    text-decoration: none;
    font-size: 8px;
    line-height: 14px;
    height: 16px;
    font-weight: 700;
    letter-spacing: 0.04em;
    padding: 0 4px;
    border-radius: 4px;
    border: 1px dashed rgba(148, 163, 184, 0.32);
    color: rgba(148, 163, 184, 0.4);
    background: rgba(148, 163, 184, 0.06);
  }

  .pm-slots u.armed {
    border-style: solid;
    color: var(--c);
    border-color: var(--c);
    background: color-mix(in srgb, var(--c) 20%, transparent);
  }

  .pm-slots u.firing {
    border-style: solid;
    color: #f8fafc;
    border-color: #f8fafc;
    background: color-mix(in srgb, var(--c) 55%, white);
  }

  /* Co-op GROUND. Hidden until that mode; the fill is the shared charge. */
  .pm-tools {
    display: none;
  }

  .pbar[data-mode="coop"] .pm-tools {
    display: flex;
  }

  .pm-tools u {
    --c: #6ee7b7;
    --pct: 0%;
    display: flex;
    align-items: center;
    gap: 4px;
    height: 16px;
    padding: 0 4px;
    border-radius: 4px;
    border: 1px dashed rgba(148, 163, 184, 0.32);
    color: rgba(148, 163, 184, 0.45);
    background: rgba(148, 163, 184, 0.06);
    text-decoration: none;
  }

  .pm-tools b {
    font-size: 8px;
    line-height: 14px;
    font-weight: 700;
    letter-spacing: 0.04em;
  }

  .pm-tools i {
    position: relative;
    width: 42px;
    height: 6px;
    border-radius: 3px;
    background: rgba(15, 23, 42, 0.9);
    border: 1px solid rgba(148, 163, 184, 0.28);
    overflow: hidden;
  }

  .pm-tools i::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: var(--pct);
    background: var(--c);
    opacity: 0.45;
  }

  .pm-tools u.armed {
    border-style: solid;
    color: var(--c);
    border-color: var(--c);
  }

  .pm-tools u.armed i {
    border-color: var(--c);
  }

  .pm-tools u.armed i::before {
    opacity: 0.95;
  }

  .pm-tools u.firing {
    border-style: solid;
    color: #f8fafc;
    border-color: #f8fafc;
  }

  .pm-tools u.firing i {
    border-color: #f8fafc;
  }

  .pm-tools u.firing i::before {
    background: #f8fafc;
    opacity: 0.9;
  }

  .pm.max {
    border-color: rgba(251, 191, 36, 0.8);
    animation: pm-glow 1s ease-in-out infinite;
  }

  .pm.full {
    border-color: rgba(52, 211, 153, 0.65);
  }

  @keyframes pm-glow {
    50% {
      box-shadow: 0 0 10px rgba(251, 191, 36, 0.5);
    }
  }

  .pm-bar {
    position: relative;
    flex: none;
    height: 8px;
    border-radius: 4px;
    background: rgba(15, 23, 42, 0.9);
    border: 1px solid rgba(148, 163, 184, 0.22);
    overflow: hidden;
    /* 14 cells with a 2 px gap */
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 2px), transparent 0);
    mask-image: linear-gradient(90deg, #000 calc(100% - 2px), transparent 0);
    -webkit-mask-size: calc(100% / 14) 100%;
    mask-size: calc(100% / 14) 100%;
  }

  .pm-fill {
    position: absolute;
    inset: 0;
    background: var(--grad);
    clip-path: inset(0 calc(100% - var(--pct, 0%)) 0 0);
  }

  .pm-s {
    font-style: normal;
    font-size: 10px;
    font-weight: 600;
    white-space: nowrap;
    text-align: right;
  }

  /* Versus: one thin charge per weapon, in place of the single shared bar. */
  .pm-charges {
    display: none;
    flex-direction: column;
    gap: 2px;
  }

  .pbar[data-mode="versus"] .pm-bar,
  .pbar[data-mode="versus"] .pm-s {
    display: none;
  }

  .pbar[data-mode="versus"] .pm-charges {
    display: flex;
  }

  .pm-charges span {
    --c: #7dd3fc;
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
  }

  #pm-right .pm-charges span {
    --c: #f472b6;
  }

  .pm-charges b {
    width: 44px;
    flex: none;
    font-size: 8px;
    letter-spacing: 0.03em;
    color: rgba(148, 163, 184, 0.7);
  }

  .pm-charges i {
    --pct: 0%;
    position: relative;
    flex: 1;
    height: 6px;
    border-radius: 3px;
    background: rgba(15, 23, 42, 0.9);
    border: 1px solid rgba(148, 163, 184, 0.28);
    overflow: hidden;
  }

  .pm-charges span[data-weapon="emf"] i {
    background:
      linear-gradient(90deg, transparent calc(40% - 1px), rgba(226, 232, 240, 0.45) 40%, transparent calc(40% + 1px)),
      rgba(15, 23, 42, 0.9);
  }

  .pm-charges span[data-weapon="laser"] i {
    background:
      linear-gradient(90deg, transparent calc(60% - 1px), rgba(226, 232, 240, 0.45) 60%, transparent calc(60% + 1px)),
      rgba(15, 23, 42, 0.9);
  }

  .pm-charges i::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: var(--pct);
    background: var(--c);
    opacity: 0.45;
  }

  .pm-charges span.armed b {
    color: var(--c);
  }

  .pm-charges span.armed i {
    border-color: var(--c);
  }

  .pm-charges span.armed i::before {
    opacity: 0.95;
  }

  .pm-charges span.firing b {
    color: #f8fafc;
  }

  .pm-charges span.firing i {
    border-color: #f8fafc;
  }

  .pm-charges span.firing i::before {
    background: #f8fafc;
    opacity: 0.9;
  }

  /* Versus MANUAL. Hidden until that mode, and only on your meter. The panel
     stays inside the 92 px strip: MANUAL tightens the rows instead of growing
     down into the thumb control. */
  .pm-auto,
  .pm-fire {
    display: none;
    margin: 0;
    padding: 0;
    appearance: none;
    font: 700 8px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
    letter-spacing: 0.03em;
    border-radius: 4px;
    cursor: pointer;
    touch-action: manipulation;
  }

  .pbar[data-mode="versus"] #pm-left .pm-auto {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 54px;
    height: 14px;
    pointer-events: auto;
    color: rgba(186, 230, 253, 0.9);
    background: rgba(15, 23, 42, 0.9);
    border: 1px solid rgba(148, 163, 184, 0.45);
  }

  .pbar[data-mode="versus"][data-manual="1"] #pm-left .pm-auto {
    color: #7dd3fc;
    border-color: #7dd3fc;
    background: rgba(125, 211, 252, 0.16);
  }

  #pm-left .pm-charges span[data-weapon="carrier"] {
    display: none;
  }

  .pbar[data-mode="versus"][data-manual="1"] {
    gap: 2px;
  }

  .pbar[data-mode="versus"][data-manual="1"] .pbar-stats {
    height: 16px;
  }

  .pbar[data-mode="versus"][data-manual="1"] .pm {
    gap: 1px;
    padding: 1px 4px;
  }

  .pbar[data-mode="versus"][data-manual="1"] #pm-left .pm-charges {
    gap: 1px;
  }

  .pbar[data-mode="versus"][data-manual="1"] #pm-left .pm-charges span {
    height: 13px;
  }

  .pbar[data-mode="versus"][data-manual="1"] #pm-left .pm-charges span[data-weapon="carrier"] {
    display: flex;
  }

  .pbar[data-mode="versus"][data-manual="1"] #pm-left .pm-fire {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 16px;
    height: 12px;
    pointer-events: auto;
    color: rgba(148, 163, 184, 0.75);
    background: rgba(15, 23, 42, 0.9);
    border: 1px solid rgba(148, 163, 184, 0.35);
  }

  .pm-charges span.armed .pm-fire {
    color: var(--c);
    border-color: var(--c);
    background: color-mix(in srgb, var(--c) 22%, transparent);
  }

  .pm-charges span.firing .pm-fire {
    color: #0f172a;
    border-color: #f8fafc;
    background: #f8fafc;
  }
}

@media (orientation: portrait) and (pointer: coarse) {
  .pbar[data-phase="paused"] .pm.max {
    animation-play-state: paused;
  }
}

/* Home-screen START: only the upright phone shows it, in place of the panel. */
.btn-start {
  display: none;
}

/* The game version, small and quiet above START (see VERSION in game.js). */
.version {
  display: none;
  margin: 0;
  font: 11px ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: 0.12em;
  text-align: center;
  color: var(--muted);
  opacity: 0.7;
  pointer-events: none;
}

.overlay[data-screen="select"] .overlay-actions {
  flex-wrap: wrap;
  row-gap: 6px;
}

.overlay[data-screen="select"] .version-in {
  display: block;
  flex: 0 0 100%;
}

@media (orientation: portrait) and (pointer: coarse) {
  /* Before a match: the bottom panel is one big START button. The overlay's
     own START is hidden here. */
  .game-shell[data-phase="select"] .pbar,
  .game-shell[data-phase="select"] #btn-pause,
  .game-shell[data-phase="select"] #btn-fullscreen,
  .game-shell[data-phase="select"] .thumb,
  .overlay[data-screen="select"] .overlay-actions {
    display: none;
  }

  /* The overlay's own START (and the version inside it) is hidden here: the
     version sits in the same grid cell as the big button, just above it. */
  .game-shell[data-phase="select"] .version-start {
    grid-row: 2 / 4;
    grid-column: 1 / -1;
    display: block;
    align-self: end;
    justify-self: center;
    margin-bottom: 92px; /* button 68 + its bottom margin 18 + a small gap */
  }

  .game-shell[data-phase="select"] .btn-start {
    grid-row: 2 / 4; /* the panel and control rows */
    grid-column: 1 / -1;
    display: block;
    align-self: end;
    margin: 0 14px 18px;
    height: 68px;
    border-radius: 16px;
    border: 1px solid var(--p1);
    background: rgba(125, 211, 252, 0.16);
    color: var(--ink);
    font: inherit;
    font-size: 22px;
    font-weight: 800;
    letter-spacing: 0.3em;
    text-shadow: 0 0 10px rgba(125, 211, 252, 0.6);
    box-shadow: 0 0 22px rgba(125, 211, 252, 0.18);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
}

/* Pause (STANDBY) and end screens: same title style, then the main button above EXIT. EXIT ends the
   match and returns to the home screen (game.js enterSelect resets it all). */
.overlay:is([data-screen="paused"], [data-screen="over"]) {
  gap: 10px;
}

.overlay:is([data-screen="paused"], [data-screen="over"]) #overlay-title {
  animation: sig-flicker 7s steps(1, end) infinite;
  font-size: clamp(26px, 5.4vw, 38px);
}

@media (prefers-reduced-motion: reduce) {
  .overlay:is([data-screen="paused"], [data-screen="over"]) #overlay-title {
    animation: none;
  }
}

.overlay:is([data-screen="paused"], [data-screen="over"]) #overlay-sub {
  font-size: 12px;
  letter-spacing: 0.16em;
}

.overlay:is([data-screen="paused"], [data-screen="over"]) .overlay-actions {
  flex-direction: column;
  width: min(240px, 64%);
  gap: 12px;
  margin-top: 14px;
}

.overlay:is([data-screen="paused"], [data-screen="over"]) .overlay-actions button {
  width: 100%;
  padding: 12px 16px;
}

.overlay:is([data-screen="paused"], [data-screen="over"]) #btn-primary {
  font-size: 16px;
  padding: 16px;
}
