/* mobile.css — responsive scaling for phones/tablets + the on-screen touch
   pad built by touch.js. Loaded after style.css/anim.css, so rules here win
   the cascade and act as overrides/additions on top of the desktop layout.
   Uses the shared CSS variables from style.css:1 — no new colors. */

/* ===================================================================
   Touch pad (built in JS as document.body > .sz-touchpad).
   Hidden by default; touch.js toggles its own ".hidden" (existing global
   rule) to show it on touch devices. The pointer/hover media query below
   is a CSS-level safety net so it can never show on a mouse-only device
   even if JS logic changes.
   =================================================================== */
:root { --sz-pad-h: 168px; }

.sz-touchpad {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 150; /* below .modal (200), above game content */
  display: none;
  justify-content: space-between;
  align-items: flex-end;
  gap: 10px;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
  padding-left: calc(12px + env(safe-area-inset-left, 0px));
  padding-right: calc(12px + env(safe-area-inset-right, 0px));
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  pointer-events: none; /* only the buttons themselves are interactive */
}
.sz-touchpad.hidden { display: none !important; }
@media (hover: none) and (pointer: coarse) {
  .sz-touchpad:not(.hidden) { display: flex; }
}

.sz-tp-group {
  pointer-events: auto;
  display: grid;
  gap: 8px;
  width: min(46vw, 220px);
}
/* Actions, left thumb: rotate takes the whole outer edge because that is where
   the thumb rests, with hold and hard drop stacked inboard of it. */
.sz-tp-acts {
  grid-template-columns: 1fr 62px;
  grid-template-areas: "rotate hold" "rotate hard";
}

/* Directions, right thumb: soft drop sits directly ABOVE the arrows, so
   sliding from a direction into a drop is one movement rather than a reach
   across the pad. */
.sz-tp-dirs {
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "s s" "l r";
}
.sz-tp-left-btn { grid-area: l; }
.sz-tp-right-btn { grid-area: r; }
.sz-tp-soft { grid-area: s; }
.sz-tp-hold { grid-area: hold; }
.sz-tp-rotate { grid-area: rotate; }
.sz-tp-hard { grid-area: hard; }

.sz-tp-btn {
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  min-height: 56px;
  font: inherit;
  font-weight: 700;
  color: var(--text);
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.92;
}
.sz-tp-move { font-size: 1.7rem; }
.sz-tp-rotate {
  font-size: 2.1rem;
  height: 100%;
  background: linear-gradient(160deg, var(--panel-2), rgba(34, 211, 238, 0.16));
  border-color: var(--accent);
}
.sz-tp-hard { font-size: 0.85rem; letter-spacing: 0.02em; }
.sz-tp-hold { font-size: 0.75rem; letter-spacing: 0.04em; }
.sz-tp-soft { font-size: 0.95rem; }

.sz-tp-btn.pressed,
.sz-tp-btn:active {
  transform: scale(0.94);
  background: #232842;
  border-color: var(--accent);
  opacity: 1;
}

/* ===================================================================
   Board scaling: the canvas has a fixed pixel width/height (10*cellSize x
   20*cellSize) set in JS. Constraining one axis to a relative unit and
   leaving the other "auto" scales it using the canvas's own intrinsic
   pixel ratio — always exactly 1:2, never distorted, on every screen.
   =================================================================== */
.arena-wrap { width: 100%; }
.arena { max-width: 100%; }
.board-wrap { max-width: 100%; }
canvas.board {
  max-width: 100%;
  height: auto;
}

/* Hide the keyboard-only hint on touch devices; the pad replaces it. */
@media (hover: none) and (pointer: coarse) {
  .controls-hint { display: none; }
  #game {
    padding-bottom: calc(var(--sz-pad-h) + env(safe-area-inset-bottom, 0px));
  }
}

/* ===================================================================
   Phones (portrait). Reflow .side into a compact horizontal strip below
   the board (its actual DOM position already), keep both versus boards
   visible side-by-side by shrinking rather than stacking, and use dvh so
   mobile browser chrome doesn't clip the board.
   =================================================================== */
@media (max-width: 760px) {
  body {
    padding: 4px;
    align-items: flex-start;
    min-height: 100vh;
    min-height: 100dvh;
  }
  #app { width: 100%; }

  /* The multi-line keyboard hint doesn't fit this layout and collides with the
     reflowed .side strip. It's already hidden on touch devices (where the pad
     replaces it); hide it at narrow widths generally, so a narrow desktop
     window gets the same clean layout instead of an overlapping one. */
  .controls-hint { display: none; }

  #menu {
    width: min(420px, 96vw);
    padding: 22px 16px;
    margin: 0 auto;
  }

  /* Board hard against the top. The deck is taken OUT of the layout flow and
     laid over the top edge as a strip, and the player name overlays the
     board's top edge (those rows are empty until you're already losing).
     Nothing above the board costs height. */
  .topbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    max-width: none;
    margin: 0;
    z-index: 120;            /* above the board, below .modal (200) */
    pointer-events: none;    /* only the deck itself is clickable */
  }
  .topbar > * { pointer-events: auto; }

  /* Full-bleed here rather than a hung marquee: there is no room either side
     of the board for a shape to be centred in, so the deck becomes the strip
     across the top of the screen instead — and a translucent one, because it
     lies over the name-tag band at the top of the board rather than pushing
     the board down. Those rows are empty until you're already losing.

     Written against #deck so it outranks the themes' moulded-plastic skin,
     which loads after this file: on a phone the deck is an overlay control,
     not a piece of the cabinet, and neither theme's frame belongs here. */
  :root[data-theme] #deck {
    width: 100%;
    min-height: 0;
    padding: 3px 2px 4px;
    border: none;
    border-radius: 0;
    background: rgba(8, 11, 16, 0.58);
    backdrop-filter: blur(5px);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.07);
  }
  :root[data-theme] #deck .deck-bay-mid { border-inline: none; box-shadow: none; }
  .deck-bay { padding: 0 6px; gap: 6px; }
  /* Everything up here now sits on the same dark strip in both themes. */
  :root[data-theme] #deck .mp-name,
  :root[data-theme] #deck .sb-name { color: #eef4e4; }
  :root[data-theme] #deck .burger-bars i { background: #eef4e4; }
  /* Nothing here is worth a pixel of board: the wordmark goes, the crest goes,
     and the mode plate keeps only its name. */
  .deck-mark,   /* the whole mark, so its hit area goes with the artwork */
  .deck-wordmark,
  .deck-crest,
  .mp-note,
  .mc-label,
  .sb-name { display: none; } /* whose side is which is obvious from the board */
  .deck[data-mode="battle"] .deck-bay-end:not(:has(#btn-rematch:not(.hidden))) { padding: 0; }
  /* The type sizes have to be written against #deck as well: both themes set
     .mc-time's size and the clock is a 2rem readout on a desktop marquee. On a
     37px strip laid over the playfield it has to be a chip. */
  :root[data-theme] #deck .mp-name { font-size: 0.66rem; }
  :root[data-theme] #deck .match-clock { padding: 1px 8px 2px; min-width: 66px; gap: 2px; }
  :root[data-theme] #deck .mc-time { font-size: 1.1rem; }
  .mc-drain { height: 3px; }
  .scoreboard { gap: 8px; }
  .ko-pips { gap: 3px; }
  .ko-pip { width: 7px; height: 7px; }

  .name-tag {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 3;
    margin: 0;
    padding: 1px 4px;
    justify-content: center;
    gap: 5px;
    font-size: 0.62rem;
    line-height: 1.4;
    pointer-events: none;
    /* Fades out downward so it never reads as a solid bar over the playfield. */
    background: linear-gradient(180deg, rgba(11, 13, 23, 0.9), rgba(11, 13, 23, 0));
  }
  .name-tag .badge { font-size: 0.55rem; padding: 0 4px; }
  .topbar button { padding: 6px 10px; font-size: 0.8rem; }
  /* Icon only — "MENU" is worth its width on a desktop deck and not on a
     phone. Kept a full 34px tall so it stays a real touch target. */
  :root[data-theme] #deck .burger {
    height: 30px;
    padding: 0 9px;
    gap: 0;
    border-radius: 8px;
  }
  .topbar .burger-text { display: none; }
  .topbar .burger-bars { width: 15px; gap: 3px; }
  .topbar .burger-bars i { height: 1.5px; }
  /* A cream cabinet key with a lip is a desktop-deck idea; on the strip it is
     just a bright blob over the playfield. */
  :root[data-theme] #deck .burger {
    background: rgba(255, 255, 255, 0.1);
    border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: none;
  }
  :root[data-theme] #deck .burger:active { transform: none; }
  :root[data-theme] #deck .match-clock {
    background: rgba(0, 0, 0, 0.3);
    border: none;
    box-shadow: none;
  }
  /* Every pixel here comes straight off the board. */
  .status-bar { margin-top: 4px; font-size: 0.75rem; min-height: 0; }
  #net-stats { margin-top: 4px; }
  #net-stats .chip { font-size: 0.6rem; padding: 2px 6px; }

  /* No height cap here: the board canvas is capped on its own below, and a cap
     on the wrapper only clipped the card so the Next/Hold/Special strip spilled
     out the bottom of it. */
  .arena-wrap {
    display: flex;
    justify-content: center;
  }
  .arena {
    gap: 8px;
    flex-wrap: nowrap;
    width: 100%;
    align-items: stretch;
  }

  /* Board left, a NARROW column of chrome on the right. Stacking Next/Hold/
     stats underneath the board (an earlier version of this file) ate the
     vertical space the board actually wants — the play field is the thing you
     need to see, so everything else is squeezed into a ~48px right column. */
  .player {
    flex-direction: row;
    align-items: stretch;
    padding: 4px;
    gap: 5px;
    flex: 1 1 0;
    min-width: 0;
  }
  .garbage-meter { width: 5px; height: auto; align-self: stretch; order: 0; }

  .board-wrap {
    align-self: center;
    flex: 1 1 auto;
    min-width: 0;
    /* Back to stretching: here the canvas is sized from a definite height and
       centred inside the wrapper, and the surrounding widths are computed from
       the viewport — the desktop shrink-to-fit rule doesn't apply. */
    width: auto;
    /* Must stay a COLUMN: .name-tag is a normal-flow child here, so a row
       direction would park it beside the board instead of above it. */
    display: flex;
    flex-direction: column;
    align-items: center;
  }
  .board-col { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }

  /* The board must scale UP as well as down. `max-height`/`max-width` alone are
     upper bounds, so the canvas just sat at its intrinsic 300x600 and left dead
     space around it on a roomy phone. A DEFINITE height of
     min(vertical room, 2 x horizontal room) fills whichever axis runs out
     first, and `width: auto` keeps the 1:2 ratio exact either way. */
  .arena {
    --sz-side-w: 48px;
    /* Measured, not guessed: one rig spends 8px of body padding, 8px of its own
       padding, 10px of gaps and a 6px shell border on either side of the board,
       which is 32px and not 56. The extra 24px was a slice of playfield nothing
       was using. Verified for horizontal overflow at 320, 390 and 430. */
    --sz-board-w: calc(100vw - var(--sz-side-w) - 34px);   /* solo: one board */
    --sz-board-reserve: 74px;              /* under-stats + status + net chips */
  }
  /* Versus on a phone: YOUR board full size, theirs an inset.
     =====================================================================
     Two equal boards do not fit side by side at this width and never did.
     Measured, each one came out 60-114px wide and used 21-25% of the screen,
     against 73% for solo - the worst view in the game by a distance, and no
     constant was going to buy that back because the side columns spend the
     width before the boards get any.

     So the phone gets the layout the original mobile Battle used: your field
     takes the whole width, and the opponent is a small inset in the top right
     corner. It overlaps the top of your own board, which is fine for the same
     reason the deck already overlays it - those rows are empty until you are
     already losing, and by then you have bigger problems than the inset.

     Not applied to the free-for-all: startTrio sets .versus AND .trio, and
     three boards is a different problem with a different answer. */
  .arena.versus:not(.trio) {
    display: block;
    position: relative;
    /* Your board now has the room solo has. */
    --sz-board-w: calc(100vw - var(--sz-side-w) - 34px);
    /* But not quite solo's height: your rig also carries the Score/Lines row
       under the board and the latency chips below that, neither of which solo
       shows. Measured, adjusted, measured again: 84px is what it actually is. */
    --sz-board-reserve: calc(136px + var(--sz-pad-h));
  }
  /* Your side column moves to the LEFT of your board, because the inset lands
     on the top right and your Next pod was underneath it. The rig is
     [meter, board, side], so reversing the row puts the column outboard on the
     left and leaves the top-right corner of the board free for the opponent. */
  .arena.versus:not(.trio) .player.mine {
    width: 100%;
    flex-direction: row-reverse;
  }
  .arena.versus:not(.trio) .player:not(.mine) {
    position: absolute;
    top: 0;
    right: 0;
    width: 38%;
    z-index: 6;
    padding: 3px;
    gap: 3px;
    opacity: 0.94;
  }
  /* The inset is a glance, not a workstation: their Next, Hold, specials and
     garbage meter all go, because at this size they are unreadable anyway and
     every one of them is width taken off the board they surround. */
  .arena.versus:not(.trio) .player:not(.mine) .side,
  .arena.versus:not(.trio) .player:not(.mine) .garbage-meter { display: none; }
  .arena.versus:not(.trio) .player:not(.mine) canvas.board {
    width: 100%;
    height: auto;
    max-height: none;
  }
  .arena.versus:not(.trio) .player:not(.mine) .under-stats { display: none; }

  /* Three boards abreast keep the old shared-width sums. */
  .arena.versus.trio {
    --sz-board-w: calc((100vw - 2 * var(--sz-side-w) - 104px) / 2);
  }
  canvas.board {
    width: auto;
    max-width: 100%;
    height: min(calc(100vh - var(--sz-board-reserve)), calc(var(--sz-board-w) * 2));
    height: min(calc(100dvh - var(--sz-board-reserve)), calc(var(--sz-board-w) * 2));
  }

  /* The right column: everything here is deliberately tiny. */
  .side {
    flex: 0 0 var(--sz-side-w);
    width: var(--sz-side-w);
    min-width: 0;
    flex-direction: column;
    align-items: center;
    gap: 4px;
  }
  .side > div { width: 100%; }
  .side h3 { font-size: 0.42rem; letter-spacing: var(--display-spacing); margin: 0 0 2px; text-align: center; }
  .side canvas.mini { display: block; margin: 0 auto; }
  .side canvas[data-hold] { width: auto; max-width: 100%; max-height: 24px; }
  .side canvas[data-next] { width: auto; max-width: 100%; max-height: 54px; }
  .slot { padding: 2px; display: flex; justify-content: center; }
  .side .stat { margin: 0; text-align: center; }
  .side .stat .label { font-size: 0.42rem; letter-spacing: 0.5px; }
  .side .stat .value { font-size: 0.7rem; }

  /* Versus keeps Score/Lines under the board — one thin line, not a block. */
  .under-stats { gap: 6px; }
  .under-stats .label { font-size: 0.42rem; letter-spacing: 0.5px; }
  .under-stats .value { font-size: 0.7rem; }

  /* In the reflowed strip the specials panel gets a full-width row of its own
     and goes back to a horizontal bar — here the space is wide, not tall. The
     keyboard hint is dropped since this layout is primarily touch. */
  .side > [data-spec-mount] { width: 100%; min-width: 0; }
  .side .spec-bar { flex-direction: column; align-items: stretch; gap: 3px; padding: 4px; }
  .side .spec-meter { flex: none; width: 100%; height: 5px; }
  .side .spec-slots { justify-content: center; gap: 3px; }
  /* The interactive slots are <button>s and inherit the global button padding.
     As flex items their automatic `min-width: auto` floor is min-content, which
     silently overrode the width here and pushed them outside the column — hence
     the explicit padding/min-* reset. The opponent's mirror uses plain divs and
     never hit this. */
  .side .spec-slot {
    width: 18px;
    height: 18px;
    padding: 0;
    min-width: 0;
    min-height: 0;
    flex: 0 0 auto;
  }
  .side .spec-slot .si { font-size: 0.65rem; }
  .side .spec-slot .sk { display: none; }
  .stat { margin-bottom: 0; text-align: center; }
  .stat .label { font-size: 0.58rem; }
  .stat .value { font-size: 1rem; }
  .side h3 { font-size: 0.52rem; margin-bottom: 2px; }

  .name-tag { font-size: 0.85rem; margin-bottom: 4px; }
  .status-bar { margin-top: 8px; font-size: 0.85rem; }
  .specials { margin-top: 8px; }

  .chat {
    left: 8px;
    right: 8px;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    width: auto;
  }
  .chat-log { height: 100px; }
}

@media (hover: none) and (pointer: coarse) and (max-width: 760px) {
  .chat { bottom: calc(var(--sz-pad-h) + 8px + env(safe-area-inset-bottom, 0px)); }
}

/* Extra-tight phones (~360-390px wide). */
@media (max-width: 420px) {
  #menu { padding: 18px 12px; }
  h1 { font-size: 2rem; }
  .arena { gap: 6px; }
  .player { padding: 6px; gap: 4px; }
  .side > div { min-width: 44px; }
  .sz-tp-group { width: min(48vw, 190px); }
  .sz-tp-btn { min-height: 56px; }
  .sz-tp-acts { grid-template-columns: 1fr 54px; }
}

/* ===================================================================
   Landscape phones / small tablets: height is the scarce resource, not
   width, so drive the board by height instead and push the pad to the
   screen edges so it doesn't eat vertical space.
   =================================================================== */
@media (max-height: 500px) and (orientation: landscape) {
  body { padding: 6px; align-items: center; min-height: 100vh; min-height: 100dvh; }
  #menu { padding: 14px; max-height: 92vh; overflow-y: auto; }

  .topbar { margin-bottom: 6px; }
  .controls-hint { display: none; }
  .status-bar { margin-top: 4px; min-height: 0; }

  .arena-wrap {
    max-height: calc(100dvh - 70px);
    max-height: calc(100vh - 70px);
  }
  .arena { gap: 10px; flex-wrap: nowrap; align-items: center; }
  .player { padding: 8px; gap: 8px; }
  .side { min-width: 74px; gap: 8px; }

  .board-wrap {
    max-height: calc(100dvh - 90px);
    max-height: calc(100vh - 90px);
  }
  canvas.board {
    height: calc(100dvh - 90px);
    height: calc(100vh - 90px);
    width: auto;
    max-width: 40vw;
    max-height: 100%;
  }

  .sz-touchpad {
    align-items: center;
    padding-top: 6px;
    padding-bottom: 6px;
  }
  .sz-tp-group { width: min(30vw, 180px); }
  .sz-tp-btn { min-height: 48px; }

  #game { padding-bottom: 0 !important; }
  .chat { bottom: 6px; max-height: 40vh; }
  .chat-log { height: 70px; }
}

/* ===================================================================
   Tablets: desktop layout mostly works, just keep it from ever exceeding
   the viewport and give the pad a bit more room.
   =================================================================== */
@media (min-width: 761px) and (max-width: 1100px) {
  .arena { gap: 16px; }
  .sz-tp-group { width: min(30vw, 240px); }
}

/* The touch pad is fixed to the bottom and #game reserves --sz-pad-h for it, so
   that height isn't available to the board. Declared last so it wins over the
   base reserve above. */
@media (hover: none) and (pointer: coarse) {
  .arena { --sz-board-reserve: calc(52px + var(--sz-pad-h)); }
}

/* Three boards abreast need a narrower share of the width than two. */
@media (max-width: 760px) {
  .arena.trio { --sz-board-w: calc((100vw - 3 * var(--sz-side-w) - 92px) / 3); }
  .arena.trio .side { --sz-side-w: 38px; }
  .arena.trio .player { padding: 3px; gap: 3px; }
  .arena.trio .name-tag { font-size: 0.52rem; }
  .arena.trio .under-stats .value { font-size: 0.6rem; }
}
