/* =====================================================================================
   [mobile] [mobile-ui] HOPPA on a phone / a tablet. Every rule here sits under html.is-touch (index.html sets it on a
   touch-primary device only), so a desktop never matches one of them: the desktop look is untouched by construction.
   The design (grid, sizes, the HUD map per device class): docs/MOBILE-UI.md.
     html.is-touch                       any touch screen (the tokens below, the HUD, the touch pad)
     html.is-touch:not(.is-tablet)       a phone, held sideways (667–932 × 375–430); upright → TURN YOUR PHONE
     html.is-touch.is-tablet             an iPad / a tablet (≥ 600 px short side), sideways AND upright
   Lightweight by rule: no backdrop blur, no looping / decorative motion, no transitions (state shows at once), the
   menus appear without entrance motion; a press shows on touchstart (:active / .is-down), never on hover.
   ===================================================================================== */

/* ------------------------------------------------------------------ tokens (docs/MOBILE-UI.md § Tokens) */
html.is-touch {
  --t-gut: 12px;            /* the safe frame's inner margin */
  --t-gap: 8px;             /* the rhythm */
  --t-hit: 44px;            /* a target, never less */
  --t-hud: 44px;            /* a HUD button's diameter */
  --t-row: 48px;            /* a menu row / pill button */
  --t-head: 56px;           /* a screen's header band (back + title) */
  --t-r: 14px;              /* a card's corner */
  --t-fs: 14px;             /* body */
  --t-fs-s: 12.5px;         /* secondary */
  --t-fs-cap: 11px;         /* caps labels */
  --t-fs-title: 20px;       /* a screen title */
  --t-ink: #1e2130; --t-deep: #141620; --t-paper: #f3ece0; --t-sand: #e3d9c6; --t-y: #ffffff; --t-mist: #9a9eab;   /* [ui-colors] --t-y = the neutral white highlight (the name kept); the colour is the cut lines (ui.css --hp-cut*) */
  --t-glass: rgba(22, 25, 38, .62);          /* a translucent control over the city */
  --t-glass-hi: rgba(22, 25, 38, .82);       /* a panel over the city */
  --t-rim: rgba(243, 236, 224, .3);          /* a control's rim */
}
html.is-touch.is-tablet {
  --t-gut: 20px; --t-gap: 10px; --t-hit: 48px; --t-hud: 52px; --t-row: 54px; --t-head: 68px; --t-r: 18px;
  --t-fs: 16px; --t-fs-s: 14px; --t-fs-cap: 12px; --t-fs-title: 26px;
}

/* ------------------------------------------------------------------ iOS: no zoom / callout / rubber-band / selection */
html.is-touch, html.is-touch body { overscroll-behavior: none; -webkit-text-size-adjust: 100%; text-size-adjust: 100%; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
html.is-touch body { position: fixed; inset: 0; width: 100%; height: 100%; }
html.is-touch #app, html.is-touch #app canvas { touch-action: none; }
html.is-touch #ui-root * { -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }
html.is-touch input, html.is-touch textarea { -webkit-user-select: text; user-select: text; touch-action: manipulation; font-size: max(16px, 1em); }   /* (16 px: iOS never zooms into a field) */
html.is-touch .iw-screen, html.is-touch .hs-rows, html.is-touch .pz-chat__log, html.is-touch .pz-inv { touch-action: pan-x pan-y; }
html.is-touch button, html.is-touch [role="button"], html.is-touch [data-nav], html.is-touch .iw-btn, html.is-touch .pz-card, html.is-touch .pz-act, html.is-touch .pz-mm,
html.is-touch .pz-bd-wrap, html.is-touch .pz-hb__slot, html.is-touch .pz-note.is-click { touch-action: manipulation; }   /* (no 300 ms wait for a double tap; core/touch.js _taps acts on the lift) */   /* (no 300 ms wait for a double tap) */

/* ------------------------------------------------------------------ lightweight (the coordinator's rule: see the header) */
html.is-touch #ui-root *, html.is-touch #ui-root *::before, html.is-touch #ui-root *::after, html.is-touch .tc-home {
  -webkit-backdrop-filter: none !important; backdrop-filter: none !important;   /* (the costliest thing iOS composites) */
  transition: none !important;                                                    /* (a state shows on the frame it changes) */
  animation-iteration-count: 1 !important;                                        /* (no loops: pulses / spins / bobs play once) */
}
html.is-touch .iw-in, html.is-touch .iw-in--logo { animation: none !important; }   /* (a menu is there at once, no staggered entrance) */
html.is-touch .iw-screen.is-leaving { display: none; }                              /* (the old screen goes at once, no 340 ms cross-fade) */
html.is-touch .iw-screen { contain: layout paint style; }
/* [punk-logo] (no logo idle on touch) */
html.is-touch :is(.hp-plogo__top, .hp-plogo__bot) { animation: none; }
/* a press shows on touchstart (iOS fires :active with any touchstart listener on the document: touch.js has one) */
html.is-touch .iw-btn:active, html.is-touch .pz-card:active, html.is-touch .hs-tab:active { scale: .97; }

/* ------------------------------------------------------------------ the safe frame */
/* (the insets as variables: tools/phone.html sets them to a real phone's notch / home bar in a desktop preview) */
html.is-touch { --sa-l: env(safe-area-inset-left, 0px); --sa-r: env(safe-area-inset-right, 0px); --sa-t: env(safe-area-inset-top, 0px); --sa-b: env(safe-area-inset-bottom, 0px); }
html.is-touch #app { right: auto; bottom: auto; width: 100vw; height: 100dvh; }   /* [viewport] (core/viewport.js pins it to the view's px size: the renderer's own — dvh until then, never the large-viewport vh) */
html.is-touch #ui-root {
  left: var(--sa-l); right: var(--sa-r);
  top: var(--sa-t); bottom: var(--sa-b);
  contain: layout;   /* (the fixed-position layers inside — the city's HUD, the war's — measure from this frame too) */
  overflow: visible;
}
/* the name tags / callouts are placed in viewport px (ui.js projects the camera): undo the frame's offset for them */
html.is-touch .pz-tags, html.is-touch .pz-callouts { position: absolute; left: calc(-1 * var(--sa-l)); top: calc(-1 * var(--sa-t)); }

/* ------------------------------------------------------------------ keyboard furniture goes */
html.is-touch .pz-bd__key, html.is-touch .pz-popup__key, html.is-touch .pz-hb__key, html.is-touch .pz-mm__tab kbd, html.is-touch .pz-act kbd,
html.is-touch .hs-tabs__key, html.is-touch .iw-prompts, html.is-touch .pz-bd-wrap[data-tip]::after, html.is-touch .pz-wx-wrap[data-tip]::after,
html.is-touch .pz-note.is-chat, html.is-touch .pz-inv__keys, html.is-touch .iw-cursor { display: none !important; }
html.is-touch .pz-war__me kbd, html.is-touch .pz-war kbd.pz-war__key { display: none; }
html.is-touch .iw-kbm, html.is-touch .iw-tabs__hint, html.is-touch .iw-ui .iw-btn .iw-key { display: none !important; }

/* =====================================================================================
   THE TOUCH PAD (src/core/touch.js): floating joystick (left), FIRE / JUMP / RUN·DASH / the context button (right)
   ===================================================================================== */
.tc { --y: #ffffff;   /* [ui-colors] (white + the cut lines; never a coloured fill) */
  --ink: #1e2130; --paper: #f3ece0; --glass: rgba(22, 25, 38, .55); --rim: rgba(243, 236, 224, .5);
  position: absolute; inset: 0; z-index: 16; pointer-events: none; display: none; font-family: 'Titan One', 'Rubik', sans-serif; -webkit-user-select: none; user-select: none; }
.tc.is-on { display: block; }
.tc button { -webkit-appearance: none; appearance: none; margin: 0; padding: 0; border: 0; font: inherit; color: inherit; background: none; touch-action: none; }
.tc [hidden] { display: none !important; }

/* the floating joystick: drawn where the thumb lands (touch.js moves it), only while held */
.tc-stick { position: fixed; left: 0; top: 0; width: 0; height: 0; opacity: 0; will-change: transform; }
.tc-stick.is-on { opacity: 1; }
.tc-stick__ring { position: absolute; left: -60px; top: -60px; width: 120px; height: 120px; border-radius: 50%; background: rgba(22, 25, 38, .3); box-shadow: inset 0 0 0 3px var(--rim); }
.tc-stick__nub { position: absolute; left: -28px; top: -28px; width: 56px; height: 56px; border-radius: 50%; background: var(--paper); box-shadow: 0 0 0 3px var(--ink); will-change: transform; }

/* [ui-sizes] the right thumb's buttons: FIRE big in the bottom-right corner, JUMP stacked right above it (the thumb rolls
   up from FIRE to JUMP: a .26 s gap between them), the yellow context button left of JUMP when a prompt shows.
   No RUN / DASH: the stick at full tilt runs (a city and a Boss War alike). */
.tc-pad { --s: clamp(64px, 17dvh, 92px); position: absolute; right: max(14px, 2.4vw); bottom: max(12px, 4dvh); width: calc(var(--s) * 2.2); height: calc(var(--s) * 2.36); pointer-events: none; }
.tc .tc-btn { position: absolute; display: grid; place-items: center; border-radius: 50%; pointer-events: auto; color: var(--paper);
  background: var(--glass); box-shadow: inset 0 0 0 2.5px var(--rim); }
.tc .tc-btn.is-down { transform: scale(.92); background: var(--y); color: var(--ink); box-shadow: inset 0 0 0 3px var(--ink); }
.tc-btn__ico { display: block; width: 46%; height: 46%; }
.tc-btn__ico svg { display: block; width: 100%; height: 100%; }
.tc-btn__lbl { position: absolute; left: 50%; bottom: -1.35em; translate: -50% 0; font: 400 11px/1 'Titan One', 'Rubik', sans-serif; letter-spacing: .04em; color: var(--paper); white-space: nowrap;
  -webkit-text-stroke: 3px var(--ink); paint-order: stroke fill; }
.tc-btn--fire { right: 0; bottom: 0; width: calc(var(--s) * 1.18); height: calc(var(--s) * 1.18); }
.tc-btn--fire .tc-btn__ico { width: 52%; height: 52%; }
.tc-btn--jump { right: calc(var(--s) * .14); bottom: calc(var(--s) * 1.44); width: calc(var(--s) * .9); height: calc(var(--s) * .9); }
.tc-btn--down { right: calc(var(--s) * .14); bottom: calc(var(--s) * .22); width: calc(var(--s) * .9); height: calc(var(--s) * .9); }   /* [soul] a Boss War soul's descend: FIRE's spot (a soul never shoots), under JUMP (rise) */
.tc-btn--act .tc-btn__lbl { bottom: auto; top: -1.3em; }
/* the context button: the one yellow thing (it is what the prompt points at) — left of JUMP, above-left of FIRE
   [ui-sizes] (.tc-prefixed: `.tc button { background: none }` outranked these — the pad was see-through, the context button not yellow) */
.tc .tc-btn--act { right: calc(var(--s) * 1.38); bottom: calc(var(--s) * 1.0); width: calc(var(--s) * .8); height: calc(var(--s) * .8); background: var(--y); color: var(--ink); box-shadow: inset 0 0 0 3px var(--ink); }
.tc-btn--act .tc-btn__lbl { right: auto; }
.tc .tc-btn--act.is-down { background: var(--paper); }
/* the war: the hotbar + HP / DASH group own the bottom centre — the pad stays right of it */
.tc.is-hotbar .tc-pad { --s: clamp(60px, 15.5dvh, 86px); }
/* the big map up: only its ✕ (the map takes the taps) */
.tc .tc-mapx { display: none; position: absolute; right: max(14px, 2vw); top: max(10px, 2.5dvh); width: 48px; height: 48px; }
.tc.is-map .tc-mapx { display: grid; }   /* [ui-sizes] (.tc-prefixed with .tc .tc-btn: the ✕ must stay hidden off the map) */
.tc.is-map .tc-pad, .tc.is-card .tc-pad { display: none; }
.tc-mapx .tc-btn__ico { width: 44%; height: 44%; }
html.is-touch.is-tablet .tc-pad { --s: clamp(76px, 11dvh, 96px); right: 24px; bottom: 24px; }
html.is-touch.is-tablet .tc.is-hotbar .tc-pad { --s: clamp(72px, 10dvh, 90px); }
html.is-touch.is-tablet .tc-btn__lbl { font-size: 12px; }

/* the prompts' key: the context button's hand */
html.is-touch .tc-kbd { display: inline-grid; place-items: center; width: 1.7em; height: 1.7em; padding: 0; vertical-align: -.45em; border-radius: 50%; background: #ffffff; color: #1e2130; box-shadow: 0 0 0 2px #1e2130; }   /* [ui-colors] */
html.is-touch .tc-kbd svg { width: 62%; height: 62%; }

/* "Add to Home Screen" (iOS Safari): a small one-time tip at the top of the title screen, never over a button */
.tc-home { position: fixed; z-index: 45; left: 50%; top: max(10px, var(--sa-t)); translate: -50% 0; display: flex; align-items: center; gap: 8px; max-width: calc(100vw - 32px);
  padding: 5px 5px 5px 12px; border: 0; border-radius: 999px; background: rgba(22, 25, 38, .86); color: rgba(243, 236, 224, .86); box-shadow: inset 0 0 0 1.5px rgba(243, 236, 224, .18);
  font: 500 12px/1.2 'Rubik', system-ui, sans-serif; white-space: nowrap; touch-action: manipulation; }
.tc-home b { font-weight: 800; color: #f3ece0; }
.tc-home__share { display: inline-block; width: 9px; height: 11px; margin: 0 1px; vertical-align: -1px; border: 1.5px solid currentColor; border-top: 0; border-radius: 0 0 2px 2px; position: relative; }
.tc-home__share::before { content: ''; position: absolute; left: 2.2px; top: -6px; width: 1.5px; height: 8px; background: currentColor; }
.tc-home__x { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; background: rgba(243, 236, 224, .1); }
.tc-home__x svg { width: 10px; height: 10px; }
.tc-home.is-off { display: none; }
html.is-standalone .tc-home { display: none; }

/* ------------------------------------------------------------------ a phone upright: turn it (never on a tablet) */
#hp-rotate { display: none; }
@media (orientation: portrait) {
  html.is-touch:not(.is-tablet) #hp-rotate { position: fixed; inset: 0; z-index: 100; display: grid; place-items: center; background: #141620; color: #f3ece0; touch-action: none; }
  html.is-touch:not(.is-tablet) .tc-home { display: none; }
}
.hp-rotate__card { display: flex; flex-direction: column; align-items: center; gap: 14px; padding: 28px; text-align: center; }
.hp-rotate__phone { display: block; width: 92px; height: 92px; color: #ffffff; rotate: -90deg; }   /* [ui-colors] (still: the phone already lies on its side) */
.hp-rotate__phone svg { width: 100%; height: 100%; display: block; }
.hp-rotate__title { font: 400 30px/1.05 'Titan One', 'Rubik', sans-serif; letter-spacing: .02em; color: #f3ece0; max-width: 300px; }
.hp-rotate__sub { font: 600 15px/1.35 'Rubik', system-ui, sans-serif; color: #c9c3b7; max-width: 280px; }

/* ------------------------------------------------------------------ the menus' backdrop: the city's still (src/ui/backdrop.js), HOPPA navy under it */
/* (main.js _menuStill: nothing simulates or renders behind the menus; the canvas hides) — [backdrop-video] the panels' scrims sit inside
   the safe frame (they read as dark bars round the notch over a full-bleed still): off here, the still's own full-bleed dim (src/ui/backdrop.js) instead */
html.is-touch.is-menu-still body { background: linear-gradient(180deg, #1e2130 0%, #141620 100%); }
html.is-touch.is-menu-still #app { visibility: hidden; }
html.is-touch.is-menu-still .iw-pause__dim, html.is-touch.is-menu-still .pz-main__scrim, html.is-touch.is-menu-still .iw-scrim-left,
html.is-mobile-kbd.is-menu-still .iw-pause__dim, html.is-mobile-kbd.is-menu-still .pz-main__scrim, html.is-mobile-kbd.is-menu-still .iw-scrim-left { background: none !important; }
/* a menu over the city: its dim also covers the notch strips outside the safe frame */
html.is-touch:not(.is-menu-still) .iw-ui.is-active { box-shadow: 0 0 0 80px rgba(16, 18, 28, .66); }

/* =====================================================================================
   THE CITY HUD (src/social/ui.js) — docs/MOBILE-UI.md § HUD map.
     top-left   MENU · CHAT · ACT (44 px glass buttons, no captions) and the corner map under them (tap = the big map)
     top-right  the clock · BOSS WAR (a pill: its round's state) · the weather dial; the coins under the dial
     bottom     the notice stack (centre) · the joystick (left, floating) · the pad (right)
   MESSAGES · FRIENDS · STALL · LOCKER live in MENU (a dot on it says when a message / a request waits); MAP is the
   corner map; VISIT is the yellow context button.
   ===================================================================================== */
html.is-touch .pz-hud { --bd: var(--t-hud); }
html.is-touch .pz-top { left: var(--t-gut); right: var(--t-gut); top: 8px; transform: none; justify-content: flex-start; align-items: center; gap: var(--t-gap);
  padding-left: calc(var(--t-hud) + var(--t-gap)); padding-right: calc(var(--t-hud) + var(--t-gap)); }
html.is-touch .pz-corner--menu { left: var(--t-gut); top: 8px; }
html.is-touch .pz-top, html.is-touch .pz-corner--menu, html.is-touch .pz-wx-wrap { z-index: 1003; }   /* (over the name tags, 0–1000: the ACT fan drops across the street) */
html.is-touch .pz-top__grp { align-items: center; gap: var(--t-gap); }
html.is-touch .pz-top__grp--r { margin-left: 0; }
html.is-touch .pz-bd-wrap { width: auto; gap: 0; }
html.is-touch .pz-bd-wrap--messages, html.is-touch .pz-bd-wrap--friends, html.is-touch .pz-bd-wrap--stall, html.is-touch .pz-bd-wrap--locker,
html.is-touch .pz-bd-wrap--map, html.is-touch .pz-bd-wrap--visit, html.is-touch .pz-bd-wrap--visit.is-on { display: none; }
/* a HUD button: a glass disc, a paper glyph; pressed / on = the yellow */
html.is-touch .pz-bd { background: var(--t-glass); box-shadow: inset 0 0 0 2px var(--t-rim); }
html.is-touch .pz-bd__disc { display: none; }
html.is-touch .pz-bd__ico { inset: 27%; color: var(--t-paper); }
html.is-touch .pz-bd:active, html.is-touch .pz-bd.is-active, html.is-touch .pz-bd-wrap--act.is-open .pz-bd { background: var(--t-y); box-shadow: none; }
html.is-touch .pz-bd:active .pz-bd__ico, html.is-touch .pz-bd.is-active .pz-bd__ico, html.is-touch .pz-bd-wrap--act.is-open .pz-bd__ico { color: var(--t-ink); }
html.is-touch .pz-bd__lbl { display: none; }
html.is-touch .pz-bd__badge { right: -4px; bottom: auto; top: -4px; min-width: 18px; height: 18px; font-size: 11px; line-height: 18px; box-shadow: 0 0 0 2px var(--t-ink); }
html.is-touch .pz-hud .pz-bd--menu .pz-bd__badge { display: none; }
/* (iOS keeps the last-tapped element :hover: the desktop's hover lifts / tooltips must not stick on glass) */
html.is-touch .pz-hud.is-free .pz-bd:hover { transform: none; box-shadow: inset 0 0 0 2px var(--t-rim); }
html.is-touch .pz-hud.is-free .pz-bd:hover .pz-bd__ico { color: var(--t-paper); transform: none; }
html.is-touch .pz-hud.is-free .pz-wx:hover, html.is-touch .pz-popup__btn:hover, html.is-touch .pz-chat__form.has-text .pz-chat__send:hover { transform: none; }
html.is-touch .pz-mm:hover .pz-mm__disc { transform: none; box-shadow: inset 0 0 0 2px var(--t-rim); }
html.is-touch .iw-ui .iw-backbtn:hover, html.is-touch .iw-backbtn:hover { transform: none; }
html.is-touch .pz-loc__row:hover, html.is-touch .pz-profile__geo:hover, html.is-touch .pz-tod__tile:hover { transform: none; translate: none; }
/* MENU wears a dot while MESSAGES / FRIENDS wait (their own badges are hidden on a phone) */
html.is-touch .pz-hud.pzh-badge .pz-bd--menu::after,   /* [perf-p2] pzh-*: src/ui/hasClasses.js (was :has()) */
html.is-touch .pz-bd.has-new::after { content: ''; position: absolute; right: 1px; top: 1px; width: 12px; height: 12px; border-radius: 50%; background: var(--t-y); box-shadow: 0 0 0 2px var(--t-ink); }   /* [ui-colors] the new-dot: white */
/* the clock: a small glass pill (time only), pushed to the right group's side */
html.is-touch .pz-clock { order: 0; margin-left: auto; min-width: 0; height: 32px; padding: 0 12px; gap: 0; background: var(--t-glass); box-shadow: inset 0 0 0 1.5px var(--t-rim); }
html.is-touch .pz-clock__time { font-size: 15px; }
html.is-touch .pz-clock__city { display: none; }
/* BOSS WAR: a pill — its glyph and the round's state (GATHERING · 0:18 / LIVE · 24/30 / NEXT IN 0:20); the whole pill taps */
html.is-touch .pz-bd-wrap--bosswar { flex-direction: row; align-items: center; height: var(--t-hud); padding-right: 14px; gap: 8px; border-radius: 999px; background: var(--t-glass); box-shadow: inset 0 0 0 2px var(--t-rim); pointer-events: auto; }
html.is-touch .pz-bd-wrap--bosswar .pz-bd { background: none; box-shadow: none; }
html.is-touch .pz-bd-wrap--bosswar .pz-bd__lbl { display: block; font: 800 var(--t-fs-cap) / 1 'Rubik', sans-serif; letter-spacing: .08em; color: var(--t-paper); text-shadow: none; }
html.is-touch .pz-bd-wrap--bosswar.is-gather { background: var(--hp-cut-pill), var(--t-y); box-shadow: none; }   /* [ui-colors] the BOSS WAR pill: white + the cut */
html.is-touch .pz-bd-wrap--bosswar.is-gather .pz-bd__ico, html.is-touch .pz-bd-wrap--bosswar.is-gather .pz-bd__lbl { color: var(--t-ink); }
html.is-touch .pz-bd-wrap--bosswar .pz-bd::after { display: none; }   /* (no pulsing ring: the pill says it) */
/* the weather dial: the right corner's disc (the temperature only) */
html.is-touch .pz-wx-wrap { width: var(--t-hud); right: var(--t-gut); top: 8px; }
html.is-touch .pz-wx { background: var(--t-glass); box-shadow: inset 0 0 0 2px var(--t-rim); }
html.is-touch .pz-wx__disc { display: none; }
html.is-touch .pz-wx__ico { top: 12%; width: 42%; height: 42%; filter: none; }
html.is-touch .pz-wx__temp { top: 58%; font-size: 11px; }
html.is-touch .pz-wx__sub { display: none; }
html.is-touch .pz-wx__pop { width: min(300px, 70vw); background: var(--t-glass-hi); }
/* the big map up: its ✕ owns the top-right corner (touch.js); the dial and the coins step aside */
html.is-touch body.pzh-map .pz-wx-wrap, html.is-touch body.pzh-map .pz-coinhud { visibility: hidden; }
/* the coins: under the dial, right-aligned */
html.is-touch .pz-coinhud { right: var(--t-gut); left: auto; top: calc(8px + var(--t-hud) + var(--t-gap)); bottom: auto; transform: none; padding: 4px 10px 4px 5px; border-radius: 999px; background: var(--t-glass); }
html.is-touch .pz-coinhud.is-on { transform: none; }
html.is-touch .pz-coinhud__ico { width: 20px; height: 20px; }
html.is-touch .pz-coinhud__n { font-size: 15px; }
html.is-touch body.pzh-warbar .pz-coinhud { display: none; }   /* (the war: its own HUD has the top-right) */   /* [inv-e] (the city bar is up too now: the coins stay) */
/* the corner map: under MENU (tap = the big map), its city's name small under it */
html.is-touch .pz-mm { --mm: 84px; left: var(--t-gut); top: calc(8px + var(--t-hud) + var(--t-gap) + 2px); bottom: auto; }
html.is-touch .pz-mm__disc { box-shadow: inset 0 0 0 2px var(--t-rim); }
html.is-touch .pz-mm__tab { display: none; }
html.is-touch .pz-mm__name { font-size: var(--t-fs-cap); margin-top: 3px; max-width: 120px; }
html.is-touch body.pzh-mmhide .pz-mm { visibility: hidden; }   /* (under a screen's back button) */
html.is-touch.is-tablet .pz-mm { --mm: 120px; }
/* ACT's eight actions: a 2-column grid of pills dropping from the button (left-aligned: the button is in the corner);
   open only while ACT is (iOS keeps a tapped element :hover — the desktop's hover-to-open would stick) */
html.is-touch .pz-top__fan { left: 0; translate: none; width: max-content; display: grid; grid-template-columns: repeat(2, minmax(96px, auto)); gap: 6px; padding-top: var(--t-gap); transform: none; }
html.is-touch .pz-hud.is-free .pz-bd-wrap--act:hover:not(.is-open) .pz-top__fan { visibility: hidden; opacity: 0; }
html.is-touch .pz-top__fan .pz-act { animation: none; min-width: 0; min-height: 40px; display: flex; align-items: center; padding: 0 14px; font-size: var(--t-fs-s); border-radius: 999px; background: var(--t-ink); box-shadow: inset 0 0 0 1.5px var(--t-rim); white-space: nowrap; }
html.is-touch .pz-act:hover { transform: none; background: var(--t-ink); color: #fff; }
html.is-touch .pz-act:active, html.is-touch .pz-act.is-active { background: var(--t-y); color: var(--t-ink); }
/* the chat: closed = only the CHAT button (a dot on it when a line arrives: touch.js); open = a panel under the top-left
   buttons, the field FIRST (the on-screen keyboard covers the lower half), the log under it */
html.is-touch .pz-chat { left: var(--t-gut); bottom: 6px; --cw: min(300px, 38%); }
html.is-touch .pz-chat:not(.is-open) .pz-chat__log { display: none; }
html.is-touch .pz-chat.is-open { top: calc(8px + var(--t-hud) + var(--t-gap)); bottom: auto; flex-direction: column-reverse; }
html.is-touch .pz.is-typing .pz-chat { --cw: min(520px, 62%); }
html.is-touch .pz-chat.is-open .pz-chat__log { max-height: 34dvh; background: var(--t-glass-hi); border-radius: var(--t-r); }
html.is-touch .pz-chat__box { height: var(--t-row); background: rgba(22, 25, 38, .92); }
html.is-touch .pz-chat__send { width: 36px; height: 36px; }
html.is-touch .pz-chat__log > * { font-size: var(--t-fs-s); }
/* the notice stack: bottom-centre (the rule), a little narrower than a desktop's */
html.is-touch .pz-notes { max-width: min(460px, 52%); }
html.is-touch .pz-note { font-size: var(--t-fs-s); }

/* ---- the Boss War HUD (bosswar.js, warHotbar.js, hud-boss.js, warClock.js) */
html.is-touch { --t-hs: 40px; }
html.is-touch.is-tablet { --t-hs: 48px; }
html.is-touch .pz-hotbar { --hs: var(--t-hs); --hg: 4px; bottom: 6px; }
/* HP · DASH ride just over the hotbar (the strip is px-sized on touch; its own rule is in --u) */
html.is-touch .pz-war__me, html.is-touch .pz-war.has-hotbar .pz-war__me { bottom: calc(6px + max(var(--t-hs), 44px) + 22px); }   /* (the strip is as tall as its 44 px bag) */
html.is-touch .pz-hb__slot, html.is-touch .pz-hb__inv { touch-action: manipulation; }
html.is-touch .pz-hb__slot:hover, html.is-touch .pz-hb__inv:hover { background: inherit; }
html.is-touch .pz-hb__inv { width: 44px; height: 44px; }
/* [inv-e] the inventory on a touch screen: cells as big as the screen allows (a thumb's 44 px+ on a phone held sideways),
   smaller upright — always 4 × 10; no key hints */
html.is-touch .pz-inv { --cs: min(56px, calc((100vw - var(--sa-l, 0px) - var(--sa-r, 0px) - 40px) / 11.3), calc((100dvh - var(--clr, 60px) - var(--sa-t, 0px) - 24px) / 6.2)); }
html.is-touch .pz-inv__locker kbd { display: none; }
html.is-touch .pz-inv__keys.is-msg { display: block !important; }   /* [inv-e] (a message from the bar shows; the key hints don't) */
html.is-touch .pz-inv__cell:hover { background: rgba(8, 10, 18, .55); }
html.is-touch .pz-inv__cell.is-empty:hover { background: rgba(8, 10, 18, .28); }
html.is-touch .pz-war-seats__list { height: calc(var(--u) * 7.2); align-content: flex-start; }   /* (the invite card keeps one height while the seats fill: its JOIN never slides from under a thumb) */
/* the cards that ask (the Boss War invite / seat card, a friend request, the send card): [viewport] centred in the safe
   frame (the user, iPhone: "the join Boss War popup is not centred" — it was a bottom-right sheet); the primary answer is
   the right-most button. A card taller than the frame scrolls inside it (max-height) */
html.is-touch .pz-popup { left: 50%; right: auto; top: 50%; bottom: auto; translate: -50% -50%; }
html.is-touch .pz-popup__card { max-height: calc(100dvh - var(--sa-t) - var(--sa-b) - 16px); overflow-y: auto; overscroll-behavior: contain; }
html.is-touch .pz-popup__card { width: min(360px, 46vw); box-shadow: 0 0 0 3px var(--t-ink); }
html.is-touch .pz-popup__btns { flex-direction: row-reverse; width: 100%; }
html.is-touch .pz-popup__btn { flex: 1; min-height: var(--t-hit); font-size: 15px; }
html.is-touch .pz-war-seats__list li { font-size: 12px; }
html.is-touch .pz-war-seats__n { font-size: 15px; }
/* the war's top: the boss bars keep one line per name; the war clock takes the top-right corner (the dial is away) */
html.is-touch .iw-bb__name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.is-touch .pz-warclock__dial { right: var(--t-gut); top: 8px; }
/* the hotbar: empty slots fold away on a touch screen (the strip stays short, between the thumbs) */
html.is-touch .pz-hb__slot.is-empty { display: none; }
html.is-touch .pz-war-res { max-height: calc(100% - 12px); overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
html.is-touch .pz-war-res__go { position: sticky; bottom: 6px; z-index: 2; min-height: var(--t-hit); }
/* [ui-audit] the sticky BACK TO REALITY sits on a strip of the card's own colour, the card's width: the rows scrolling under it
   no longer show half-hidden round the pill ("Rift Breaker badg" | BACK TO REALITY | "keep") */
html.is-touch .pz-war-res { overflow-x: hidden; border-radius: calc(var(--u) * 1.6); }
html.is-touch .pz-war-res__go::before { content: ''; position: absolute; z-index: -1; left: -60vw; right: -60vw; top: -10px; bottom: -6px; background: rgb(16, 18, 27); pointer-events: none; }

/* the TOUCH table's chips: the touch buttons' own words */
html.is-touch .tc-chip { display: inline-grid; place-items: center; min-width: 2.4em; height: 1.9em; padding: 0 .6em; margin-left: .3em; border-radius: 999px; background: rgba(243, 236, 224, .1);
  box-shadow: inset 0 0 0 1.5px rgba(243, 236, 224, .35); font: 400 max(11px, .8em) / 1 'Titan One', 'Rubik', sans-serif; letter-spacing: .04em; color: #f3ece0; white-space: nowrap; }

/* =====================================================================================
   THE MENUS on any touch screen
   ===================================================================================== */
/* the type scale's floors, raised for arm's length (the kit's --fs-* drive most of the menus' and cards' words) */
html.is-touch .iw-ui, html.is-touch .iw-hud, html.is-touch .iw-hud-over, html.is-touch .pz {
  --fs-xs: max(11.5px, calc(var(--u) * .8)); --fs-s: max(13px, calc(var(--u) * .95)); --fs-m: max(14.5px, calc(var(--u) * 1.1)); --fs-l: max(17px, calc(var(--u) * 1.4)); }
html.is-touch.is-tablet .iw-ui, html.is-touch.is-tablet .iw-hud, html.is-touch.is-tablet .iw-hud-over, html.is-touch.is-tablet .pz {
  --fs-xs: max(12.5px, calc(var(--u) * .8)); --fs-s: max(14.5px, calc(var(--u) * .95)); --fs-m: max(16px, calc(var(--u) * 1.1)); --fs-l: max(19px, calc(var(--u) * 1.4)); }
html.is-touch .iw-btn.is-focus { transform: rotate(var(--tilt, 0deg)); }   /* (no slide-out on a tap: the focus is the keyboard's / pad's) */
html.is-touch .iw-btn--primary::before { animation: none; }
/* a menu over the city is a sheet: one flat navy, the city barely through (no blur: the costliest layer on iOS) */
html.is-touch .iw-dimbg { background: rgba(20, 22, 32, .9); }
html.is-touch:not(.is-menu-still) .iw-pause__dim { background: rgba(20, 22, 32, .88); }

/* ---- the in-city MENU: a grid of tiles (glyph over word), RESUME the one primary — a full-width bar at the grid's
   foot (the left thumb's corner); the city panel (SOCIAL · DISTANCE) to the right */
html.is-touch .pz-pause .iw-pause__col { left: var(--t-gut); top: 8px; bottom: 8px; transform: none; width: calc(56% - var(--t-gut)); gap: var(--t-gap); }
html.is-touch .pz-pause .iw-pause__title { flex: none; }
html.is-touch .pz-pause .iw-pause__menu { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: clamp(64px, 22dvh, 128px); align-content: start; gap: var(--t-gap); padding-bottom: calc(var(--t-row) + 8px); }
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu { height: auto; min-height: 0; flex-direction: column; justify-content: center; align-items: center; gap: 6px; padding: 6px 4px; text-align: center;
  font-size: 12px; rotate: 0deg; transform: none; border-radius: var(--t-r); }
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__icon { width: 26px; height: 26px; }
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__text { max-width: 100%; }
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__label { white-space: normal !important; line-height: 1.15; }
html.is-touch.is-tablet .pz-pause .iw-pause__menu .iw-btn--menu { font-size: 14px; gap: 10px; }
html.is-touch.is-tablet .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__icon { width: 34px; height: 34px; }
html.is-touch .pz-pause .iw-pause__menu [data-id="resume"] { position: absolute; left: 0; right: 0; bottom: 0; height: calc(var(--t-row) + 4px); flex-direction: row; gap: 10px; font-size: 17px; }
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__blob { display: none; }
html.is-touch .pz-pause .pz-mp__city { font-size: 17px; }
html.is-touch .pz-pause .hs-row__label { font-size: var(--t-fs); }
html.is-touch .pz-pause .iw-pause__menu [data-id="resume"] .iw-btn__icon { width: 20px; height: 20px; }
html.is-touch .pz-pause .iw-pmatch { right: var(--t-gut); top: 8px; bottom: auto; transform: none; width: calc(44% - var(--t-gut) - var(--t-gap)); max-height: calc(100% - 16px); }

/* ---- HOW TO HOPPA: the cards' words readable at arm's length (the stickers shrink to make room) */
html.is-touch .iw-howto .iw-rule__text { font-size: var(--t-fs-s); line-height: 1.4; }
html.is-touch .iw-howto .iw-rule__title { font-size: 15px; }
/* ---- the Locker: thumb-sized tabs */
html.is-touch .iw-locker .iw-tab { min-height: var(--t-hit); font-size: 13px; }
/* ---- the city list (WHERE ARE YOU?): rows a thumb can hit, words readable */
html.is-touch .pz-loc__row { min-height: var(--t-hit); font-size: var(--t-fs-s); }

/* =====================================================================================
   PHONES held sideways (≤ 500 px tall): the menus re-flowed. The UI is sized in --u (1 % of a 16:9 frame fitted to
   the screen: ≈ 7 px on an iPhone).
   ===================================================================================== */
@media (max-height: 500px) {
  /* ---- every screen's header: compact, top-left */
  html.is-touch .iw-head { left: 12px; top: 8px; gap: 10px; }
  html.is-touch .iw-ui .iw-backbtn { width: 44px; height: 44px; }
  html.is-touch .iw-ui .iw-head__title { font-size: 20px; }
  html.is-touch .iw-ui .iw-head__sub { margin-top: 3px; font-size: 12px; }

  /* ---- MAIN MENU: the wordmark top-left, your card bottom-left, the menu down the right */
  html.is-touch .pz-main__logo { scale: 1.1; left: 18px; top: 16px; }
  html.is-touch .pz-main__me { left: 14px; right: auto; top: auto; bottom: 12px; width: min(330px, 44%); min-width: 0; }
  html.is-touch .pz-main__col { left: auto; right: 14px; translate: none; top: 12px; bottom: 12px; width: min(380px, 50%); min-width: 0; display: flex; flex-direction: column; justify-content: flex-end; }
  html.is-touch .pz-main--centre .pz-main__menu { gap: 7px; }
  html.is-touch .pz-main__col .iw-btn--menu { min-height: 46px; }
  html.is-touch .pz-main__col .pz-btn--enter { min-height: 64px; }
  html.is-touch .pz-main__desc, html.is-touch .iw-corner--bl { display: none !important; }

  /* ---- PICK A CITY · browse: one row of postcards that swipes sideways, each fully on screen */
  html.is-touch .pz-city__left { left: 12px; right: 12px; top: 64px; bottom: 8px; }
  html.is-touch .pz-city__label { display: none; }
  html.is-touch .pz-city__grid { display: flex; gap: 12px; overflow-x: auto; overflow-y: hidden; padding: 6px 2px 8px; align-items: stretch; scroll-snap-type: x proximity; -webkit-mask-image: none; mask-image: none; touch-action: pan-x; }
  html.is-touch .pz-city__grid .pz-card { flex: 0 0 auto; width: min(250px, 38vw); height: auto; scroll-snap-align: start; }
  html.is-touch .pz-city__grid .pz-card__art { flex: 1 1 auto; height: auto; min-height: 0; aspect-ratio: auto; }
  html.is-touch .pz-city__arrow { display: none !important; }
  /* · picked: the hero card left, TIME · YOU down the right (it scrolls), ENTER! always on screen at its foot */
  html.is-touch .pz-city__hero { left: 12px; top: 64px; width: calc(48% - 18px); max-height: calc(100% - 72px); }
  html.is-touch .pz-card--hero .pz-card__art { min-height: 0; }
  html.is-touch .pz-card--hero .pz-card__name { font-size: 24px; }
  html.is-touch .pz-city__right { right: 12px; top: 64px; bottom: 76px; width: calc(52% - 18px); gap: 8px; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; touch-action: pan-y; }
  html.is-touch .pz-city__right > * { flex: none; }
  /* (ENTER! sits under the column, never over its rows: fixed = to the screen, .iw-screen's containment) */
  html.is-touch .pz-city__right .iw-btn--start { position: fixed; right: 12px; bottom: 8px; z-index: 3; width: calc(52% - 18px); height: 60px; }
  html.is-touch .pz-city__grid .pz-card__body { flex: none; }

  /* ---- SETTINGS: the panel takes the screen under the header; its rows scroll */
  html.is-touch .hs-set .hs-panel, html.is-touch .iw-settings .hs-panel { left: 12px; right: 12px; top: 58px; bottom: 8px; width: auto; max-width: none; min-width: 0; max-height: none; translate: none; display: flex; flex-direction: column; }
  html.is-touch .hs-panel .hs-rows { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
  html.is-touch .hs-tab { min-height: 44px; }

  /* ---- the panel screens (profile · stall · browse · location · friends · chats): the panel left, the buttons right */
  html.is-touch .pz-stallform { left: 12px; top: 58px; width: calc(60% - 18px); min-width: 0; max-height: calc(100% - 66px); }
  html.is-touch .pz-panelscr__btns { right: 12px; left: auto; top: 58px; bottom: auto; width: calc(40% - 18px); min-width: 0; gap: 7px; }
  html.is-touch .pz-panelscr__btns .iw-btn--menu { width: 100%; min-height: 44px; }
  /* · profile: name + photo left, coins right, the photo buttons under the name panel */
  html.is-touch .pz-profscr .pz-prof { left: 12px; top: 58px; width: calc(52% - 18px); min-width: 0; }
  html.is-touch .pz-profscr .pz-prof.pz-prof__coins { left: auto; right: 12px; width: calc(48% - 18px); bottom: 8px; max-height: none; }
  html.is-touch .pz-prof__av { width: 72px; height: 72px; }
  html.is-touch .pz-profscr .pz-panelscr__btns { left: 12px; right: auto; top: auto; bottom: 8px; width: calc(52% - 18px); flex-direction: row; flex-wrap: wrap; }
  html.is-touch .pz-profscr .pz-panelscr__btns .iw-btn--menu { width: auto; flex: 1 1 auto; padding-right: 12px; }
  /* · location: the city list left (it scrolls), USE MY LOCATION · SKIP right */
  html.is-touch .pz-loc .pz-loc__list { width: calc(60% - 18px); bottom: 8px; display: flex; flex-direction: column; }
  html.is-touch .pz-loc__rows { flex: 1; min-height: 0; overflow-y: auto; touch-action: pan-y; }
  html.is-touch .pz-loc__row { min-height: 34px; }
  /* · messages: the list left, the thread right */
  html.is-touch .pz-chats__list { left: 12px; top: 58px; width: calc(36% - 18px); max-height: calc(100% - 66px); }
  html.is-touch .pz-chats__panel { left: 36%; right: 12px; top: 58px; bottom: 8px; }

  /* ---- HOW TO HOPPA: the four cards + the TOUCH table side by side, the whole body scrolls */
  html.is-touch .iw-howto__body { left: 12px; right: 12px; top: 58px; bottom: 8px; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; align-items: start; grid-template-columns: 1.15fr 1fr; gap: 12px; }
  html.is-touch .iw-howto__rules { gap: 10px; }
  html.is-touch .iw-howto .iw-rule__art { height: 52px; margin-bottom: 6px; }

  /* ---- the in-city MENU: the title a line */
  html.is-touch .iw-pause__col .iw-pause__title { font-size: 18px; padding-top: 4px; }
  html.is-touch .pz-itemgrid { grid-template-columns: 1fr; }

  /* ---- the Boss War on a phone: the results card fits the screen */
  html.is-touch { --t-hs: 38px; }
  html.is-touch .pz-war-res__card { zoom: .86; }
}
@media (max-height: 500px) and (max-width: 700px) {
  html.is-touch { --t-hs: 34px; }
  html.is-touch .pz-hotbar { --hg: 3px; }
}

/* =====================================================================================
   A TABLET UPRIGHT (iPad portrait, 768–1024 × 1024–1366). The desktop's layouts assume a 16:9 frame 100u wide; upright
   that frame is the screen's width and the type shrinks to a phone's. Here --u follows the screen's HEIGHT (≈ 11 px on
   an 11" iPad) and every screen re-flows into ONE column: the header, the content full width, the actions at the foot.
   ===================================================================================== */
@media (orientation: portrait) {
  html.is-touch.is-tablet .iw-ui, html.is-touch.is-tablet .iw-hud, html.is-touch.is-tablet .iw-hud-over, html.is-touch.is-tablet .pz,
  html.is-touch.is-tablet .pz-mm, html.is-touch.is-tablet .pz-bm { --u: min(1.3vw, .92dvh); }
  /* every screen's header: top-left, roomy */
  html.is-touch.is-tablet .iw-head { left: var(--t-gut); top: 16px; }
  html.is-touch.is-tablet .iw-ui .iw-backbtn { width: 52px; height: 52px; }
  /* ---- MAIN MENU: the wordmark big up top, the menu a centred column, your card at the foot */
  html.is-touch.is-tablet .pz-main__logo { left: 50%; top: 9dvh; translate: -50% 0; scale: 1.9; transform-origin: 50% 0; }
  html.is-touch.is-tablet .pz-main__col { left: max(var(--t-gut), calc(50% - 280px)); right: max(var(--t-gut), calc(50% - 280px)); top: auto; bottom: calc(var(--t-gut) + 200px); translate: none; transform: none; width: auto; min-width: 0; }
  html.is-touch.is-tablet .pz-main__col .iw-btn--menu { min-height: 60px; }
  html.is-touch.is-tablet .pz-main__col .pz-btn--enter { min-height: 84px; }
  html.is-touch.is-tablet .pz-main__me { left: max(var(--t-gut), calc(50% - 280px)); right: max(var(--t-gut), calc(50% - 280px)); top: auto; bottom: var(--t-gut); translate: none; transform: none; width: auto; min-width: 0; }
  html.is-touch.is-tablet .pz-main__desc, html.is-touch.is-tablet .iw-corner--bl { display: none !important; }
  /* ---- PICK A CITY · picked: the hero card on top, TIME · YOU under it, ENTER! at the foot */
  html.is-touch.is-tablet .pz-city__hero { left: var(--t-gut); right: var(--t-gut); top: 100px; width: auto; max-height: 46dvh; }
  html.is-touch.is-tablet .pz-city__right { left: var(--t-gut); right: var(--t-gut); top: calc(100px + 46dvh + 16px); bottom: calc(var(--t-gut) + 96px); width: auto; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
  html.is-touch.is-tablet .pz-city__right > * { flex: none; }
  html.is-touch.is-tablet .pz-city__right .iw-btn--start { position: fixed; left: var(--t-gut); right: var(--t-gut); bottom: var(--t-gut); width: auto; height: 80px; z-index: 3; }
  html.is-touch.is-tablet .pz-city__left { left: var(--t-gut); right: var(--t-gut); top: 100px; bottom: var(--t-gut); width: auto; }
  /* ---- SETTINGS: the panel full width under the header, its rows scroll */
  html.is-touch.is-tablet .hs-set .hs-panel, html.is-touch.is-tablet .iw-settings .hs-panel { left: var(--t-gut); right: var(--t-gut); top: 100px; bottom: auto; max-height: calc(100% - 100px - var(--t-gut)); width: auto; max-width: none; min-width: 0; translate: none; display: flex; flex-direction: column; }
  html.is-touch.is-tablet .hs-panel .hs-rows { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
  html.is-touch.is-tablet .hs-row__label { font-size: 17px; }
  html.is-touch.is-tablet .hs-tab { min-height: 56px; }
  /* ---- the panel screens: the panel full width, the buttons a row at the foot */
  html.is-touch.is-tablet .pz-stallform, html.is-touch.is-tablet .pz-loc .pz-loc__list { left: var(--t-gut); right: var(--t-gut); top: 100px; width: auto; min-width: 0; max-height: none; bottom: calc(var(--t-gut) + 88px); display: flex; flex-direction: column; }
  html.is-touch.is-tablet .pz-loc__rows { flex: 1; min-height: 0; overflow-y: auto; touch-action: pan-y; }
  html.is-touch.is-tablet .pz-panelscr__btns { left: var(--t-gut); right: var(--t-gut); top: auto; bottom: var(--t-gut); width: auto; min-width: 0; flex-direction: row-reverse; gap: var(--t-gap); }
  html.is-touch.is-tablet .pz-panelscr__btns > * { flex: 1 1 0; width: auto; min-width: 0; min-height: 68px; }
  html.is-touch.is-tablet .pz-loc .pz-loc__btns { left: var(--t-gut); right: var(--t-gut); width: auto; }
  html.is-touch.is-tablet .pz-loc__btns .pz-loc__gps.iw-btn--xl { font-size: 20px; height: 68px; }
  /* · profile: name + photo, then coins, then the buttons */
  html.is-touch.is-tablet .pz-profscr .pz-prof { left: var(--t-gut); right: var(--t-gut); top: 100px; width: auto; min-width: 0; }
  html.is-touch.is-tablet .pz-profscr .pz-prof.pz-prof__coins { left: var(--t-gut); right: var(--t-gut); top: 400px; bottom: calc(var(--t-gut) + 88px); width: auto; max-height: none; }
  html.is-touch.is-tablet .pz-profscr .pz-panelscr__btns { flex-direction: row; }
  /* · messages: the list on top, the thread under it */
  html.is-touch.is-tablet .pz-chats__list { left: var(--t-gut); right: var(--t-gut); top: 100px; width: auto; max-height: 30dvh; }
  html.is-touch.is-tablet .pz-chats__panel { left: var(--t-gut); right: var(--t-gut); top: calc(100px + 30dvh + 12px); bottom: var(--t-gut); width: auto; }
  /* ---- HOW TO: the cards, then the TOUCH table, one column that scrolls */
  html.is-touch.is-tablet .iw-howto__body { left: var(--t-gut); right: var(--t-gut); top: 100px; bottom: var(--t-gut); overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; grid-template-columns: 1fr; align-content: start; }
  /* ---- the in-city MENU: the tiles across the top, the city panel under them, RESUME at the foot */
  html.is-touch.is-tablet .pz-pause .iw-pause__col { right: var(--t-gut); width: auto; bottom: var(--t-gut); }
  html.is-touch.is-tablet .pz-pause .iw-pause__menu { grid-auto-rows: 120px; }
  html.is-touch.is-tablet .tc.is-hotbar .tc-pad { --s: 78px; }
  html.is-touch.is-tablet .pz-war__me { width: min(300px, 38vw); }
  html.is-touch.is-tablet .pz-pause .iw-pmatch { left: var(--t-gut); right: var(--t-gut); top: 420px; width: auto; }
}

/* =====================================================================================
   [ui-sizes] THE SIZE PASS — every screen at every device size (docs/MOBILE-UI.md § The device matrix; tools/ui-matrix.mjs
   audits it: words ≥ 13 px on a phone / ≥ 14 px on a tablet (caps micro-labels one px less), every target ≥ 44 px, nothing
   off the screen, the notice stack never over a control).
   ===================================================================================== */
/* ---- the type tokens, raised to the floors (phone 13 · tablet 14) */
html.is-touch { --t-fs: 15px; --t-fs-s: 13.5px; --t-fs-cap: 12.5px; --t-fmin: 13px; --t-fmicro: 12px; }   /* (--t-fmin: the floor for words; --t-fmicro: a numeral badge / a world tag) */
html.is-touch.is-tablet { --t-fs: 16.5px; --t-fs-s: 15px; --t-fs-cap: 13.5px; --t-fmin: 14px; --t-fmicro: 13px; }
html.is-touch .iw-ui, html.is-touch .iw-hud, html.is-touch .iw-hud-over, html.is-touch .pz {
  --fs-xs: max(13px, calc(var(--u) * .8)); --fs-s: max(13.5px, calc(var(--u) * .95)); --fs-m: max(15px, calc(var(--u) * 1.1)); --fs-l: max(17.5px, calc(var(--u) * 1.4)); }
html.is-touch.is-tablet .iw-ui, html.is-touch.is-tablet .iw-hud, html.is-touch.is-tablet .iw-hud-over, html.is-touch.is-tablet .pz {
  --fs-xs: max(14px, calc(var(--u) * .8)); --fs-s: max(15px, calc(var(--u) * .95)); --fs-m: max(16.5px, calc(var(--u) * 1.1)); --fs-l: max(19.5px, calc(var(--u) * 1.4)); }
/* ---- every text field 16 px (iOS zooms the page into a field whose text is smaller: the chat's was 8.8 px on an SE) */
html.is-touch #ui-root input:not([type="range"]):not([type="checkbox"]):not([type="radio"]), html.is-touch #ui-root textarea { font-size: 16px !important; }
html.is-touch #ui-root input::placeholder, html.is-touch #ui-root textarea::placeholder { font-size: 16px; }
/* ---- the targets: ≥ 44 px (a tablet's --t-hit: 48) */
html.is-touch .iw-btn--small, html.is-touch .iw-lbtn, html.is-touch .iw-locker .iw-btn, html.is-touch .iw-btn--ghost { min-height: var(--t-hit); }
html.is-touch .iw-name { min-height: var(--t-hit); }
html.is-touch .pz-me__geo, html.is-touch .pz-me__edit, html.is-touch .pz-you__link { min-height: var(--t-hit); display: inline-flex; align-items: center; }
html.is-touch .pz-chat__send { width: var(--t-hit); height: var(--t-hit); }
html.is-touch .pz-mic__btn { width: var(--t-hit); height: var(--t-hit); }
html.is-touch .pz-thumb--add { min-width: var(--t-hit); min-height: var(--t-hit); }
html.is-touch .pz-swatches { gap: 6px; }
html.is-touch .pz-swatch { width: var(--t-hit); height: var(--t-hit); }
html.is-touch .pz-city__you .pz-emoji, html.is-touch .pz-emoji { width: var(--t-hit); height: var(--t-hit); font-size: 24px; }
html.is-touch .pz-top__fan .pz-act { min-height: var(--t-hit); font-size: 14px; }
html.is-touch .tc-home { min-height: var(--t-hit); font-size: var(--t-fmin); padding-left: 16px; }
html.is-touch .tc-home__x { width: 34px; height: 34px; }
/* ---- headers: the sub line readable */
html.is-touch .iw-ui .iw-head__sub { font-size: var(--t-fs-s); }
/* ---- MAIN MENU: the menu words + ENTER CITY's district line, your card's links */
html.is-touch .pz-main__col .iw-btn--menu .iw-btn__label { font-size: max(14px, var(--fs-m)); }
html.is-touch .pz-btn--enter .iw-btn__sub { font-size: var(--t-fmin); }
html.is-touch .pz-me__slabel { font-size: var(--t-fmin); }
/* ---- PICK A CITY: the postcards' words, the time tiles' lines */
html.is-touch .pz-card__name { font-size: max(16px, calc(var(--u) * 1.65)); }
html.is-touch .pz-city__grid .pz-card__name { font-size: max(16px, min(calc(var(--u) * 1.65), 8.6cqi)); }
html.is-touch .pz-card__num { width: max(26px, calc(var(--u) * 2.7)); height: max(26px, calc(var(--u) * 2.7)); font-size: max(var(--t-fmicro), calc(var(--u) * 1.1)); }
html.is-touch .pz-tod__sub { font-size: max(var(--t-fmin), calc(var(--u) * .78)); }
html.is-touch .pz-card--hero .pz-card__wxtxt { white-space: normal; }
/* ---- WHERE ARE YOU: the city rows */
html.is-touch .pz-loc__name { font-size: max(15px, calc(var(--u) * 1.3)); }
html.is-touch .pz-loc__country { font-size: var(--t-fmin); }
html.is-touch .pz-loc__row { min-height: var(--t-hit) !important; }
/* ---- the LOCKER: tile names, the foot's buttons */
html.is-touch .iw-ltile__name { font-size: max(var(--t-fs-cap), calc(var(--u) * 1.15)) !important; }
html.is-touch .iw-lfoot .iw-btn__label, html.is-touch .iw-lfoot b { font-size: 14px; }
/* ---- HOW TO: the rule cards + the TOUCH table */
html.is-touch .iw-howto .iw-rule__text { font-size: var(--t-fs-s); }
html.is-touch .iw-howto .iw-ctl-wrap em { font-size: var(--t-fmin); }
html.is-touch .tc-chip { font-size: var(--t-fs-cap); }
/* ---- the city HUD: the corner map's name, the dial, the BOSS WAR pill, the notices, the chat */
html.is-touch .pz-mm__name { font-size: var(--t-fmin); }
html.is-touch .pz-wx__temp { font-size: var(--t-fmicro); }
html.is-touch .pz-bd-wrap--bosswar .pz-bd__lbl { font-size: var(--t-fs-cap); }
html.is-touch .pz-note, html.is-touch .pz-note__text { font-size: var(--t-fs-s); }
html.is-touch .pz-chat__log > *, html.is-touch .pz-line__txt { font-size: var(--t-fs-s); }
html.is-touch .tc-btn__lbl { font-size: var(--t-fs-cap); }
/* [viewport] a card that asks is up, centred: the notice stack (bottom-centre) steps aside under it — faded, as on a desktop
   while the war's invite is up (an invite / a request never sits on a notice; the chat button keeps its new-message dot) */
html.is-touch body.pzh-popup .pz-notes { opacity: 0; pointer-events: none; }
/* ---- the big map: the pins' and the header's words */
html.is-touch .pz-bm-pin__label { font-size: var(--t-fmin); }
html.is-touch .pz-bm__city { font-size: var(--t-fs-cap); }
html.is-touch .pz-bm b, html.is-touch .pz-bm small, html.is-touch .pz-bm__foot, html.is-touch .pz-bm__hint { font-size: var(--t-fmin); }
/* ---- the in-city MENU: tile words, the city panel */
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu { font-size: var(--t-fmin); }
html.is-touch .iw-pause__live { font-size: var(--t-fs-cap); }
html.is-touch .pz-mp__time { font-size: var(--t-fs-cap); }
/* ---- the stall editor / browse: the goods rows */
html.is-touch .pz-goods__name { font-size: max(15px, calc(var(--u) * 1.45)); }
html.is-touch .pz-goods__num { width: 24px; height: 24px; font-size: var(--t-fs-cap); }
html.is-touch .pz-goods { min-height: var(--t-hit); }
html.is-touch .pz-field--item .iw-name__label { font-size: var(--t-fs-cap); }
html.is-touch .pz-field--price { flex-basis: max(84px, calc(var(--u) * 8.4)); }
/* ---- the Boss War: the invite card's line, the boss bars, the results */
html.is-touch .pz-popup__line { font-size: var(--t-fmin); }
html.is-touch .pz-war-res__stats small, html.is-touch .pz-war-res__mvp small { font-size: max(var(--t-fmicro), calc(var(--u) * 1.05)); }
html.is-touch .pz-war-res__head span { font-size: max(13.5px, calc(var(--u) * 1.35)); }
html.is-touch .pz-war-res__list li { font-size: max(13.5px, calc(var(--u) * 1.3)); }
html.is-touch .pz-war-res__mvp em, html.is-touch .pz-war-res__list em { font-size: var(--t-fmicro); }
html.is-touch .pz-war-res__dmg { font-size: max(14px, calc(var(--u) * 1.7)); }
html.is-touch .pz-war-res__stats b { font-size: max(16px, calc(var(--u) * 2.2)); }
html.is-touch { --t-hs: 44px; }
html.is-touch.is-tablet { --t-hs: 52px; }
/* ---- a phone held sideways: the war's top (the boss bars were drawn at 0.7 u: 8.6 px names) + the results at full size */
@media (max-height: 500px) {
  html.is-touch .pz-war-res__card { zoom: 1; width: min(560px, calc(100vw - var(--sa-l) - var(--sa-r) - 24px)); }
  html.is-touch .pz-war-res__head b { font-size: 30px; }
  html.is-touch .iw-ui .iw-head__sub { font-size: var(--t-fmin); }
}
/* ---- batch 2 (the SE's second audit) */
html.is-touch .pz-prof__stat small, html.is-touch .pz-prof__histhd { font-size: var(--t-fs-cap); }
html.is-touch .pz-tod__sub { white-space: normal; text-overflow: clip; line-height: 1.15; }
html.is-touch .pz-loc__gps .iw-btn__sub { font-size: var(--t-fmin); white-space: normal; }
html.is-touch .pz-loc__country { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.is-touch .pz-pause .pz-mp__city span, html.is-touch .pz-pause .hs-row__label { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.15; }
html.is-touch .pz-bm-area span { font-size: var(--t-fs-cap); }
html.is-touch .pz-war-seats__list li { font-size: var(--t-fmin); }
html.is-touch .pz-war-seats__list li .pz-war-seats__vac { font-size: var(--t-fmicro); }
html.is-touch .pz-war-seats__first, html.is-touch .pz-war-seats__tag { font-size: var(--t-fmicro); }
html.is-touch .pz-warclock__num { font-size: var(--t-fmin); }
html.is-touch .pz-war__lbl { font-size: max(var(--t-fs-cap), calc(var(--u) * 1.05)); }
html.is-touch .pz-war__num { font-size: max(14px, calc(var(--u) * 1.6)); }
html.is-touch .pz-war__tagname { font-size: var(--t-fmicro); }
html.is-touch .pz-war__tagname small, html.is-touch .pz-war__tag small { font-size: 11px; }
html.is-touch .pz-war__info > span { font-size: 14px; }
html.is-touch .pz-war__info small { font-size: var(--t-fs-cap); }
html.is-touch .pz-war-res__reward b, html.is-touch .pz-war-res__coins b { font-size: max(14.5px, calc(var(--u) * 1.45)); }
html.is-touch .pz-war-res__reward small, html.is-touch .pz-war-res__coins small { font-size: max(var(--t-fmin), calc(var(--u) * 1.15)); }
html.is-touch .iw-bb__grow, html.is-touch .iw-bb__rage { font-size: var(--t-fmicro); }
html.is-touch .iw-linfo__names b { font-size: max(15px, calc(var(--u) * 1.55)); }
@media (max-height: 500px) {
  /* the LOCKER: the body fills the frame under the header; its grids scroll, SHUFFLE · DONE stay on screen */
  html.is-touch .iw-locker__body { top: 58px; bottom: 8px; }
  html.is-touch .iw-locker__body > .iw-lpanel { flex: 1 1 auto; min-height: 0; }
  html.is-touch .iw-lgrids { flex: 1 1 auto; height: auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
  html.is-touch .iw-lfoot { flex: none; }
}
/* ---- the war's top on a phone and on an upright tablet: the boss bars at 1.05 u (they were 0.7 u: 8–9 px names), the
   tally chip under them */
@media (max-height: 500px), (orientation: portrait) {
  html.is-touch .iw-bhud .iw-bb, html.is-touch .iw-bhud .iw-bcall, html.is-touch .iw-bhud .iw-bmv { --u: max(7.1px, calc(min(1vw, 1.7778dvh) * 1.05)); }
  html.is-touch .pz-war__info { top: calc(max(7.1px, calc(min(1vw, 1.7778dvh) * 1.05)) * (4 + 5.6 * var(--war-bars, 1))); }
}
/* ---- a TABLET held sideways (4:3 – 3:2: an iPad's frame is taller than the 16:9 the desktop layouts fill): the room
   under them goes to the thumbs — every screen's actions drop to the bottom edge (a 12.9" iPad's top-right is out of a
   thumb's reach), the tiles and the lists grow into the height */
@media (orientation: landscape) and (max-aspect-ratio: 8/5) {
  html.is-touch.is-tablet .iw-screen:not(.pz-profscr) .pz-panelscr__btns { top: auto; bottom: calc(var(--t-gut) + var(--sa-b)); }
  html.is-touch.is-tablet .pz-city__right { bottom: calc(var(--t-gut) + 4px); }
  html.is-touch.is-tablet .pz-city__right .iw-btn--start { margin-top: auto; height: max(72px, calc(var(--u) * 6)); }
  html.is-touch.is-tablet .pz-city__hero { max-height: calc(100% - var(--u) * 9.6 - var(--t-gut) - 8px); }
  html.is-touch.is-tablet .pz-pause .iw-pause__menu { grid-auto-rows: clamp(120px, 22dvh, 220px); }
  html.is-touch.is-tablet .pz-pause .iw-pause__menu .iw-btn--menu { font-size: 15px; }
  html.is-touch.is-tablet .iw-lgrids { height: min(calc(var(--u) * 23.2 + (100dvh - 56.25vw) * .8), calc(100dvh - var(--u) * 30)); }
  html.is-touch.is-tablet .pz-stallform { max-height: calc(100% - var(--u) * 12.6); }
}
/* =====================================================================================
   [ui-sizes] a KEYBOARD TABLET (an iPad on a Magic Keyboard: html.is-mobile-kbd, src/ui/menus.js). The desktop's keyboard +
   mouse UI — keycaps, hover, no touch pad — with the tablet's type floors (it is read at arm's length, not a desk's).
   ===================================================================================== */
html.is-mobile-kbd .iw-ui, html.is-mobile-kbd .iw-hud, html.is-mobile-kbd .iw-hud-over, html.is-mobile-kbd .pz {
  --fs-xs: max(13px, calc(var(--u) * .8)); --fs-s: max(14px, calc(var(--u) * .95)); --fs-m: max(15.5px, calc(var(--u) * 1.1)); --fs-l: max(18px, calc(var(--u) * 1.4)); }
html.is-mobile-kbd .pz-bd__lbl, html.is-mobile-kbd .pz-bd__key { font-size: max(11px, calc(var(--u) * .8)); letter-spacing: .04em; }   /* (wider type, tighter tracking: MESSAGES · FRIENDS must not touch) */
html.is-mobile-kbd .pz-clock__city { font-size: 11px; }
html.is-mobile-kbd .pz-wx__sub { font-size: 10.5px; }
html.is-mobile-kbd .pz-mm__name, html.is-mobile-kbd .pz-line__txt { font-size: 14px; }
html.is-mobile-kbd .pz-pause .iw-pause__live, html.is-mobile-kbd .pz-mp__time { font-size: 12.5px; }
html.is-mobile-kbd .pz-war__info small, html.is-mobile-kbd .pz-war__tagname small { font-size: 12px; }
html.is-touch .pz-bd-wrap--bosswar > .pz-bd__lbl { align-self: center; margin-left: 0; }   /* [ui-sizes] (the desktop's left-anchored state label: a row here) */
/* ---- batch 3 (the SE's third audit) */
html.is-touch .iw-ui .iw-backbtn, html.is-touch .pz-mic__btn { flex: none; }   /* (a long header sub / caption squeezed them to 40 / 28 px) */
html.is-touch .pz-wx__temp { font-size: var(--t-fmin); }
html.is-touch .iw-rule__num { font-size: var(--t-fmicro); }
html.is-touch .iw-ltile__name { font-size: max(var(--t-fmin), calc(var(--u) * 1.15)) !important; }
html.is-touch .pz-war-seats__list li .pz-war-seats__vac, html.is-touch .pz-war-seats__first, html.is-touch .pz-war-seats__tag { font-size: var(--t-fmin); }
html.is-touch .pz-war__info small { font-size: var(--t-fmin); }
html.is-touch .iw-bhud .iw-bb .iw-bb__grow, html.is-touch .iw-bhud .iw-bb .iw-bb__rage { font-size: var(--t-fmicro); }
html.is-touch .pz-war-res__mvp span { font-size: max(15px, calc(var(--u) * 1.6)); }
html.is-touch .pz-war-res__list li small { font-size: max(var(--t-fmin), calc(var(--u) * 1.15)); }
/* ACT open: the smiley's eyes + mouth are drawn in --k (ink) — on the yellow disc the face went ink too: one blob */
html.is-touch .pz-bd-wrap--act.is-open .pz-bd__ico, html.is-touch .pz-bd--act:active .pz-bd__ico, html.is-touch .pz-bd--act.is-active .pz-bd__ico { --k: var(--t-y); }
/* the ACT fan on a phone: 4 × 2 (2 × 4 pills of 44 px ran down over the notice stack) */
@media (max-height: 500px) {
  html.is-touch .pz-top__fan { grid-template-columns: repeat(4, minmax(84px, auto)); }
  html.is-touch .iw-ui .iw-head__sub { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: calc(100vw - var(--sa-l) - var(--sa-r) - 90px); }
}
html.is-touch .pz-war-res__card { background: rgba(16, 18, 27, .97); }   /* (no blur on glass: the boss bars showed through) */
/* ---- batch 4 (the tablets' audit: the fixed floors are tokens now — phone 13 / tablet 14) */
html.is-touch .pz-bm__legend span, html.is-touch .pz-bm__legend b { font-size: var(--t-fs-cap); }
html.is-touch .pz-prof__coinbal span { font-size: var(--t-fmin); }
html.is-touch .tc-btn__lbl { font-size: var(--t-fs-cap); }
html.is-touch .tc-chip { font-size: var(--t-fs-cap); }
/* the city's YOU panel: colours + emoji wrap onto as many rows as 44 px targets need (a fixed 10 / 17-column grid
   squeezed the 44 px emoji onto each other) */
html.is-touch .pz-city__you .pz-swatches { grid-template-columns: repeat(auto-fill, minmax(var(--t-hit), 1fr)); row-gap: 6px; }
@media (orientation: landscape) and (max-aspect-ratio: 8/5) {
  html.is-touch.is-tablet .pz-city__right .pz-city__you { flex: none; justify-content: flex-start; gap: calc(var(--u) * .8); }
  html.is-touch.is-tablet .pz-pause .iw-pause__menu { grid-auto-rows: clamp(120px, 17dvh, 180px); }
}
html.is-touch .pz-mic .pz-mic__btn, html.is-touch .pz-vnote__row .pz-mic__btn { width: var(--t-hit); height: var(--t-hit); }
html.is-touch .iw-bb .iw-bb__grow { font-size: var(--t-fmicro) !important; }
/* ---- batch 5 (the iPad mini's audit) */
html.is-touch.is-tablet .iw-ui .iw-backbtn { width: 52px; height: 52px; }
html.is-touch .pz-city__arrow { min-width: var(--t-hit); min-height: var(--t-hit); }
html.is-touch .pz-city__right .iw-setrow__label, html.is-touch .pz-city__right .iw-seclabel { font-size: max(var(--t-fs-cap), calc(var(--u) * 1.02)); }
html.is-touch .pz-you__link, html.is-touch .pz-prof__hempty { font-size: var(--t-fmin); }
/* CJK on touch: no caps to lean on — the caps-label token rises to the word floor (12.5 px ideographs read small) */
html.is-touch:is(:lang(ja), :lang(zh-Hant), :lang(zh-Hans), :lang(ko)) { --t-fs-cap: 13px; --t-fmicro: 12.5px; }
html.is-touch.is-tablet:is(:lang(ja), :lang(zh-Hant), :lang(zh-Hans), :lang(ko)) { --t-fs-cap: 14px; --t-fmicro: 13.5px; }
/* the war's name tags over heads: the city line under the name (11 px) follows the micro floor */
html.is-touch .pz-war__tagname small, html.is-touch .pz-war__tag small { font-size: calc(var(--t-fmicro) - 1px); }
/* the How-to TOUCH table: the hint pill sits under its action on a line of its own (inline, a long hint — ja / fr — broke
   the pill across two lines); the action never splits a word from its chips */
html.is-touch .iw-ctl__act em { display: block; width: fit-content; margin: 4px 0 0; line-height: 1.2; }
html.is-touch .iw-ctl__row { padding-block: 6px; }
/* Japanese: break between phrases, not inside a word (わたしの屋 / 台) — where the engine knows how (Chrome 119+) */
html:lang(ja) #ui-root :is(.iw-btn__label, .iw-ctl__act, .hs-row__label, .iw-rule__text, .iw-head__sub) { word-break: auto-phrase; }
html.is-touch .hs-saved span { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.2; }   /* (fr: « Les changements sont enregistrés automatiquement ») */
/* a card that asks is up: the city's context prompt steps out (the card has the thumb's attention), the other notices wrap
   in the narrowed stack instead of being cut */
html.is-touch body.pzh-popup .pz-prompt { display: none; }
html.is-touch body.pzh-popup .pz-note { white-space: normal; }
html.is-mobile-kbd .pz-act { font-size: 13px; }
html.is-mobile-kbd .pz-war-seats__list li .pz-war-seats__vac, html.is-mobile-kbd .pz-war-seats__first, html.is-mobile-kbd .pz-war-seats__tag { font-size: 12px; }
html.is-mobile-kbd .pz-bm-pin__label, html.is-mobile-kbd .pz-bm__city, html.is-mobile-kbd .pz-bm-key { font-size: 12.5px; }
html.is-mobile-kbd .pz-tod__sub, html.is-mobile-kbd .pz-prof__histhd, html.is-mobile-kbd .pz-prof__stat small { font-size: 12.5px; }
html.is-mobile-kbd .iw-name__label { font-size: 12.5px; }
html.is-touch.is-tablet .tc-btn__lbl { font-size: var(--t-fs-cap); }
html.is-touch .pz-bm__legend span { font-size: var(--t-fmin); }
/* ---- batch 6 (the final audit) */
/* a tablet sideways: HOW TO's TOUCH table (taller with the hints on their own lines) ran off an iPad mini's foot → the
   body scrolls inside the frame */
html.is-touch.is-tablet .iw-howto__body { bottom: var(--t-gut); overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; }
/* the picked city on a 4:3 tablet: ENTER! pinned to the bottom edge, the TIME · YOU column scrolls above it (on an iPad
   mini the natural-height panels pushed ENTER! 2 px off the screen) */
@media (orientation: landscape) and (max-aspect-ratio: 8/5) {
  html.is-touch.is-tablet .pz-city__right { bottom: calc(var(--t-gut) + max(72px, calc(var(--u) * 6)) + 12px); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none; touch-action: pan-y; }
  html.is-touch.is-tablet .pz-city__right > * { flex: none; }
  html.is-touch.is-tablet .pz-city__right .iw-btn--start { position: fixed; z-index: 3; margin: 0; right: calc(var(--u) * 3.4 + var(--sar, 0px)); bottom: var(--t-gut);
    width: min(calc(50% - var(--u) * 5.6 - var(--sar, 0px)), calc(var(--u) * 42)); }
}
html.is-touch.is-tablet .pz-war-res__list li, html.is-touch.is-tablet .pz-war-res__head span { font-size: max(var(--t-fs-s), calc(var(--u) * 1.3)); }
html.is-touch .pz-hb__n { font-size: max(var(--t-fmin), 1em); }

/* =====================================================================================
   [locker-ui] the LOCKER on a touch screen (menus.js _scr_locker; desktop: social.css "LOCKER · HOPPA"). Settings' panel and
   tab bar, sized like SETTINGS here; the kid on the hop pad beside it (sideways) or under it (an upright tablet). No
   key hints (the prompts bar is hidden on touch), no entrance motion, cards and buttons ≥ the thumb target.
   ===================================================================================== */
html.is-touch .lk .lk-tile, html.is-touch .lk .lk-btn { transition: none; }
html.is-touch .lk .lk-tile:active { scale: .97; }
html.is-touch .lk .lk-tile:hover { background: rgba(243, 236, 224, .06); }
html.is-touch .lk .lk-tile.is-on:hover { background: rgba(243, 236, 224, .13); }
html.is-touch .lk .lk-tile.is-pick, html.is-touch .lk .lk-tile__pic, html.is-touch .lk .lk-shuffle.is-roll .iw-btn__icon { animation: none; }
html.is-touch .lk .lk-btn { min-height: var(--t-hit); }
html.is-touch .lk .lk-spin { bottom: calc(var(--t-gut) + 2px); }
/* · a tablet held sideways: the panel runs to the bottom edge (no key hints under it) */
html.is-touch.is-tablet .hs-set.lk .lk-panel { height: calc(100% - var(--u) * 8.6 - var(--t-gut)); }
/* · a phone held sideways: the panel fills the frame under the header, left; four looks a row; the info row folds away
     (each group's head already names the pick) */
@media (max-height: 500px) {
  html.is-touch .lk { --lk-l: var(--t-gut); --lk-w: min(calc(58% - var(--t-gut)), 560px); --lk-c-bust: 5; --lk-c-head: 5; --lk-c-face: 5; --lk-c-body: 5; --lk-c-swatch: 7; }
  html.is-touch .hs-set.lk .lk-panel { left: var(--lk-l); right: auto; top: 58px; bottom: 8px; width: var(--lk-w); height: auto; padding: 8px; }
  html.is-touch .lk .hs-tabs { padding: 4px; gap: 4px; }
  html.is-touch .lk .hs-tab { min-height: var(--t-hit); height: var(--t-hit); gap: .4em; font-size: 15px; }
  html.is-touch .lk .hs-tab i { display: none; }
  html.is-touch .lk .lk-rows { margin-top: 6px; padding: 0; gap: 6px; }
  html.is-touch .lk .lk-sec { gap: 8px; padding: 8px 10px 10px; border-radius: 12px; }
  html.is-touch .lk .lk-sec__head .hs-row__label { font-size: 15px; }
  html.is-touch .lk .lk-sec__cur { font-size: 13px; }
  html.is-touch .lk .lk-grid { gap: 6px; }
  html.is-touch .lk .lk-tile { border-radius: 10px; }
  html.is-touch .lk .lk-tile__name { font-size: 13.5px; padding: 0 .2em 7px; }
  html.is-touch .lk .lk-tile--head .lk-tile__name, html.is-touch .lk .lk-tile--face .lk-tile__name { font-size: 13px; }
  html.is-touch .lk .lk-tile__eq { top: 5px; right: 5px; width: 20px; height: 20px; }
  html.is-touch .lk .lk-info { display: none; }
  html.is-touch .lk .hs-foot { margin-top: 6px; padding: 6px 2px 0; gap: 8px; }
  html.is-touch .lk .lk-foot__acts { gap: 6px; }
  html.is-touch .lk .lk-btn { padding: 0 12px; font-size: 14px; }
  html.is-touch .lk .hs-saved { font-size: 13px; }
  html.is-touch .hs-set.lk .hs-saved span { white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.2; }
}
/* · an upright tablet: the panel full width under the header (about half the screen), the kid on the pad under it */
@media (orientation: portrait) {
  html.is-touch.is-tablet .lk { --lk-l: var(--t-gut); --lk-c-bust: 6; --lk-c-head: 8; --lk-c-face: 8; --lk-c-body: 6; --lk-c-swatch: 10; }
  html.is-touch.is-tablet .hs-set.lk .lk-panel { left: var(--t-gut); right: var(--t-gut); top: 100px; bottom: auto; width: auto; height: calc(54% - 100px); max-height: none; }
  html.is-touch.is-tablet .lk .lk-spin { left: 50%; }
  html.is-touch.is-tablet .lk .lk-tile__name { font-size: 15px; }
  html.is-touch.is-tablet .lk .lk-tile--bust .lk-tile__name { font-size: 17px; }
  html.is-touch.is-tablet .lk .lk-tile--head .lk-tile__name, html.is-touch.is-tablet .lk .lk-tile--face .lk-tile__name { font-size: 14px; }
}
/* · a 4:3 tablet held sideways: the panel is tall — the looks a size up (five a row) */
@media (orientation: landscape) and (max-aspect-ratio: 8/5) {
  html.is-touch.is-tablet .lk { --lk-c-bust: 5; }
}

/* [ui-audit] text floors the audit found under the phone's 13 px: the boss's move callout (POUNCE! / STOMP!: 11 px) and the
   toasts over a menu (ROAR is hunting …: 9 px) */
html.is-touch .iw-bmv__pill b { font-size: max(13px, calc(var(--u) * 1.4)); }
html.is-touch .pz-toast { font-size: max(13px, calc(var(--u) * 1.2)); }
html.is-touch.is-tablet .iw-bmv__pill b, html.is-touch.is-tablet .pz-toast { font-size: max(14px, calc(var(--u) * 1.3)); }
/* [ui-audit] the main menu's stall badge (STALL · city / No stall open) is a button: a thumb-sized target on touch */
html.is-touch .pz-stallbadge { min-height: var(--t-hit); }
/* [ui-audit] a phone: a menu fills the safe frame — the over-the-menu toasts (social/ui.js toast() while a menu is up; top
   right) landed on the menu's own panel header (ROAR is hunting … over the coins / DAY chips). Not shown there on a phone:
   a DM keeps its dot on MESSAGES / MENU, the war's lines are the war HUD's once the menu closes */
html.is-touch:not(.is-tablet) .pz-toasts { display: none; }
/* [ui-audit] layers whose children are placed from a 3D projection in VIEW px (war name tags, damage numbers / CRIT!, coin
   pops, weak-point marks) span the view from its origin, like .pz-tags above — inside the safe frame they sat a notch's
   width right of what they label */
html.is-touch :is(.pz-war__tags, .pz-coinpops, .iw-bnums, .pz-shop-reveal) { inset: auto; left: calc(-1 * var(--sa-l)); top: calc(-1 * var(--sa-t)); width: 100vw; height: 100dvh; }
/* [ui-audit] a boss bar's status word (FALLEN / PINNED! / À TERRE) never shrinks under its own width: the name beside it takes
   the ellipsis instead (the word was cut to 12 px of 50) */
.iw-bb__grow:not(:empty) { flex: 1 0 auto !important; }   /* (!important: hud-boss.js sets flex: 1 inline on the twin bars) */
/* [ui-audit] CJK / Hangul on a phone: the micro token at the phone's 13 px word floor (12.5 px read small: 撃破 / 暴怒 / 나!) */
html.is-touch:not(.is-tablet):is(:lang(ja), :lang(zh-Hant), :lang(zh-Hans), :lang(ko)) { --t-fmicro: 13px; }
/* [ui-audit] the in-city MENU's tiles on a small phone (SE: ≈ 85 px a tile): long words (MESSAGES / RÉGLAGES / MENSAJES) were cut
   by the tile and QUITTER LA GUERRE DES BOSS ran out of its bottom — tighter tracking, a word may break (hyphenated where the
   language allows), and a row grows to its label instead of cutting it */
html.is-touch .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__label { letter-spacing: .03em; overflow-wrap: anywhere; hyphens: auto; }
html.is-touch:not(.is-tablet) .pz-pause .iw-pause__menu { grid-auto-rows: minmax(clamp(64px, 22dvh, 128px), auto); }
@media (max-width: 760px) { html.is-touch:not(.is-tablet) .pz-pause .iw-pause__menu .iw-btn--menu { gap: 3px; padding: 4px 3px; } html.is-touch:not(.is-tablet) .pz-pause .iw-pause__menu .iw-btn--menu .iw-btn__icon { width: 22px; height: 22px; } }
/* [ui-audit] a card's title keeps a floor when the view gets short (the URL bar shown: 12 px at --u × 2.1) */
html.is-touch .pz-popup__name { font-size: max(16px, calc(var(--u) * 2.6)); }
html.is-touch .pz-war-inv .pz-popup__name { font-size: max(15px, calc(var(--u) * 2.1)); }
/* [ui-audit] Settings' foot: RESET DISPLAY / RÉINITIALISER AFFICHAGE gets at most half the foot and wraps inside it (fr ran
   off the screen on an SE) */
html.is-touch .hs-foot .hs-reset { flex: 0 1 auto; min-width: 0; max-width: 52%; }
html.is-touch .hs-foot .hs-reset .iw-btn__text, html.is-touch .hs-foot .hs-reset .iw-btn__label { min-width: 0; white-space: normal !important; line-height: 1.1; text-align: left; }
/* [ui-audit] WHERE ARE YOU?: the two city columns share the list's width (1fr grew to its longest row: the right column ran out
   of the list, cut); a long country name takes an ellipsis. USE MY LOCATION grows to its two-line sub (it cut both lines) */
.pz-loc__rows { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pz-loc__row > * { min-width: 0; }
html.is-touch .pz-loc [data-id="gps"], html.is-touch .pz-loc [data-id="skip"] { height: auto !important; min-height: var(--t-hit); padding-top: 8px; padding-bottom: 8px; }
/* [ui-audit] the loading screen's tip: at most the SAFE frame's width (90vw is wider than the frame beside a notch) */
html.is-touch .iw-loading--hoppa .iw-tip { max-width: calc(100% - 32px); }
/* [ui-audit] a menu button's sub-line never runs out of its button: an ellipsis, like ENTER CITY's (es: « sobre la publicación
   · chat … » was cut mid-word by ASK's button) */
html.is-touch .iw-btn--menu .iw-btn__text { min-width: 0; max-width: 100%; }
html.is-touch .iw-btn--menu .iw-btn__sub:not(.pz-loc *) { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* [ui-audit] the war results' coin reward (shop.css .pz-shop-reward, the new shop) and its items-used rows at the touch word
   floor (they were 9.6–12 px on an iPad: --u sized for a desktop's distance) */
html.is-touch :is(.pz-shop-reward__hd small, .pz-shop-reward__total small, .pz-shop-reward__lines li, .pz-shop-reward__buys, .pz-shop-reward__rec, .pz-shop-reward__none, .pz-shop-used__you) { font-size: var(--t-fmin); }
html.is-touch .pz-shop-reward__hd b { font-size: var(--t-fs-cap); }
html.is-touch .pz-shop-used em, html.is-touch .pz-shop-used b { font-size: var(--t-fmicro); }
/* [ui-audit] a tablet: the stall badge and PLAYED's rows at the tablet's 14 px word floor (13 px) */
html.is-touch :is(.pz-stallbadge, .pz-played, .pz-played__rows) { font-size: var(--t-fmin); }
/* [ui-audit] a tablet in CJK / Hangul: the micro token at the tablet's 14 px floor (あなた！ was 13.5 px) */
html.is-touch.is-tablet:is(:lang(ja), :lang(zh-Hant), :lang(zh-Hans), :lang(ko)) { --t-fmicro: 14px; }
/* [ui-audit] PROFILE's photo buttons wrap a long label (ja 写真をアップロード, fr IMPORTER UNE PHOTO: cut on an upright iPad) */
html.is-touch .pz-profscr .pz-panelscr__btns .iw-btn--menu { height: auto; min-height: var(--t-hit); }
html.is-touch .pz-profscr .pz-panelscr__btns .iw-btn__text, html.is-touch .pz-profscr .pz-panelscr__btns .iw-btn__label { min-width: 0; white-space: normal !important; line-height: 1.15; }
/* [ui-audit] the KO card's sub-line at the phone's word floor (9.3 px on an SE in ja / fr / es / ko) */
html.is-touch .pz-war__out span { font-size: max(var(--t-fmin), calc(var(--u) * 1.4)); line-height: 1.25; text-align: center; }
html.is-touch .pz-shop-used b { font-size: var(--t-fmicro); }

/* =====================================================================================
   [ui-audit] THE SHOP on a touch screen (styles/shop.css, src/ui/menus-shop.js). The touch Settings rule above (.hs-set .hs-panel:
   12 px from both sides) out-ranked shop.css's sideways-phone split, so the cards ran full width UNDER the details sheet
   (a 4th card column and OUTFITS / EFFECTS behind it). The split again, in the safe frame's own % (it is the containing
   block: no vw, no inset maths), and the words / targets at the touch floors.
   ===================================================================================== */
@media (max-height: 520px) and (min-aspect-ratio: 6/5) {
  html.is-touch .hs-set.sh .sh-panel { left: 8px; right: auto; width: calc(60% - 14px); top: 52px; bottom: 8px; height: auto; padding: 8px; }
  html.is-touch .sh-side { left: auto; right: 8px; width: calc(40% - 8px); top: 52px; bottom: 8px; height: auto; }
  html.is-touch .sh .iw-head { scale: 1; }
  html.is-touch .sh .iw-head__sub { max-width: calc(60% - 60px); }
}
html.is-touch .sh-tabs .hs-tab { min-height: var(--t-hit); }
html.is-touch .sh-tabs .hs-tab span { font-size: var(--t-fs-cap); letter-spacing: .04em; }
html.is-touch .sh-chip { min-height: var(--t-hit); font-size: var(--t-fs-cap); }
html.is-touch .sh-filters { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
html.is-touch :is(.sh-wallet small, .sh-card__tag, .sh-d__tier, .sh-d__tag, .sh-d__blurb, .sh-d__note, .sh-d__stats, .sh-d__own, .sh-pvnote, .sh-hero__blurb, .sh-empty small) { font-size: var(--t-fmin); }
html.is-touch :is(.sh-card__badges em, .sh-hero__badges em, .sh-bar em, .sh-pb em, .sh-dock__lbl, .sh-slot b, .sh-chip b) { font-size: var(--t-fs-cap); }
html.is-touch :is(.sh-bar small, .sh-pb b) { font-size: var(--t-fmin); }
html.is-touch .sh-slot { min-width: var(--t-hit); min-height: var(--t-hit); }
/* [ui-audit] the shop on a phone: whole tab words in a row that swipes (WEA… / OUT… / EFF… read as nothing), and cards wide
   enough for their TRY ONCE / OWN FOREVER prices (TRY… / OW…) */
html.is-touch:not(.is-tablet) .sh-tabs { overflow-x: auto; scrollbar-width: none; touch-action: pan-x; }
html.is-touch:not(.is-tablet) .sh-tabs::-webkit-scrollbar { display: none; }
html.is-touch:not(.is-tablet) .sh-tabs .hs-tab { flex: 0 0 auto; padding: 0 .9em; }
html.is-touch:not(.is-tablet) .sh-tabs .hs-tab span { overflow: visible; text-overflow: clip; }
html.is-touch:not(.is-tablet) .sh-grid { grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); }
/* [ui-audit] the shop's badges wrap a long word pair (fr POSSÉDER POUR TOUJOURS was cut by the hero card on an iPad) */
.sh-hero__badges em, .sh-card__badges em { white-space: normal; text-align: center; }
/* [ui-audit] the shop on a tablet (the stage between the panels): its kicker, the dock's slot words, the spin hint and the buy
   price at the tablet floors (9–13.7 px) */
html.is-touch :is(.sh-hero__kick > b, .sh-slot em) { font-size: var(--t-fs-cap); }
html.is-touch :is(.sh-spin, .sh-spin span, .sh-buy__p) { font-size: var(--t-fmin); }
html.is-touch .sh-slot em { white-space: nowrap; }
html.is-touch .sh-tagpv .pz-tag__name { font-size: var(--t-fmin); }   /* [ui-audit] (the shop's name-tag preview) */
/* [ui-audit] the shop on a tablet: card names and the buy buttons' words at the 14 px floor (13 px in ja / zh) */
html.is-touch :is(.sh-card__name, .sh-buy .iw-btn__label) { font-size: max(var(--t-fmin), 1em); }
html.is-touch .sh-card__name { font-size: var(--t-fmin); }
/* [vac-slot] the Blight Vac's hold-to-suck button: up-left of FIRE (the quick item sits left of it), GLOW green */
.tc .tc-btn--vac { right: calc(var(--s) * 1.12); bottom: calc(var(--s) * .92); width: calc(var(--s) * .72); height: calc(var(--s) * .72); color: #8dffc0; }
.tc .tc-btn--vac .tc-btn__ico { width: 62%; height: 62%; }
.tc .tc-btn--vac.is-down { background: rgba(141, 255, 192, .32); }
.tc:not(.is-war) .tc-btn--vac { display: none; }
html.is-touch .sh-slot em { font-size: var(--t-fmin); }   /* [ui-audit] ("empty" / "vide": a word, not a caps label) */
html.is-touch .sh .iw-btn__label { font-size: max(var(--t-fmin), 1em); }   /* [ui-audit] (TRY IN THE LOCKER: ロッカーで試着 13.5 px on an iPad) */
/* [ui-audit] a tablet: the dock's slot captions go, as on a phone (at the touch floor they ran into the dock's coins line —
   ピュリファイアー over コインはプレイでしか…); the slot's own icon says what is in it */
html.is-touch .sh-slot em { display: none; }
/* [popup-fit] a phone: the answers share the card's row evenly and keep their words inside (tighter side padding, tracking) */
html.is-touch .pz-popup__btns { flex-wrap: nowrap; gap: 8px; }
html.is-touch .pz-popup__btn { flex: 1 1 0; min-width: 0; padding-inline: .5em; letter-spacing: .02em; }
/* [popup-fit] three answers on a phone (FERMER | REGARDER | ÉLIMINÉ CETTE MANCHE): the card widens to fit them (a single word
   like REGARDER cannot break, and was cut at a third of a 46vw card on an SE) */
html.is-touch .pz-popup__card:has(.pz-popup__btns > :nth-child(3)) { width: min(460px, calc(100% - 24px)); }
html.is-touch .pz-popup__btns:has(> :nth-child(3)) .pz-popup__btn { font-size: 14px; }
/* [popup-fit] the card's wrapper spans the frame's width and centres the card (left: 50% + translate left the card only half
   the frame to grow into: a widened card hit that edge and sat off-centre) */
html.is-touch .pz-popup { left: 0; right: 0; translate: 0 -50%; display: flex; justify-content: center; pointer-events: none; }
html.is-touch .pz-popup[hidden] { display: none; }
html.is-touch .pz-popup > .pz-popup__card { pointer-events: auto; }
/* [ui-audit] last touch findings: the buy button's "Need N more" (9.8 px), a price box's label in the city's shop, the war bag's
   LOCKER / close buttons (36 / 34 px targets) */
html.is-touch .sh .iw-btn__sub { font-size: var(--t-fmin); }
html.is-touch .sh-pb em { font-size: var(--t-fs-cap) !important; }
html.is-touch .pz-inv__locker { min-height: var(--t-hit); }
html.is-touch .pz-inv__x { min-width: var(--t-hit); min-height: var(--t-hit); }
/* [ui-audit] an upright iPad: the notice stack centres in the space left of the touch pad (its right end touched the context button) */
@media (orientation: portrait) {
  html.is-touch.is-tablet .pz-notes { max-width: calc(100% - 2 * 250px); }   /* (still bottom-centre — the notice-stack rule — narrowed to clear the pad on both sides; the pills wrap) */
  html.is-touch.is-tablet .pz-notes .pz-note { white-space: normal; }
}
/* [ui-audit] WHERE ARE YOU? on an upright iPad: USAR MI UBICACIÓN / its sub wrap inside their buttons */
#ui-root .pz-loc :is([data-id="gps"], [data-id="skip"]) :is(.iw-btn__label, .iw-btn__sub) { white-space: normal; }
/* [ui-audit] the war bag's LOCKER word at the floor (ja ロッカー 12.8 px) */
html.is-touch .pz-inv__locker { font-size: var(--t-fmin); }
html.is-touch .pz-inv__locker * { font-size: inherit; }
