* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: var(--bg); }
body { font-family: var(--ff); color: var(--ink); user-select: none; }
#game { position: absolute; inset: 0; display: block; cursor: crosshair; }
.hidden { display: none !important; }

/* ---------- design tokens ----------
   One palette for the menu and the in-game panels. Semantic colours (team
   red/blue, health green, points gold, damage red) deliberately stay OUT of
   this set: they carry meaning and must not drift with the art direction.
   The in-game panels take surfaces, edges and the cut corners only — no grain,
   no decorative vignette. #vignette is the damage indicator; competing with it
   would cost a signal that currently means "you are about to die". */
:root {
  --bg: #07090a;
  --fill: rgba(20, 22, 25, .93);   /* concrete panel */
  --fill-2: #191c20;
  --edge: #33383f;                 /* chipped concrete edge */
  --edge-lit: #545b64;
  --ink: #cbcec7;                  /* bone */
  --ink-dim: #838a80;
  --ink-faint: #575d55;
  --blood: #8e2018;                /* dried */
  --blood-lit: #c4392c;            /* fresh */
  --steel: #3f5f7a;
  --steel-lit: #7fa9c9;
  --ff: 'Segoe UI', system-ui, sans-serif;
  /* condensed stencil-ish stack for headings; every entry is an OS font, so
     nothing is fetched (the project ships no assets) */
  --ff-head: 'Oswald', 'Arial Narrow', 'Roboto Condensed', 'Liberation Sans Narrow', var(--ff);
  --ff-num: ui-monospace, 'SF Mono', 'Cascadia Mono', Consolas, monospace;
  /* film grain, inline so it costs no request and ships no file */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
  --s: 1;
}

/* HUD scale. Every fixed size in the HUD below is expressed as a multiple of
   --s, so one number retunes the whole overlay for a small screen. The
   selecting condition is mirrored in JS (COMPACT_UI in main.ts, which scales
   the canvas-drawn minimap) — keep the two in step. */
@media (pointer: coarse), (max-height: 500px) { :root { --s: .62; } }

/* ---------- cut panels ----------
   clip-path does not clip a `border` onto the diagonal, so the edge is drawn as
   the element's own background and the fill is an inset ::before wearing the
   same path. Content must then be lifted above that pseudo-element, which is
   what the `.cut > *` rule does — bare text nodes inside a .cut would be
   painted over. */
.cut {
  --c: 12px; --cw: 1px;
  position: relative;
  background: var(--edge);
  clip-path: polygon(var(--c) 0, 100% 0, 100% calc(100% - var(--c)), calc(100% - var(--c)) 100%, 0 100%, 0 var(--c));
}
.cut::before { content: ''; position: absolute; inset: var(--cw); background: var(--fill); clip-path: inherit; }
.cut > * { position: relative; z-index: 1; }

/* ---------- menu ---------- */
.overlay { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  background: #0a0c0d; z-index: 20;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  overflow: auto; }
/* heavy vignette + a cold concrete wash */
.overlay::before { content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 70% 60% at 50% 38%, rgba(48,52,50,.42) 0%, transparent 70%),
    radial-gradient(ellipse at 50% 45%, transparent 28%, rgba(0,0,0,.82) 100%); }
/* grain: static, no animation — a full-screen animated noise composite is the
   one thing on this page that would cost battery on the phone about to run the
   actual game */
.overlay::after { content: ''; position: absolute; inset: 0; pointer-events: none;
  opacity: .05; background-image: var(--grain); background-size: 180px 180px; }

.menu-card { --c: 18px; z-index: 1; text-align: left; padding: 34px 38px;
  width: min(620px, 100%); box-shadow: 0 26px 90px rgba(0,0,0,.75); }
.menu-card::before { background: linear-gradient(170deg, #191c20 0%, #131619 55%, #0f1214 100%); }

.mc-brand h1 { font-family: var(--ff-head); font-size: 54px; line-height: 1; font-weight: 800;
  letter-spacing: 9px; color: #e3e5df; text-transform: uppercase;
  text-shadow: 0 0 26px rgba(142,32,24,.45), 0 2px 0 #000;
  animation: flicker 7s steps(1, end) infinite; }
.menu-card h1 .t2 { color: var(--blood-lit); }
/* a dying-bulb stutter: irregular, mostly off, never strobing */
@keyframes flicker {
  0%, 40% { opacity: 1; }
  41% { opacity: .62; } 42% { opacity: 1; } 44% { opacity: .78; } 45% { opacity: 1; }
  76% { opacity: 1; } 77% { opacity: .55; } 78% { opacity: 1; }
  100% { opacity: 1; }
}
.tagline { color: var(--ink-faint); letter-spacing: 5px; text-transform: uppercase; font-size: 11px;
  margin: 8px 0 22px; }

.field { display: block; margin-bottom: 14px; }
.field .fl { display: block; font-size: 10px; letter-spacing: 3px; text-transform: uppercase;
  color: var(--ink-faint); margin-bottom: 5px; }
#name-input { width: 100%; padding: 11px 14px; font-size: 16px; letter-spacing: 3px; font-family: var(--ff-head);
  text-transform: uppercase; background: #0b0d0f; color: #e6e8e2; border: 1px solid #2b3036;
  border-left: 2px solid var(--blood); outline: none; }
#name-input::placeholder { color: #4a4f48; letter-spacing: 2px; }
#name-input:focus { border-color: #454c54; border-left-color: var(--blood-lit); background: #0e1113; }

#cp-row { display: flex; align-items: center; gap: 10px; margin: 0 0 14px; }
#cp-label { font-size: 11px; letter-spacing: 1px; color: #9fb87a; }
#cp-clear { padding: 4px 9px; background: #0b0d0f; color: var(--ink-dim); font-size: 10px; letter-spacing: 1px;
  font-family: var(--ff); text-transform: uppercase; border: 1px solid #2b3036; cursor: pointer; }
#cp-clear:hover { color: #fff; border-color: var(--blood-lit); }

/* mode cards: same grimy world, two factions of it. OUTBREAK decays, SKIRMISH
   is cold steel — the card previews the mode's feel rather than only naming it. */
.mode-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
.mode-card { --c: 14px; --accent: var(--blood); --accent-lit: var(--blood-lit);
  display: block; text-align: left; padding: 16px 18px 14px; cursor: pointer; color: var(--ink);
  font-family: var(--ff); transition: transform .12s, background .12s; }
.mode-card::before { transition: background .15s; }
.mode-card .mc-idx { display: block; font-family: var(--ff-num); font-size: 10px; letter-spacing: 2px;
  color: var(--ink-faint); }
.mode-card .mode-title { display: block; font-family: var(--ff-head); font-size: 21px; font-weight: 700;
  letter-spacing: 3px; text-transform: uppercase; color: #e3e5df; margin: 2px 0 6px; }
.mode-card .mode-desc { display: block; font-size: 12px; color: var(--ink-dim); line-height: 1.55; }
.mode-card .mc-go { display: block; margin-top: 10px; font-size: 10px; letter-spacing: 4px;
  text-transform: uppercase; color: var(--accent-lit); opacity: .8; }
.mode-card:hover, .mode-card:focus-visible { background: var(--accent-lit); transform: translateY(-2px); outline: none; }
.mode-card:hover::before, .mode-card:focus-visible::before { background: #16191c; }
.mode-card:active { transform: translateY(0); }
.mc-outbreak { --accent: var(--blood); --accent-lit: var(--blood-lit); }
.mc-outbreak::before { background: linear-gradient(160deg, #1c1719 0%, #141517 70%); }
.mc-skirmish { --accent: var(--steel); --accent-lit: var(--steel-lit); }
.mc-skirmish::before { background: linear-gradient(160deg, #161b1f 0%, #131618 70%); }
.mc-skirmish .mode-title { letter-spacing: 2px; }

.settings { display: flex; flex-direction: column; gap: 8px; }
.set-row { display: flex; align-items: center; gap: 12px; }
.loadout-label { flex: 0 0 62px; font-size: 10px; letter-spacing: 3px; color: var(--ink-faint);
  text-transform: uppercase; }
#loadout-opts, #gfx-opts, #touch-opts { display: flex; gap: 4px; flex-wrap: wrap; }
#loadout-opts button, #gfx-opts button, #touch-opts button { padding: 7px 11px; min-height: 32px;
  display: inline-flex; align-items: center; background: #0e1113; color: var(--ink-dim);
  border: 1px solid #2b3036; cursor: pointer; font-size: 11px; letter-spacing: 1px; font-family: var(--ff); }
#loadout-opts button:hover, #gfx-opts button:hover, #touch-opts button:hover { color: var(--ink); border-color: #454c54; }
#loadout-opts button.sel, #gfx-opts button.sel, #touch-opts button.sel { color: #fff;
  border-color: var(--blood-lit); background: #241416; }

.mc-foot { margin-top: 18px; border-top: 1px solid #23272c; padding-top: 12px; }
.help { font-size: 11px; color: var(--ink-faint); letter-spacing: 1px; }
#conn-status { margin-top: 8px; font-size: 12px; color: #c08f3a; min-height: 16px; letter-spacing: 1px; }

/* portrait is a designed layout, not the landscape card squeezed: a phone user
   lands here before they ever rotate */
@media (orientation: portrait) {
  .overlay { align-items: stretch; }
  .menu-card { --c: 0px; width: 100%; padding: 30px 22px calc(22px + env(safe-area-inset-bottom));
    display: flex; flex-direction: column; box-shadow: none; }
  .menu-card::before { inset: 0; }
  .mc-brand h1 { font-size: clamp(38px, 13vw, 58px); letter-spacing: 7px; }
  .tagline { margin-bottom: 26px; }
  #name-input { padding: 14px; font-size: 17px; }
  .mode-row { grid-template-columns: 1fr; gap: 10px; }
  .mode-card { padding: 18px 20px; min-height: 96px; }
  .mc-main { margin-top: 4px; }
  /* Rows stay horizontal even here. Stacking the label above its buttons reads
     better but costs ~57px over three rows, which is exactly what pushed the
     card past a 844px-tall phone into scrolling. */
  .settings { gap: 10px; margin-top: 4px; }
  #loadout-opts, #gfx-opts, #touch-opts { flex: 1; }
  #loadout-opts button, #gfx-opts button, #touch-opts button { flex: 1; min-height: 44px;
    justify-content: center; font-size: 12px; }
  .mc-foot { margin-top: auto; padding-top: 16px; }
}

/* short landscape (phones in play orientation): brand beside the controls, so
   the card never scrolls */
@media (orientation: landscape) and (max-height: 560px) {
  .menu-card { padding: 16px 20px; width: min(760px, 100%);
    display: grid; grid-template-columns: minmax(170px, 0.85fr) 1.3fr;
    grid-template-areas: "brand main" "foot foot"; column-gap: 22px; }
  .mc-brand { grid-area: brand; }
  .mc-main { grid-area: main; }
  .mc-foot { grid-area: foot; margin-top: 10px; padding-top: 8px; }
  .mc-brand h1 { font-size: 32px; letter-spacing: 5px; }
  .tagline { font-size: 9px; margin: 4px 0 12px; letter-spacing: 3px; }
  #name-input { padding: 8px 11px; font-size: 14px; }
  .mode-row { margin-bottom: 10px; gap: 10px; }
  .mode-card { padding: 10px 12px; }
  .mode-card .mode-title { font-size: 16px; margin: 1px 0 4px; }
  .mode-card .mode-desc { font-size: 10px; line-height: 1.4; }
  .mode-card .mc-go { margin-top: 6px; }
  .settings { gap: 5px; }
  #loadout-opts button, #gfx-opts button, #touch-opts button { padding: 5px 8px; min-height: 28px; font-size: 10px; }
  .help { font-size: 10px; }
  #conn-status { margin-top: 4px; }
}

/* flashing text is an accessibility problem, not a taste one */
@media (prefers-reduced-motion: reduce) {
  .mc-brand h1 { animation: none; }
  .mode-card { transition: none; }
  #shophint, #winded, #reloadhint, #killfeed div { animation: none; }
}

/* ---------- HUD ---------- */
#hud { position: absolute; inset: 0; pointer-events: none; z-index: 10;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); }
#hud > * { pointer-events: none; }

#topbar { --c: 9px; position: absolute; top: calc(14px * var(--s)); left: 50%; transform: translateX(-50%);
  display: flex; gap: calc(18px * var(--s)); align-items: center; font-weight: 700;
  font-family: var(--ff-head); font-size: calc(20px * var(--s));
  padding: calc(8px * var(--s)) calc(22px * var(--s)); }
#topbar::before { background: rgba(12,14,16,.82); }
#topbar .red { color: #ff6a5e; } #topbar .blue { color: #5ea2ff; }
#topbar .timer { color: #cfd6df; font-size: calc(16px * var(--s)); font-weight: 600; font-family: var(--ff-num); }
#topbar .wave { color: #9fe870; letter-spacing: 2px; }
#topbar .zleft { color: #cfd6df; font-size: calc(14px * var(--s)); font-weight: 600; font-family: var(--ff); }

#banner { position: absolute; top: 20%; left: 50%; transform: translateX(-50%);
  font-family: var(--ff-head); font-size: calc(34px * var(--s)); font-weight: 800;
  letter-spacing: calc(6px * var(--s)); color: #fff;
  text-shadow: 0 2px 18px rgba(196,57,44,.85); opacity: 0; transition: opacity .3s; white-space: nowrap; }

/* top-right strip: pause control + perf readout. Killfeed stacks below it. */
#topright { position: absolute; top: calc(14px * var(--s)); right: calc(16px * var(--s));
  display: flex; gap: 8px; align-items: center; }
#pausebtn { display: none; pointer-events: auto; touch-action: manipulation;
  width: 40px; height: 40px; align-items: center; justify-content: center;
  font: 700 15px/1 var(--ff); color: var(--ink); background: rgba(12,14,16,.82);
  border: 1px solid var(--edge); cursor: pointer; }
#pausebtn:hover { border-color: var(--blood-lit); color: #fff; }
body.touch #pausebtn { display: flex; }
body.touch #killfeed { top: 62px; }

#perf { display: flex; gap: 10px;
  font-size: calc(11px * var(--s)); font-weight: 700; letter-spacing: 1px; font-family: var(--ff-num);
  background: rgba(12,14,16,.75); padding: 3px 9px; border: 1px solid #23272c; }
#perf span { color: var(--ink-dim); }
#perf .warn { color: #e8a53f; }
#perf .bad { color: #ff6a5e; }

#killfeed { position: absolute; top: calc(44px * var(--s)); right: calc(16px * var(--s));
  text-align: right; font-size: calc(13px * var(--s)); }
#killfeed div { background: rgba(12,14,16,.75); margin-bottom: 4px; padding: 4px 10px;
  border-left: 2px solid var(--edge); animation: feedin .2s; }
#killfeed .k0 { color: #ff8b81; } #killfeed .k1 { color: #8ebbff; } #killfeed .k2 { color: #9fe870; }
#killfeed .wname { color: var(--ink-dim); font-size: calc(11px * var(--s)); margin: 0 6px; }
@keyframes feedin { from { transform: translateX(30px); opacity: 0; } }

#bottom-left { position: absolute; left: calc(20px * var(--s)); bottom: calc(20px * var(--s)); }
#healthwrap { width: calc(240px * var(--s)); height: calc(20px * var(--s)); background: rgba(12,14,16,.85);
  border: 1px solid #2b3036; position: relative; overflow: hidden; }
#healthbar { height: 100%; width: 100%; background: linear-gradient(90deg,#3fae5a,#59d97c); transition: width .15s; }
#healthnum { position: absolute; inset: 0; text-align: center; font-size: calc(13px * var(--s)); font-weight: 700;
  font-family: var(--ff-num); line-height: calc(20px * var(--s)); color: #fff; text-shadow: 0 1px 3px #000; }
#stamwrap { width: calc(240px * var(--s)); height: calc(6px * var(--s)); background: rgba(12,14,16,.85);
  border: 1px solid #2b3036; border-top: none; overflow: hidden; }
#stambar { height: 100%; width: 100%; background: #d9b13f; transition: width .1s linear; }
#stambar.low { background: #c0392b; }
#points { margin-top: 8px; font-size: calc(18px * var(--s)); font-weight: 800; font-family: var(--ff-num);
  color: #ffd75e; text-shadow: 0 1px 4px #000; }
#winded { margin-top: 5px; font-size: calc(12px * var(--s)); font-weight: 800; letter-spacing: 3px; color: #ff6a5e;
  text-shadow: 0 1px 3px #000; animation: pulse .9s infinite; }
#shophint { display: inline-block; margin-top: 6px; font-size: calc(12px * var(--s)); font-weight: 700; letter-spacing: 2px;
  color: #ffd75e; border: 1px solid rgba(255,215,94,.5); padding: 3px 9px;
  background: rgba(12,14,16,.75); animation: pulse 1.6s infinite; }
@keyframes pulse { 0%, 100% { opacity: .45; } 50% { opacity: 1; } }

#bottom-right { position: absolute; right: calc(20px * var(--s)); bottom: calc(20px * var(--s)); text-align: right; }
#weapon-slots { font-size: calc(12px * var(--s)); margin-bottom: 6px; color: var(--ink-dim); }
#reloadhint { font-size: calc(14px * var(--s)); font-weight: 800; letter-spacing: 2px; color: #e8a53f;
  text-shadow: 0 1px 3px #000; margin-bottom: 4px; animation: pulse .9s infinite; }
#weapon-slots span { padding: 3px 10px; border: 1px solid #2b3036; margin-left: 6px;
  background: rgba(12,14,16,.75); }
#weapon-slots span.active { color: #fff; border-color: #e8a53f; }
/* weapon icons: rasterised from the same draw code as the world sprites */
.wicon { height: calc(11px * var(--s)); width: auto; vertical-align: -1px; margin: 0 5px; opacity: .85;
  image-rendering: auto; }
#weapon-slots span.active .wicon { opacity: 1; }
#loadout-opts button .wicon { height: 12px; margin: 0 6px 0 0; }
#ammo { font-size: calc(34px * var(--s)); font-weight: 800; font-family: var(--ff-num); color: #f2f5f9;
  text-shadow: 0 2px 6px #000; }
#ammo #reserve { font-size: calc(18px * var(--s)); color: var(--ink-dim); margin-left: 6px; }
#reloadwrap { width: calc(160px * var(--s)); height: 5px; background: #1a1d21; margin-top: 5px; margin-left: auto; }
#reloadbar { height: 100%; width: 0%; background: #e8a53f; }

#botbar { position: absolute; right: calc(20px * var(--s)); top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 6px; }
#botbar button { pointer-events: auto; padding: 7px 12px; font-size: calc(12px * var(--s));
  background: rgba(14,17,19,.88); color: #b6c0cf; border: 1px solid var(--edge);
  cursor: pointer; letter-spacing: 1px; font-family: var(--ff); }
#botbar button:hover { border-color: #e8a53f; color: #fff; }

/* ---------- in-game panels ---------- */
#buymenu, #scoreboard, #pause { --c: 12px; position: absolute; left: 50%; top: 50%;
  transform: translate(-50%,-50%); pointer-events: auto; }
#buymenu::before, #scoreboard::before, #pause::before { background: rgba(16,18,21,.96); }

#buymenu { padding: calc(20px * var(--s)) calc(26px * var(--s)); min-width: calc(340px * var(--s)); }
#buymenu h3 { letter-spacing: 3px; margin-bottom: 12px; color: #e3e5df; display: flex; align-items: center;
  gap: 12px; font-family: var(--ff-head); font-size: calc(19px * var(--s)); }
#buymenu .bm-t { flex: 1; }
#buymenu .bm-pts { color: #ffd75e; font-family: var(--ff-num); }
#bm-close { width: calc(28px * var(--s)); height: calc(28px * var(--s)); flex: none; cursor: pointer;
  font: 400 calc(20px * var(--s))/1 var(--ff); color: var(--ink-dim); background: transparent;
  border: 1px solid var(--edge); }
#bm-close:hover { color: #fff; border-color: var(--blood-lit); }
#buy-items div { display: flex; justify-content: space-between; align-items: center;
  padding: calc(9px * var(--s)) 12px; margin: 4px 0;
  background: var(--fill-2); border: 1px solid #23272c; cursor: pointer; font-size: calc(14px * var(--s)); }
#buy-items div:hover { border-color: #e8a53f; }
/* Closing the armory now MEANS the purchase went through, so a row the server
   would reject must not be clickable — otherwise silence is the only feedback
   for three different failures (broke, already owned, health already full). */
#buy-items div.cant, #buy-items div.owned { pointer-events: none; }
#buy-items div.cant { opacity: .34; }
#buy-items div.owned { opacity: .5; border-color: #3fae5a; }
#buy-items .cost { color: #ffd75e; font-family: var(--ff-num); font-weight: 700; }
#buy-items .num { color: var(--ink-faint); font-family: var(--ff-num); margin-right: 8px; }
#buy-items .wicon { height: calc(13px * var(--s)); margin-right: 9px; }

#pause { padding: calc(22px * var(--s)) calc(30px * var(--s)); min-width: calc(320px * var(--s)); text-align: center; }
#pause h3 { font-family: var(--ff-head); font-size: calc(24px * var(--s)); letter-spacing: 7px;
  color: #e3e5df; margin-bottom: 6px; }
#pause .pz-note { font-size: calc(12px * var(--s)); color: var(--ink-dim); letter-spacing: 1px;
  margin-bottom: 14px; }
#pause .help { margin-top: 12px; }
.pz-btns { display: flex; gap: 10px; justify-content: center; }
.pz-btns button { flex: 1; min-height: 44px; padding: 0 16px; cursor: pointer; touch-action: manipulation;
  font: 700 calc(13px * var(--s))/1 var(--ff-head); letter-spacing: 3px; color: var(--ink);
  background: var(--fill-2); border: 1px solid var(--edge); }
.pz-btns button:hover { color: #fff; border-color: var(--edge-lit); }
.pz-btns .pz-go:hover { border-color: var(--steel-lit); }
.pz-btns .pz-bad { color: #e39a92; }
.pz-btns .pz-bad:hover { color: #fff; background: var(--blood); border-color: var(--blood-lit); }

#scoreboard { padding: calc(18px * var(--s)) calc(26px * var(--s)); min-width: calc(480px * var(--s)); }
#scoreboard table { width: 100%; border-collapse: collapse; font-size: calc(14px * var(--s)); }
#scoreboard th { text-align: left; color: var(--ink-faint); font-size: calc(11px * var(--s)); letter-spacing: 2px;
  padding: 4px 10px; }
#scoreboard td { padding: calc(5px * var(--s)) 10px; border-top: 1px solid #1e2226; font-variant-numeric: tabular-nums; }
#scoreboard .t0 td:first-child { color: #ff8b81; } #scoreboard .t1 td:first-child { color: #8ebbff; }
#scoreboard .t2 td:first-child { color: #9fe870; }
#scoreboard .me td { background: rgba(232,165,63,.08); }
#scoreboard .hdr { font-family: var(--ff-head); font-size: calc(15px * var(--s)); font-weight: 800;
  letter-spacing: 3px; padding-top: 12px; }

#center-msg { position: absolute; left: 50%; top: 38%; transform: translateX(-50%); text-align: center; }
#center-msg .big { font-family: var(--ff-head); font-size: calc(44px * var(--s)); font-weight: 800;
  letter-spacing: calc(8px * var(--s)); text-shadow: 0 2px 24px #000; }
#center-msg .sub { font-size: calc(16px * var(--s)); color: #b6c0cf; margin-top: 10px; letter-spacing: 2px; }
#center-msg .sub.dim { font-size: calc(13px * var(--s)); color: var(--ink-dim); }

#vignette { position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(ellipse at center, transparent 55%, rgba(180,20,10,.55) 100%); }
#hitflash { position: absolute; inset: 0; pointer-events: none; opacity: 0; background: rgba(255,40,20,.14); }

/* ---------- touch controls ---------- */
/* z-index 9 keeps the pads under #hud, which is pointer-events:none except for
   its interactive children — so drags fall through to here, but a tap on the
   armory or the bot bar still hits the HUD. */
#touch { position: absolute; inset: 0; z-index: 9; touch-action: none;
  -webkit-user-select: none; user-select: none; -webkit-tap-highlight-color: transparent; }
/* the pads and the orientation gate belong to a running match, not the menu —
   the menu itself is perfectly usable in portrait */
#menu:not(.hidden) ~ #touch, #menu:not(.hidden) ~ #rotate { display: none !important; }
#touch button { pointer-events: auto; touch-action: none; min-width: 96px; padding: 13px 14px;
  font: 700 12px/1 var(--ff); letter-spacing: 2px; color: #c6cfdd;
  background: rgba(14,19,22,.74); border: 1px solid rgba(96,108,118,.45); border-radius: 10px; }
#touch button.down { background: rgba(44,52,62,.92); color: #fff; border-color: rgba(150,164,180,.7); }
#tb-sprint.on { color: #ffd75e; border-color: rgba(217,177,63,.85); background: rgba(48,38,14,.8); }

#dpad { position: absolute; width: 136px; height: 136px; border-radius: 50%;
  left: calc(26px + env(safe-area-inset-left)); bottom: calc(26px + env(safe-area-inset-bottom));
  background: radial-gradient(circle, rgba(22,26,30,.5) 0%, rgba(15,18,21,.28) 68%, rgba(15,18,21,0) 72%);
  border: 1px solid rgba(96,108,118,.32); }
.dp { position: absolute; width: 0; height: 0; opacity: .4; transition: opacity .06s; }
.dp.on { opacity: 1; }
.dp-w { top: 13px; left: 50%; margin-left: -9px;
  border-left: 9px solid transparent; border-right: 9px solid transparent; border-bottom: 13px solid #cfd8e6; }
.dp-s { bottom: 13px; left: 50%; margin-left: -9px;
  border-left: 9px solid transparent; border-right: 9px solid transparent; border-top: 13px solid #cfd8e6; }
.dp-a { left: 13px; top: 50%; margin-top: -9px;
  border-top: 9px solid transparent; border-bottom: 9px solid transparent; border-right: 13px solid #cfd8e6; }
.dp-d { right: 13px; top: 50%; margin-top: -9px;
  border-top: 9px solid transparent; border-bottom: 9px solid transparent; border-left: 13px solid #cfd8e6; }

/* floating: left/top are written inline at touchdown */
#astick { position: absolute; width: 104px; height: 104px; margin: -52px 0 0 -52px; border-radius: 50%;
  background: rgba(18,22,26,.34); border: 1px solid rgba(96,108,118,.34); }
#aknob { position: absolute; left: 50%; top: 50%; width: 46px; height: 46px; margin: -23px 0 0 -23px;
  border-radius: 50%; background: rgba(196,57,44,.32); border: 1px solid rgba(255,130,120,.62); }
/* Pushed into the outer ring = firing. The inner travel only aims, and that is
   invisible under a thumb, so the ring lights up to say which state you are in. */
#astick.hot { background: rgba(46,20,22,.42); border-color: rgba(255,120,110,.72); }
#astick.hot #aknob { background: rgba(196,57,44,.62); border-color: rgba(255,196,190,.9); }

#tbtns-left { position: absolute; display: flex; flex-direction: column; gap: 10px; align-items: flex-start;
  left: calc(26px + env(safe-area-inset-left)); bottom: calc(174px + env(safe-area-inset-bottom)); }
#tbtns-right { position: absolute; display: flex; flex-direction: column; gap: 10px; align-items: flex-end;
  right: calc(22px + env(safe-area-inset-right)); bottom: calc(118px + env(safe-area-inset-bottom)); }

/* ---------- touch-mode HUD adjustments ---------- */
body.touch #game { cursor: none; }
body.touch #topbar { pointer-events: auto; }          /* tap to toggle the scoreboard */
body.touch #botbar { top: 28%; transform: none; }     /* out of the aim-thumb arc */
/* The bottom-left corner belongs to the dpad, so the left side stacks into three
   non-overlapping bands: minimap (16..100), health/stamina/points (108..150),
   then the pad in the corner with its buttons beside it rather than above. */
body.touch #bottom-left { left: 16px; bottom: auto; top: 108px; }
body.touch #tbtns-left { left: calc(180px + env(safe-area-inset-left)); bottom: calc(26px + env(safe-area-inset-bottom)); }
/* these name keys a touch player does not have, and both now have real buttons
   a thumb's width away */
body.touch #shophint, body.touch #reloadhint { display: none; }
.bb-toggle { display: none; }
body.touch .bb-toggle { display: block; }
body.touch #botbar .bb-list { display: none; flex-direction: column; gap: 6px; margin-top: 6px; }
body.touch #botbar.open .bb-list { display: flex; }
#botbar .bb-list { display: flex; flex-direction: column; gap: 6px; }
.kbd-only { display: revert; }
body.touch .kbd-only { display: none; }
.cm-btns { display: none; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 12px; }
body.touch .cm-btns { display: flex; }
.cm-btns button { pointer-events: auto; touch-action: none; min-height: 44px; padding: 10px 14px;
  font: 700 12px/1 var(--ff); letter-spacing: 2px; color: #c6cfdd; background: rgba(14,19,22,.88);
  border: 1px solid rgba(96,108,118,.5); }

/* In-game panels on a phone. The play orientation is landscape (see #rotate),
   so a full-height bottom sheet is the wrong shape — a two-column tile grid
   fits the short viewport and is reachable from either thumb. Sizes here are
   deliberately NOT multiplied by --s: these are tap targets, not decoration,
   and 44px is a floor rather than something to scale down from. */
/* Top-anchored, not centred. A landscape phone is ~390px tall and the panel is
   ~215px of that: centred, it lands squarely on top of the ARMORY button that
   opened it, so the panel could not be dismissed by the control that summoned
   it. Anchoring to the top leaves the whole bottom band — pads and action
   buttons — reachable while the shop is up. */
body.touch #buymenu { min-width: 0; width: min(600px, calc(100vw - 40px)); padding: 14px 16px;
  top: 8px; transform: translateX(-50%); }
body.touch #buymenu h3 { font-size: 15px; margin-bottom: 10px; }
body.touch #buymenu .bm-pts { font-size: 15px; }
body.touch #bm-close { width: 40px; height: 40px; font-size: 22px; }
body.touch #buy-items { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
body.touch #buy-items div { margin: 0; min-height: 48px; padding: 8px 12px; font-size: 13px; }
body.touch #buy-items .num { display: none; }   /* no number keys to press */
body.touch #buy-items .wicon { height: 15px; }
/* same reasoning: the score bar is the tap target that toggles this, so the
   panel must never cover it */
body.touch #scoreboard { min-width: 0; width: min(560px, calc(100vw - 40px)); padding: 14px 16px;
  top: 46px; transform: translateX(-50%); max-height: calc(100% - 58px); overflow-y: auto; }
body.touch #scoreboard table { font-size: 13px; }
body.touch #scoreboard th { font-size: 10px; }
body.touch #scoreboard td { padding: 7px 10px; }
body.touch #scoreboard .hdr { font-size: 14px; }
body.touch #pause { min-width: 0; width: min(420px, calc(100vw - 60px)); padding: 18px 20px; }
body.touch #pause h3 { font-size: 20px; }
body.touch #pause .pz-note { font-size: 12px; }
body.touch .pz-btns button { font-size: 13px; }

/* ---------- orientation gate ---------- */
#rotate { display: none; position: absolute; inset: 0; z-index: 30; background: #07090a;
  align-items: center; justify-content: center; text-align: center;
  color: #cfd8e6; font-family: var(--ff-head); font-weight: 800; letter-spacing: 5px; font-size: 14px; }
.rot-icon { display: block; font-size: 56px; margin-bottom: 16px; color: var(--blood-lit); }
@media (orientation: portrait) { body.touch #rotate { display: flex; } }
