/* Effective viewport units: 1 unit of app-height/width regardless of how the
   phone is held — in portrait the app is rotated 90°, so the axes swap. */
:root { --vhu: 1vh; --vwu: 1vw; --dvhu: 1vh; --dvwu: 1vw; --dvhu: 1dvh; --dvwu: 1dvw; }
@media (orientation: portrait) {
  :root { --vhu: 1vw; --vwu: 1vh; --dvhu: 1vw; --dvwu: 1vh; --dvhu: 1dvw; --dvwu: 1dvh; }
}

:root {
  --bg: #0b1020;
  --panel: #141b33;
  --panel-2: #1c2444;
  --line: #2a3358;
  --text: #eaf0ff;
  --muted: #8f9bc4;
  --primary: #ff7a2e;
  --primary-2: #ff5a52;
  --accent: #54c8ff;
  --p0: #54c8ff;
  --p1: #ff6b6b;
  --p2: #ffd23f;
  --p3: #b6ff5a;
  --good: #3ce88f;
  --shadow: 0 10px 30px rgba(0,0,0,.45);
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; margin: 0; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  background: radial-gradient(120% 100% at 50% 0%, #16204a 0%, var(--bg) 60%);
  color: var(--text);
  overflow: hidden;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}
#app { position: fixed; inset: 0; }

/* ---------- Screens ---------- */
.screen { position: absolute; inset: 0; display: none; flex-direction: column; }
.screen.active { display: flex; }

/* ---------- Buttons / fields ---------- */
.btn {
  appearance: none; border: 1px solid var(--line); background: var(--panel-2);
  color: var(--text); font-size: 16px; font-weight: 700; padding: 14px 18px;
  border-radius: 14px; cursor: pointer; transition: transform .05s ease, filter .15s ease;
}
.btn:active { transform: translateY(1px) scale(.99); }
.btn.big { width: 100%; padding: 15px; font-size: 17px; }
.btn.primary { background: linear-gradient(180deg, var(--primary), var(--primary-2)); border-color: transparent; color: #240a00; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn:disabled { opacity: .4; cursor: not-allowed; filter: grayscale(.4); }

.field { display: flex; flex-direction: column; gap: 6px; text-align: left; margin: 8px 0 4px; }
.field span { font-size: 12px; color: var(--muted); letter-spacing: .08em; text-transform: uppercase; }
input {
  font-size: 17px; padding: 14px; border-radius: 12px; border: 1px solid var(--line);
  background: #0e142b; color: var(--text); width: 100%;
}
input:focus { outline: 2px solid var(--accent); border-color: transparent; }

/* ---------- Home / Lobby ---------- */
/* Scrollable so nothing is ever clipped on short screens; `safe center` keeps it
   centered when it fits but falls back to top-aligned (never cuts off the top)
   when the card is taller than the viewport. Safe-area padding clears notches. */
#lobby {
  align-items: center;
  justify-content: safe center;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: max(22px, env(safe-area-inset-top)) max(22px, env(safe-area-inset-right))
           max(22px, env(safe-area-inset-bottom)) max(22px, env(safe-area-inset-left));
  text-align: center;
}
.home-card {
  width: 100%; max-width: 420px; background: var(--panel); border: 1px solid var(--line);
  border-radius: 22px; padding: 26px 22px; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 12px;
}
.logo { font-size: 29px; font-weight: 900; line-height: 1.08; letter-spacing: .012em; }
.logo em { font-style: normal; color: var(--primary); padding: 0 .1em; }
.logo.small { font-size: 18px; }
.byline { margin: -4px 0 0; font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .28em; }
.byline b { color: var(--primary); font-weight: 800; }
.tagline { color: var(--muted); margin: 2px 0 8px; font-size: 15px; }
.or { display: flex; align-items: center; gap: 12px; color: var(--muted); font-size: 12px; margin: 6px 0; text-transform: uppercase; letter-spacing: .1em; }
.or::before, .or::after { content: ""; height: 1px; background: var(--line); flex: 1; }
.join-row { display: flex; gap: 10px; }
/* CPU difficulty selector (now lives inside the "Play the computer" tile) */
.diffrow { display: flex; gap: 6px; }
.diff {
  flex: 1; appearance: none; cursor: pointer; padding: 9px 0; border-radius: 10px;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--muted);
  font-weight: 800; font-size: 13px; letter-spacing: .03em; transition: border-color .12s, color .12s, background .12s;
}
.diff:active { transform: scale(.97); }
.diff.active { color: #0a1020; background: var(--accent); border-color: var(--accent); }
/* Game-mode picker + FFA player count */
.modrow { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.countrow { display: flex; gap: 6px; }
.countrow.hidden { display: none; }
.mode, .cnt {
  flex: 1; appearance: none; cursor: pointer; padding: 11px 0; border-radius: 10px;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--muted);
  font-weight: 800; font-size: 13.5px; transition: border-color .12s, color .12s, background .12s;
}
.mode:active, .cnt:active { transform: scale(.97); }
.mode.active, .cnt.active { color: #0a1020; background: var(--accent); border-color: var(--accent); }
/* Lobby roster */
.roster { display: flex; flex-direction: column; gap: 6px; text-align: left; }
.rp { display: flex; align-items: center; gap: 8px; padding: 8px 11px; border-radius: 11px;
      background: var(--panel-2); border: 1px solid var(--line); font-weight: 700; font-size: 14px; }
.rp .dot { width: 11px; height: 11px; border-radius: 50%; background: var(--seat); flex: 0 0 auto; }
.rp .tag { margin-left: auto; font-size: 11px; color: var(--muted); font-weight: 600; }
.rp.empty { opacity: .38; font-style: italic; font-weight: 600; }
#startMatchBtn.hidden { display: none; }
#helpDemoBtn.hidden { display: none; }
.code-input { text-transform: uppercase; letter-spacing: .35em; text-align: center; font-weight: 800; font-size: 22px; }
.join-row .btn { flex: 0 0 auto; }
.error { color: var(--p1); min-height: 18px; font-size: 14px; margin: 2px 0 0; }
.footnote { color: var(--muted); font-size: 12.5px; margin-top: 18px; opacity: .8; }
.muted { color: var(--muted); font-size: 14px; }
.home-card h2 { margin: 4px 0; font-size: 20px; }
.code-display {
  font-size: 46px; font-weight: 900; letter-spacing: .3em; color: var(--primary);
  background: #0e142b; border: 1px dashed var(--line); border-radius: 14px; padding: 14px; padding-left: calc(14px + .3em);
}
.spinner { width: 30px; height: 30px; border: 3px solid var(--line); border-top-color: var(--primary); border-radius: 50%; margin: 8px auto 0; animation: spin 1s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
/* Lobby composition: slim brand/status head, then invite | roster+actions.
   Tall screens stack the two; the landscape block further down puts them side
   by side so the whole waiting room fits a phone with ZERO scrolling. */
.lobby-card { gap: 10px; }
.lb-head { display: flex; flex-direction: column; gap: 8px; align-items: center; }
.lb-status { display: flex; align-items: center; justify-content: center; gap: 10px; min-width: 0; }
.lb-status .spinner { margin: 0; flex: 0 0 auto; width: 20px; height: 20px; border-width: 3px; }
.lb-status h2 { margin: 0; font-size: 18px; }
.lb-grid { display: flex; flex-direction: column; gap: 12px; }
.lb-invite { display: flex; flex-direction: column; gap: 10px; }
.lb-invite .muted { margin: 0; }
.lb-btnrow { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.lb-side { display: flex; flex-direction: column; gap: 8px; }
.lb-side .roster:empty { display: none; }

/* ==========================================================================
   TITLE SCREEN
   The menu screens sit on a live canyon backdrop; the card above it is a
   three-part composition (.hero / .deck / .loadout) that reflows into two
   columns in landscape. #home itself is untouched as a scroller — everything
   here is inside .home-card or in a pointer-transparent layer behind it.
   ========================================================================== */

/* ---- Animated backdrop --------------------------------------------------- */
.bg-canyon { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.bg-canyon svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Dropped entirely in-match: #hud-top / #dock use backdrop-filter and would
   otherwise blur the canyon art instead of nothing. Also saves the GPU. */
body.in-game .bg-canyon { display: none; }
/* Vignette so the card always has contrast, whatever the ridges are doing. */
.bg-canyon::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(110% 78% at 50% 42%, rgba(8,12,26,0) 0%, rgba(8,12,26,.55) 62%, rgba(8,12,26,.86) 100%);
}
/* Parallax. Transform units on an SVG <g> are viewBox user units, so the drift
   is the same proportion of the artwork on every device. */
.bg-canyon .ridge { will-change: transform; }
@keyframes driftFar  { from { transform: translate3d(-9px, 0, 0);  } to { transform: translate3d(9px, 0, 0);  } }
@keyframes driftMid  { from { transform: translate3d(-20px, 0, 0); } to { transform: translate3d(20px, 0, 0); } }
@keyframes driftNear { from { transform: translate3d(-34px, 0, 0); } to { transform: translate3d(34px, 0, 0); } }
.bg-canyon .r3 { animation: driftFar  86s ease-in-out infinite alternate; }
.bg-canyon .r2 { animation: driftMid  61s ease-in-out infinite alternate-reverse; }
.bg-canyon .r1 { animation: driftNear 44s ease-in-out infinite alternate; }
/* A short dash running a ballistic path — a streak, never a blob. */
.bg-canyon .tracer {
  fill: none; stroke-linecap: round; stroke-dasharray: 84 1600;
}
.bg-canyon .t1 { stroke: #ffb45a; stroke-width: 3.4; animation: tracer 11s cubic-bezier(.32,0,.66,1) infinite; }
.bg-canyon .t2 { stroke: #54c8ff; stroke-width: 2.4; opacity: .55; animation: tracer 15s cubic-bezier(.32,0,.66,1) 5.5s infinite; }
@keyframes tracer {
  0%        { stroke-dashoffset: 84;    opacity: 0; }
  5%        { opacity: 1; }
  62%       { opacity: 1; }
  76%, 100% { stroke-dashoffset: -1560; opacity: 0; }
}

/* ---- Title treatment ----------------------------------------------------- */
/* NOTE: .logo / .logo.small still belong to #lobby — do not fold these in. */
.gtitle {
  margin: 0; display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 0 .1em; line-height: .94; text-transform: uppercase;
  font-size: clamp(30px, calc(8.4 * var(--vwu)), 48px); font-weight: 900; letter-spacing: .015em;
}
/* Extruded gradient lettering: background-clip paints the face, two hard
   drop-shadows are the bevel, the third is the cast shadow. */
.gtitle .w {
  background: linear-gradient(180deg, #ffffff 0%, #ffe2c6 38%, #ff9a4a 74%, #d9500f 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 2px 0 #8d3208) drop-shadow(0 4px 0 #4d1a03) drop-shadow(0 12px 20px rgba(0,0,0,.6));
}
.gtitle .amp {
  font-size: .38em; font-weight: 900; color: #2a0d00;
  width: 1.55em; height: 1.55em; line-height: 1.55em; text-align: center;
  border-radius: .32em; transform: rotate(-7deg);
  background: linear-gradient(180deg, #ffb45a, var(--primary));
  box-shadow: 0 3px 0 #8b3708, 0 8px 18px rgba(0,0,0,.5);
}
.title-rule {
  height: 3px; width: min(280px, 72%); margin: 9px auto 0; border-radius: 2px;
  background: linear-gradient(90deg, transparent, var(--primary) 20%, #ffd9a8 50%, var(--primary) 80%, transparent);
  box-shadow: 0 0 14px rgba(255,122,46,.45);
}

/* ---- Card composition ---------------------------------------------------- */

/* ---- Callsign field ------------------------------------------------------ */
.callsign {
  display: flex; align-items: center; gap: 8px; text-align: left; margin-top: 8px;
  background: #0e142b; border: 1px solid var(--line); border-radius: 14px; padding: 5px 5px 5px 12px;
}
.callsign:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(84,200,255,.22); }
.callsign .cs-label { flex: 0 0 auto; font-size: 10px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted); }
.callsign input {
  flex: 1 1 auto; width: auto; min-width: 0;
  background: transparent; border: 0; padding: 8px 0; font-size: 17px; font-weight: 800;
}
.callsign input:focus { outline: none; }        /* beats the global input:focus ring */
.reroll {
  flex: 0 0 auto; width: 40px; height: 40px; padding: 0; border-radius: 11px; cursor: pointer;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
}
.reroll svg { width: 20px; height: 20px; display: block; }
.reroll:active { transform: scale(.94); }

/* ---- Play deck ----------------------------------------------------------- */
.playdeck { display: flex; flex-direction: column; gap: 10px; }
/* A tile is ONE object: the action plus its own options, so the options never
   read as a separate decision. Buttons cannot nest, hence the wrapper. */
.tile { border: 1px solid var(--line); border-radius: 16px; background: var(--panel-2); overflow: hidden; }
.playcard {
  appearance: none; width: 100%; border: 0; background: transparent; color: var(--text);
  font: inherit; text-align: left; cursor: pointer;
  display: flex; align-items: center; gap: 12px; padding: 13px 14px;
  transition: transform .05s ease;
}
.playcard:active { transform: translateY(1px); }
.playcard .pc-ico {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.07);
}
.playcard .pc-ico svg { width: 21px; height: 21px; display: block; }
.playcard .pc-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.playcard .pc-txt b { font-size: 16.5px; font-weight: 800; }
.playcard .pc-txt i { font-style: normal; font-size: 11.5px; line-height: 1.25; color: var(--muted); }
.playcard .pc-go { flex: 0 0 auto; display: flex; color: var(--muted); }
.playcard .pc-go svg { width: 18px; height: 18px; display: block; }
.tile .suboptions { display: flex; flex-direction: column; gap: 6px; padding: 0 10px 10px; }

/* PRIMARY call to action — the only saturated element on the screen. */
.tile.hot {
  border-color: transparent;
  background: linear-gradient(180deg, var(--primary), var(--primary-2));
  box-shadow: 0 10px 26px rgba(255,90,60,.30);
}
.tile.hot .playcard { color: #240a00; padding: 16px 14px; }
.tile.hot .pc-ico   { background: rgba(255,255,255,.28); }
.tile.hot .pc-txt b { font-size: 19px; }
.tile.hot .pc-txt i { color: rgba(36,10,0,.72); }
.tile.hot .pc-go    { color: rgba(36,10,0,.78); }

/* ---- Loadout strip ------------------------------------------------------- */
.opt-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: .16em; color: var(--muted); }
.optline { display: flex; align-items: center; justify-content: space-between; gap: 10px; }

/* ---- Rotate prompt ------------------------------------------------------- */
.rotate-hint { display: none; }
/* ==========================================================================
   HARD LANDSCAPE LOCK — a browser cannot rotate the device, so in portrait the
   ENTIRE app is laid out at calc(100 * var(--dvhu)) x calc(100 * var(--dvwu)) and rotated 90°: whatever way the
   phone is held, the game IS landscape. Canvas input is safe (offsetX/Y are
   local coords; sizing reads clientWidth). Every size-sensitive media query
   below carries a portrait twin phrased against the EFFECTIVE (rotated) axes.
   ========================================================================== */
html { background: var(--bg); }
@media (orientation: portrait) {
  body {
    position: fixed; top: 0; left: 100vw; left: 100dvw;
    width: 100vh; width: 100dvh;
    height: 100vw; height: 100dvw;
    transform: rotate(90deg); transform-origin: top left;
    overflow: hidden;
  }
}

@media (orientation: portrait) and (max-width: 0px) {   /* retired: shim replaces the rotate prompt */
  body.in-game .rotate-hint {
    display: flex; position: absolute; inset: 0; z-index: 18;
    align-items: center; justify-content: center; text-align: center;
    padding: max(24px, env(safe-area-inset-top)) 26px max(24px, env(safe-area-inset-bottom));
    background: rgba(6,9,20,.94); backdrop-filter: blur(6px);
  }
}
.rh-card { max-width: 320px; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.rh-phone { width: 104px; height: 104px; transform-origin: 50% 50%; animation: rhTurn 3.4s ease-in-out infinite; }
.rh-body   { fill: none; stroke: var(--primary); stroke-width: 4; }
.rh-screen { fill: rgba(255,122,46,.16); }
@keyframes rhTurn {
  0%, 16%   { transform: rotate(0deg); }
  44%, 80%  { transform: rotate(-90deg); }
  100%      { transform: rotate(0deg); }
}
.rh-title { font-size: 21px; font-weight: 900; }
.rh-sub   { color: var(--muted); font-size: 14px; margin: 0; line-height: 1.4; }

/* ---- Reduced motion ------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .bg-canyon .ridge, .bg-canyon .tracer, .rh-phone { animation: none !important; }
  .bg-canyon .t1 { stroke-dashoffset: -760; opacity: .8; }
  .bg-canyon .t2 { stroke-dashoffset: -900; opacity: .4; }
  .rh-phone { transform: rotate(-90deg); }
}

/* ---------- Game: top HUD ---------- */
#game { display: none; }
/* Keep every game element (scoreboard, battlefield, dock) clear of the iPhone
   notch/speaker in landscape. env(safe-area-inset-*) is 0 on devices without one. */
#game.active { display: flex; padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
/* ...and in PORTRAIT the rotation shim has turned the app 90°, so its edges no
   longer line up with the device's: the app's left edge is the phone's TOP, its
   right edge the phone's BOTTOM, its top the phone's RIGHT and its bottom the
   phone's LEFT. Each edge needs the inset that physically applies to IT. With the
   device-space values (all of which are 0 on the sides in portrait) the FIRE
   button — the app's right-most control — sat under the home indicator / gesture
   bar along the phone's bottom edge, which reads as FIRE being cut off on the
   right, while the dock spent that allowance at the app's bottom where the phone
   has no inset at all. `body` prefixes keep these winning over the tier
   overrides further down the file. */
@media (orientation: portrait) {
  body #game.active {
    padding-left: env(safe-area-inset-top);
    padding-right: env(safe-area-inset-bottom);
  }
  body #dock { padding-bottom: calc(3px + env(safe-area-inset-left)); }
}
#hud-top {
  display: flex; flex-direction: column; gap: 3px;
  padding: max(8px, env(safe-area-inset-top)) 12px 8px; background: rgba(10,14,30,.6);
  backdrop-filter: blur(6px); border-bottom: 1px solid var(--line);
}
/* One equal column per player, 2..4. `--seat` is set per card from JS. */
.score-row { display: grid; grid-template-columns: repeat(var(--n, 2), minmax(0, 1fr)); gap: 8px; }
.pscore { min-width: 0; border-bottom: 2px solid transparent; padding-bottom: 2px; }
.pscore.acting { border-bottom-color: var(--seat); }
.pscore.dead { opacity: .42; filter: grayscale(1); }
.pscore.dead .pname { text-decoration: line-through; }
/* The WARLORD's card reads as the threat it is. */
.pscore.bossrow { --seat: #ff3b30; }
.pscore.bossrow .pname { color: #ff5a52; letter-spacing: .06em; font-weight: 900; }
.pname { font-size: 12.5px; color: var(--seat, var(--muted)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pval { display: flex; align-items: baseline; gap: 8px; }
.score { font-size: 26px; font-weight: 900; font-variant-numeric: tabular-nums; }
.shots { font-size: 11px; color: var(--muted); }
.hpbar { height: 6px; border-radius: 3px; background: #0e142b; border: 1px solid var(--line); overflow: hidden; margin-top: 3px; }
.hpbar i { display: block; height: 100%; width: 100%; background: var(--good); transition: width .35s ease, background .35s ease; }
/* 3-4 players: shrink the numerals so four cards still fit a 375px portrait screen. */
.score-row.n3 .score, .score-row.n4 .score { font-size: 18px; }
.score-row.n3 .pname, .score-row.n4 .pname { font-size: 11px; }
.score-row.n4 .shots { display: none; }
.turnbox { text-align: center; }
.clock { font-size: 22px; font-weight: 900; font-variant-numeric: tabular-nums; line-height: 1; }
.clock.low { color: var(--p1); animation: pulse .6s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .4; } }
.turnlabel { font-size: 11px; color: var(--muted); margin-top: 2px; letter-spacing: .04em; }

/* ---------- Game: stage / canvas ---------- */
#stage { position: relative; flex: 1; min-height: 0; }
#canvas { display: block; width: 100%; height: 100%; touch-action: none; image-rendering: auto; }
/* very faint scanlines — barely there, so the HD art stays clean */
#stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 3;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,.022) 0 1px, transparent 1px 5px);
}
.mute { position: absolute; top: 10px; left: 10px; width: 40px; height: 40px; border-radius: 12px; border: 1px solid var(--line); background: rgba(10,14,30,.6); color: var(--text); font-size: 18px; cursor: pointer; backdrop-filter: blur(4px); z-index: 4; }
.mute:active { transform: scale(.95); }
/* Leave-game button — top-right so it can't be fat-fingered with the left-side controls */
.leave { position: absolute; top: 10px; right: 10px; width: 40px; height: 40px; border-radius: 12px; border: 1px solid var(--line); background: rgba(10,14,30,.6); color: var(--text); cursor: pointer; backdrop-filter: blur(4px); z-index: 4; display: flex; align-items: center; justify-content: center; padding: 0; }
.leave svg { width: 21px; height: 21px; }
.leave:active { transform: scale(.95); }
/* Leave/help live inside the "..." meta stack now, so they flow in its column
   instead of being individually pinned to the corner. (The golf scorecard is
   standalone again since 8.22 — see #golfCardBtn.) */
.golf-only { display: none; }
body.golf .golf-only { display: flex; }
/* Draft slot row: one box per pick, filled boxes carry the weapon's icon,
   empty ones the slot number — full row = ready to battle. */
.arm-slots { display: flex; gap: 8px; justify-content: center; margin: 2px 0 8px; }
.arm-slot {
  width: 34px; height: 34px; border: 2px dashed var(--line); border-radius: 9px;
  display: flex; align-items: center; justify-content: center; color: var(--muted);
}
.arm-slot i { font-style: normal; font-weight: 800; font-size: 12px; }
.arm-slot.filled { border: 2px solid #54c8ff; background: rgba(84, 200, 255, .12); }
.arm-slot.filled svg { width: 22px; height: 22px; }
/* Short viewports: the GRID absorbs the squeeze (scrolls), never the lock
   button — same pattern as .menu-card panes. */
.arm-card .arm-grid { min-height: 0; overflow-y: auto; }

/* The standalone scorecard button sits one slot left of the "..." button
   (8.22 — out of the meta stack, one tap away). Plain 58px: #game.active
   already pads the whole stage by the right safe-area inset — adding env()
   here would count the notch twice and float the button away from "...". */
#golfCardBtn { right: 58px; }
/* Between-holes score banner: strokes + to-par per player, self-hiding. */
#holeScore {
  position: absolute; left: 50%; top: max(16%, 56px); transform: translateX(-50%) translateY(-6px);   /* clear of the toast band on short stages */
  background: rgba(8, 12, 26, .88); border: 1px solid var(--line); border-radius: 14px;
  padding: 12px 22px; z-index: 5; pointer-events: none; text-align: center;
  min-width: 230px; opacity: 0; transition: opacity .3s ease, transform .3s ease;
}
#holeScore.show { opacity: 1; transform: translateX(-50%) translateY(0); }
#holeScore .hs-head { font-weight: 900; letter-spacing: .12em; font-size: 12px; color: var(--muted); }
#holeScore .hs-row { display: flex; gap: 16px; justify-content: space-between; font-size: 15px; margin-top: 6px; }
#holeScore .hs-row b { font-weight: 800; }
#holeScore .hs-under { color: #4ce88f; }
#holeScore .hs-over { color: #ff5a52; }
#holeScore .hs-next { margin-top: 9px; font-size: 10.5px; letter-spacing: .14em; color: var(--muted); font-weight: 700; }
.btn.danger { color: var(--p1); }
.zoomctl {
  position: absolute; top: 58px; left: 10px; display: flex; flex-direction: column; gap: 6px; z-index: 4;
  /* Collapsed by default: the six camera buttons slide in from the rail and
     fade, and are fully inert until the camera button expands them. Pinch and
     two-finger pan remain the primary camera — these are the fallback. */
  transform: translateX(-14px) scale(.9); transform-origin: top left;
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .18s ease, transform .18s ease, visibility 0s linear .18s;
}
#stage.cam-open .zoomctl {
  transform: none; opacity: 1; pointer-events: auto; visibility: visible;
  transition: opacity .18s ease, transform .18s ease, visibility 0s;
}
#camBtn.on, #metaBtn.on { border-color: var(--accent); color: var(--accent); }
/* The meta stack ("...") holds sound, help and leave. */
.metamenu {
  position: absolute; top: 58px; right: 10px; display: flex; flex-direction: column; gap: 6px; z-index: 4;
  transform: translateX(14px) scale(.9); transform-origin: top right;
  opacity: 0; pointer-events: none; visibility: hidden;
  transition: opacity .18s ease, transform .18s ease, visibility 0s linear .18s;
}
#stage.meta-open .metamenu {
  transform: none; opacity: 1; pointer-events: auto; visibility: visible;
  transition: opacity .18s ease, transform .18s ease, visibility 0s;
}
/* Inside the stack the buttons flow in the column, not pinned to the corner. */
.metamenu .leave { position: static; top: auto; right: auto; }
/* Keyboard users must always see where they are. */
#camBtn:focus-visible, #metaBtn:focus-visible, .zbtn:focus-visible,
.metamenu .leave:focus-visible, .dock-tab:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.zbtn { width: 40px; height: 40px; border-radius: 12px; border: 1px solid var(--line); background: rgba(10,14,30,.6); color: var(--text); cursor: pointer; backdrop-filter: blur(4px); display: flex; align-items: center; justify-content: center; padding: 0; }
.zbtn svg { width: 22px; height: 22px; }
.zbtn:active { transform: scale(.95); }
#toast { position: absolute; left: 50%; top: 12px; transform: translateX(-50%); display: flex; flex-direction: column; gap: 6px; align-items: center; pointer-events: none; z-index: 6; }   /* above the hole banner (z 5): a disconnect notice must never hide behind it */
.toast-item { background: rgba(10,14,30,.85); border: 1px solid var(--line); padding: 8px 14px; border-radius: 999px; font-weight: 700; font-size: 14px; animation: toastIn .3s ease, toastOut .3s ease 1.4s forwards; }

@keyframes toastIn { from { opacity: 0; transform: translateY(-8px); } }
@keyframes toastOut { to { opacity: 0; transform: translateY(-8px); } }

/* ---------- Game: bottom dock ---------- */
#dock {
  position: relative; background: rgba(10,14,30,.72); backdrop-filter: blur(6px);
  border-top: 1px solid var(--line); padding: 6px 12px calc(3px + env(safe-area-inset-bottom));
  display: flex; flex-direction: column; gap: 6px;
}
.weapon-strip { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px; scrollbar-width: none; }
.weapon-strip::-webkit-scrollbar { display: none; }
.wchip {
  flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 60px; padding: 6px 5px; border-radius: 12px; border: 1px solid var(--line);
  background: var(--panel-2); cursor: pointer; transition: border-color .12s, transform .05s;
}
.wchip:active { transform: translateY(1px); }
.wchip.sel { border-color: var(--primary); background: #2a1c12; box-shadow: 0 0 0 1px var(--primary) inset; }
.wchip .wrow { display: flex; align-items: center; gap: 3px; }
.wchip .wi { width: 24px; height: 24px; display: block; }
.wchip .wi svg { width: 100%; height: 100%; display: block; }
.wchip .wt { width: 26px; height: 15px; display: block; opacity: .85; }
.wchip .wt svg { width: 100%; height: 100%; display: block; }
.wchip .wn { font-size: 10.5px; font-weight: 700; white-space: nowrap; }
.wchip .wa { font-size: 10px; color: var(--muted); }
.wchip.empty { opacity: .35; pointer-events: none; }

/* Transient weapon-name flash — appears above the chip you just tapped, fades
   after ~1.2s. position:fixed and placed from the chip's getBoundingClientRect
   because .weapon-strip is overflow-x:auto (which clips its children vertically
   too) and #dock's backdrop-filter would trap a fixed child. z-index 12 clears
   the stage buttons (4) and scanlines (3), stays under .overlay (20). It never
   affects layout, so the dock does not shift when it shows. */
.wpop {
  position: fixed; left: 0; top: 0; z-index: 12;
  transform: translate(-50%, -100%);
  pointer-events: none; opacity: 0; visibility: hidden;
  padding: 4px 10px; border-radius: 999px; white-space: nowrap;
  font-size: 12.5px; font-weight: 800; line-height: 1.25;
  color: var(--text); background: rgba(10,14,30,.94);
  border: 1px solid var(--primary); box-shadow: 0 6px 18px rgba(0,0,0,.45);
}
.wpop::after {           /* little pointer down at the chip */
  content: ""; position: absolute; left: 50%; top: 100%; margin-left: -4px;
  border: 4px solid transparent; border-top-color: var(--primary);
}
.wpop.show { visibility: visible; animation: wpop 1.2s ease-out forwards; }
@keyframes wpop {
  0%   { opacity: 0; transform: translate(-50%, calc(-100% + 6px)); }
  12%  { opacity: 1; transform: translate(-50%, -100%); }
  72%  { opacity: 1; transform: translate(-50%, -100%); }
  100% { opacity: 0; transform: translate(-50%, calc(-100% - 8px)); }
}
@media (prefers-reduced-motion: reduce) {
  .wpop.show { animation: wpopFade 1.2s linear forwards; }
}
@keyframes wpopFade { 0%, 82% { opacity: 1; transform: translate(-50%, -100%); }
                      100%    { opacity: 0; transform: translate(-50%, -100%); } }

.control-rows { display: flex; flex-direction: column; gap: 6px; }
.aim-readout { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.stepper { display: flex; align-items: center; justify-content: space-between; gap: 6px; background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px; padding: 4px; }
.readout { text-align: center; line-height: 1.1; }
.readout label { font-size: 10px; color: var(--muted); letter-spacing: .08em; display: block; }
.readout b { font-size: 18px; font-variant-numeric: tabular-nums; }
.mini { width: 42px; height: 40px; border-radius: 10px; border: 1px solid var(--line); background: #0e142b; color: var(--text); font-size: 20px; font-weight: 800; cursor: pointer; }
.mini:active { background: var(--panel-2); }

.drive-row { display: grid; grid-template-columns: auto 1fr auto; gap: 10px; align-items: center; }
.drive { width: 72px; height: 50px; border-radius: 12px; border: 1px solid var(--line); background: var(--panel-2); color: var(--text); font-size: 22px; cursor: pointer; }
.drive:active { background: #24305a; }
.drive:disabled { opacity: .35; }
.fuel { position: relative; height: 30px; border-radius: 999px; background: #0e142b; border: 1px solid var(--line); overflow: hidden; display: flex; align-items: center; justify-content: center; }
.fuel-bar { position: absolute; left: 0; top: 0; bottom: 0; width: 100%; background: linear-gradient(90deg, var(--good), #9be15d); transition: width .12s ease; }
.fuel span { position: relative; font-size: 11px; font-weight: 800; letter-spacing: .12em; color: #06210f; }

/* Skin picker (home screen) */
.skinlabel { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: .18em; margin-top: 4px; text-align: left; }
.skinrow { display: flex; gap: 8px; justify-content: flex-start; }
.swatch { width: 34px; height: 34px; border-radius: 10px; border: 2px solid var(--line); cursor: pointer; position: relative; padding: 0; }
.swatch.sel { border-color: var(--primary); box-shadow: 0 0 0 2px rgba(255,122,46,.35); }
.swatch .lock { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 14px; background: rgba(8,10,20,.45); border-radius: 8px; }

/* ---------- Overlay ---------- */
.overlay { position: absolute; inset: 0; background: rgba(6,9,20,.82); display: flex; align-items: center; justify-content: center; padding: 22px; z-index: 20; backdrop-filter: blur(4px); }
.overlay.hidden { display: none; }
.overlay-card { width: 100%; max-width: 400px; max-height: calc(94 * var(--dvhu)); overflow-y: auto; background: var(--panel); border: 1px solid var(--line); border-radius: 22px; padding: clamp(14px, calc(3.2 * var(--vhu)), 28px) 22px; text-align: center; box-shadow: var(--shadow); display: flex; flex-direction: column; gap: clamp(7px, calc(1.6 * var(--vhu)), 14px); }
.menu-card { overflow-y: hidden; }   /* fitted menus never scroll — they compress */
.result { font-size: 30px; font-weight: 900; }
.result.win { color: var(--good); } .result.lose { color: var(--p1); } .result.draw { color: var(--accent); }
.final-scores { display: flex; justify-content: center; gap: 24px; font-size: 18px; }
.final-scores .fs { display: flex; flex-direction: column; gap: 2px; }
.final-scores .fs b { font-size: 30px; font-weight: 900; }
.final-scores { flex-wrap: wrap; gap: 18px; }
.final-scores .fs b { color: var(--seat, var(--text)); }
.final-scores .fs span { font-size: 12px; color: var(--muted); }

.conn-banner { position: absolute; top: 0; left: 0; right: 0; text-align: center; background: var(--primary-2); color: #fff; font-size: 13px; font-weight: 700; padding: 6px; z-index: 30; }
.conn-banner.hidden { display: none; }

/* ---------- Killcam ---------- */
/* Transitions live on the BASE selectors so the chrome fades back in too. */
#hud-top, #dock { transition: opacity .25s ease, filter .25s ease; }
.mute, .leave { transition: opacity .2s ease; }   /* .zoomctl/.metamenu own theirs (transform+visibility) */
#game.killcam #hud-top, #game.killcam #dock { opacity: .26; filter: saturate(.35); pointer-events: none; }
#game.killcam .mute, #game.killcam .leave, #game.killcam .zoomctl,
#game.killcam .metamenu, #game.killcam .dock-tab { opacity: 0; pointer-events: none; }

@media (orientation: landscape) and (min-width: 620px), (orientation: portrait) and (min-height: 620px) {
  .aim-readout { grid-template-columns: 1fr 1fr; max-width: 640px; margin: 0 auto; width: 100%; }
  .control-rows { max-width: 640px; margin: 0 auto; width: 100%; }
  /* `safe center` degrades to start-alignment once the chips outgrow the strip:
     plain `center` overflows BOTH ends and the first chips cannot be scrolled to.
     Browsers without it drop the second declaration and keep the old behaviour. */
  .weapon-strip { justify-content: center; justify-content: safe center; }
}

/* Landscape phones: ultra-compact dock — icon-only weapons + one control row
   so the battlefield keeps nearly all of the screen. */
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  /* Slim single-row scoreboard: name · HP number · inline bar — minimal height. */
  #hud-top { flex-direction: row; align-items: center; padding: 1px 10px; gap: 10px; }
  .score-row { flex: 1 1 auto; gap: 6px; }
  .pscore { display: flex; align-items: center; gap: 6px; border-bottom: none; padding-bottom: 0; }
  .pscore.acting { box-shadow: inset 0 -2px 0 var(--seat); }
  .pval { gap: 3px; }
  .score-row .score, .score-row.n3 .score, .score-row.n4 .score { font-size: 15px; }
  .shots, .score-row.n3 .shots, .score-row.n4 .shots { display: none; }
  .pname, .score-row.n3 .pname, .score-row.n4 .pname { font-size: 10px; max-width: 84px; }
  .score-row.n4 .pname { max-width: 62px; }
  .hpbar { height: 5px; margin-top: 0; flex: 1 1 34px; min-width: 24px; }
  .turnbox { flex: 0 0 auto; line-height: 1.1; }
  .turnlabel { font-size: 9.5px; margin-top: 0; }
  #dock { padding: 3px 8px calc(3px + env(safe-area-inset-bottom)); gap: 3px; }
  .weapon-strip { padding-bottom: 1px; gap: 5px; }
  /* Icons were too small to read at arm's length. Naively bumping .wi costs dock
     HEIGHT (the ammo count owns a whole row) and overflows the strip anyway, so
     instead: pin the ammo into the chip corner and drop the trajectory badge.
     Every weapon now flies the same arc except the railgun, so that badge says
     almost nothing in landscape — it survives in portrait. Measured: icon
     17 -> 26px (+53%), dock 83.5 -> 82.5px, and all 12 chips still fit a 667px
     phone with no swipe. */
  /* Shot-type/trajectory badge shown beside every icon (user request) — icon
     eases 26 -> 24px to pay for it; the strip scrolls a touch on a 667px phone. */
  .wchip { position: relative; min-width: 52px; padding: 3px 4px; border-radius: 10px; gap: 0; }
  .wchip .wi { width: 24px; height: 24px; }
  .wchip .wt { display: block; width: 20px; height: 10px; }
  .wchip .wn { display: none; }
  .wchip .wa {
    position: absolute; right: 3px; bottom: 0; font-size: 8.5px; line-height: 1;
    text-shadow: 0 1px 2px rgba(10,14,30,.95);
  }
  /* One row: angle · power · drive · fuel · drive · FIRE. Every flexible track is
     minmax(0, …fr) so the row is sized BY the dock instead of forcing the dock
     wider than the screen — with fixed-width tracks the FIRE button hung off the
     right edge on phones whose safe-area insets are wider than a width media
     query can see. The fuel gauge takes a smaller share than the aim readouts. */
  .control-rows {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto minmax(40px, .34fr) auto auto;
    gap: 6px; align-items: center; max-width: none; min-width: 0;
  }
  .aim-readout { display: contents; }
  .stepper, .drive, .fuel { min-width: 0; }
  .stepper { padding: 2px; }
  .mini { width: 30px; height: 30px; font-size: 15px; }
  .readout label { font-size: 8px; }
  .readout b { font-size: 13px; }
  .drive-row { display: contents; }
  .drive { width: 54px; height: 40px; font-size: 18px; }
  .fuel { height: 22px; }
  .fuel span { font-size: 9px; }
  .mute, .zbtn { width: 32px; height: 32px; font-size: 15px; border-radius: 9px; }
  /* Six buttons in one column ran past the bottom of a short landscape stage and
     disappeared under the dock. Two columns (zoom pair · tilt pair · pan pair)
     keep the whole set on the battlefield. */
  .zoomctl { top: 44px; display: grid; grid-template-columns: repeat(2, auto); gap: 5px; }
  /* .wchip .wn is hidden up here, so this popup is the ONLY place the weapon
     name is readable in landscape — keep it legible but compact. */
  .wpop { font-size: 11px; padding: 3px 8px; }
}

/* ==========================================================================
   TITLE SCREEN — LANDSCAPE (lobby only; the home dashboard sizes itself with
   vh-clamps further down and never scrolls)
   The lobby goes two-column here — invite beside roster/actions — and every
   size rides --vhu so the card NEVER outgrows a 375px-tall phone. Budgeted at
   375: head ~26 + grid ~230 (worst case: 4-seat FFA roster + 3 buttons) +
   paddings ≈ 300px. #lobby keeps overflow-y:auto purely as a safety net.
   ========================================================================== */
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  #lobby {
    padding: max(8px, env(safe-area-inset-top)) max(14px, env(safe-area-inset-right))
             max(8px, env(safe-area-inset-bottom)) max(14px, env(safe-area-inset-left));
  }
  .home-card.lobby-card {
    max-width: min(calc(94 * var(--vwu)), 720px);
    padding: calc(2.2 * var(--vhu)) calc(2.4 * var(--vwu));
    gap: calc(1.8 * var(--vhu));
  }
  .lb-head { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; }
  .lb-brand { text-align: left; }
  .lb-brand .logo.small { font-size: clamp(13px, calc(4 * var(--vhu)), 17px); }
  .lb-brand .byline { font-size: clamp(7.5px, calc(2.2 * var(--vhu)), 10px); }
  .lb-status h2 { font-size: clamp(13px, calc(3.8 * var(--vhu)), 17px); white-space: nowrap; }
  .lb-status .spinner { width: 17px; height: 17px; }
  .lb-grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: calc(2.6 * var(--vwu)); align-items: start; }
  .lb-invite { gap: calc(1.6 * var(--vhu)); }
  #lobbyHint { font-size: clamp(10px, calc(2.6 * var(--vhu)), 12.5px); }
  #lobby .code-display {
    font-size: clamp(24px, calc(9 * var(--vhu)), 40px);
    padding: calc(1.6 * var(--vhu)) 10px; padding-left: calc(10px + .3em);
  }
  .lobby-card .btn { padding: calc(1.8 * var(--vhu)) 10px; font-size: clamp(11px, calc(2.8 * var(--vhu)), 13.5px); }
  .lobby-card .btn.big { padding: calc(2.1 * var(--vhu)) 12px; font-size: clamp(12px, calc(3 * var(--vhu)), 15px); }
  .lobby-card .rp { padding: calc(1.3 * var(--vhu)) 10px; font-size: clamp(11px, calc(2.7 * var(--vhu)), 13px); }
}

/* ---------- Artillery Golf ---------- */
/* No driving in golf — your tank walks to your ball. */
body.golf .drive-row { display: none; }
body.golf .fuel { display: none; }
/* With the drive row gone the compact dock is angle · power · FIRE, and the
   six-track template left the drive/fuel tracks behind as dead space — the panel
   sat well left of centre. Size the three surviving controls to their content and
   CENTRE the group. max-content tracks still shrink when the screen is tight, so
   this cannot reintroduce an overflow. */
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  body.golf .control-rows {
    grid-template-columns: repeat(3, minmax(0, max-content));
    justify-content: center;
  }
}

/* ---------- Boss health bar ---------- */
#bossbar { display: flex; align-items: center; gap: 10px; padding: 2px 2px 0; }
#bossbar .bb-name { font-size: 12px; font-weight: 900; color: #ff5a52; letter-spacing: .08em; white-space: nowrap; }
#bossbar .bb-track { flex: 1; height: 11px; border-radius: 6px; background: #0e142b; border: 1px solid #552e33; overflow: hidden; }
#bossbar .bb-track i { display: block; height: 100%; width: 100%; background: linear-gradient(90deg, #ff3b30, #ff7a2e); transition: width .35s ease; }
#bossbar .bb-num { font-size: 11px; font-weight: 800; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
#bossbar.dead .bb-track i { background: #39424a; }

/* ---------- After-action report + loot ---------- */
#battleReport { margin-top: 10px; text-align: left; }
#battleReport .br-title { font-size: 11px; letter-spacing: .18em; color: var(--muted); margin-bottom: 6px; text-align: center; }
#battleReport .br-row { display: flex; gap: 10px; align-items: baseline; padding: 5px 10px; border-radius: 9px; background: var(--panel-2); border: 1px solid var(--line); margin-bottom: 5px; font-size: 13.5px; }
#battleReport .br-name { font-weight: 800; color: var(--seat, var(--text)); flex: 1; }
#battleReport .br-stat { color: var(--muted); font-variant-numeric: tabular-nums; }
#lootLine { margin: 6px 0 2px; font-size: 14.5px; color: #ffd23f; font-weight: 700; }

/* ---- Help modal --------------------------------------------------------- */
.howto {
  margin-top: 10px; padding: 7px 14px; border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.14); background: rgba(255,255,255,0.05);
  color: var(--ink-dim, #aeb9d6); font: inherit; font-size: 13px; cursor: pointer;
}
.howto:active { transform: translateY(1px); }
.help-card { max-width: 560px; width: min(calc(92 * var(--vwu)), 560px); max-height: calc(86 * var(--dvhu)); display: flex; flex-direction: column; }
.help-scroll { overflow-y: auto; text-align: left; margin: 10px 0 14px; padding-right: 6px; min-height: 0; }
.help-sec { margin-bottom: 16px; }
.help-sec h3 { margin: 0 0 6px; font-size: 13px; letter-spacing: .08em; text-transform: uppercase; color: var(--accent, #ff9d3d); }
.help-sec p, .help-sec li { font-size: 13.5px; line-height: 1.5; color: var(--ink-dim, #c5cde0); }
.help-sec ul { margin: 0; padding-left: 18px; }
.help-sec li { margin-bottom: 6px; }
.hw-row {
  display: grid; grid-template-columns: 30px minmax(90px, auto) 44px 1fr;
  gap: 8px; align-items: center; padding: 6px 0;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.hw-row:last-child { border-bottom: 0; }
.hw-ico svg { width: 26px; height: 26px; display: block; }
.hw-traj svg { width: 40px; height: 24px; display: block; }
.hw-name { font-weight: 700; font-size: 13px; }
.hw-name i { display: block; font-style: normal; font-weight: 400; font-size: 10.5px; color: #8a93a8; }
.hw-desc { font-size: 12.5px; line-height: 1.4; color: var(--ink-dim, #c5cde0); }

/* ---- Home dashboard 2.0 -------------------------------------------------------
   Three fixed bands (head / main / foot) sized with vh-clamps so the whole
   thing ALWAYS fits the viewport. #home never scrolls — that is the contract. */
#home { overflow: hidden; padding: 0; justify-content: center; }   /* dashboard sits CENTRED, not pinned to the top */
.hs {
  width: 100%; height: auto; max-height: 100%; min-height: 0;
  max-width: 1100px; margin: 0 auto;
  display: flex; flex-direction: column;
  gap: clamp(6px, calc(1.5 * var(--vhu)), 14px);
  padding: calc(env(safe-area-inset-top) + clamp(8px, calc(2 * var(--vhu)), 20px))
           max(clamp(10px, calc(3 * var(--vwu)), 28px), env(safe-area-inset-right))
           calc(env(safe-area-inset-bottom) + clamp(6px, calc(1.5 * var(--vhu)), 14px))
           max(clamp(10px, calc(3 * var(--vwu)), 28px), env(safe-area-inset-left));
}

/* Band 1: brand + identity */
.hs-head { display: flex; align-items: center; justify-content: space-between; gap: 10px 18px; flex-wrap: wrap; }
.hs-title { font-size: clamp(20px, calc(5.2 * var(--vhu)), 40px); justify-content: flex-start; }
.hs-by { margin: 2px 0 0; font-size: clamp(8px, calc(1.3 * var(--vhu)), 11px); color: var(--muted); text-transform: uppercase; letter-spacing: .26em; }
.hs-by b { color: var(--primary); font-weight: 800; }
.hs-id { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.hs-cs {
  display: flex; align-items: center; gap: 8px;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px;
  padding: clamp(4px, calc(0.9 * var(--vhu)), 8px) 10px;
}
.hs-cs:focus-within { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(84,200,255,.22); }
.hs-cs-label { font-size: 10px; text-transform: uppercase; letter-spacing: .18em; color: var(--muted); }
.hs-cs input { border: 0; background: transparent; padding: 2px 0; width: clamp(110px, calc(16 * var(--vwu)), 170px); font-weight: 700; font-size: clamp(13px, calc(1.9 * var(--vhu)), 16px); }
.hs-cs input:focus { outline: none; }
.hs-reroll { border: 0; background: transparent; color: var(--accent); width: 26px; height: 26px; padding: 2px; cursor: pointer; }
.hs-reroll svg { width: 100%; height: 100%; }
.hs-help {
  display: flex; align-items: center; gap: 7px;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  border-radius: 12px; padding: clamp(5px, calc(1 * var(--vhu)), 9px) 12px; font-weight: 700;
  font-size: clamp(11px, calc(1.7 * var(--vhu)), 14px); cursor: pointer;
}
.hs-help svg { width: 17px; height: 17px; color: var(--accent); }

/* Band 2: the two action columns */
.hs-main {
  flex: 1; min-height: 0;
  display: grid; grid-template-columns: 1fr 1fr; gap: clamp(8px, calc(1.6 * var(--vwu)), 16px);
  align-content: stretch;
}
.hs-col { display: flex; flex-direction: column; gap: clamp(6px, calc(1.4 * var(--vhu)), 12px); min-height: 0; min-width: 0; }
.hs-col-join { justify-content: center; }   /* the lone Join panel sits centred, not stranded at the top */
.hs-quick {
  display: flex; align-items: center; gap: 12px; text-align: left;
  border: 0; border-radius: 16px; cursor: pointer; color: #2b1002;
  background: linear-gradient(160deg, #ffb056 0%, #ff7a2e 55%, #f0561d 100%);
  box-shadow: 0 8px 22px rgba(240, 96, 30, .35);
  padding: clamp(10px, calc(2.2 * var(--vhu)), 18px) clamp(12px, calc(1.6 * var(--vwu)), 18px);
}
.hs-quick:active { transform: translateY(1px); }
.hs-quick-ico { flex: 0 0 auto; width: clamp(26px, calc(4.6 * var(--vhu)), 38px); height: clamp(26px, calc(4.6 * var(--vhu)), 38px); border-radius: 10px; background: rgba(255,255,255,.28); display: grid; place-items: center; }
.hs-quick-ico svg { width: 70%; height: 70%; }
.hs-quick-txt b { display: block; font-size: clamp(14px, calc(2.6 * var(--vhu)), 20px); font-weight: 900; letter-spacing: .02em; }
.hs-quick-txt i { display: block; font-style: normal; font-size: clamp(10px, calc(1.6 * var(--vhu)), 12.5px); opacity: .85; }
.hs-panel {
  background: rgba(20, 27, 51, .78); border: 1px solid var(--line); border-radius: 16px;
  padding: clamp(8px, calc(1.6 * var(--vhu)), 14px); display: flex; flex-direction: column; gap: clamp(6px, calc(1.2 * var(--vhu)), 10px);
  min-height: 0;
}
.hs-panel-head { display: flex; align-items: center; gap: 8px; font-weight: 800; font-size: clamp(12px, calc(1.9 * var(--vhu)), 15px); }
.hs-panel-head svg { width: clamp(15px, calc(2.4 * var(--vhu)), 19px); height: clamp(15px, calc(2.4 * var(--vhu)), 19px); color: var(--accent); flex: 0 0 auto; }
.hs-panel-head i { font-style: normal; font-weight: 500; font-size: clamp(9px, calc(1.4 * var(--vhu)), 11.5px); color: var(--muted); margin-left: auto; }
.hs-row { display: flex; align-items: center; gap: 8px; }
.hs-row .diffrow { flex: 1; display: flex; gap: 6px; }
.hs-row .diff { flex: 1; }
.hs-go {
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  font-weight: 800; font-size: clamp(12px, calc(1.8 * var(--vhu)), 14px);
  border-radius: 11px; padding: clamp(6px, calc(1.3 * var(--vhu)), 10px) 16px; cursor: pointer;
}
.hs-go.primary { background: var(--accent); border-color: var(--accent); color: #0a1020; }
.hs-go:active { transform: translateY(1px); }
.hs-create { flex: 1; }
.modegrid {
  /* Flex-wrap (not a fixed grid) so the final row of modes CENTRES under the
     first — with 5 modes that keeps the layout balanced instead of leaving an
     empty grid cell. Three per row via a 1/3 basis; grow disabled so the last
     row stays the same tile size, just centred. */
  display: flex; flex-wrap: wrap; justify-content: center; align-content: start;
  gap: clamp(5px, calc(1 * var(--vhu)), 8px);
  min-height: 0;
}
.modegrid .mode { flex: 0 0 calc(33.333% - 8px); }
.modegrid .mode {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: clamp(2px, calc(0.7 * var(--vhu)), 6px);
  padding: clamp(5px, calc(1.3 * var(--vhu)), 11px) 4px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  font-weight: 700; font-size: clamp(9.5px, calc(1.5 * var(--vhu)), 12.5px); cursor: pointer;
}
.modegrid .mode svg { width: clamp(16px, calc(3 * var(--vhu)), 24px); height: clamp(16px, calc(3 * var(--vhu)), 24px); }
.modegrid .mode.active { color: #0a1020; background: var(--accent); border-color: var(--accent); }
#countRow { display: flex; gap: 6px; }
#countRow.hidden { display: none; }
#countRow .cnt { flex: 1; }
#codeInput.code-input { flex: 1; min-width: 0; text-align: center; letter-spacing: .4em; font-weight: 800; }

/* Band 3: kit strip */
.hs-foot { display: flex; align-items: center; gap: clamp(6px, calc(1 * var(--vwu)), 12px); flex-wrap: wrap; }
.hs-chip {
  display: flex; align-items: center; gap: 8px;
  background: rgba(20, 27, 51, .78); border: 1px solid var(--line); border-radius: 999px;
  padding: clamp(4px, calc(0.9 * var(--vhu)), 7px) 12px; color: var(--text);
  font-size: clamp(10px, calc(1.5 * var(--vhu)), 12px); min-height: clamp(28px, calc(4.6 * var(--vhu)), 38px);
}
.hs-chip > span { color: var(--muted); text-transform: uppercase; letter-spacing: .14em; font-size: clamp(8.5px, calc(1.3 * var(--vhu)), 10px); }
.hs-armoury { cursor: pointer; font-weight: 800; }
.hs-armoury svg { width: 17px; height: 17px; color: var(--primary); }
.hs-armoury b { color: var(--accent); font-weight: 800; }
.hs-error { margin: 0 0 0 auto; }
/* The privacy link — the app's only anchor, required in-app by App Store
   5.1.1(i). Pushed to the end of the footer row so it reads as fine print
   without competing with Career or the paint picker. The 44px min tap target
   is the platform minimum; the text itself is smaller than that. */
.hs-legal { margin-left: auto; }
.hs-legal a {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px;
  color: var(--muted); font-size: clamp(10px, calc(1.5 * var(--vhu)), 12px);
  font-weight: 600; text-decoration: underline; text-underline-offset: 3px;
}
.hs-legal a:hover, .hs-legal a:focus-visible { color: var(--text); }
.hs-foot .skinrow { display: flex; gap: 5px; }
.hs-foot .skinrow .skin { width: clamp(18px, calc(3.4 * var(--vhu)), 26px); height: clamp(18px, calc(3.4 * var(--vhu)), 26px); }

/* Narrow / portrait: stack the columns; everything stays inside the viewport
   because the bands share the height budget and panels compress via clamps. */
@media (orientation: landscape) and (max-width: 640px), (orientation: portrait) and (max-height: 640px) {
  .hs-main { grid-template-columns: 1fr; overflow: hidden; }
  .hs-title { font-size: clamp(19px, calc(3.4 * var(--vhu)), 30px); }
  .hs-quick-txt i { display: none; }
  .modegrid .mode { flex-direction: row; justify-content: flex-start; padding-left: 9px; gap: 7px; }
  .hs-foot { gap: 5px; }
}
/* Very short landscape phones: tighten the brand row so the panels get room. */
@media (orientation: landscape) and (max-height: 430px), (orientation: portrait) and (max-width: 430px) {
  .hs-title { font-size: clamp(17px, calc(4.6 * var(--vhu)), 24px); }
  .hs-by { display: none; }
  .hs-quick-txt i { display: none; }
  .hs-panel-head i { display: none; }
}

/* ---- Armoury modal ---- */
.arm-sub { text-align: left; margin: 3px 0 7px; font-size: clamp(10.5px, calc(1.7 * var(--vhu)), 12.5px); line-height: 1.4; }
.arm-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: clamp(4px, calc(1 * var(--vhu)), 7px);
  margin-bottom: 10px;
}
.arm-cell {
  display: flex; align-items: center; gap: 8px; text-align: left;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  border-radius: 11px; padding: 7px 9px; cursor: pointer; font-weight: 700; font-size: 12px;
}
.arm-cell svg { width: 22px; height: 22px; flex: 0 0 auto; }
.arm-cell i { display: none; }
.arm-cell.picked { border-color: var(--accent); background: rgba(84, 200, 255, .16); box-shadow: inset 0 0 0 1px var(--accent); }
.arm-cell.dim { opacity: .45; }
.arm-status { font-size: 12px; color: var(--muted); margin-bottom: 7px; }
.arm-status.ready { color: #3ce88f; }

/* FIRE button flame */

/* mute button icon */
.mute svg { width: 20px; height: 20px; display: block; margin: auto; }

/* Inline UI glyph sizing (battle report, spoils, boss bar, skin locks) */
.br-stat svg { width: 12px; height: 12px; vertical-align: -1.5px; margin-right: 2px; }
#lootLine svg { width: 14px; height: 14px; vertical-align: -2px; margin-right: 3px; }
#bossbar .bb-name svg { width: 14px; height: 14px; vertical-align: -2.5px; margin-right: 2px; }
.skin .lock svg { width: 13px; height: 13px; display: block; margin: auto; color: #dfe6f2; }
.drive svg { width: 22px; height: 22px; }

/* tee-set chips share the countrow look */
#teeRow { display: flex; gap: 6px; }
#teeRow.hidden { display: none; }
#teeRow .cnt { flex: 1; font-size: clamp(10px, calc(1.5 * var(--vhu)), 12px); padding: 6px 0; }

/* ---- Dashboard menu screens: whole screen, no scrolling, ever ------------- */
.menu-card {
  max-width: 640px; width: min(calc(94 * var(--vwu)), 640px); max-height: calc(92 * var(--dvhu));
  display: flex; flex-direction: column; overflow: hidden;
}
.menu-card .result { flex: 0 0 auto; font-size: clamp(20px, calc(3.4 * var(--vhu)), 28px); }
/* The action button ALWAYS survives a tight landscape screen: panes SCROLL
   inside themselves (stats, challenges, how-to-play are all browsable), the
   button never moves. */
.menu-card > .btn { flex: 0 0 auto; }
.menu-card .tabpane, .menu-card .career-wrap { min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
/* Landscape: the help/career cards use the width a sideways phone actually has,
   so diagrams and rows breathe instead of cramping. */
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  .menu-card { max-width: 780px; width: min(calc(96 * var(--vwu)), 780px); }
}
.tabrow { display: flex; gap: 6px; margin: 8px 0 10px; }
.tab {
  flex: 1; border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  border-radius: 10px; padding: clamp(5px, calc(1.2 * var(--vhu)), 9px) 0; font-weight: 800;
  font-size: clamp(11px, calc(1.7 * var(--vhu)), 13px); cursor: pointer;
}
.tab.active { color: #0a1020; background: var(--accent); border-color: var(--accent); }
.tabpane { display: none; min-height: 0; }
.tabpane.active { display: block; }

/* Basics: three teaching diagrams */
/* Basics: the three taught gestures as roomy cards, then glyph'd quick facts.
   Every figure is hand-drawn inline SVG (house rule — no emojis, ever). */
.hb-figs { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(6px, calc(1.2 * var(--vwu)), 12px); margin-bottom: clamp(7px, calc(1.6 * var(--vhu)), 14px); }
.hb-fig { margin: 0; background: var(--panel-2); border: 1px solid var(--line); border-radius: 13px; padding: clamp(6px, calc(1.3 * var(--vhu)), 10px); }
.hb-fig svg { width: 100%; max-width: 190px; height: auto; margin: 0 auto; display: block; }
.hb-fig figcaption { margin-top: clamp(4px, calc(1 * var(--vhu)), 8px); text-align: left; }
.hb-fig figcaption b { display: block; color: var(--text); font-size: clamp(11px, calc(1.8 * var(--vhu)), 13.5px); margin-bottom: 2px; }
.hb-fig figcaption span { display: block; font-size: clamp(9.5px, calc(1.5 * var(--vhu)), 11.5px); line-height: 1.4; color: var(--muted); }
.hb-facts { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(5px, calc(1 * var(--vwu)), 9px); }
.hb-fact {
  display: flex; gap: 9px; align-items: flex-start; text-align: left;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 11px;
  padding: clamp(6px, calc(1.3 * var(--vhu)), 9px) clamp(8px, calc(1.6 * var(--vwu)), 11px);
}
.hb-fact > svg { width: clamp(18px, calc(3 * var(--vhu)), 22px); height: clamp(18px, calc(3 * var(--vhu)), 22px); flex: 0 0 auto; color: var(--accent); margin-top: 1px; }
.hb-fact b { display: block; font-size: clamp(10.5px, calc(1.7 * var(--vhu)), 12.5px); margin-bottom: 1px; }
.hb-fact span { display: block; font-size: clamp(9.5px, calc(1.5 * var(--vhu)), 11px); line-height: 1.4; color: var(--muted); }

/* Arsenal: compact cells + one live detail line */
/* Arsenal: one self-explaining row per round — icon | name + ammo + what it
   does | flight-shape badge. The pane scrolls; nothing hides behind a tap. */
.hw-lead { margin: 0 0 clamp(5px, calc(1.2 * var(--vhu)), 9px); font-size: clamp(10px, calc(1.6 * var(--vhu)), 12px); color: var(--muted); text-align: left; }
.hw-list { display: flex; flex-direction: column; gap: clamp(4px, calc(0.9 * var(--vhu)), 6px); }
.hw-row {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: clamp(8px, calc(1.6 * var(--vwu)), 12px);
  align-items: center; text-align: left;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 11px;
  padding: clamp(5px, calc(1.2 * var(--vhu)), 8px) clamp(8px, calc(1.6 * var(--vwu)), 12px);
}
.hw-row > svg:first-child { width: clamp(22px, calc(3.6 * var(--vhu)), 27px); height: clamp(22px, calc(3.6 * var(--vhu)), 27px); }
.hw-row > svg:last-child { width: clamp(26px, calc(4.2 * var(--vhu)), 32px); height: clamp(15px, calc(2.5 * var(--vhu)), 19px); opacity: .9; }
.hw-top { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.hw-nm { font-size: clamp(11px, calc(1.8 * var(--vhu)), 13.5px); font-weight: 800; white-space: nowrap; }
.hw-note {
  font-style: normal; font-size: clamp(8.5px, calc(1.35 * var(--vhu)), 10px); font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--accent); white-space: nowrap;
}
.hw-desc { margin: 1px 0 0; font-size: clamp(9.5px, calc(1.5 * var(--vhu)), 11.5px); line-height: 1.35; color: var(--muted); }
/* Modes: a card per mode — the home screen's own icon, a player-count chip,
   and the goal in one line you can actually skim. */
.hm-cards { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(5px, calc(1 * var(--vwu)), 9px); }
.hm-cards .hm-card:first-child { grid-column: 1 / -1; }
.hm-card {
  display: flex; gap: 10px; align-items: flex-start; text-align: left;
  background: var(--panel-2); border: 1px solid var(--line); border-radius: 12px;
  padding: clamp(7px, calc(1.4 * var(--vhu)), 10px) clamp(9px, calc(1.8 * var(--vwu)), 12px);
}
.hm-card > svg { width: clamp(20px, calc(3.3 * var(--vhu)), 24px); height: clamp(20px, calc(3.3 * var(--vhu)), 24px); flex: 0 0 auto; color: var(--accent); margin-top: 1px; }
.hm-top { display: flex; align-items: baseline; gap: 8px; }
.hm-top b { font-size: clamp(11.5px, calc(1.9 * var(--vhu)), 14px); }
.hm-top i {
  font-style: normal; font-size: clamp(8.5px, calc(1.35 * var(--vhu)), 10px); font-weight: 800;
  letter-spacing: .07em; text-transform: uppercase; color: var(--accent);
  background: rgba(84,200,255,.1); border: 1px solid rgba(84,200,255,.35); border-radius: 999px;
  padding: 1px 7px; white-space: nowrap;
}
.hm-txt span { display: block; margin-top: 2px; font-size: clamp(9.5px, calc(1.5 * var(--vhu)), 11.5px); line-height: 1.4; color: var(--muted); }

/* Career */
.career-wrap { margin: 6px 0 12px; min-height: 0; }
#careerModal .tabpane { margin-bottom: 10px; }
#careerModal .car-stats { column-count: 2; column-gap: 18px; }
.cs-row { display: flex; justify-content: space-between; gap: 10px; padding: clamp(2px, calc(0.55 * var(--vhu)), 4.5px) 0; border-bottom: 1px solid rgba(255,255,255,.05); font-size: clamp(9.5px, calc(1.5 * var(--vhu)), 12px); }
.cs-row span { color: var(--muted); }
.cs-row b { color: var(--text); }
.cs-sep { border-top: 1px solid var(--line); margin-top: 4px; padding-top: 7px; }
.car-achs { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(3px, calc(0.7 * var(--vhu)), 6px); align-content: start; }
@media (orientation: landscape) and (max-width: 700px), (orientation: portrait) and (max-height: 700px) { .car-achs { grid-template-columns: repeat(2, 1fr); } }
.ach { display: flex; align-items: center; gap: 7px; border: 1px solid var(--line); border-radius: 8px; padding: clamp(2px, calc(0.6 * var(--vhu)), 5px) 8px; opacity: .45; }
.ach-txt { min-width: 0; text-align: left; }
.ach-txt b { display: block; font-size: clamp(8.5px, calc(1.4 * var(--vhu)), 11px); }
.ach-txt i { display: block; font-style: normal; font-size: clamp(7.5px, calc(1.2 * var(--vhu)), 9.5px); line-height: 1.25; color: var(--muted); }
.ach.got { opacity: 1; border-color: rgba(255, 210, 63, .5); background: rgba(255, 210, 63, .08); }
.ach-ic svg { width: clamp(10px, calc(1.8 * var(--vhu)), 14px); height: clamp(10px, calc(1.8 * var(--vhu)), 14px); display: block; color: #ffd23f; }
.ach .ach-ic svg { color: #6b7488; }
.ach.got .ach-ic svg { color: #ffd23f; }
.ach-nm { font-size: clamp(8px, calc(1.35 * var(--vhu)), 10.5px); font-weight: 700; }

/* Share row on the game-over card */
.share-row { display: flex; gap: 8px; justify-content: center; margin: 2px 0 10px; flex-wrap: wrap; }
.share-row .btn { display: flex; align-items: center; gap: 7px; font-size: 13px; padding: 9px 14px; }
.share-row .btn svg { width: 16px; height: 16px; }
.share-row .btn.hidden { display: none; }

/* Native selects, dashboard-styled */
.hs-selwrap { display: flex; align-items: center; gap: 7px; flex: 1; min-width: 0; }
.hs-selwrap.hidden { display: none; }
.hs-selwrap > span { font-size: clamp(8.5px, calc(1.3 * var(--vhu)), 10px); text-transform: uppercase; letter-spacing: .14em; color: var(--muted); flex: 0 0 auto; }
.hs-select {
  flex: 1; min-width: 0; appearance: none; -webkit-appearance: none;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  font: inherit; font-weight: 700; font-size: clamp(11px, calc(1.7 * var(--vhu)), 13.5px);
  border-radius: 10px; padding: clamp(5px, calc(1.1 * var(--vhu)), 9px) 30px clamp(5px, calc(1.1 * var(--vhu)), 9px) 11px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2354c8ff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat: no-repeat; background-position: right 9px center; background-size: 13px;
  cursor: pointer;
}
.hs-select:focus { outline: 2px solid var(--accent); }

/* Opponent = two real buttons (a segmented toggle), not a dropdown. */
.hs-oppbtns { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.hs-oppbtns.hidden { display: none; }
.hs-oppbtns .opp {
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  font-weight: 700; font-size: clamp(10px, calc(1.55 * var(--vhu)), 13px);
  border-radius: 11px; padding: clamp(6px, calc(1.3 * var(--vhu)), 10px) 8px; cursor: pointer;
  min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hs-oppbtns .opp.active { color: #0a1020; background: var(--accent); border-color: var(--accent); }
.hs-oppbtns .opp:active { transform: translateY(1px); }

/* Custom in-game dropdown — a game-styled menu built over a hidden native
   <select> (the select stays the source of truth, so every existing .value /
   .onchange keeps working). Opens UPWARD over the mode grid so it never
   collides with the CREATE button or the panel's bottom edge. */
.gsel-native { display: none !important; }
.gsel { position: relative; flex: 1; min-width: 0; }
.gsel-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 6px;
  border: 1px solid var(--line); background: var(--panel-2); color: var(--text);
  font: inherit; font-weight: 700; font-size: clamp(11px, calc(1.7 * var(--vhu)), 13.5px);
  border-radius: 10px; padding: clamp(5px, calc(1.1 * var(--vhu)), 9px) 11px; cursor: pointer;
}
.gsel-btn .gsel-cur { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gsel-btn svg { width: 13px; height: 13px; color: var(--accent); flex: 0 0 auto; transition: transform .15s ease; }
.gsel.open .gsel-btn svg { transform: rotate(180deg); }
.gsel-list {
  position: absolute; left: 0; right: 0; bottom: calc(100% + 5px);
  background: var(--panel); border: 1px solid var(--line); border-radius: 11px;
  box-shadow: 0 12px 34px rgba(0,0,0,.55); padding: 5px; z-index: 60;
  /* Effective unit, not raw dvh: under the portrait rotation shim a raw dvh
     measures the wrong axis, so this dropdown could grow past the screen. */
  display: none; max-height: calc(46 * var(--dvhu)); overflow-y: auto; overscroll-behavior: contain;
}
.gsel.open .gsel-list { display: block; }
.gsel-opt {
  display: block; width: 100%; text-align: left; border: 0; background: transparent; color: var(--text);
  font: inherit; font-weight: 600; font-size: clamp(11px, calc(1.7 * var(--vhu)), 13.5px);
  padding: clamp(6px, calc(1.3 * var(--vhu)), 9px) 10px; border-radius: 8px; cursor: pointer;
}
.gsel-opt:hover, .gsel-opt:focus { background: var(--panel-2); outline: none; }
.gsel-opt.sel { color: var(--accent); font-weight: 800; }
/* An open dropdown must escape the narrow-mode overflow clip on .hs-main. */
body.dd-open .hs-main { overflow: visible; }

/* ---- Drum sliders (angle / power) ----------------------------------------- */
.drum-wrap { min-width: 0; flex: 1 1 auto; }
/* Fixed CELL geometry: every cell has a SET width (tabular digits included), so
   the value never breathes or shifts while you roll through it. The drum ITSELF
   is FLUID — it takes whatever the stepper can spare up to 170px and clips ghost
   neighbours symmetrically (centred + overflow:hidden). A fixed drum width made
   the one-row dock wider than the screen on any phone whose safe-area insets ate
   more than the width tiers below assumed, and the FIRE button fell off the edge. */
.drum {
  display: flex; align-items: center; justify-content: center; gap: 2px;
  width: 100%; min-width: 58px; max-width: 170px;
  touch-action: none; cursor: ew-resize; user-select: none;
  overflow: hidden; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.stepper .mini { flex: 0 0 auto; }      /* squeeze the drum, never the tap targets */
.drum .dc {
  flex: 0 0 18px; width: 18px; overflow: hidden; text-align: center;
  font-size: 10.5px; font-weight: 600; color: var(--muted); pointer-events: auto;
}
.drum .dc.cur {
  flex: 0 0 48px; width: 48px; font-size: clamp(15px, calc(2.6 * var(--vhu)), 18px); font-weight: 900; color: var(--text);
}
@media (orientation: landscape) and (max-width: 700px), (orientation: portrait) and (max-height: 700px) {
  .drum { max-width: 128px; }
  .drum .dc { flex: 0 0 13px; width: 13px; font-size: 8.5px; }
  .drum .dc.cur { flex: 0 0 36px; width: 36px; }
}

/* The primary action of the whole dashboard: CREATE GAME — big, and the
   app's victory green rather than another blue chip. */
#createBtn {
  /* flex-basis auto, never 100%: inside the panel's COLUMN flex, a 100% basis
     makes the button claim the panel's full height and ride over its
     neighbours. Prominent, but strictly its own row. */
  flex: 0 0 auto; width: 100%;
  padding: clamp(9px, calc(1.9 * var(--vhu)), 14px) 16px;
  font-size: clamp(13px, calc(2.2 * var(--vhu)), 17px); font-weight: 900; letter-spacing: .03em;
  color: #06180e; border: 0; border-radius: 13px;
  background: linear-gradient(160deg, #52f0a2 0%, #3ce88f 45%, #1fae66 100%);
  box-shadow: 0 4px 14px rgba(60, 232, 143, .28);
}
#createBtn:active { transform: translateY(1px); }

/* ---- Draft screen: 12 weapons in two short rows on landscape so the SAVE
   button always has room; portrait stacks 3-wide. ---- */
.arm-card { max-width: 720px; width: min(calc(96 * var(--vwu)), 720px); }
.arm-card .arm-grid { grid-template-columns: repeat(6, 1fr); }
.arm-card .arm-cell { flex-direction: column; text-align: center; gap: 3px; padding: clamp(4px, calc(1 * var(--vhu)), 8px) 4px; font-size: clamp(8.5px, calc(1.5 * var(--vhu)), 11px); }
.arm-card .arm-cell svg { width: clamp(15px, calc(3 * var(--vhu)), 22px); height: clamp(15px, calc(3 * var(--vhu)), 22px); }
.arm-card .result { font-size: clamp(19px, calc(3.6 * var(--vhu)), 30px); }

/* ---- Aim controls: proper touch targets — taller drums, taller buttons ---- */
.stepper { padding: 5px; }
.mini { width: 42px; height: 43px; font-size: 19px; }
.drum { min-height: 41px; align-items: center; }
.drum .dc.cur { font-size: clamp(17px, calc(3 * var(--vhu)), 21px); }
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  .mini { width: 34px; height: 38px; font-size: 16px; }
  .drum { min-height: 36px; }
  /* The one-row dock is all fixed-width pieces: at ~844px wide it totalled
     846px. Slimmer gaps + side padding keep every control INSIDE the screen. */
  #dock { gap: 5px; padding-left: 8px; padding-right: 8px; }
  .control-rows { gap: 5px; }
}

/* Compact dock: the FIRE button and fuel bar fill their row's full height —
   no dead strip under the controls. */
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  .control-rows .fire { align-self: center; }   /* a fixed square must never stretch */
  .control-rows .stepper { align-self: stretch; }
}

/* Narrow-phone dock tier (iPhone SE etc): every control must fit INSIDE the
   screen. Same one-row layout, each piece a notch tighter than the <=600px
   effective-height tier so the row totals ~640px, not ~760. Portrait twin
   phrased on effective axes per the rotation shim. */
@media (orientation: landscape) and (max-width: 830px), (orientation: portrait) and (max-height: 830px) {
  #dock { gap: 4px; padding-left: 8px; padding-right: 8px; }
  .control-rows { gap: 4px; }
  .mini { width: 28px; height: 36px; font-size: 14px; }
  .drum { max-width: 112px; }
  .drum .dc { flex: 0 0 11px; width: 11px; font-size: 8px; }
  .drum .dc.cur { flex: 0 0 32px; width: 32px; }
  .drive { width: 46px; height: 38px; font-size: 16px; }
}

/* ---- Golf scorecard (on-screen button + end-of-round summary) ------------- */
.gcard { max-width: 760px; width: min(calc(97 * var(--vwu)), 760px); }
.gc-scroll { min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; margin: 4px 0 12px; }
.gc-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.gc-table th, .gc-table td {
  padding: clamp(3px, calc(0.9 * var(--vhu)), 7px) clamp(3px, calc(0.7 * var(--vwu)), 9px);
  text-align: center; font-size: clamp(10px, calc(1.6 * var(--vhu)), 13px);
  border-bottom: 1px solid var(--line);
}
.gc-table thead th { color: var(--muted); font-weight: 800; letter-spacing: .04em; }
.gc-table .gc-head { text-align: left; color: var(--muted); font-weight: 800; text-transform: uppercase; letter-spacing: .08em; white-space: nowrap; }
.gc-table .gc-name { text-align: left; font-weight: 800; white-space: nowrap; }
.gc-table .gc-name i { display: inline-block; width: 9px; height: 9px; border-radius: 3px; background: var(--seat, var(--accent)); margin-right: 7px; vertical-align: -1px; }
.gc-table tr.gc-parrow td, .gc-table tr.gc-parrow .gc-head { color: var(--muted); font-weight: 700; }
.gc-table .gc-sep { border-left: 1px solid var(--line); }
.gc-table .gc-tot { font-weight: 900; }
.gc-table .gc-vs { font-weight: 900; }
.gc-table td.gc-now { background: rgba(84, 200, 255, .14); }
.gc-table td.gc-under { color: #3ce88f; }
.gc-table td.gc-over { color: #ffb45a; }
.gc-vs.up { color: #ffb45a; }
.gc-vs.down { color: #3ce88f; }

/* ---- Dock collapse ---------------------------------------------------------
   The dock slides down to a sliver that keeps only FIRE and a live aim
   readout. The SLIDE is a transform (cheap); once it lands, the same offset is
   handed to a negative margin so the layout actually reclaims the space and
   the battlefield grows into it (the draw loop re-sizes the canvas on its own
   when the box changes). Both states put the dock in the identical place, so
   the swap is invisible. */
#dock { --dock-sliver: 28px; }
#dock.dock-anim { transition: transform .18s ease; will-change: transform; }
#dock.collapsed { margin-bottom: calc(-1 * var(--dock-slide, 0px)); }
/* The tab rides the dock's top edge, so it is grabbable in either state.
   OPEN it is a quiet chevron pill; COLLAPSED it grows a CONTROLS label, takes
   the accent colour and beckons twice — the controls start hidden every match,
   so this tab is how a new player discovers them (Jordan: 'make the toggle
   more obvious'). */
.dock-tab {
  position: absolute; top: -19px; left: 50%; transform: translateX(-50%);
  min-width: 62px; height: 22px; padding: 0 10px; z-index: 6; cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  border: 1px solid var(--line); border-bottom: 0;
  border-radius: 11px 11px 0 0; background: rgba(10,14,30,.86);
  color: var(--muted); backdrop-filter: blur(6px);
  font: 800 10px/1 system-ui, -apple-system, sans-serif; letter-spacing: .14em;
}
.dock-tab svg { width: 17px; height: 17px; flex: 0 0 auto; transition: transform .18s ease; }
/* The chevron points where a tap takes you: dock OPEN = down (collapse),
   dock TUCKED = up — and it gently beckons upward, a two-nudge 'come on up'
   gesture inviting the tap (Jordan, 8.22). */
#dock:not(.collapsed) .dock-tab svg { transform: rotate(180deg); }
/* NB: dtBeckon (below) is the TAB's glow pulse from 8.16 — the chevron's
   nudge needs its own name or the later keyframes definition swallows it. */
#dock.collapsed .dock-tab svg { animation: dtNudgeUp 2.2s ease-in-out infinite; }
@keyframes dtNudgeUp {
  0%, 52%, 100% { transform: translateY(0); }
  12% { transform: translateY(-2.5px); }
  26% { transform: translateY(0); }
  38% { transform: translateY(-2.5px); }
}
@media (prefers-reduced-motion: reduce) {
  #dock.collapsed .dock-tab svg { animation: none; }
}
.dock-tab .dt-label { display: none; }
#dock.collapsed .dock-tab {
  height: 26px; top: -25px; padding: 0 14px;
  color: #0a1020; background: var(--accent); border-color: var(--accent);
  animation: dtBeckon 2s ease-in-out 2;
}
#dock.collapsed .dock-tab .dt-label { display: inline; }
@keyframes dtBeckon {
  0%, 100% { box-shadow: 0 0 0 0 rgba(84,200,255,0); }
  50%      { box-shadow: 0 0 16px 3px rgba(84,200,255,.6); }
}
.dock-tab:active { color: var(--text); }
#dock.collapsed .dock-tab:active { color: #0a1020; filter: brightness(1.12); }
/* Sliver contents: hidden while open, and the ONLY things on show when shut. */
.dock-mini { display: none; }
#dock.collapsed .dock-mini {
  display: flex; align-items: center; gap: clamp(8px, calc(1.6 * var(--vwu)), 16px);
  position: absolute; left: 12px; top: 0; height: var(--dock-sliver);
  color: var(--text); pointer-events: none;
}
/* The selected weapon anchors the LEFT end of the sliver — icon + name + ammo
   — so a tucked dock never hides what's loaded (Jordan, 8.22). */
.dock-mini .dm-ic { width: clamp(16px, calc(2.6 * var(--vhu)), 21px); height: clamp(16px, calc(2.6 * var(--vhu)), 21px); display: flex; flex: 0 0 auto; }
.dock-mini .dm-ic svg { width: 100%; height: 100%; }
.dock-mini .dm-wep {
  font-weight: 800; font-size: clamp(10.5px, calc(1.7 * var(--vhu)), 13px);
  max-width: calc(34 * var(--vwu)); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dock-mini .dm-ammo { font-weight: 700; font-size: clamp(9px, calc(1.4 * var(--vhu)), 11px); color: var(--muted); font-variant-numeric: tabular-nums; }
.dock-mini .dm-aim { display: flex; align-items: baseline; gap: 3px; font-variant-numeric: tabular-nums; }
.dock-mini .dm-aim b { font-size: clamp(11px, calc(1.8 * var(--vhu)), 14px); font-weight: 900; }
.dock-mini .dm-aim i {
  font-style: normal; font-size: clamp(7.5px, calc(1.2 * var(--vhu)), 9.5px);
  letter-spacing: .1em; color: var(--muted);
}
/* Everything except FIRE leaves with the dock. visibility (not display) so no
   reflow, and so the compact grid keeps its shape for the ride back up. */
#dock.collapsed .weapon-strip,
#dock.collapsed .stepper,
#dock.collapsed .drive-row,
#dock.collapsed .drive,
#dock.collapsed .fuel { visibility: hidden; }
/* Collapsed: the button overhangs the 28px sliver upward (like the collapse
   tab) so it costs no layout height. Only --fs and placement here — every
   dimension inside the object follows --fs on its own. */
#dock.collapsed .control-rows .fire {
  --fs: 96px;
  visibility: visible; position: absolute; right: 6px; z-index: 6; align-self: auto;
  top: calc(var(--dock-sliver) - (0.708 * var(--fs)) - ((var(--fs) - (0.708 * var(--fs))) / 2) - 2px);
}

/* ---- Watching: fade the HUD down while the shot flies / on the other turn ---
   Purely visual — the controls KEEP pointer-events so you can still zoom and
   pan to follow the shell, and any touch or hover brings them straight back.
   The killcam rule above is stronger and still wins. */
#game.watching #hud-top, #game.watching #dock { opacity: .16; }
#game.watching .mute, #game.watching .leave,
#game.watching .zoomctl, #game.watching .metamenu { opacity: .16; }
#game.watching.hud-wake #hud-top, #game.watching.hud-wake #dock,
#game.watching.hud-wake .mute, #game.watching.hud-wake .leave,
#game.watching.hud-wake .zoomctl, #game.watching.hud-wake .metamenu { opacity: 1; }

/* ===== FIRE BUTTON — H05 "Lit ring" ==================================
   Camera above and in front: every horizontal circle is an ellipse
   foreshortened to 0.62 of its width. One key light from the upper left
   drives the face gradient, the specular, the sheen, the rim light and
   both shadows. Footprint --fs x --fs; the VISIBLE object is --fs wide by
   0.708--fs tall, centred vertically, and the cast shadow reaches a little
   past the bottom and right — so no ancestor may set overflow:hidden.

   TWO SCALES: percentages are of the button's own square box (so the
   geometry follows --fs by itself), and every hand-tuned pixel value is a
   multiple of --u (1px at the 210px reference). Never hard-code a px in
   here — an absolute travel punches through the cap wall once the button
   is smaller than the reference size. */
.fire-btn {
  --fs: min(clamp(104px, calc(18 * var(--vwu)), 132px), calc(21 * var(--vhu)));
  --u: calc(var(--fs) / 210);        /* 1u = 1px at the reference size    */
  --tr: calc(8 * var(--u));          /* cap travel — about half the wall  */
  --dur: .34s;
  --rest: .68;                       /* band brightness at rest           */
  position: relative; width: var(--fs); height: var(--fs); flex: 0 0 auto;
  border: 0; padding: 0; background: none; cursor: pointer; border-radius: 50%;
  -webkit-tap-highlight-color: transparent; font-family: inherit;
  /* The footprint is square but the OBJECT is only 0.708--fs tall and centred
     in it, so the transparent band above and below would inflate the dock row
     by a quarter of --fs. Pull the LAYOUT box in to the object; the box still
     paints outside it, cast shadow included. */
  margin-block: calc((calc(0.708 * var(--fs)) - var(--fs)) / 2);
}
.fire-btn i, .fire-btn b { position: absolute; display: block; }
.fire-btn i { border-radius: 50%; }          /* every horizontal circle */
.fire-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* cast shadow on the dock, thrown down and right, away from the key light */
.fb-floor { left: 3%; right: -5%; top: 56.08%; height: 43.75%; z-index: 0;
  background: radial-gradient(ellipse at 50% 50%, rgba(0,0,0,.72), rgba(0,0,0,0) 70%);
  filter: blur(calc(6 * var(--u))); }

/* bezel: bottom ellipse, side wall, top face. The wall spans between two
   ellipse centre-lines, where a cylinder is at full width, so the silhouette
   between them is a clean rectangle. */
.fb-bez-bot  { left: 1%; right: 1%; top: 29.62%; height: 60.76%; background: #0d0f12; z-index: 1; }
.fb-bez-wall { left: 1%; right: 1%; top: 50%; height: 10%; border-radius: 0; z-index: 1;
  background: linear-gradient(180deg,#2e343c,#101215); }
.fb-bez-top  { left: 1%; right: 1%; top: 19.62%; height: 60.76%; z-index: 2;
  background: radial-gradient(ellipse at 42% 30%, #2c323a, #131619);
  box-shadow: inset 0 calc(1 * var(--u)) 0 rgba(255,255,255,.18); }

/* The warning band is struck in a SQUARE and then scaled to the camera, so the
   wedges bunch toward the left and right the way radial divisions on a tilted
   ring do. Painting the conic straight onto an ellipse spaces them by screen
   angle instead — the wrong mapping, and it reads as a sunburst. Starting the
   repeat a quarter-period early (-11.25deg on a 45deg period) puts a wedge
   centre on both axes, so the ring is symmetric across both. */
.fb-band { left: 2%; right: 2%; top: 2%; height: 96%; transform: scaleY(.62);
  opacity: var(--rest); z-index: 3;
  background: repeating-conic-gradient(from -11.25deg,
              #ffcf4a 0deg 22.5deg, #241d07 22.5deg 45deg);
  box-shadow: inset 0 0 0 calc(2 * var(--u)) #0d0f12,
              0 0 calc(16 * var(--u)) rgba(255,180,50,.5); }
.fb-band > i { left: 0; right: 0; top: 0; bottom: 0;
  background: radial-gradient(ellipse at 50% 50%, rgba(255,214,120,.3), rgba(255,150,40,0) 72%); }

/* machined lip, so the dark wedges cannot bleed into the dark of the bore */
.fb-lip { left: 7%; right: 7%; top: 23.34%; height: 53.32%; z-index: 3;
  background: linear-gradient(180deg,#6a7079 0%,#3d434a 50%,#22262b 100%);
  box-shadow: inset 0 0 0 calc(1 * var(--u)) rgba(0,0,0,.55); }

/* the bore the cap runs in, its occlusion, and the cap's contact shadow */
.fb-bore    { left: 11%; right: 11%; top: 25.82%; height: 48.36%; z-index: 4;
  background: radial-gradient(ellipse at 50% 38%, #1e2229, #0c0e11);
  box-shadow: inset 0 calc(7 * var(--u)) calc(15 * var(--u)) rgba(0,0,0,.95),
              0 0 0 calc(2 * var(--u)) #131519; }
.fb-occ     { left: 11%; right: 11%; top: 25.82%; height: 48.36%; z-index: 5; opacity: .85;
  background: radial-gradient(ellipse at 50% 28%, rgba(0,0,0,.55), rgba(0,0,0,0) 62%); }
.fb-contact { left: 11%; right: 11%; top: 25.82%; height: 48.36%; z-index: 6; pointer-events: none;
  box-shadow: inset 0 calc(3 * var(--u)) calc(10 * var(--u)) rgba(0,0,0,.6); }

/* The cap's side wall STAYS PUT and the face slides down over it, so the visible
   wall shortens by exactly the travel — the cap really is sliding into its bore
   rather than being scaled. The lower disc is what you read as the wall, so it is
   shaded like the cylinder it is rather than filled flat. */
.fb-skirt { left: 16%; right: 16%; top: 45.4%; height: 28.58%; border-radius: 0; z-index: 7; }
.fb-skirt > .fb-disc { left: 0; right: 0; bottom: 0; height: 147.52%;
  background: radial-gradient(ellipse at 50% 28%, #d33528 0%, #a01b13 60%, #520805 100%); }
.fb-skirt > .fb-wall { left: 0; right: 0; top: 0; bottom: 73.76%; border-radius: 0;
  background: linear-gradient(180deg,#bb271b,#700e09); }

/* the moving group: face, sheen, hotspot, rim light, label */
.fb-cap   { left: 0; right: 0; top: 0; bottom: 0; border-radius: 0; z-index: 8; }
.fb-face  { left: 16%; right: 16%; top: 24.32%; height: 42.16%; z-index: 7;
  background: radial-gradient(ellipse at 33% 21%, #ff8a78 0%, #ee4032 28%, #b81c14 64%, #7c0f0a 100%);
  box-shadow: inset 0 calc(2 * var(--u)) calc(3 * var(--u)) rgba(255,255,255,.42),
              inset 0 calc(-8 * var(--u)) calc(15 * var(--u)) rgba(70,4,2,.6); }
.fb-sheen { left: 22.8%; right: 22.8%; top: 27.271%; height: 21.08%; z-index: 8; pointer-events: none;
  background: radial-gradient(ellipse at 50% 0%, rgba(255,255,255,.28), rgba(255,255,255,0) 72%); }
.fb-spec  { left: 27.56%; width: 21.76%; top: 30.644%; height: 11.805%; z-index: 9; pointer-events: none;
  background: radial-gradient(ellipse at 50% 50%, rgba(255,255,255,.95), rgba(255,255,255,0) 68%);
  filter: blur(calc(1 * var(--u))); }
/* rim light along the far edge. This MUST be a length — a percentage here is
   invalid CSS and silently drops the whole declaration. */
.fb-rim   { left: 16%; right: 16%; top: 24.32%; height: 42.16%; z-index: 9; pointer-events: none;
  box-shadow: inset 0 calc(4.43 * var(--u)) 0 rgba(255,255,255,.3); }
.fb-label { left: 0; top: 38.088%; width: 100%; text-align: center; z-index: 10; pointer-events: none;
  font-weight: 900; letter-spacing: .11em; font-size: calc(var(--fs) * .125);
  color: #fff3f1; text-shadow: 0 calc(1 * var(--u)) calc(3 * var(--u)) rgba(50,3,2,.95);
  transform: scaleY(.62); }

/* --- the press: bite down, hold, damped overshoot, settle. Only the cap group
   moves; the band, lip and bezel are outside it and hold dead still. --- */
.fire-btn.is-pressed .fb-cap   { animation: fbDrop  var(--dur) cubic-bezier(.34,.06,.2,1); }
.fire-btn.is-pressed .fb-floor { animation: fbFloor var(--dur) cubic-bezier(.34,.06,.2,1); }
.fire-btn.is-pressed .fb-spec  { animation: fbSpec  var(--dur) cubic-bezier(.34,.06,.2,1); }
.fire-btn.is-pressed .fb-sheen { animation: fbSheen var(--dur) cubic-bezier(.34,.06,.2,1); }
.fire-btn.is-pressed .fb-occ   { animation: fbOcc   var(--dur) cubic-bezier(.34,.06,.2,1); }
.fire-btn.is-pressed .fb-band  { animation: fbFlare var(--dur) cubic-bezier(.34,.06,.2,1); }

@keyframes fbDrop {
  0%   { transform: translateY(0); }
  26%  { transform: translateY(var(--tr)); }
  46%  { transform: translateY(var(--tr)); }
  72%  { transform: translateY(calc(var(--tr) * -.13)); }
  88%  { transform: translateY(calc(var(--tr) * .05)); }
  100% { transform: translateY(0); }
}
@keyframes fbFloor { 0%,100% { transform: scale(1); opacity: 1; }
                     26%,46% { transform: scale(.9,.78); opacity: .78; } }
/* the hotspot slides toward the key light and tightens as the face falls away */
@keyframes fbSpec  { 0%,100% { transform: translate(0,0) scale(1); opacity: 1; }
                     26%,46% { transform: translate(calc(-2 * var(--u)), calc(-2.5 * var(--u))) scale(.8);
                               opacity: .85; } }
@keyframes fbSheen { 0%,100% { opacity: 1; } 26%,46% { opacity: .7; } }
@keyframes fbOcc   { 0%,100% { opacity: .85; } 26%,46% { opacity: 1; } }
/* the band is the feedback: it idles at --rest and surges as the cap bottoms out */
@keyframes fbFlare { 0%,100% { opacity: var(--rest); } 24%,52% { opacity: 1; } }

/* not your turn */
.fire-btn:disabled { cursor: not-allowed; filter: grayscale(.55) brightness(.62); }
.fire-btn:disabled .fb-band { opacity: .26; box-shadow: inset 0 0 0 calc(2 * var(--u)) #0d0f12; }

@media (prefers-reduced-motion: reduce) { .fire-btn * { animation: none !important; } }

/* --- size per dock tier. --fs is sized from the HEIGHT the row can give the
   object (it is 0.708--fs tall), never from the width, and never squashed:
   the 0.62 foreshortening is the whole illusion. Portrait twins phrased on the
   effective axes, per the rotation shim. --- */
@media (orientation: landscape) and (max-height: 600px), (orientation: portrait) and (max-width: 600px) {
  .fire-btn { --fs: 104px; }
}
@media (orientation: landscape) and (max-width: 830px), (orientation: portrait) and (max-height: 830px) {
  .fire-btn { --fs: 92px; }
}
/* ===== end FIRE BUTTON ============================================== */
