* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: 'Segoe UI', system-ui, sans-serif;
  background: #10141f;
  color: #e8e8e8;
  overflow: hidden;
}

.screen { position: fixed; inset: 0; }
.hidden { display: none !important; }

/* ---------- title screen (login / signup) ---------- */
/* The GBA title screen. Everything it draws is OURS: the painted plate
   public/battle/bg/night.jpg (the battle-scene terrain art) and the OFL
   "Press Start 2P" latin subset in public/vendor — the only two assets that
   survive the public-mode prune (server/publicmode.js PUBLIC_DENY_RE +
   scripts/prune-public.mjs ALLOW_RE), so the screen looks the same before and
   after the player builds their ROM store.
   #login[data-step] walks title -> menu -> form; the form is only ever
   HIDDEN, never renamed (js/core.js setTitleStep). */
@font-face {
  font-family: 'PressStart2P';
  src: url('/vendor/pressstart2p.woff2') format('woff2');
  font-display: swap;
}
#login {
  display: flex; align-items: center; justify-content: center;
  overflow-y: auto; overflow-x: hidden; padding: 16px 0 52px;
  background: linear-gradient(160deg, #1b2a4a 0%, #0e1626 60%, #251b3a 100%);
  --pix: 'PressStart2P', 'Courier New', monospace;
}
.ttl-bg { position: absolute; inset: 0; overflow: hidden; z-index: 0; }
/* the plate: cover-cropped, dimmed so the menu always wins the contrast */
.ttl-bg::before {
  content: ''; position: absolute; inset: -2%;
  background: url('/battle/bg/night.jpg') center 38% / cover no-repeat;
  filter: saturate(.86) brightness(.62);
}
/* faint CRT read: scanlines + vignette. Never strong enough to shimmer. */
.ttl-bg::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    repeating-linear-gradient(to bottom, rgba(0,0,0,.20) 0 1px, rgba(0,0,0,0) 1px 3px),
    radial-gradient(120% 85% at 50% 45%, rgba(5,6,15,0) 38%, rgba(5,6,15,.82) 100%);
}
.ttl-stage {
  position: relative; z-index: 1; margin: auto;
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  padding: 8px 12px;
}
.ttl-left { display: flex; flex-direction: column; align-items: center; gap: 13px; }

.ttl-mark { line-height: 1; font-weight: 400; }
.ttl-mark .wm {
  font-family: var(--pix); font-size: clamp(26px, 5.2vw, 58px); letter-spacing: .02em;
  color: #fff; text-shadow: 4px 4px 0 #101528, 8px 8px 0 rgba(0,0,0,.45);
}
.ttl-mark .wm b { color: #ffd60a; font-weight: 400; }
.ttl-tag {
  font-family: var(--pix); font-size: 10px; letter-spacing: .22em; color: #cfe0ff;
  display: inline-flex; align-items: center; gap: 10px; text-transform: uppercase;
}
.ttl-tag::before, .ttl-tag::after { content: ''; width: 34px; height: 2px; background: #ffd60a; opacity: .75; }

.ttl-press {
  font-family: var(--pix); font-size: 11px; letter-spacing: .16em; color: #ffd60a;
  background: none; border: 0; cursor: pointer; padding: 6px 8px;
  animation: ttlBlink 1.1s steps(1) infinite; text-shadow: 2px 2px 0 rgba(0,0,0,.7);
}
@keyframes ttlBlink { 0%, 55% { opacity: 1; } 56%, 100% { opacity: .12; } }
@keyframes ttlRise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .ttl-press { animation: none; }
  #login .ttl-menu, #login .ttl-form { animation: none !important; }
}

/* ---- the menu window ---- */
.ttl-menu {
  position: relative; width: min(430px, 92vw); text-align: left;
  background: rgba(14, 22, 38, .92); border: 2px solid #3b4a6b; border-radius: 14px;
  box-shadow: 0 20px 60px rgba(0,0,0,.6);
  padding: 14px 16px 16px;
}
/* step 'title': nothing but the wordmark. step 'menu': the two rows.
   step 'form': the chosen branch ALONE — the rows go, BACK brings them back.
   step 'all': the automation boot (tabs AND form mounted at once), the layout
   every other playwright suite has always driven. */
#login[data-step="title"] .ttl-menu { display: none; }
#login[data-step="menu"] .ttl-menu, #login[data-step="form"] .ttl-menu { animation: ttlRise .22s ease-out both; }
#login[data-step="title"] .ttl-foot { opacity: .75; }
#login[data-step="menu"] .ttl-form { display: none; }
#login[data-step="form"] .auth-tabs, #login[data-step="reset"] .auth-tabs { display: none; }
/* the reset panel is a fourth step of the same menu plate: it REPLACES the
   sign-in form (which every suite keeps mounted) and BACK returns to it */
#resetForm { display: none; }
/* confirming an address asks for the code alone — no new password */
#resetForm[data-mode="verify"] #resetPassRow { display: none; }
#login[data-step="reset"] #ttlForm { display: none; }
#login[data-step="reset"] #resetForm { display: block; animation: ttlRise .2s ease-out both; }
/* ...and the two-factor code, a fifth step that replaces it the same way */
#totpForm { display: none; }
#login[data-step="totp"] .auth-tabs, #login[data-step="totp"] #ttlForm { display: none; }
#login[data-step="totp"] #totpForm { display: block; animation: ttlRise .2s ease-out both; }
/* ...and the updated-Terms acceptance, a sixth (server/features/legal.js) */
#termsForm { display: none; }
#login[data-step="terms"] .auth-tabs, #login[data-step="terms"] #ttlForm { display: none; }
#login[data-step="terms"] #termsForm { display: block; animation: ttlRise .2s ease-out both; }
#totpForm[data-mode="recovery"] #totpCode { letter-spacing: .08em; font-family: inherit; }
#login[data-step="all"] .ttl-head { display: none; }
#login[data-step="form"] .ttl-form { animation: ttlRise .2s ease-out both; }
#login:not([data-step="title"]) .ttl-press { visibility: hidden; }
/* the window's header: BACK on the left, the chosen branch named on the right */
.ttl-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; }
.ttl-back {
  padding: 5px 8px 5px 0;
  font-family: var(--pix); font-size: 9px; letter-spacing: .1em;
  color: #7f8fb6; background: none; border: 0; border-radius: 6px; cursor: pointer;
}
.ttl-mode { font-family: var(--pix); font-size: 9px; letter-spacing: .1em; color: #ffd60a; }
.ttl-back:hover { color: #ffd60a; }
/* the two menu rows: a gen-3 list with a ▶ cursor, not pill tabs — the shared
   .auth-tab rules (market/corner/roulette) are overridden only in here */
#login .auth-tabs { display: flex; flex-direction: column; gap: 2px; margin: 0 0 12px; }
#login .auth-tab {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  font-family: var(--pix); font-size: 11px; letter-spacing: .04em; padding: 10px;
  border: 0; background: none; color: #9fb0d0; border-radius: 6px; cursor: pointer;
}
#login .auth-tab::before { content: '\25B6'; font-size: 9px; opacity: 0; color: #ffd60a; }
#login .auth-tab:hover { color: #cfe0ff; }
#login .auth-tab:focus-visible { outline: none; color: #fff; background: #1d2745; }
#login .auth-tab:focus-visible::before { opacity: .6; }
#login .auth-tab.selected { color: #fff; background: #232f4e; }
#login .auth-tab.selected::before { opacity: 1; }
.ttl-rule { height: 2px; background: #3b4a6b; margin: 2px 0 12px; }

.ttl-field { position: relative; margin-bottom: 8px; }
#nameInput, #emailInput, #passInput, #resetEmail, #resetCode, #resetPass, #totpCode {
  width: 100%; padding: 11px 14px; font-size: 16px; border-radius: 8px; outline: none;
  border: 2px solid #3b4a6b; background: #0e1626; color: #fff;
}
#passInput, #resetPass { padding-right: 44px; }
#resetCode, #totpCode { letter-spacing: .35em; font-family: var(--pix); font-size: 15px; }
#nameInput::placeholder, #emailInput::placeholder, #passInput::placeholder,
#resetEmail::placeholder, #resetCode::placeholder, #resetPass::placeholder, #totpCode::placeholder { color: #65769b; }
#nameInput:focus, #emailInput:focus, #passInput:focus,
#resetEmail:focus, #resetCode:focus, #resetPass:focus, #totpCode:focus { border-color: #ffd60a; }
.ttl-eye {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 34px; height: 30px; border: 0; border-radius: 6px; cursor: pointer;
  background: none; color: #9fb0d0; font-size: 15px; line-height: 1;
}
.ttl-eye:hover { color: #ffd60a; }
.ttl-stay {
  display: flex; align-items: center; gap: 8px; font-size: 13px; margin: 10px 2px 2px;
  color: #9fb0d0; cursor: pointer;
}
.ttl-stay input { width: 15px; height: 15px; accent-color: #c99b00; }
.ttl-accept { align-items: flex-start; font-size: 12px; line-height: 1.45; }
.ttl-accept input { flex: none; margin-top: 2px; }
.ttl-accept a, .ttl-legal-links a, .ttl-legal a { color: #ffd60a; }
.ttl-legal-links { text-align: center; font-size: 13px; margin: 6px 0 2px; }
.ttl-legal a { color: inherit; text-decoration: none; border-bottom: 1px dotted rgba(159,176,208,.5); }

/* .hint is shared with 19 other panels — the title screen only tightens it */
.hint { margin: 16px 0 8px; color: #9fb0d0; font-size: 14px; }
#login .hint { margin: 10px 0 6px; font-size: 13px; }
#skinGrid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.skin {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: #0e1626; border: 2px solid #3b4a6b; border-radius: 9px;
  padding: 7px 4px 5px; cursor: pointer; transition: transform .1s, border-color .1s;
  text-align: center; color: inherit; font: inherit;
}
.skin:hover, .skin:focus-visible { transform: translateY(-2px); border-color: #7f93c0; }
.skin.selected, .skin.selected:hover, .skin.selected:focus-visible { border-color: #ffd60a; background: #232f4e; }
.skin .srow { display: flex; gap: 4px; }
/* the sprites come from the ROM store — before it exists the canvas is blank,
   so each slot carries its own silhouette plate and the card still reads */
.skin canvas {
  width: 24px; height: 48px; image-rendering: pixelated;
  background: linear-gradient(180deg, #17203a, #101728); border-radius: 3px;
}
.skin .kname { font-family: var(--pix); font-size: 10px; text-transform: uppercase; }
.skin .kregion { font-size: 10px; color: #9fb0d0; }

/* Cloudflare Turnstile (server/turnstile.js): empty — and so invisible —
   unless the server hands out a site key and the check needs an interaction */
.ts-box { display: flex; justify-content: center; margin-top: 10px; }
.ts-box:empty { display: none; }

/* the two quiet links under the buttons — a link, not a control */
.ttl-forgot {
  display: block; width: 100%; margin: 9px 0 0; padding: 0; border: 0; background: none;
  color: #9fb0d0; font: inherit; font-size: 13px; text-align: center; cursor: pointer;
  text-decoration: underline dotted;
}
.ttl-forgot:hover { color: #ffd60a; }

#playBtn, #resetBtn, #totpBtn, #termsBtn {
  width: 100%; margin-top: 14px; padding: 13px; cursor: pointer; border: 0; border-radius: 9px;
  font-family: var(--pix); font-size: 12px; letter-spacing: .06em;
  background: #ffd60a; color: #171a21; box-shadow: 0 4px 0 #b99700;
}
#playBtn:hover, #resetBtn:hover, #totpBtn:hover, #termsBtn:hover { background: #ffe44d; }
#playBtn:active, #resetBtn:active, #totpBtn:active, #termsBtn:active { transform: translateY(2px); box-shadow: 0 2px 0 #b99700; }
.error { color: #ff6b6b; margin-top: 9px; min-height: 18px; font-size: 13px; text-align: center; }
#autoLoginBar { margin-top: 9px; font-size: 13px; text-align: center; color: #9fb0d0; }
#autoLoginBar a { color: #ffd60a; }

.ttl-foot {
  position: absolute; left: 0; right: 0; bottom: 14px; z-index: 1;
  display: flex; align-items: center; justify-content: center; gap: 14px;
  font-size: 12px; color: #cbd7ef;
}
.ttl-online {
  display: inline-flex; align-items: center; gap: 7px; padding: 5px 11px; border-radius: 999px;
  border: 1px solid rgba(159,176,208,.35); background: rgba(10,14,26,.55);
}
.ttl-online i { width: 7px; height: 7px; border-radius: 50%; background: #58e08a; box-shadow: 0 0 8px #58e08a; }
.ttl-about { color: inherit; text-decoration: none; border-bottom: 1px dotted rgba(159,176,208,.5); }

/* landscape phone: title left, menu right — the login screen is exempt from
   the in-game orientation lock, so it must fit 844x390 without scrolling */
@media (max-height: 480px) and (orientation: landscape) {
  .ttl-stage { flex-direction: row; align-items: center; gap: 26px; }
  .ttl-mark .wm { font-size: 30px; }
  .ttl-tag { font-size: 9px; }
  .ttl-menu { width: 360px; padding: 10px 12px 12px; }
  .ttl-foot { display: none; }
  .skin canvas { width: 20px; height: 40px; }
}
@media (max-width: 520px) {
  .ttl-menu { width: 94vw; }
  /* one line on a phone: at .22em "KANTO · JOHTO · HOENN" wraps under 390px
     and its second line runs into the first */
  .ttl-tag { letter-spacing: .1em; white-space: nowrap; }
  .ttl-tag::before, .ttl-tag::after { width: 18px; }
  .ttl-foot { flex-direction: column; gap: 6px; bottom: 8px; }
  /* the plate is 2.36:1 — a portrait crop of its centre is all sky, so pull
     the framing down onto the meadow */
  .ttl-bg::before { background-position: 46% 62%; }
}

/* ---------- PUBLIC_MODE ROM builder overlay (js/builder.js) ---------- */
/* The first screen a public-mode player ever sees. It draws the SAME scenery
   as the title screen behind it, so "build your game" reads as a beat of the
   title rather than a different app. Every id here is a test contract
   (rom-builder-ui / rom-update-ui). */
#romBuilder {
  position: fixed; inset: 0; z-index: 4000; overflow: auto;
  display: flex; align-items: center; justify-content: center;
  color: #e8ecff; font-family: inherit;
  background: #070a14 url('/battle/bg/night.jpg') center 38% / cover no-repeat;
}
#romBuilder::before {
  content: ''; position: fixed; inset: 0; pointer-events: none;
  background:
    repeating-linear-gradient(to bottom, rgba(0,0,0,.20) 0 1px, rgba(0,0,0,0) 1px 3px),
    radial-gradient(120% 85% at 50% 45%, rgba(5,6,15,.45) 0%, rgba(5,6,15,.88) 100%);
}
.rb-card {
  position: relative; z-index: 1; margin: auto;
  max-width: 560px; width: 92vw; padding: 22px 20px 20px;
  background: rgba(14, 22, 38, .93); border: 2px solid #3b4a6b; border-radius: 14px;
  box-shadow: 0 20px 60px rgba(0,0,0,.65);
}
.rb-card h1 {
  font-family: 'PressStart2P', 'Courier New', monospace; font-size: 14px;
  letter-spacing: .02em; text-transform: uppercase; margin: 0 0 12px; line-height: 1.5;
}
.rb-card p { line-height: 1.45; }
#rbDrop {
  border: 2px dashed #4a5a9a; border-radius: 10px; padding: 20px; margin: 14px 0;
  text-align: center; cursor: pointer; background: rgba(10,14,26,.5);
  transition: border-color .12s, background .12s;
}
#rbDrop:hover, #rbDrop.over { border-color: #ffd60a; background: #182046; }
.rb-drop-icon { font-size: 26px; margin-bottom: 6px; }
#rbSlots, #rbPlan { list-style: none; padding: 0; margin: 12px 0; display: grid; gap: 5px; }
#rbSlots li, #rbPlan li {
  font-size: 13px; padding: 7px 10px; border-radius: 8px; background: rgba(10,14,26,.5);
}
.rb-bar .lbl { display: flex; justify-content: space-between; font-size: 12px; color: #9fb0d0; }
.rb-bar .track { background: #0b1020; border: 1px solid #3b4a6b; border-radius: 5px; height: 10px; margin: 3px 0 8px; padding: 1px; }
.rb-bar .f { height: 100%; width: 0%; border-radius: 3px; background: repeating-linear-gradient(90deg, #ffd60a 0 6px, #ffe875 6px 8px); }
#rbErr { color: #ff7b7b; min-height: 18px; }
#rbGo {
  width: 100%; padding: 13px; border: 0; border-radius: 9px; cursor: pointer;
  font-family: 'PressStart2P', 'Courier New', monospace; font-size: 12px; letter-spacing: .04em;
  background: #ffd60a; color: #171a21; box-shadow: 0 4px 0 #b99700;
}
#rbGo:disabled { opacity: .45; box-shadow: none; cursor: default; }
#rbGo:not(:disabled):hover { background: #ffe44d; }

/* ---------- game ---------- */
/* touch-action none: a touch on the world canvas must never pan/zoom the page */
#canvas { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; touch-action: none; }
/* buttons: manipulation kills the 300ms double-tap-zoom delay on touch */
button { touch-action: manipulation; }

/* Game-Boy mobile layout: the canvas shrinks to leave a left gutter (D-pad)
   and a right gutter (A/B/Select/Start). The control gutters sit "outside the
   game" on each side. Desktop never gets `.touch-pad`, so it's unaffected. */
body.touch-pad #canvas {
  /* <canvas> is a replaced element: width:auto falls back to its intrinsic
     pixel size, NOT the left/right box — so we must size it explicitly. */
  left: var(--gutter-l, 0) !important; right: auto !important;
  width: calc(100% - var(--gutter-l, 0px) - var(--gutter-r, 0px)) !important;
}

#topbar {
  position: absolute; top: 10px; left: 50%; transform: translateX(-50%);
  display: flex; gap: 14px; align-items: center; z-index: 5;
  background: rgba(14, 22, 38, .85); border: 1px solid #3b4a6b;
  border-radius: 12px; padding: 8px 18px; font-size: 15px;
}
#regionLabel { font-weight: 700; color: #ffd60a; }
#clockLabel { color: #9fb6e0; cursor: help; font-variant-numeric: tabular-nums; white-space: nowrap; }
#weatherLabel:not(:empty) { color: #9fb6e0; cursor: help; }
.boxmon img { width: 32px; height: 32px; image-rendering: pixelated; vertical-align: middle; }
/* every navbar button shares one dark style (some used to fall through to the
   browser default white background) */
#topbar button { background: #232f4e; color: #fff; border: 1px solid #3b4a6b; border-radius: 8px; padding: 4px 10px; cursor: pointer; font-family: inherit; }
#topbar button:hover { background: #2f3f68; }

#party {
  position: absolute; top: 10px; right: 10px; z-index: 5;
  display: flex; flex-direction: column; gap: 6px; width: 210px;
}
.pmon {
  background: rgba(14, 22, 38, .88); border: 1px solid #3b4a6b; border-radius: 10px;
  padding: 4px 8px; font-size: 13px; cursor: pointer;
  display: flex; align-items: center; gap: 6px;
}
.pmon img { width: 40px; height: 40px; image-rendering: pixelated; flex-shrink: 0; }
.pmon .pinfo { flex: 1; min-width: 0; }
.pmon .row1 { display: flex; justify-content: space-between; font-weight: 600; }
.pmon .lvl { color: #9fb0d0; font-weight: 400; }
.pmon.fainted { opacity: .45; }
.pmon.egg { cursor: default; }
.pmon.dragging { opacity: .4; }
.pmon.dragover { border-color: #ffd60a; box-shadow: 0 0 0 2px #ffd60a66 inset; }
.pmon .eggicon { width: 40px; font-size: 26px; text-align: center; flex-shrink: 0; }
.pmon .pmoves {
  background: #232f4e; border: 1px solid #3b4a6b; color: #9fb0d0; border-radius: 6px;
  font-size: 11px; padding: 2px 5px; cursor: pointer; flex-shrink: 0;
}
.pmon .pmoves:hover { color: #fff; border-color: #ffd60a; }

.hpbar { height: 8px; background: #2a3450; border-radius: 4px; overflow: hidden; margin-top: 4px; }
.hpfill { height: 100%; background: #2ecc71; width: 100%; transition: width .4s ease-out; border-radius: 4px; }
.hpfill.mid { background: #f1c40f; }
.hpfill.low { background: #e74c3c; }

/* ---------- chat ---------- */
#chat {
  position: absolute; left: 10px; bottom: 10px; width: 360px; z-index: 5;
  display: flex; flex-direction: column; gap: 6px;
}
/* WoW-style channel tabs (created lazily by client.js): General always,
   Party/Guild only while a member; the active tab filters #chatLog below */
#chatTabs { display: flex; gap: 3px; margin-bottom: -4px; }
#chatTabs .chattab {
  font-size: 11px; padding: 2px 9px 3px; cursor: pointer; line-height: 1.5;
  background: rgba(14, 22, 38, .6); color: #9fb3c8;
  border: 1px solid #2e3d4f; border-bottom: none; border-radius: 8px 8px 0 0;
}
#chatTabs .chattab.active { background: rgba(24, 38, 62, .9); color: #fff; border-color: #4b6b8f; }
#chatTabs .chattab.unread::after { content: ' •'; color: #ffd60a; }
#chatLog {
  height: 160px; overflow-y: auto; font-size: 13px;
  background: rgba(14, 22, 38, .75); border-radius: 10px; padding: 8px 10px;
  display: flex; flex-direction: column; gap: 2px;
}
/* the box holds its full height from the start (WoW-style) — with few
   messages they sit at the BOTTOM: margin-top:auto on the first line pushes
   the stack down without breaking overflow scrolling (justify-content would) */
#chatLog > :first-child { margin-top: auto; }
/* tab filters: Party/Guild show only their own channel; General shows all */
#chatLog.tab-party > div:not(.partychat) { display: none; }
#chatLog.tab-guild > div:not(.guild) { display: none; }
#chatLog .sys { color: #8fb4ff; font-style: italic; }
#chatLog .from { color: #ffd60a; font-weight: 600; }
#chatInput {
  padding: 8px 12px; border-radius: 10px; border: 1px solid #3b4a6b;
  background: rgba(14, 22, 38, .9); color: #fff; outline: none; font-size: 14px;
}
/* name-command autocomplete strip (created lazily by client.js) */
#chatSuggest { display: flex; gap: 4px; flex-wrap: wrap; }
#chatSuggest.hidden { display: none; }
#chatSuggest .suggest {
  font-size: 12px; padding: 2px 9px; border-radius: 8px; cursor: pointer;
  background: rgba(24, 38, 62, .9); color: #cfe3ff; border: 1px solid #4b6b8f;
}

/* ---------- battle ---------- */
#battle {
  position: absolute; inset: 0; z-index: 20;
  background: rgba(8, 12, 22, .92);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  /* battle-scene geometry (docs/mockups/battle-scene): one frame = the painted
     scene (--bt-arena-h) over the control band (--bt-band-h). --bt-scale is
     set by layoutBattleSlots() as the scene shrinks on short screens. */
  --bt-w: 840px; --bt-arena-h: 356px; --bt-band-h: 116px; --bt-scale: 1;
}
/* the chat + party panel stay reachable OVER the battle overlay: type a
   message or mute your own mic mid-fight. :has() tracks the overlay's
   .hidden class itself, so every open/close path (start, end event,
   teardown, spectate) is covered with no JS toggle to forget. */
#game:has(#battle:not(.hidden)) #chat,
#game:has(#battle:not(.hidden)) #crewPanel { z-index: 22; }
/* phones: the battle panels need the width — keep the chat present but
   short so it never buries the action buttons under the arena */
body.touch-pad #game:has(#battle:not(.hidden)) #chatLog { height: 64px; }
/* ...but on the phone the panel would sit ON the band's first move button
   (the frame spans the gutters' gap, the chat the bottom-left corner): while
   a battle is open it drops BEHIND the overlay — read it dimmed, fight first */
body.touch-pad #game:has(#battle:not(.hidden)) #chat { z-index: 19; }
#battleFrame {
  position: relative; width: var(--bt-w); max-width: 95vw;
  border: 2px solid #3b4a6b; border-radius: 16px; overflow: hidden; background: #0e1626;
  box-shadow: 0 16px 36px rgba(0, 0, 0, .6);
}
/* the scene: a painted terrain (applyBattleTerrain sets data-terrain + the
   image); the FX canvas, level box and ball projectile size off this box.
   Short windows trade scene height first so the band never spills. */
#battleArena {
  position: relative; width: 100%;
  height: min(var(--bt-arena-h), calc(100vh - var(--bt-band-h) - 90px)); min-height: 140px;
  background: #1b2a44 center / cover no-repeat;
}
#battleArena::after {
  content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0) 70%, rgba(8, 12, 22, .5) 100%);
}
/* singles: each side is a full-scene layer — the INFO PLATE pinned to its
   corner (foe top-left, mine bottom-right) and the sprite SLOT dropped on the
   painting's platform anchor (terrains.json → layoutBattleSlots), so the two
   plates can never collide at any scene size */
.combatant { position: absolute; inset: 0; z-index: 1; pointer-events: none; }
.combatant > * { pointer-events: auto; }
.combatant .plate { position: absolute; }
.combatant.foe .plate { top: 14px; left: 14px; }
.combatant.mine .plate { right: 14px; bottom: 14px; }
.slot {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -100%);
  filter: drop-shadow(0 10px 8px rgba(0, 0, 0, .45));
}
/* both slots are EXACTLY 2x the 96px sprite frame: pixel art under
   image-rendering:pixelated only looks right at an integer zoom (the old
   150/180 slots put the 96-frames at 1.56x, where nearest-neighbour doubles
   every other pixel column — the "jaggy foe" report); the classic 64x64 ROM
   pics and the animated set's bbox crops size by natural/96 of the slot
   (fitMonSprite), so they land on the same 2x */
.slot-mine, .slot-foe { width: calc(192px * var(--bt-scale)); height: calc(192px * var(--bt-scale)); }
.slot img { display: block; width: 100%; height: 100%; image-rendering: pixelated; }
/* the fallback back-facing trainer is a 16x32 (1:2) overworld-sheet crop, not
   ROM battle art — it keeps its own box. The REAL pics (the opposing trainer's
   front pic, our /trainers/back_*.png) are ROM art like the mons and are sized
   by fitMonSprite's natural/96 rule, so they stand at the same 2x instead of
   stretching to the whole slot at 3x */
.slot-mine img.trainer { width: 50%; margin: 0 auto; object-fit: contain; }
/* species that float (Emerald gEnemyMonElevation → public/battle/elevation.json)
   ride --bt-elev above the platform and cast the ROM's elliptical shadow on it */
.hover-shadow {
  display: none; position: absolute; left: 50%; bottom: calc(-1 * var(--bt-elev, 0px));
  width: 55%; height: 14%; transform: translate(-50%, 50%); border-radius: 50%; pointer-events: none;
  background: radial-gradient(ellipse at center, rgba(0, 0, 0, .45) 0%, rgba(0, 0, 0, .25) 55%, rgba(0, 0, 0, 0) 100%);
}
.slot.hover .hover-shadow { display: block; }
/* doubles keeps the classic corner groups: the cloned plates take the free
   corners (inline styles from ensureDoublesDom), the primaries pull back into
   their own corner as flex rows */
#battleArena.doubles .combatant { inset: auto; display: flex; align-items: center; gap: 12px; }
#battleArena.doubles .combatant.foe { top: 26px; right: 48px; flex-direction: row-reverse; align-items: flex-start; }
#battleArena.doubles .combatant.mine { bottom: 26px; left: 48px; align-items: flex-end; }
#battleArena.doubles .combatant .plate { position: static; }
#battleArena.doubles .slot { position: static; transform: none; filter: none; }
#battleArena.doubles .slot-mine, #battleArena.doubles .slot-foe { width: 192px; height: 192px; }
#battleArena.doubles .hover-shadow { display: none; }

/* ---------- battle juice (animation polish) ---------- */
#battleArena img { transition: transform .25s ease, opacity .25s ease; }
/* attack lunge: my mon darts up-right, the foe down-left */
@keyframes lungeMine { 30% { transform: translate(14px, -10px); } 100% { transform: translate(0, 0); } }
@keyframes lungeFoe { 30% { transform: translate(-14px, 10px); } 100% { transform: translate(0, 0); } }
.combatant.mine img.lunge, .allymate img.lunge { animation: lungeMine .22s ease-out; }
.combatant.foe img.lunge { animation: lungeFoe .22s ease-out; }
/* hit flash: two quick brightness pulses */
@keyframes hitFlash {
  0%, 40%, 80%, 100% { filter: brightness(1); }
  20%, 60% { filter: brightness(2.6) saturate(.4); }
}
#battleArena img.hitflash { animation: hitFlash .3s linear; }
/* arena shake on big hits */
@keyframes arenaShake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-4px, 2px); }
  40% { transform: translate(4px, -2px); }
  60% { transform: translate(-4px, -2px); }
  80% { transform: translate(4px, 2px); }
}
#battleArena.shake { animation: arenaShake .25s linear; }
/* status tint pulse, colored per ailment via --stc */
@keyframes statusPulse {
  0%, 100% { filter: none; }
  35%, 75% { filter: drop-shadow(0 0 10px var(--stc)) drop-shadow(0 0 2px var(--stc)) brightness(1.2); }
}
#battleArena img.stflash { animation: statusPulse .5s ease; }
#battleArena img.st-psn { --stc: #b35cc6; }
#battleArena img.st-brn { --stc: #ff8c42; }
#battleArena img.st-par { --stc: #f5d442; }
#battleArena img.st-slp, #battleArena img.st-frz { --stc: #6fc3ff; }
/* faint: drop down and fade */
#battleArena img.faint { transition: transform .5s ease-in, opacity .5s ease-in; transform: translateY(46px); opacity: 0; }
/* catch attempt: foe shrinks into the ball; removing .caught pops it back */
#battleArena img.caught { transform: scale(.12) translateY(20px); opacity: .35; }
.ballproj {
  position: absolute; left: 0; top: 0; width: 20px; height: 20px; z-index: 7;
  border-radius: 50%; border: 2px solid #1a2238; pointer-events: none;
  background: linear-gradient(180deg, #e63946 0 44%, #1a2238 44% 56%, #f1f1f1 56% 100%);
  will-change: transform;
}
@keyframes ballWobble {
  0%, 100% { transform: rotate(0deg); }
  12%, 45%, 78% { transform: rotate(-22deg); }
  28%, 62%, 92% { transform: rotate(22deg); }
}
.ballproj.wobble { animation: ballWobble .55s ease-in-out; }
/* battle entry: sprites slide in from their own side */
@keyframes enterMine { from { transform: translateX(-120px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes enterFoe { from { transform: translateX(120px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
#battleArena img.enter-mine { animation: enterMine .35s ease-out; }
#battleArena img.enter-foe { animation: enterFoe .35s ease-out; }
/* the opposing trainer's front pic bows out to the right (the originals
   slide the trainer off before the first mon is sent out) */
@keyframes exitFoe { to { transform: translateX(140px); opacity: 0; } }
#battleArena img.exit-foe { animation: exitFoe .32s ease-in forwards; }
@keyframes exitMine { to { transform: translateX(-140px); opacity: 0; } }
#battleArena img.exit-mine { animation: exitMine .3s ease-in forwards; }
/* staged battle opening: a held plate stays out of sight until its mon's
   send-out reveals it; the player's gen3 back pic sizes like a mon sprite */
#battleArena .combatant.hold-plate .plate { visibility: hidden; }
#battleArena .combatant.mine img.backpic { image-rendering: pixelated; }
/* the blinking "press A" cue riding the battle log's corner */
#battleLog { position: relative; }
#blMore { position: absolute; right: 10px; bottom: 2px; color: #ffd60a; font-size: 12px; pointer-events: none; animation: blMoreBlink 0.9s steps(2, jump-none) infinite; }
@keyframes blMoreBlink { 50% { opacity: 0; } }
/* pre-battle intro: the whole plates ride in from their own side as the scene
   opens after the screen wipe (transform + opacity only — no layout thrash) */
@keyframes introPlateMine { from { transform: translateX(-48px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes introPlateFoe { from { transform: translateX(48px); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
.combatant.mine.intro-mine { animation: introPlateMine .3s ease-out; }
.combatant.foe.intro-foe { animation: introPlateFoe .3s ease-out; }
.plate {
  background: linear-gradient(180deg, #273556, #1e2a48); border: 1px solid #3b4a6b;
  border-radius: 10px; padding: 6px 10px 8px; width: 210px; color: #fff;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45);
  /* LOW plates: name·status + Lv on one line, then the HP label, bar and
     (ours) the numbers side by side; the foe's ball row and our EXP line
     span the full width underneath */
  display: grid; grid-template-columns: auto 1fr; column-gap: 6px; align-items: center;
}
.combatant.mine .plate { width: 232px; grid-template-columns: auto 1fr auto; }
.plate-top { grid-column: 1 / -1; display: flex; align-items: baseline; margin-bottom: 4px; font-size: 13px; }
.plate-top > b { text-transform: uppercase; letter-spacing: .4px; }
.plate-top > span:last-child { margin-left: auto; font-size: 11px; color: #9fb0d0; font-weight: 600; }
.hplabel { font-size: 9px; font-weight: 800; color: #e5a53b; background: #141b2d; padding: 1px 4px; border-radius: 3px; letter-spacing: .5px; }
.plate .hpbar { margin: 0; height: 7px; background: #101625; border: 1px solid #283756; border-radius: 4px; }
.plate .hpfill { background: linear-gradient(90deg, #2ecc71, #48e487); }
.plate .hpfill.mid { background: linear-gradient(90deg, #f39c12, #f1c40f); }
.plate .hpfill.low { background: linear-gradient(90deg, #e74c3c, #ff7b6b); }
.hptext { font-size: 10px; font-weight: 700; color: #fff; text-align: right; white-space: nowrap; min-width: 46px; margin: 0; }
/* the foe's trainer balls get their own row UNDER the bar (never beside it) */
.combatant.foe .plate .hptext { grid-column: 1 / -1; min-width: 0; margin-top: 4px; }
.combatant.foe .plate .hptext:empty { display: none; }
/* gen3 party status summary balls on the foe plate (build-battle-balls.mjs).
   The selector must out-rank BOTH `.combatant.foe img` (the 150px sprite
   sizing) and `#battleArena:not(.doubles) .combatant.foe img` (the sprite's
   28px top offset — it shoved the whole ball row 28px under the HP bar), so
   it carries the #battleArena id and zeroes the margin explicitly. */
#battleArena .combatant .plate img.ballrow-ball { width: 14px; height: 14px; image-rendering: pixelated; vertical-align: middle; margin: 0 0 0 2px; }
.expbar { grid-column: 1 / -1; height: 3px; background: #101625; border: 1px solid #202c46; border-radius: 2px; margin-top: 5px; overflow: hidden; }
.expfill.ticking { transition: none; } /* the rAF sweep drives the width frame by frame */
/* level-up stats box (gen3 drawlvlupbox): a plain plate in the arena's corner */
#lvlBox {
  position: absolute; right: 12px; bottom: 12px; z-index: 3; min-width: 150px;
  background: rgba(14, 22, 38, .92); border: 1px solid #3b4a6b; border-radius: 10px;
  padding: 8px 12px; font-size: 12px; color: #e6ecf5;
}
#lvlBox .lvl-title { font-weight: bold; margin-bottom: 4px; }
#lvlBox table { border-collapse: collapse; width: 100%; }
#lvlBox td { padding: 1px 0; }
#lvlBox td + td { text-align: right; color: #9fb0d0; padding-left: 14px; }
.expfill { height: 100%; background: #4ea8de; transition: width .3s; }

/* the control band: while text plays it is ONE full-width message box; on
   the player's turn (#battleFrame.choosing, setActionsEnabled) it swaps to the
   move grid + Bag/Pokémon/Run column like the ROM's text box vs. menu */
#battleBand {
  position: relative; height: var(--bt-band-h); box-sizing: border-box; padding: 6px 8px;
  border-top: 1px solid #3b4a6b; background: #0e1626; display: grid; grid-template-rows: minmax(0, 1fr);
}
#battleLog {
  position: relative; overflow-y: auto; scrollbar-width: none;
  background: linear-gradient(180deg, #16223a, #0f182b); border: 1px solid #3b4a6b; border-radius: 8px;
  padding: 8px 16px; font-size: 17px; line-height: 1.6; color: #fff;
}
#battleLog::-webkit-scrollbar { display: none; }
#battleLog > div { color: #9fb0d0; }
#battleLog > div:last-child { color: #fff; }
#battleFrame.choosing #battleLog { display: none; }
#battleFrame:not(.choosing) #battleActions { display: none; }
#battleActions { display: grid; grid-template-columns: 1fr 118px; grid-template-rows: 16px minmax(0, 1fr); column-gap: 8px; row-gap: 4px; min-height: 0; }
#battleTicker { grid-column: 1 / -1; display: flex; justify-content: space-between; align-items: center; padding: 0 4px; font-size: 11px; color: #9fb0d0; letter-spacing: .3px; white-space: nowrap; overflow: hidden; }
#battleTicker b { color: #fff; }
#battleTicker .hint { display: flex; gap: 8px; font-size: 10px; margin: 0; }
#battleTicker kbd { background: #232f4e; border: 1px solid #3b4a6b; color: #9fb0d0; padding: 0 4px; border-radius: 3px; font-size: 9px; font-family: inherit; }
body.touch-pad #battleTicker .hint { display: none; }
#moveButtons { display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); gap: 6px; min-height: 0; }
#moveButtons button {
  position: relative; display: grid; grid-template-rows: auto auto; align-items: center;
  padding: 3px 8px 3px 10px; min-height: 36px; overflow: hidden; font-size: 13px; font-weight: 600; text-align: left;
  border: 1px solid #3b4a6b; border-radius: 8px; background: #232f4e; color: #fff; cursor: pointer;
  font-family: inherit; box-shadow: 0 2px 4px rgba(0, 0, 0, .2);
}
#moveButtons button:hover:not(:disabled) { background: #2a385e; }
#moveButtons button .mv-meta { display: flex; gap: 6px; align-items: center; font-size: 11px; color: #9fb0d0; font-weight: 400; white-space: nowrap; overflow: hidden; }
#moveButtons button .mv-pp { margin-left: auto; }
#moveButtons button .mv-pp b { color: #fff; }
.tchip { background: var(--tc, #3b4a6b); color: #0e1626; font-size: 9px; font-weight: 800; text-transform: uppercase; padding: 0 6px; border-radius: 999px; line-height: 14px; letter-spacing: .5px; }
#moveButtons button small { display: block; font-weight: 400; color: #9fb0d0; font-size: 11px; }
#moveButtons button.nopp { opacity: .45; background: #192137; border-color: #5a3b3b; }
#moveButtons button.nopp .mv-name { text-decoration: line-through; }
#moveButtons button.nopp .mv-pp b { color: #e74c3c; }
#metaButtons { display: flex; flex-direction: column; gap: 6px; }
#metaButtons button {
  flex: 1; display: flex; align-items: center; padding: 0 8px; min-height: 0;
  border: 1px solid #3b4a6b; border-radius: 6px; background: #1a2238; color: #fff; cursor: pointer;
  font-family: inherit; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
}
#metaButtons button:hover:not(:disabled) { background: #253356; border-color: #526794; }
#metaButtons button .ic { display: inline-flex; color: #9fb0d0; margin-right: 7px; }
#battleActions button:disabled { opacity: .4; cursor: default; }

#switchMenu {
  position: absolute; left: 12px; bottom: calc(var(--bt-band-h) + 8px); background: #1a2238; border: 2px solid #ffd60a;
  border-radius: 12px; padding: 12px; display: flex; flex-direction: column; gap: 6px; z-index: 25;
  width: 280px;
  /* never taller than the space above the action bar — a 6-mon party (or a
     stuffed battle bag) scrolls INSIDE the menu instead of running off the
     top of a short phone screen (battleKeySync keeps the cursor in view) */
  max-height: calc(100% - var(--bt-band-h) - 16px); overflow-y: auto;
}
#switchMenu button {
  padding: 10px; border: 1px solid #3b4a6b; border-radius: 8px; background: #232f4e;
  color: #fff; cursor: pointer; text-align: left; font-size: 14px;
}
#switchMenu button:disabled { opacity: .4; cursor: default; }

/* ---------- box ---------- */
#boxModal, #bagModal, #movesModal, #flyModal, #seagallopModal {
  position: absolute; inset: 0; z-index: 30; background: rgba(8, 12, 22, .85);
  display: flex; align-items: center; justify-content: center;
}
#movesList { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; max-height: 50vh; overflow-y: auto; }
.movessub { margin: 8px 2px 2px; color: #8fa3c8; font-size: 12px; font-weight: 700; }
.movessub:first-child { margin-top: 0; }
.moveopt {
  display: flex; align-items: center; gap: 10px;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #cdd6ea; padding: 7px 10px; cursor: grab; text-align: left; font-size: 13px;
}
.moveopt small { display: block; color: #9fb0d0; }
.moveopt .moveslot {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  background: #232f4e; color: #ffd60a; font-weight: 700;
  display: flex; align-items: center; justify-content: center; font-size: 12px;
}
.moveopt .movemeta { flex: 1; }
.moveopt .movearrs { flex: none; display: flex; flex-direction: column; gap: 2px; }
.moveopt .movearr {
  background: #232f4e; border: 1px solid #3b4a6b; border-radius: 5px;
  color: #cdd6ea; cursor: pointer; line-height: 1; padding: 1px 6px; font-size: 11px;
}
.moveopt .movearr:disabled, .moveopt .moverm:disabled { opacity: .3; cursor: default; }
.moveopt .moverm {
  flex: none; background: #2a1622; border: 1px solid #5b3b4a; border-radius: 5px;
  color: #e2a0b4; cursor: pointer; line-height: 1; padding: 3px 7px; font-size: 12px;
}
.moveopt.moveadd { cursor: pointer; border-style: dashed; }
.moveopt.moveadd:disabled { opacity: .4; cursor: default; }
.moveopt .moveplus { flex: none; color: #7fd08a; font-weight: 700; font-size: 16px; }
.moveopt.dragging { opacity: .5; }
.moveopt.dragover { border-color: #ffd60a; background: #232f4e; }
#movesConfirm {
  width: 100%; padding: 10px; border: none; border-radius: 8px;
  background: #ffd60a; font-weight: 700; cursor: pointer;
}
#movesConfirm:disabled { opacity: .4; cursor: default; }
.box-card {
  background: #1a2238; border: 2px solid #3b4a6b; border-radius: 14px;
  width: 520px; max-width: 94vw; max-height: 80vh; padding: 18px; overflow-y: auto;
}
.box-card h2 { display: flex; justify-content: space-between; margin-bottom: 12px; }
#boxClose { background: none; border: none; color: #fff; font-size: 18px; cursor: pointer; }
.box-empty { color: #9fb0d0; font-style: italic; }

/* ---------- PC storage box (the gen3 multi-box grid, js/pcbox.js) ---------- */
/* every size derives from --pcb-tile, so the mobile queries scale the whole
   layout by rewriting one value */
.box-card.pcbox { width: 900px; }
#boxList {
  --pcb-tile: 58px; --pcb-gap: 3px;
  display: grid; gap: 10px;
  grid-template-columns: auto auto minmax(150px, 1fr);
  grid-template-areas: "head head head" "bulk bulk bulk" "party grid info" "wall wall wall";
}
#pcbHead { grid-area: head; display: flex; flex-wrap: wrap; gap: 6px 10px; align-items: center; }
#pcbBulk { grid-area: bulk; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; font-size: 12px; color: #cdd6ea; }
#pcbTabs { display: flex; gap: 4px; }
.pcb-tab {
  background: #232f4e; border: 1px solid #3b4a6b; border-radius: 8px 8px 0 0; color: #cdd6ea;
  padding: 5px 12px; font-size: 12px; font-weight: 700; cursor: pointer;
}
.pcb-tab.sel { background: #ffd60a; color: #10131f; border-color: #ffd60a; }
.pcb-tab.dragover, #pcbPager button.dragover { border-color: #ffd60a; box-shadow: 0 0 0 2px #ffd60a66 inset; }
#pcbPager { display: flex; align-items: center; gap: 6px; }
#pcbPager button {
  background: #232f4e; border: 1px solid #3b4a6b; border-radius: 6px; color: #cdd6ea;
  cursor: pointer; padding: 3px 10px; font-size: 14px; line-height: 1;
}
#pcbName { min-width: 130px; text-align: center; font-weight: 700; color: #e8ecf6; font-size: 13px; }
#pcbTools { display: flex; gap: 4px; align-items: center; margin-left: auto; }
#pcbSearch {
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px; color: #e8ecf6;
  padding: 5px 9px; font-size: 16px; font-family: inherit; outline: none; width: 150px;
}
#pcbSearch:focus { border-color: #ffd60a; }
#pcbSort { background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px; color: #e8ecf6; font-family: inherit; font-size: 12px; padding: 5px; }

/* the wallpaper (public/box/wp-<n>.png) is the gen3 framed box, already
   cropped to the grid rectangle by the builder — so it stretches over the
   grid area 1:1 at any tile size */
#pcbGridWrap {
  grid-area: grid; position: relative; overflow: hidden; padding: 6px;
  border: 2px solid #3b4a6b; border-radius: 10px; background: #0e1626;
}
/* the wallpaper is the gen3 box background: 160x144 stretched over the whole
   grid area (fill, not cover — cropping would cut its decorative frame off) */
#pcbWallImg {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: fill;
  image-rendering: pixelated; opacity: .6; pointer-events: none;
}
#pcbGrid {
  position: relative; display: grid; gap: var(--pcb-gap);
  grid-template-columns: repeat(6, var(--pcb-tile)); grid-auto-rows: var(--pcb-tile);
}
.pcb-slot {
  position: relative; display: flex; align-items: center; justify-content: center;
  border: 1px solid rgba(59, 74, 107, .55); border-radius: 8px; background: rgba(14, 22, 38, .42);
  /* touch-action:none is what lets a finger drag instead of scrolling — safe
     because the 6x5 grid is fixed and never scrolls itself */
  cursor: pointer; touch-action: none; user-select: none; -webkit-user-select: none;
}
.pcb-slot.empty { background: rgba(14, 22, 38, .22); }
.pcb-slot img {
  width: calc(var(--pcb-tile) - 10px); height: calc(var(--pcb-tile) - 10px);
  object-fit: contain; image-rendering: pixelated; pointer-events: none;
}
.pcb-slot .eggicon { font-size: calc(var(--pcb-tile) - 28px); pointer-events: none; }
.pcb-slot .shiny { position: absolute; top: 1px; right: 2px; font-size: 10px; pointer-events: none; }
.pcb-slot .held { position: absolute; bottom: 1px; right: 2px; font-size: 9px; pointer-events: none; }
.pcb-slot.dragging, .pcb-slot.inhand, .pcb-pmon.dragging, .pcb-pmon.inhand { opacity: .35; }
.pcb-slot.dragover, .pcb-pmon.dragover { border-color: #ffd60a; box-shadow: 0 0 0 2px #ffd60a66 inset; }
.pcb-slot.sel { box-shadow: 0 0 0 2px #7fd08a inset; }
.pcb-slot.sel::after { content: "✓"; position: absolute; top: 0; left: 3px; color: #7fd08a; font-size: 11px; }
/* over the region's badge level cap: it cannot join the party here, so the tile
   reads as barred BEFORE the withdraw bounces (pcbOverCap in js/pcbox.js). The
   "!" carries the same meaning for anyone who can't separate the red. */
.pcb-slot.overcap { background: rgba(140, 30, 38, .58); border-color: rgba(230, 57, 70, .75); }
.pcb-slot.overcap::before {
  content: "!"; position: absolute; bottom: 0; left: 3px;
  color: #ff9aa2; font-size: 11px; font-weight: 700; pointer-events: none;
}
#boxList.holding .pcb-slot, #boxList.holding .pcb-pmon { cursor: copy; }

#pcbParty { grid-area: party; display: flex; flex-direction: column; gap: 4px; width: 150px; }
.pcb-phead { font-size: 11px; font-weight: 700; color: #9fb0d0; letter-spacing: .5px; }
.pcb-pmon {
  display: flex; align-items: center; gap: 6px; min-height: 40px; padding: 3px 6px;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  font-size: 12px; color: #cdd6ea; cursor: pointer; touch-action: none;
  user-select: none; -webkit-user-select: none;
}
.pcb-pmon img { width: 32px; height: 32px; object-fit: contain; image-rendering: pixelated; pointer-events: none; }
.pcb-pmon.empty { opacity: .45; justify-content: center; }

#pcbInfoPanel { grid-area: info; min-height: 120px; font-size: 12px; color: #cdd6ea; }
#pcbInfoPanel img { width: 64px; height: 64px; image-rendering: pixelated; }
#pcbInfoPanel .pcb-hand { color: #ffd60a; font-weight: 700; }
#pcbInfoPanel .pcb-overcap { color: #ff9aa2; font-size: 12px; }
#pcbWallPick { grid-area: wall; display: grid; grid-template-columns: repeat(8, 1fr); gap: 5px; }
.pcb-wallopt { aspect-ratio: 1; overflow: hidden; border: 1px solid #3b4a6b; border-radius: 6px; cursor: pointer; background: #0e1626; }
.pcb-wallopt img { width: 100%; height: 100%; object-fit: cover; image-rendering: pixelated; }
.pcb-wallopt.sel { border-color: #ffd60a; }

/* the floating drag ghost: above every modal AND the touch pad (z70), and
   pointer-events:none so elementFromPoint sees the tile underneath */
.drag-ghost {
  position: fixed; z-index: 90; pointer-events: none; opacity: .9;
  transform: translate(-50%, -60%); filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .6));
}
.drag-ghost img { width: 56px; height: 56px; image-rendering: pixelated; }
.drag-ghost .n {
  position: absolute; right: -8px; top: -8px; background: #ffd60a; color: #10131f;
  border-radius: 9px; padding: 0 5px; font-size: 11px; font-weight: 700;
}

/* ---------- dex / market / leaderboards / guild ---------- */
#dexModal, #marketModal, #lbModal, #guildModal, #friendsModal, #profileModal, #towerModal, #gmModal, #achvModal, #monModal, #rouletteModal, #fameModal {
  position: absolute; inset: 0; z-index: 30; background: rgba(8, 12, 22, .85);
  display: flex; align-items: center; justify-content: center;
}
.mon-meta { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 14px; margin: 8px 0; font-size: 13px; }
.mon-meta b { color: #9fb3d8; font-weight: 600; }
.mon-met { background: rgba(255,255,255,.05); border-left: 3px solid #ffd60a; padding: 8px 10px; border-radius: 6px; font-size: 13px; }
.mon-moves { columns: 2; margin: 4px 0 0; padding-left: 16px; font-size: 13px; }
.mon-ribbons { display: flex; flex-wrap: wrap; gap: 5px; margin: 4px 0; }
/* IVs & EVs on the owner's card (mon-stats-detail) — compact 7-column grid */
.mon-ivev { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 12px; text-align: center; margin: 4px 0 2px; }
.mon-ivev th { color: #9fb3d8; font-weight: 600; }
.mon-ivev tr > th:first-child { text-align: left; width: 34px; }
.mon-ivev td, .mon-ivev th { padding: 1px 2px; }
.mon-ivev tr + tr { border-top: 1px solid rgba(255,255,255,.07); }
.mon-ev-total { font-size: 12px; color: #9fb3d8; text-align: right; margin: 0 0 4px; }
.ribbon-chip {
  padding: 2px 9px; border-radius: 10px; font-size: 12px;
  background: #232f4e; border: 1px solid #3b4a6b; color: #e8ecf6;
}
#monModal .box-card { max-width: 360px; }
.mon-actions { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0; }
.mon-actions button {
  flex: 1 1 auto; padding: 7px 10px; border-radius: 8px; font-size: 13px;
  background: #232f4e; color: #fff; border: 1px solid #3b4a6b; cursor: pointer; font-family: inherit;
}
.mon-actions button:hover { background: #2f3f68; }
/* the card sits BELOW the rename/moves/held-item windows it opens, so closing one
   reveals the card again instead of dismissing it. A BOX-opened card sits at 31
   (above the box modal it came from), so the windows it opens must clear 31 too —
   the move editor and the held-item / move-learn picker sit at 32, above either
   the party card (28) or the box card (31). */
#monModal { z-index: 28; }
#movesModal, #bagModal { z-index: 32; }

/* ---------- achievements panel ---------- */
#achvList { display: flex; flex-direction: column; gap: 6px; max-height: 62vh; overflow-y: auto; }
.achv-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px; background: rgba(255,255,255,.05); }
.achv-row.got { background: rgba(244,197,66,.14); border: 1px solid rgba(244,197,66,.4); }
.achv-row.locked { opacity: .55; }
.achv-ico { font-size: 22px; width: 26px; text-align: center; flex: none; }
.achv-txt { display: flex; flex-direction: column; flex: 1; }
.achv-txt small { color: #9fb0d0; font-size: 12px; }
.achv-row.locked .achv-txt b { color: #b9c4da; }
.achv-check { color: #f4c542; font-weight: bold; font-size: 18px; flex: none; }

/* ---------- game-master give panel ---------- */
#gmBtn { background: #7a3bbf; color: #fff; border: 1px solid #9a5bdf; border-radius: 8px; padding: 4px 10px; cursor: pointer; }
.gm-row { display: flex; gap: 10px; align-items: center; margin-bottom: 8px; }
.gm-row #gmPlayerSearch { flex: 1; }
.gm-row label { color: #9fb0d0; font-size: 13px; display: flex; align-items: center; gap: 6px; }
.gm-row #gmQty, .gm-row #gmLevel { width: 56px; }
.gm-row #gmItemSearch, .gm-row #gmMonSearch { flex: 1; }
#gmModal input { background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #cdd6ea; padding: 8px 10px; font-size: 14px; }
#gmPlayerSearch { width: 100%; box-sizing: border-box; margin-bottom: 10px; }
/* Item / Pokémon tabs — both give flows share the player search above them. */
/* ⚡ Turbo (QA/GM fast lane — field.js turboButton): the tester panel's row and the GM header chip */
.turbo-toggle.on { background: #3a300c !important; border-color: #ffd60a !important; color: #ffd60a !important; }
.box-card h2 .turbo-toggle { margin-left: auto; margin-right: 8px; font-size: 13px; border: 1px solid #44507a; border-radius: 8px; padding: 4px 10px; }
.gm-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.gm-tab {
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #9fb0d0; padding: 6px 16px; cursor: pointer; font-size: 13px; font-weight: 600;
}
.gm-tab.selected { border-color: #ffd60a; background: #232f4e; color: #fff; }
#gmMonSearch { width: 100%; box-sizing: border-box; margin-bottom: 10px; }

/* ---------- bag pockets ---------- */
.bag-tabs {
  display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px;
  position: sticky; top: 0; background: inherit; z-index: 1;
}
.bag-tab {
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #9fb0d0; padding: 5px 11px; cursor: pointer; font-size: 12px; font-weight: 600;
}
.bag-tab.selected { border-color: #ffd60a; background: #232f4e; color: #fff; }
.bag-items { display: flex; flex-direction: column; max-height: 56vh; overflow-y: auto; }
/* per-Pokémon customize form (nature/ability/IVs/EVs/level) */
#gmModal select { background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #cdd6ea; padding: 7px 8px; font-size: 13px; }
.gm-detail-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.gm-detail-head img { width: 40px; height: 40px; image-rendering: pixelated; }
.gm-detail-head button { margin-left: auto; }
.gm-detail-head .dexno { color: #9fb0d0; font-size: 12px; }
.gm-row .gm-grow { flex: 1; }
.gm-row .gm-grow select { flex: 1; }
.gm-fixed { color: #6f7fa0; font-style: italic; }
.gm-statgrid { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; flex-wrap: wrap; }
.gm-statlbl { color: #9fb0d0; font-size: 12px; width: 28px; }
.gm-statgrid label { display: flex; flex-direction: column; align-items: center; gap: 2px;
  color: #9fb0d0; font-size: 10px; }
.gm-statgrid input { width: 42px; text-align: center; }
.gm-mini { background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px; color: #cdd6ea;
  padding: 6px 10px; cursor: pointer; font-size: 12px; align-self: flex-end; }
.gm-mini:hover { border-color: #ffd60a; }
.gm-give-btn { width: 100%; padding: 10px; margin-top: 6px; border: none; border-radius: 8px;
  background: #ffd60a; color: #1a1f2e; font-weight: 700; cursor: pointer; font-size: 14px; }
.gm-give-btn:hover { background: #ffe14d; }
.gm-players { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; min-height: 22px; }
.gm-players .gm-chip {
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 14px;
  color: #cdd6ea; padding: 4px 12px; cursor: pointer; font-size: 13px;
}
.gm-players .gm-chip.selected { border-color: #ffd60a; background: #232f4e; color: #fff; }
.gm-empty { color: #9fb0d0; font-style: italic; font-size: 13px; }
.gm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 6px; }
.gm-item {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #cdd6ea; padding: 8px 4px; cursor: pointer; text-align: center; font-size: 11px;
}
.gm-item:hover { border-color: #ffd60a; background: #232f4e; }
.gm-item .gm-icon { width: 32px; height: 32px; image-rendering: pixelated; }
.gm-item .gm-emoji { font-size: 26px; line-height: 32px; }
/* read-only inspector pane */
#gmInspectPane { max-height: 56vh; overflow-y: auto; }
.gm-inspect-head { display: flex; flex-direction: column; gap: 2px; margin-bottom: 8px; }
.gm-inspect-head strong { color: #fff; font-size: 16px; }
.gm-section-title { color: #ffd60a; font-size: 13px; margin: 12px 0 6px; font-weight: 700; }
.gm-party-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 6px; }
.gm-partymon { display: flex; align-items: center; gap: 8px; background: #0e1626;
  border: 1px solid #3b4a6b; border-radius: 8px; padding: 6px 8px; }
.gm-partymon .gm-icon { width: 40px; height: 40px; image-rendering: pixelated; flex: 0 0 auto; }
.gm-mon-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.gm-mon-info strong { color: #fff; font-size: 13px; }
.gm-mon-sub { color: #9fb0d0; font-size: 11px; }
.gm-box-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 4px; }
.gm-boxmon { display: flex; align-items: center; gap: 6px; background: #0e1626;
  border: 1px solid #2b3a59; border-radius: 6px; padding: 4px 6px; }
.gm-boxmon .gm-icon { width: 28px; height: 28px; image-rendering: pixelated; flex: 0 0 auto; }
.gm-bag-list { display: flex; flex-direction: column; gap: 3px; }
.gm-bag-row { display: flex; align-items: center; gap: 8px; background: #0e1626;
  border: 1px solid #2b3a59; border-radius: 6px; padding: 4px 8px; }
.gm-bag-row .gm-icon { width: 24px; height: 24px; image-rendering: pixelated; }
.gm-bag-row .gm-emoji { font-size: 20px; line-height: 24px; }
.gm-bag-name { color: #cdd6ea; font-size: 13px; flex: 1; }
.gm-bag-qty { color: #ffd60a; font-size: 13px; font-weight: 700; }
#towerStartBtn {
  width: 100%; padding: 10px; margin-top: 8px; border: none; border-radius: 8px;
  background: #ffd60a; font-weight: 700; cursor: pointer;
}
.box-card.wide { width: 760px; }
.box-card h2 button { background: none; border: none; color: #fff; font-size: 18px; cursor: pointer; }
.modal-sub { font-size: 14px; color: #9fb0d0; font-weight: 400; align-self: center; flex: 1; text-align: right; margin-right: 12px; }
/* ---------- Pokédex (js/dex.js) ----------
   A master-detail panel in the app's own palette: list left, detail right on
   a wide window (#dexPanes --dex-panes:2 — the JS reads this custom property
   instead of guessing breakpoints), stacked + swapped on phones. Per-type
   colours live on :root so the mon card's .dex-type pills share them. */
:root {
  --type-normal: #d8d0c0; --type-fire: #ff9a3c; --type-water: #4aa8ff; --type-electric: #ffe45c;
  --type-grass: #5fd35f; --type-ice: #9fe2ff; --type-fighting: #d65a45; --type-poison: #a55fd3;
  --type-ground: #d3b35f; --type-flying: #a8c4e8; --type-psychic: #ff6bd3; --type-bug: #b3d35f;
  --type-rock: #bfae94; --type-ghost: #7b6bd3; --type-dragon: #7b8cff; --type-dark: #6b5f70; --type-steel: #c4c4d3;
  --dex-ink: #e8ecf6; --dex-mute: #9fb0d0; --dex-line: #3b4a6b; --dex-well: #0e1626; --dex-accent: #ffd60a;
}
.dex-type { font-size: 11px; padding: 2px 9px; border-radius: 10px; background: #2a3550; color: #cdd6f4; letter-spacing: .5px; font-weight: 700; }
.dex-type.t-normal { background: var(--type-normal); color: #1a1a1a; }
.dex-type.t-fire { background: var(--type-fire); color: #2a1200; }
.dex-type.t-water { background: var(--type-water); color: #061a33; }
.dex-type.t-electric { background: var(--type-electric); color: #2a2200; }
.dex-type.t-grass { background: var(--type-grass); color: #0a2a0a; }
.dex-type.t-ice { background: var(--type-ice); color: #05263a; }
.dex-type.t-fighting { background: var(--type-fighting); color: #fff; }
.dex-type.t-poison { background: var(--type-poison); color: #fff; }
.dex-type.t-ground { background: var(--type-ground); color: #2a2000; }
.dex-type.t-flying { background: var(--type-flying); color: #0f1f3a; }
.dex-type.t-psychic { background: var(--type-psychic); color: #3a0028; }
.dex-type.t-bug { background: var(--type-bug); color: #1e2a00; }
.dex-type.t-rock { background: var(--type-rock); color: #2a2010; }
.dex-type.t-ghost { background: var(--type-ghost); color: #fff; }
.dex-type.t-dragon { background: var(--type-dragon); color: #fff; }
.dex-type.t-dark { background: var(--type-dark); color: #fff; }
.dex-type.t-steel { background: var(--type-steel); color: #1a1a2a; }

.box-card.dex-card {
  width: min(1040px, 96vw); height: min(760px, 90vh);
  display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden; padding: 16px 18px;
}
.box-card.dex-card h2 { margin-bottom: 8px; }
#dexTop { flex: none; }
#dexTabs { display: flex; gap: 6px; margin-bottom: 8px; }
.dex-tab {
  display: flex; align-items: baseline; gap: 6px; padding: 6px 12px; border-radius: 999px;
  background: var(--dex-well); border: 1px solid var(--dex-line); color: var(--dex-mute);
  font-family: inherit; font-size: 13px; cursor: pointer; transition: background .15s, color .15s, border-color .15s;
}
.dex-tab small { font-size: 10px; color: #6b7a9c; }
.dex-tab.done small { color: #7fd08a; }
.dex-tab:hover { color: var(--dex-ink); border-color: #55679a; }
.dex-tab.on { background: #26335a; color: var(--dex-ink); border-color: var(--dex-accent); }
#dexProgress { margin-bottom: 8px; }
.dex-prog-row { display: flex; justify-content: space-between; align-items: baseline; font-size: 12px; color: var(--dex-mute); margin-bottom: 4px; }
.dex-counts b { color: var(--dex-ink); }
.dex-pct { color: var(--dex-ink); font-weight: 700; }
.dex-complete { color: #1a1400; background: var(--dex-accent); border-radius: 999px; padding: 1px 9px; font-weight: 700; font-size: 11px; }
.dex-bar { height: 6px; background: #2a3450; border-radius: 3px; overflow: hidden; }
.dex-bar-fill { height: 100%; background: linear-gradient(90deg, #4ea8de, #7fd08a); border-radius: 3px; transition: width .4s ease; }
.dex-tier { font-size: 12px; color: var(--dex-mute); margin-top: 6px; line-height: 1.35; }
.dex-tier b { color: var(--dex-accent); font-weight: 600; }
#dexSearchBar { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
#dexSearch {
  flex: 1; min-width: 0; background: var(--dex-well); border: 1px solid var(--dex-line); border-radius: 8px;
  color: var(--dex-ink); padding: 6px 10px; font-size: 16px; font-family: inherit; outline: none;
}
#dexSearch:focus { border-color: var(--dex-accent); }
#dexSearchClear { color: var(--dex-mute); cursor: pointer; padding: 2px 8px; font-size: 15px; }
#dexType, #dexSort { background: var(--dex-well); border: 1px solid var(--dex-line); border-radius: 8px; color: var(--dex-ink); font-family: inherit; font-size: 12px; padding: 6px 5px; }
#dexCaughtOnly { background: var(--dex-well); border: 1px solid var(--dex-line); border-radius: 8px; color: var(--dex-mute); font-size: 14px; padding: 4px 10px; cursor: pointer; }
#dexCaughtOnly.on { color: #1a1400; background: var(--dex-accent); border-color: var(--dex-accent); }
#dexPanes { flex: 1; min-height: 0; display: grid; grid-template-columns: 1fr; gap: 12px; --dex-panes: 1; }
@media (min-width: 900px) and (min-height: 480px) {
  body:not(.touch-pad) #dexPanes { grid-template-columns: 300px 1fr; --dex-panes: 2; }
}
#dexGrid { overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 4px; padding-right: 4px; }
.dexmon {
  display: grid; grid-template-columns: 36px 44px 1fr auto auto; align-items: center; gap: 8px;
  height: 44px; flex: none; padding: 0 10px 0 6px; border-radius: 10px; cursor: pointer;
  background: var(--dex-well); border: 1px solid var(--dex-line); color: var(--dex-ink); font-size: 13px;
  transition: background .15s, border-color .15s;
}
.dexmon:hover { background: #172037; border-color: #55679a; }
.dexmon.selected { background: #1c2542; border-color: var(--dex-accent); }
.dexmon.unseen { opacity: .45; cursor: default; }
.dexmon .dex-icon { width: 32px; height: 32px; image-rendering: pixelated; justify-self: center; }
.dexmon.seen .dex-icon { filter: brightness(0) opacity(.85); }
.dexmon .dexq { width: 32px; height: 32px; line-height: 32px; text-align: center; justify-self: center; font-size: 18px; color: var(--dex-line); font-weight: 700; }
.dexmon .dexno { color: #6b7a9c; font-size: 12px; font-variant-numeric: tabular-nums; }
.dexmon .dex-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dex-dots { display: flex; gap: 3px; }
.dex-dots i { width: 8px; height: 8px; border-radius: 50%; display: block; background: var(--dex-line); }
.dex-dots i.t-normal { background: var(--type-normal); } .dex-dots i.t-fire { background: var(--type-fire); }
.dex-dots i.t-water { background: var(--type-water); } .dex-dots i.t-electric { background: var(--type-electric); }
.dex-dots i.t-grass { background: var(--type-grass); } .dex-dots i.t-ice { background: var(--type-ice); }
.dex-dots i.t-fighting { background: var(--type-fighting); } .dex-dots i.t-poison { background: var(--type-poison); }
.dex-dots i.t-ground { background: var(--type-ground); } .dex-dots i.t-flying { background: var(--type-flying); }
.dex-dots i.t-psychic { background: var(--type-psychic); } .dex-dots i.t-bug { background: var(--type-bug); }
.dex-dots i.t-rock { background: var(--type-rock); } .dex-dots i.t-ghost { background: var(--type-ghost); }
.dex-dots i.t-dragon { background: var(--type-dragon); } .dex-dots i.t-dark { background: var(--type-dark); }
.dex-dots i.t-steel { background: var(--type-steel); }
/* caught = a filled ball, seen = an empty ring */
.dex-ball { width: 12px; height: 12px; border-radius: 50%; border: 2px solid #6b7a9c; }
.dex-ball.caught { border-color: #e2513f; background: linear-gradient(180deg, #e2513f 50%, #fff 50%); box-shadow: inset 0 0 0 1px #2a1a1a; }

/* ---- detail pane ---- */
#dexDetail { overflow-y: auto; min-height: 0; border-radius: 12px; background: var(--dex-well); border: 1px solid var(--dex-line); padding: 14px 16px; }
@keyframes dexSlideIn { from { transform: translateX(28px); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes dexFade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
#dexDetail.dex-in { animation: dexSlideIn .22s ease-out; }
#dexDetail .dex-body { animation: dexFade .18s ease-out; }
@media (prefers-reduced-motion: reduce) { #dexDetail.dex-in, #dexDetail .dex-body, .dex-bar-fill { animation: none; transition: none; } }
.dex-empty { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; color: var(--dex-mute); }
.dex-empty-ball { width: 56px; height: 56px; border-radius: 50%; border: 3px solid #2a3450; background: linear-gradient(180deg, #2a3450 50%, #1a2238 50%); }
.dex-hero {
  display: flex; align-items: center; gap: 16px; padding: 12px 14px; border-radius: 12px; margin-bottom: 10px;
  background: #111a2e;
  background: linear-gradient(120deg, color-mix(in srgb, var(--t1) 22%, #111a2e), color-mix(in srgb, var(--t2) 14%, #111a2e));
  border: 1px solid color-mix(in srgb, var(--t1) 35%, var(--dex-line));
}
.dex-hero-pic { position: relative; flex: none; width: 192px; height: 192px; display: flex; align-items: center; justify-content: center; }
/* object-fit: the public-mode animated set's GIFs are bbox-cropped, not 96x96 frames — never stretch them */
.dex-hero-sprite { width: 192px; height: 192px; image-rendering: pixelated; object-fit: contain; filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .45)); }
@media (max-height: 860px) { .dex-hero-pic, .dex-hero-sprite { width: 144px; height: 144px; } }
.dex-card.detail-open #dexTop { display: none; }
.dex-hero-sprite.silhouette { filter: brightness(0) opacity(.9); }
.dex-foot { position: absolute; right: 0; bottom: 0; width: 28px; height: 28px; background: var(--dex-ink); opacity: .85;
  -webkit-mask: var(--fp) center / contain no-repeat; mask: var(--fp) center / contain no-repeat; }
.dex-foot-probe { display: none; }
.dex-hero.nofoot .dex-foot { display: none; }
.dex-hero-id { min-width: 0; flex: 1; }
.dex-hero-id h3 { margin: 0 0 2px; font-size: 22px; letter-spacing: .3px; }
.dex-cat { color: var(--dex-mute); font-size: 13px; margin-bottom: 8px; }
.dex-hero-id .dex-detail-types { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.dex-chip { font-size: 11px; padding: 2px 9px; border-radius: 10px; background: #26335a; color: var(--dex-ink); border: 1px solid #3b4a6b; white-space: nowrap; }
.dex-hero-actions { display: flex; gap: 6px; margin-top: 10px; }
.dex-hero-actions button { padding: 5px 12px; border-radius: 8px; font-size: 12px; background: #1a2238; border: 1px solid var(--dex-line); color: var(--dex-ink); cursor: pointer; }
.dex-hero-actions button:hover { border-color: #55679a; }
.dex-hero-actions button.on { border-color: var(--dex-accent); color: var(--dex-accent); }
.dex-hero-note { margin-top: 10px; font-size: 12px; color: var(--dex-mute); font-style: italic; }
.dex-vtabs { display: flex; gap: 4px; margin-bottom: 10px; border-bottom: 1px solid var(--dex-line); }
.dex-vtab { padding: 7px 12px; background: none; border: none; border-bottom: 2px solid transparent; color: var(--dex-mute); font-family: inherit; font-size: 13px; cursor: pointer; transition: color .15s, border-color .15s; }
.dex-vtab:hover:not(:disabled) { color: var(--dex-ink); }
.dex-vtab.on { color: var(--dex-ink); border-bottom-color: var(--dex-accent); }
.dex-vtab:disabled { opacity: .35; cursor: default; }
.dex-body h4 { margin: 12px 0 6px; color: #9fb3d8; font-size: 12px; text-transform: uppercase; letter-spacing: .6px; }
.dex-body h4:first-child { margin-top: 0; }
.dex-desc { font-size: 14px; line-height: 1.55; color: var(--dex-ink); margin-bottom: 8px; }
.dex-games { display: flex; gap: 4px; margin-bottom: 12px; }
.dex-game { padding: 3px 10px; border-radius: 999px; background: #1a2238; border: 1px solid var(--dex-line); color: var(--dex-mute); font-family: inherit; font-size: 11px; cursor: pointer; }
.dex-game.on { color: var(--dex-ink); border-color: var(--dex-accent); }
.dex-facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 6px 14px; font-size: 13px; }
.dex-facts > div { display: flex; justify-content: space-between; gap: 8px; padding: 6px 0; border-bottom: 1px solid rgba(255, 255, 255, .06); }
.dex-facts b { color: #9fb3d8; font-weight: 600; }
.dex-facts span { text-align: right; display: flex; gap: 4px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.dex-swatch { width: 12px; height: 12px; border-radius: 3px; display: inline-block; margin-right: 4px; border: 1px solid rgba(255, 255, 255, .25); }
.dex-swatch.c-red { background: #e04040; } .dex-swatch.c-blue { background: #4a7fe0; } .dex-swatch.c-yellow { background: #f0d040; }
.dex-swatch.c-green { background: #4cb85a; } .dex-swatch.c-black { background: #202020; } .dex-swatch.c-brown { background: #9a6a3a; }
.dex-swatch.c-purple { background: #9a5ad0; } .dex-swatch.c-gray { background: #8a8a94; } .dex-swatch.c-white { background: #f4f4f4; }
.dex-swatch.c-pink { background: #f08ab8; }
.dex-stats { margin-bottom: 12px; }
.dex-statrow { display: grid; grid-template-columns: 62px 34px 1fr; align-items: center; gap: 8px; font-size: 13px; padding: 3px 0; }
.dex-statrow span { color: #9fb3d8; }
.dex-statrow b { text-align: right; font-variant-numeric: tabular-nums; }
.dex-statrow.total { border-top: 1px solid rgba(255, 255, 255, .08); margin-top: 4px; padding-top: 6px; }
.dex-statbar { height: 8px; background: #2a3450; border-radius: 4px; overflow: hidden; }
.dex-statfill { height: 100%; border-radius: 4px; transition: width .35s ease; background: #4ea8de; }
.dex-statfill.low { background: #e06060; } .dex-statfill.mid { background: #e0b060; } .dex-statfill.good { background: #7fd08a; } .dex-statfill.hi { background: #4ea8de; }
.dex-gender-wrap { display: block; min-width: 130px; }
.dex-gender { height: 8px; border-radius: 4px; background: #ff7fb6; overflow: hidden; }
.dex-gender .m { height: 100%; background: #4ea8de; }
.dex-gender-lbl { display: flex; justify-content: space-between; font-size: 11px; color: var(--dex-mute); margin-top: 2px; }
.dex-genderless { color: var(--dex-mute); }
.dex-moves { width: 100%; border-collapse: collapse; font-size: 13px; }
.dex-moves th { text-align: left; color: #9fb3d8; font-weight: 600; font-size: 11px; padding: 2px 6px; }
.dex-moves td { padding: 4px 6px; border-top: 1px solid rgba(255, 255, 255, .06); }
.dex-moves td.lv, .dex-moves td.num { color: var(--dex-mute); font-variant-numeric: tabular-nums; text-align: right; }
.dex-moves td.lv { text-align: left; width: 34px; }
.dex-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.dex-chip.mv { border-left: 4px solid var(--dex-line); }
.dex-chip.mv b { color: var(--dex-mute); font-weight: 600; margin-right: 3px; }
.dex-chip.mv.t-normal { border-left-color: var(--type-normal); } .dex-chip.mv.t-fire { border-left-color: var(--type-fire); }
.dex-chip.mv.t-water { border-left-color: var(--type-water); } .dex-chip.mv.t-electric { border-left-color: var(--type-electric); }
.dex-chip.mv.t-grass { border-left-color: var(--type-grass); } .dex-chip.mv.t-ice { border-left-color: var(--type-ice); }
.dex-chip.mv.t-fighting { border-left-color: var(--type-fighting); } .dex-chip.mv.t-poison { border-left-color: var(--type-poison); }
.dex-chip.mv.t-ground { border-left-color: var(--type-ground); } .dex-chip.mv.t-flying { border-left-color: var(--type-flying); }
.dex-chip.mv.t-psychic { border-left-color: var(--type-psychic); } .dex-chip.mv.t-bug { border-left-color: var(--type-bug); }
.dex-chip.mv.t-rock { border-left-color: var(--type-rock); } .dex-chip.mv.t-ghost { border-left-color: var(--type-ghost); }
.dex-chip.mv.t-dragon { border-left-color: var(--type-dragon); } .dex-chip.mv.t-dark { border-left-color: var(--type-dark); }
.dex-chip.mv.t-steel { border-left-color: var(--type-steel); }
.dex-evo { display: flex; align-items: center; gap: 10px; padding: 6px 2px; flex-wrap: wrap; }
.dex-evo-col { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; }
.dex-evo-item { display: flex; flex-direction: column; align-items: center; gap: 4px; width: 100px; }
.dex-evo-arrow { font-size: 11px; color: var(--dex-mute); text-align: center; line-height: 1.25; min-height: 14px; }
.dex-evo-arrow::before { content: '→ '; color: var(--dex-accent); }
.dex-evo-node {
  display: flex; flex-direction: column; align-items: center; gap: 2px; width: 92px; padding: 8px 4px; border-radius: 10px;
  background: #1a2238; border: 1px solid var(--dex-line); color: var(--dex-ink); font-family: inherit; font-size: 12px; cursor: pointer;
}
.dex-evo-node img { width: 32px; height: 32px; image-rendering: pixelated; }
.dex-evo-node.seen img { filter: brightness(0) opacity(.85); }
.dex-evo-node.cur { border-color: var(--dex-accent); }
.dex-evo-node.unseen { cursor: default; opacity: .5; }
.dex-evo-node .dexq { font-size: 18px; color: var(--dex-line); font-weight: 700; line-height: 32px; }
button.dex-evo-node:hover { border-color: #55679a; }
.dex-loc-region { margin-bottom: 8px; }
.dex-loc-region b { color: var(--dex-accent); }
.dex-loc-region ul { margin: 4px 0 0; padding: 0; list-style: none; }
.dex-loc-region li { display: flex; justify-content: space-between; gap: 10px; padding: 3px 4px; font-size: 13px; border-bottom: 1px solid rgba(255,255,255,.05); }
.dex-loc-region li em { color: #8fa3c8; font-style: normal; font-size: 12px; white-space: nowrap; }
.dex-map-btn { margin-top: 10px; padding: 8px 14px; border-radius: 8px; }
/* the mon card (ui-town.js showMonDetail) shares these */
.dex-detail-head { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; flex-wrap: wrap; }
.dex-detail-sprite { width: 72px; height: 72px; image-rendering: pixelated; object-fit: contain; }
.dex-detail-id h3 { margin: 0 0 6px; }
.dex-detail-types { display: flex; gap: 6px; }
.dex-back { padding: 6px 12px; border-radius: 8px; }
.market-mon {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  padding: 8px 12px; margin-bottom: 6px; font-size: 14px;
}
.market-mon img { width: 40px; height: 40px; image-rendering: pixelated; vertical-align: middle; }
.market-mon button {
  background: #ffd60a; border: none; border-radius: 6px; padding: 4px 10px;
  cursor: pointer; font-weight: 600;
}
.market-mon button.cancel { background: #adb5bd; }
.market-mon .price { color: #80ed99; font-weight: 600; }
.market-mon input {
  width: 90px; padding: 4px 8px; border-radius: 6px; border: 1px solid #3b4a6b;
  background: #1a2238; color: #fff;
}
.guild-row {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  padding: 8px 12px; margin-bottom: 6px; font-size: 14px;
}
.guild-row button {
  background: #80ed99; border: none; border-radius: 6px; padding: 4px 10px;
  cursor: pointer; font-weight: 600; color: #08261a;
}
.guild-row button.leave { background: #ef798a; color: #2b0a12; }
.guild-tag { color: #80ed99; font-weight: 700; }
.guild-dot {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  background: #555f78; margin-right: 6px; vertical-align: middle;
}
.guild-dot.online { background: #80ed99; }
.guild-star { color: #ffd60a; }
.guild-create input {
  padding: 6px 8px; border-radius: 6px; border: 1px solid #3b4a6b;
  background: #1a2238; color: #fff; margin-right: 6px;
}
.guild-create input.tag { width: 64px; text-transform: uppercase; }
.guild-create button {
  background: #ffd60a; border: none; border-radius: 6px; padding: 6px 10px;
  cursor: pointer; font-weight: 600;
}

#lbBoards { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.lb-board h3 { margin-bottom: 6px; font-size: 15px; }
.lb-board table { width: 100%; border-collapse: collapse; font-size: 13px; }
.lb-board td { padding: 3px 6px; border-bottom: 1px solid #232f4e; }
.lb-board td:last-child { text-align: right; color: #80ed99; }
.lb-board tr.me td { background: #2c3a22; color: #ffd60a; font-weight: 700; }


/* ---------- auth ---------- */
.auth-tabs { display: flex; gap: 8px; margin-bottom: 12px; }
.auth-tab {
  flex: 1; padding: 8px; border-radius: 8px; border: 2px solid #3b4a6b;
  background: #0e1626; color: #9fb0d0; cursor: pointer; font-size: 15px;
}
.auth-tab.selected { border-color: #ffd60a; color: #fff; background: #232f4e; }
/* #passInput lives with the title screen at the top of this file */
#logoutBtn { background: #232f4e; color: #fff; border: 1px solid #3b4a6b; border-radius: 8px; padding: 4px 10px; cursor: pointer; }

/* ---------- hint bar / dialog ---------- */
#hintBar {
  position: absolute; bottom: 8px; right: 12px; z-index: 4;
  color: rgba(255,255,255,.55); font-size: 12px; text-shadow: 0 1px 2px #000;
}
/* the originals' FIXED two-line text window: the box never grows with its
   content — #dialogText is a 2-line viewport (see field.js: extra lines
   scroll in one at a time, "\n\n" turns the page) */
#dialog {
  position: absolute; left: 50%; transform: translateX(-50%);
  bottom: 48px; width: 640px; max-width: 92vw; z-index: 18;
  background: #f8f8f8; color: #222; border: 3px solid #3b4a6b; border-radius: 10px;
  padding: 12px 20px; font-size: 19px; line-height: 27px;
  box-shadow: 0 8px 24px rgba(0,0,0,.5);
}
#dialogText { height: 54px; overflow: hidden; white-space: pre; padding-right: 22px; }
.dlg-inner { will-change: transform; }
/* the ▼ sits in the box's corner like the GBA's and blinks while it waits */
.dialog-hint { position: absolute; right: 11px; bottom: 7px; color: #666; font-size: 13px; line-height: 1; animation: dlgBlink 1s steps(2, start) infinite; }
@keyframes dlgBlink { 50% { opacity: 0; } }
#dialog.typing .dialog-hint { visibility: hidden; } /* the ▼ waits for the text crawl */
/* a scene's verticalmenu (Crystal's loadmenu over the text box — js/field.js
   showSceneMenu): a right-aligned window sitting on the box, rows under the ▶
   cursor; the pad-nav .kbsel row is the cursor row */
.scene-menu {
  position: absolute; right: -3px; bottom: calc(100% + 6px); /* outer edges flush with the box (its 3px border) */
  display: flex; flex-direction: column; align-items: stretch;
  background: #f8f8f8; color: #222; border: 3px solid #3b4a6b; border-radius: 10px;
  padding: 8px 18px 8px 10px; box-shadow: 0 8px 24px rgba(0,0,0,.5);
}
.scene-menu-row {
  all: unset; cursor: pointer; font-size: 19px; line-height: 27px; white-space: pre;
}
.scene-menu-row::before { content: '\25B6'; display: inline-block; width: 1.2em; font-size: 15px; visibility: hidden; }
.scene-menu-row.kbsel::before, .scene-menu-row:hover::before { visibility: visible; }
/* a window at the screen's top-left (BUENA's password words, her prize list —
   menu_coords 0, 0 / 1, 1): the screen's left edge is the text box's */
.scene-menu.scene-menu-topleft {
  position: absolute; left: max(4vw, calc(50% - 320px)); top: 16px; right: auto; bottom: auto; z-index: 19;
  max-height: calc(100% - 200px); overflow-y: auto;
}
/* the side box a script keeps beside its text: PlaceMoneyTopRight's wallet
   (menu_coords 11, 0 — top-right) and BUENA's "Points" balance (0, 11 — left,
   over the text box) */
.scene-aside {
  position: absolute; z-index: 19; background: #f8f8f8; color: #222; border: 3px solid #3b4a6b; border-radius: 10px;
  padding: 6px 14px; font-size: 19px; line-height: 27px; white-space: pre; box-shadow: 0 8px 24px rgba(0,0,0,.5);
}
.scene-aside-money { right: max(4vw, calc(50% - 320px)); top: 16px; }
.scene-aside-points { left: max(4vw, calc(50% - 320px)); bottom: 138px; }

/* braille carvings (the Ruby Path, the Dotted Hole): the cartridge prints
   these with FONT_BRAILLE at speed 0 — one line of 8x16 cells, no crawl. We
   draw the six dots ourselves (2 columns x 3 rows, dot order 1,4 / 2,5 / 3,6)
   so no font is needed; js/field.js brailleCells builds the markup. */
#dialog.braille #dialogText { white-space: normal; display: flex; align-items: center; height: 54px; }
#dialog.braille .dlg-inner { display: flex; flex-wrap: wrap; gap: 2px 6px; }
.bcell {
  display: grid; grid-template-columns: repeat(2, 7px); grid-auto-rows: 7px;
  gap: 2px; align-content: center;
}
.bcell.bspace { grid-template-columns: 16px; }
.bcell i { width: 7px; height: 7px; border-radius: 50%; background: rgba(34,34,34,.14); }
.bcell i.on { background: #222; box-shadow: inset 0 -1px 0 rgba(255,255,255,.35); }
@media (max-width: 700px) {
  .bcell { grid-template-columns: repeat(2, 6px); grid-auto-rows: 6px; }
  .bcell i { width: 6px; height: 6px; }
}

/* ---------- shop / menus ---------- */
.shop-item {
  display: flex; justify-content: space-between; align-items: center;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  padding: 8px 12px; margin-bottom: 6px; font-size: 14px;
}
.shop-item .buy-buttons { display: flex; gap: 6px; }
.shop-item button {
  background: #ffd60a; border: none; border-radius: 6px; padding: 4px 10px;
  cursor: pointer; font-weight: 600;
}
/* the Poké Mart list (js/ui-town.js renderShop): icon · name / "In bag" · price · Buy
   — scoped to #shopList because the bag reuses .shop-item for its own rows */
#shopSearchBar { display: flex; align-items: center; gap: 6px; margin-bottom: 8px; }
#shopSearch {
  flex: 1; min-width: 0; background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #fff; padding: 6px 10px; font-size: 16px; font-family: inherit; outline: none;
}
#shopSearch:focus { border-color: #ffd60a; }
#shopSearchClear { color: #9fb0d0; cursor: pointer; padding: 2px 8px; font-size: 15px; }
#shopList .shop-item { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; gap: 10px; }
#shopList .shop-icon { width: 28px; height: 28px; image-rendering: pixelated; }
#shopList .shop-emoji { font-size: 22px; line-height: 28px; width: 28px; text-align: center; }
#shopList .shop-info { display: flex; flex-direction: column; min-width: 0; }
#shopList .shop-info b { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#shopList .shop-owned { color: #9fb0d0; font-size: 12px; }
#shopList .shop-price { font-weight: 600; white-space: nowrap; }
#shopList .shop-item.cant .shop-price { color: #9fb0d0; }
#shopList .shop-item button:disabled { opacity: .45; cursor: default; }
.box-card.small { width: 340px; text-align: center; padding: 22px; }
.row-buttons { display: flex; gap: 10px; justify-content: center; margin-top: 14px; }
.row-buttons button {
  padding: 10px 22px; border-radius: 8px; border: none; cursor: pointer; font-weight: 700;
}
#challengeAccept { background: #80ed99; }
#challengeDecline { background: #adb5bd; }

#playerMenu {
  position: absolute; z-index: 25; background: #1a2238; border: 2px solid #ffd60a;
  border-radius: 10px; padding: 6px; display: flex; flex-direction: column; gap: 4px;
}
#playerMenu button {
  background: #232f4e; color: #fff; border: 1px solid #3b4a6b; border-radius: 6px;
  padding: 8px 14px; cursor: pointer; font-size: 14px; text-align: left;
}
#playerMenu button:hover { background: #2f3f68; }

#bagMenu {
  position: absolute; bottom: calc(var(--bt-band-h) + 8px); right: 12px; background: #1a2238; border: 2px solid #ffd60a;
  border-radius: 12px; padding: 12px; display: flex; flex-direction: column; gap: 6px; z-index: 25;
  width: 260px;
  max-height: calc(100% - var(--bt-band-h) - 16px); overflow-y: auto; /* see #switchMenu */
}
#bagMenu button {
  padding: 9px; border: 1px solid #3b4a6b; border-radius: 8px; background: #232f4e;
  color: #fff; cursor: pointer; text-align: left; font-size: 14px;
}
#bagMenu button:disabled { opacity: .4; cursor: default; }

/* ---------- trade ---------- */
#tradeModal { position: absolute; inset: 0; z-index: 30; background: rgba(8,12,22,.85); display: flex; align-items: center; justify-content: center; }
.trade-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.trade-offer {
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px; padding: 10px;
  min-height: 64px; font-size: 14px; display: flex; align-items: center; gap: 8px;
}
.trade-offer img { width: 48px; height: 48px; image-rendering: pixelated; }
.trade-mine-mon {
  display: flex; align-items: center; gap: 6px; background: #0e1626; border: 1px solid #3b4a6b;
  border-radius: 8px; padding: 6px 10px; margin-bottom: 4px; cursor: pointer; font-size: 14px;
}
.trade-mine-mon img { width: 32px; height: 32px; image-rendering: pixelated; }
.trade-mine-mon.selected { border-color: #ffd60a; background: #232f4e; }
#tradeConfirm {
  margin-top: 12px; width: 100%; padding: 12px; font-weight: 700; border: none;
  border-radius: 8px; background: #80ed99; cursor: pointer;
}
#tradeConfirm:disabled { opacity: .4; cursor: default; }
#shopModal, #challengeModal { position: absolute; inset: 0; z-index: 30; background: rgba(8,12,22,.85); display: flex; align-items: center; justify-content: center; }

/* ---------- story objective ---------- */
#objectiveBar {
  position: absolute; top: 84px; left: 50%; transform: translateX(-50%);
  z-index: 5; background: rgba(14, 22, 38, .85); border: 1px solid #ffd60a55;
  border-radius: 10px; padding: 5px 14px; font-size: 13px; color: #ffe9a3;
  max-width: 70vw; text-align: center;
}
#chatLog .whisper { color: #c8b6ff; font-style: italic; }
#chatLog .partychat { color: #ffb86b; }
#chatLog .localchat { color: #8fe3a0; }
#crewPanel {
  position: absolute; right: 12px; bottom: 120px; min-width: 150px;
  background: rgba(16, 20, 31, 0.92); border: 1px solid #3a4a6b; border-radius: 8px;
  padding: 8px 10px; font-size: 13px; color: #dce6ff; z-index: 5;
}
#crewPanel .crew-row { padding: 2px 0 2px 14px; position: relative; }
/* voice-state dot at the left of a party member's row */
#crewPanel .crew-row.voice-connected::before,
#crewPanel .crew-row.voice-speaking::before,
#crewPanel .crew-row.voice-self::before {
  content: ''; position: absolute; left: 2px; top: 50%; transform: translateY(-50%);
  width: 7px; height: 7px; border-radius: 50%; background: #4a6b8a;
}
#crewPanel .crew-row.voice-self::before { background: #7fd0ff; }
#crewPanel .crew-row.voice-connected::before { background: #4ad991; }
#crewPanel .crew-row.voice-speaking::before { background: #6bff9f; box-shadow: 0 0 6px 2px #6bff9f88; animation: voicePulse .5s infinite alternate; }
@keyframes voicePulse { from { box-shadow: 0 0 3px 1px #6bff9f66; } to { box-shadow: 0 0 8px 3px #6bff9fbb; } }
#crewPanel .crew-hint { color: #8fa3c8; font-size: 11px; margin: 4px 0; }
#crewPanel button { width: 100%; margin-top: 4px; font-size: 12px; }
#crewPanel .crew-voice { display: flex; gap: 4px; margin-top: 6px; }
#crewPanel .crew-voice button { margin-top: 0; }
#crewPanel .crew-voice-btn.on { background: #1f6b4a; border-color: #4ad991; }
#crewPanel .crew-voice-btn.muted { background: #6b2f2f; border-color: #d97f7f; }
/* per-member local voice mute (🔈/🔇) at the right of a party row */
#crewPanel .crew-row { display: flex; align-items: center; gap: 6px; }
#crewPanel .crew-row span { flex: 1; }
#crewPanel .crew-row .crew-peer-mute {
  width: auto; margin: 0; padding: 0 4px; font-size: 12px; line-height: 18px;
  background: transparent; border: 1px solid transparent; border-radius: 6px; cursor: pointer;
}
#crewPanel .crew-row .crew-peer-mute:hover { border-color: #3a4a6b; background: #232f4e; }
#crewPanel .crew-row .crew-peer-mute.muted { background: #6b2f2f55; border-color: #d97f7f88; }

/* ---------- audio settings panel (the ⚙ next to the mute button) ---------- */
#audioPanel {
  position: absolute; top: 52px; right: 12px; z-index: 25; min-width: 240px;
  background: rgba(16, 20, 31, 0.95); border: 1px solid #3a4a6b; border-radius: 10px;
  padding: 10px 12px; font-size: 13px; color: #dce6ff;
}
#audioPanel .audio-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
#audioPanel .audio-close {
  background: transparent; border: none; color: #8fa3c8; font-size: 14px;
  cursor: pointer; padding: 0 2px;
}
#audioPanel .audio-close:hover { color: #fff; }
#audioPanel .audio-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; }
#audioPanel .audio-name { width: 92px; white-space: nowrap; }
#audioPanel .audio-row input[type="range"] { flex: 1; accent-color: #ffd60a; }
#audioPanel .audio-mute {
  background: none; border: none; cursor: pointer; font-size: 14px;
  padding: 0 4px 0 0; color: inherit;
}
#audioPanel .audio-val { width: 28px; text-align: right; color: #8fa3c8; font-variant-numeric: tabular-nums; }
#audioPanel .audio-hint { color: #8fa3c8; font-size: 11px; margin-top: 6px; }

/* ---------- controls panel (the ⌨ next to the ⚙, desktop keybinds) ---------- */
#keysPanel {
  position: absolute; top: 52px; right: 12px; z-index: 25; min-width: 300px;
  max-height: 72vh; overflow-y: auto;
  background: rgba(16, 20, 31, 0.95); border: 1px solid #3a4a6b; border-radius: 10px;
  padding: 10px 12px; font-size: 13px; color: #dce6ff;
}
#keysPanel .audio-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
#keysPanel .audio-close {
  background: transparent; border: none; color: #8fa3c8; font-size: 14px;
  cursor: pointer; padding: 0 2px;
}
#keysPanel .audio-close:hover { color: #fff; }
#keysPanel .audio-hint { color: #8fa3c8; font-size: 11px; margin-top: 6px; }
#keysPanel .keys-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
#keysPanel .keys-name { flex: 1; white-space: nowrap; }
#keysPanel .keys-chip {
  min-width: 72px; text-align: center; padding: 1px 8px; border-radius: 6px;
  background: #232f4e; border: 1px solid #3a4a6b; font-variant-numeric: tabular-nums; white-space: nowrap;
}
#keysPanel .keys-rebind {
  width: auto; margin: 0; padding: 2px 8px; font-size: 12px; cursor: pointer;
  background: #232f4e; border: 1px solid #3a4a6b; border-radius: 6px; color: #dce6ff;
}
#keysPanel .keys-rebind:hover { border-color: #8fa3c8; }
#keysPanel .keys-rebind.armed { background: #6b5a2f55; border-color: #ffd60a; color: #ffd60a; }
#keysPanel .keys-foot { margin-top: 8px; text-align: right; }
#keysPanel .keys-foot button {
  width: auto; padding: 3px 10px; font-size: 12px; cursor: pointer;
  background: #232f4e; border: 1px solid #3a4a6b; border-radius: 6px; color: #dce6ff;
}
#keysPanel .keys-foot button:hover { border-color: #8fa3c8; }

/* ---------- display panel (the 🖥 next to the ⌨, render resolution) ---------- */
#displayPanel {
  position: absolute; top: 52px; right: 12px; z-index: 25; min-width: 240px;
  background: rgba(16, 20, 31, 0.95); border: 1px solid #3a4a6b; border-radius: 10px;
  padding: 10px 12px; font-size: 13px; color: #dce6ff;
}
#displayPanel .audio-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
#displayPanel .audio-close {
  background: transparent; border: none; color: #8fa3c8; font-size: 14px;
  cursor: pointer; padding: 0 2px;
}
#displayPanel .audio-close:hover { color: #fff; }
#displayPanel .audio-hint { color: #8fa3c8; font-size: 11px; margin-top: 6px; }
#displayPanel .display-row {
  display: block; width: 100%; margin: 2px 0; padding: 4px 8px; text-align: left;
  font-size: 13px; cursor: pointer; color: #dce6ff;
  background: #232f4e; border: 1px solid #3a4a6b; border-radius: 6px;
}
#displayPanel .display-row:hover { border-color: #8fa3c8; }
#displayPanel .display-row.on { border-color: #ffd60a; color: #ffd60a; background: #6b5a2f55; }

/* A fixed Display resolution: the backing store is the preset; the CSS box
   still fills the window and object-fit letterboxes the content, black bars
   on the mismatched axis. Pointer math maps through the same rect
   (render.js canvasPt). */
#canvas.fixed-res { object-fit: contain; background: #000; }
#chatLog .guild { color: #80ed99; }
#chatLog .guild .from { color: #4cd97b; }
.friend-add-row { display: flex; gap: 6px; margin-bottom: 4px; }
.friend-add-row input { flex: 1; }
.friend-row { display: flex; align-items: center; gap: 8px; padding: 4px 2px; border-bottom: 1px solid #232c44; }
.friend-row .friend-name { flex: 1; }
.friend-row .dot { width: 9px; height: 9px; border-radius: 50%; background: #4a5677; display: inline-block; }
.friend-row .dot.on { background: #4cd97b; box-shadow: 0 0 6px #4cd97b88; }
.friend-row button { font-size: 12px; }
.prof-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.prof-skin { width: 32px; height: 48px; object-fit: none; object-position: 0 0; image-rendering: pixelated; }
.prof-row { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; border-bottom: 1px solid #232c44; font-size: 13px; }
/* trainer-card badge sprites: the authentic 16x16 sheet art at 1.5x —
   owned draws as-is, missing as a black silhouette of the same sprite */
.prof-badges { display: inline-flex; gap: 0; }
.prof-badge { display: inline-block; width: 24px; height: 24px; background-repeat: no-repeat; background-size: 192px 24px; image-rendering: pixelated; cursor: help; }
.prof-badge.off { filter: brightness(0); opacity: 0.75; }
.prof-party { display: flex; gap: 4px; margin-top: 8px; flex-wrap: wrap; }
.prof-mon { position: relative; }
.prof-mon img { width: 40px; height: 40px; image-rendering: pixelated; object-fit: contain; }
.prof-mon small { position: absolute; bottom: -2px; right: 0; background: #1c2335; border-radius: 4px; padding: 0 3px; font-size: 10px; }
/* the Safari Game / Bug-Catching Contest pills sit in the TOP-LEFT corner —
   where FRLG draws its safari stats window (tilemapLeft 1, tilemapTop 1); the
   top-right corner is the six-mon strip's, they used to overlap it */
#safariHud, #contestHud {
  position: absolute; top: 10px; left: 10px; z-index: 5;
  display: flex; align-items: center; gap: 10px; white-space: nowrap;
  background: rgba(20, 34, 18, .9); border: 1px solid #6a8f3f; border-radius: 10px;
  padding: 5px 12px; font-size: 13px; color: #d9f2c0;
}
#safariHudText { line-height: 1.35; }
#safariHud button {
  background: #2c4520; color: #e8f7d6; border: 1px solid #6a8f3f; border-radius: 8px;
  padding: 2px 9px; font-size: 12px; font-family: inherit; cursor: pointer;
}
#safariHud button:hover { background: #3a5a2b; }
.achv-toast {
  position: absolute; top: -90px; left: 50%; transform: translateX(-50%);
  z-index: 40; background: linear-gradient(160deg, #2b2440, #1c2335);
  border: 1px solid #ffd60a; border-radius: 12px; padding: 10px 22px;
  text-align: center; transition: top .5s cubic-bezier(.2,.9,.3,1.2);
  box-shadow: 0 8px 30px rgba(0,0,0,.5);
}
.achv-toast.show { top: 64px; }
.achv-toast b { color: #ffd60a; }
.achv-toast small { color: #9fb0d0; }
.prof-achv { display: flex; gap: 4px; flex-wrap: wrap; font-size: 18px; margin-top: 6px; }
.prof-achv span { cursor: help; }

/* pad/keyboard cursor — battle buttons AND every modal's controls/rows
   (pad-nav): arrows/joystick move · Z/A confirm · X/B back. The yellow
   outline + glow reads on both the dark cards and light button faces. */
.kbsel {
  outline: 3px solid #ffd60a; outline-offset: -3px;
  box-shadow: 0 0 10px rgba(255, 214, 10, .35);
  border-radius: 6px;
}

/* mobile touch pad: an analog JOYSTICK (LEFT, sits ABOVE the chat), A/B +
   Select/Start (RIGHT), created lazily by client.js. The canvas shrinks between
   the two gutters (see body.touch-pad #canvas above; client.js sets --gutter-l/r). */
/* the pad sits ABOVE the START menu / modals / offer overlays (z ≤ 60): with a
   menu open the joystick + A/B keep driving its pad-nav cursor — only the
   rotate-lock curtain (9999) may cover the controls */
#touchUI { position: fixed; inset: 0; z-index: 70; pointer-events: none; }

/* --- D-pad cross (left gutter, raised so the chat sits below it, never
   covered). One pointer surface (#joyBase) — the arms are visual; direction
   comes from the thumb's offset, so sliding across the cross re-steers. --- */
#joyBase {
  /* safe-area insets keep the controls clear of notches / home bars */
  position: absolute; left: calc(14px + env(safe-area-inset-left, 0px)); bottom: 150px;
  width: 184px; height: 184px;
  pointer-events: auto; touch-action: none; user-select: none; -webkit-user-select: none;
}
/* the WHOLE square steers (corner taps snap to the dominant axis) — a faint
   plate under the cross makes that touchable area visible, so thumbs never
   feel like they landed "outside" the pad */
#joyBase::before {
  content: ''; position: absolute; inset: 0; border-radius: 26%;
  background: rgba(18, 26, 48, .30); border: 1px solid rgba(160, 180, 220, .18);
}
#joyBase .dpArm {
  position: absolute; pointer-events: none;
  background: rgba(18, 26, 48, .72); border: 2px solid rgba(160, 180, 220, .5);
  display: flex; align-items: center; justify-content: center;
}
/* FAT arms — 40% thick, ending flush at the 30-70% hub band so the four wings
   plus the static centre fill read as ONE solid plus (no seams, no inner lines) */
#joyBase .dpUp    { left: 30%; width: 40%; top: 0;    height: 30%; border-radius: 12px 12px 0 0; border-bottom: none; }
#joyBase .dpDown  { left: 30%; width: 40%; bottom: 0; height: 30%; border-radius: 0 0 12px 12px; border-top: none; }
#joyBase .dpLeft  { top: 30%;  height: 40%; left: 0;  width: 30%;  border-radius: 12px 0 0 12px; border-right: none; }
#joyBase .dpRight { top: 30%;  height: 40%; right: 0; width: 30%;  border-radius: 0 12px 12px 0; border-left: none; }
/* BIG arrow glyphs (CSS triangles) so each wing reads as a button */
#joyBase .dpArm::after { content: ''; width: 0; height: 0; }
#joyBase .dpUp::after    { border-left: 12px solid transparent; border-right: 12px solid transparent; border-bottom: 15px solid rgba(205, 218, 248, .6); }
#joyBase .dpDown::after  { border-left: 12px solid transparent; border-right: 12px solid transparent; border-top: 15px solid rgba(205, 218, 248, .6); }
#joyBase .dpLeft::after  { border-top: 12px solid transparent; border-bottom: 12px solid transparent; border-right: 15px solid rgba(205, 218, 248, .6); }
#joyBase .dpRight::after { border-top: 12px solid transparent; border-bottom: 12px solid transparent; border-left: 15px solid rgba(205, 218, 248, .6); }
#joyBase[data-dir="up"] .dpUp, #joyBase[data-dir="down"] .dpDown,
#joyBase[data-dir="left"] .dpLeft, #joyBase[data-dir="right"] .dpRight {
  background: rgba(90, 120, 190, .9);
}
#joyBase[data-dir="up"] .dpUp::after { border-bottom-color: #eaf1ff; }
#joyBase[data-dir="down"] .dpDown::after { border-top-color: #eaf1ff; }
#joyBase[data-dir="left"] .dpLeft::after { border-right-color: #eaf1ff; }
#joyBase[data-dir="right"] .dpRight::after { border-left-color: #eaf1ff; }
#joyKnob { /* STATIC centre fill — completes the plus, never moves, no dimple */
  position: absolute; inset: 30%;
  background: rgba(18, 26, 48, .72); border: none;
  pointer-events: none;
}

/* on touch devices the top navbar shrinks to just the info labels — every
   action moves into the START menu (client.js), so the bar stays tiny. */
/* the top bar is INFO-ONLY everywhere now (player request): region, place,
   clock, weather. Every action lives in the START menu — G / the START pad
   button / the one ☰ button kept for mouse users (hidden on touch, where
   the pad's START opens the same menu). The buttons stay in the DOM: their
   handlers are what the START menu entries forward to. */
#topbar button { display: none; }
#topbar #menuBtn { display: inline-block; }
/* on touch the pad's START button opens the same menu — no ☰ needed */
body.touch-pad #topbar #menuBtn { display: none; }

/* touch layout, landscape: the navbar modals sit INSIDE the canvas strip
   between the control gutters (the #battle overlay precedent) — the D-pad and
   the A/B cluster stay clear, and the card centers in the visible play area.
   The card itself caps to the strip (the Pokédex's 760px "wide" card would
   otherwise span both gutters); tall content already scrolls in the card.
   Portrait keeps the full-width overlay: its strip is a sliver (the rotate
   lock curtains the game there anyway). */
@media (orientation: landscape) {
  body.touch-pad #bagModal, body.touch-pad #dexModal, body.touch-pad #marketModal,
  body.touch-pad #friendsModal, body.touch-pad #guildModal, body.touch-pad #boxModal,
  body.touch-pad #shopModal {
    left: var(--gutter-l, 0); right: var(--gutter-r, 0);
  }
  body.touch-pad #bagModal .box-card, body.touch-pad #dexModal .box-card,
  body.touch-pad #marketModal .box-card, body.touch-pad #friendsModal .box-card,
  body.touch-pad #guildModal .box-card, body.touch-pad #boxModal .box-card,
  body.touch-pad #shopModal .box-card {
    max-width: calc(100% - 12px);
  }
}

/* --- START action menu (mobile) --- */
#startMenu {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(6, 10, 20, .72);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px;
}
#startMenu.hidden { display: none; }
#startMenuGrid,
#startMenuSettingsGrid {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px;
  background: rgba(14, 22, 38, .96); border: 1px solid #3b4a6b; border-radius: 14px;
  padding: 16px; max-width: 92vw;
}
#startMenuGrid button,
#startMenuSettingsGrid button {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  min-width: 82px; padding: 10px 8px; border-radius: 12px;
  border: 1px solid #3b4a6b; background: rgba(24, 34, 60, .92); color: #dfe8ff;
  font-family: inherit; font-size: 12px; cursor: pointer; touch-action: manipulation;
}
#startMenuGrid .smIcon,
#startMenuSettingsGrid .smIcon { font-size: 24px; line-height: 1; }
#startMenuGrid button:active,
#startMenuSettingsGrid button:active { background: rgba(70, 100, 170, .85); }
#startMenuClose {
  padding: 10px 30px; border-radius: 12px; border: 1px solid #3b4a6b;
  background: rgba(24, 34, 60, .92); color: #dfe8ff; font-family: inherit; font-size: 14px; cursor: pointer;
}

/* the chat sits compact at the very bottom-left, clearing the joystick above it */
body.touch-pad #chat { width: 240px; left: calc(10px + env(safe-area-inset-left, 0px)); bottom: calc(8px + env(safe-area-inset-bottom, 0px)); }
/* the tab strip must not grow the chat's footprint upward into the play
   area (mobile-responsive guards the canvas center third): denser tabs and
   a log shortened by the strip's height keep the total rect where it was */
body.touch-pad #chatTabs .chattab { font-size: 10px; padding: 1px 7px 2px; }
body.touch-pad #chatLog { height: 74px; }

/* --- action buttons (right gutter) --- */
#touchButtons {
  position: absolute; right: calc(14px + env(safe-area-inset-right, 0px));
  bottom: calc(24px + env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; align-items: flex-end; gap: 16px;
  pointer-events: auto;
}
#touchButtons button {
  touch-action: none; user-select: none; -webkit-user-select: none;
  border: 2px solid rgba(160, 180, 220, .5); background: rgba(18, 26, 48, .62);
  color: #dfe8ff; font-weight: 700; font-family: inherit; cursor: pointer;
}
#touchButtons button:active { background: rgba(70, 100, 170, .8); }
#abCluster { display: flex; align-items: flex-end; gap: 14px; }
#padA, #padB { width: 64px; height: 64px; border-radius: 50%; font-size: 22px; }
#padA { margin-bottom: 26px; }
#ssCluster { display: flex; gap: 10px; }
/* ≥44px tall so the pills are honest touch targets, not decorations */
#padSelect, #padStart { height: 44px; border-radius: 22px; padding: 0 16px; font-size: 11px; min-width: 64px; }

/* ---------- landscape lock (phones held upright) ---------- */
#rotateOverlay {
  position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center;
  background: #0b0f1a; color: #dfe8ff; text-align: center;
}
#rotateOverlay.hidden { display: none; }
#rotateOverlay .rotate-card { padding: 24px 28px; }
#rotateOverlay .rotate-icon { font-size: 52px; animation: rotateHint 1.8s ease-in-out infinite; }
#rotateOverlay p { font-size: 20px; font-weight: 700; margin: 14px 0 4px; }
#rotateOverlay small { color: #9fb0d0; font-size: 13px; }
@keyframes rotateHint { 0%, 60% { transform: rotate(0); } 80%, 100% { transform: rotate(90deg); } }

/* ---------- responsive: small landscape screens (phones) ---------- */
/* Only resize on coarse pointers in landscape; desktop is untouched. The
   #touchUI itself stays visible whenever it's created (JS gates that on touch),
   we only shrink it + the HUD so everything fits a short viewport. */
@media (pointer: coarse) and (max-height: 500px) {
  /* compact navbar */
  #topbar { gap: 5px; padding: 3px 7px; font-size: 11px; top: 5px; border-radius: 9px; }
  #topbar button { padding: 2px 5px; font-size: 11px; }
  #clockLabel { font-size: 9px; }            /* date/time small so it doesn't hog the bar */
  #weatherLabel:not(:empty) { font-size: 9px; }
  #objectiveBar { top: 46px; font-size: 10px; padding: 3px 9px; max-width: 84vw; }
  #safariHud, #contestHud { top: 5px; left: calc(6px + env(safe-area-inset-left, 0px)); font-size: 11px; padding: 3px 9px; gap: 7px; }
  #safariHud button { font-size: 10px; padding: 1px 6px; }
  #chat { width: 40vw; bottom: 6px; }
  #chatLog { max-height: 11vh; }
  #hintBar { display: none; }

  /* party as small thumbnails — compact enough that all 6 fit ABOVE the touch
     buttons in the bottom-right gutter (the last one used to overlap them) */
  #party { width: 108px; gap: 2px; top: 54px; right: 6px; }
  .pmon { padding: 1px 4px; font-size: 10px; gap: 4px; border-radius: 7px; }
  .pmon img, .pmon .eggicon { width: 20px; height: 20px; }
  .pmon .hpbar { height: 3px; }
  .pmon .pinfo > .row1:first-child > span:first-child { display: none; } /* hide the name — keep just Lv */
  .pmon .pinfo > .row1:first-child { justify-content: flex-end; }        /* Lv sits left where the name was */
  .pmon .pinfo > .row1:last-child { display: none; } /* drop the ability/held-item line (it's the last row when present) */
  .pmon .pmoves { width: 16px; height: 16px; font-size: 9px; padding: 0; line-height: 16px; }

  /* touch controls compacted for a short viewport (the D-pad + buttons sit
     in the side gutters; client.js keeps the canvas between them). The pad
     is raised high so a roomier chat tucks underneath it, never covered. */
  #joyBase { width: 148px; height: 148px; left: calc(10px + env(safe-area-inset-left, 0px)); bottom: 158px; }
  body.touch-pad #chat { width: 40vw; bottom: 6px; }
  body.touch-pad #chatLog { height: 15vh; }
  #touchButtons { right: calc(10px + env(safe-area-inset-right, 0px)); bottom: calc(14px + env(safe-area-inset-bottom, 0px)); gap: 10px; }
  #abCluster { gap: 10px; }
  #padA, #padB { width: 52px; height: 52px; font-size: 18px; }
  #padA { margin-bottom: 20px; }
  /* stay ≥40px even compacted — below that a thumb misses the pill */
  #padSelect, #padStart { height: 40px; border-radius: 20px; font-size: 10px; padding: 0 12px; min-width: 56px; }
  .box-card { max-height: 88vh; overflow-y: auto; }
  /* the Pokédex: no fixed height on a phone, the card takes what fits and
     the list/detail scroll inside it */
  body.touch-pad .box-card.dex-card { height: auto; max-height: 88vh; padding: 10px 12px; }
  body.touch-pad .dexmon { height: 40px; }
  body.touch-pad .dex-tier { display: none; }
  body.touch-pad #dexTabs { overflow-x: auto; }
  body.touch-pad .dex-hero-pic, body.touch-pad .dex-hero-sprite { width: 96px; height: 96px; }
  body.touch-pad .dex-hero-id h3 { font-size: 18px; }
  /* the tall list panels (awards / ranks) must fit BETWEEN the pad gutters —
     they used to span ~94vw and sit under the joystick and the A/B cluster
     (player-reported). Width caps to the canvas strip, lists scroll inside. */
  #achvModal .box-card, #lbModal .box-card {
    width: auto; min-width: 300px;
    max-width: calc(100vw - 310px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
    max-height: 80vh;
  }
  #achvList { max-height: 52vh; }

  /* START action menu: smaller, denser tiles so the whole grid stays on a short
     landscape screen (it never runs off the bottom), and scrolls if it must */
  #startMenu { gap: 8px; }
  #startMenuGrid,
  #startMenuSettingsGrid {
    grid-template-columns: repeat(5, 1fr); gap: 6px; padding: 10px;
    max-height: 78vh; overflow-y: auto;
  }
  #startMenuGrid button,
  #startMenuSettingsGrid button { min-width: 58px; padding: 6px 4px; font-size: 10px; gap: 2px; }
  #startMenuGrid .smIcon,
  #startMenuSettingsGrid .smIcon { font-size: 19px; }
  #startMenuClose { padding: 7px 24px; font-size: 12px; }

  /* battle scene sized to the short landscape phone: the arena takes all the
     height the log + move buttons leave (dvh tracks the collapsing address
     bar), and the plates keep the gen3 diagonal so they can never collide */
  #battle { gap: 6px; --bt-band-h: 128px; }
  #battleArena { height: clamp(140px, calc(100dvh - var(--bt-band-h) - 26px), var(--bt-arena-h)); }
  .combatant.foe .plate { top: 10px; left: 10px; }
  .combatant.mine .plate { right: 10px; bottom: 10px; }
  .plate { width: 170px; padding: 5px 9px 6px; }
  .combatant.mine .plate { width: 180px; }
  .plate-top { font-size: 12px; }
  #battleArena .combatant .plate img.ballrow-ball { width: 11px; height: 11px; margin: 0 0 0 1px; }
  #battleBand { padding: 4px 6px; }
  #battleLog { font-size: 13px; line-height: 1.4; padding: 5px 10px; }
  /* no ticker row: two move rows + the three meta buttons share the 128px band */
  #battleActions { grid-template-columns: 1fr 84px; grid-template-rows: minmax(0, 1fr); column-gap: 5px; }
  #moveButtons button .mv-pwr { display: none; }
  #battleTicker { display: none; }
  #moveButtons { gap: 4px; }
  #moveButtons button { min-height: 40px; font-size: 12px; padding: 3px 6px 3px 8px; }
  #moveButtons button .mv-meta { font-size: 10px; }
  #moveButtons button small { font-size: 9px; }
  #metaButtons { gap: 4px; }
  #metaButtons button { font-size: 10px; padding: 0 6px; min-height: 0; }

  /* the battle overlay shrinks to the CANVAS area (between the control gutters)
     so the joystick + A/B buttons stay visible beside it and you can still fight */
  body.touch-pad #battle { left: var(--gutter-l, 0); right: var(--gutter-r, 0); }
  body.touch-pad #battleFrame { max-width: calc(100vw - var(--gutter-l, 0px) - var(--gutter-r, 0px) - 12px); }
}

/* ---------- responsive: small screens (phones + narrow/short windows) ----------
   One shared fit rule for EVERY modal: all of them wrap their content in a
   .box-card, so capping the card caps the modal. dvh (where supported) tracks
   the browser's collapsing address bar; the vh line is the fallback. */
@media (max-width: 700px), (max-height: 520px) {
  .box-card {
    max-width: 94vw;
    max-height: 86vh;
    max-height: 86dvh;
    overflow-y: auto;
    padding: 12px;
  }
  /* two-column layouts collapse to one so nothing squeezes off the card */
  .box-card.dex-card { width: 94vw; height: 86vh; height: 86dvh; }
  #lbBoards { grid-template-columns: 1fr; }
  .trade-cols { grid-template-columns: 1fr; }
  .mon-moves { columns: 1; }
  #dialog { max-width: 94vw; font-size: 15px; line-height: 21px; padding: 9px 14px; }
  #dialogText { height: 42px; }
  #objectiveBar { max-width: 86vw; }
  .ttl-menu { padding: 12px 12px 14px; }
}

/* PC box: one --pcb-tile rewrite rescales the whole grid, and the info panel
   folds under the grid so the party column and the 6x5 stay side by side */
@media (max-width: 860px), (max-height: 560px) {
  #boxList {
    --pcb-tile: 44px;
    grid-template-columns: auto auto;
    grid-template-areas: "head head" "bulk bulk" "party grid" "info info" "wall wall";
  }
  #pcbParty { width: 116px; }
  #pcbSearch { width: 108px; }
  #pcbName { min-width: 96px; }
}
/* landscape phone (844x390) with the pad mounted: the card must fit the strip
   between the gutters, so the info panel goes and the tiles hit their 40px
   tap-target floor exactly */
@media (max-height: 430px) {
  #boxList { --pcb-tile: 40px; --pcb-gap: 2px; }
  #pcbInfoPanel { display: none; }
  #pcbParty { width: 100px; font-size: 11px; }
  .pcb-pmon img { width: 26px; height: 26px; }
}

/* narrow windows (phone-portrait width): the topbar wraps into a compact grid
   instead of overflowing off-screen, and the battle actions stack. Desktop is
   only affected when the window is genuinely this narrow. */
@media (max-width: 560px) {
  #topbar {
    max-width: 96vw; flex-wrap: wrap; justify-content: center;
    gap: 6px; row-gap: 4px; padding: 6px 10px; font-size: 13px;
  }
  #party { width: 170px; }
  /* battle: arena paddings tighten (the diagonal plate arrangement holds),
     meta buttons drop under the move grid */
  #battle { --bt-band-h: 212px; }
  #battleArena { height: min(var(--bt-arena-h), calc(100vh - var(--bt-band-h) - 60px)); }
  .combatant.foe .plate { top: 12px; left: 10px; }
  .combatant.mine .plate { right: 10px; bottom: 12px; }
  .plate { width: 160px; padding: 6px 9px; }
  .combatant.mine .plate { width: 170px; }
  #battleActions { grid-template-columns: 1fr; grid-template-rows: 16px 1fr 44px; }
  #metaButtons { flex-direction: row; }
  #metaButtons button { padding: 10px 6px; justify-content: center; }
}

/* touch devices: real tap targets + inputs big enough that iOS doesn't zoom
   the page on focus (anything under 16px triggers the auto-zoom) */
@media (pointer: coarse) {
  #chatInput, #gmModal input, #gmModal select, .guild-create input,
  .market-mon input, .friend-add-row input, #nameInput, #passInput { font-size: 16px; }
  .box-card h2 button { min-width: 40px; min-height: 40px; }
  .bag-tab, .auth-tab, .gm-tab { min-height: 40px; }
  .market-mon button, .shop-item button, .guild-row button,
  .mon-actions button, .row-buttons button { min-height: 40px; }
  #pcbTools button, #pcbPager button, .pcb-tab, #pcbBulk button { min-height: 40px; min-width: 40px; }
  #pcbSearch, #pcbSort { font-size: 16px; }
  #moveButtons button, #metaButtons button { min-height: 40px; }
  #switchMenu button, #bagMenu button, #playerMenu button { min-height: 44px; }
}

/* ---------- open Town Map sits above the HUD ---------- */
/* The region map draws on the game canvas; while it's open the canvas is
   raised over the floating HUD (chat z5, navbar z5, party z5) so the map
   layers ABOVE them without hiding anything (player-requested). The touch
   pad (z70) stays on top — it steers the cursor and closes the map. */
body.map-open #canvas { z-index: 10; }

/* ---------- POKéRUS markers (party panel + mon card) ---------- */
/* A live infection wears a tiny purple PKRS chip beside the name; a mon
   that has shaken it off keeps a small smiley (the permanent EV boost). */
.pkrs-badge {
  display: inline-block; font-size: 9px; font-weight: 700; letter-spacing: .5px;
  color: #fff; background: #a05ac8; border-radius: 3px; padding: 0 3px;
  vertical-align: 15%;
}
.pkrs-cured { color: #a05ac8; font-weight: 700; }

/* ---------- roulette (Mauville Game Corner) ---------- */
/* The 12-square betting board: 5 columns — a corner spacer + the 4 Pokémon
   column-bet headers, then each color row = a row-bet button + 4 squares.
   Simple colored cells, no game art. */
#rouletteGrid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; margin: 12px 0; }
.rcell {
  padding: 8px 2px; text-align: center; border-radius: 6px; font-family: inherit;
  border: 1px solid #3b4a6b; background: #232f4e; color: #fff; cursor: pointer; font-size: 15px;
}
.rcell:hover { filter: brightness(1.25); }
.rcell.rhead { font-size: 12px; }
.rcell.rspacer { visibility: hidden; }
.rcell.r-orange { background: #8a5220; }
.rcell.r-green { background: #1e6136; }
.rcell.r-purple { background: #573289; }
.rcell.selected { outline: 2px solid #ffd60a; outline-offset: -2px; }
.rcell.rball { box-shadow: inset 0 0 0 3px #fff; }
.rcell.rwin { box-shadow: inset 0 0 0 3px #ffd60a; }
/* ---------- pokédle minigame (see the Pokédle section in client.js) ---------- */
.pdrow { display: grid; grid-template-columns: 56px repeat(6, 1fr); gap: 4px; margin-top: 4px; align-items: stretch; }
.pdcell {
  border-radius: 6px; min-height: 48px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; font-size: 12px; padding: 2px 1px;
  text-align: center; color: #eef2fb; overflow: hidden;
}
.pdcell.g { background: #2f7d46; }
.pdcell.y { background: #b9942d; }
.pdcell.r { background: #8f3b3b; }
.pdrow.pdhead .pdcell { background: #222a3d; font-weight: 700; min-height: 20px; }
.pdbtn {
  padding: 9px 14px; border-radius: 8px; border: 1px solid #44507a;
  background: #222a3d; color: #e6ecf8; font-size: 14px; cursor: pointer;
}
.pdbtn:hover { filter: brightness(1.2); }
/* ---------- pokéguessr (see the PokéGuessr section in js/ui-town.js) ----------
   The modals themselves are lazily created with inline geometry, so only the
   content classes live here. */
.pgpad { min-width: 46px; padding: 9px 12px; font-size: 16px; line-height: 1; }
/* ---------- cry quiz (see the Cry Quiz section in js/ui-town.js) ---------- */
.cqtype {
  display: inline-block; padding: 2px 9px; border-radius: 10px;
  font-size: 11px; font-weight: 700; color: #14161f; text-transform: uppercase;
}
/* ---------- fame checker (FRLG gossip log) ---------- */
/* Opened from the bag's "Use" — it must PAINT above the bag modal (32). */
#fameModal { z-index: 33; }
#fameList { max-height: 56vh; overflow-y: auto; }
.fame-person {
  display: flex; justify-content: space-between; align-items: center;
  width: 100%; margin-bottom: 4px; padding: 8px 12px; font-size: 14px;
  background: #0e1626; border: 1px solid #3b4a6b; border-radius: 8px;
  color: #fff; cursor: pointer; font-family: inherit; text-align: left;
}
.fame-person:hover { background: #1b2742; }
.fame-person small { color: #9fb0d0; font-weight: 600; }
.fame-entries { margin: 0 0 8px; padding: 2px 4px 0; }
.fame-entry {
  background: rgba(255, 255, 255, .05); border-left: 3px solid #ffd60a;
  border-radius: 6px; padding: 6px 10px; margin-bottom: 4px; font-size: 13px;
}
.fame-entry.locked {
  color: #9fb0d0; font-style: italic; border-left-color: #3b4a6b; opacity: .6;
}

/* ---------- evolution scene (js/evoscene.js) ---------- */
/* the "What? X is evolving!" line has no \p: it stays without the ▼ */
#dialog.evo-hold .dialog-hint { visibility: hidden; }
/* the ROM's battle YES/NO box (YESNOBOX_X_Y: right side, above the text)
   and the move picker (the summary screen's four moves), styled like the
   dialog box they sit over */
.evo-menu {
  position: absolute; z-index: 19;
  background: #f8f8f8; color: #222; border: 3px solid #3b4a6b; border-radius: 10px;
  padding: 8px 14px; font-size: 19px; line-height: 27px;
  box-shadow: 0 8px 24px rgba(0,0,0,.5);
}
#evoYesNo { left: calc(50% + 190px); bottom: 150px; min-width: 96px; }
#evoMoveMenu { left: 50%; transform: translateX(-50%); bottom: 150px; width: 420px; max-width: 90vw; }
.evo-opt { white-space: pre; }
.evo-opt::before { content: '  '; }
.evo-opt.sel::before { content: '▶ '; }
.evo-sub { float: right; color: #666; font-size: 15px; }
@media (max-width: 720px) {
  #evoYesNo { left: auto; right: 6vw; }
}
/* in-battle move learning (js/battle-ui.js playBattleLearn): the same YES/NO
   box and move picker over the battle text box, above the switch menu (25) */
#battle .evo-menu { z-index: 26; }
.battle-learn-menu button.evo-opt {
  display: flex; gap: 14px; width: 100%; text-align: left; background: none; border: 0;
  padding: 0; margin: 0; font: inherit; color: inherit; cursor: pointer;
}
.battle-learn-menu .evo-opt.kbsel { outline: none; box-shadow: none; }
.battle-learn-menu .evo-opt.kbsel::before { content: '▶ '; }
.battle-learn-menu .evo-sub { float: none; margin-left: auto; }

/* a move the mon can't pick right now (Disable / Taunt / Torment) */
.mv-name.mv-blocked { opacity: .45; text-decoration: line-through; }
