/* Cross-platform layout: the touch control surface, safe-area handling, and
   the two viewport shapes style.css was never written for — a landscape phone
   (wide but only ~390 px TALL, so no width-based query ever fires) and a
   portrait one (narrow enough that the desktop HUD overlaps itself).

   Everything here is gated on `html.touch`, which touch.js sets from the
   primary pointer and then keeps in step with whatever the player actually
   uses, so a tablet with a keyboard case can change its mind mid-match. */

:root {
  /* Notches, home indicators and rounded corners. viewport-fit=cover in the
     document head is what makes these non-zero; without the padding below,
     the score bar sits under the camera housing on a landscape iPhone. */
  --sat: env(safe-area-inset-top, 0px);
  --sar: env(safe-area-inset-right, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
  --tbtn: 76px;      /* main action button */
  --ubtn: 44px;      /* utility button — the accessibility floor */
}

/* ===================== page-level gesture suppression =====================
   The canvas already declines its own gestures, but the document still owns
   pull-to-refresh, rubber-band scroll, double-tap zoom and the long-press
   callout, and every one of those fires in the middle of a firefight.

   Deliberately `manipulation` and not `none` on the document. `none` here
   would also be the correct-looking answer, and it kills double-tap zoom just
   the same — but it is one specification detail away from making the deploy
   menu unscrollable, and an unscrollable menu means the DEPLOY button cannot
   be reached and the game is not playable at all. `manipulation` keeps
   panning and pinch, drops the double-tap, and cannot fail that way.
   `overscroll-behavior` is the right tool for pull-to-refresh regardless, and
   the surfaces that genuinely must swallow every gesture opt into `none`
   individually below. */
html, body {
  overscroll-behavior: none;
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
#hud, #touchui { touch-action: none; }
/* Text that exists to be copied has to stay selectable — the share URL is the
   entire mechanism for getting a second player into your room, and the blanket
   rule above applies on desktop too. */
#menu input, .share code, #shareUrl {
  -webkit-user-select: text; user-select: text; -webkit-touch-callout: default;
}

/* ===================== safe areas =====================
   These are plain ID selectors in a stylesheet that loads last, so they beat
   style.css's own `@media (max-width: 720px)` compaction of #statusbar and
   #minimap — which would silently undo it. The small-screen values are
   therefore restated with the insets folded in, further down. */
#scorebar { margin-top: var(--sat); }
#netinfo { top: calc(8px + var(--sat)); left: calc(12px + var(--sal)); }
#killfeed { top: calc(76px + var(--sat)); right: calc(16px + var(--sar)); }
#statusbar { left: calc(20px + var(--sal)); bottom: calc(20px + var(--sab)); }
#minimap { right: calc(18px + var(--sar)); bottom: calc(18px + var(--sab)); }
#menu { padding: calc(20px + var(--sat)) calc(20px + var(--sar))
                calc(20px + var(--sab)) calc(20px + var(--sal)); }

@media (max-width: 720px) {
  #statusbar { left: calc(10px + var(--sal)); bottom: calc(12px + var(--sab)); }
  #minimap { right: calc(10px + var(--sar)); bottom: calc(10px + var(--sab)); }
}

@media (max-width: 620px) {
  /* Narrow enough that the scorebar reaches both screen edges, so the ping
     readout in the top-left corner was being drawn straight over the
     leftmost score — which since the bar started showing every player is a
     player's whole marker. Below the bar instead, above the killfeed.
     Restated here rather than in style.css for the reason at the top of
     this section: this sheet loads last and would otherwise undo it. */
  #netinfo { top: calc(60px + var(--sat)); }
}

/* ===================== which control legend to show ===================== */
.controls.touchctl { display: none; }
html.touch .controls.keyctl { display: none; }
html.touch .controls.touchctl { display: grid; }
html.touch #hintbar { display: none; }

/* ===================== touch control surface ===================== */
#touchui { position: absolute; inset: 0; pointer-events: none; }
#touchui[hidden] { display: none; }
html:not(.touch) #touchui { display: none; }

/* The stick zone is an invisible surface, not a widget: a thumb landing
   anywhere in the lower-left starts a stick under itself, which beats hunting
   for a fixed ring you cannot see without looking down. */
#tstickzone {
  position: absolute; left: 0; bottom: 0;
  width: 46%; height: 66%;
  pointer-events: auto;
}

#tstick {
  position: absolute; left: 0; top: 0;
  width: 124px; height: 124px; margin: -62px 0 0 -62px;
  transform: translate(var(--sx, -999px), var(--sy, -999px));
  border-radius: 50%;
  border: 2px solid rgba(245, 185, 59, .30);
  background: radial-gradient(circle, rgba(10, 14, 22, .38), rgba(10, 14, 22, .12));
  opacity: 0; transition: opacity .12s;
  pointer-events: none;
}
#tstick.on { opacity: 1; }

#tknob {
  position: absolute; left: 50%; top: 50%;
  width: 54px; height: 54px; margin: -27px 0 0 -27px;
  transform: translate(var(--kx, 0px), var(--ky, 0px));
  border-radius: 50%;
  background: radial-gradient(circle at 38% 34%, #ffd071, var(--amber));
  box-shadow: 0 3px 14px rgba(0, 0, 0, .6);
  opacity: 0;
}

/* ---- action cluster, bottom-right ---- */
#tactions {
  position: absolute;
  right: calc(14px + var(--sar)); bottom: calc(14px + var(--sab));
  display: grid; gap: 10px;
  grid-template-columns: auto auto;
  /* MNE fills the cell that used to be empty, so the cluster keeps the same
     footprint and FIRE stays exactly where the thumb already rests. Every
     button is placed by name rather than left to auto-placement: with four
     items and one blank cell, source order alone decided the layout. */
  grid-template-areas: "mne abl" "msl fire";
  align-items: end;
  pointer-events: none;
}
#btnMine { grid-area: mne; }
#btnAbil { grid-area: abl; }
#btnMsl { grid-area: msl; }
#btnFire { grid-area: fire; }

.tbtn {
  position: relative;
  width: var(--ubtn); height: var(--ubtn);
  display: grid; place-items: center;
  font: inherit; color: #e9eef7;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .3);
  background: rgba(10, 14, 22, .55);
  backdrop-filter: blur(6px);
  pointer-events: auto;
  touch-action: none;
  transition: transform .07s, background .12s;
}
.tbtn em { font-style: normal; font-size: 10px; letter-spacing: .1em; }
.tbtn.fire {
  width: var(--tbtn); height: var(--tbtn);
  border-color: rgba(245, 185, 59, .75);
  background: rgba(245, 185, 59, .16);
}
.tbtn.fire em { font-size: 12px; font-weight: 700; letter-spacing: .14em; color: #ffd888; }
.tbtn.down { transform: scale(.92); background: rgba(245, 185, 59, .42); }

/* Cooldown sweep: main.js writes --cd as 0..1 of the cooldown still to run,
   so the dark wedge unwinds anticlockwise as the ability comes back. */
.tbtn s {
  position: absolute; inset: 0; border-radius: 50%; text-decoration: none;
  background: conic-gradient(rgba(0, 0, 0, .68) calc(var(--cd, 0) * 360deg), transparent 0);
  pointer-events: none;
}
.tbtn.ready { border-color: rgba(126, 214, 255, .8); box-shadow: 0 0 10px rgba(126, 214, 255, .3); }

/* ---- utility row, top-right under the safe area ---- */
#tutil {
  position: absolute;
  top: calc(8px + var(--sat)); right: calc(10px + var(--sar));
  display: flex; gap: 8px;
  pointer-events: none;
}
.ubtn {
  width: var(--ubtn); height: var(--ubtn);
  font: inherit; font-size: 10px; letter-spacing: .08em; color: #cdd6e4;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, .2);
  background: rgba(10, 14, 22, .55);
  backdrop-filter: blur(6px);
  pointer-events: auto;
  touch-action: none;
}
.ubtn.down { background: rgba(245, 185, 59, .3); }
.ubtn.lit { border-color: var(--amber); color: var(--amber); }
.ubtn.off { color: #6b7484; text-decoration: line-through; }

/* MENU spells a word rather than a three-letter code, and swaps it for a
   longer one once armed, so its label is tracked in tighter to stay inside
   the same square every other utility button uses. `lit` doubles as the armed
   state: amber is already what this HUD uses for "this is live". */
#btnMenu { font-size: 9px; letter-spacing: .04em; white-space: nowrap; }

/* A fourth button reaches toward the gauges on the narrowest phones. Closing
   the gap buys the difference back without taking any button below the 44 px
   touch floor. */
@media (max-width: 380px) { #tutil { gap: 5px; } }

/* With a utility row in the top-right corner the kill feed has to start
   below it rather than behind it. */
html.touch #killfeed { top: calc(60px + var(--sat)); }

/* ===================== HUD reflow for touch =====================
   The gauges live bottom-left on a desktop, which is exactly where the drive
   stick now is, so they move to the top-left and shrink. */
html.touch {
  /* Drives .hbar, #ammo, #missiles and #abil together — see style.css. */
  --gaugew: 132px;
}
html.touch #statusbar {
  top: calc(30px + var(--sat)); bottom: auto;
  left: calc(10px + var(--sal));
  gap: 6px;
}
html.touch .gauge .glabel { font-size: 8px; letter-spacing: .18em; margin-bottom: 2px; }
html.touch .gauge .glabel small { display: none; }
html.touch .hbar { height: 16px; }
html.touch .hbar b { font-size: 10px; }
html.touch #abil { height: 17px; }
html.touch #abil b { font-size: 9px; letter-spacing: .1em; }
html.touch #ammo { gap: 3px; }
html.touch #ammo i { height: 10px; }
html.touch #missiles i { height: 9px; }

/* The minimap cannot stay bottom-right under the fire button. Centre-bottom
   is the one place on a phone that neither thumb covers. */
html.touch #minimap {
  right: auto; left: 50%; transform: translateX(-50%);
  bottom: calc(8px + var(--sab));
  width: 104px; height: 104px; padding: 4px;
}

/* ===================== landscape phone =====================
   Wide but short. `max-width: 720px` in style.css never matches an 852 px
   landscape iPhone, so this is the query that actually catches it. */
@media (orientation: landscape) and (max-height: 520px) {
  #scorebar .team { padding: 5px 12px; gap: 8px; }
  #scorebar .tscore { font-size: 21px; }
  #scorebar .tname { font-size: 10px; max-width: 9ch; }
  #scorebar .clock { padding: 4px 12px; min-width: 74px; }
  #scorebar .clock span { font-size: 15px; }
  #centre { top: 26%; }
  #killfeed { font-size: 11px; gap: 3px; }
  #killfeed div { padding: 3px 7px; }
  #hintbar { display: none; }
  /* Narrow enough to leave the right-hand action cluster showing: the
     scoreboard is a hold-to-read overlay, and a player checking it should not
     lose sight of the FIRE button they are about to go back to. */
  #scoreboard {
    min-width: 0; width: min(460px, calc(100% - 150px));
    max-height: calc(100% - 24px); overflow: auto; padding: 12px 16px;
  }
  #scoreboard table { font-size: 12px; }
  #scoreboard td { padding: 4px 0; }
  /* And if it ever does reach them, the buttons stay on top. */
  html.touch #tactions, html.touch #tutil { z-index: 3; }

  html.touch #statusbar { top: calc(26px + var(--sat)); }
  html.touch #minimap { width: 88px; height: 88px; }
  :root { --tbtn: 66px; --ubtn: 40px; }
}

/* ===================== portrait phone =====================
   The score bar spans the full width here rather than floating in the middle,
   so everything else in the top band has to start below it instead of beside
   it — roughly 46 px of bar plus the inset. */
@media (orientation: portrait) and (max-width: 560px) {
  #scorebar { width: 100%; border-radius: 0; }
  #scorebar .team { flex: 1; padding: 7px 10px; justify-content: center; }
  #centre { top: 32%; }
  #scoreboard {
    min-width: 0; width: calc(100% - 24px);
    max-height: 62%; overflow: auto; padding: 14px 12px;
  }
  #scoreboard table { font-size: 12px; }

  /* Below the full-width score bar, not on top of its RED side. */
  html.touch #tutil { top: calc(56px + var(--sat)); }
  html.touch #killfeed { top: calc(108px + var(--sat)); font-size: 11px; }
  /* Likewise: the gauges cannot start at 30px when the bar owns the top 46. */
  html.touch #statusbar { top: calc(58px + var(--sat)); }

  /* Two thumbs on a narrow screen leave a band across the middle and nothing
     else, so the stick zone gets the bottom-left corner. The gauges stay at
     the TOP — putting them above the stick meant the hull bar, the one thing
     you most need to read, sat under the driving thumb. The minimap has to
     clear the stick zone entirely for the same reason, so it goes to the
     right-hand edge above the action cluster. */
  html.touch #tstickzone { width: 52%; height: 34%; }
  html.touch #minimap {
    left: auto; transform: none;
    right: calc(10px + var(--sar));
    bottom: calc(210px + var(--sab));
    width: 84px; height: 84px;
  }
}

/* ===================== menu on a small screen ===================== */
@media (max-width: 560px), (orientation: landscape) and (max-height: 520px) {
  .panel { padding: 18px 16px 16px; }
  .panel h1 { font-size: 22px; }
  .tag { margin: 6px 0 14px; }
  .field { margin-bottom: 10px; }
  #playBtn { padding: 17px; }
  .controls { grid-template-columns: 1fr; gap: 5px; font-size: 11px; }
  .rules { font-size: 11px; line-height: 1.5; }
}

@media (max-width: 420px) {
  .vehrow, .maprow { grid-template-columns: 1fr; }
}

/* Touch sizing has to key off the POINTER, not the viewport. A tablet is
   1194x834 in landscape and 834x1194 in portrait, so it matches no
   width-based or height-based phone query in either orientation — and would
   otherwise get desktop-sized 15px inputs and 30px-tall chips under a finger.
   Anything under 16px also makes iOS zoom the page on focus, and that zoom
   persists into the match. */
@media (pointer: coarse) {
  .field input { font-size: 16px; padding: 13px; min-height: 48px; }
  .vcard, .mapchip, .modechip { min-height: 48px; }
  #playBtn { min-height: 52px; }
  .ubtn, .tbtn { min-width: 44px; min-height: 44px; }
}

/* The panel is taller than a landscape phone, so DEPLOY is below the fold and
   reads as missing. */
@media (orientation: landscape) and (max-height: 520px) {
  #playBtn {
    position: sticky; bottom: 0; z-index: 2;
    box-shadow: 0 -12px 22px rgba(11, 16, 25, .92);
  }
}

/* A finger cannot hover, so hover-only affordances must not be the only way
   to see that something is interactive. */
@media (hover: none) {
  .vcard:hover, .mapchip:hover, .modechip:hover { border-color: rgba(255, 255, 255, .13); }
  .vcard.sel:hover { border-color: var(--amber); }
  .mapchip.sel:hover { border-color: var(--amber); }
  .modechip.sel:hover { border-color: var(--amber); }
  #playBtn:hover { filter: none; }
}
