/* =================================================================== the window system (docs/menus.md)
   One set of rules for every menu, window and dialog: tokens per form factor, how a window sits on the screen, the
   title bar and its close button, the footer key hints, scroll areas, the focus ring, row heights, the dim under a
   modal window. client/js/winsys.js keeps the keyboard inside the open window. Loaded after style.css / touch.css;
   the feature sheets (jobs.css, pokedex.css, ...) load later and build on these tokens.

   Sizes: the HUD windows (menus, dialog, bag, settings, chat, Players) follow --k (layout.js --ui-scale: 1 at 1280x720,
   1.25 at 1080p, down to 0.8 on phones). The big fixed-size windows (shop, Friend Areas, jobs, Journal, Pokédex, Hall of
   Legends, the personality test) are drawn at their 720p size and zoomed by --wk (--k capped at 1.3; 1 on phones and
   tablets, where they fill the screen): inside them a viewport unit is --zvw / --zvh. */
:root {
  --wk: clamp(0.8, var(--k), 1.3);
  --zvw: calc(100vw / var(--wk)); --zvh: calc(var(--vh) / var(--wk));
  --win-dim: rgba(4, 8, 30, 0.55);                 /* the world under a modal window */
  --win-font: calc(16px * var(--k));               /* body text */
  --win-small: calc(13px * var(--k));              /* notes, subs, hints */
  --win-head: calc(11px * var(--k));               /* titles (the pixel font) */
  --row-h: calc(32px * var(--k));                  /* a cursor row */
  --win-x: calc(30px * var(--k));                  /* the close button */
  --maprow-h: 150px;                               /* the minimap row's height (hud.js sets it): menus start under it */
}
html.touch { --row-h: 48px; --win-x: 44px; }
html.form-phone, html.form-tablet { --wk: 1; }
html.form-phone { --win-font: 16px; --win-small: 13px; --win-head: 10px; }
/* phones (--k 0.8): the pixel-font labels and the body text never fall under 10 / 9 / 15 px */
html.form-phone #dialog .dname, html.form-phone .notice .nbody b, html.form-phone #sos b, html.form-phone .set-gt, html.form-phone .bp-head, html.form-phone #cutscene .cs-name, html.form-phone .tt-head { font-size: 10px; }
html.form-phone .mitem .msub, html.form-phone .keycap { font-size: 9px; }
html.form-phone #dialog, html.form-phone .notice .nbody, html.form-phone #sos, html.form-phone #tooltip, html.form-phone .mitem, html.form-phone #help { font-size: 15px; }
html.form-phone .pmd-menu .mtext, html.form-phone .tt-line, html.form-phone .bp-hint, html.form-phone .set-sub, html.form-phone #settings .set-k { font-size: 13px; }
/* a value: the numeral face, tabular, never broken (fonts.css .num) */
.window .num, .pmd-menu .msub, .bp-grid .cnt, #sos .stime { font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- keyboard: a gold focus ring on every control, the cursor row stays its own highlight ---------- */
.window :is(button, input, select, textarea, [tabindex]):focus-visible, .pmd-menu :is(button, input):focus-visible, .shop-row:focus-visible, .dxcard:focus-visible, .jnote:focus-visible, .lcard2:focus-visible, .sw-row:focus-visible {
  outline: 3px solid var(--gold); outline-offset: 2px; box-shadow: none;
}
.window :is(button, input, select):focus:not(:focus-visible) { outline: none; }
/* the footer line of key hints: "↑↓ select · Enter: go · Esc: close" (the touch sheets say it with their buttons) */
.win-keys { flex: none; padding: 6px 2px 0; font-size: var(--win-small); color: var(--dim); line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.win-keys b { color: #e8ecff; font-weight: 400; }
html.touch .win-keys { display: none; }

/* ---------- the close button: one square in every window's corner, 44 px with touch ---------- */
.win-x, .pmd-menu .mclose, .bp-x, .set-x, .help-x, .sw-x, .jclose, .dxclose, .jb-close, .shop-x, .lclose {
  width: var(--win-x); height: var(--win-x); min-width: 0; min-height: 0; flex: none; padding: 0; margin: 0; border-radius: 6px; border: 2px solid var(--win-border); background: #0c1240; color: #fff;
  font: calc(13px * var(--k)) var(--font); line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; touch-action: manipulation;
}
.sw-x, .bp-x, .set-x { margin-left: auto; }
.pmd-menu .mclose, .help-x { position: absolute; top: 6px; right: 6px; }
.win-x:hover, .pmd-menu .mclose:hover, .bp-x:hover, .set-x:hover, .help-x:hover, .sw-x:hover, .jclose:hover, .dxclose:hover, .jb-close:hover, .shop-x:hover, .lclose:hover { border-color: var(--gold); color: var(--gold); filter: none; }
/* inside a zoomed window the zoom does the scaling */
.jclose, .dxclose, .jb-close, .shop-x, .lclose { width: 36px; height: 36px; font-size: 16px; }
html.touch .jclose, html.touch .dxclose, html.touch .jb-close, html.touch .shop-x, html.touch .lclose { width: 44px; height: 44px; }

/* ---------- the dim under a modal window (fixed windows: a shadow the size of the screen) ---------- */
#settings, html.touch #help, html.touch #bagpanel, html.touch #social, html.touch.form-phone #pcard.open .sdetail, html.touch.form-phone #squad .scard.open + .sdetail {
  box-shadow: 0 0 0 200vmax var(--win-dim), 0 0 0 2px #0a0e30, 0 6px 18px rgba(0, 0, 0, 0.5);
}
body.rom-ui #settings, body.rom-ui #help, body.rom-ui #bagpanel, body.rom-ui .pmd-menu, body.rom-ui #social { box-shadow: none; }
/* the sheets and the centred menus sit above the notices (a notice over them hid their rows); they come back when it closes */
html.touch #bagpanel, .pmd-menu, html.touch #help { z-index: 36; }
html.touch #settings { z-index: 45; }
html.touch #social { z-index: 36; }

/* ---------- PMD cursor menus (ui.js menu): a centred window on every screen with the world dimmed under it (the Square's
   keepers, the gates, the channels, Friend Areas, the Team window's menus...). On the desktop ui.js pins its top once it
   is drawn (.pinned), so a menu that changes height (pages, the search) grows down instead of jumping. Two exceptions on
   the desktop: a menu opened at a point (opts.x / y, .at: the player menu) stays by the pointer, and the bag's own item
   menus (opts.side, .side: Use / Throw / Give, the held item, Throw or Eat) stay a panel at the right, under the minimap
   row, so the floor and the foes stay in view. Long labels end in "…" ---------- */
.pmd-menu { left: 50%; top: 50%; right: auto; transform: translate(-50%, -50%); animation: popc 0.12s ease-out; max-height: calc(var(--vh) - 32px - var(--sat) - var(--sab)); font-size: var(--win-font);
  box-shadow: 0 0 0 200vmax var(--win-dim), 0 0 0 2px #0a0e30, 0 6px 18px rgba(0, 0, 0, 0.5); }
html:not(.touch) .pmd-menu.pinned { transform: translateX(-50%); animation: popx 0.12s ease-out; }
@keyframes popx { from { transform: translateX(-50%) scale(0.97); opacity: 0; } }
html:not(.touch) .pmd-menu.side { z-index: 30; left: auto; right: calc(12px + var(--sar)); top: calc(var(--sat) + 14px + var(--maprow-h)); transform: none; animation: pop 0.12s ease-out;
  max-height: calc(var(--vh) - var(--sat) - 14px - var(--maprow-h) - var(--abar-h) - 24px - var(--sab)); box-shadow: 0 0 0 2px #0a0e30, 0 6px 18px rgba(0, 0, 0, 0.5); }
html:not(.touch) .pmd-menu.at { z-index: 30; transform: none; animation: pop 0.12s ease-out; box-shadow: 0 0 0 2px #0a0e30, 0 6px 18px rgba(0, 0, 0, 0.5); }
.pmd-menu .mtitle { display: flex; align-items: baseline; gap: 10px; font-size: var(--win-head); line-height: 1.35; padding-right: calc(var(--win-x) + 10px); }
.pmd-menu .mtitle > .t:first-child { flex: 1 1 auto; min-width: 0; }
.pmd-menu .mtitle .mpage { float: none; flex: none; margin-left: auto; padding: 0; }
.pmd-menu .mtext { font-size: var(--win-small); line-height: 1.35; }
.pmd-menu .mhint { font-size: var(--win-small); }
.mitem { min-height: var(--row-h); padding-top: 2px; padding-bottom: 2px; }
.mitem .mlabel { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mitem .msub { flex: none; max-width: 45%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pmd-menu .mitems { scroll-padding: 4px 0; }
.pmd-menu .mitems .mitem { scroll-margin: 4px 0; }
/* the desktop footer: the keys (paged menus add "←→ page · F find"); with touch the OK / Back bar is the footer */
.pmd-menu .mkeys { display: block; flex: none; padding: 6px 8px 0 calc(22px * var(--k)); font-size: var(--win-small); color: var(--dim); border-top: 1px solid rgba(201, 210, 255, 0.2); margin-top: 6px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
html.touch .pmd-menu .mkeys { display: none; }
/* touch sheets: the list never shrinks under three rows (the text gives way instead), the title clears the close button */
html.touch .pmd-menu { top: 50% !important; max-height: calc(var(--vh) - 16px - var(--sat) - var(--sab)); }
html.touch .pmd-menu .mitems { flex: 1 1 auto; min-height: calc(3 * var(--row-h)); max-height: none; }
html.touch .pmd-menu .mtext { flex: 0 1 auto; min-height: 0; overflow-y: auto; max-height: calc(4 * 1.35em + 8px); }
html.touch .pmd-menu .mitem { padding-left: 8px; }
html.touch .pmd-menu .mitem .mlabel { white-space: normal; overflow-wrap: anywhere; }
html.touch .pmd-menu .mfoot { padding-top: 8px; border-top: 1px solid rgba(201, 210, 255, 0.2); margin-top: 6px; }
@media (max-height: 420px) {   /* phones held sideways: two text lines, no hint line */
  html.touch .pmd-menu .mtext { max-height: calc(2 * 1.35em + 4px); }
  html.touch .pmd-menu .mhint { display: none; }
  html.touch .pmd-menu .mitems { min-height: calc(2 * var(--row-h)); }
}

/* the bank's digit steppers (ui.js numberInput) */
.dstep { width: calc(26px * var(--k)); height: calc(20px * var(--k)); font-size: calc(10px * var(--k)); }
html.touch .dstep { width: 44px; height: 44px; font-size: 13px; }
/* ---------- notices (ui.js notice): on a short screen (phones held sideways) two of them sit side by side, not off the bottom ---------- */
@media (max-height: 460px) { #notices { left: calc(8px + var(--sal)); right: calc(8px + var(--sar)); transform: none; flex-direction: row; flex-wrap: wrap; justify-content: center; align-items: flex-start; } }
/* ---------- dialog box (ui.js dialog): answers are rows of the same height ---------- */
#dialog .dchoices .mitem { min-height: calc(26px * var(--k)); }
html.touch #dialog .dchoices .mitem { min-height: 44px; }

/* ---------- bag (hud.js bagPanel): a title bar like every window, the hint under the grid ---------- */
.bp-head { font-size: var(--win-head); align-items: center; min-height: var(--win-x); margin-bottom: 8px; padding-bottom: 6px; border-bottom: 1px solid rgba(201, 210, 255, 0.3); }
.bp-hint { font-size: var(--win-small); line-height: 1.35; }
.bp-grid .iname { font-size: calc(12px * var(--k)); }
html.touch .bp-hint { text-align: left; }

/* ---------- settings (hud.js): one row height, a lit footer, never taller than the screen ---------- */
#settings { width: min(calc(1180px * var(--k)), 96vw); max-height: calc(var(--vh) - 24px - var(--sat) - var(--sab)); font-size: calc(15px * var(--k)); display: flex; flex-direction: column; }
#settings .set-head { flex: none; font-size: var(--win-head); min-height: var(--win-x); padding-bottom: 8px; border-bottom: 1px solid rgba(201, 210, 255, 0.3); margin-bottom: 8px; }
#settings .set-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; padding-right: 4px; }
#settings .set-row { min-height: var(--row-h); margin: 4px 0; }
#settings .set-l { font-size: var(--win-font); }
#settings .sbtn { min-height: calc(28px * var(--k)); }
html.touch #settings .sbtn { min-height: 44px; }
#settings .set-sub { font-size: var(--win-small); }
#settings .set-grid { grid-template-columns: repeat(auto-fit, minmax(calc(180px * var(--k)), 1fr)); gap: 4px 18px; }
#settings .set-k { font-size: calc(14px * var(--k)); min-height: calc(24px * var(--k)); }
#settings .set-foot { flex: none; margin-top: 10px; padding-top: 8px; border-top: 1px solid rgba(201, 210, 255, 0.2); font-size: var(--win-small); color: var(--dim); }
#settings .set-foot .win-keys { padding: 0; white-space: normal; flex: 1 1 auto; }
html.touch #settings .set-foot { font-size: 14px; }

/* ---------- help (hud.js renderHelp): a title bar with its close button on every screen ---------- */
#help { font-size: calc(15px * var(--k)); padding-right: calc(var(--win-x) + 18px); }
#help > b { display: inline-block; font-size: var(--win-head); min-height: var(--win-x); line-height: var(--win-x); }
#help .help-x { display: inline-flex; }
#help .hl { margin-right: 0; }

/* ---------- the stats pop-up (hudcards.js: a tap on the player card, a long-press on a squad card): a sheet on phones, the cards never grow into the controls ---------- */
.sdetail .sd-head { display: none; }
html.touch.form-phone #pcard.open .sdetail, html.touch.form-phone #squad .scard.open + .sdetail {
  position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(420px, calc(100vw - 24px - var(--sal) - var(--sar))); max-height: calc(var(--vh) - 24px - var(--sat) - var(--sab)); overflow-y: auto;
  margin: 0; padding: 12px 14px 14px; border: 2px solid var(--win-border); border-radius: 8px; background: linear-gradient(180deg, var(--win-a), var(--win-b)); z-index: 36; font-size: 15px; cursor: pointer;
}
html.touch.form-phone .sdetail .sd-head { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; padding-bottom: 6px; border-bottom: 1px solid rgba(201, 210, 255, 0.3); font: 10px var(--head); color: var(--gold); }
html.touch.form-phone .sdetail .sd-head small { margin-left: auto; font: 13px var(--font); color: var(--dim); }
html.touch.form-phone .sdetail .sd-stats, html.touch.form-phone .sdetail .sd-moves, html.touch.form-phone .sdetail .sd-iq { font-size: 15px; }
html.touch.form-phone .sdetail .sd-move { min-height: 32px; }

/* ---------- the Players window (social.js): rows take the keyboard, a footer with the keys, subs never under 13 px ---------- */
#social .sw-row { scroll-margin: 4px 0; }
#social .sw-sub, #social .sw-where, #social .sw-lv, #social .pf-small, #social .pf-sub, #social .pf-where, #social .sw-pgt, #social .sw-note, #social .sw-h, #social .pf-h, #social .pf-st > span { font-size: var(--win-small); }
#social .sw-tag { font-size: max(10px, calc(11px * var(--k))); }
#social .sw-tag.sent { background: rgba(255, 255, 255, 0.2); }
html.form-phone #social { font-size: 15px; }
#social .sw-foot .win-keys, #social .sw-keys { padding-top: 6px; }

/* ---------- the small tags of the fixed-size windows: never under 8 px of the pixel font ---------- */
.dxsky { font-size: 7px; }
.as-gen { font-size: 8px; }
#results .rs-chip em { font-size: 8px; }
.shop-row .own { font-size: 9px; }
/* phones: the jobs' action button stays in reach while the details scroll */
.jdetail .jgo { position: sticky; bottom: 0; z-index: 1; }
/* ---------- the fixed-size windows: zoomed on big screens (their sheets set `zoom: var(--wk)`), phones keep the full-screen layouts ---------- */
.win-zoom { zoom: var(--wk); --pxz: var(--wk); }

/* =================================================================== grids and drag-and-drop (gridview.js, dnd.js)
   Pixel tiles: square corners, a 1-px dark outline, a 3-shade bevel (light top-left, dark bottom-right), whole-pixel
   sizes (--gv-w / --gv-h from gridview.js), no blur or gradient; animations step. */
.gv { overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; touch-action: pan-y; min-height: 0; position: relative; }
.gv-in { display: grid; grid-template-columns: repeat(auto-fill, var(--gv-w, 64px)); grid-auto-rows: var(--gv-h, 64px); gap: var(--gv-gap, 6px); justify-content: center; align-content: start; padding: 4px; box-sizing: border-box; }
.gv-tile {
  position: relative; width: var(--gv-w, 64px); height: var(--gv-h, 64px); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: var(--slot); border: 2px solid var(--slot-line); border-radius: 0; cursor: pointer; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
  box-shadow: inset 2px 2px 0 #1c2668, inset -2px -2px 0 #070a26, 0 0 0 1px #050820;
}
.gv-tile:not(.empty):hover { border-color: #8fa0ff; }
.gv-tile.empty { cursor: default; background: #0a0f38; border-color: #2c3878; box-shadow: inset 2px 2px 0 #070a26, 0 0 0 1px #050820; }
.gv-tile.off .itm, .gv-tile.off .ico { filter: grayscale(1) brightness(0.55); }   /* a darker ramp, no see-through pixels */
.gv-tile .itm, .gv-tile .ico, .gv-tile .held-ico { flex: none; }
/* the corners: a count bottom-right, a mark top-left, a price strip along the bottom, a key cap top-right */
.gv-n { position: absolute; right: 3px; bottom: 1px; font: calc(12px * var(--k)) var(--num); color: #fff; line-height: 1; text-shadow: -1px 0 #000, 1px 0 #000, 0 1px #000, 0 -1px #000; pointer-events: none; }
.gv-mark { position: absolute; left: 2px; top: 2px; line-height: 0; pointer-events: none; }
.gv-key { position: absolute; right: 2px; top: 1px; font: calc(8px * var(--k)) var(--pixel); color: var(--gold); line-height: 1; text-shadow: -1px 0 #000, 1px 0 #000, 0 1px #000, 0 -1px #000; pointer-events: none; }
.gv-tag { position: absolute; left: 0; right: 0; bottom: 0; padding: 2px 4px 1px; background: #070a26; border-top: 1px solid var(--slot-line); font: calc(12px * var(--k)) var(--num); color: var(--gold); text-align: right; line-height: 1.1; white-space: nowrap; overflow: hidden; pointer-events: none; }
.gv-tag.no { color: #ff9a7a; }
.gv-name { max-width: 100%; padding: 0 3px; font-size: calc(11px * var(--k)); line-height: 1.1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; pointer-events: none; }
/* the selection frame: the tile's own rim turns gold, then a 1-px dark line, a 2-px gold ring and the dark outline; the ring blinks in two steps */
.gv-tile.sel { border-color: var(--gold); box-shadow: inset 2px 2px 0 #3a4690, inset -2px -2px 0 #070a26, 0 0 0 1px #050820, 0 0 0 3px var(--gold), 0 0 0 4px #050820; z-index: 1; animation: gv-blink 1s steps(1) infinite; }
@keyframes gv-blink { 50% { box-shadow: inset 2px 2px 0 #3a4690, inset -2px -2px 0 #070a26, 0 0 0 1px #050820, 0 0 0 3px #fff6c0, 0 0 0 4px #050820; } }
.gv-tile:focus-visible { outline: none; }
/* a grid with nothing to scroll (gridview.js .fits): a finger on a tile never pans the page, the press-and-hold drag is sure */
.gv.fits .gv-tile[data-drag] { touch-action: none; }
.gv-none { padding: 16px; color: var(--dim); font-size: var(--win-small); text-align: center; }
.gv-in > :not(.gv-tile) { grid-column: 1 / -1; }   /* an empty-list note spans the row */
@media (prefers-reduced-motion: reduce) { .gv-tile.sel { animation: none; } }

/* drag-and-drop: the ghost under the pointer, the targets that take it (a light ring), the one under the pointer (gold, two-step blink) */
.dnd-ghost {
  position: fixed; left: 0; top: 0; z-index: 2000; pointer-events: none; display: flex; align-items: center; justify-content: center;
  background: var(--slot); border: 2px solid var(--gold); box-shadow: 0 0 0 1px #050820, 3px 3px 0 1px #050820;
}
.dnd-ghost > * { pointer-events: none; }
.dnd-ghost.back { transition: transform 0.18s steps(3, end); }
html.dnd-on, html.dnd-on * { cursor: grabbing !important; }
/* the lifted tile: its item is in the ghost, so the slot shows empty (its key cap stays); a lifted row or squad place takes a
   darker ramp (no see-through pixels) */
.gv-tile.dnd-src > :not(.kc):not(.gv-key) { visibility: hidden; }
.dnd-src:not(.gv-tile) { filter: grayscale(1) brightness(0.55); }
.tw-slot.dnd-src .tw-spt { visibility: hidden; }
.dnd-hold { animation: dnd-hold 0.3s steps(3, end) forwards; }
@keyframes dnd-hold { to { box-shadow: inset 2px 2px 0 #3a4690, inset -2px -2px 0 #070a26, 0 0 0 1px #050820, 0 0 0 3px #8fa0ff, 0 0 0 4px #050820; } }
.dnd-can { outline: 2px solid #8fa0ff; outline-offset: -2px; }
.dnd-over { outline: 2px solid var(--gold); outline-offset: -2px; animation: dnd-over 0.5s steps(1) infinite; }
@keyframes dnd-over { 50% { outline-color: #fff6c0; } }
.gv-tile.dnd-can, .gv-tile.dnd-over { outline-offset: -4px; }
.dnd-hit { animation: dnd-hit 0.3s steps(2, end); }
@keyframes dnd-hit { 0%, 49% { filter: brightness(1.8); } }
/* the bag (hud.js bagPanel) on the grid: six slots a row (four on phones), the key caps above the tiles' corners */
.bp-grid.gv { display: block; max-height: calc(var(--vh) - 200px); }
.bp-grid .gv-in { padding: calc(10px * var(--k)) 8px 4px; justify-content: start; }
.bp-grid .gv-tile { padding-top: 4px; }
.bp-grid .gv-tile .kc { right: auto; left: -6px; }
.bp-grid .gv-name { font-size: calc(11px * var(--k)); }
html.touch .bp-grid .gv-in { padding-top: 6px; }
.bp-grid .gv-tile.empty .kc { filter: brightness(0.5); }
.gv-own { position: absolute; right: 3px; top: 2px; font: calc(12px * var(--k)) var(--num); color: var(--dim); line-height: 1; text-shadow: -1px 0 #000, 1px 0 #000, 0 1px #000, 0 -1px #000; pointer-events: none; }
/* the Kecleon shop's shelf (shop.js): icon on top, the name, the price tag along the bottom (the window zooms, so plain px) */
#shop .shop-list.gv { border-radius: 0; }
#shop .gv-tile { justify-content: flex-start; padding-top: 16px; gap: 4px; }
#shop .gv-name { font-size: 14px; max-width: 100%; }
#shop .gv-tag, #shop .gv-own { font-size: 14px; }
/* inside a zoomed window (the shop's frame: shop, storage) the zoom scales: plain px, not × --k */
.shop-win .gv-n, .shop-win .gv-own, .shop-win .gv-tag { font-size: 14px; }
.shop-win .gv-key { font-size: 8px; }
#shop .gv-own.num { color: var(--dim); font-weight: 400; }
#shop .gv-mark .pxi { --want: 14px; }
#shop .shop-money small .pxi { --want: 14px; vertical-align: -2px; }
