/* ==========================================================================================
   devices.css — multi-device layer (loaded last). Desktop Chrome / Edge / Firefox / Safari, iPad and Android tablets
   in landscape, phones in landscape (≥ 640×360 CSS px). js/ui/device.js puts the feature classes on <html>
   (sp-touch, sp-coarse, sp-hover / sp-no-hover, sp-fs, sp-standalone, sp-reduced-motion) — never UA sniffing.

   1. no page zoom / scroll / pull-to-refresh while playing (touch-action, overscroll-behavior, callouts)
   2. safe-area insets (notches, rounded corners, home indicator): the HUD and every screen stay inside them while the
      board and the backdrops stay full-bleed
   3. touch: every small control gets an invisible ≥ 44 px hit area (::before, no layout change); on short touch
      screens (phones) the most used controls also grow visually
   4. reduced motion extras; fullscreen button
   ========================================================================================== */

:root {
  --sa-t: env(safe-area-inset-top, 0px);
  --sa-r: env(safe-area-inset-right, 0px);
  --sa-b: env(safe-area-inset-bottom, 0px);
  --sa-l: env(safe-area-inset-left, 0px);
  --tap-min: 44px;
}

/* ---- 1. gestures ------------------------------------------------------------------------------------------------- */
html, body { overscroll-behavior: none; }
/* pan only: no pinch-zoom / double-tap zoom anywhere (scrollable lists still scroll); the field canvas uses none */
html { touch-action: pan-x pan-y; }
body { -webkit-touch-callout: none; }
button, a, label, summary, [role="button"], [role="tab"], [role="option"], .scard, .lvcard, .dband, .bond, .pavatar { touch-action: manipulation; }
img { -webkit-user-drag: none; }
.gm__field, .gm__field canvas, .ff, .fwheel, .fwheel__dia { touch-action: none; }
/* the DOM fallback board drags with pointer events too */
.ff-piece, .ff-slot, .ff-tile { touch-action: none; -webkit-user-select: none; user-select: none; }
input, textarea, select { -webkit-user-select: text; user-select: text; }

/* ---- 2. safe areas ------------------------------------------------------------------------------------------------ */
/* the in-match HUD layer sits inside the safe area; the field (canvas) below it stays full-bleed */
.gm__hud { top: var(--sa-t); right: var(--sa-r); bottom: var(--sa-b); left: var(--sa-l); }
/* the selected unit's underframe (ui/underframe.js) is placed at the tile's CLIENT px (view.tileScreen) inside the HUD
   layer: step back over the HUD's safe-area offset so it stays on its unit on a notched phone */
.gm__hud > .uframe { margin-left: calc(-1 * var(--sa-l)); margin-top: calc(-1 * var(--sa-t)); }
/* the shop bar keeps its place at the bottom edge (it may reach into the home-indicator strip): raised by the bottom
   inset it covered ~3/4 of the bench pads 2–9 on a notched phone (user playtest #4 item 1), and a bench piece is
   pressed / dropped on by its tile. The prep camera keeps the bench clear of the bar (ui/fieldHost.js hudBands →
   render/projection.js clearHud, user playtest #5 item 9). Its right edge stays inside the inset (the notch / rounded
   corner). */
.gm__hud > .shopbar { bottom: calc(.2rem - var(--sa-b)); }
.gm > .spov { left: calc(2.8rem + var(--sa-l)); right: var(--sa-r); }
/* every other screen is laid out inside the safe area (the app backdrop fills the notch strip) */
.screen:not(.gm) { top: var(--sa-t); right: var(--sa-r); bottom: var(--sa-b); left: var(--sa-l); }
.guide, .awayov { padding: var(--sa-t) var(--sa-r) var(--sa-b) var(--sa-l); }
/* (in a match the toasts sit under the top bar: components.css .sp-in-match .toast-host already adds --sa-t) */
html:not(.sp-in-match) .toast-host { margin-top: var(--sa-t); }
.conn-banner { margin-bottom: var(--sa-b); }
.rotate-hint { padding: calc(24px + var(--sa-t)) calc(24px + var(--sa-r)) calc(24px + var(--sa-b)) calc(24px + var(--sa-l)); }

/* ---- 3. touch targets ---------------------------------------------------------------------------------------------- */
/* An invisible hit area of at least --tap-min around small controls on touch screens: centred, never smaller than the
   control, no layout change. Only controls that do not use ::before themselves are listed. */
:where(.sp-coarse) :where(.tapx, .gtop__exit, .gtop__iconbtn, .enemybtn, .readybtn, .gm__gear, .fsbtn, .ewheel__btn, .ewheel__nav,
  .toolbtn, .funds__collapse, .team__btn, .effect, .vswitch__arrow, .edrawer__close, .dpanel__close, .bpop__close,
  .modal__close, .uf__btn, .chud__back, .tabs__tab, .btn, .pill-btn, .title-guide, .stephead__guide, .set-toggle, .set-seg button) {
  position: relative;
}
.sp-coarse :is(.tapx, .gtop__exit, .gtop__iconbtn, .enemybtn, .readybtn, .gm__gear, .fsbtn, .ewheel__btn, .ewheel__nav,
  .toolbtn, .funds__collapse, .team__btn, .effect, .vswitch__arrow, .edrawer__close, .dpanel__close, .bpop__close,
  .modal__close, .uf__btn, .chud__back, .tabs__tab, .btn, .pill-btn, .title-guide, .stephead__guide, .set-toggle, .set-seg button)::before {
  content: '';
  position: absolute; left: 50%; top: 50%; z-index: 0;
  width: max(100%, var(--tap-min)); height: max(100%, var(--tap-min));
  transform: translate(-50%, -50%);
  background: transparent; border: 0; box-shadow: none; clip-path: none; pointer-events: auto;
}
/* The 交流 panel's pager (‹ dots ›) sits in the strip under the emote cells (panel y 1.97–2.31rem, css/emotes.css). Its
   hit areas stay inside that strip and never overlap each other: a centred 44 px area of ‹ / › covered the centres of
   the bottom-left / bottom-right emotes (a tap there turned the page or hit the disabled ‹), and 28 px dot areas 0.21rem
   apart covered the neighbouring dot (a tap on dot N opened page N+1). ‹ / › grow outwards (away from the dots), the
   dots only up to half the gap. Selectors ≥ the specificity of the generic hit-area rule above. */
.sp-coarse .ewheel__panel .ewheel__nav::before { top: .03rem; bottom: -.15rem; height: auto; transform: none; }
.sp-coarse .ewheel__panel .ewheel__nav.is-prev::before { left: auto; right: 0; }
.sp-coarse .ewheel__panel .ewheel__nav.is-next::before { left: 0; right: auto; }
.sp-coarse .ewheel__dot::before { inset: -.02rem -.05rem -.2rem; top: -.02rem; left: -.05rem; right: -.05rem; bottom: -.2rem; width: auto; height: auto; transform: none; }

/* Phones in landscape (short touch screens: 1rem ≈ 40 px here): the most used controls grow a little so they are
   comfortable to hit and to read, without changing the official layout. */
@media (max-height: 600px) and (pointer: coarse), (max-height: 600px) and (any-pointer: coarse) {
  .readybtn { height: max(.56rem, 34px); }
  .toolbtn { min-height: max(.5rem, 30px); }
  .gm__gear { width: max(.56rem, 34px); height: max(.56rem, 34px); }
  /* ⚙ / 📖 / ⛶ keep their desktop proportion (half the button) instead of an 11 px glyph in the grown button */
  .gm__corner .gm__gear .icon { width: max(.28rem, 17px); height: max(.28rem, 17px); }
  .gtop__exit { min-width: max(.56rem, 34px); min-height: max(.56rem, 34px); }
  .gtop__iconbtn.has-sprite, .enemybtn.has-sprite { height: max(.46rem, 26px); width: calc(max(.46rem, 26px) * 35 / 29); }
  .gtop__iconbtn.has-sprite.is-wide, .enemybtn.has-sprite.is-wide { width: calc(max(.46rem, 26px) * 61 / 29); }
  .gtop__iconbtn:not(.has-sprite), .enemybtn:not(.has-sprite) { height: max(.46rem, 26px); min-width: max(.46rem, 26px); }
  .ewheel__panel { scale: 1.3; transform-origin: 0 100%; }
  .fwheel__cancel { min-height: 30px; }
  .set-toggle, .set-seg button { height: max(.38rem, 30px); }
  /* a taller range input whose visible track stays thin: transparent borders are part of the hit area */
  .set-range { height: 30px; border: 11px solid transparent; border-left-width: 0; border-right-width: 0; background-clip: padding-box; box-shadow: inset 0 0 0 1px var(--line-2); }
  .field--lg .field__box { height: max(.68rem, 40px); }
}

/* ---- 4. misc ------------------------------------------------------------------------------------------------------ */
.fsbtn { display: grid; place-items: center; padding: 0; background: rgba(8, 11, 10, .85); border: 1px solid var(--line-2); color: var(--text-lo); transition: color var(--t-fast), border-color var(--t-fast); }
.fsbtn .icon { width: .26rem; height: .26rem; }
.fsbtn:hover, .fsbtn[aria-pressed="true"] { color: var(--mint-400); border-color: var(--mint-700); }
.title-fs { width: .4rem; height: .4rem; margin-left: .06rem; }
/* standalone / fullscreen: the browser bars are gone, nothing to reserve */
.sp-standalone .rotate-hint__micro::after { content: ' · PWA'; }

/* reduced motion: camera-free UI pieces that animate continuously stop (the global rule in theme.css shortens the rest) */
@media (prefers-reduced-motion: reduce) {
  .team__status.is-gold, .ff-tile--gate, .title-bg__sweep, .boot__hex { animation: none !important; }
}
.sp-reduced-motion .team__status.is-gold, .sp-reduced-motion .ff-tile--gate { animation: none; }

/* (the shop cards have no ⓘ corner: its invisible 44 px touch area — the 30 px override here lost on specificity to the
   generic rule above — covered the bottom-right quarter of a phone's 67 × 97 px card and half of its 确认购买 strip, so
   the confirming tap re-opened the detail instead; user playtest #6 item 10) */

/* Narrow viewports (< 768 CSS px: the root scale is clamped at 40 px, so the layout is narrower than the 19.2 rem
   design): the shop bar would cover the corner's ⚙ / 📖 / ⛶ buttons — they wrap into a row above the 交流 button. */
/* The left-docked detail card then ends above that two-row corner (.24rem + 交流 + .1rem gap + ⚙ row + .1rem): at its
   desktop bottom (1.02rem) it hid ⚙ / 📖 / ⛶. (gameLogic panelSlots keeps the taller desktop slot: conservative.) */
@media (max-width: 767px) {
  .gm__corner { flex-wrap: wrap-reverse; align-content: flex-start; width: max(72px, calc(3 * .56rem + .2rem)); }
  .dpanel:not(.dpanel--right) { bottom: calc(.44rem + max(1.51rem, 72px) * 55 / 151 + .56rem); }
}
@media (max-width: 767px) and (pointer: coarse), (max-width: 767px) and (any-pointer: coarse) {
  .gm__corner { width: max(96px, calc(3 * max(.56rem, 34px) + .2rem)); }
  .dpanel:not(.dpanel--right) { bottom: calc(.44rem + max(1.51rem, 96px) * 55 / 151 + max(.56rem, 34px)); }
}
/* Mobile detail panel dimensions & clearance (vivo V2520A: 761x360 dpr 3) */
:is(.sp-touch, .sp-coarse) .rwtag__micro { display: none; }
@media (max-width: 767px), (max-height: 460px) {
  .brief-stage { flex-wrap: wrap; gap: .06rem .12rem; }
  .brief-stage__k { width: 100%; justify-content: space-between; }
  .brief-stage__name { width: 100%; }
  .gm__bonds { top: max(1.1rem, 36px); }
  .dpanel {
    width: max(4.9rem, 210px);
    left: max(2.3rem, 76px);
    top: max(2.1rem, 90px);
  }
  .dstat__k { font-size: max(.12rem, 8px); }
  .dstat__k-full { display: none; }
  .dstat__k::after { content: attr(data-short); }
  .dstat__v { font-size: max(.17rem, 10px); }
  .dstat small { font-size: max(.11rem, 8px); }
  .dhead__name { font-size: max(.32rem, 12px); }
  .dhead__class, .dhead__pos, .dtag-elite, .dtag-token, .dtag-kind, .drank { font-size: max(.13rem, 8px); }
  .dtrait, .dtext, .dsec__title, .dskill__name, .dmodule__name, .ditem__text b, .ditem__desc, .dtalent b { font-size: max(.14rem, 8px); }
  .dsp, .dsp__num, .dmodule__type, .dtag-loadout { font-size: max(.11rem, 8px); }
  .dbond__name, .dbond__count { font-size: max(.12rem, 8px); }
  .dbond__count small, .dskill__slot { font-size: max(.11rem, 8px); }
  .rt-vup, .rt-rem, .rt-kw { font-size: max(.12rem, 8px); }
  .scard__free, .scard__name, .scard__bond, .scard__class { font-size: max(.13rem, 8px); }
  .dstats__tag { font-size: max(.11rem, 8px); }
  .dgarrison__k, .dgarrison__v { font-size: max(.13rem, 8px); }
  .dpanel .micro { font-size: max(.11rem, 8px); }
  .gm.has-dpanel .gm__bonds {
    opacity: .35;
    transition: opacity var(--t-fast);
  }
  .gm.has-dpanel .gm__bonds:hover {
    opacity: 1;
  }
}
/* With the shop folded (收起) no bar covers the corner: one row again, so the folded shop's prep camera, which keeps the
   bench above the corner's hit areas (ui/fieldHost.js hudBands), grows the board on narrow phones too (public issue #5). */
@media (max-width: 767px) {
  .gm.is-collapsed .gm__corner { flex-wrap: nowrap; width: auto; }
}

/* Short landscape phones (≤ 460 CSS px tall, 1rem = 40 px): the lobby's two columns are compressed so the
   创建同盟 button and the join panel stay on screen without scrolling. The detail card's header is shorter (no
   romanised name, a shorter portrait) so the operator's own effect (特质) under it stays in view even in the short card
   docked above the shop bar (user playtest #3 item 8). */
@media (max-height: 460px) {
  .dhead__art { height: 1.66rem; }
  .dhead__en { display: none; }
  .lobby-body { padding-top: .2rem; padding-bottom: .2rem; gap: .36rem; }
  .mode-cards { margin-bottom: .2rem; }
  .mode-card { min-height: 0; gap: .12rem; padding: .22rem .26rem .2rem; }
  .mode-card__icon { width: .66rem; height: .66rem; }
  .mode-card__name { font-size: .4rem; }
  .mode-card__points, .diff-card__effects, .tips, .create-box__hint { display: none; }
  .diff-list { gap: .1rem; }
  .diff-card { padding-top: .12rem; padding-bottom: .12rem; }
  .create-box { margin-top: .18rem; }
  .create-box .btn--xl { height: .8rem; }
}

/* ---- 5. Multi-Aspect-Ratio & Screen Size Adaptations --------------------------------------------- */

/* Ultra-wide screens (19:9, 19.5:9, 20:9, 21:9 modern flagship phones):
   Keep central stage centered and prevent edge controls from being obscured by curved corners or camera cutouts */
@media (min-aspect-ratio: 19/9) {
  .gm__hud {
    padding-left: max(var(--sa-l), 16px);
    padding-right: max(var(--sa-r), 16px);
  }
  .screen:not(.gm) {
    padding-left: max(var(--sa-l), 20px);
    padding-right: max(var(--sa-r), 20px);
  }
}

/* Narrow aspect-ratio screens (4:3, 16:10, 3:2 tablets, iPads, foldable phones unfolded):
   Give more vertical breathing room to the central chessboard and scale shop/topbar gracefully */
@media (max-aspect-ratio: 16/10) {
  .gm__hud > .shopbar {
    bottom: calc(.1rem + var(--sa-b));
  }
  .lobby-body {
    flex-direction: column;
    overflow-y: auto;
    max-height: 90vh;
  }
}

/* Compact low-profile phone screens (≤ 380px CSS height, e.g. 720p/1080p landscape with 3x scale):
   Ensure all modals, drawers, and battle action overlays stay 100% visible without clipping */
@media (max-height: 380px) {
  .modal__box {
    max-height: 96vh;
    padding: .2rem .24rem;
  }
  .shopbar {
    scale: 0.95;
    transform-origin: center bottom;
  }
  .topbar {
    height: max(.48rem, 30px);
  }
}

