/* =====================================================================
   INK RUSH — UI style contract
   Derived from the scene BEFORE any rule below was written:
     palette sampled from scene materials  -> player ink  #ffe11f (splat quads)
                                              rival ink   #8b3cf5
                                              arena plate #c8ccd6 (floor material)
                                              deep trim   #16121f (girders / outlines)
                                              sky         #ff9ad5 -> #55e3ff (hemisphere)
     shape language  -> irregular cartoon ink blobs, thick black outlines
     material language -> matte painted, flat opaque backings, hard offset shadows
   Archetype: HAND-PAINTED / CARTOON.  Fallback display face is the archetype's
   documented stack (no external font URLs anywhere in this build).
   ===================================================================== */
:root {
  --ui-surface: #16121f;          /* deep girder trim */
  --ui-surface-2: #241c33;
  --ui-ink: #fff6e0;              /* text/lines */
  --ui-accent: #ffe11f;           /* player ink */
  --ui-accent-dk: #d9a800;
  --ui-danger: #8b3cf5;           /* rival ink */
  --ui-danger-dk: #5c1fae;
  --ui-plate: #c8ccd6;            /* arena floor */
  --ui-font: "Trebuchet MS", "Verdana", "DejaVu Sans", sans-serif;
  --ui-outline: 3px;
  --ui-motion: 280ms cubic-bezier(0.34, 1.56, 0.64, 1);
  --ui-motion-fast: 150ms cubic-bezier(0.34, 1.56, 0.64, 1);
  --blob-a: 46% 54% 52% 48% / 58% 44% 56% 42%;
  --blob-b: 58% 42% 47% 53% / 44% 57% 43% 56%;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; padding: 0; height: 100%; width: 100%;
  overflow: hidden; background: #0d0a14;
  font-family: var(--ui-font);
  color: var(--ui-ink);
  overscroll-behavior: none;
  touch-action: none;
  user-select: none; -webkit-user-select: none;
}
#app { position: fixed; inset: 0; overflow: hidden; }
canvas#scene { display: block; width: 100%; height: 100%; touch-action: none; }

/* ============================ HUD shell ============================ */
.hud {
  position: absolute; inset: 0;
  pointer-events: none;
  padding: calc(10px + var(--safe-t)) calc(12px + var(--safe-r)) calc(10px + var(--safe-b)) calc(12px + var(--safe-l));
  container-type: inline-size;
  opacity: 0; transition: opacity 260ms ease-out;
}
.hud.live { opacity: 1; }

/* ---- shared cartoon plate ---- */
.plate, .timer-plaque, .splat-chip, .turf-badge, .tank-shell, .tbtn, .panel, .big-btn {
  border: var(--ui-outline) solid var(--ui-surface);
  background: var(--ui-surface-2);
  box-shadow: 3px 4px 0 rgba(10, 6, 18, 0.55);
}

/* ============================ ink tank (top-left) ============================ */
.hud-tank {
  position: absolute;
  top: calc(10px + var(--safe-t)); left: calc(12px + var(--safe-l));
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  width: clamp(96px, 15cqw, 138px);
}
.tank-label {
  font-size: 12px; font-weight: 700; font-style: italic; letter-spacing: 0.14em;
  color: var(--ui-accent);
  text-shadow: 2px 2px 0 var(--ui-surface);
}
.tank-shell {
  position: relative; width: 100%; height: 22px;
  border-radius: 12px 12px 12px 12px;
  background: #120e1c; overflow: hidden;
  padding: 0;
}
.tank-fill {
  position: absolute; inset: 0; right: auto; width: 100%;
  background: linear-gradient(180deg, #fff08a 0%, var(--ui-accent) 45%, var(--ui-accent-dk) 100%);
  transform-origin: left center;
  transition: width 120ms linear, background 200ms ease-out;
}
.tank-shell.low .tank-fill { background: linear-gradient(180deg, #ffd0d0 0%, #ff5a5a 50%, #b81f1f 100%); }
.tank-ticks {
  position: absolute; inset: 0;
  background-image: repeating-linear-gradient(90deg, transparent 0 24%, rgba(22,18,31,.55) 24% 25.4%);
  pointer-events: none;
}
.tank-state {
  font-size: 12px; font-weight: 700; letter-spacing: 0.1em;
  color: var(--ui-ink); opacity: .75;
  text-shadow: 1px 1px 0 var(--ui-surface);
  min-width: 68px;
}
.tank-shell.low + .tank-state { color: #ff8a8a; opacity: 1; }

/* ============================ timer + turf (top-center) ============================ */
.hud-top {
  position: absolute; top: calc(8px + var(--safe-t)); left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  width: min(58cqw, 460px);
}
.timer-plaque {
  padding: 2px 16px 3px;
  border-radius: 4px 12px 5px 11px;
  background: var(--ui-surface);
  font-size: clamp(19px, 3.4cqw, 28px);
  font-weight: 700; font-style: italic;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--ui-ink);
  transition: transform var(--ui-motion), color 200ms;
}
.timer-plaque.urgent { color: #ff6a6a; transform: scale(1.1); }

.turf-row { display: flex; align-items: center; gap: 6px; width: 100%; }
.turf-badge {
  min-width: 52px; text-align: center;
  padding: 1px 6px 2px;
  font-size: clamp(13px, 2.2cqw, 17px); font-weight: 700; font-style: italic;
  font-variant-numeric: tabular-nums;
  border-radius: var(--blob-a);
  color: var(--ui-surface);
  transition: transform var(--ui-motion);
}
.turf-badge.you { background: var(--ui-accent); }
.turf-badge.foe { background: var(--ui-danger); color: #fff6e0; }
.turf-badge.pop { transform: scale(1.16) rotate(-3deg); }

.turf-bar {
  position: relative; flex: 1; height: 18px;
  border: var(--ui-outline) solid var(--ui-surface);
  border-radius: 10px;
  background: #4a4356;
  overflow: hidden;
  box-shadow: 3px 4px 0 rgba(10, 6, 18, 0.55);
}
.turf-fill { position: absolute; top: 0; bottom: 0; width: 0%; transition: width 220ms ease-out; }
.turf-fill.you { left: 0;  background: linear-gradient(180deg, #fff293, var(--ui-accent) 60%, var(--ui-accent-dk)); }
.turf-fill.foe { right: 0; background: linear-gradient(180deg, #c99cff, var(--ui-danger) 60%, var(--ui-danger-dk)); }
.turf-mid { position: absolute; left: 50%; top: 0; bottom: 0; width: 2px; background: rgba(22,18,31,.5); transform: translateX(-1px); }

/* ============================ splat chip (top-right) ============================ */
.hud-splats {
  position: absolute; top: calc(10px + var(--safe-t)); right: calc(12px + var(--safe-r));
  display: flex; gap: 6px;
}
.splat-chip {
  display: flex; align-items: center; gap: 5px;
  padding: 3px 11px 4px;
  border-radius: var(--blob-b);
  font-size: 15px; font-weight: 700; font-style: italic;
  font-variant-numeric: tabular-nums;
  min-width: 56px; justify-content: center;
  transition: transform var(--ui-motion);
}
.splat-chip.pop { transform: scale(1.2) rotate(4deg); }
.chip-icon { color: var(--ui-accent); font-style: normal; }

/* ============================ reticle ============================ */
.reticle {
  position: absolute; left: 50%; top: 52%;
  width: 42px; height: 42px; margin: -21px 0 0 -21px;
  transition: transform 90ms ease-out, opacity 200ms;
}
.reticle i {
  position: absolute; left: 50%; top: 50%;
  width: 3px; height: 11px; margin: -5.5px 0 0 -1.5px;
  background: var(--ui-accent);
  box-shadow: 0 0 0 1.5px rgba(22,18,31,.85);
  border-radius: 2px;
}
.reticle i:nth-child(1) { transform: translateY(-13px); }
.reticle i:nth-child(2) { transform: translateY(13px); }
.reticle i:nth-child(3) { transform: rotate(90deg) translateY(-13px); }
.reticle i:nth-child(4) { transform: rotate(90deg) translateY(13px); }
.reticle b {
  position: absolute; left: 50%; top: 50%; width: 5px; height: 5px;
  margin: -2.5px 0 0 -2.5px; border-radius: 50%;
  background: var(--ui-ink); box-shadow: 0 0 0 1.5px rgba(22,18,31,.85);
}
.reticle.fire { transform: scale(1.28); }
.reticle.hidden { opacity: 0; }
/* HIT MARKER. Firing already kicks the reticle, but the kick happens whether or
   not the shot connected, so it tells the player nothing about aim. This one
   only fires when ink actually landed on a rival: the ticks swing to an X and
   flip to rival ink, which is the one moment those two colours are allowed to
   touch. It is the cheapest aiming lesson the game can give. */
.reticle.hit { transform: scale(1.5) rotate(45deg); }
.reticle.hit i { background: var(--ui-danger); height: 13px; }
.reticle.hit b { background: var(--ui-danger); transform: scale(1.4); }

/* ============================ taking fire ============================
   hitFlash was being counted down every frame and drawn precisely nowhere —
   the damage feedback existed as a number and never as a picture. Rival ink
   now creeps in from the frame edge with the centre left clear, so the warning
   never covers the thing that is shooting you.
   ================================================================= */
.hurt {
  position: absolute; inset: 0; z-index: 7;
  pointer-events: none; opacity: 0;
  /* Two layers, because the deck is already covered in rival violet and a violet
     vignette alone vanishes into it: ink at the edge for WHOSE hit it was, and a
     dark falloff underneath it for the fact that you were hit at all. */
  background:
    radial-gradient(ellipse 74% 68% at 50% 52%,
      transparent 40%,
      color-mix(in srgb, var(--ui-danger) 42%, transparent) 72%,
      color-mix(in srgb, var(--ui-danger) 88%, #ffffff) 100%),
    radial-gradient(ellipse 66% 62% at 50% 52%,
      transparent 46%,
      rgba(14, 8, 26, 0.5) 100%);
  transition: opacity 90ms linear;
}

/* ============================ banner ============================ */
.banner {
  position: absolute; left: 50%; top: 26%;
  transform: translate(-50%, 0) rotate(-2.5deg) scale(0.7);
  padding: 6px 24px 8px;
  border: 4px solid var(--ui-surface);
  border-radius: var(--blob-a);
  background: var(--ui-accent);
  color: var(--ui-surface);
  font-size: clamp(22px, 5cqw, 42px); font-weight: 700; font-style: italic;
  letter-spacing: 0.02em;
  box-shadow: 4px 6px 0 rgba(10,6,18,.5);
  opacity: 0; pointer-events: none;
  white-space: nowrap;
  transition: opacity 180ms ease-out, transform var(--ui-motion);
}
.banner.show { opacity: 1; transform: translate(-50%, 0) rotate(-2.5deg) scale(1); }
.banner.bad { background: var(--ui-danger); color: #fff6e0; }

/* ============================ touch controls ============================ */
.touch-layer { position: absolute; inset: 0; pointer-events: none; }
.stick-zone {
  position: absolute; left: 0; bottom: 0;
  width: 46%; height: 62%;
  pointer-events: auto; touch-action: none;
}
.stick-base {
  position: absolute;
  left: calc(22px + var(--safe-l)); bottom: calc(22px + var(--safe-b));
  width: 116px; height: 116px; border-radius: 50%;
  border: var(--ui-outline) solid var(--ui-surface);
  background: rgba(36, 28, 51, 0.55);
  opacity: .55; transition: opacity 160ms;
}
.stick-zone.active .stick-base { opacity: 1; }
.stick-knob {
  position: absolute; left: 50%; top: 50%;
  width: 52px; height: 52px; margin: -26px 0 0 -26px;
  border-radius: 50%;
  border: var(--ui-outline) solid var(--ui-surface);
  background: var(--ui-accent);
}
.touch-actions {
  position: absolute; right: calc(18px + var(--safe-r)); bottom: calc(20px + var(--safe-b));
  display: flex; flex-direction: column; gap: 12px; align-items: flex-end;
  pointer-events: auto;
}
.tbtn {
  width: 92px; height: 68px;
  border-radius: var(--blob-b);
  font-family: var(--ui-font);
  font-size: 17px; font-weight: 700; font-style: italic; letter-spacing: .06em;
  color: var(--ui-surface);
  touch-action: none; cursor: pointer;
  transition: transform var(--ui-motion-fast), filter 120ms;
}
.tbtn.fire { background: var(--ui-accent); width: 108px; height: 82px; font-size: 20px; }
.tbtn.dive { background: #55e3ff; }
.tbtn:active, .tbtn.held { transform: scale(0.9) rotate(-3deg); filter: brightness(1.15); }
.tbtn:focus-visible { outline: 3px solid var(--ui-ink); outline-offset: 3px; }

/* ============================ screens ============================ */
.screen {
  position: absolute; inset: 0; z-index: 20;
  display: flex; align-items: center; justify-content: center;
  padding: calc(12px + var(--safe-t)) calc(12px + var(--safe-r)) calc(12px + var(--safe-b)) calc(12px + var(--safe-l));
  background:
    radial-gradient(ellipse at 50% 40%, rgba(139,60,245,.30), transparent 62%),
    rgba(13, 10, 20, 0.78);
  container-type: inline-size;
}
.screen[hidden] { display: none; }
.panel {
  width: min(92cqw, 520px);
  max-height: calc(100dvh - 24px - var(--safe-t) - var(--safe-b));
  overflow-y: auto;
  padding: 16px 20px 20px;
  border-radius: 10px 26px 12px 24px;
  background: var(--ui-surface-2);
  text-align: center;
  box-shadow: 6px 8px 0 rgba(10,6,18,.6);
}
.logo-wrap { margin: 0 0 6px; }
#logoImg { display: block; width: min(100%, 380px); margin: 0 auto; height: auto; }
.logo-text {
  margin: 4px 0 2px;
  font-size: clamp(38px, 12cqw, 70px); font-weight: 700; font-style: italic;
  letter-spacing: -0.01em; line-height: .95;
  color: var(--ui-accent);
  text-shadow: 4px 4px 0 var(--ui-surface), -2px -2px 0 var(--ui-surface), 2px -2px 0 var(--ui-surface), -2px 2px 0 var(--ui-surface);
  transform: rotate(-2deg);
}
.logo-text span { color: var(--ui-danger); display: inline-block; transform: rotate(3deg); margin-left: .1em; }
.tag {
  margin: 8px 0 12px; font-size: clamp(13px, 3cqw, 16px); line-height: 1.35;
  color: var(--ui-ink); opacity: .88;
}
.ctl-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(122px, 1fr));
  gap: 6px; margin: 0 0 14px; text-align: left;
}
.ctl {
  display: flex; align-items: center; gap: 7px;
  padding: 5px 8px; border-radius: 4px 11px 5px 10px;
  background: rgba(13,10,20,.55);
  font-size: 12.5px;
}
.ctl kbd {
  flex: 0 0 auto; min-width: 30px; text-align: center;
  padding: 2px 6px; border-radius: 4px;
  border: 2px solid var(--ui-surface);
  background: var(--ui-accent); color: var(--ui-surface);
  font-family: var(--ui-font); font-size: 12.5px; font-weight: 700;
}
.ctl span { opacity: .9; }
.big-btn {
  display: block; width: 100%;
  padding: 12px 18px 14px;
  border-radius: 8px 22px 9px 20px;
  background: var(--ui-accent);
  color: var(--ui-surface);
  font-family: var(--ui-font);
  font-size: clamp(19px, 5cqw, 27px); font-weight: 700; font-style: italic;
  letter-spacing: .04em;
  cursor: pointer;
  min-height: 52px;
  transition: transform var(--ui-motion), filter 140ms;
}
.big-btn:hover { filter: brightness(1.08); transform: rotate(-1deg) scale(1.02); }
.big-btn:active { transform: scale(0.96) rotate(1deg); }
.big-btn:focus-visible { outline: 3px solid var(--ui-ink); outline-offset: 4px; }

.verdict {
  margin: 2px 0 12px;
  font-size: clamp(34px, 11cqw, 62px); font-weight: 700; font-style: italic;
  color: var(--ui-accent);
  text-shadow: 4px 4px 0 var(--ui-surface);
  transform: rotate(-2deg);
}
.verdict.lose { color: var(--ui-danger); }
.verdict.draw { color: #55e3ff; }
.score-rows { display: flex; flex-direction: column; gap: 8px; margin: 0 0 12px; }
.score-row { display: flex; align-items: center; gap: 8px; }
.team-tag {
  flex: 0 0 74px; text-align: left;
  font-size: 12px; font-weight: 700; font-style: italic; letter-spacing: .08em;
}
.score-row.you .team-tag { color: var(--ui-accent); }
.score-row.foe .team-tag { color: var(--ui-danger); }
.score-bar {
  flex: 1; height: 20px;
  border: var(--ui-outline) solid var(--ui-surface);
  border-radius: 10px; background: #4a4356; overflow: hidden;
  box-shadow: 3px 4px 0 rgba(10,6,18,.5);
}
.score-bar i { display: block; height: 100%; width: 0%; transition: width 700ms cubic-bezier(.2,.9,.3,1); }
.score-row.you .score-bar i { background: linear-gradient(180deg, #fff293, var(--ui-accent) 60%, var(--ui-accent-dk)); }
.score-row.foe .score-bar i { background: linear-gradient(180deg, #c99cff, var(--ui-danger) 60%, var(--ui-danger-dk)); }
.score-num {
  flex: 0 0 62px; text-align: right;
  font-size: 20px; font-weight: 700; font-style: italic;
  font-variant-numeric: tabular-nums;
}
.result-note { margin: 0 0 14px; font-size: 13.5px; opacity: .85; line-height: 1.35; }

/* ============================ short screens ============================ */
@media (max-height: 460px) {
  .panel { padding: 10px 14px 14px; border-radius: 8px 18px 9px 16px; }
  .logo-text { font-size: clamp(30px, 9cqw, 44px); }
  .tag { margin: 5px 0 8px; }
  .ctl-grid { gap: 4px; margin-bottom: 9px; }

  /* A phone held sideways is wide and very short, so the title screen turns
     on its side too: name and pitch on the left, controls and the start
     button on the right. Nothing scrolls, so nothing is lost below a fold. */
  #screenTitle .panel {
    width: min(96cqw, 720px);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    grid-template-areas: "logo ctl" "tag btn";
    align-items: center; column-gap: 16px; row-gap: 6px;
    max-height: none; overflow: visible;
  }
  #screenTitle .logo-wrap { grid-area: logo; margin: 0; }
  #screenTitle .tag { grid-area: tag; margin: 0; align-self: start; }
  #screenTitle .ctl-grid { grid-area: ctl; margin: 0; grid-template-columns: 1fr 1fr; }
  #screenTitle .big-btn { grid-area: btn; }
  #screenTitle #logoImg { width: min(100%, 240px); }
  .ctl { padding: 3px 7px; font-size: 12.5px; }
  .big-btn { padding: 9px 14px 10px; min-height: 46px; }
  .verdict { font-size: clamp(26px, 8cqw, 40px); margin-bottom: 8px; }
  .stick-base { width: 96px; height: 96px; }
  .stick-knob { width: 44px; height: 44px; margin: -22px 0 0 -22px; }
  .tbtn { width: 80px; height: 56px; font-size: 15px; }
  .tbtn.fire { width: 92px; height: 66px; font-size: 17px; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 1ms !important; animation-duration: 1ms !important; }
}

/* =====================================================================
   IMPACT LAYER
   Same kit as everything above: irregular blob silhouettes (--blob-a/b),
   the two ink colours, deep-girder outline, overshoot motion curve.
   Two jobs, neither of them decoration:
     - LENS: ink thrown at the camera. Sits over the frame and under every
       readable HUD element, never over the reticle, and never wide enough
       to hide a threat — the blobs cluster at the frame edges.
     - COV POPS: the turf bar lurching is the score changing. A big flip
       gets a number that leaves the bar, so a glance at the top of the
       screen tells you the match just moved.
   ===================================================================== */
.lens { position: absolute; inset: 0; z-index: 6; pointer-events: none; overflow: hidden; }
/* Ink on GLASS — not a marble stuck to the screen. These used to carry an inset
   white specular over an inset dark underside, which is the exact shading recipe
   for a sphere: at 96px of fully opaque violet they read as soap bubbles floating
   in front of the arena, and they hid whatever was behind them. Real ink on a
   lens is pooled off-centre, thin and translucent at the rim, still see-through
   enough to fight through, and it RUNS. So: a soft-edged radial pool that fades
   to nothing at the edge, one thin gloss sliver instead of a round highlight,
   and a drip that stretches downward as it goes. --ink is set per-fleck by the
   game (yours yellow, theirs violet). */
.lens i {
  position: absolute;
  display: block;
  border-radius: var(--blob-a);
  opacity: 0;
  will-change: opacity, transform;
  animation: lensSplat 1250ms cubic-bezier(0.16, 0.9, 0.3, 1) forwards;
  /* No bright core: a lit centre with a dark rim is how you draw a SPHERE, and
     that is exactly what these used to look like. Flat ink through the middle,
     thinning to nothing at the edge, is how you draw a stain on glass. */
  background:
    radial-gradient(ellipse 72% 66% at 42% 38%,
      var(--ink, var(--ui-danger)) 0%,
      var(--ink, var(--ui-danger)) 44%,
      color-mix(in srgb, var(--ink, var(--ui-danger)) 72%, transparent) 76%,
      color-mix(in srgb, var(--ink, var(--ui-danger)) 34%, transparent) 92%,
      transparent 100%);
  filter: blur(1.1px);
}
.lens i.b { border-radius: var(--blob-b); }
/* the run: wet ink never stops where it lands */
.lens i::after {
  content: ""; position: absolute;
  left: 36%; top: 58%; width: 24%; height: 76%;
  border-radius: 50% 50% 46% 54% / 30% 26% 74% 70%;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--ink, var(--ui-danger)) 70%, transparent), transparent 90%);
  filter: blur(0.8px);
}
/* one thin wet gloss, angled — a lens smear catches light in a streak */
.lens i::before {
  content: ""; position: absolute;
  left: 20%; top: 19%; width: 32%; height: 12%;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.3);
  transform: rotate(-24deg);
  filter: blur(2px);
}
@keyframes lensSplat {
  0%   { opacity: 0;    transform: scale(0.28) rotate(var(--r, 0deg)); }
  10%  { opacity: 0.78; transform: scale(1.16, 1.05) rotate(var(--r, 0deg)); }
  26%  { opacity: 0.6;  transform: scale(1) rotate(var(--r, 0deg)); }
  100% { opacity: 0;    transform: scale(0.97, 1.14) translateY(24px) rotate(var(--r, 0deg)); }
}

.turf-fill.lurch { transition: width 380ms cubic-bezier(0.34, 1.56, 0.64, 1); }
.turf-bar.flip { animation: barFlip 340ms cubic-bezier(0.34, 1.56, 0.64, 1); }
@keyframes barFlip {
  0%   { transform: scale(1, 1); }
  35%  { transform: scale(1.035, 1.5); }
  100% { transform: scale(1, 1); }
}

.cov-pops {
  position: absolute; top: calc(104px + var(--safe-t)); left: 50%;
  width: min(60cqw, 460px); height: 0;
  transform: translateX(-50%);
  pointer-events: none;
}
.cov-pops b {
  position: absolute; top: 0;
  padding: 2px 10px 3px;
  border: var(--ui-outline) solid var(--ui-surface);
  border-radius: var(--blob-b);
  background: var(--ui-accent);
  color: var(--ui-surface);
  font-size: 15px; font-weight: 800; font-style: italic;
  font-variant-numeric: tabular-nums;
  text-shadow: none;
  box-shadow: 2px 3px 0 rgba(10, 6, 18, 0.5);
  animation: covPop 900ms cubic-bezier(0.16, 0.9, 0.3, 1) forwards;
}
.cov-pops b.foe { background: var(--ui-danger); color: var(--ui-ink); }
@keyframes covPop {
  0%   { opacity: 0; transform: translate(-50%, 6px) scale(0.6) rotate(-6deg); }
  22%  { opacity: 1; transform: translate(-50%, -6px) scale(1.12) rotate(2deg); }
  100% { opacity: 0; transform: translate(-50%, -34px) scale(0.95) rotate(-2deg); }
}

/* ===================== splat callouts (world-anchored) =====================
   The critic's note: "no +1 popup". Worse than missing, it was missing at the
   only moment the game has that deserves one. A splat is scored at the top-right
   chip, which is nowhere near where the player is looking — their eyes are on the
   rival they just popped. So the callout is thrown FROM the rival: it spawns at
   that actor's projected screen position and climbs, which is the same trick the
   turf chips use, aimed at the fight instead of the bar.
   Same kit as everything else: blob silhouette, girder outline, hard offset
   shadow, overshoot curve, player ink for a kill and rival ink for a death.
   ===================================================================== */
.splat-pops { position: absolute; inset: 0; pointer-events: none; }
.splat-pops b {
  position: absolute;
  display: flex; align-items: baseline; gap: 5px;
  padding: 3px 11px 4px;
  border: var(--ui-outline) solid var(--ui-surface);
  border-radius: var(--blob-a);
  background: var(--ui-accent);
  color: var(--ui-surface);
  font-size: clamp(15px, 2.4cqw, 20px); font-weight: 800; font-style: italic;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  box-shadow: 3px 4px 0 rgba(10, 6, 18, 0.55);
  animation: splatPop 1000ms cubic-bezier(0.16, 0.9, 0.3, 1) forwards;
}
.splat-pops b i { font-size: 0.72em; letter-spacing: 0.06em; opacity: 0.85; }
.splat-pops b.foe { background: var(--ui-danger); color: var(--ui-ink); }
@keyframes splatPop {
  0%   { opacity: 0; transform: translate(-50%, -40%) scale(0.5) rotate(-8deg); }
  18%  { opacity: 1; transform: translate(-50%, -62%) scale(1.18) rotate(3deg); }
  34%  { opacity: 1; transform: translate(-50%, -70%) scale(1) rotate(-1deg); }
  100% { opacity: 0; transform: translate(-50%, -168%) scale(0.94) rotate(-3deg); }
}

/* the replay caption over the map filling in, before the panel lands */
.replay-tag {
  position: absolute; left: 50%; bottom: calc(46px + var(--safe-b));
  transform: translateX(-50%);
  z-index: 18;
  padding: 5px 18px 7px;
  border: var(--ui-outline) solid var(--ui-surface);
  border-radius: var(--blob-a);
  background: var(--ui-plate);
  color: var(--ui-surface);
  font-size: clamp(13px, 2.4cqw, 18px); font-weight: 800; font-style: italic;
  letter-spacing: 0.06em;
  box-shadow: 3px 4px 0 rgba(10, 6, 18, 0.55);
  opacity: 0; transition: opacity 200ms ease-out;
}
.replay-tag.show { opacity: 1; }

/* =====================================================================
   MULTIPLAYER ADDENDUM
   The world's ink colours are fixed (yellow crew vs violet crew), but "you"
   is now whichever crew this browser was dealt. When you play violet, every
   piece of you/foe chrome swaps its ink, not its geometry.
   ===================================================================== */
body.team-violet {
  --ui-accent: #8b3cf5;  --ui-accent-dk: #5c1fae;
  --ui-danger: #ffe11f;  --ui-danger-dk: #d9a800;
}
body.team-violet .turf-fill.you {
  background: linear-gradient(180deg, #c99cff, #8b3cf5 60%, #5c1fae);
}
body.team-violet .turf-fill.foe {
  background: linear-gradient(180deg, #fff293, #ffe11f 60%, #d9a800);
}
body.team-violet .score-row.you .score-bar i {
  background: linear-gradient(180deg, #c99cff, #8b3cf5 60%, #5c1fae);
}
body.team-violet .score-row.foe .score-bar i {
  background: linear-gradient(180deg, #fff293, #ffe11f 60%, #d9a800);
}
body.team-violet .turf-badge.you { color: #fff6e0; }
body.team-violet .turf-badge.foe { color: #16121f; }
body.team-violet .cov-pops b.foe,
body.team-violet .splat-pops b.foe { color: #16121f; }

/* start buttons while the room forms: still a button, visibly parked */
.big-btn[disabled] {
  opacity: 0.55;
  cursor: default;
  filter: saturate(0.4);
}

/* ============================ gz lobby ==============================
   This build brings its own lobby (hosted backends ship one inside
   insertCoin). Same cartoon-plate language as every other panel. */
#gzLobby {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(13, 10, 20, 0.72);
  backdrop-filter: blur(3px);
}
.gz-lobby-card {
  border: var(--ui-outline) solid var(--ui-surface);
  background: var(--ui-surface-2);
  border-radius: var(--blob-a);
  box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.35);
  padding: 34px 44px 30px;
  display: flex; flex-direction: column; gap: 12px;
  min-width: 300px; max-width: 86vw;
}
.gz-lobby-title {
  font-size: 28px; font-weight: 900; letter-spacing: 1px;
  color: var(--ui-accent); text-shadow: 2px 2px 0 var(--ui-surface);
  text-align: center; margin-bottom: 6px;
}
.gz-lobby-title span { color: var(--ui-danger); }
.gz-lobby-btn {
  border: var(--ui-outline) solid var(--ui-surface);
  background: linear-gradient(180deg, #fff08a 0%, var(--ui-accent) 45%, var(--ui-accent-dk) 100%);
  color: var(--ui-surface);
  border-radius: var(--blob-b);
  font: 900 17px/1 var(--ui-font); letter-spacing: 0.5px;
  padding: 13px 18px; cursor: pointer;
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.3);
  transition: transform var(--ui-motion-fast);
}
.gz-lobby-btn:hover:not([disabled]) { transform: scale(1.04) rotate(-1deg); }
.gz-lobby-btn[disabled] { opacity: 0.55; cursor: default; filter: saturate(0.4); }
.gz-lobby-btn.small { padding: 11px 16px; font-size: 15px; flex: 0 0 auto; }
.gz-lobby-sep {
  text-align: center; font-size: 13px; opacity: 0.6; margin: -2px 0;
}
.gz-lobby-join { display: flex; gap: 8px; }
.gz-lobby-input {
  flex: 1 1 auto; min-width: 0;
  border: var(--ui-outline) solid var(--ui-surface);
  background: #0d0a14; color: var(--ui-ink);
  border-radius: 12px;
  font: 900 17px/1 var(--ui-font); letter-spacing: 4px; text-align: center;
  padding: 11px 8px; text-transform: uppercase;
  user-select: text; -webkit-user-select: text;
}
.gz-lobby-status {
  min-height: 17px; text-align: center; font-size: 13px;
  color: var(--ui-ink); opacity: 0.8;
}

/* room code chip: the invite handle once a friend room is up */
#gzRoomChip {
  position: fixed; z-index: 55;
  top: calc(10px + var(--safe-t)); right: calc(12px + var(--safe-r));
  border: var(--ui-outline) solid var(--ui-surface);
  background: var(--ui-surface-2);
  border-radius: var(--blob-b);
  box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.3);
  padding: 8px 14px;
  font: 900 14px/1.3 var(--ui-font); letter-spacing: 1px;
  color: var(--ui-ink); cursor: pointer;
}
#gzRoomChip b { color: var(--ui-accent); letter-spacing: 3px; }
#gzRoomChip small { display: block; font-size: 10px; opacity: 0.65; letter-spacing: 0.5px; }
/* the splat counters own the top-right corner once the HUD is live;
   the invite chip belongs to the room-forming screens only */
body:has(.hud.live) #gzRoomChip { display: none; }
