/*
 * style.css - every style in Palvale's UI: the page base, the design tokens (all colours are variables here),
 * the screens (title, loading, death, characters and the creator), the HUD, the capture aim ring and meters, nameplates, the Esc menu and its pages,
 * modals, and the per-breakpoint restructures.
 *
 * Breakpoints (see game-ui.md in memory):
 *   phone    max-width 599px (portrait)       menu = full-screen sheet with a top tab scroller; HUD compact; compass off
 *   short    max-height 499px (landscape phone) menu = full-screen with a left icon rail; HUD compact
 *   tablet   600-1023px                       menu = near full-screen, horizontal tab bar; detail panels become sheets
 *   desktop  1024px+                          menu = centred panel with a left tab rail and a side detail column
 *   characters / creator: a right-hand column in landscape (narrower on short phones), a bottom sheet in portrait
 *            (phones also merge the header with the name and scroll each option row sideways)
 *   touch    html.is-touch (set by ui.js)     follows core/touch.js's ZONES: the action bars sit between the stick and
 *                                             the action pad (landscape) or on the right edge above the pad, with the
 *                                             experience bar in the free bottom strip under them (portrait: hud.css);
 *                                             Menu = the minimap's Menu button, Map = tap the minimap (ui.js
 *                                             hides touch.js's top-centre pair); no compass strip, no key hints
 * The UI scales with --fs (viewport-based) x --ui-scale (the Interface size setting); sizes are in em.
 *
 * Owns: the look of every UI element. Does NOT own layout logic (ui/*.js) or the touch overlay (core/touch.js).
 */

/* ----------------------------------------------------------------------------- page base (index.html) */
html, body { margin: 0; height: 100%; overflow: hidden; background: #0e1a2b; }
#stage { position: fixed; inset: 0; }
#stage canvas { display: block; width: 100%; height: 100%; touch-action: none; }
#ui { position: fixed; inset: 0; pointer-events: none; }

/* ----------------------------------------------------------------------------- tokens */
:root {
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --accent-primary: #3fe0ff;
  --color-lime: #b8ff4a;
  --accent: var(--accent-primary);
  --accent-2: var(--color-lime);
  --accent-deep: #0b6f93;
  --ink: #0b1322;
  --panel: rgba(11, 19, 34, 0.8);
  --panel-2: rgba(22, 34, 58, 0.9);
  --panel-3: rgba(36, 52, 84, 0.94);
  --panel-solid: #0f1829;
  --panel-menu: rgba(11, 18, 32, 0.95);
  --line: rgba(255, 255, 255, 0.09);
  --line-2: rgba(255, 255, 255, 0.17);
  --text: #f3f7ff;
  --text-2: #b1bfd8;
  --text-3: #7a89a6;
  --hp: #ff4d6d;
  --st: #ffd23f;
  --o2: #5ad8ff;
  --exp: #b98aff;
  --gold: #ffd35a;
  --good: #5ef08a;
  --warn: #ffc53a;
  --bad: #ff5a6e;
  --info: #5ab8ff;
  --r-lg: 20px;
  --r: 14px;
  --r-sm: 10px;
  --shadow: 0 12px 32px rgba(0, 0, 0, 0.38);
  --shadow-sm: 0 3px 10px rgba(0, 0, 0, 0.32);
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --fs: clamp(14px, 0.45vw + 8.5px, 20px);
  --ui-scale: 1;
  --tap: 44px;
  /* touch controls: in landscape the stick and the action pad hold the bottom corners (--tz-left / --tz-right wide);
     in portrait they sit above a free bottom strip (--tz-strip) that holds the experience bar. core/touch.js writes the real
     footprint from ifn_pkg_input's touch layout (left-handed, button size) on the document while touch is in use;
     the values below are the fallback until it does. All 0 without touch. */
  --tz-left: 0px;
  --tz-right: 0px;
  --tz-strip: 0px;
}
html.is-touch { --tz-left: 150px; --tz-right: 226px; }                                        /* phone: stick ~140, pad 3.6 x 56 + 14 */
@media (max-height: 380px) { html.is-touch { --tz-left: 134px; --tz-right: 200px; } }          /* short phone: pad 3.6 x 50 + 10 */
@media (min-width: 600px) and (min-height: 600px) { html.is-touch { --tz-left: 180px; --tz-right: 270px; } }   /* tablet: 3.6 x 66 + 22 */
@media (orientation: portrait) { html.is-touch { --tz-left: 0px; --tz-right: 0px; --tz-strip: 84px; } }
@media (orientation: portrait) and (min-width: 600px) { html.is-touch { --tz-strip: 92px; } }

/* ----------------------------------------------------------------------------- root and primitives */
/* .pv is the UI root ui.js builds (pv = Palvale, as in the touch overlay's .pv-* classes) */
.pv {
  position: absolute; inset: 0; pointer-events: none; overflow: hidden;
  font: 600 calc(var(--fs) * var(--ui-scale)) / 1.3 var(--font); color: var(--text);
  -webkit-font-smoothing: antialiased; user-select: none; -webkit-user-select: none; -webkit-tap-highlight-color: transparent;
  --gap: 14px; --mm: 11em;
}
.pv *, .pv *::before, .pv *::after { box-sizing: border-box; }
.pv.boot, .pv.boot * { transition: none !important; }   /* first frames: hidden screens start hidden, no fade */
/* every top-level layer is its own stacking context: z-indexes inside one (the HP numbers, the side sheet) never
   climb over the next layer (HUD < menu < screens < toasts < modals, in DOM order) */
.pv > .hud, .pv > .menu, .pv > .scr, .pv > .toasts, .pv > .modals { isolation: isolate; }
.pv button, .pv input { font: inherit; color: inherit; }
.pv [hidden] { display: none !important; }
.pv .ico { display: inline-flex; width: 1.25em; height: 1.25em; flex: none; }
.pv .ico svg { width: 100%; height: 100%; display: block; overflow: visible; }
.pv .num, .pv .tab-num { font-variant-numeric: tabular-nums; }
.pv .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.btn {
  pointer-events: auto; display: inline-flex; align-items: center; justify-content: center; gap: 0.5em;
  min-height: max(2.75em, var(--tap)); padding: 0 1.15em; border-radius: 999px; border: 2px solid var(--line-2);
  background: var(--panel-2); color: var(--text); font-weight: 800; cursor: pointer; white-space: nowrap;
  transition: transform 120ms var(--ease), background 120ms, border-color 120ms, box-shadow 120ms, opacity 120ms;
  touch-action: manipulation;
}
.btn .ico { width: 1.2em; height: 1.2em; }
.btn:hover { background: var(--panel-3); border-color: rgba(255, 255, 255, 0.3); }
.btn:active { transform: scale(0.96); }
.btn.primary { background: linear-gradient(180deg, #6deeff, #1fb8e6); color: #04202d; border-color: #b4f6ff; box-shadow: 0 4px 0 var(--accent-deep), var(--shadow-sm); }
.btn.primary:active { transform: translateY(2px); box-shadow: 0 2px 0 var(--accent-deep); }
.btn.lime { background: linear-gradient(180deg, #d6ff7a, #8fe01e); color: #172600; border-color: #eaffb8; box-shadow: 0 4px 0 #4f8a08, var(--shadow-sm); }
.btn.danger { background: linear-gradient(180deg, #ff8595, #e8384f); color: #fff; border-color: #ffc0c8; box-shadow: 0 4px 0 #8f1c2c, var(--shadow-sm); }
.btn.ghost { background: transparent; border-color: transparent; }
.btn.ghost:hover { background: rgba(255, 255, 255, 0.08); }
.btn.icon { width: max(2.75em, var(--tap)); padding: 0; }
.btn.icon .ico { width: 1.35em; height: 1.35em; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.42; cursor: default; transform: none; box-shadow: none; }

.keycap {
  display: inline-grid; place-items: center; min-width: 1.9em; height: 1.9em; padding: 0 0.45em; border-radius: 0.45em;
  background: #f3f7ff; color: var(--ink); font-weight: 900; font-size: 0.8em; line-height: 1; white-space: nowrap;
  box-shadow: 0 3px 0 #97a8c6, 0 0 0 2px var(--ink);
}
.keycap.pad { border-radius: 999px; min-width: 1.9em; }
.keycap.touch { background: var(--accent); }
.keycap .ico { width: 1.2em; height: 1.2em; }

.pv :focus { outline: none; }
.pv.nav-keys :focus { outline: 3px solid var(--accent); outline-offset: 3px; }
.pv :focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

/* ----------------------------------------------------------------------------- screens */
.scr {
  position: absolute; inset: 0; display: flex; pointer-events: none; opacity: 0; visibility: hidden;
  transition: opacity 420ms var(--ease), visibility 0s linear 420ms;
}
.scr.on { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity 420ms var(--ease); }

/* the logo: an inked word with a gradient fill, two stacked layers */
.logo { display: flex; align-items: center; gap: 0.4em; }
.logo-mark { width: 3.6em; height: 3.6em; flex: none; filter: drop-shadow(0 0.25em 0.4em rgba(0, 0, 0, 0.35)); }
.logo-word { display: inline-grid; margin: 0; font-size: clamp(2.6em, 6.2vw, 5em); font-weight: 900; line-height: 1; letter-spacing: -0.01em; }
.logo-word > span { grid-area: 1 / 1; }
.logo-word .ink { color: var(--ink); -webkit-text-stroke: 0.2em var(--ink); text-shadow: 0 0.1em 0 var(--ink), 0 0.2em 0.45em rgba(0, 0, 0, 0.5); }
.logo-word .fill { background: linear-gradient(180deg, #ffffff 8%, #d6f7ff 42%, #7fe6ff 70%, #b8ff4a 100%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.tagline { margin: 0.9em 0 0 0.25em; color: var(--text-2); font-weight: 800; letter-spacing: 0.32em; text-transform: uppercase; font-size: 0.82em; text-shadow: 0 1px 0 var(--ink); }

.title {
  flex-direction: column; justify-content: center; gap: 2.6em;
  padding: calc(var(--safe-t) + 6dvh) calc(var(--safe-r) + 6vw) calc(var(--safe-b) + 6dvh) calc(var(--safe-l) + 6vw);
  background:
    linear-gradient(90deg, rgba(6, 12, 24, 0.82) 0%, rgba(6, 12, 24, 0.45) 38%, rgba(6, 12, 24, 0) 68%),
    linear-gradient(0deg, rgba(6, 12, 24, 0.7) 0%, rgba(6, 12, 24, 0) 40%);
}
.title-menu { display: flex; flex-direction: column; gap: 0.7em; width: min(24em, 100%); }
.title-btn { justify-content: flex-start; min-height: 3.5em; padding: 0 1.3em; border-radius: var(--r); font-size: 1.05em; text-align: left; }
.title-btn .ico { width: 1.4em; height: 1.4em; }
.title-btn .t { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.title-btn small { font-weight: 700; font-size: 0.72em; opacity: 0.78; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.title-btn.primary small { opacity: 0.85; }
.title-foot { position: absolute; right: calc(var(--safe-r) + 1.6em); bottom: calc(var(--safe-b) + 1.2em); color: var(--text-3); font-size: 0.78em; text-shadow: 0 1px 0 var(--ink); }

.loading {
  flex-direction: column; align-items: center; justify-content: center; gap: 2.2em; text-align: center;
  padding: calc(var(--safe-t) + 2em) calc(var(--safe-r) + 1.5em) calc(var(--safe-b) + 2em) calc(var(--safe-l) + 1.5em);
  background: radial-gradient(120% 90% at 50% 40%, #16335a 0%, #0c1a30 55%, #070f1d 100%);
}
.loading .logo-word { font-size: clamp(2.2em, 5vw, 3.6em); }
.load-box { display: flex; flex-direction: column; align-items: center; gap: 0.8em; width: min(28em, 86vw); }
.load-bar { width: 100%; height: 0.9em; border-radius: 999px; background: rgba(255, 255, 255, 0.08); border: 2px solid var(--line-2); overflow: hidden; box-shadow: 0 0 0 2px var(--ink); }
.load-fill { position: relative; height: 100%; transform-origin: 0 50%; transform: scaleX(0); background: linear-gradient(90deg, var(--accent), var(--accent-2)); transition: transform 280ms var(--ease); border-radius: inherit; overflow: hidden; }
.load-fill::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.55), transparent); animation: shimmer 1.3s linear infinite; }
.load-label { display: flex; justify-content: space-between; width: 100%; color: var(--text-2); font-size: 0.85em; }
.load-tip { max-width: 30em; min-height: 2.8em; color: var(--text-2); font-weight: 600; line-height: 1.4; transition: opacity 300ms; }
.load-tip b { color: var(--accent); font-weight: 900; letter-spacing: 0.12em; text-transform: uppercase; font-size: 0.78em; display: block; margin-bottom: 0.3em; }

.dead { flex-direction: column; align-items: center; justify-content: center; gap: 1.2em; text-align: center; background: radial-gradient(circle, rgba(70, 0, 16, 0.35), rgba(20, 0, 6, 0.86)); }
.dead h2 { margin: 0; font-size: 2.6em; font-weight: 900; color: #ffd0d6; text-shadow: 0 3px 0 var(--ink); }
.dead p { margin: 0; color: var(--text-2); }

/* ----------------------------------------------------------------------------- character creator (ui/creator.js)
   The studio (player/studio.js) draws the character on the canvas behind this screen; .cr-stage is the drag surface
   over it. Landscape: the panel is a column on the right and the character stands in the space to its left. Portrait
   (phones, portrait tablets): the panel is a sheet along the bottom and the character stands above it; on phones the
   header and the name share a row and each option row scrolls sideways inside itself. Short landscape phones: a
   narrower full-height column. The panel always scrolls within itself; the page never scrolls. */
.cr-stage { position: absolute; inset: 0; touch-action: none; cursor: grab; }
.cr-stage:active { cursor: grabbing; }
.cr-panel {
  position: absolute; z-index: 1; display: flex; flex-direction: column; gap: 0.9em; min-height: 0;
  top: calc(var(--safe-t) + 1.2em); right: calc(var(--safe-r) + 1.2em); bottom: calc(var(--safe-b) + 1.2em);
  width: min(31em, 44vw); padding: 1.1em 1.2em 1.2em;
  border-radius: var(--r-lg); background: var(--panel-menu); border: 2px solid var(--line-2);
  box-shadow: 0 0 0 3px var(--ink), var(--shadow);
}
.scr.on .cr-panel { animation: page-in 320ms var(--ease) both; }
.cr-head { display: flex; align-items: center; gap: 0.7em; flex: none; }
.cr-head h2 { margin: 0; flex: 1; min-width: 0; font-size: 1.45em; font-weight: 900; text-shadow: 0 2px 0 var(--ink); }

/* a thumbnail (web/thumbs.js renders it with a transparent background): a tile with a shimmer until the image lands */
.cr-pic {
  position: relative; display: block; width: 100%; aspect-ratio: 1; border-radius: var(--r-sm); overflow: hidden;
  background: radial-gradient(circle at 50% 36%, #3d5a8c 0%, #243a60 60%, #1b2c4a 100%); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.07);
}
.cr-pic::after { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.09), transparent); animation: shimmer 1.4s linear infinite; }
.cr-pic.in::after { display: none; }
.cr-pic img { display: block; width: 100%; height: 100%; object-fit: cover; opacity: 0; transition: opacity 220ms var(--ease); }
.cr-pic img.in { opacity: 1; }

/* the creator: name, category tabs, option rows, Surprise me / Create */
.cr-name { display: flex; flex-direction: column; gap: 0.35em; flex: none; }
.cr-name > span, .cr-row-title { margin: 0; color: var(--text-2); font-size: 0.78em; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase; }
.cr-name-row { display: flex; gap: 0.5em; }
.creator .char-name {
  pointer-events: auto; flex: 1; min-width: 0; min-height: max(2.75em, var(--tap)); padding: 0 1em; border-radius: 999px;
  border: 2px solid var(--line-2); background: rgba(6, 12, 24, 0.6); font-weight: 800; font-size: 1.05em; user-select: text; -webkit-user-select: text;
}
.creator .char-name:focus { border-color: var(--accent); }
.cr-tabs {
  display: flex; gap: 0.3em; flex: none; padding: 0.3em; border-radius: 999px; background: rgba(6, 12, 24, 0.55); border: 2px solid var(--line);
  overflow-x: auto; scrollbar-width: none;
}
.cr-tabs::-webkit-scrollbar { display: none; }
.creator .cr-tab {
  pointer-events: auto; flex: 1 0 auto; min-height: max(2.5em, var(--tap)); padding: 0 1em; border: 0; border-radius: 999px;
  background: transparent; color: var(--text-2); font-weight: 900; cursor: pointer; touch-action: manipulation; transition: background 150ms, color 150ms;
}
.creator .cr-tab:hover { color: var(--text); background: rgba(255, 255, 255, 0.06); }
.creator .cr-tab[aria-selected="true"] { background: linear-gradient(180deg, #6deeff, #1fb8e6); color: #04202d; box-shadow: 0 3px 0 var(--accent-deep); }
.cr-rows { display: flex; flex-direction: column; gap: 1.15em; flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0.25em 0.25em 0.5em; margin: 0 -0.25em; }
.cr-row { display: flex; flex-direction: column; gap: 0.55em; flex: none; }
.cr-row-head { display: flex; align-items: baseline; justify-content: space-between; gap: 1em; }
.cr-val { font-weight: 900; font-variant-numeric: tabular-nums; }
.cr-opts { display: grid; grid-template-columns: repeat(auto-fill, minmax(5.4em, 1fr)); gap: 0.55em; }
.creator .cr-opt {
  pointer-events: auto; display: flex; flex-direction: column; gap: 0.3em; min-width: 0; padding: 0.3em; border-radius: var(--r);
  border: 2px solid var(--line); background: var(--panel-2); cursor: pointer; touch-action: manipulation; text-align: center;
  transition: border-color 150ms, background 150ms, transform 150ms var(--spring), box-shadow 150ms;
}
.creator .cr-opt:hover { border-color: rgba(255, 255, 255, 0.3); background: var(--panel-3); }
.creator .cr-opt:active { transform: scale(0.96); }
.creator .cr-opt[aria-pressed="true"] { border-color: var(--accent); background: rgba(63, 224, 255, 0.14); box-shadow: 0 0 0 2px var(--ink), 0 0 14px rgba(63, 224, 255, 0.35); }
.cr-lbl { padding: 0 0.2em 0.1em; font-size: 0.75em; font-weight: 800; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cr-opt[aria-pressed="true"] .cr-lbl { color: var(--text); }
.cr-swatches { display: flex; flex-wrap: wrap; gap: 0.5em; }
.creator .cr-swatch {
  pointer-events: auto; display: grid; place-items: center; width: max(2.6em, var(--tap)); height: max(2.6em, var(--tap)); padding: 0;
  border-radius: 50%; border: 3px solid rgba(255, 255, 255, 0.28); background: var(--sw, repeating-linear-gradient(45deg, #2c4068 0 5px, #1d2d4b 5px 10px));
  box-shadow: 0 0 0 2px var(--ink); cursor: pointer; touch-action: manipulation; transition: transform 150ms var(--spring), border-color 150ms, box-shadow 150ms;
}
.creator .cr-swatch:hover { transform: scale(1.07); }
.creator .cr-swatch[aria-pressed="true"] { border-color: #fff; box-shadow: 0 0 0 2px var(--ink), 0 0 0 5px var(--accent); }
.cr-swatch span { font-size: 0.6em; font-weight: 900; letter-spacing: 0.04em; text-transform: uppercase; text-shadow: 0 1px 0 var(--ink); }
.creator .cr-slider { pointer-events: auto; -webkit-appearance: none; appearance: none; width: 100%; height: var(--tap); margin: 0; background: transparent; cursor: pointer; touch-action: pan-y; }
.cr-slider::-webkit-slider-runnable-track { height: 0.55em; border-radius: 999px; background: linear-gradient(90deg, var(--accent-deep), var(--accent)); box-shadow: 0 0 0 2px var(--ink); }
.cr-slider::-webkit-slider-thumb { -webkit-appearance: none; box-sizing: border-box; width: 1.7em; height: 1.7em; margin-top: -0.575em; border-radius: 50%; background: #fff; border: 3px solid var(--accent); box-shadow: 0 0 0 2px var(--ink), 0 2px 6px rgba(0, 0, 0, 0.4); }
.cr-slider::-moz-range-track { height: 0.55em; border-radius: 999px; background: linear-gradient(90deg, var(--accent-deep), var(--accent)); box-shadow: 0 0 0 2px var(--ink); }
.cr-slider::-moz-range-thumb { box-sizing: border-box; width: 1.7em; height: 1.7em; border-radius: 50%; background: #fff; border: 3px solid var(--accent); box-shadow: 0 0 0 2px var(--ink); }
.cr-ends { display: flex; justify-content: space-between; margin-top: -0.3em; color: var(--text-3); font-size: 0.72em; font-weight: 800; }
.cr-foot { display: flex; gap: 0.6em; flex: none; }
.cr-foot .btn { flex: 1 1 0; min-width: 0; }
.cr-foot .btn.primary { flex-grow: 1.4; }

@media (orientation: portrait) {                          /* phones and portrait tablets: a sheet along the bottom */
  .cr-panel {
    top: auto; left: 0; right: 0; bottom: 0; width: auto;
    padding: 0.9em calc(var(--safe-r) + 1em) calc(var(--safe-b) + 0.9em) calc(var(--safe-l) + 1em);
    border-radius: var(--r-lg) var(--r-lg) 0 0; border-width: 2px 0 0; box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.45);
  }
  .scr.on .cr-panel { animation: sheet 300ms var(--ease) both; }
  .cr-panel { height: 50dvh; }                             /* fixed: switching tabs never moves the character */
}
@media (orientation: portrait) and (max-width: 599px) {   /* phones: header + name on one row, option rows scroll sideways */
  .cr-panel {
    height: 56dvh; display: grid; gap: 0.75em 0.5em; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "head name" "tabs tabs" "rows rows" "foot foot";
  }
  .cr-head { grid-area: head; }
  .cr-head h2, .cr-name > span { display: none; }
  .cr-name { grid-area: name; }
  .cr-tabs { grid-area: tabs; }
  .cr-rows { grid-area: rows; gap: 0.9em; }
  .cr-foot { grid-area: foot; }
  .cr-opts { display: flex; gap: 0.5em; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; padding: 0.25em 0.25em 0.45em; margin: -0.25em; scrollbar-width: none; }
  .cr-opts::-webkit-scrollbar { display: none; }
  .creator .cr-opt { flex: 0 0 5.3em; scroll-snap-align: start; }
  .creator .cr-tab { padding: 0 0.7em; }
}
@media (max-height: 499px) and (orientation: landscape) { /* landscape phones: a narrower, compact full-height column */
  .cr-panel {
    top: calc(var(--safe-t) + 0.5em); right: calc(var(--safe-r) + 0.5em); bottom: calc(var(--safe-b) + 0.5em);
    width: min(25em, 54vw); padding: 0.65em 0.8em; gap: 0.55em;
    display: grid; grid-template-columns: auto minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr) auto;
    grid-template-areas: "head name" "tabs tabs" "rows rows" "foot foot";
  }
  .cr-head { grid-area: head; }
  .cr-head h2, .cr-name > span { display: none; }
  .cr-name { grid-area: name; }
  .cr-tabs { grid-area: tabs; }
  .cr-rows { grid-area: rows; gap: 0.8em; }
  .cr-foot { grid-area: foot; }
  .cr-opts { grid-template-columns: repeat(auto-fill, minmax(4.6em, 1fr)); gap: 0.45em; }
}

/* ----------------------------------------------------------------------------- HUD */
.hud { position: absolute; inset: 0; opacity: 0; visibility: hidden; transition: opacity 300ms, visibility 0s linear 300ms; }
.hud.on { opacity: 1; visibility: visible; transition: opacity 300ms; }
.shade-text { text-shadow: 0 1px 0 var(--ink), 0 0 6px rgba(0, 0, 0, 0.55); }

.vignette { position: absolute; inset: 0; opacity: 0; background: radial-gradient(ellipse at center, transparent 52%, rgba(210, 16, 44, 0.62) 100%); will-change: opacity; }


/* compass strip */
/* width: whatever is left between the vitals (~18.7em) and the minimap (~11em) on each side, at most 30em */
.compass { position: absolute; top: calc(var(--safe-t) + var(--gap)); left: 50%; width: min(30em, calc(100vw - 37.5em - 48px)); height: 2.3em; transform: translateX(-50%); overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent); mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent); }
.compass::before { content: ""; position: absolute; left: 0; right: 0; bottom: 0.45em; height: 2px; background: rgba(255, 255, 255, 0.35); }
.compass { background: linear-gradient(180deg, rgba(8, 14, 26, 0.42), rgba(8, 14, 26, 0.12)); border-radius: 0.6em; }
.cp-strip { position: absolute; left: 50%; top: 0; height: 100%; will-change: transform; }
.cp-strip i { position: absolute; bottom: 0.45em; width: 2px; height: 0.45em; margin-left: -1px; background: rgba(255, 255, 255, 0.55); }
.cp-strip b { position: absolute; bottom: 0.95em; transform: translateX(-50%); font-size: 0.8em; font-weight: 900; text-shadow: 0 1px 0 var(--ink), 0 0 5px rgba(0, 0, 0, 0.6); }
.cp-strip b.card { font-size: 1em; }
.cp-strip b.n { color: #ff8a9a; }
.cp-marks { position: absolute; inset: 0; }
.cp-marks span { position: absolute; left: 50%; bottom: 0.9em; width: 1.3em; height: 1.3em; margin-left: -0.65em; display: none; filter: drop-shadow(0 1px 0 var(--ink)); }
.cp-marks span.on { display: block; }
.cp-caret { position: absolute; left: 50%; bottom: 0; width: 0; height: 0; margin-left: -0.35em; border: 0.35em solid transparent; border-bottom-color: var(--accent); }


/* interaction prompt, reticle */
.prompt { position: absolute; left: 0; top: 0; display: flex; align-items: center; gap: 0.5em; padding: 0.4em 0.95em 0.4em 0.42em; border-radius: 999px; background: var(--panel); border: 2px solid var(--line-2); box-shadow: 0 0 0 1.5px var(--ink), var(--shadow-sm); font-weight: 800; white-space: nowrap; opacity: 0; transition: opacity 150ms; will-change: transform; }
.prompt.on { opacity: 1; }
/* a station's state and its keys, hung under the prompt's pill (wraps on a narrow screen) */
.prompt-detail { position: absolute; top: calc(100% + 6px); left: 50%; transform: translateX(-50%); display: none; width: max-content; max-width: min(88vw, 30em); padding: 0.3em 0.8em; border-radius: 0.8em; background: var(--panel); border: 2px solid var(--line-2); box-shadow: 0 0 0 1.5px var(--ink), var(--shadow-sm); font-size: 0.78em; font-weight: 700; line-height: 1.35; text-align: center; white-space: pre-line; }
.prompt-detail.on { display: block; }
.reticle { position: absolute; left: 50%; top: 50%; width: 3.2em; height: 3.2em; margin: -1.6em 0 0 -1.6em; color: #fff; opacity: 0; transform: scale(0.6); transition: opacity 120ms, transform 180ms var(--spring); filter: drop-shadow(0 0 1.5px var(--ink)) drop-shadow(0 1px 0 var(--ink)); }
.reticle.on { opacity: 1; transform: none; }
.reticle svg { width: 100%; height: 100%; overflow: visible; }

/* toasts */
.toasts { position: absolute; left: calc(var(--safe-l) + var(--gap)); top: 32%; width: min(22em, 64vw); display: flex; flex-direction: column; align-items: flex-start; gap: 0.4em; }
.menu.on ~ .toasts, .scr.on ~ .toasts { top: auto; bottom: calc(var(--safe-b) + 1.2em); left: 50%; transform: translateX(-50%); align-items: center; }
.toast { display: flex; align-items: center; gap: 0.55em; max-width: 100%; padding: 0.45em 0.95em 0.45em 0.5em; border-radius: var(--r); background: var(--panel); border: 2px solid var(--line-2); box-shadow: 0 0 0 1.5px var(--ink), var(--shadow-sm); animation: toast-in 300ms var(--spring) both; }
.toast.bump { animation: bump 260ms var(--spring); }
.toast.out { animation: toast-out 260ms var(--ease) both; }
.toast > .ico { width: 1.7em; height: 1.7em; }
.toast .tx { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.toast .x { color: var(--accent-2); font-weight: 900; margin-left: 0.2em; }
.toast.good { border-color: rgba(94, 240, 138, 0.55); }
.toast.good > .ico { color: var(--good); }
.toast.warn { border-color: rgba(255, 197, 58, 0.6); }
.toast.warn > .ico { color: var(--warn); }
.toast.error { border-color: rgba(255, 90, 110, 0.65); }
.toast.error > .ico { color: var(--bad); }
.toast.info > .ico { color: var(--info); }
.toast.unlock, .toast.level { border-color: rgba(255, 211, 90, 0.75); background: linear-gradient(90deg, rgba(255, 211, 90, 0.26), var(--panel) 65%); }
.toast.unlock > .ico, .toast.level > .ico { color: var(--gold); }
.toast.capture { border-color: rgba(63, 224, 255, 0.6); background: linear-gradient(90deg, rgba(63, 224, 255, 0.2), var(--panel) 65%); }
.toast.exp > .ico { color: var(--exp); }

/* banners: level up, place names */
.banner { position: absolute; left: 50%; top: 19%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 0.2em; text-align: center; white-space: nowrap; opacity: 0; }
.banner.on { animation: banner 2.8s var(--ease) both; }
.banner .big { display: inline-grid; font-size: 2.7em; font-weight: 900; letter-spacing: 0.03em; line-height: 1; }
.banner .big > span { grid-area: 1 / 1; }
.banner .big .ink { color: var(--ink); -webkit-text-stroke: 0.18em var(--ink); text-shadow: 0 0.08em 0 var(--ink); }
.banner .big .fill { background: linear-gradient(180deg, #fff6c8 10%, #ffd35a 55%, #ff9a2a 100%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.banner .sub { font-size: 1.05em; font-weight: 800; color: #fff; text-shadow: 0 2px 0 var(--ink), 0 0 8px rgba(0, 0, 0, 0.5); }
.banner .burst { position: absolute; left: 50%; top: 45%; width: 16em; height: 16em; margin: -8em 0 0 -8em; z-index: -1; background: repeating-conic-gradient(rgba(255, 211, 90, 0.28) 0 7deg, transparent 7deg 20deg); -webkit-mask-image: radial-gradient(circle, #000 20%, transparent 68%); mask-image: radial-gradient(circle, #000 20%, transparent 68%); animation: spin 9s linear infinite; }
/* a warning announced once (ui/weatherhud.js): fades in, holds, fades out - no flash, no strobe, no colour cycling */
.wx-card { position: absolute; left: 50%; top: 19%; transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: 0.35em; width: max-content; max-width: min(34em, calc(100vw - 2 * var(--gap)));
  padding: 0.8em 2.4em; text-align: center; opacity: 0; visibility: hidden; pointer-events: none; transition: opacity 450ms var(--ease), visibility 0s linear 450ms;
  background: radial-gradient(closest-side, rgba(8, 14, 26, 0.72), rgba(8, 14, 26, 0)); }
.wx-card.on { opacity: 1; visibility: visible; transition: opacity 450ms var(--ease); }
.wx-card-h { font-size: 1.9em; font-weight: 900; letter-spacing: 0.06em; text-transform: uppercase; color: #ff8a78; text-shadow: 0 2px 0 var(--ink), 0 0 10px rgba(0, 0, 0, 0.55); }
.wx-card-sub { font-size: 1em; font-weight: 800; color: #fff; text-shadow: 0 2px 0 var(--ink), 0 0 8px rgba(0, 0, 0, 0.5); }
.place { position: absolute; left: 50%; top: 13%; transform: translateX(-50%); text-align: center; opacity: 0; white-space: nowrap; padding: 0.7em 3.2em; background: radial-gradient(closest-side, rgba(8, 14, 26, 0.55), rgba(8, 14, 26, 0)); }
.place.on { animation: place 3.6s var(--ease) both; }
.place small { display: block; color: var(--text-2); font-size: 0.75em; letter-spacing: 0.35em; text-transform: uppercase; font-weight: 900; }
.place b { display: block; font-size: 1.75em; font-weight: 900; letter-spacing: 0.04em; }
.place b::before, .place b::after { content: ""; display: inline-block; width: 1.6em; height: 2px; margin: 0 0.6em; vertical-align: middle; background: rgba(255, 255, 255, 0.6); }
.fps { position: absolute; top: calc(var(--safe-t) + 4px); left: 50%; transform: translateX(-50%); padding: 0.2em 0.55em; border-radius: 6px; background: rgba(0, 0, 0, 0.5); color: var(--good); font: 800 0.72em/1.2 ui-monospace, Consolas, monospace; }
.floaters { position: absolute; inset: 0; }
.floater { position: absolute; left: 50%; top: 42%; transform: translateX(-50%); font-weight: 900; color: var(--exp); font-size: 0.95em; animation: float-up 1.4s var(--ease) both; white-space: nowrap; }

/* ----------------------------------------------------------------------------- capture: the aim ring */
.cap-ring { position: absolute; left: 0; top: 0; width: 200px; height: 200px; margin: -100px 0 0 -100px; opacity: 0; transition: opacity 140ms; will-change: transform; --c: var(--good); --k: 1; }
.cap-ring.on { opacity: 1; }
.cap-ring svg { width: 100%; height: 100%; overflow: visible; }
.cap-ring circle { fill: none; }
.cap-ring .glow { stroke: var(--c); stroke-width: calc(18px * var(--k)); opacity: 0.14; animation: cap-breathe 1.8s ease-in-out infinite; }
.cap-ring .tr { stroke: rgba(8, 14, 26, 0.6); stroke-width: calc(11px * var(--k)); }
.cap-ring .tk line { stroke: rgba(255, 255, 255, 0.3); stroke-width: calc(1.6px * var(--k)); stroke-linecap: round; }
.cap-ring .arc { stroke: var(--c); stroke-width: calc(7px * var(--k)); stroke-linecap: round; transition: stroke-dashoffset 260ms var(--ease), stroke 220ms; filter: drop-shadow(0 0 4px var(--c)); }
.cap-ring .spin { stroke: rgba(255, 255, 255, 0.7); stroke-width: calc(2px * var(--k)); stroke-dasharray: 3 11; transform-origin: 100px 100px; animation: spin 7s linear infinite; }
.cap-ring.far { --c: #8a96aa; }
.cap-ring.far .arc { opacity: 0.55; }
.cap-ring.far .glow { opacity: 0.05; animation: none; }
.cap-label { position: absolute; left: 0; top: 0; display: flex; flex-direction: column; align-items: center; gap: 0.3em; opacity: 0; transition: opacity 140ms; will-change: transform; white-space: nowrap; --c: var(--good); }
.cap-label.on { opacity: 1; }
.cap-pct { display: inline-flex; align-items: baseline; padding: 0.1em 0.55em 0.14em; border-radius: 999px; background: rgba(8, 14, 26, 0.8); border: 2px solid var(--c); box-shadow: 0 0 0 1.5px var(--ink), 0 0 14px -4px var(--c); font-size: 1.75em; font-weight: 900; line-height: 1; color: #fff; transition: border-color 220ms, box-shadow 220ms; }
.cap-pct small { font-size: 0.56em; margin-left: 0.05em; color: var(--c); }
.cap-meta { display: flex; align-items: center; gap: 0.4em; padding: 0.2em 0.7em 0.2em 0.3em; border-radius: 999px; background: rgba(8, 14, 26, 0.72); border: 1.5px solid var(--line-2); font-size: 0.8em; font-weight: 800; }
.cap-meta .ico { width: 1.35em; height: 1.35em; }
.cap-meta .lv { color: var(--text-2); }
.cap-tags { display: flex; gap: 0.3em; font-size: 0.72em; font-weight: 900; }
.cap-tags span { padding: 0.15em 0.55em; border-radius: 999px; background: rgba(8, 14, 26, 0.72); border: 1.5px solid var(--line-2); }
.cap-tags .head { color: var(--accent-2); border-color: rgba(184, 255, 74, 0.5); }
.cap-tags .caught { color: var(--text-2); }
.cap-tags .far { color: #ffb0ba; }

/* ----------------------------------------------------------------------------- capture: the meter (after a hit) */
/* One per capture, on the sphere: .cm is a 0 x 0 point at the sphere's screen position (translate3d from capture.js)
   and everything is laid out round it in em. --c: the chance colour (gold on a critical); --cc: the spinning light;
   --heat: 0 -> 1 as the checks go by. The ring is a 240-unit SVG drawn 12em across: its track (radius 96) runs 4.8em
   out, its outer edge 5.2em. Below it: the % pill on the track, the gems, the card; above it the word. */
.cm-layer { position: absolute; inset: 0; }
.cm { position: absolute; left: 0; top: 0; width: 0; height: 0; opacity: 0; transition: opacity 240ms; will-change: transform, opacity; --c: var(--good); --cc: #ffffff; --heat: 0; }
.cm.on { opacity: 1; }
.cm[data-step="1"] { --heat: 0.35; }
.cm[data-step="2"] { --heat: 0.65; }
.cm[data-step="3"], .cm.final { --heat: 1; }
.cm.crit { --c: var(--gold); --cc: #fff3b8; }
.cm.out { --cc: var(--bad); }
.cm-ringbox { position: absolute; left: -6em; top: -6em; width: 12em; height: 12em; }
.cm.on .cm-ringbox { animation: cm-in 460ms var(--spring) both; }
.cm.on .cm-ringbox.beat { animation: cm-beat 620ms ease-out; }
.cm.on.win .cm-ringbox { animation: cm-win 720ms var(--ease) 60ms both; }
.cm.on.lose .cm-ringbox { animation: cm-break 560ms var(--ease) both; }
.cm.on.fizzle .cm-ringbox { animation: cm-fizzle 420ms var(--ease) both; }
.cm-ring { display: block; width: 100%; height: 100%; overflow: visible; }
.cm-ring circle, .cm-ring line { fill: none; }
.cm-ring .cm-halo { stroke: var(--c); stroke-width: 30; opacity: calc(0.07 + 0.16 * var(--heat)); transition: opacity 400ms, stroke 300ms; }
.cm-ring .cm-track { stroke: rgba(8, 14, 26, 0.74); stroke-width: 15; }
.cm-ring .cm-rim { stroke: rgba(255, 255, 255, 0.16); stroke-width: 1.5; }
.cm-ring .cm-zone-glow { stroke: var(--c); stroke-width: 22; opacity: calc(0.16 + 0.2 * var(--heat)); }
.cm-ring .cm-zone { stroke: var(--c); stroke-width: 9; }
.cm.out .cm-zone, .cm.out .cm-zone-glow { opacity: 0.4; }
.cm-ticks line { stroke: rgba(255, 255, 255, 0.34); stroke-width: 2.4; stroke-linecap: round; transition: stroke 420ms, stroke-width 420ms; }
.cm-ticks line.hot { stroke: var(--cc); stroke-width: 4; transition: none; }
.cm-chase { opacity: 0; transition: opacity 180ms; }
.cm.go .cm-chase { opacity: 1; }
.cm-ring .cm-trail { stroke: var(--cc); stroke-width: 8; stroke-linecap: round; }
.cm-ring .cm-trail.t1 { opacity: 0.7; }
.cm-ring .cm-trail.t2 { opacity: 0.36; }
.cm-ring .cm-trail.t3 { opacity: 0.14; }
.cm-ring .cm-head { fill: var(--cc); stroke: var(--ink); stroke-width: 3; transition: fill 200ms; }
.cm-ring .cm-head-glow { fill: var(--cc); opacity: 0.3; }
.cm-ring .cm-flash { stroke: #fff; stroke-width: 16; opacity: 0; }
.cm-ring .cm-flash.hit { animation: cm-ringflash 460ms var(--ease); }
/* a win charging up: the lit zone sweeps on to a full ring behind a bright head, the % counting to 100 */
.cm-fillhead { opacity: 0; transition: opacity 150ms; }
.cm.charging .cm-fillhead { opacity: 1; }
.cm-ring .cm-fh { fill: #fff; stroke: var(--ink); stroke-width: 3; }
.cm-ring .cm-fh-glow { fill: var(--c); opacity: 0.55; }
.cm.charging .cm-ring .cm-zone { stroke-width: 11; }
.cm.charging .cm-ring .cm-halo { opacity: 0.4; }
.cm.charging .cm-badge { border-color: #fff; box-shadow: 0 0 0 1.5px var(--ink), 0 0 22px -2px var(--c); }
.cm.maxed .cm-badge { scale: 1.1; }
.cm.on.maxed .cm-badge { animation: cm-max 420ms var(--spring); }
.cm.maxed .cm-pct { color: #f6fff0; text-shadow: 0 0 10px var(--c); }

/* the % on slot reels, in a pill over the bottom of the ring */
.cm-badge { position: absolute; left: 0; top: 3.65em; translate: -50% 0; display: flex; align-items: center; padding: 0.12em 0.62em 0.16em; border-radius: 999px; background: rgba(8, 14, 26, 0.88); border: 2px solid var(--c); box-shadow: 0 0 0 1.5px var(--ink), 0 0 16px -4px var(--c); transition: border-color 300ms, box-shadow 300ms, opacity 260ms; }
.cm.on .cm-badge { animation: cm-badge-in 420ms var(--spring) 60ms backwards; }   /* (not 'both': a held end would pin opacity) */
.cm.win .cm-badge, .cm.lose .cm-badge, .cm.fizzle .cm-badge { opacity: 0; }
.cm-pct { display: flex; align-items: baseline; font-size: 1.8em; font-weight: 900; line-height: 1; color: #fff; }
.cm-reel { display: inline-block; height: 1em; overflow: hidden; -webkit-mask-image: linear-gradient(transparent, #000 16%, #000 84%, transparent); mask-image: linear-gradient(transparent, #000 16%, #000 84%, transparent); }
.cm-strip { display: block; will-change: transform; }
.cm-strip i { display: block; height: 1em; font-style: normal; text-align: center; }
.cm-reel.stop { animation: cm-thunk 280ms var(--spring); }
.cm-sign { font-size: 0.56em; margin-left: 0.06em; color: var(--c); }

/* the three checks: gems under the pill */
.cm-gems { position: absolute; left: 0; top: 6.55em; translate: -50% 0; display: flex; gap: 0.75em; }
.cm-gems i { width: 0.92em; height: 0.92em; rotate: 45deg; border-radius: 0.22em; background: rgba(8, 14, 26, 0.82); border: 2.5px solid rgba(255, 255, 255, 0.55); box-shadow: 0 0 0 1.5px var(--ink); transition: background 220ms, border-color 220ms, scale 280ms var(--spring), box-shadow 220ms; }
.cm-gems i.active { border-color: #fff; animation: cm-gem-live 0.5s ease-in-out infinite; }
.cm-gems i.pass { background: linear-gradient(135deg, #f0ffff, var(--accent) 50%, var(--accent-2)); border-color: #f0ffff; scale: 1.2; box-shadow: 0 0 0 1.5px var(--ink), 0 0 12px var(--accent); animation: cm-gem-pop 380ms var(--spring); }
.cm-gems i.free { background: linear-gradient(135deg, #f7ffe4, var(--accent-2)); border-color: #f7ffe4; scale: 1.05; }
.cm-gems i.gold { background: linear-gradient(135deg, #fffbe6, var(--gold) 50%, #ff9a2a); border-color: #fff6d0; scale: 1.22; box-shadow: 0 0 0 1.5px var(--ink), 0 0 14px var(--gold); }
.cm-gems i.fail { background: linear-gradient(135deg, #ffd6dc, var(--bad)); border-color: #ffd6dc; animation: cm-gem-crack 420ms ease-in-out; }
.cm.win .cm-gems i { animation: cm-gem-pop 420ms var(--spring) both; }
.cm.win .cm-gems i:nth-child(2) { animation-delay: 90ms; }
.cm.win .cm-gems i:nth-child(3) { animation-delay: 180ms; }

/* the result: a word above the ring, the new pal's card below */
.cm-word { position: absolute; left: 0; bottom: 5.35em; translate: -50% 0; }
.cm-word .big, .cap-note .big { display: inline-grid; font-size: 2.4em; font-weight: 900; line-height: 1; white-space: nowrap; }
.cm-word .big > span, .cap-note .big > span { grid-area: 1 / 1; }
.cm-word .ink, .cap-note .ink { color: var(--ink); -webkit-text-stroke: 0.2em var(--ink); text-shadow: 0 0.09em 0 var(--ink); }
.cm-word .fill, .cap-note .fill { color: #fff; }
.cm-word.good .fill { background: linear-gradient(180deg, #f2ffe0, #7cff9a 55%, #2fd66a); -webkit-background-clip: text; background-clip: text; color: transparent; }
.cm-word.crit .fill { background: linear-gradient(100deg, transparent 40%, rgba(255, 255, 255, 0.95) 50%, transparent 60%), linear-gradient(180deg, #fffbe0, #ffd35a 50%, #ff8a2a);
  background-size: 250% 100%, 100% 100%; -webkit-background-clip: text; background-clip: text; color: transparent; animation: cm-shine 1.5s linear 0.4s infinite; }
.cm-word.bad .fill { background: linear-gradient(180deg, #ffe0e4, #ff7a8c 55%, #e8384f); -webkit-background-clip: text; background-clip: text; color: transparent; }
.cm-word:not([hidden]) .big { animation: cm-word-in 560ms var(--spring) both; }
.cm-word.bad:not([hidden]) .big { animation: shake-x 0.45s ease-in-out both; }
.cm-card { position: absolute; left: 0; top: 8.1em; translate: -50% 0; display: flex; align-items: center; gap: 0.6em; padding: 0.42em 0.95em 0.42em 0.42em; border-radius: 999px; background: var(--panel); border: 2px solid rgba(63, 224, 255, 0.55); box-shadow: 0 0 0 1.5px var(--ink), var(--shadow-sm); white-space: nowrap; }
.cm-card:not([hidden]) { animation: pop 440ms var(--spring) 140ms both; }
.cm.crit .cm-card { border-color: rgba(255, 211, 90, 0.75); }
.cm-card .badge { font-size: 0.72em; }
.cm-card-main { display: flex; flex-direction: column; gap: 0.08em; }
.cm-card small { color: var(--text-2); font-weight: 700; }
.cm-where { display: inline-flex; align-items: center; gap: 0.25em; font-size: 0.8em; }
.cm-where .ico { width: 1.05em; height: 1.05em; color: var(--accent); }
.cm-new { position: absolute; top: -0.85em; right: -0.5em; padding: 0.18em 0.6em; border-radius: 999px; background: linear-gradient(180deg, #eaffa6, var(--accent-2)); color: #172600; font-size: 0.72em; font-weight: 900; box-shadow: 0 0 0 1.5px var(--ink), 0 0 12px rgba(184, 255, 74, 0.6); animation: cm-new 700ms var(--spring) 420ms both; }

/* burst and shatter: rays, a shockwave, sparks / shards */
.cm-rays { position: absolute; left: -10.5em; top: -10.5em; width: 21em; height: 21em; border-radius: 50%; opacity: 0;
  background: repeating-conic-gradient(rgba(184, 255, 74, 0.3) 0 7deg, transparent 7deg 20deg);
  -webkit-mask-image: radial-gradient(circle, #000 18%, transparent 68%); mask-image: radial-gradient(circle, #000 18%, transparent 68%); }
.cm.crit .cm-rays { background: repeating-conic-gradient(rgba(255, 211, 90, 0.4) 0 7deg, transparent 7deg 20deg); }
.cm.win .cm-rays { animation: cm-rays 1.9s var(--ease) both; }
.cm-wave { position: absolute; left: -5.2em; top: -5.2em; width: 10.4em; height: 10.4em; border-radius: 50%; border: 0.3em solid #fff; opacity: 0; }
.cm.win .cm-wave { animation: cm-wave 700ms var(--ease) both; }
.cm.crit .cm-wave { border-color: #fff3b8; }
.cm.lose .cm-wave { border-color: var(--bad); animation: cm-wave 520ms var(--ease) both; }
.cm-sparks i, .cm-shards i { position: absolute; left: 0; top: 0; width: var(--s, 0.5em); height: var(--s, 0.5em); margin: calc(var(--s, 0.5em) / -2) 0 0 calc(var(--s, 0.5em) / -2); background: var(--sc, #fff); opacity: 0; }
.cm-sparks i { border-radius: 50%; box-shadow: 0 0 0.4em var(--sc, #fff); }
.cm-sparks i:nth-child(3n) { border-radius: 0.08em; rotate: 45deg; }
.cm.win .cm-sparks i { animation: cm-spark 1s cubic-bezier(0.12, 0.75, 0.3, 1) var(--dl, 0ms) both; }
.cm-shards i { width: calc(var(--s, 0.5em) * 1.6); height: var(--s, 0.5em); clip-path: polygon(0 0, 100% 35%, 55% 100%); filter: drop-shadow(0 0 0.15em var(--sc, #fff)); }
.cm.lose .cm-shards i { animation: cm-shard 800ms cubic-bezier(0.2, 0.6, 0.4, 1) var(--dl, 0ms) both; }

/* shared by the meters: the last check's darkening edge (a red heartbeat pulse), result flashes, "Missed" */
.cap-tension { position: absolute; inset: 0; opacity: 0; transition: opacity 380ms; background: radial-gradient(ellipse at center, transparent 42%, rgba(4, 8, 20, 0.6) 100%); }
.cap-tension.on { opacity: 1; }
.cap-tension::after { content: ""; position: absolute; inset: 0; opacity: 0; background: radial-gradient(ellipse at center, transparent 40%, rgba(150, 12, 40, 0.42) 100%); }
.cap-tension.beat::after { animation: cm-tension-beat 640ms ease-out; }
.cap-flash { position: absolute; inset: 0; opacity: 0; --fx: 50%; --fy: 40%; }
.cap-flash.good { background: radial-gradient(circle at var(--fx) var(--fy), rgba(255, 255, 255, 0.6), rgba(184, 255, 74, 0.18) 22%, transparent 55%); }
.cap-flash.gold { background: radial-gradient(circle at var(--fx) var(--fy), rgba(255, 251, 230, 0.75), rgba(255, 211, 90, 0.3) 25%, transparent 62%); }
.cap-flash.bad { background: radial-gradient(ellipse at center, transparent 48%, rgba(255, 40, 70, 0.55) 100%); }
.cap-flash.go { animation: cm-flash 640ms var(--ease) both; }
.cap-note { position: absolute; left: 50%; top: 26%; translate: -50% 0; }
.cap-note.go .big { animation: shake-x 0.45s ease-in-out both; }


/* ----------------------------------------------------------------------------- mini cast bar (ui/castmini.js) */
/* someone else's cast, just under their name tag or plate: absolute, so the name never moves when a cast starts; in em,
   so it follows the name's size on phone, tablet and desktop */
.mcast { position: absolute; left: 50%; top: calc(100% + 0.3em); width: 8.4em; height: 1.4em; transform: translateX(-50%); display: none;
  border-radius: 0.45em; overflow: hidden; background: rgba(8, 14, 26, 0.8); border: 1px solid rgba(255, 255, 255, 0.16); pointer-events: none; }
.mcast.on, .mcast.stopped { display: block; }
.mcast i { position: absolute; inset: 0; transform-origin: 0 50%; background: var(--school, var(--accent)); opacity: 0.88; }
.mcast span { position: relative; display: block; padding: 0 0.4em; font-size: 0.9em; line-height: 1.55; font-weight: 800; font-style: normal;
  color: #fff; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85); }
.mcast.stopped i { background: var(--bad); }

/* ----------------------------------------------------------------------------- badges (pal portraits) and chips */
.badge { position: relative; flex: none; width: 3.2em; height: 3.2em; border-radius: 50%; display: grid; place-items: center; color: #fff;
  background: radial-gradient(circle at 34% 28%, var(--b2, #7a8aa8) 0%, var(--b1, #3a4660) 72%); box-shadow: inset 0 -0.28em 0 rgba(0, 0, 0, 0.22), 0 0 0 2.5px var(--ink); }
.badge > b { font-size: 1.4em; font-weight: 900; line-height: 1; text-shadow: 0 2px 0 var(--ink), 0 0 2px var(--ink), 0 0 2px var(--ink); }
.badge > .ico.el { position: absolute; right: -0.25em; bottom: -0.2em; width: 1.35em; height: 1.35em; }
.badge > .ico.mk { position: absolute; top: -0.4em; width: 1.25em; height: 1.25em; filter: drop-shadow(0 1px 0 var(--ink)) drop-shadow(0 0 1px var(--ink)); }
.badge > .ico.mk.alpha { left: 50%; margin-left: -0.62em; color: #ff6a7c; }
.badge > .ico.mk.lucky { right: -0.3em; top: -0.25em; color: var(--gold); }
.badge.big { font-size: 1.7em; }
.badge > .ico.item { width: 64%; height: 64%; }
.badge.unknown { background: radial-gradient(circle at 34% 28%, #2a3654, #161f33 72%); }
.badge.unknown > b { color: #56668a; text-shadow: none; }
.el-chip { display: inline-flex; align-items: center; gap: 0.35em; padding: 0.18em 0.65em 0.18em 0.22em; border-radius: 999px; background: rgba(255, 255, 255, 0.07); border: 1.5px solid var(--line); font-size: 0.82em; font-weight: 800; white-space: nowrap; }
.el-chip > .ico { width: 1.35em; height: 1.35em; }
.tag { display: inline-flex; align-items: center; gap: 0.25em; padding: 0.12em 0.55em; border-radius: 999px; font-size: 0.75em; font-weight: 900; background: rgba(255, 255, 255, 0.08); white-space: nowrap; }
.tag .ico { width: 1.1em; height: 1.1em; }
.tag.alpha { color: #ff8a9a; background: rgba(255, 90, 110, 0.14); }
.tag.lucky { color: var(--gold); background: rgba(255, 211, 90, 0.14); }
.minibar { height: 0.42em; border-radius: 999px; background: rgba(0, 0, 0, 0.45); overflow: hidden; }
.minibar i { display: block; height: 100%; border-radius: inherit; background: linear-gradient(90deg, #ff6a86, var(--hp)); }
.minibar.exp i { background: linear-gradient(90deg, #9a6aff, var(--exp)); }

/* ----------------------------------------------------------------------------- Esc menu */
.menu { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; opacity: 0; visibility: hidden; transition: opacity 200ms, visibility 0s linear 200ms; }
.menu.on { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity 200ms; }
.menu-back { position: absolute; inset: 0; background: rgba(4, 8, 16, 0.5); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.menu-panel {
  position: relative; display: grid; overflow: hidden;
  width: min(74em, calc(100vw - 2 * var(--gap) - var(--safe-l) - var(--safe-r)));
  height: min(48em, calc(100dvh - 2 * var(--gap) - var(--safe-t) - var(--safe-b)));
  grid-template-columns: 13.5em minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "tabs head" "tabs body" "tabs foot";
  background: var(--panel-menu); border: 2px solid var(--line-2); border-radius: var(--r-lg); box-shadow: 0 0 0 3px var(--ink), var(--shadow);
  transform: scale(0.97) translateY(0.6em); transition: transform 260ms var(--spring);
}
.menu.on .menu-panel { transform: none; }
.menu-head { grid-area: head; display: flex; align-items: center; gap: 1em; min-width: 0; padding: 0.95em 1.1em 0.8em 1.4em; border-bottom: 2px solid var(--line); }
.menu-title { min-width: 0; }
.menu-title h2 { margin: 0; font-size: 1.5em; font-weight: 900; line-height: 1.1; }
.menu-sub { display: flex; flex-wrap: wrap; gap: 0.35em 1em; margin-top: 0.25em; color: var(--text-2); font-size: 0.82em; font-weight: 700; }
.menu-sub span { display: inline-flex; align-items: center; gap: 0.3em; white-space: nowrap; }
.menu-sub .ico { width: 1.1em; height: 1.1em; }
.menu-sub .gold .ico { color: var(--gold); }
.menu-sub .gold .coins { font-weight: 800; }
.menu-actions { margin-left: auto; display: flex; gap: 0.5em; flex: none; }
.resume .ico.x { display: none; }
@media (max-width: 599px), (max-height: 499px) { .resume .ico.play { display: none; } .resume .ico.x { display: inline-flex; } }
.menu-tabs { grid-area: tabs; display: flex; flex-direction: column; gap: 0.3em; padding: 1em 0.7em; background: rgba(255, 255, 255, 0.025); border-right: 2px solid var(--line); overflow-y: auto; scrollbar-width: none; }
.menu-tabs::-webkit-scrollbar { display: none; }
.menu-brand { display: flex; align-items: center; gap: 0.45em; padding: 0.2em 0.6em 0.9em; font-weight: 900; font-size: 1.05em; }
.menu-brand .ico { width: 1.6em; height: 1.6em; }
.menu-tab { pointer-events: auto; position: relative; display: flex; align-items: center; gap: 0.75em; min-height: max(2.9em, var(--tap)); padding: 0 0.9em; border-radius: var(--r); border: 2px solid transparent; background: transparent; color: var(--text-2); font-weight: 800; text-align: left; cursor: pointer; transition: background 120ms, color 120ms, border-color 120ms; touch-action: manipulation; }
.menu-tab .ico { width: 1.4em; height: 1.4em; }
.menu-tab:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }
.menu-tab[aria-selected="true"] { color: #fff; background: linear-gradient(90deg, rgba(63, 224, 255, 0.24), rgba(63, 224, 255, 0.05)); border-color: rgba(63, 224, 255, 0.45); }
.menu-tab[aria-selected="true"] .ico { color: var(--accent); }
.menu-tab .cnt { margin-left: auto; font-size: 0.75em; color: var(--text-3); font-variant-numeric: tabular-nums; }
.menu-tab.quit { margin-top: auto; color: #ff9aa6; }
.menu-tab.quit .ico { color: #ff7a8a; }
.menu-body { grid-area: body; position: relative; display: grid; grid-template-columns: minmax(0, 1fr); min-height: 0; overflow: hidden; }
.menu-body.has-side { grid-template-columns: minmax(0, 1fr) min(23em, 40%); }
.page { min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 1.2em 1.4em 1.8em; scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.2) transparent; animation: page-in 220ms var(--ease); }
.page.flush { padding: 0; overflow: hidden; position: relative; }
.side { position: relative; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 1.2em; border-left: 2px solid var(--line); background: rgba(255, 255, 255, 0.02); }
.side-close { display: none; }
.menu-foot { grid-area: foot; display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.4em 1.2em; padding: 0.55em 1.2em; border-top: 2px solid var(--line); color: var(--text-3); font-size: 0.78em; }
.menu-foot span { display: inline-flex; align-items: center; gap: 0.4em; }
html.is-touch .menu-foot { display: none; }

/* ----------------------------------------------------------------------------- page building blocks */
.pg-h { display: flex; align-items: center; gap: 0.6em; margin: 1.5em 0 0.7em; font-size: 0.76em; font-weight: 900; letter-spacing: 0.13em; text-transform: uppercase; color: var(--text-3); }
.pg-h:first-child { margin-top: 0; }
.pg-h .r { margin-left: auto; letter-spacing: 0.02em; text-transform: none; font-size: 1.1em; color: var(--text-2); }
.toolbar { display: flex; flex-wrap: wrap; gap: 0.6em; align-items: center; margin-bottom: 1em; }
.search { pointer-events: auto; flex: 1 1 12em; display: flex; align-items: center; gap: 0.5em; min-height: max(2.75em, var(--tap)); padding: 0 0.9em; border-radius: 999px; background: rgba(0, 0, 0, 0.35); border: 2px solid var(--line-2); }
.search .ico { width: 1.2em; height: 1.2em; color: var(--text-3); }
.search input { flex: 1; align-self: stretch; min-width: 0; border: 0; outline: 0; background: transparent; font-weight: 700; user-select: text; -webkit-user-select: text; }
.search input::placeholder { color: var(--text-3); }
.chips { display: flex; flex-wrap: wrap; gap: 0.45em; }
.chip { pointer-events: auto; display: inline-flex; align-items: center; gap: 0.4em; min-height: max(2.5em, 40px); padding: 0 1em; border-radius: 999px; border: 2px solid var(--line-2); background: rgba(255, 255, 255, 0.05); color: var(--text-2); font-weight: 800; cursor: pointer; white-space: nowrap; touch-action: manipulation; transition: background 120ms, border-color 120ms, color 120ms; }
.chip .ico { width: 1.15em; height: 1.15em; }
.chip:hover { color: var(--text); }
.chip[aria-pressed="true"], .chip[aria-selected="true"] { background: rgba(63, 224, 255, 0.18); border-color: rgba(63, 224, 255, 0.62); color: #fff; }
.chip .n { color: var(--text-3); font-size: 0.85em; }
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8.2em, 1fr)); gap: 0.7em; }
.empty { display: flex; flex-direction: column; align-items: center; gap: 0.6em; padding: 3em 1em; text-align: center; color: var(--text-3); }
.empty > .ico { width: 3em; height: 3em; opacity: 0.5; }
.empty b { color: var(--text-2); font-size: 1.05em; }
.progress { display: flex; align-items: center; gap: 0.8em; padding: 0.9em 1em; margin-bottom: 1em; border-radius: var(--r); background: rgba(255, 255, 255, 0.04); border: 2px solid var(--line); }
.progress .minibar { flex: 1; height: 0.6em; }
.progress .minibar i { background: linear-gradient(90deg, var(--accent), var(--accent-2)); }
.progress b { font-variant-numeric: tabular-nums; }

/* pal cards (party) and tiles (box, dex, bag) */
.pals { display: flex; flex-direction: column; gap: 0.6em; }
.pal { pointer-events: auto; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 0.9em; width: 100%; min-height: 4.8em; padding: 0.7em 1em 0.7em 0.8em; border-radius: var(--r); border: 2px solid var(--line); background: rgba(255, 255, 255, 0.04); text-align: left; cursor: pointer; transition: background 120ms, border-color 120ms; touch-action: manipulation; }
.pal:hover { background: rgba(255, 255, 255, 0.07); }
.pal[aria-pressed="true"] { border-color: rgba(63, 224, 255, 0.62); background: rgba(63, 224, 255, 0.1); }
.pal-main { min-width: 0; display: flex; flex-direction: column; gap: 0.25em; }
.pal-name { display: flex; align-items: center; gap: 0.4em; font-weight: 900; font-size: 1.05em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pal-name .ico { width: 1em; height: 1em; }
.pal-name .ico.male { color: #6ab8ff; }
.pal-name .ico.female { color: #ff8ac8; }
.pal-sub { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3em 0.6em; color: var(--text-2); font-size: 0.8em; }
.pal-hp { display: flex; align-items: center; gap: 0.5em; font-size: 0.75em; color: var(--text-3); font-variant-numeric: tabular-nums; }
.pal-hp .minibar { flex: 1; max-width: 12em; }
.pal-lv { font-size: 0.8em; font-weight: 900; color: var(--text-2); text-align: right; line-height: 1.1; }
.pal-lv b { display: block; font-size: 1.6em; color: var(--text); }
.pal.slot-empty { cursor: default; border-style: dashed; color: var(--text-3); grid-template-columns: auto 1fr; }
.pal.slot-empty .badge { background: transparent; box-shadow: inset 0 0 0 2px var(--line-2); }
.tile { pointer-events: auto; position: relative; display: flex; flex-direction: column; align-items: center; gap: 0.45em; min-height: 8em; padding: 1em 0.5em 0.75em; border-radius: var(--r); border: 2px solid var(--line); background: rgba(255, 255, 255, 0.04); text-align: center; cursor: pointer; transition: background 120ms, border-color 120ms; touch-action: manipulation; }
.tile:hover { background: rgba(255, 255, 255, 0.07); }
.tile[aria-pressed="true"] { border-color: rgba(63, 224, 255, 0.62); background: rgba(63, 224, 255, 0.1); }
.tile-name { font-weight: 800; font-size: 0.88em; line-height: 1.15; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile-sub { color: var(--text-3); font-size: 0.74em; font-weight: 700; }
.tile .corner { position: absolute; top: 0.45em; left: 0.6em; font-size: 0.7em; font-weight: 900; color: var(--text-3); }
.tile .ok { position: absolute; top: 0.4em; right: 0.45em; width: 1.15em; height: 1.15em; color: var(--good); }
.tile .qty { position: absolute; top: 0.4em; right: 0.55em; font-size: 0.82em; font-weight: 900; font-variant-numeric: tabular-nums; }
.tile > .ico.item { width: 2.6em; height: 2.6em; filter: drop-shadow(0 2px 0 rgba(0, 0, 0, 0.3)); }
.tile.dim { opacity: 0.55; }
.tile.eq { border-color: rgba(184, 255, 74, 0.6); }
.tile .eq-tag { position: absolute; top: 0.4em; left: 0.5em; width: 1.2em; height: 1.2em; color: var(--accent-2); }

/* detail panel (side column on desktop, bottom sheet below 1024px) */
.det { display: flex; flex-direction: column; gap: 1em; }
.det-top { display: flex; align-items: center; gap: 1em; }
.det-name { font-size: 1.4em; font-weight: 900; line-height: 1.1; overflow-wrap: anywhere; }
.det-sp { color: var(--text-2); font-size: 0.85em; margin-top: 0.2em; }
.det-tags { display: flex; flex-wrap: wrap; gap: 0.35em; margin-top: 0.45em; }
.det-desc { margin: 0; color: var(--text-2); font-weight: 600; line-height: 1.5; }
.stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5em; }
.stat { display: flex; align-items: center; gap: 0.5em; padding: 0.55em 0.75em; border-radius: var(--r-sm); background: rgba(255, 255, 255, 0.04); border: 1.5px solid var(--line); font-size: 0.9em; min-width: 0; }
.stat > .ico { width: 1.2em; height: 1.2em; color: var(--text-3); }
.stat span { color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.stat b { margin-left: auto; font-variant-numeric: tabular-nums; white-space: nowrap; }
.stat.wide { grid-column: 1 / -1; }
.stat.wide span { flex: none; }
.stat.wide b { white-space: normal; text-align: right; min-width: 0; }
.det-bars { display: flex; flex-direction: column; gap: 0.5em; }
.det-bar { display: grid; grid-template-columns: 3.4em 1fr auto; align-items: center; gap: 0.6em; font-size: 0.82em; color: var(--text-2); }
.det-bar .minibar { height: 0.55em; }
.det-bar b { color: var(--text); font-variant-numeric: tabular-nums; }
.det-actions { display: flex; flex-wrap: wrap; gap: 0.5em; }
.det-actions .btn { flex: 1 1 auto; }
.det-note { font-size: 0.8em; color: var(--text-3); }
.side-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.6em; height: 100%; min-height: 12em; text-align: center; color: var(--text-3); }
.side-empty .ico { width: 2.6em; height: 2.6em; opacity: 0.45; }

/* settings */
.set-jump { position: sticky; top: 0; z-index: 1; margin: -1.2em -1.4em 1em; padding: 0.9em 1.4em 0.7em; background: linear-gradient(180deg, var(--panel-menu) 75%, rgba(11, 18, 32, 0)); }
.set-sec { margin-bottom: 1.6em; scroll-margin-top: 4em; }
.set-row { display: grid; grid-template-columns: minmax(10em, 1fr) minmax(13em, 1.25fr); align-items: center; gap: 0.6em 1.2em; min-height: 3.6em; padding: 0.6em 0.2em; border-bottom: 1.5px solid var(--line); }
.set-row.bool { cursor: pointer; }
.set-row .lbl b { display: block; font-weight: 800; }
.set-row .lbl small { display: block; margin-top: 0.15em; color: var(--text-3); font-weight: 600; font-size: 0.8em; line-height: 1.35; }
.seg { display: flex; gap: 0.25em; padding: 0.25em; border-radius: 999px; background: rgba(0, 0, 0, 0.38); border: 2px solid var(--line); }
.seg button { pointer-events: auto; flex: 1; min-height: max(2.3em, 40px); padding: 0 0.6em; border: 0; border-radius: 999px; background: transparent; color: var(--text-2); font-weight: 800; cursor: pointer; white-space: nowrap; touch-action: manipulation; transition: background 120ms, color 120ms; }
.seg button[aria-checked="true"] { background: var(--accent); color: var(--ink); box-shadow: 0 2px 0 var(--accent-deep); }
.switch { pointer-events: auto; justify-self: end; position: relative; width: 3.5em; height: 2em; min-height: 32px; padding: 0; border-radius: 999px; border: 2px solid var(--line-2); background: rgba(0, 0, 0, 0.42); cursor: pointer; transition: background 160ms, border-color 160ms; touch-action: manipulation; }
.switch::after { content: ""; position: absolute; top: 50%; left: 0.2em; width: 1.4em; height: 1.4em; border-radius: 50%; background: #cfd8ea; box-shadow: 0 2px 0 rgba(0, 0, 0, 0.35); transform: translateY(-50%); transition: transform 200ms var(--spring), background 160ms; }
.switch[aria-checked="true"] { background: var(--accent); border-color: #b4f6ff; }
.switch[aria-checked="true"]::after { background: #fff; transform: translate(1.5em, -50%); }
.rng { display: flex; align-items: center; gap: 0.8em; }
.rng input { pointer-events: auto; flex: 1; min-width: 0; height: 40px; margin: 0; background: transparent; cursor: pointer; -webkit-appearance: none; appearance: none; --p: 50%; touch-action: pan-y; }
.rng input::-webkit-slider-runnable-track { height: 0.55em; border-radius: 999px; background: linear-gradient(90deg, var(--accent) var(--p), rgba(255, 255, 255, 0.14) var(--p)); }
.rng input::-webkit-slider-thumb { -webkit-appearance: none; width: 1.55em; height: 1.55em; margin-top: -0.5em; border-radius: 50%; background: #fff; border: 3px solid var(--accent); box-shadow: 0 2px 0 rgba(0, 0, 0, 0.35); }
.rng input::-moz-range-track { height: 0.55em; border-radius: 999px; background: rgba(255, 255, 255, 0.14); }
.rng input::-moz-range-progress { height: 0.55em; border-radius: 999px; background: var(--accent); }
.rng input::-moz-range-thumb { width: 1.2em; height: 1.2em; border-radius: 50%; background: #fff; border: 3px solid var(--accent); }
.rng output { min-width: 3.8em; text-align: right; font-weight: 800; font-variant-numeric: tabular-nums; }
.presets { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0.5em; margin-bottom: 0.5em; }
.preset { pointer-events: auto; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.15em; min-height: 3.8em; padding: 0.4em; border-radius: var(--r); border: 2px solid var(--line-2); background: rgba(255, 255, 255, 0.04); font-weight: 900; cursor: pointer; touch-action: manipulation; transition: background 120ms, border-color 120ms; }
.preset small { color: var(--text-3); font-weight: 700; font-size: 0.7em; }
.preset[aria-checked="true"] { border-color: var(--accent); background: rgba(63, 224, 255, 0.16); }
.preset[aria-checked="true"] small { color: var(--text-2); }
.custom-note { display: flex; align-items: center; gap: 0.45em; margin: 0.2em 0 0.4em; color: var(--warn); font-size: 0.8em; font-weight: 800; }
.custom-note .ico { width: 1.1em; height: 1.1em; }
.set-foot { display: flex; justify-content: flex-end; margin-top: 1em; }

/* controls */
.ctl-row { display: grid; grid-template-columns: minmax(9em, 1fr) minmax(0, 1.4fr); align-items: center; gap: 0.5em 1em; min-height: 3.2em; padding: 0.45em 0.2em; border-bottom: 1.5px solid var(--line); }
.ctl-row .keys { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4em; justify-content: flex-end; }
.ctl-row .touch-hint { color: var(--text-2); font-size: 0.9em; text-align: right; }
.ctl-row .rebind { min-height: 2.2em; padding: 0 0.8em; font-size: 0.8em; }
.ctl-row.listening { background: rgba(63, 224, 255, 0.08); }
.ctl-row .lbl small { display: block; margin-top: 0.15em; color: var(--text-3); font-size: 0.78em; font-weight: 700; }
.ctl-row .lbl small.ctl-changed { display: inline-block; margin: 0 0 0 0.5em; padding: 0.1em 0.5em; border-radius: 999px; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent); font-size: 0.7em; font-weight: 900; letter-spacing: 0.04em; text-transform: uppercase; }
/* a binding is its own button (tap to change that slot): a keycap with a full touch target */
.keycap.ctl-slot { min-width: max(3.2em, var(--tap)); height: auto; min-height: max(2.4em, var(--tap)); border: 0; font-family: inherit; cursor: pointer;
  color: var(--ink); transition: transform 90ms var(--ease), box-shadow 120ms; }
.keycap.ctl-slot:not(:disabled):active { transform: translateY(2px); box-shadow: 0 1px 0 #97a8c6, 0 0 0 2px var(--ink); }
.keycap.ctl-slot:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.keycap.ctl-slot:disabled { cursor: default; opacity: 0.75; }
.keycap.ctl-slot.conflict { background: #fff3cf; box-shadow: 0 3px 0 #c9a24a, 0 0 0 2px var(--ink), 0 0 0 4px color-mix(in srgb, var(--warn) 55%, transparent); }
.keycap.ctl-add { background: transparent; color: var(--text-2); box-shadow: inset 0 0 0 2px var(--line-2); }
.ctl-row .ctl-reset { width: var(--tap); height: var(--tap); }
.ctl-wait { display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: 0.4em; }
.ctl-wait .btn { min-height: var(--tap); padding: 0 0.9em; font-size: 0.8em; }
.ctl-warn { grid-column: 1 / -1; display: flex; align-items: center; gap: 0.4em; margin: -0.1em 0 0.1em; color: var(--warn); font-size: 0.8em; font-weight: 800; }
.ctl-warn .ico { flex: none; width: 1.1em; height: 1.1em; }
.ctl-note { margin-top: 1em; color: var(--text-3); font-size: 0.82em; line-height: 1.45; }

/* bag */
.bag-top { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6em 1em; margin-bottom: 1em; }
.gold-pill { display: inline-flex; align-items: center; gap: 0.4em; min-height: var(--tap); padding: 0.35em 0.9em; border-radius: 999px; background: rgba(255, 211, 90, 0.12); border: 2px solid rgba(255, 211, 90, 0.4); font-weight: 900; font-variant-numeric: tabular-nums; }
.gold-pill .ico { width: 1.4em; height: 1.4em; color: var(--gold); }
/* money as coins (ui/coins.js): each count beside a coin in its colour (--c: content/currency/money.js), never wrapped */
.coins { display: inline-flex; align-items: center; gap: 0.5em; white-space: nowrap; font-weight: 900; font-variant-numeric: tabular-nums; }
.coin { display: inline-flex; align-items: center; gap: 0.2em; }
.coin i { flex: none; width: 0.82em; height: 0.82em; border-radius: 50%; box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.55), inset 0 -1px 0 rgba(0, 0, 0, 0.3);
  background: radial-gradient(circle at 36% 30%, color-mix(in srgb, var(--c) 30%, #fff) 0 18%, var(--c) 48%, color-mix(in srgb, var(--c) 60%, #000) 100%); }
.coins.neg { color: #ff6a7c; }
.tt-line .coins { margin-left: 0.25em; }

/* map */
.map-cv { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; cursor: grab; background: #1d5fa8; pointer-events: auto; }
.map-cv.drag { cursor: grabbing; }
.map-ctl { position: absolute; right: 1em; bottom: 1em; display: flex; flex-direction: column; gap: 0.5em; }
.map-ctl .btn { width: max(3em, var(--tap)); height: max(3em, var(--tap)); padding: 0; border-radius: var(--r); background: var(--panel); }
.map-legend { position: absolute; left: 1em; top: 1em; right: 1em; display: flex; flex-wrap: wrap; gap: 0.4em; pointer-events: none; }
.map-legend .chip { background: var(--panel); min-height: max(2.3em, 40px); }
.map-info { position: absolute; left: 1em; bottom: 1em; display: flex; flex-direction: column; gap: 0.35em; padding: 0.5em 0.8em; border-radius: var(--r-sm); background: var(--panel); border: 2px solid var(--line); font-size: 0.8em; font-weight: 800; color: var(--text-2); pointer-events: none; font-variant-numeric: tabular-nums; }
.map-scale { display: flex; align-items: center; gap: 0.5em; }
.map-scale i { display: block; height: 0.45em; border: 2px solid #fff; border-top: 0; }
.map-tip { position: absolute; left: 0; top: 0; padding: 0.35em 0.75em; border-radius: 999px; background: var(--panel-solid); border: 2px solid var(--line-2); font-weight: 800; font-size: 0.85em; white-space: nowrap; pointer-events: none; transform: translate(-50%, -150%); opacity: 0; transition: opacity 150ms; }
.map-tip.on { opacity: 1; }

/* ----------------------------------------------------------------------------- modals */
.modals { position: absolute; inset: 0; pointer-events: none; }
.modal { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: auto; padding: calc(var(--safe-t) + 1em) calc(var(--safe-r) + 1em) calc(var(--safe-b) + 1em) calc(var(--safe-l) + 1em); background: rgba(4, 8, 16, 0.58); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); animation: fade 180ms var(--ease) both; }
.modal-card { display: flex; flex-direction: column; gap: 1em; width: min(30em, 100%); max-height: 100%; overflow: hidden; padding: 1.4em; border-radius: var(--r-lg); background: var(--panel-solid); border: 2px solid var(--line-2); box-shadow: 0 0 0 3px var(--ink), var(--shadow); animation: pop 260ms var(--spring) both; }
.modal-card.wide { width: min(58em, 100%); height: min(46em, 100%); }
.modal-head { display: flex; align-items: center; gap: 0.8em; }
.modal-head h3 { margin: 0; font-size: 1.35em; font-weight: 900; flex: 1; }
.modal-body { min-height: 0; overflow-y: auto; overscroll-behavior: contain; color: var(--text-2); line-height: 1.5; }
.modal-body p { margin: 0 0 0.8em; }
.modal-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 0.6em; }
/* a full page (settings from the title) inside a wide modal: the page scrolls, not the modal */
.modal-card.wide .modal-body { flex: 1; display: flex; flex-direction: column; overflow: hidden; margin: 0 -1.4em -1.4em; }
.modal-card.wide .modal-body > .page { flex: 1; }

/* ----------------------------------------------------------------------------- tablet (below 1024px): tab bar on top, sheets */
@media (max-width: 1023px) {
  .menu-panel {
    width: calc(100vw - 1.6em - var(--safe-l) - var(--safe-r)); height: calc(100dvh - 1.6em - var(--safe-t) - var(--safe-b));
    grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto minmax(0, 1fr) auto; grid-template-areas: "head" "tabs" "body" "foot";
  }
  .menu-tabs { flex-direction: row; gap: 0.25em; padding: 0.5em 0.8em; border-right: 0; border-bottom: 2px solid var(--line); overflow-x: auto; overflow-y: hidden; }
  .menu-brand { display: none; }
  .menu-tab { flex: 1 0 auto; flex-direction: column; justify-content: center; gap: 0.25em; min-width: 5.4em; min-height: 3.7em; padding: 0.35em 0.6em; font-size: 0.85em; text-align: center; }
  .menu-tab .cnt { display: none; }
  .menu-tab.quit { margin: 0; }
  .menu-body.has-side { grid-template-columns: minmax(0, 1fr); }
  .side { position: absolute; left: 0; right: 0; bottom: 0; z-index: 3; max-height: 84%; padding: 0.9em 1.2em calc(var(--safe-b) + 1.2em); border-left: 0; border-top: 2px solid var(--line-2); border-radius: var(--r-lg) var(--r-lg) 0 0; background: var(--panel-solid); box-shadow: 0 -12px 32px rgba(0, 0, 0, 0.45); transform: translateY(105%); transition: transform 280ms var(--ease); visibility: hidden; }
  .side.open { transform: none; visibility: visible; }
  .side .side-empty { display: none; }
  .side-close { display: flex; justify-content: center; margin: -0.3em 0 0.6em; }
  .side-close .btn { min-height: max(2.2em, var(--tap)); padding: 0 1.4em; }
}
@media (max-width: 700px) { .compass { display: none; } }     /* too little room: the minimap's N E S W does the job */

/* ----------------------------------------------------------------------------- phone portrait (below 600px) */
@media (max-width: 599px) {
  .pv { --gap: 10px; --mm: 7.6em; }
  .title { justify-content: flex-end; gap: 2em; padding-bottom: calc(var(--safe-b) + 2em); background: linear-gradient(0deg, rgba(6, 12, 24, 0.92) 0%, rgba(6, 12, 24, 0.55) 45%, rgba(6, 12, 24, 0.2) 100%); }
  .title .logo { flex-direction: column; align-items: flex-start; gap: 0.3em; }
  .title-menu { width: 100%; }
  .title-foot { right: auto; left: 50%; transform: translateX(-50%); bottom: calc(var(--safe-b) + 0.5em); white-space: nowrap; }
  .menu-panel { width: 100vw; height: 100dvh; border: 0; border-radius: 0; box-shadow: none; padding: var(--safe-t) var(--safe-r) 0 var(--safe-l); }
  .menu-head { padding: 0.6em 0.6em 0.5em 1em; gap: 0.5em; }
  .menu-title h2 { font-size: 1.25em; }
  .menu-sub { font-size: 0.75em; gap: 0.2em 0.7em; }
  .menu-actions .btn .lbl { display: none; }
  .menu-actions .btn { width: var(--tap); padding: 0; }
  .menu-tabs { padding: 0.4em 0.6em; }
  .menu-tab { min-width: 4.7em; font-size: 0.76em; }
  .menu-foot { display: none; }
  .page { padding: 1em 1em calc(var(--safe-b) + 1.6em); }
  .set-jump { margin: -1em -1em 0.8em; padding: 0.7em 1em 0.6em; }
  .chips.scroll { flex-wrap: nowrap; overflow-x: auto; margin: 0 -1em; padding: 0 1em 0.2em; scrollbar-width: none; }
  .chips.scroll::-webkit-scrollbar { display: none; }
  .set-row { grid-template-columns: minmax(0, 1fr); }
  .set-row.bool { grid-template-columns: minmax(0, 1fr) auto; }
  .presets { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ctl-row { grid-template-columns: minmax(0, 1fr) auto; }
  .grid { grid-template-columns: repeat(auto-fill, minmax(6.6em, 1fr)); gap: 0.55em; }
  .tile { min-height: 7.2em; padding: 0.85em 0.35em 0.6em; }
  .modal { place-items: end center; padding: 0; }
  .modal-card { width: 100%; max-height: 92dvh; border-radius: var(--r-lg) var(--r-lg) 0 0; padding-bottom: calc(var(--safe-b) + 1.2em); animation: sheet 280ms var(--ease) both; }
  .modal-card.wide { height: 92dvh; }
  .modal-actions { flex-direction: column-reverse; }
  .modal-actions .btn { width: 100%; }
  .compass { display: none; }
  .toasts { top: calc(var(--safe-t) + 5em); width: calc(100vw - var(--mm) - 2 * var(--mm-pad) - 4 * var(--gap) - var(--safe-l) - var(--safe-r)); font-size: 0.9em; }
  .banner { font-size: 0.78em; top: 27%; }                /* all below the minimap cluster (~21% of a phone's height) */
  .wx-card { font-size: 0.8em; top: 35%; padding: 0.7em 1.2em; }   /* under the whole map cluster (its warning line too) */
  .place { top: 22%; font-size: 0.8em; }
  .cm-layer { font-size: 0.86em; }                        /* capture meters: a little smaller (capture.js clamps them on screen) */
  .cap-note { top: 32%; font-size: 0.9em; }
}

/* ----------------------------------------------------------------------------- touch: make room for core/touch.js */
html.is-touch .compass { display: none; }                /* a calmer phone HUD: the minimap's N E S W is the compass */

/* ----------------------------------------------------------------------------- short landscape (phones on their side) */
@media (max-height: 499px) and (orientation: landscape) {
  .pv { --gap: 8px; --mm: 6.6em; }
  .title { gap: 1.2em; padding-top: calc(var(--safe-t) + 1.2em); padding-bottom: calc(var(--safe-b) + 1.2em); }
  .title .logo-word { font-size: 2.6em; }
  .title-menu { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); width: min(34em, 100%); }
  .title-btn { min-height: 3em; }
  .loading { gap: 1.2em; }
  .menu-panel { width: 100vw; height: 100dvh; border: 0; border-radius: 0; box-shadow: none; padding: 0 var(--safe-r) 0 var(--safe-l);
    grid-template-columns: 5em minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); grid-template-areas: "tabs head" "tabs body"; }
  .menu-head { padding: calc(var(--safe-t) + 0.4em) 0.6em 0.4em 1em; }
  .menu-title h2 { font-size: 1.15em; }
  .menu-actions .btn .lbl { display: none; }
  .menu-actions .btn { width: var(--tap); padding: 0; }
  .menu-tabs { flex-direction: column; gap: 0.2em; padding: 0.4em 0.35em; border-right: 2px solid var(--line); border-bottom: 0; overflow-x: hidden; overflow-y: auto; }
  .menu-tab { flex: none; min-width: 0; min-height: max(3.1em, var(--tap)); padding: 0.25em; gap: 0.1em; font-size: 0.66em; }
  .menu-tab.quit { margin-top: auto; }
  .menu-foot { display: none; }
  .page { padding: 0.8em 1em calc(var(--safe-b) + 1em); }
  .side { max-height: 92%; }
  .compass { width: min(18em, 30vw); height: 2em; }
  .toasts { top: calc(var(--safe-t) + 4.4em); font-size: 0.85em; }
  .banner { top: 14%; font-size: 0.75em; }
  .wx-card { top: 14%; font-size: 0.75em; }
  .place { top: 12%; font-size: 0.75em; }
  .cm-layer { font-size: 0.74em; }
  .cap-note { top: 18%; font-size: 0.85em; }
  .modal-card.wide { height: 100%; }
}

/* ----------------------------------------------------------------------------- large screens: a little more room */
@media (min-width: 1600px) { .pv { --gap: 20px; } }

/* ----------------------------------------------------------------------------- motion */
@keyframes shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
@keyframes spin { to { transform: rotate(360deg); } }
@keyframes pop { 0% { transform: scale(0.6); opacity: 0; } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: scale(1); } }
@keyframes fade { from { opacity: 0; } }
@keyframes sheet { from { transform: translateY(100%); } }
@keyframes page-in { from { opacity: 0; transform: translateY(0.4em); } }
@keyframes toast-in { from { opacity: 0; transform: translateX(-1.2em) scale(0.96); } }
@keyframes toast-out { to { opacity: 0; transform: translateX(-1em); } }
@keyframes blink { 50% { opacity: 0.55; } }
@keyframes bump { 40% { transform: scale(1.06); } }
@keyframes shake-x { 0%, 100% { transform: translateX(0); } 20% { transform: translateX(-0.12em); } 40% { transform: translateX(0.12em); } 60% { transform: translateX(-0.08em); } 80% { transform: translateX(0.08em); } }
/* capture: aim ring and meter */
@keyframes cap-breathe { 0%, 100% { opacity: 0.1; } 50% { opacity: 0.24; } }
@keyframes cm-in { 0% { transform: scale(0.5); opacity: 0; } 55% { transform: scale(1.07); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
@keyframes cm-badge-in { 0% { transform: scale(0.4); opacity: 0; } 60% { transform: scale(1.1); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
@keyframes cm-beat { 0% { transform: scale(1); } 22% { transform: scale(1.07); } 40% { transform: scale(0.99); } 58% { transform: scale(1.045); } 100% { transform: scale(1); } }
@keyframes cm-win { 0% { transform: scale(1); opacity: 1; } 30% { transform: scale(1.12); opacity: 1; } 100% { transform: scale(1.45); opacity: 0; } }
@keyframes cm-break { 0% { transform: none; opacity: 1; } 12% { transform: translateX(-0.18em) rotate(-3deg); } 24% { transform: translateX(0.18em) rotate(3deg); } 36% { transform: scale(1.06); opacity: 1; } 100% { transform: scale(1.3); opacity: 0; } }
@keyframes cm-fizzle { to { transform: scale(0.6); opacity: 0; } }
@keyframes cm-ringflash { 0% { opacity: 0.9; } 100% { opacity: 0; } }
@keyframes cm-thunk { 0% { transform: translateY(0.1em); } 50% { transform: translateY(-0.06em); } 100% { transform: none; } }
@keyframes cm-max { 0% { transform: scale(1); } 45% { transform: scale(1.28); } 100% { transform: scale(1); } }
@keyframes cm-gem-live { 0%, 100% { scale: 1; box-shadow: 0 0 0 1.5px var(--ink); } 50% { scale: 1.22; box-shadow: 0 0 0 1.5px var(--ink), 0 0 12px #fff; } }
@keyframes cm-gem-pop { 0% { scale: 0.6; } 55% { scale: 1.5; } 100% { scale: 1.2; } }
@keyframes cm-gem-crack { 0%, 100% { translate: 0 0; } 20% { translate: -0.14em 0; } 40% { translate: 0.14em 0; } 60% { translate: -0.08em 0; } 80% { translate: 0.08em 0; } }
@keyframes cm-word-in { 0% { transform: scale(0.3) translateY(0.4em); opacity: 0; } 55% { transform: scale(1.12); opacity: 1; } 100% { transform: scale(1); opacity: 1; } }
@keyframes cm-shine { from { background-position: 160% 0, 0 0; } to { background-position: -60% 0, 0 0; } }
@keyframes cm-new { 0% { transform: scale(0) rotate(-20deg); } 60% { transform: scale(1.2) rotate(6deg); } 100% { transform: scale(1) rotate(-4deg); } }
@keyframes cm-rays { 0% { opacity: 0; transform: scale(0.35) rotate(0deg); } 15% { opacity: 1; transform: scale(1) rotate(10deg); } 65% { opacity: 0.85; } 100% { opacity: 0; transform: scale(1.12) rotate(64deg); } }
@keyframes cm-wave { 0% { opacity: 0.95; transform: scale(0.9); } 100% { opacity: 0; transform: scale(2.4); } }
@keyframes cm-spark { 0% { opacity: 1; transform: rotate(var(--a)) translateY(-4.8em) scale(1.3); } 75% { opacity: 1; } 100% { opacity: 0; transform: rotate(var(--a)) translateY(calc(-4.8em - var(--d))) scale(0.25); } }
@keyframes cm-shard { 0% { opacity: 1; transform: rotate(var(--a)) translateY(-4.8em) rotate(0deg); } 100% { opacity: 0; transform: rotate(var(--a)) translateY(calc(-4.8em - var(--d))) rotate(var(--r)); } }
@keyframes cm-flash { 0% { opacity: 0; } 14% { opacity: 1; } 100% { opacity: 0; } }
@keyframes cm-tension-beat { 0% { opacity: 0; } 20% { opacity: 1; } 38% { opacity: 0.25; } 56% { opacity: 0.75; } 100% { opacity: 0; } }
@keyframes banner { 0% { opacity: 0; transform: translateX(-50%) scale(0.6); } 12% { opacity: 1; transform: translateX(-50%) scale(1.06); } 20% { transform: translateX(-50%) scale(1); } 82% { opacity: 1; transform: translateX(-50%) scale(1); } 100% { opacity: 0; transform: translateX(-50%) scale(0.96) translateY(-0.6em); } }
@keyframes place { 0% { opacity: 0; transform: translateX(-50%) translateY(0.5em); } 15%, 80% { opacity: 1; transform: translateX(-50%); } 100% { opacity: 0; transform: translateX(-50%) translateY(-0.4em); } }
@keyframes float-up { 0% { opacity: 0; transform: translate(-50%, 0.5em); } 15% { opacity: 1; } 100% { opacity: 0; transform: translate(-50%, -2.5em); } }
@media (prefers-reduced-motion: reduce) {
  .pv *, .pv *::before, .pv *::after { animation-duration: 1ms !important; animation-iteration-count: 1 !important; transition-duration: 1ms !important; }
}

/* ----------------------------------------------------------------------------- admin tools + asset zoo
 * The Admin Esc-menu page (ui/pages/admin.js) reuses the menu's .chip / .tile / .grid / .det classes, so it
 * inherits the per-breakpoint restructure; only its own controls are styled here. The Zoo overlay (ui.js
 * setZoo) is a full-screen controls layer over the 3D gallery main.js draws. All of it is touch-friendly
 * (>= var(--tap) targets) and reflows for phone / tablet / desktop; nothing scrolls the page sideways.
 */
.hidden { display: none !important; }

/* admin page: search box, field rows, stepper, spawned list */
.admin-search { width: 100%; margin: 0 0 0.8em; padding: 0.6em 0.9em; min-height: var(--tap); box-sizing: border-box;
  border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--panel-2); color: var(--text); font: inherit; }
.admin-search:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.admin-field { margin: 0.7em 0; }
.admin-field.row { display: flex; align-items: center; justify-content: space-between; gap: 0.6em; flex-wrap: wrap; }
.stepper { display: inline-flex; align-items: center; gap: 0.5em; }
.stepper b { min-width: 2ch; text-align: center; font-variant-numeric: tabular-nums; }
.btn.icon { min-width: var(--tap); min-height: var(--tap); padding: 0; display: inline-grid; place-items: center; }
.admin-tools { display: flex; flex-wrap: wrap; gap: 0.5em; margin-bottom: 0.9em; }
.admin-tools .btn { min-height: var(--tap); }
/* the World view's live list (vortices): one row each, its action at the end; wraps under the text on a phone */
.admin-rows { display: grid; gap: 0.4em; margin: 0.4em 0 0.9em; }
.admin-row { display: flex; align-items: center; justify-content: space-between; gap: 0.6em; flex-wrap: wrap; padding: 0.45em 0.6em;
  border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--panel-2); min-width: 0; }
.admin-row > span { min-width: 0; overflow-wrap: anywhere; }
.admin-row .btn { min-height: var(--tap); min-width: var(--tap); }
.tile.admin-spawn { position: relative; }
.tile.admin-spawn .rm { position: absolute; top: 0.3em; right: 0.3em; min-width: 2em; min-height: 2em; background: rgba(255, 90, 110, 0.16); }
.tile.admin-spawn .rm:hover { background: rgba(255, 90, 110, 0.3); }

/* the zoo overlay: a top bar (Back + title + category jump) and a bottom element picker, over the canvas */
.zoo-ui { position: absolute; inset: 0; pointer-events: none; display: none; flex-direction: column; justify-content: space-between;
  padding: calc(0.7em + var(--safe-t)) calc(0.9em + var(--safe-r)) calc(0.7em + var(--safe-b)) calc(0.9em + var(--safe-l)); }
.zoo-ui.on { display: flex; }
.zoo-ui > * { pointer-events: auto; }
.zoo-bar { display: flex; align-items: center; gap: 0.7em; flex-wrap: wrap; }
.zoo-bar .btn { min-height: var(--tap); }
.zoo-title { display: inline-flex; align-items: center; gap: 0.4em; font-weight: 800; letter-spacing: 0.02em; color: var(--text);
  background: var(--panel-menu); padding: 0.4em 0.8em; border-radius: 999px; box-shadow: var(--shadow-sm); }
.zoo-title .ico { width: 1.1em; height: 1.1em; color: var(--accent); }
.zoo-jump { display: flex; gap: 0.5em; overflow-x: auto; max-width: 100%; padding-bottom: 0.2em; scrollbar-width: none; }
.zoo-jump::-webkit-scrollbar { display: none; }
.zoo-jump .btn { flex: none; min-height: var(--tap); background: var(--panel-2); }
.zoo-elements { align-self: stretch; background: var(--panel-menu); border-radius: var(--r); box-shadow: var(--shadow);
  padding: 0.6em 0.8em; max-height: 34vh; overflow: auto; }
.zoo-elements .pg-h { margin: 0 0 0.4em; }
@media (max-width: 599px) {
  .zoo-bar { gap: 0.5em; }
  .zoo-title { order: -1; }             /* title first, then Back + jump wrap under it on a phone */
  .zoo-elements { max-height: 40vh; }
}

/* ---- gear details (geardetail.js): an item's badge and tooltip, shared by the character window and the bags. */
.gear-badge { background: radial-gradient(circle at 34% 28%, #2a3654, #161f33 72%); box-shadow: 0 0 0 2px var(--ink), 0 0 0 4px color-mix(in srgb, var(--rar) 80%, transparent); }
.gear-tt .tt { display: flex; flex-direction: column; gap: 0.2em; padding: 0.7em 0.85em; border-radius: var(--r-sm); background: rgba(6, 12, 24, 0.5); border: 1.5px solid var(--line); }
.tt-line { color: var(--text); font-weight: 700; line-height: 1.35; overflow-wrap: anywhere; }
.tt-line.green { color: #5ef08a; }
.tt-line.grey, .tt-grey { color: var(--text-3); }
.tt-line.red, .tt-red { color: #ff6a7c; }
.tt-line.gold { color: #ffd86a; font-style: italic; }
.tt-row { display: flex; justify-content: space-between; gap: 1em; color: var(--text); font-weight: 700; }
.tt-sock { display: flex; align-items: center; gap: 0.5em; font-weight: 700; }
.sock { flex: none; width: 0.9em; height: 0.9em; border-radius: 0.2em; background: var(--sock); box-shadow: 0 0 0 2px var(--ink), inset 0 0 0 2px rgba(255, 255, 255, 0.35); transform: rotate(45deg); }

/* ----------------------------------------------------------------------------- class picker (classpick.js)
 * The classes as cards in the wide modal: four across on a wide desktop, two on a tablet, one scrolling column on a
 * phone (where the modal is a near-full-screen sheet). */
.cp { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0 1.4em 1.4em; }
.cp-lead { margin: 0 0 1em; }
.cp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15em, 1fr)); gap: 0.8em; }
.cp-card { display: flex; flex-direction: column; gap: 0.55em; padding: 1em; border-radius: var(--r); border: 2px solid color-mix(in srgb, var(--class) 55%, var(--line));
  background: linear-gradient(180deg, color-mix(in srgb, var(--class) 14%, transparent), rgba(255, 255, 255, 0.03)); }
.cp-card h4 { margin: 0; font-size: 1.25em; color: var(--class); }
.cp-desc { margin: 0; color: var(--text-2); }
.cp-roles { display: flex; flex-wrap: wrap; gap: 0.35em; }
.cp-role { display: inline-flex; align-items: center; gap: 0.35em; min-height: 2em; padding: 0 0.65em; border-radius: 999px; background: rgba(255, 255, 255, 0.06); border: 1.5px solid var(--line); font-size: 0.8em; }
.cp-role .ico { width: 1em; height: 1em; }
.cp-role span { color: var(--text-3); }
.cp-meta { display: grid; grid-template-columns: auto 1fr; gap: 0.2em 0.7em; margin: 0; font-size: 0.85em; }
.cp-meta dt { color: var(--text-3); }
.cp-meta dd { margin: 0; color: var(--text); font-weight: 700; }
.cp-pick { margin-top: auto; min-height: var(--tap); }
@media (max-width: 599px) { .cp-grid { grid-template-columns: 1fr; } .cp { padding: 0 1em 1em; } }

/* ----------------------------------------------------------------------------- the Class tab (pages/talents.js)
 * The class, level and points; the specializations as cards; the class tree and the spec's tree side by side from 900 px
 * of page width, stacked below it; each talent a square of at least 44 px on its tree's grid. */
.tl-head { display: flex; align-items: center; justify-content: space-between; gap: 1em; margin-bottom: 1em; padding: 0.9em 1em; border-radius: var(--r);
  border: 2px solid color-mix(in srgb, var(--class) 50%, var(--line)); background: linear-gradient(90deg, color-mix(in srgb, var(--class) 16%, transparent), transparent); }
.tl-title { display: flex; flex-direction: column; min-width: 0; }
.tl-title b { font-size: 1.3em; color: var(--class); }
.tl-title span { color: var(--text-2); }
.tl-points { display: flex; flex-direction: column; align-items: flex-end; flex: none; }
.tl-points b { font-size: 1.6em; color: var(--accent-2); }
.tl-points span { font-size: 0.72em; letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3); }
.tl-spec-note { display: flex; align-items: center; gap: 0.5em; margin-bottom: 1em; padding: 0.8em 1em; border-radius: var(--r-sm); background: rgba(255, 255, 255, 0.04); color: var(--text-2); }
.tl-spec-note .ico { flex: none; width: 1.1em; height: 1.1em; }
.tl-spec-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(13em, 1fr)); gap: 0.6em; }
.tl-spec { display: flex; flex-direction: column; gap: 0.4em; padding: 0.8em; border-radius: var(--r); border: 2px solid var(--line); background: rgba(255, 255, 255, 0.03); }
.tl-spec.mine { border-color: rgba(184, 255, 74, 0.6); background: rgba(184, 255, 74, 0.07); }
.tl-spec-h { display: flex; align-items: center; gap: 0.45em; }
.tl-spec-h .ico { width: 1.1em; height: 1.1em; }
.tl-spec-h > span:last-child { margin-left: auto; color: var(--text-3); font-size: 0.8em; }
.tl-spec p { margin: 0; color: var(--text-2); font-size: 0.9em; }
.tl-spec .btn { margin-top: auto; min-height: var(--tap); }
.tl-current { margin-top: auto; color: var(--accent-2); font-weight: 800; font-size: 0.85em; }
.tl-trees { display: grid; gap: 1.2em; margin-top: 1.2em; }
@media (min-width: 900px) { .tl-trees { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } }
.tl-grid { display: grid; grid-template-columns: repeat(var(--cols), minmax(var(--tap), 4.2em)); grid-template-rows: repeat(var(--rows), auto); gap: 0.6em;
  justify-content: center; padding: 0.8em; border-radius: var(--r); background: rgba(6, 12, 24, 0.35); border: 2px solid var(--line); }
.tl-node { position: relative; aspect-ratio: 1; min-width: var(--tap); min-height: var(--tap); padding: 0; border-radius: var(--r-sm); border: 2px solid var(--line-2);
  background: rgba(255, 255, 255, 0.04); color: var(--text-2); font: inherit; font-weight: 900; cursor: pointer; touch-action: manipulation; }
.tl-node.has { color: var(--text); border-color: rgba(63, 224, 255, 0.55); background: rgba(63, 224, 255, 0.1); }
.tl-node.max { border-color: rgba(255, 211, 90, 0.8); background: rgba(255, 211, 90, 0.12); color: #ffe7a0; }
.tl-node.can { box-shadow: 0 0 0 2px rgba(184, 255, 74, 0.38); }
.tl-node.locked { opacity: 0.45; }
.tl-node[aria-pressed="true"] { box-shadow: 0 0 0 3px var(--accent); }
.tl-mono { font-size: 1.05em; }
.tl-rank { position: absolute; right: 0.25em; bottom: 0.12em; font-size: 0.62em; color: var(--text-2); }
.tl-note { color: var(--text-3); text-align: center; }
.tl-detail h3 { margin: 0 0 0.3em; }
.tl-detail-rank { display: flex; gap: 1em; margin-bottom: 0.8em; color: var(--text-3); }
.tl-words { margin: 0 0 0.8em; }
.tl-words small { color: var(--text-3); font-size: 0.7em; font-weight: 900; letter-spacing: 0.1em; text-transform: uppercase; }
.tl-words p { margin: 0.2em 0; color: var(--text); font-weight: 700; }
.tl-words.next p { color: #5ef08a; }
.tl-needs { display: flex; align-items: center; gap: 0.45em; margin-bottom: 0.5em; color: var(--text-2); font-size: 0.9em; }
.tl-needs .ico { flex: none; width: 1em; height: 1em; }
.tl-learn { width: 100%; min-height: var(--tap); margin-top: 0.6em; }
.tl-options { display: flex; flex-direction: column; gap: 0.5em; margin-top: 0.6em; }
.tl-options .btn { min-height: var(--tap); }

/* ----------------------------------------------------------------------------- HUD Edit mode (ui/layout.js)
   A backdrop over the whole screen (a 16 px grid while snapping; it also keeps clicks off the frames' own buttons), a
   dashed handle over each movable frame with its name and a reset button (shown once it has moved), and a small panel
   in the middle that can be dragged by any spot but its buttons. Frames empty right now show while being placed.
   Every handle and button is at least --tap; nothing needs hover. */
.lay-layer { position: absolute; inset: 0; pointer-events: auto; touch-action: none; background: rgba(4, 8, 16, 0.22); }
.lay-layer.snap { background-image: linear-gradient(rgba(63, 224, 255, 0.07) 1px, transparent 1px), linear-gradient(90deg, rgba(63, 224, 255, 0.07) 1px, transparent 1px);
  background-size: 16px 16px; }
.lay-handles { position: absolute; inset: 0; }
.lay-handle { position: absolute; left: 0; top: 0; display: grid; place-items: center; min-width: var(--tap); min-height: var(--tap);
  border: 2px dashed rgba(63, 224, 255, 0.9); border-radius: var(--r-sm); background: rgba(63, 224, 255, 0.14); cursor: grab; touch-action: none; }
.lay-handle:hover { background: rgba(63, 224, 255, 0.24); }
.lay-handle.drag { cursor: grabbing; border-style: solid; background: rgba(63, 224, 255, 0.3); }
.lay-handle.grab { border-style: solid; border-color: var(--accent-2); background: rgba(184, 255, 74, 0.2); }
.lay-name { max-width: 100%; padding: 0.2em 0.65em; border-radius: 999px; background: var(--panel-solid); border: 2px solid var(--line-2);
  font-size: 0.78em; font-weight: 900; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; pointer-events: none; }
.lay-reset { position: absolute; top: 0; right: 0; translate: 40% -40%; display: grid; place-items: center; width: var(--tap); height: var(--tap); padding: 0;
  border-radius: 50%; border: 2px solid var(--line-2); background: var(--panel-solid); color: var(--text); cursor: pointer; box-shadow: var(--shadow-sm); touch-action: manipulation; }
.lay-reset .ico { width: 1.2em; height: 1.2em; }
.lay-reset:hover { background: var(--panel-3); }
.lay-panel { position: absolute; left: 50%; top: 50%; translate: calc(-50% + var(--lay-px, 0px)) calc(-50% + var(--lay-py, 0px));
  display: flex; flex-direction: column; align-items: center; gap: 0.6em; width: max-content; max-width: calc(100% - 2 * var(--gap));
  padding: 1em 1.2em; border-radius: var(--r-lg); background: var(--panel-menu); border: 2px solid var(--line-2);
  box-shadow: 0 0 0 1.5px var(--ink), var(--shadow); cursor: move; touch-action: none; }
.lay-title { margin: 0; font-size: 1.1em; font-weight: 900; }
.lay-hint { margin: 0; max-width: 24em; color: var(--text-2); font-size: 0.85em; text-align: center; }
.lay-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.5em; }
.lay-actions .btn, .lay-actions .chip { cursor: pointer; }
.hud-foot { flex-wrap: wrap; align-items: center; gap: 0.5em; }
@media (max-width: 599px), (max-height: 499px) { .lay-panel { padding: 0.8em; gap: 0.45em; } .lay-hint { display: none; } }

/* ----------------------------------------------------------------------------- the create screen's steps (ui/creator.js)
   Side -> Race -> Class -> Look -> Name, in the creator's panel (a right column in landscape, a bottom sheet in portrait).
   The chosen side's colour (--side, the faction's content colour: blue Concord, red Covenant) tints the panel's edge, the
   current step and the choices; a step not reached yet is dimmed and cannot be pressed. Cards are full-width buttons
   (44 px+), the body scrolls inside the panel, nothing needs hover. */
.creator { --side: #3fe0ff; }
.creator.sided .cr-panel { border-color: color-mix(in srgb, var(--side) 55%, var(--line-2)); box-shadow: 0 0 0 3px var(--ink), 0 0 42px -12px var(--side), var(--shadow); }
.cr-panel.stepped .cr-head h2 { flex: 1; font-size: 1.3em; }
.cr-count { color: var(--text-3); font-weight: 900; font-size: 0.85em; }
.cr-steps { display: flex; gap: 0.3em; flex: none; margin: 0; padding: 0.3em; list-style: none; border-radius: 999px; background: rgba(6, 12, 24, 0.55); border: 2px solid var(--line); overflow-x: auto; scrollbar-width: none; }
.cr-steps::-webkit-scrollbar { display: none; }
.cr-steps li { flex: 1 1 auto; min-width: 0; display: flex; }
.creator .cr-step { pointer-events: auto; flex: 1; min-width: 0; display: inline-flex; align-items: center; justify-content: center; gap: 0.3em; min-height: max(2.4em, var(--tap)); padding: 0 0.45em; border: 0; border-radius: 999px;
  background: transparent; color: var(--text-2); font-size: 0.92em; font-weight: 900; cursor: pointer; touch-action: manipulation; transition: background 150ms, color 150ms; }
.cr-step span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-step b { display: grid; place-items: center; width: 1.5em; height: 1.5em; border-radius: 50%; background: rgba(255, 255, 255, 0.08); font-size: 0.8em; }
.cr-step.done { color: var(--text); }
.cr-step.done b { background: color-mix(in srgb, var(--side) 45%, transparent); }
.creator .cr-step[aria-current="step"] { background: color-mix(in srgb, var(--side) 30%, rgba(6, 12, 24, 0.4)); color: #fff; box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--side) 70%, transparent); }
.creator .cr-step:disabled { opacity: 0.4; cursor: default; }
.cr-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; display: flex; flex-direction: column; padding: 0.25em; margin: 0 -0.25em; }
.cr-look { display: flex; flex-direction: column; gap: 0.9em; flex: 1; min-height: 0; }
.cr-look .cr-rows { flex: none; overflow: visible; }
.cr-sides, .cr-races { display: flex; flex-direction: column; gap: 0.7em; }
.creator .cr-side, .creator .cr-race { pointer-events: auto; display: flex; align-items: flex-start; gap: 0.85em; width: 100%; min-height: var(--tap); padding: 0.9em 1em; text-align: left;
  border-radius: var(--r); border: 2px solid var(--line); background: var(--panel-2); cursor: pointer; touch-action: manipulation;
  transition: border-color 150ms, background 150ms, box-shadow 150ms, transform 150ms var(--spring); }
.creator .cr-side:hover, .creator .cr-race:hover { border-color: rgba(255, 255, 255, 0.3); background: var(--panel-3); }
.creator .cr-side:active, .creator .cr-race:active { transform: scale(0.98); }
.creator .cr-side[aria-checked="true"] { border-color: var(--fc); background: color-mix(in srgb, var(--fc) 16%, var(--panel-2)); box-shadow: 0 0 0 2px var(--ink), 0 0 22px -6px var(--fc); }
.creator .cr-race[aria-checked="true"] { border-color: var(--side); background: color-mix(in srgb, var(--side) 14%, var(--panel-2)); box-shadow: 0 0 0 2px var(--ink), 0 0 18px -8px var(--side); }
.cr-crest { flex: none; display: grid; place-items: center; width: 2.8em; height: 2.8em; border-radius: 50%; color: var(--fc, var(--side)); background: rgba(6, 12, 24, 0.6); border: 2px solid currentColor; }
.cr-crest svg { width: 1.5em; height: 1.5em; }
.cr-side-text { display: flex; flex-direction: column; gap: 0.25em; min-width: 0; }
.cr-side-text b { font-size: 1.15em; font-weight: 900; color: var(--fc); }
.cr-side-text span, .cr-race span { color: var(--text-2); font-size: 0.88em; line-height: 1.35; }
.cr-side-text small { color: var(--text); font-size: 0.8em; font-weight: 800; letter-spacing: 0.02em; }
.creator .cr-race { flex-direction: column; gap: 0.3em; }
.cr-race b { font-size: 1.1em; font-weight: 900; }
.cr-note { color: var(--warn); font-size: 0.75em; font-weight: 800; }
.cr-empty { margin: auto; color: var(--text-3); font-weight: 800; }
.cr-classes { grid-template-columns: 1fr; }
.cr-classes .cp-card.sel { box-shadow: 0 0 0 2px var(--ink), 0 0 22px -6px var(--class); border-color: var(--class); }
.cr-namestep { display: flex; flex-direction: column; gap: 1em; }
.cr-summary { display: flex; align-items: center; gap: 0.8em; padding: 0.9em 1em; border-radius: var(--r); background: color-mix(in srgb, var(--side) 12%, var(--panel-2)); border: 2px solid color-mix(in srgb, var(--side) 45%, var(--line)); }
.cr-summary .cr-crest { --fc: var(--side); }
.cr-summary > div { display: flex; flex-direction: column; gap: 0.15em; min-width: 0; }
.cr-summary b { font-size: 1.2em; font-weight: 900; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cr-summary > div > span { color: var(--text-2); font-weight: 800; }
.cr-panel.stepped .cr-foot .btn { padding: 0 0.8em; }
/* ----------------------------------------------------------------------------- the waypoint (ui/waypoint.js, map, compass)
   The beacon: a flag badge standing over the spot, a lime beam down to the ground, the distance under it; at the screen's
   edge (off screen or behind) the badge carries an arrow pointing the way. Steady: it fades, never flashes. */
.wp { position: absolute; left: 0; top: 0; display: flex; flex-direction: column; align-items: center; opacity: 0; transition: opacity 250ms; pointer-events: none;
  translate: -50% -100%; }
.wp.on { opacity: 1; }
.wp-head { position: relative; display: grid; place-items: center; width: 2.3em; height: 2.3em; border-radius: 50%; color: #172600;
  background: radial-gradient(circle at 35% 30%, #eaffb8, #b8ff4a 55%, #7cc414); box-shadow: 0 0 0 2px var(--ink), 0 0 16px rgba(184, 255, 74, 0.55); }
.wp-head .ico { width: 1.25em; height: 1.25em; }
.wp-beam { position: absolute; left: 50%; top: 100%; width: 3px; height: 0; margin-left: -1.5px; border-radius: 2px; pointer-events: none;
  background: linear-gradient(180deg, rgba(184, 255, 74, 0.95), rgba(184, 255, 74, 0.15)); box-shadow: 0 0 8px rgba(184, 255, 74, 0.45); }
.wp-dist { order: 2; margin-top: 0.3em; padding: 0.12em 0.55em; border-radius: 999px; background: var(--panel-solid); border: 2px solid rgba(184, 255, 74, 0.7);
  font-size: 0.78em; font-weight: 900; white-space: nowrap; text-shadow: none; }
.wp.edge { translate: -50% -50%; }
.wp.edge .wp-beam { display: none; }
.wp-arrow { display: none; position: absolute; inset: -0.55em; pointer-events: none; }
.wp.edge .wp-arrow { display: block; }
.wp-arrow::after { content: ""; position: absolute; right: -0.15em; top: 50%; margin-top: -0.45em; border: 0.45em solid transparent; border-left: 0.6em solid #b8ff4a;
  filter: drop-shadow(0 0 1px var(--ink)); }
.wp.edge .wp-dist { position: absolute; top: calc(100% + 0.2em); margin: 0; }
/* the compass strip's waypoint mark: the flag and its distance; pinned to an end (dimmer) while it is behind */
.cp-wp { position: absolute; left: 50%; bottom: 0.55em; display: none; align-items: center; gap: 0.2em; translate: -50% 0; color: #b8ff4a; filter: drop-shadow(0 1px 0 var(--ink)); }
.cp-wp.on { display: inline-flex; }
.cp-wp.behind { opacity: 0.6; }
.cp-wp .ico { width: 1.2em; height: 1.2em; }
.cp-wp b { font-size: 0.7em; font-weight: 900; color: var(--text); text-shadow: 0 1px 0 var(--ink), 0 0 4px var(--ink); }
/* the map's waypoint menu (right-click / long press) and the flag button */
.map-pop { position: absolute; left: 0; top: 0; z-index: 2; display: flex; flex-direction: column; gap: 0.25em; min-width: 12em; padding: 0.4em; pointer-events: auto;
  border-radius: var(--r); background: var(--panel-solid); border: 2px solid var(--line-2); box-shadow: 0 0 0 1.5px var(--ink), var(--shadow); }
.map-pop-where { padding: 0.2em 0.6em 0.3em; color: var(--text-3); font-size: 0.78em; font-weight: 800; }
.map-pop-item { display: flex; align-items: center; gap: 0.6em; min-height: var(--tap); padding: 0 0.8em; border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--text); font-weight: 800; text-align: left; cursor: pointer; touch-action: manipulation; }
.map-pop-item:hover, .map-pop-item:focus-visible { background: var(--panel-3); }
.map-pop-item .ico { width: 1.2em; height: 1.2em; color: #b8ff4a; }
.map-pop-item.danger .ico { color: var(--bad); }
.map-ctl .map-wp.on { border-color: #b8ff4a; color: #b8ff4a; }


/* ----------------------------------------------------------------------------- combat text (ui/combat-text.js)
   Numbers rising off hits: yours dealt (white, a spell's school colour), healing green, what hits you red; a crit larger.
   Placed by transform each frame (no layout), under the HUD's widgets; never a flash - they ease and fade. */
.ctext { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.ct { position: absolute; left: 0; top: 0; display: none; font-size: 1.3em; font-weight: 900; line-height: 1; white-space: nowrap; font-variant-numeric: tabular-nums;
  text-shadow: 0 1px 0 var(--ink), 0 0 3px rgba(0, 0, 0, 0.8), 0 0 1px var(--ink); will-change: transform, opacity; }
.ct.on { display: block; }
.ct.taken { font-size: 1.1em; }
.ct.pet { font-size: 1.05em; }
.ct.heal { font-size: 1.15em; }                           /* (a crit of any kind settles at 1.25x its size: combat-text.js) */
@media (max-width: 599px) { .ct { font-size: 1.15em; } .ct.taken, .ct.pet, .ct.heal { font-size: 1em; } }
/* phones in portrait: the stepped panel is a plain column (the old creator's header-and-name grid does not apply) */
@media (orientation: portrait) and (max-width: 599px) {
  .cr-panel.stepped { display: flex; height: 58dvh; }
  .cr-panel.stepped .cr-head h2 { display: block; font-size: 1.1em; }
  .cr-panel.stepped .cr-name > span { display: block; }
  .cr-step span { display: none; }                         /* the numbers alone: five fit across */
  .creator .cr-side, .creator .cr-race { padding: 0.75em 0.85em; }
}

/* ----------------------------------------------------------------------------- windows (ui/window.js)
   Floating panels over the running game - they never pause it: a title bar to move them by (layout.js keeps where),
   a close button, the pointer free while any is up. Desktop and tablet: a floating panel; phones: a sheet from the
   bottom, full width, that cannot be moved (the touch controls step aside while it is up). */
.wins { position: absolute; inset: 0; pointer-events: none; }
/* touch: the online pill and the chat (net/netui.js, beside this UI in the same root) sit where windows open; they
   step aside while one is open */
html.is-touch :has(> .pv.win-open) > #net-ui .nu-dock { visibility: hidden; }
.win { position: absolute; pointer-events: auto; display: flex; flex-direction: column; max-height: calc(100% - var(--safe-t) - var(--safe-b) - 2 * var(--gap));
  background: var(--panel-solid); border: 1.5px solid var(--line-2); border-radius: var(--r); box-shadow: 0 0 0 1.5px var(--ink), var(--shadow); color: var(--text); overflow: hidden; }
.win[hidden] { display: none; }
.win-head { flex: none; display: flex; align-items: center; gap: 0.5em; min-height: var(--tap); padding: 0.2em 0.3em 0.2em 0.8em; border-bottom: 1.5px solid var(--line-2);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent); cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
.win-head:active { cursor: grabbing; }
.win-ico { width: 1.2em; height: 1.2em; color: var(--accent); }
.win-title { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: 900; }
.win-tools { display: flex; gap: 0.2em; }
.win-x, .win-tool { display: grid; place-items: center; width: var(--tap); height: var(--tap); padding: 0; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--text-2); font: inherit; cursor: pointer; }
.win-x svg, .win-tool svg { width: 1.25em; height: 1.25em; }
.win-x:focus-visible, .win-tool:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (hover: hover) { .win-x:hover, .win-tool:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); } }
.win-body { flex: 1; min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 0.7em; }
@media (max-width: 599px) {
  .win { left: 0 !important; right: 0 !important; top: auto !important; bottom: 0 !important; width: auto !important; max-height: 80dvh; translate: none !important;
    border-radius: var(--r-lg) var(--r-lg) 0 0; border-width: 2px 0 0; padding-bottom: var(--safe-b); animation: sheet 240ms var(--ease) both; }
  .win-head { cursor: default; }
}
/* the drag's ghost (ui/drag.js): what is being carried, under the pointer; drop targets light up while hovered */
.drag-ghost { position: absolute; left: 0; top: 0; z-index: 60; width: 3em; height: 3em; pointer-events: none; }
.drag-ghost[hidden] { display: none; }
.drag-ghost > * { width: 100%; height: 100%; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5); }
.drop-target.drop-ok { outline: 2px solid var(--accent); outline-offset: 1px; }
.drop-target.drop-no { outline: 2px solid #ff5a6e; outline-offset: 1px; }
.pv.dragging-any, .pv.dragging-any * { cursor: grabbing !important; }

/* ----------------------------------------------------------------------------- bags (ui/bags.js)
   Every bag in one window: the backpack, each bag in the bag slots, what waits for room; slots of at least 44 px that
   fill the window's width; the picked item's details and actions under the grid; money, free slots and the bag bar at
   the foot. Desktop / tablet: bottom right, above the action bars; phone: a bottom sheet with the grid scrolling. */
.win-bags { right: calc(var(--safe-r) + var(--gap)); bottom: calc(var(--safe-b) + var(--gap) + 4.4em); width: min(27em, calc(100vw - var(--safe-l) - var(--safe-r) - 2 * var(--gap))); max-height: min(44em, calc(100% - var(--safe-t) - var(--safe-b) - 6em)); }
.bg-sec + .bg-sec { margin-top: 0.75em; }
.bg-h { display: flex; align-items: center; gap: 0.4em; margin: 0 0 0.4em; font-size: 0.8em; font-weight: 900; color: var(--text-2); }
.bg-h small { font-weight: 700; color: var(--text-3); }
.bg-h .bg-n { margin-left: auto; }
.bg-h-ico { display: grid; width: 1.25em; height: 1.25em; color: var(--text-2); }
.bg-h-ico svg { width: 100%; height: 100%; }
.bg-sec.waiting .bg-h { color: #ffd84a; }
.bg-cells { display: grid; grid-template-columns: repeat(auto-fill, minmax(max(2.9em, var(--tap)), 1fr)); gap: 0.3em; }
.bg-slot, .bg-bagslot { position: relative; display: block; aspect-ratio: 1; min-width: var(--tap); min-height: var(--tap); padding: 0; border-radius: var(--r-sm);
  border: 2px solid color-mix(in srgb, var(--rar, var(--line-2)) 75%, transparent); background: radial-gradient(circle at 35% 28%, #1c2944, #0e1627 78%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4); color: var(--text); font: inherit; cursor: pointer; touch-action: pan-y; -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
.bg-slot.empty, .bg-bagslot.empty { background: rgba(4, 8, 16, 0.55); border-color: var(--line); }
.bg-bagslot.empty { border-style: dashed; }
.bg-slot.sel { outline: 2px solid var(--accent); outline-offset: 1px; }
.bg-slot.dragging, .bg-bagslot.dragging { opacity: 0.4; }
.bg-slot:focus-visible, .bg-bagslot:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.bg-ico { position: absolute; inset: 0.28em; display: grid; place-items: center; pointer-events: none; }
.bg-ico svg { width: 100%; height: 100%; }
.bg-count { position: absolute; right: 0.25em; bottom: 0.1em; font-size: 0.74em; font-weight: 900; pointer-events: none; text-shadow: 0 1px 0 var(--ink), 0 0 3px var(--ink), 0 0 3px var(--ink); }
.bg-plus { position: absolute; inset: 0; display: grid; place-items: center; opacity: 0.45; pointer-events: none; }
.bg-plus svg { width: 1em; height: 1em; }
.bg-wait { margin: 1em 0; color: var(--text-3); text-align: center; }
.bg-status { min-height: 1.3em; margin-top: 0.45em; font-size: 0.82em; font-weight: 800; color: var(--text-2); }
.bg-status.bad { color: #ff6a7c; }
.bg-detail { display: flex; flex-direction: column; gap: 0.45em; margin-top: 0.4em; padding: 0.6em; border-radius: var(--r-sm); background: rgba(4, 8, 16, 0.45); border: 1.5px solid var(--line-2); }
.bg-detail:empty { display: none; }
.bg-dhead { display: flex; align-items: center; gap: 0.6em; }
.bg-dico { flex: none; display: grid; width: 2.6em; height: 2.6em; padding: 0.3em; border-radius: var(--r-sm); border: 2px solid var(--rar, var(--line-2)); background: #0e1627; }
.bg-dico svg { width: 100%; height: 100%; }
.bg-dname { display: block; font-weight: 900; }
.bg-dsub { color: var(--text-3); font-weight: 700; }
.bg-ddesc { margin: 0; color: var(--text-2); font-size: 0.86em; }
.bg-dworth { display: flex; align-items: center; gap: 0.4em; color: var(--text-3); font-size: 0.86em; font-weight: 700; }
.bg-dacts { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4em; }
.bg-split { display: inline-flex; align-items: center; gap: 0.3em; }
.bg-split .num { min-width: 2ch; text-align: center; font-weight: 900; }
.bg-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5em 0.8em; margin-top: 0.6em; padding-top: 0.6em; border-top: 1.5px solid var(--line-2); }
.bg-free { color: var(--text-3); font-size: 0.8em; font-weight: 800; }
.bg-bagbar { display: flex; gap: 0.3em; margin-left: auto; }
.bg-bagslot { width: var(--tap); height: var(--tap); }

/* ----------------------------------------------------------------------------- spellbook (ui/spellbook.js)
   The class's abilities and Attack as entries to drag onto the action bars (or tap: the first empty slot); passives
   listed apart. Desktop / tablet: a floating panel on the left; phone: the bottom sheet, one column. */
.win-book { left: calc(var(--safe-l) + var(--gap) + 1em); top: calc(var(--safe-t) + var(--gap) + 9em); width: min(24em, calc(100vw - var(--safe-l) - var(--safe-r) - 2 * var(--gap))); max-height: min(36em, calc(100% - var(--safe-t) - var(--safe-b) - 12em)); }
.sb-note { margin: 0 0 0.6em; color: var(--text-3); font-size: 0.82em; }
.sb-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(10.5em, 1fr)); gap: 0.4em; }
.sb-entry { display: flex; align-items: center; gap: 0.55em; min-height: var(--tap); padding: 0.3em 0.5em 0.3em 0.3em; border-radius: var(--r-sm); border: 1.5px solid var(--line-2);
  background: rgba(4, 8, 16, 0.45); color: var(--text); font: inherit; text-align: left; cursor: grab; touch-action: pan-y; -webkit-touch-callout: none; user-select: none; -webkit-user-select: none; }
.sb-entry:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.sb-entry.dragging { opacity: 0.45; }
.sb-face { position: relative; flex: none; display: grid; place-items: center; width: 2.6em; height: 2.6em; border-radius: var(--r-sm);
  border: 2px solid color-mix(in srgb, var(--school) 70%, var(--line-2)); background: radial-gradient(circle at 35% 28%, color-mix(in srgb, var(--school) 38%, #16223a), #0f1829 78%); }
.sb-face .ab-mark { position: absolute; inset: 0.35em; opacity: 0.35; color: var(--school); }
.sb-face .ab-mark svg { width: 100%; height: 100%; }
.sb-face .ab-mono { font-size: 0.95em; }
.sb-text { display: flex; flex-direction: column; min-width: 0; }
.sb-text b { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.sb-text small { color: var(--text-3); font-weight: 700; font-size: 0.74em; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.sb-h { grid-column: 1 / -1; margin: 0.5em 0 0; font-size: 0.8em; color: var(--text-2); }
.sb-passive { display: flex; flex-direction: column; gap: 0.1em; padding: 0.4em 0.6em; border-radius: var(--r-sm); background: rgba(4, 8, 16, 0.3); border: 1px dashed var(--line-2); }
.sb-passive small { color: var(--text-3); font-size: 0.78em; }
@media (max-width: 599px) { .sb-list { grid-template-columns: 1fr; } }

/* ----------------------------------------------------------------------------- character window (ui/character.js)
   World of Warcraft's character frame: slots | live model | slots, the weapons under the model, and the stats pane
   (folding sections; a picked slot's tooltip in its place). The model is drawn by main.js and copied into .cw-canvas
   in the same frame (a window's panel sits above the game canvas). Desktop and tablet: the pane on the right; small
   tablet: under the model; phone: the sheet; a short screen (a phone on its side): a smaller model, the window higher. */
.win-char { left: calc(var(--safe-l) + var(--gap) + 1em); top: calc(var(--safe-t) + var(--gap) + 7em); width: min(42em, calc(100vw - var(--safe-l) - var(--safe-r) - 2 * var(--gap)));
  max-height: min(40em, calc(100% - var(--safe-t) - var(--safe-b) - 9em)); }
.cw { display: grid; grid-template-columns: auto minmax(14em, 1fr); grid-template-areas: "top top" "main pane"; gap: 0.7em 0.9em; }
.cw-top { grid-area: top; display: flex; align-items: center; gap: 0.6em; }
.cw-crest { display: grid; width: 1.8em; height: 1.8em; }
.cw-crest svg { width: 100%; height: 100%; }
.cw-who { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.cw-name { font-size: 1.1em; font-weight: 900; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.cw-sub { color: var(--text-3); font-weight: 700; }
.cw-ilvl { flex: none; padding: 0.25em 0.7em; border-radius: 999px; border: 1.5px solid var(--line-2); color: #ffd86a; font-size: 0.8em; font-weight: 900; }
.cw-main { grid-area: main; display: flex; gap: 0.5em; align-items: flex-start; }
.cw-col { display: flex; flex-direction: column; gap: 0.3em; }
.cw-center { display: flex; flex-direction: column; align-items: center; gap: 0.5em; }
.cw-doll { position: relative; width: 13.5em; height: 21em; max-width: 100%; border-radius: var(--r-sm); border: 1.5px solid var(--line-2); cursor: grab; touch-action: none; }
.cw-canvas { position: absolute; inset: 0; width: 100%; height: 100%; border-radius: inherit; pointer-events: none; }
.cw-doll:active { cursor: grabbing; }
.cw-turn { position: absolute; right: 0.4em; bottom: 0.4em; width: 1.2em; height: 1.2em; opacity: 0.45; color: var(--text); pointer-events: none; }
.cw-turn svg { width: 100%; height: 100%; }
.cw-weapons { display: flex; gap: 0.35em; }
.cw-slot { position: relative; width: max(2.9em, var(--tap)); height: max(2.9em, var(--tap)); padding: 0; border-radius: var(--r-sm);
  border: 2px solid color-mix(in srgb, var(--rar) 80%, var(--line-2)); background: radial-gradient(circle at 35% 28%, #1c2944, #0e1627 78%);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4); color: var(--text); font: inherit; cursor: pointer; touch-action: pan-y; -webkit-touch-callout: none; user-select: none; }
.cw-slot.empty { background: rgba(4, 8, 16, 0.55); border-color: var(--line); }
.cw-slot.sel { outline: 2px solid var(--accent); outline-offset: 1px; }
.cw-slot:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.cw-ico { position: absolute; inset: 0.28em; display: grid; place-items: center; pointer-events: none; }
.cw-ico svg { width: 100%; height: 100%; }
.cw-empty { font-size: 0.7em; font-weight: 800; color: var(--text-3); text-transform: uppercase; }
.cw-ico.cw-ghost { inset: 0.5em; opacity: 0.55; }                       /* an empty slot's own silhouette */
.cw-pane { grid-area: pane; min-width: 0; display: flex; flex-direction: column; gap: 0.4em; }
.cw-sec { border-radius: var(--r-sm); background: rgba(4, 8, 16, 0.35); border: 1px solid var(--line); }
.cw-sec > summary { display: flex; align-items: center; min-height: var(--tap); padding: 0 0.7em; font-size: 0.82em; font-weight: 900; color: var(--text-2); cursor: pointer; list-style: none; }
.cw-sec > summary::-webkit-details-marker { display: none; }
.cw-sec > summary::after { content: ''; margin-left: auto; width: 0.5em; height: 0.5em; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg); transition: transform 150ms; }
.cw-sec:not([open]) > summary::after { transform: rotate(-45deg); }
.cw-rows { display: flex; flex-direction: column; padding: 0 0.3em 0.3em; }
.cw-stat { display: flex; align-items: center; justify-content: space-between; gap: 0.6em; min-height: 2.2em; padding: 0 0.45em; border: 0; border-radius: var(--r-sm); background: transparent; color: var(--text); font: inherit; font-size: 0.86em; cursor: pointer; text-align: left; }
.cw-stat b { font-weight: 900; }
.cw-stat:focus-visible { outline: 2px solid var(--accent); }
@media (hover: hover) { .cw-stat:hover { background: rgba(255, 255, 255, 0.05); } }
.cw-buff span { color: #7cf29a; }
.cw-buff.debuff span { color: #ff6b6b; }
.cw-back { align-self: flex-start; }
@media (max-width: 719px) {
  .win-char { width: min(30em, calc(100vw - var(--safe-l) - var(--safe-r) - 2 * var(--gap))); }
  .cw { grid-template-columns: 1fr; grid-template-areas: "top" "main" "pane"; }
  .cw-main { justify-content: center; }
}
@media (max-width: 599px) {
  .cw-doll { width: min(11em, 42vw); height: 16em; }
}
@media (max-height: 540px) and (min-width: 600px) {
  .win-char { top: calc(var(--safe-t) + var(--gap)); max-height: calc(100% - var(--safe-t) - var(--safe-b) - 2 * var(--gap)); }
  .cw-doll { width: 10em; height: 15em; }
}

.connection-notice { position: fixed; inset: 0; z-index: 100000; display: grid; place-items: center; background: #09122266; padding: 20px; }
.connection-notice[hidden] { display: none; }
.connection-notice > div { max-width: 520px; padding: 28px; border: 2px solid #64748b; border-radius: 18px; background: #101a2e; color: #f4f7ff; text-align: center; }
