/* ==========================================================================================
   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, .bslot .bond, .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, .bslot .bond, .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;
}
/* Adjacent corner controls share the .08rem gap: keep the extra vertical tap area, but split the horizontal
   space between neighbours. A full 44px width over a 20px icon otherwise sends taps to the next button. */
.sp-coarse .gm__corner :is(.gm__gear, .ewheel__btn)::before { width: calc(100% + .08rem); }
/* The compact emote button follows the other corner controls instead of retaining its separate 34px floor. */
.sp-coarse .gm__corner .ewheel__btn--compact { width: .56rem !important; height: .56rem !important; }
.sp-coarse .gm__corner .ewheel__btn--compact .icon { width: .28rem !important; height: .28rem !important; }
.set-seg button { pointer-events: auto; position: relative; z-index: 1; touch-action: manipulation; }
.set-seg button::before { display: none !important; }
/* 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; width: auto; height: auto; transform: none; }

/* Match controls keep the same rem proportions on landscape phones. The invisible touch targets above provide
   the extra tap area without enlarging the HUD or pushing the board out of its normal frame. */
@media (max-height: 600px) and (pointer: coarse), (max-height: 600px) and (any-pointer: coarse) {
  .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, .title-settings { 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)); gap: .06rem; }
  .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 { flex-wrap: nowrap; width: auto; gap: .12rem; align-items: flex-end; left: max(.16rem, var(--sa-l, 8px)); bottom: max(.16rem, var(--sa-b, 8px)); }
  .gm__corner .gm__gear, .gm__corner .ewheel__btn { width: .82rem !important; height: .82rem !important; padding: 0 !important; }
  .gm__corner .gm__gear .icon, .gm__corner .ewheel__btn .icon { width: .44rem !important; height: .44rem !important; }
  .dpanel:not(.dpanel--right) { bottom: calc(.44rem + max(.82rem, 44px)); }
  .team__chat-bubble, .ebubble { font-size: max(.18rem, 15px) !important; padding: .09rem .20rem .09rem .26rem !important; max-width: 4.8rem !important; }
  .team__chat-text, .ebubble__txt { font-size: max(.18rem, 15px) !important; }
}
/* 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%; }
  /* The centred bonds sit below the centre HUD, as on desktop. The countdown / ready controls are at the right;
     reserving their stacked height across the full screen lowered the bonds into the back row of the board. */
  .gm__bonds { top: 1.36rem; }
  .gm__bonds .bslot .bond__name { font-size: .16rem; }
  .dpanel {
    width: max(4.9rem, 210px);
    left: max(2.3rem, 76px);
    top: max(2.1rem, 90px);
  }
  .dstat__k { font-size: max(calc(.12 * var(--t)), 8px); }
  .dstat__k-full { display: none; }
  .dstat__k::after { content: attr(data-short); }
  .dstat__v { font-size: max(calc(.17 * var(--t)), 10px); }
  .dstat small { font-size: max(calc(.11 * var(--t)), 8px); }
  .dhead__name { font-size: max(calc(.32 * var(--t)), 12px); }
  .dhead__class, .dhead__pos, .dtag-elite, .dtag-token, .dtag-kind, .drank { font-size: max(calc(.13 * var(--t)), 8px); }
  .dtrait, .dtext, .dsec__title, .dskill__name, .dmodule__name, .ditem__text b, .ditem__desc, .dtalent b { font-size: max(calc(.14 * var(--t)), 8px); }
  .dsp, .dsp__num, .dmodule__type, .dtag-loadout { font-size: max(calc(.11 * var(--t)), 8px); }
  .dbond__name, .dbond__count { font-size: max(calc(.12 * var(--t)), 8px); }
  .dbond__count small, .dskill__slot { font-size: max(calc(.11 * var(--t)), 8px); }
  .rt-vup, .rt-rem, .rt-kw { font-size: max(calc(.12 * var(--t)), 8px); }
  .scard__free, .scard__name, .scard__bond, .scard__class { font-size: max(.13rem, 8px); }
  .dstats__tag { font-size: max(calc(.11 * var(--t)), 8px); }
  .dgarrison__k, .dgarrison__v { font-size: max(calc(.13 * var(--t)), 8px); }
  .dpanel .micro { font-size: max(calc(.11 * var(--t)), 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: calc(.4 * var(--t)); }
  .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; }
  .matchmaking-hud { padding: .12rem .2rem; }
  .matchmaking-hud__info { font-size: calc(.16 * var(--t)); gap: .1rem; }
  .matchmaking-hud__time { font-size: calc(.18 * var(--t)); }
}

/* ---- 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.
   The shop bar's +10 % request (game-shop.css, user) applies here too: 0.95 × 1.1 ≈ 1.045 relative
   to the old 0.95 — the later rule wins the cascade, so this is the net size on the shortest phones. */
@media (max-height: 460px) {
  .shopbar {
    scale: 0.9;
    transform-origin: 100% 100%;
  }
}
@media (max-height: 380px) {
  .modal__box {
    max-height: 96vh;
    padding: .2rem .24rem;
  }
  .shopbar {
    scale: 0.85;
    transform-origin: 100% 100%;
  }
  .topbar {
    height: max(.48rem, 30px);
  }
}

/* Phone landscape: keep the complete title console in view and use the game's rem proportions. */
@media (orientation: landscape) and (max-height: 600px) {
  :is(.sp-touch, .sp-coarse) .title-screen { justify-content: center; overflow: hidden; }
  :is(.sp-touch, .sp-coarse) .title-screen .title-main { width: min(13rem, calc(100% - 32px)); padding: 0; margin: -.15rem 0 0; flex-shrink: 0; transform: none; }
  :is(.sp-touch, .sp-coarse) .title-screen .emblem { display: flex; margin-bottom: .08rem; }
  :is(.sp-touch, .sp-coarse) .emblem__svg { width: .48rem; height: .5rem; }
  :is(.sp-touch, .sp-coarse) .emblem__bracket { height: .62rem; width: .08rem; border-width: 1px; }
  :is(.sp-touch, .sp-coarse) .title-en__a { font-size: .2rem; }
  :is(.sp-touch, .sp-coarse) .title-en__b { font-size: .22rem; }
  :is(.sp-touch, .sp-coarse) .title-screen .title-cn { font-size: max(.58rem, 22px); margin-top: .08rem; white-space: nowrap; }
  :is(.sp-touch, .sp-coarse) .title-tag { display: none; }
  :is(.sp-touch, .sp-coarse) .title-screen .title-login { width: min(12rem, 100%); margin-top: .14rem; padding: .16rem .24rem; gap: .12rem; }
  :is(.sp-touch, .sp-coarse) .title-login .server-picker__heading { font-size: 11px; margin-bottom: 5px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-picker__heading > span { font-size: 9px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-card { padding: 6px 8px; gap: 3px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-card__top { font-size: 12px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-card__count { font-size: 10px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-card__count > b { font-size: 16px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-card__metrics,
  :is(.sp-touch, .sp-coarse) .title-login .server-card__meta { font-size: 9px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-card__pressure { font-size: 10px; }
  :is(.sp-touch, .sp-coarse) .title-login .server-picker__note { font-size: 9px; margin-top: 5px; line-height: 1.4; }
  :is(.sp-touch, .sp-coarse) .title-login .field--lg .field__box { height: max(.68rem, 32px); }
  :is(.sp-touch, .sp-coarse) .title-login .btn--xl { height: max(.82rem, 32px); }
  :is(.sp-touch, .sp-coarse) .title-login .title-conn { font-size: 9px; gap: .12rem; min-height: 24px; }
  :is(.sp-touch, .sp-coarse) .title-screen .title-foot { position: absolute; left: 12px; right: 12px; bottom: 5px; width: auto; margin: 0; font-size: 8px; line-height: 1.35; }
  :is(.sp-touch, .sp-coarse) .title-foot .micro { font-size: 8px; }
  :is(.sp-touch, .sp-coarse) .title-foot__right > .micro { display: none; }
  :is(.sp-touch, .sp-coarse) .title-corner { display: none; }
}
/* Keep a complete login console even with the address bar visible on the shortest phones. */
@media (orientation: landscape) and (max-height: 400px) {
  :is(.sp-touch, .sp-coarse) .title-screen .title-main { width: min(25rem, calc(100% - 40px)); display: grid; grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); grid-template-rows: auto auto auto; column-gap: .5rem; justify-items: center; align-items: center; }
  :is(.sp-touch, .sp-coarse) .title-screen .title-login { grid-column: 2; grid-row: 1 / 4; margin: 0; width: 100%; }
  :is(.sp-touch, .sp-coarse) .title-screen .title-cn { font-size: max(.64rem, 20px); }
}

/* Safe-area offsets define the HUD's available box; 100% dimensions would overflow it. */
.gm__hud, .screen:not(.gm) { width: auto; height: auto; }
.rotate-hint__pwa { pointer-events: auto; margin-top: 6px; }
.rotate-hint__pwa[hidden] { display: none; }

/* Phone shop reference v2: preserve card height and compact its information rows. */
@media (orientation: landscape) and (max-height: 600px) {
  :is(.sp-touch, .sp-coarse) .shopbar .scard,
  :is(.sp-touch, .sp-coarse) .shopbar .lvcard { height: 2.36rem; }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__name { font-size: max(.16rem, 7px); }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__bonds { gap: .02rem .05rem; }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__bond { font-size: max(.105rem, 6px); white-space: nowrap; }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__bond .bglyph { width: .14rem; height: .14rem; }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__class { font-size: max(.1rem, 5.5px); }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__body { gap: .02rem; padding-top: .22rem; }
  :is(.sp-touch, .sp-coarse) .shopbar .scard__idesc { font-size: max(.1rem, 5.5px); line-height: 1.35; }
}
