/* ==========================================================================================
   utility-mobile.css — compact density for the *management* surfaces only. Loaded last, after
   devices.css, in source mode and in the Vite CSS bundle.

   Scope: dialogs marked `utility` (components.js <Modal utility>), the guide, the title screen,
   the lobby, the room, the loadout screen, the local-statistics screen — and the single
   battle-side surface the owner chose to carry here, the 作战统计 panel (`.combat-metrics`: its
   compact height, its pinned title/scope/close chrome and the position it floats to when the
   corner no longer fits the visible viewport). Nothing else of the battlefield is touched: the
   shop, the HUD bands, the detail card and the chat panel keep their own geometry from game.css /
   game-panels.css / game-shop.css / emotes.css and keep reading the plain --t, because the floor
   below is declared on the management roots only — the combat panel is not one of them and keeps
   the explicit px floors of its own rules (see its block).

   Rules for this file:
     * html's rem, the global --t and every layout width/height stay where they were;
     * --utility-text is read by font-size declarations ONLY (test/ui/utility-mobile.test.js);
     * compact targets use their real box, never an oversized ::before that overlaps a neighbour;
     * larger saved text sizes still enlarge the content — density comes from columns, gaps and
       wrapping, never from scale()/zoom or from hiding content.
   ========================================================================================== */

/* ---- shared dialog chrome ------------------------------------------------------------------- */

.modal__titles { display: flex; flex-direction: column; gap: .04rem; min-width: 0; }
.utility-modal { width: var(--utility-width, min(6.4rem, 94vw)); max-width: 100%; min-height: 0; }
.utility-modal .modal__head { flex: none; flex-direction: row; align-items: center; justify-content: space-between; }
.utility-modal .modal__title { overflow-wrap: anywhere; }
.utility-modal .modal__body {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  touch-action: pan-y; -webkit-overflow-scrolling: touch;
}
.utility-modal__close {
  display: grid; place-items: center; flex: none; width: max(.36rem, 32px); height: max(.36rem, 32px);
  padding: 0; background: var(--bg-1); border: 1px solid var(--line-2); color: var(--text-md);
}
.utility-modal__close .icon { width: 50%; height: 50%; }
.utility-modal__close:hover { color: var(--mint-400); border-color: var(--mint-700); }

@media (max-width: 1000px), (max-height: 600px) {

  /* A local readable floor derived from the saved text size setting. --t stays owned by theme.css
     and is never redefined. Each management root declares the variable itself: UiHosts / GuideHost /
     LoadoutHost / StatsHost / ResourceManagerHost are all children of .app-root, so a dialog opened
     from the title screen or from the match never inherits it from the screen behind it. */
  :is(.modal--utility, .guide, .lo, .st) { --utility-text: max(var(--t), 64px); }
  /* The title, the lobby, the room and the settings / about dialogs are game-scale surfaces:
     they follow the saved text size exactly as the battlefield does and take no readability floor
     (ported from xinhai ba744327). The floor is off on purpose — on a phone it pins 小 and 中 to the same
     64 px, so choosing 小 would change nothing at all on any of these screens. The resource planner overrides
     its own token after the compact rules below, with a readable floor for each saved text size. */
  :is(.title-screen, .lobby-screen, .room-screen) { --utility-text: var(--t); }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel) { --utility-text: var(--t); }

  /* device.js keeps --sp-vh at the real visible height (visualViewport), so a soft keyboard shrinks
     these budgets instead of leaving the footer actions behind it. Only management surfaces adopt
     it — the battlefield keeps its own viewport ownership. */
  .modal--utility, .guide, .lo, .st {
    bottom: auto; height: min(100dvh, calc(var(--sp-vh, 1dvh) * 100));
  }
  .title-screen, .lobby-screen, .room-screen {
    bottom: auto; height: calc(min(100dvh, calc(var(--sp-vh, 1dvh) * 100)) - var(--sa-t, 0px) - var(--sa-b, 0px));
  }

  /* ---- generic utility dialog -------------------------------------------------------------- */

  .modal--utility {
    padding: calc(var(--sa-t, 0px) + 6px) calc(var(--sa-r, 0px) + 6px)
      calc(var(--sa-b, 0px) + 6px) calc(var(--sa-l, 0px) + 6px);
  }
  .modal--utility .utility-modal {
    width: min(12rem, 100%);
    max-height: calc(min(100dvh, calc(var(--sp-vh, 1dvh) * 100)) - var(--sa-t, 0px) - var(--sa-b, 0px) - 12px);
    font-size: max(calc(.16 * var(--utility-text)), 11px);
  }
  .modal--utility .resource-modal { width: min(12rem, 100%); }
  .modal--utility .settings-modal { width: min(14rem, 100%); }
  .modal--utility .minfo-dlg { width: min(17rem, 100%); }
  .modal--utility .resume-modal { width: min(10rem, 100%); }
  .utility-modal .modal__head { padding: 6px 10px 4px; gap: 8px; }
  .utility-modal .modal__head .micro { font-size: max(calc(.1 * var(--utility-text)), 9px); letter-spacing: .08em; white-space: normal; }
  .utility-modal .modal__title { font-size: max(calc(.22 * var(--utility-text)), 15px); line-height: 1.25; letter-spacing: .02em; }
  .utility-modal .modal__body { padding: 6px 10px 8px; }
  .utility-modal .modal__actions { flex-wrap: wrap; gap: 6px; padding: 6px 10px; }
  .utility-modal .modal__actions .btn { min-height: 30px; height: auto; font-size: max(calc(.16 * var(--utility-text)), 11px); }
  .utility-modal .modal__text { line-height: 1.5; }
  .utility-modal :is(.btn, .set-toggle, .set-seg button) {
    min-height: 30px; height: auto; padding: 5px 9px; line-height: 1.25;
    font-size: max(calc(.16 * var(--utility-text)), 11px); letter-spacing: .02em;
  }
  .utility-modal :is(.btn--square, .utility-modal__close) { width: 30px; height: 30px; padding: 0; }

  /* devices.css expands small controls to an invisible 44 px hit area. Inside a compact management
     surface that area would cover the neighbouring control — a tap between two 30 px buttons would
     land on the wrong one. Clip the hit area to the real box here; the compaction itself keeps the
     targets at 26–30 px (still above the 24 px WCAG 2.2 minimum). */
  .sp-coarse :is(.utility-modal, .lo, .st, .lobby-screen, .room-screen, .title-screen) :is(.btn, .tabs__tab, .set-toggle, .set-seg button, .fsbtn)::before {
    inset: 0; width: 100%; height: 100%; transform: none;
  }
  /* iOS zooms into a focused field below 16 px (ui/clipboard.js relies on the same floor). */
  .utility-modal :is(input:not([type="radio"]):not([type="checkbox"]):not([type="range"]), textarea, select) {
    font-size: max(calc(.2 * var(--utility-text)), 16px);
  }
  .utility-modal :is(.field__label, .field__hint) { font-size: max(calc(.13 * var(--utility-text)), 11px); }

  /* ---- resource manager -------------------------------------------------------------------- */

  .resource-manager { gap: 8px; font-size: max(calc(.16 * var(--utility-text)), 11px); }
  .resource-manager p { line-height: 1.45; }
  /* Both tiers fit side by side on a landscape phone; a genuinely narrow viewport stacks them below. */
  .resource-manager__tiers { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; align-items: stretch; }
  .resource-tier, .resource-archive { padding: 8px; min-width: 0; }
  .resource-tier h3, .resource-skins h3, .resource-archive h3 { font-size: max(calc(.19 * var(--utility-text)), 13px); }
  .resource-tier__head { gap: 6px; flex-wrap: wrap; }
  .resource-tier__head p, .resource-archive p, .resource-tier__summary, .resource-tier__list li,
  .resource-manager__status, .resource-manager__maintenance, .resource-archive__help, .resource-cache p {
    font-size: max(calc(.14 * var(--utility-text)), 11px);
  }
  .resource-choice { min-height: 28px; gap: 5px; white-space: normal; font-size: max(calc(.14 * var(--utility-text)), 11px); }
  .resource-choice input { flex: none; width: 14px; height: 14px; margin: 0; }
  .resource-scope { padding: 6px 8px; gap: 4px; }
  .resource-scope__head h3 { font-size: max(calc(.16 * var(--utility-text)), 12px); }
  .resource-scope__total, .resource-choice__size { font-size: max(calc(.13 * var(--utility-text)), 10px); }
  .resource-tier__summary { margin: 6px 0 4px; gap: 3px; }
  .resource-tier__list { margin-top: 4px; }
  .resource-tier__list li { gap: 5px; padding: 4px 0; align-items: baseline; }
  .resource-tier__list .num { white-space: nowrap; }
  .resource-tier__list small { font-size: max(calc(.12 * var(--utility-text)), 10px); }
  .resource-manager__status { padding: 6px; }
  .resource-archive .res-actions, .resource-archive .pbar { margin-top: 6px; }
  .resource-modal .res-link { min-height: 28px; font-size: max(calc(.13 * var(--utility-text)), 11px); }
  .resource-modal .pbar__meta { flex-wrap: wrap; gap: 2px 6px; font-size: max(calc(.14 * var(--utility-text)), 11px); }
  .resource-modal .pbar__value { font-size: max(calc(.16 * var(--utility-text)), 12px); }

  /* ---- settings --------------------------------------------------------------------------- */

  .set-list { gap: 6px; }
  .set-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr) auto; gap: 8px; min-height: 30px; }
  .set-row__label { gap: 5px; line-height: 1.35; font-size: calc(.18 * var(--utility-text)); }
  /* the Latin hint sits inline here (game.css .set-row__label is a wrapping flex row), so it stays —
     it only needs the same floor as the label beside it */
  .set-row__label .micro { font-size: max(calc(.11 * var(--utility-text)), 9px); letter-spacing: .1em; }
  .set-row__label .icon { width: 14px; height: 14px; }
  .set-row__val { min-width: 2.5em; font-size: calc(.18 * var(--utility-text)); }
  .set-seg { width: 100%; }
  .set-seg button { min-width: 0; padding: 4px 7px; }
  .set-toggle { padding: 4px 8px; }
  .set-toggle i { width: 28px; height: 16px; }
  .set-toggle i::after { left: 2px; top: 2px; width: 12px; height: 12px; }
  .set-toggle.is-on i::after { transform: translateX(12px); }
  .set-range { min-width: 0; height: 28px; border-block: 10px solid transparent; background-clip: padding-box; }
  .set-hint { margin: 0; font-size: max(calc(.14 * var(--utility-text)), 11px); line-height: 1.45; color: var(--text-lo); }
  /* The 快捷键 and 问题反馈 sections live in game.css, which this port deliberately leaves alone (it also owns
     the battle UI), so their text is restated here to pick up the same floor: at 小 on a phone .15rem is 6 px. */
  .set-keys { gap: 6px; padding-top: 6px; }
  .set-keys__list { gap: 4px 8px; }
  .set-keys__row { min-height: 30px; padding: 3px 3px 3px 8px; gap: 6px; }
  .set-keys__name, .shortcut-row, .set-res__text, .set-res__num { font-size: max(calc(.15 * var(--utility-text)), 11px); line-height: 1.3; }
  .set-key, .shortcut-key { min-width: 34px; height: 26px; padding: 0 6px; font-size: max(calc(.15 * var(--utility-text)), 11px); }
  .set-key.is-waiting { font-size: max(calc(.13 * var(--utility-text)), 11px); }
  .set-key.is-fixed small { font-size: max(calc(.12 * var(--utility-text)), 10px); }
  .set-keys__note, .shortcut-error { font-size: max(calc(.13 * var(--utility-text)), 10px); line-height: 1.4; }
  .set-keys__more > summary { font-size: max(calc(.15 * var(--utility-text)), 11px); }
  .set-diag__stat, .set-diag__url { font-size: max(calc(.13 * var(--utility-text)), 10px); line-height: 1.4; }
  .set-diag__count { font-size: max(calc(.18 * var(--utility-text)), 12px); }
  .set-diag { gap: 4px; padding-top: 6px; }
  .set-diag__text { height: 96px; min-height: 64px; }
  .set-lang, .lang-select select { font-size: max(calc(.2 * var(--utility-text)), 16px); }

  /* ---- about / announcement / resume ------------------------------------------------------- */

  .about-panel .modal__body { line-height: 1.5; overflow-wrap: anywhere; }
  .about-links dt { font-size: max(calc(.14 * var(--utility-text)), 11px); }
  .announcement-detail .announcement-detail__text { line-height: 1.55; }
  .resume-modal .btn--block { margin-top: 6px; white-space: normal; overflow-wrap: anywhere; }

  /* ---- title screen ------------------------------------------------------------------------ */

  .title-screen { overflow-y: auto; justify-content: flex-start; }
  .title-screen .title-main { flex: none; width: 100%; min-width: 0; margin: auto 0; padding: .25rem .2rem; }
  /* The emblem and the name scale with the text root like the rest of the game (xinhai ba744327), so the
     title screen keeps its proportion on a phone instead of a fixed emblem over shrunken type. */
  .title-screen .title-cn { font-size: calc(.72 * var(--t)); line-height: 1.1; letter-spacing: .04em; }
  .title-screen .title-cn--latin { font-size: calc(.44 * var(--t)); }
  .title-screen .title-login { width: min(7.2rem, 100%); margin-top: .3rem; gap: .15rem; padding: .25rem; }
  .title-screen .title-login .field__box { min-height: .85rem; height: auto; }
  /* 16 px stays: below it iOS zooms the page in when the field takes focus (test/ui/utility-mobile.test.js). */
  .title-screen .title-login .field__input { font-size: max(calc(.2 * var(--utility-text)), 16px); }
  .title-screen .title-login .btn--xl { height: auto; min-height: .9rem; padding: .15rem .25rem; letter-spacing: .16em; font-size: calc(.24 * var(--utility-text)); }
  .title-screen :is(.title-invite, .title-conn) { font-size: calc(.14 * var(--utility-text)); }
  .title-screen .title-conn { flex-wrap: wrap; gap: .1rem; }
  .title-screen :is(.title-settings, .title-fs) { width: .7rem; height: .7rem; }
  .title-screen .title-tag { max-width: 7rem; font-size: calc(.16 * var(--utility-text)); letter-spacing: .02em; text-align: center; }
  .title-screen .title-foot { position: relative; inset: auto; width: 100%; flex-wrap: wrap; padding: .15rem .25rem; gap: .1rem; font-size: calc(.13 * var(--utility-text)); }
  .title-screen .title-corner { position: relative; inset: auto; }
  /* the language / statistics / about / history entries must stay reachable: they move into the flow
     instead of the absolutely positioned desktop corners */
  .title-screen .title-corner > * { flex-wrap: wrap; justify-content: center; }
  .title-screen .title-corner .micro { display: none; }
  .title-screen .lang-select button, .title-screen .title-corner .btn { height: auto; min-height: .75rem; font-size: calc(.16 * var(--utility-text)); }
  .title-screen .res-pill__head { min-height: .75rem; flex-wrap: wrap; font-size: calc(.16 * var(--utility-text)); }
  .title-screen .res-pill__state { font-size: calc(.14 * var(--utility-text)); }

  /* ---- lobby ------------------------------------------------------------------------------- */

  .lobby-screen .lobby-body { max-width: none; padding: .2rem .25rem; gap: .3rem; }
  .lobby-screen .mode-cards { gap: .15rem; margin-bottom: .2rem; }
  .lobby-screen .mode-card { min-height: 0; gap: .15rem; padding: .2rem; }
  .lobby-screen .mode-card__name { font-size: calc(.25 * var(--utility-text)); letter-spacing: .02em; }
  .lobby-screen .mode-card__desc { line-height: 1.4; }
  .lobby-screen .mode-card__points { display: flex; gap: .05rem; font-size: calc(.14 * var(--utility-text)); }
  .lobby-screen .mode-card__check { top: .1rem; right: .1rem; padding: .05rem .1rem; font-size: calc(.12 * var(--utility-text)); }
  .lobby-screen .diff-list { gap: .1rem; }
  .lobby-screen .diff-card { padding-block: .125rem; }
  .lobby-screen .create-box { margin-top: .2rem; gap: .1rem; }
  .lobby-screen .create-box .btn--xl { height: auto; min-height: 1rem; font-size: calc(.24 * var(--utility-text)); letter-spacing: .16em; }
  .lobby-screen .join-panel .panel__body { padding: .2rem; gap: .15rem; }
  .lobby-screen .tips { margin-top: .2rem; padding: .2rem; }
  .lobby-screen .tips__text { margin-top: .1rem; line-height: 1.4; }

  /* ---- room chrome ------------------------------------------------------------------------- */
  /* Named areas at every compact width, including 761–1000 px landscape phones: the title stays
     next to the controls and the invitation on one row, and both bars grow instead of keeping the
     desktop fixed heights. */

  .room-screen .topbar {
    height: auto; min-height: 0; padding: .15rem .2rem; gap: .15rem;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr) minmax(0, 1fr);
    grid-template-areas: "controls title invite";
  }
  .room-screen .topbar__left {
    grid-area: controls; justify-self: start; min-width: 0; max-width: 100%;
    flex-wrap: nowrap; gap: .1rem; overflow: hidden;
  }
  .room-screen .topbar__center { grid-area: title; min-width: 0; padding: 0; }
  .room-screen .topbar__center > .micro { display: none; }
  .room-screen .topbar__title {
    justify-content: center; flex-wrap: nowrap; white-space: nowrap; min-width: 0; max-width: 100%; gap: .1rem;
    font-size: calc(.16 * var(--utility-text)); letter-spacing: 0;
  }
  .room-screen .topbar__right { grid-area: invite; justify-self: end; max-width: 100%; min-width: 0; gap: 0; }
  .room-screen .room-topbar__tools { display: flex; flex: none; align-items: center; gap: .1rem; }
  .room-screen .room-tools { width: .75rem; min-width: .75rem; height: .75rem; min-height: .75rem; padding: 0; }
  /* A single row: the controls hold their size and the ping gives way (xinhai ba744327) — wrapping here
     pushed the title out of its own grid track instead. */
  .room-screen .room-ping { align-items: flex-start; gap: 0; min-width: 0; flex: 1 1 auto; overflow: hidden; }
  .room-screen .room-ping > .micro { display: none; }
  .room-screen .connection-status { flex-wrap: nowrap; gap: .1rem; max-width: 100%; overflow: hidden; }
  .room-screen .invite { min-width: 0; max-width: 100%; padding: .075rem .1rem; gap: .05rem .1rem; }
  .room-screen .invite__label { flex-wrap: nowrap; gap: .075rem; }
  .room-screen .invite__label .micro { display: none; }
  .room-screen .invite__code { gap: .025rem; }
  /* The key glyph boxes scale with their own font size instead of being a tiny rem box around it. */
  .room-screen .invite__code span { width: .72em; height: 1em; flex: none; font-size: calc(.2 * var(--utility-text)); }
  .room-screen .invite__btns { flex-direction: row; gap: .05rem; }
  .room-screen .invite__btns .btn { min-width: .65rem; width: .65rem; min-height: .65rem; height: .65rem; padding: .075rem; font-size: 0; }
  .room-screen .invite__btns .icon { width: .4rem; height: .4rem; }
  .room-screen--coop { overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
  .room-screen .seats { padding: .2rem .25rem; gap: .2rem; grid-template-rows: minmax(0, 1fr); overflow-y: auto; }
  .room-screen--coop .seats { flex: 1 0 3.6rem; min-height: 3.6rem; }
  .room-screen .seat { padding: .15rem; gap: .1rem; }
  .room-screen .seat__art .avatar { --av: min(1.5rem, 18vh); }
  .room-screen .seat__name { font-size: calc(.2 * var(--utility-text)); }
  .room-screen .seat__state { min-width: 0; max-width: 100%; overflow-wrap: anywhere; line-height: 1.25; }
  .room-screen .seat__foot { flex-wrap: wrap; gap: .1rem; }
  .room-screen .solo-brief { padding: .25rem; gap: .15rem; overflow-y: auto; touch-action: pan-y; }
  .room-screen .solo-brief h2 { font-size: calc(.26 * var(--utility-text)); }
  .room-screen .specbar { padding: 0 .25rem .15rem; gap: .15rem; }
  .room-screen .room-bar {
    height: auto; min-height: 0; padding: .15rem .25rem; gap: .15rem .25rem;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: "options actions" "status actions";
  }
  .room-screen :is(.room-bar__left, .room-bar__right) { gap: 6px; flex-wrap: wrap; }
  .room-screen .room-bar__left { grid-area: options; min-width: 0; }
  .room-screen .room-bar__label .micro { display: none; }
  .room-screen .room-bar__center { grid-area: status; flex-direction: row; flex-wrap: wrap; justify-self: start; gap: .1rem .2rem; min-width: 0; text-align: left; }
  .room-screen .room-bar__right { grid-area: actions; min-width: 0; align-items: flex-end; justify-content: flex-end; }
  .room-screen .room-bar__status { overflow-wrap: anywhere; }
  .room-screen .room-bar .btn--xl { min-width: 0; height: auto; min-height: 34px; font-size: max(calc(.2 * var(--utility-text)), 12px); letter-spacing: .1em; }
  .room-screen .dpick { min-width: 0; max-width: 100%; flex-wrap: wrap; }
  .room-screen .dpick__opt { height: auto; min-height: .7rem; padding: .1rem .175rem; }

  /* ---- loadout / ownership / DIY ------------------------------------------------------------ */

  :is(.lo-top, .st-top) { height: auto; min-height: 40px; padding: 4px 8px; gap: 6px; }
  :is(.lo-top__left, .lo-top__right, .st-top__left, .st-top__right) { gap: 4px; min-width: 0; }
  :is(.lo-top, .st-top) .micro { display: none; }
  .lo .lo-back, .lo .lo-top__right .btn, .st .st-back, .st .st-top__right .btn { height: 30px; min-height: 30px; padding: 4px 7px; min-width: 30px; }
  :is(.lo-tab, .st-tab) { min-height: 30px; font-size: max(calc(.2 * var(--utility-text)), 12px); letter-spacing: 0; padding: 4px 6px; }
  .lo-body { padding: 6px 8px; gap: 6px; }
  .lo-filters, .lo-frow { gap: 4px; }
  .lo-list, .sp-coarse .lo-list {
    --q: max(.4rem, 28px); --qg: 3px; --art: max(.48rem, 30px);
    --cols: minmax(100px, 1fr) calc(3 * var(--q) + 2 * var(--qg)) calc(4 * var(--q) + 3 * var(--qg)) minmax(148px, .8fr);
    padding-right: 0;
  }
  .lo-list__head, .lo .lo-card { column-gap: 6px; }
  .lo-card__art { width: var(--art); height: var(--art); }
  .lo .lo-card { padding-block: 3px; }
  .lo-card__name { font-size: max(calc(.17 * var(--utility-text)), 11px); }
  .lo-card__pick { gap: 5px; }
  .lo-card__bonds { display: flex; }
  .lo .lo-search .field__box { min-height: 30px; height: auto; }
  .lo .lo-search .field__input, .lo-select select, .lo .lo-cult .lo-select select { font-size: max(calc(.2 * var(--utility-text)), 16px); }
  .lo-select { height: auto; min-height: 30px; }
  .lo .lo-chip, .lo .lo-toggle { min-height: 28px; }
  .lo .lo-seg button { min-height: 26px; }
  .own-card { padding: 5px 6px; }
  .own-grid, .diy-grid { grid-template-columns: repeat(auto-fill, minmax(min(100%, 240px), 1fr)); gap: 6px; }
  .diy-pick__list .diy-opt { min-height: 44px; }
  .lo-io__text { height: 120px; min-height: 72px; }

  /* ---- local statistics -------------------------------------------------------------------- */

  .st-body { padding: 6px 8px 10px; }
  .st-body > * { max-width: none; }
  .st-cards { grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); gap: 4px; }
  .st-card { padding: 5px 6px; }
  .st-sec__h { margin-bottom: 5px; }
  .st-table td, .st-table th { padding: 5px 6px; }
  .st-titles { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 4px; }
  .st-sums { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 4px; }
  .st-note { font-size: max(calc(.14 * var(--utility-text)), 11px); line-height: 1.45; }

  /* ---- combat statistics (the one battle-side surface this layer carries) ------------------ */
  /* The 作战统计 panel docks over the corner; on a short or partly occluded viewport the ranking
     must not be squeezed out. It gets a definite height (the layout module measures how much room
     is really left and publishes it), only title / scope / close stay pinned, and the whole body
     scrolls with the ranking first. Floats inside the visible viewport when the corner no longer
     fits above it (data-viewport-docked, ui/combatMetrics.js).

     These rules read --t with the same explicit px floors as the panel's own rules in game.css,
     and deliberately NOT the management floor: --utility-text is declared on the management roots
     only, this panel is not one of them, so the token would fall back to --t and the base floors
     would be lost — 9 px body text on a phone. This layer re-lays-out, it never shrinks type
     below the surface's own floor. */
  .combat-metrics {
    width: min(max(7.2rem, 360px), calc(100vw - var(--sa-l, 0px) - var(--sa-r, 0px) - .48rem));
    height: min(10rem, var(--combat-available-height, 240px));
    max-height: min(10rem, var(--combat-available-height, 240px));
  }
  .combat-metrics[data-viewport-docked="true"] {
    position: fixed; left: calc(var(--sa-l, 0px) + .24rem);
    top: var(--combat-viewport-top, calc(var(--sa-t, 0px) + 6px)); bottom: auto;
    height: min(10rem, var(--combat-viewport-height, calc(100dvh - var(--sa-t, 0px) - var(--sa-b, 0px) - 12px)));
    max-height: min(10rem, var(--combat-viewport-height, calc(100dvh - var(--sa-t, 0px) - var(--sa-b, 0px) - 12px)));
  }
  .combat-metrics__head { flex-wrap: nowrap; padding: .1rem .2rem; gap: .15rem; }
  .combat-metrics__head > div:first-child { min-width: 0; }
  .combat-metrics__head h2 { font-size: max(calc(.2 * var(--t)), 16px); overflow-wrap: anywhere; }
  .combat-metrics__micro { display: none; }
  .combat-metrics__close { order: 1; width: .7rem; min-width: .7rem; height: .7rem; min-height: .7rem; }
  .combat-metrics__body { display: flex; flex-direction: column; min-height: 0; overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; -webkit-overflow-scrolling: touch; }
  .combat-metrics__head > .combat-metrics__tools { flex: 1 1 0; min-width: 0; padding: 0; }
  .combat-metrics__scopes button { min-height: .7rem; padding: .075rem .15rem; white-space: normal; overflow-wrap: anywhere; }
  .combat-metrics__totals { padding: 0 .2rem .1rem; gap: .15rem; }
  .combat-metrics__totals b { font-size: max(calc(.18 * var(--t)), 14px); }
  .combat-metrics__legend { gap: .075rem .2rem; padding: 0 .2rem .1rem; }
  .combat-metrics__list { order: -1; flex: none; min-height: 0; padding: 0 .2rem; overflow: visible; }
  .combat-metrics__row { grid-template-columns: .4rem .65rem minmax(0, 1fr); padding: .1rem 0; gap: .125rem; }
  .combat-metrics__row > .uthumb { width: .65rem; height: .65rem; }
  .combat-metrics__bar { margin: .075rem 0; height: .1rem; }
  .combat-metrics__values { gap: .1rem; }
  .combat-metrics__values span { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: .05rem .1rem; }
  .combat-metrics__values b { font-size: max(calc(.14 * var(--t)), 12px); }
  .combat-metrics__note { padding: .1rem .2rem; font-size: max(calc(.1 * var(--t)), 10px); line-height: 1.3; }
  .combat-metrics__note br { display: none; }

  /* ---- guide ------------------------------------------------------------------------------- */

  .guide { padding-bottom: 0; }
  .guide__box {
    max-width: calc(100vw - var(--sa-l, 0px) - var(--sa-r, 0px) - 12px);
    max-height: calc(min(100dvh, calc(var(--sp-vh, 1dvh) * 100)) - var(--sa-t, 0px) - var(--sa-b, 0px) - 12px);
    padding: 6px; gap: 6px; min-height: 0; overflow: hidden;
  }
  .guide__head { min-height: 30px; gap: 6px; }
  .guide__chapters { min-width: 0; overflow-x: auto; }
  .guide__chapter { flex: none; min-width: 60px; height: 30px; padding: 3px 7px; }
  .guide__chname { font-size: max(calc(.19 * var(--utility-text)), 11px); letter-spacing: .02em; }
  .guide__chmicro { display: none; }
  .guide__close { width: 30px; height: 30px; }
  .guide__close .icon { width: 50%; height: 50%; }
  /* 16:9 pages are bounded by BOTH the width and the height left under the head and the footer. */
  .guide__page {
    width: min(calc(100vw - var(--sa-l, 0px) - var(--sa-r, 0px) - 28px),
      calc((min(100dvh, calc(var(--sp-vh, 1dvh) * 100)) - var(--sa-t, 0px) - var(--sa-b, 0px) - 90px) * 16 / 9));
  }
  .guide__stage--text { min-height: 0; width: 100%; max-height: none; overflow-y: auto; touch-action: pan-y; }
  .guide__tips li { font-size: max(calc(.18 * var(--utility-text)), 12px); }
  .guide__foot { grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr) auto; gap: 6px; min-height: 24px; }
  .guide__dots { overflow-x: auto; min-width: 0; max-width: 100%; touch-action: pan-x; }
  .guide__dot { flex: none; height: 26px; min-width: 26px; }
  .guide__ptitle { font-size: max(calc(.18 * var(--utility-text)), 11px); }
  .guide__count { font-size: max(calc(.22 * var(--utility-text)), 12px); }

  /* ---- resource preload / settings / about: game-scale dialogs ------------------------------ */
  /* These three are reachable from the title screen and from a match and read like the game, not
     like a management sheet, so their type and chrome follow --t directly instead of the readable
     floor (xinhai ba744327). They are restated here rather than rewritten in place because the
     rules above are shared with the guide / loadout / stats surfaces, which keep the floor. */
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel) {
    --utility-text: var(--t);
    font-size: calc(.16 * var(--t));
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel) .modal__head {
    padding: .12rem .2rem .08rem; gap: .15rem;
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel) .modal__title {
    font-size: calc(.22 * var(--t)); line-height: 1.25;
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel) .modal__body {
    padding: .1rem .2rem .15rem;
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel) .modal__actions {
    gap: .1rem; padding: .1rem .2rem; font-size: calc(.16 * var(--t));
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel)
    :is(.btn, .set-toggle, .set-seg button, .set-key, .shortcut-key) {
    min-height: .75rem; height: auto; padding: .125rem .225rem;
    font-size: calc(.16 * var(--t)); line-height: 1.25;
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel)
    :is(.btn--square, .utility-modal__close) {
    width: .75rem; height: .75rem; min-width: .75rem; min-height: .75rem; padding: 0;
  }
  :is(.utility-modal.resource-modal, .utility-modal.settings-modal, .utility-modal.about-panel)
    :is(input:not([type="radio"]):not([type="checkbox"]):not([type="range"]), textarea, select) {
    font-size: max(calc(.2 * var(--t)), 16px); /* the iOS focus-zoom floor stays a floor */
  }

  .resource-manager { gap: .12rem; font-size: calc(.14 * var(--utility-text)); }
  .resource-manager__tiers { gap: .12rem; }
  .resource-tier, .resource-archive { padding: .13rem .16rem; }
  .resource-tier h3, .resource-skins h3, .resource-archive h3 { font-size: calc(.17 * var(--utility-text)); }
  .resource-tier__head { gap: .15rem; }
  .resource-tier__head p, .resource-archive p,
  .resource-tier__summary, .resource-tier__list li, .resource-manager__maintenance { font-size: calc(.13 * var(--utility-text)); }
  .resource-choice { min-height: 30px; gap: 5px; font-size: calc(.13 * var(--utility-text)); }
  .resource-choice input { width: .35rem; height: .35rem; }
  .resource-scope { padding: .15rem .2rem; gap: .1rem; }
  .resource-tier__summary { margin: .08rem 0 .06rem; gap: .075rem; }
  .resource-tier__list { margin-top: .1rem; }
  .resource-tier__list li { gap: .125rem; padding: .1rem 0; }
  .resource-tier__list small { font-size: calc(.12 * var(--utility-text)); }
  .resource-manager__status { padding: .15rem; }
  .resource-archive .res-actions, .resource-archive .pbar { margin-top: .15rem; }
  .resource-modal .res-link { min-height: 30px; font-size: calc(.13 * var(--utility-text)); }
  .resource-modal .pbar__meta { gap: .05rem .15rem; font-size: calc(.13 * var(--utility-text)); }
  .resource-modal .pbar__value { font-size: calc(.16 * var(--utility-text)); }

  /* The hub's new controls need their own compact rules (the old room/topbar rules do not match them). */
  .resource-manager__voice { padding: .05rem .1rem; gap: .05rem .15rem; }
  .resource-voice-option { min-height: max(.75rem, 44px); padding: .08rem .1rem; }
  .resource-voice-option input { width: .28rem; height: .28rem; }
  .resource-modal .resource-manager summary { min-height: .65rem; }
  .resource-modal .resource-manager__status { font-size: calc(.14 * var(--utility-text)); }
  .resource-modal .resource-archive__toolbar .res-actions { margin-top: 0; }
  .resource-presets button { min-height: .7rem; padding: .1rem .2rem; }
  .resource-overview { gap: .15rem; padding: .06rem 0; }
  .resource-overview > div + div { padding-left: .2rem; }
  .resource-manager__tiers > .resource-skins { padding: .13rem .16rem; }
  .resource-tier__head .micro { margin-bottom: .1rem; font-size: calc(.1 * var(--utility-text)); }
  .resource-tier .resource-manager__voice { margin-top: .1rem; gap: .08rem; }
  .resource-extra { margin-top: .1rem; padding-top: .08rem; }
  .resource-archive > summary { min-height: .65rem; }
  .resource-footer__hint { flex-basis: 100%; }

  .lobby-hub--searching .hub-stage {
    grid-template-columns: minmax(3rem, 1fr) minmax(0, 2.5fr);
    grid-template-rows: auto minmax(0, 1fr); gap: .15rem .25rem;
  }
  .lobby-hub--searching .hub-center { display: none; }
  .lobby-hub--searching .hub-side { grid-column: 1; grid-row: 1 / -1; padding-top: 0; }
  .lobby-hub--searching .hub-right { grid-column: 2; grid-row: 1; width: 100%; padding: 0; }
  .lobby-hub--searching .hub-right__plates { flex-direction: row; gap: .15rem; }
  .lobby-hub--searching .hub-right__plates > * { flex: 1; min-width: 0; }
  .lobby-hub--searching .hub-entries { grid-column: 2; grid-row: 2; min-height: 0; align-items: stretch; }
  .lobby-hub--searching .hub-searching { width: 100%; min-height: 0; flex: 1; overflow-y: auto; padding: .2rem; gap: .12rem; }
  .lobby-hub--searching .matching-panel__head { padding-bottom: .1rem; }
  .lobby-hub--searching .matching-panel__count strong { font-size: calc(.28 * var(--utility-text)); }
  .lobby-hub--searching .matching-panel__count p { margin: .05rem 0 0; }
  .lobby-hub--searching .matching-panel__note, .lobby-hub--searching .matching-panel__foot { line-height: 1.4; }
  .lobby-hub--searching .hub-entries__row { flex: none; gap: .15rem; }
  .lobby-hub--searching .hub-entry-wrap { flex: 1; min-width: 0; }
  .lobby-hub--searching .hub-entry { width: 100%; height: .85rem; min-height: 36px; padding: .1rem; }
  .lobby-hub--searching .hub-entry__en { display: none; }
  .lobby-hub--searching .hub-entry__name { font-size: calc(.22 * var(--utility-text)); }

  .settings-modal .set-list { gap: .15rem; }
  .settings-modal .set-row { gap: .2rem; min-height: .75rem; }
  .settings-modal .set-row__label { gap: .125rem; line-height: 1.35; font-size: calc(.18 * var(--t)); }
  .settings-modal .set-row__label .micro { font-size: calc(.11 * var(--t)); }
  .settings-modal .set-row__label .icon { width: .35rem; height: .35rem; }
  .settings-modal .set-row__val { font-size: calc(.18 * var(--t)); }
  .settings-modal :is(.set-seg button, .set-toggle, .set-key, .shortcut-key) {
    min-height: .75rem; height: auto; padding: .1rem .175rem;
    font-size: calc(.16 * var(--t)); line-height: 1.25;
  }
  .settings-modal .set-seg button { min-width: 0; }
  .settings-modal .set-toggle { padding: .1rem .2rem; }
  .settings-modal .modal__actions .btn { min-height: .75rem; font-size: calc(.16 * var(--t)); }
  .settings-modal .set-toggle i { width: .7rem; height: .4rem; }
  .settings-modal .set-toggle i::after { left: .05rem; top: .05rem; width: .3rem; height: .3rem; }
  .settings-modal .set-toggle.is-on i::after { transform: translateX(.3rem); }
  .settings-modal .set-range { height: .7rem; border-block: .25rem solid transparent; }
  .settings-modal .set-range::-webkit-slider-thumb { width: .35rem; height: .5rem; }
  .settings-modal .set-range::-moz-range-thumb { width: .35rem; height: .5rem; }
  .settings-modal .set-hint { font-size: calc(.14 * var(--t)); }
  .settings-modal .set-res, .settings-modal .set-res__body { gap: .1rem; }
  .settings-modal .set-keys, .settings-modal .set-keys__row, .settings-modal .set-diag { gap: .1rem; }
  .settings-modal .set-diag { padding-top: .15rem; }
  .settings-modal .set-diag__text { height: 2.4rem; min-height: 1.6rem; }

  .utility-modal.about-panel .about-links { gap: .2rem; }
  .utility-modal.about-panel .about-links dt { margin-bottom: .075rem; font-size: calc(.16 * var(--t)); }
  .utility-modal.about-panel .about-links dd { font-size: calc(.2 * var(--t)); line-height: 1.7; }
  .utility-modal.about-panel .about-section { margin-top: .25rem; padding-top: .15rem; }
  .utility-modal.about-panel .about-section h3,
  .utility-modal.about-panel .about-section p { font-size: calc(.16 * var(--t)); }
  .utility-modal.about-panel .about-section p + p { margin-top: .125rem; }
}

/* Below a real phone width there is only one column: the resource tiers and the lobby stack, the
   room seats fall into two columns and then into one, and the statistics tables scroll sideways. */
@media (max-width: 560px) {
  .resource-manager__tiers { grid-template-columns: minmax(0, 1fr); }
  .lobby-screen .lobby-body { grid-template-columns: minmax(0, 1fr); }
  .room-screen .seats { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; overflow-y: auto; align-content: start; }
  .room-screen .seat { min-height: 3.5rem; }
  .room-screen--coop .seats { flex-basis: 7.6rem; grid-template-rows: none; grid-auto-rows: minmax(3.5rem, auto); }
  .room-screen .seats--solo { grid-template-columns: minmax(0, 1fr); }
  .room-screen .topbar { grid-template-columns: minmax(0, .85fr) minmax(0, 1.3fr) minmax(0, .85fr); grid-template-areas: "controls title invite"; }
  .room-screen .topbar__left { flex-direction: column; align-items: flex-start; }
  .room-screen .topbar__right { justify-self: end; }
  .room-screen .invite { display: flex; flex-direction: column; align-items: center; width: auto; }
  .room-screen .invite__btns { flex-direction: row; justify-content: center; flex-wrap: nowrap; }
  .room-screen .room-bar { grid-template-columns: minmax(0, 1fr); grid-template-areas: "options" "status" "actions"; }
  .room-screen .room-bar__right { justify-self: stretch; }
  .lo-top, .st-top { grid-template-columns: auto minmax(0, 1fr); }
  .lo-top__center, .st-top__center { grid-column: 1 / -1; grid-row: 2; }
  .lo-top__right, .st-top__right { grid-column: 2; grid-row: 1; }
  .st-tablewrap { overflow-x: auto; touch-action: pan-x; }
}

/* Keep resource planning readable at compact game text sizes; geometry still uses the viewport scale. */
.utility-modal.resource-modal { --utility-text: max(var(--t), 92px); }
.utility-modal.resource-modal .modal__title { font-size: max(calc(.22 * var(--utility-text)), 18px); }
.utility-modal.resource-modal .modal__head { padding: 10px 12px; }
.utility-modal.resource-modal .modal__head .micro { font-size: calc(.1 * var(--utility-text)); }
.utility-modal.resource-modal button.btn { min-height: 32px; padding: 6px 12px; font-size: calc(.14 * var(--utility-text)); }
.resource-modal .resource-presets button { min-height: 30px; padding: 5px 8px; font-size: calc(.13 * var(--utility-text)); }
.resource-modal .resource-choice input { width: 14px; height: 14px; }
:root[data-text="md"] .utility-modal.resource-modal { --utility-text: max(var(--t), 100px); }
:root[data-text="lg"] .utility-modal.resource-modal { --utility-text: max(var(--t), 112px); }
:root[data-text="xl"] .utility-modal.resource-modal { --utility-text: max(var(--t), 124px); }
@media (orientation: landscape) and (max-height: 600px) {
  .modal--utility .resource-modal { width: min(16rem, 100%); }
  .resource-modal .resource-manager { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: stretch; gap: 6px; }
  .resource-manager > .resource-scope, .resource-manager > .resource-archive { min-width: 0; }
  .resource-manager > :not(.resource-scope):not(.resource-archive) { grid-column: 1 / -1; }
  .resource-modal .resource-scope__head { gap: 4px; }
  .resource-modal .resource-scope .resource-presets { gap: 3px; }
  .resource-modal .resource-scope .resource-presets button { padding: 4px 5px; min-height: 28px; font-size: 11px; }
  .resource-modal .resource-overview strong { font-size: max(calc(.18 * var(--utility-text)), 16px); }
  .resource-modal .resource-archive__toolbar > p { flex-basis: 100%; }
}
@media (orientation: landscape) and (max-width: 800px) {
  .resource-modal .resource-card__description { min-height: 3.1em; }
}
