:root {
  --bg: #14161d;
  --panel: #1c1f29;
  --panel2: #232734;
  --line: #2e3342;
  --ink: #e6e9f0;
  --muted: #8b93a7;
  --accent: #6ea8fe;
  --accent2: #ffd166;
  --animated: #b48cff;
  --special: #ffd166;
  --obstacle: #ff6b6b;
  --shadow: 0 2px 10px rgba(0,0,0,.35);
}

* { box-sizing: border-box; }
/* No page-level drag on mobile: the document is a fixed app shell (overflow:hidden, sized to the
   viewport) so there's nothing to scroll, and overscroll-behavior:none kills the iOS rubber-band /
   pull-to-refresh. Inner scroll areas (menus, sidebar, resource browser) keep their own scrolling —
   overscroll-behavior:contain (set on them below) stops that scroll from chaining out to the page. */
html, body { height: 100%; margin: 0; overscroll-behavior: none; touch-action: none; }
/* iOS Safari/standalone: 100% / 100vh stop short of the home-indicator area, leaving a dead strip at
   the bottom. The dynamic viewport unit fills the whole screen (with viewport-fit=cover the background
   reaches the bottom edge); the game controls keep clear of the indicator via their safe-area padding. */
@supports (height: 100dvh) { html, body { height: 100dvh; } }
body {
  font: 13px/1.45 ui-sans-serif, system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--ink);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ---- top bar ---- */
#topbar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 18px; padding: 10px 16px;
  background: linear-gradient(180deg, #1b1f2b, #171a23);
  border-bottom: 1px solid var(--line);
  z-index: 5; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 12px; }
.brand .logo { font-size: 26px; line-height: 1; filter: drop-shadow(0 0 6px rgba(110,168,254,.5)); }
.brand h1 { font-size: 15px; margin: 0; letter-spacing: .2px; }
.brand p { margin: 2px 0 0; color: var(--muted); font-size: 11px; }

.controls { display: flex; gap: 16px; align-items: flex-end; flex-wrap: wrap; }
.group { display: flex; flex-direction: column; gap: 5px; }
.group > label { font-size: 10px; text-transform: uppercase; letter-spacing: .8px; color: var(--muted); }
.btnrow { display: flex; gap: 6px; align-items: center; }

button {
  font: inherit; color: var(--ink);
  background: var(--panel2); border: 1px solid var(--line);
  padding: 6px 11px; border-radius: 7px; cursor: pointer;
  transition: background .12s, border-color .12s, transform .04s;
}
button:hover { background: #2b3142; border-color: #3a4256; }
button:active { transform: translateY(1px); }
button.toggle.on, button.ovl.on, button.season.on {
  background: #28406b; border-color: var(--accent); color: #dbe7ff;
}
button.season.on { box-shadow: var(--shadow); color: #fff; }
button.toggle#tAnim.on { background: #2e5b3a; border-color: #5fd07e; color: #d8ffe2; }
.readout { font-variant-numeric: tabular-nums; color: var(--muted); min-width: 46px; text-align: right; }

/* ---- main split ---- */
main { flex: 1; display: flex; min-height: 0; }
#stage { position: relative; flex: 1; min-width: 0;
  background: radial-gradient(1200px 700px at 50% 35%, #1a1e2a 0%, #101219 70%, #0c0e14 100%); }
#viewport { position: absolute; inset: 0; overflow: hidden; cursor: grab; }
#viewport.dragging { cursor: grabbing; }
#world { position: absolute; top: 0; left: 0; transform-origin: 0 0; }
#mapimg { display: block; image-rendering: pixelated; user-select: none; }
#overlay { position: absolute; top: 0; left: 0; pointer-events: none; image-rendering: pixelated; }
/* "smooth" toggle re-enables browser antialiasing on the scaled map + sprites */
#stage.smoothgfx #mapimg, #stage.smoothgfx #overlay { image-rendering: auto; }

/* minimap */
#minimap {
  position: absolute; right: 12px; bottom: 12px; width: 220px; height: 124px;
  border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  background: rgba(12,14,20,.85); box-shadow: var(--shadow); cursor: crosshair;
}
#minimap canvas { position: absolute; inset: 0; image-rendering: pixelated; }
#miniView { pointer-events: none; }

/* bottom game bar: movement d-pad (left) + MMO-style action hotbar (right), centred */
#gameBar { position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); z-index: 8;
  display: flex; align-items: flex-end; gap: 14px;
  user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
#gameBar.hidden { display: none; }
#gameBar canvas { -webkit-user-drag: none; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
#actionBar { padding: 6px; border: 1px solid var(--line); border-radius: 10px;
  background: rgba(12,14,20,.86); box-shadow: var(--shadow); backdrop-filter: blur(4px); }
#actionCanvas { display: block; image-rendering: pixelated; cursor: pointer; }
/* movement d-pad: the game's A/S/Z/X direction controls (2x2), extracted from the hotbar */
#moveDpad { padding: 6px; border: 1px solid var(--line); border-radius: 10px;
  background: rgba(12,14,20,.86); box-shadow: var(--shadow); backdrop-filter: blur(4px); }
#dpadCanvas { display: block; image-rendering: pixelated; cursor: pointer; }
/* Robin's status HUD (top-right): vitality / strength bars + gold */
#playerStatus {
  position: absolute; right: 12px; top: 12px; z-index: 6; pointer-events: none;
  display: flex; flex-direction: column; gap: 5px; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 8px;
  background: rgba(12,14,20,.86); box-shadow: var(--shadow); backdrop-filter: blur(4px);
  font: 600 12px/1 ui-sans-serif, system-ui, sans-serif; color: #e8e6df;
}
#playerStatus.hidden { display: none; }
#playerStatus .stat { display: flex; align-items: center; gap: 7px; }
#playerStatus .stat .ic { width: 15px; text-align: center; }
#playerStatus .bar { width: 96px; height: 9px; background: rgba(0,0,0,.45); border-radius: 5px; overflow: hidden; }
#playerStatus .bar > i { display: block; height: 100%; border-radius: 5px; transition: width .2s ease, background-color .2s; }
#playerStatus .gold { color: #ffd86b; }
/* Marian's-ring target stats: same look as the player status, centred-top, dismissable */
#ringStats {
  position: absolute; left: 50%; top: 64px; transform: translateX(-50%); z-index: 9;
  display: flex; flex-direction: column; gap: 5px; padding: 10px 12px; min-width: 150px;
  border: 1px solid var(--accent); border-radius: 10px;
  background: rgba(12,14,20,.94); box-shadow: 0 10px 40px rgba(0,0,0,.55); backdrop-filter: blur(4px);
  font: 600 12px/1 ui-sans-serif, system-ui, sans-serif; color: #e8e6df;
}
#ringStats.hidden { display: none; }
#ringStats .rs-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
#ringStats .rs-title { flex: 1; color: var(--accent); font-size: 12px; }
#ringStats .rs-portrait { image-rendering: pixelated; border: 1px solid var(--line); border-radius: 5px; background: #0d0f15; }
#ringStats .rs-x { padding: 1px 7px; font-size: 12px; }
#ringStats .stat { display: flex; align-items: center; gap: 7px; }
#ringStats .stat .ic { width: 15px; text-align: center; }
#ringStats .bar { width: 110px; height: 9px; background: rgba(0,0,0,.45); border-radius: 5px; overflow: hidden; }
#ringStats .bar > i { display: block; height: 100%; border-radius: 5px; transition: width .2s ease, background-color .2s; }
#ringStats .gold { color: #ffd86b; }
/* floating game-speed control (top-centre): play/pause + speed slider + tick count.
   Visible whenever the simulation is active — crucially also in immersive mode, where the
   toolbar (and its speed slider) is hidden. */
#simHud {
  position: absolute; left: 50%; top: 12px; transform: translateX(-50%); z-index: 7;
  display: flex; align-items: center; gap: 9px; padding: 6px 12px;
  border: 1px solid var(--line); border-radius: 8px;
  background: rgba(12,14,20,.86); box-shadow: var(--shadow); backdrop-filter: blur(4px);
}
#simHud.hidden { display: none; }
#simHud button { padding: 3px 9px; }
#simHud input[type=range] { width: 130px; }
#simHud .readout { min-width: 3ch; color: var(--accent2); }

/* immersive game mode: hide the editor chrome, leave only the game (Tab toggles it back) */
body.immersive #topbar, body.immersive #sidebar { display: none; }
body.immersive #hud { opacity: 0; }
body.immersive main { height: 100dvh; }
#immersiveHint { position: absolute; left: 12px; top: 12px; z-index: 7; padding: 4px 8px;
  font: 600 11px/1 ui-sans-serif, system-ui, sans-serif; color: #cbd2dd;
  background: rgba(12,14,20,.7); border: 1px solid var(--line); border-radius: 6px; pointer-events: none; opacity: .65; }
body:not(.immersive) #immersiveHint { display: none; }
/* when a two-step action is armed, JS sets the viewport cursor to the action's IDEOGRAM icon
   (see actionCursor() in app.js) so the pointer shows which action you're about to perform */

#hud {
  position: absolute; left: 12px; bottom: 12px; display: flex; gap: 14px; align-items: center;
  background: rgba(16,18,24,.82); border: 1px solid var(--line);
  padding: 6px 12px; border-radius: 8px; backdrop-filter: blur(4px); font-size: 12px;
}
#hudCoord { font-variant-numeric: tabular-nums; color: var(--accent2); font-weight: 600; }
#hudHint { color: var(--muted); }

#loading {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--muted); background: var(--bg); z-index: 3; transition: opacity .3s; font-size: 14px;
}
#loading.hidden { opacity: 0; pointer-events: none; }

/* No desktop-editor flash on phones: until boot() finishes (it adds `booted`), hide the toolbar and
   sidebar on small / coarse-pointer viewports so the #loading splash — then the start screen — owns
   the whole screen, instead of the full editor chrome painting while assets stream in. Without
   `booted` the chrome stays outside #stage's splash and shows on the very first paint, before
   detectMobile() has even run. The media query mirrors detectMobile()'s
   (pointer: coarse) || innerWidth <= 760 so CSS and JS agree on what counts as "mobile". */
@media (pointer: coarse), (max-width: 760px) {
  body:not(.booted) #topbar,
  body:not(.booted) #sidebar { display: none; }
}

/* ---- sidebar ---- */
#sidebar {
  width: 344px; flex: 0 0 344px; border-left: 1px solid var(--line);
  background: var(--bg); overflow-y: auto; padding: 12px;
  display: flex; flex-direction: column; gap: 12px;
}
.panel { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 12px; }
.panel h2 {
  font-size: 12px; text-transform: uppercase; letter-spacing: .8px; color: var(--muted);
  margin: 0 0 9px; font-weight: 600; display: flex; align-items: center; gap: 8px;
}
.panel .count { color: var(--accent); font-size: 11px; }
.panel .hint, .hint { color: var(--muted); font-size: 11px; margin: 0 0 9px; }
.panel.hidden { display: none; }
#simSpeed { width: 80px; vertical-align: middle; accent-color: var(--accent); }
button#simToggle.on { background: #2e5b3a; border-color: #5fd07e; color: #d8ffe2; }
.chartag { display:inline-flex; align-items:center; gap:6px; padding:3px 7px; border:1px solid var(--line); border-radius:6px; cursor:pointer; margin:0 4px 4px 0; }
.chartag:hover { background:#1a1e28; }
.chartag.sel { border-color: var(--accent); background:#24314a; }
.chartag canvas { width:18px; height:18px; image-rendering:pixelated; }
#simBody .row { display:flex; justify-content:space-between; padding:3px 0; border-bottom:1px dashed #262b38; }
#simBody .row .k { color: var(--muted); }
#simBody .row .v { font-variant-numeric: tabular-nums; }
#bCutscene { width: 100%; }
#simActions { margin-top: 10px; display: flex; gap: 6px; flex-direction: column; }
#simActions.hidden { display: none; }
.runrow { display: flex; gap: 6px; align-items: center; }
.runrow .aslbl { color: var(--muted); font-size: 11px; }
.runrow select { background: var(--panel2); color: var(--ink); border: 1px solid var(--line);
  border-radius: 6px; padding: 5px 6px; font: inherit; }
#scriptSel { flex: 1; min-width: 0; }
#scriptChar { width: 64px; }
#runResult { min-height: 14px; }
#intro { position: fixed; inset: 0; z-index: 30; display: flex;
  align-items: center; justify-content: center; cursor: pointer; transition: opacity .4s;
  background: rgba(4,6,10,.92); backdrop-filter: blur(3px); overflow: auto;
  padding: max(10px, env(safe-area-inset-top)) max(10px, env(safe-area-inset-right)) max(10px, env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left)); }
#intro.hidden { display: none; }
#introBox, #eventBox { max-width: 100%; max-height: 100%; overflow: auto; }
#introBox { margin: 0; padding: 12px; border: 1px solid var(--line); border-radius: 10px;
  background: rgba(14,16,22,.96); box-shadow: 0 14px 52px rgba(0,0,0,.6); }
#introImg { display: block; image-rendering: pixelated; border-radius: 4px; background: #000; transition: opacity .5s; }
#introHint { margin-top: 8px; text-align: right; color: #9aa3b4; font-size: 11px; }

/* scripted event scenes (displayVGAFile: gallows, death, victory, season cards…) — a centred
   dialog with the bitmap scaled up (crisp 2x, capped to the viewport in JS), not a full-bleed image */
#eventScene { position: fixed; inset: 0; z-index: 32; display: flex; align-items: center; justify-content: center;
  background: rgba(4,6,10,.82); backdrop-filter: blur(3px); cursor: pointer; overflow: auto;
  padding: max(8px, env(safe-area-inset-top)) max(8px, env(safe-area-inset-right)) max(8px, env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left)); }
#eventScene.hidden { display: none; }
#eventBox { margin: 0; padding: 12px; border: 1px solid var(--line); border-radius: 10px;
  background: rgba(14,16,22,.96); box-shadow: 0 14px 52px rgba(0,0,0,.6); }
#eventImg { display: block; image-rendering: pixelated; border-radius: 4px; background: #000; }
#eventHint { margin-top: 8px; text-align: right; color: #9aa3b4; font-size: 11px; }
#eventScene.gameover { cursor: default; }
#eventScene.gameover #eventHint { text-align: center; }
#eventHint .restart-btn { color: #fff; background: #7a2b2b; border-color: #b5564b;
  font-size: 14px; font-weight: 600; padding: 9px 22px; margin-top: 2px; }
#eventHint .restart-btn:hover { background: #9a3a3a; border-color: #d06a5e; }

/* the feather's free-look "scout" banner — a centred hint while the fog is lifted and the camera roams */
#scoutBadge { position: fixed; left: 50%; transform: translateX(-50%);
  top: max(10px, env(safe-area-inset-top)); z-index: 9;
  padding: 7px 14px; border-radius: 999px; pointer-events: none;
  background: rgba(20,30,46,.86); border: 1px solid rgba(110,168,254,.7);
  color: #dbe6f7; font-size: 12px; font-weight: 600; letter-spacing: .02em;
  box-shadow: 0 6px 22px rgba(0,0,0,.5); white-space: nowrap; }
#scoutBadge.hidden { display: none; }
body.mobile #scoutBadge { font-size: 11px; padding: 6px 11px; max-width: 92vw; white-space: normal; text-align: center; }

/* ---- shared menu overlay: the start screen + the in-game pause screen (a painting + a
   New game / Save / Load / Resume menu). Fully responsive: the painting stacks over the menu in
   portrait and sits beside it in landscape; the overlay scrolls if a small screen still can't fit,
   and pads to the safe-area insets so nothing hides under a notch / home indicator. ---- */
/* #menuScreen is a non-scrolling, full-bleed fixed overlay (overflow:hidden) so it covers the whole
   screen edge-to-edge — including the iOS bottom safe-area / home-indicator strip. The PANEL does any
   scrolling a tiny screen needs (below), which also avoids iOS Safari's "position:fixed child of an
   overflow:auto container is clipped" bug that was stopping the backdrop short of the bottom. */
#menuScreen { position: fixed; inset: 0; z-index: 33; display: flex; overflow: hidden;
  background: #0a0d13;
  padding: max(14px, env(safe-area-inset-top)) max(14px, env(safe-area-inset-right))
           max(14px, env(safe-area-inset-bottom)) max(14px, env(safe-area-inset-left)); }
#menuScreen.hidden { display: none; }
/* the game's own forest UI frame (SCREEN.GFX) as an ambient backdrop: cover-scaled, lightly blurred,
   with a soft dark tint so the title art + menu stay legible while most of the forest shows through.
   absolute + a small negative inset overscans the blur's soft edge (clipped by #menuScreen's
   overflow:hidden — no scrollbar) and fills the whole overlay, reaching every screen edge incl. the
   bottom safe area. pointer-events:none so backdrop taps still reach #menuScreen (dismiss). */
#menuBg { position: absolute; inset: -8px; z-index: 0; pointer-events: none;
  background: linear-gradient(rgba(8,11,17,.28), rgba(8,11,17,.48)), url("/api/image/SCREEN.png") center / cover no-repeat;
  filter: blur(3px) saturate(1.14); }
/* the panel scrolls (not #menuScreen) when a small screen can't fit it; margin:auto centres it yet
   still lets it scroll to the top when taller than the viewport (align-items:center would clip the
   overflowing top — this doesn't). Scrollbar hidden. */
#menuPanel { position: relative; z-index: 1; margin: auto; display: flex; flex-direction: column;
  align-items: center; gap: 16px; max-width: 100%; max-height: 100%;
  overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; scrollbar-width: none; }
#menuPanel::-webkit-scrollbar { display: none; }
#menuArt { display: block; image-rendering: pixelated; border-radius: 6px; background: #000;
  width: auto; height: auto; max-width: min(560px, 100%); max-height: 46vh; object-fit: contain;
  border: 1px solid var(--line); box-shadow: 0 14px 52px rgba(0,0,0,.6); }
#menuBody { width: min(360px, 100%); scrollbar-width: none; }
#menuBody::-webkit-scrollbar { display: none; }
/* the remaining scroll areas (scene/intro dialogs, the editor sidebar + resource browser) keep their
   own touch scrolling but don't chain overscroll back out to the now-locked page */
#eventScene, #intro, #sidebar, #modalBody, #resGrid { overscroll-behavior: contain; }
/* landscape on a phone: painting + menu side-by-side so the short height isn't overflowed */
@media (orientation: landscape) {
  body.mobile #menuPanel { flex-direction: row; align-items: center; gap: 18px; }
  body.mobile #menuArt { max-height: calc(100dvh - 32px); max-width: 46vw; }
  body.mobile #menuBody { width: min(330px, 46vw); max-height: calc(100dvh - 32px); overflow-y: auto; }
}

#menuBody .pm-title { text-align: center; font-size: 14px; font-weight: 700; letter-spacing: .03em;
  color: #e7ecf5; margin-bottom: 12px; text-shadow: 0 1px 5px rgba(0,0,0,.9), 0 0 2px rgba(0,0,0,.7); }
#menuBody .pm-slots { display: flex; flex-direction: column; gap: 6px; margin: 10px 0; }
#menuBody .pm-slot { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 7px 9px; border: 1px solid var(--line); border-radius: 7px; background: rgba(20,24,34,.7); }
#menuBody .pm-slot-label { display: flex; flex-direction: column; line-height: 1.25; font-size: 12px; }
#menuBody .pm-slot-label b { color: #e7ecf5; }
#menuBody .pm-when { color: #8b94a6; font-size: 10.5px; }
#menuBody .pm-slot-btns { display: flex; gap: 5px; flex-shrink: 0; }
#menuBody .pm-actions { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 4px; }
#menuBody .pm-note { color: #c2c9d6; font-size: 11px; text-align: center; padding: 8px 4px; text-shadow: 0 1px 4px rgba(0,0,0,.9); }
#menuBody .pm-msg { min-height: 14px; margin-top: 7px; text-align: center; font-size: 11px; color: #7fd49a; text-shadow: 0 1px 4px rgba(0,0,0,.9); }
#menuBody .pm-msg.err { color: #f08a7e; }
.pm-btn { font: inherit; font-size: 13px; color: #dbe3f0; background: rgba(38,46,64,.95);
  border: 1px solid rgba(90,102,128,.9); border-radius: 6px; padding: 8px 14px; cursor: pointer; }
.pm-btn:hover { background: rgba(52,64,92,.98); border-color: #6ea8fe; }
.pm-btn:active { transform: translateY(1px); }
.pm-btn:disabled { opacity: .5; cursor: default; }
.pm-btn.pm-primary { background: #2f5d36; border-color: #4f8f57; color: #eafff0; font-weight: 600; }
.pm-btn.pm-primary:hover { background: #387044; border-color: #62b06a; }
.pm-btn.pm-del { padding: 8px 11px; color: #f0a99e; }
.pm-btn.pm-del:hover { background: #5a2b2b; border-color: #b5564b; }
/* "Install / Add to Home Screen" nudge on the start screen (mobile, non-PWA only) */
#menuBody .pm-install { margin: 12px 0 2px; padding: 10px 12px; text-align: center;
  border: 1px solid var(--line); border-radius: 10px; background: rgba(40,64,107,.32); }
#menuBody .pm-install.hidden { display: none; }
#menuBody .pm-install-title { font-size: 12px; font-weight: 600; color: #dbe7ff; margin-bottom: 8px; }
#menuBody .pm-install-steps { font-size: 11.5px; line-height: 1.45; color: #c2c9d6; }
#menuBody .pm-install-steps b { color: #e7ecf5; }
#menuBody .pm-share-ic { vertical-align: -3px; margin: 0 1px; }
.pm-btn.pm-install-btn { width: 100%; justify-content: center; background: #28406b; border-color: var(--accent); color: #dbe7ff; }
.pm-btn.pm-install-btn:hover { background: #305088; border-color: #8cbcff; }
.muted { color: var(--muted); }

/* inspector */
#inspBody .row { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; border-bottom: 1px dashed #262b38; }
#inspBody .row:last-child { border-bottom: 0; }
#inspBody .k { color: var(--muted); }
#inspBody .v { font-variant-numeric: tabular-nums; text-align: right; }
.thumb { width: 56px; height: 56px; image-rendering: pixelated; border: 1px solid var(--line); border-radius: 6px; background: #0d0f15; }

/* badges */
.badge { display: inline-block; font-size: 10px; line-height: 1.4; padding: 1px 6px; border-radius: 999px;
  margin: 0 4px 4px 0; border: 1px solid var(--line); background: var(--panel2); color: var(--muted); }
.badge.animated { color: #1a1330; background: var(--animated); border-color: var(--animated); }
.badge.special  { color: #2a2000; background: var(--special);  border-color: var(--special); }
.badge.obstacle { color: #2a0000; background: var(--obstacle); border-color: var(--obstacle); }
.badge.pass { color: #04210f; background: #5fd07e; border-color: #5fd07e; }
.badge.path { color: #04212a; background: #5fd0d0; border-color: #5fd0d0; }

/* lists */
.list { max-height: 190px; overflow-y: auto; display: flex; flex-direction: column; gap: 3px; }
.list .item {
  display: flex; align-items: center; gap: 8px; padding: 4px 6px; border-radius: 6px;
  cursor: pointer; border: 1px solid transparent;
}
.list .item:hover { background: #1a1e28; border-color: var(--line); }
.list .item.sel { background: #24314a; border-color: var(--accent); }
.list .item .sprite { width: 22px; height: 22px; image-rendering: pixelated; flex: 0 0 22px; }
.list .item .label { flex: 1; }
.list .item .sub { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }

/* cube grid */
#cubeGrid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.cube { position: relative; background: #0d0f15; border: 1px solid var(--line); border-radius: 7px;
  padding: 5px 4px 4px; cursor: pointer; text-align: center; transition: border-color .1s, background .1s; }
.cube:hover { border-color: #3a4256; background: #161a24; }
.cube.sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.cube canvas { width: 42px; height: 42px; image-rendering: pixelated; display: block; margin: 0 auto; }
.cube .idx { font-size: 10px; color: var(--muted); margin-top: 3px; font-variant-numeric: tabular-nums; }
.cube .used { font-size: 9px; color: #5c647a; }
.cube .flagdots { position: absolute; top: 4px; right: 4px; display: flex; gap: 2px; }
.cube .dot { width: 6px; height: 6px; border-radius: 50%; }
.dot.animated { background: var(--animated); }
.dot.special  { background: var(--special); }
.dot.obstacle { background: var(--obstacle); }

#legend .leg { display: flex; align-items: center; gap: 8px; margin: 4px 0; }
#legend .chip { width: 12px; height: 12px; border-radius: 3px; flex: 0 0 12px; }
#stats { margin-top: 10px; font-size: 11px; line-height: 1.7; }
#stats .row { display: flex; justify-content: space-between; }
#stats .k { color: var(--muted); }

/* ---- resource modal ---- */
#modal { position: fixed; inset: 0; background: rgba(6,8,12,.78); z-index: 20;
  display: flex; align-items: center; justify-content: center; backdrop-filter: blur(3px); }
#modal.hidden { display: none; }
#modalBox { width: min(1100px, 94vw); height: min(760px, 90vh); background: var(--panel);
  border: 1px solid var(--line); border-radius: 12px; display: flex; flex-direction: column; box-shadow: var(--shadow); }
#modalHead { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; border-bottom: 1px solid var(--line); }
#modalHead h2 { margin: 0; font-size: 14px; }
#modalClose { padding: 4px 10px; }
#modalBody { flex: 1; display: flex; min-height: 0; }
#resGrid { width: 240px; flex: 0 0 240px; overflow-y: auto; border-right: 1px solid var(--line); padding: 10px; display: flex; flex-direction: column; gap: 4px; }
#resGrid .ritem { padding: 7px 10px; border-radius: 6px; cursor: pointer; border: 1px solid transparent; display: flex; justify-content: space-between; gap: 8px; }
#resGrid .ritem:hover { background: #1a1e28; border-color: var(--line); }
#resGrid .ritem.sel { background: #24314a; border-color: var(--accent); }
#resGrid .ritem .dim { color: var(--muted); font-size: 11px; font-variant-numeric: tabular-nums; }
#resView { flex: 1; overflow: auto; display: flex; align-items: center; justify-content: center; padding: 16px;
  background: repeating-conic-gradient(#16181f 0% 25%, #1b1e26 0% 50%) 0 0 / 24px 24px; }
#resView img { image-rendering: pixelated; max-width: 100%; box-shadow: 0 0 0 1px var(--line); }
#resView .meta { position: absolute; bottom: 18px; right: 260px; background: rgba(12,14,20,.85);
  padding: 6px 10px; border-radius: 6px; border: 1px solid var(--line); font-size: 11px; }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: #2c3142; border-radius: 6px; }
::-webkit-scrollbar-track { background: transparent; }

/* ============================================================== mobile / touch ============== */
/* The app owns pan/zoom (pointer events + pinch), so stop the browser hijacking touch gestures
   over the map and kill the grey tap flash / rubber-band scroll. */
* { -webkit-tap-highlight-color: transparent; }
html, body { overscroll-behavior: none; }
#viewport { touch-action: none; }

/* iOS/Android: a long-press — which hold-to-walk on the d-pad *is* — must NOT pop the system callout
   ("Save Image" / Copy), the selection magnifier, or an image drag. -webkit-touch-callout:none is the
   reliable suppressor; pair it with user-select:none + user-drag:none. Applied to the map image and
   every game-overlay surface (the d-pad/action canvases especially). Harmless on desktop. */
#viewport, #world, #mapimg, #overlay,
#gameBar, #moveDpad, #actionBar, #combatBar, #dpadCanvas, #actionCanvas, #combatCanvas,
#invBar, #invCanvas,
#simHud, #playerStatus, #ringStats, #minimap, #minimap canvas {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* The phone layout is driven by `body.mobile` (set by detectMobile() in app.js) so CSS and the
   JS canvas sizing always agree on when we're "mobile". */

/* declutter the immersive game view: drop the keyboard hint, the coord readout and the minimap */
body.mobile #immersiveHint,
body.mobile #hud,
body.mobile #minimap { display: none; }

/* game controls -> a compact cluster top-left; player stats stay top-right (no centre overlap) */
body.mobile #simHud {
  left: max(8px, env(safe-area-inset-left)); right: auto; transform: none;
  top: max(8px, env(safe-area-inset-top));
  gap: 6px; padding: 5px 8px;
}
body.mobile #simHud input[type=range] { display: none; }   /* the speed slider -> the > / >> / >>> toggle on mobile */
body.mobile #simHud #simHudTick { display: none; }          /* drop the frame counter on mobile */
body.mobile #simHud button { padding: 6px 11px; font-size: 15px; }   /* finger-sized play / new */
body.mobile #simHudSpeedToggle { width: 3.1em; text-align: center; letter-spacing: 1px; }   /* stable width across > / >> / >>> */

/* elements only shown on touch (the mobile speed toggle) */
.mobileOnly { display: none; }
body.mobile .mobileOnly { display: inline-block; }

body.mobile #playerStatus {
  top: max(8px, env(safe-area-inset-top));
  right: max(8px, env(safe-area-inset-right));
  padding: 6px 9px;
}
body.mobile #playerStatus .bar { width: 76px; }

body.mobile #ringStats { top: 60px; }

/* acquired-item icons (disguise robe, ring, horn, command, crystal, …): a vertical column tucked
   just under the top-left controls (#simHud) on mobile. Same per-slot well chrome as the bottom bar,
   sized to the d-pad buttons. Desktop keeps these in the bottom action bar, so this is mobile-only. */
#invBar { display: none; }
body.mobile #invBar {
  display: block; position: absolute; z-index: 8;
  left: max(8px, env(safe-area-inset-left));
  top: calc(max(8px, env(safe-area-inset-top)) + 46px);
  pointer-events: auto;
}
body.mobile #invBar.hidden { display: none; }
#invCanvas { display: block; image-rendering: pixelated; touch-action: none; cursor: default; }

/* bottom game bar (grid): d-pad bottom-left, the bow/sword combat pair bottom-right (mirrored), and a
   full-width action bar below them. All borderless — the per-slot wells already frame the buttons —
   and clear of the home indicator / rounded-screen edges. */
#combatBar { display: none; }
body.mobile #gameBar {
  left: 0; right: 0; bottom: 0; width: 100%; transform: none;
  display: grid; align-items: end; gap: 8px;
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "dpad . combat" "action action action";
  padding: 0 max(8px, env(safe-area-inset-right)) calc(8px + env(safe-area-inset-bottom)) max(8px, env(safe-area-inset-left));
  pointer-events: none;                 /* taps in the gaps fall through to the map */
  opacity: .8;                          /* 20% transparent so the map reads through the bottom controls (both orientations) */
}
/* d-pad + weapon clusters are frameless (no panel box) — only the per-slot wells outline each button;
   the action bar keeps its translucent backdrop as the central hotbar */
body.mobile #moveDpad  { grid-area: dpad;   justify-self: start;  pointer-events: auto; padding: 0; border: none; background: none; box-shadow: none; backdrop-filter: none; }
body.mobile #actionBar { grid-area: action; justify-self: center; pointer-events: auto; padding: 5px; border: none; border-radius: 14px; }
body.mobile #combatBar { grid-area: combat; justify-self: end;    pointer-events: auto; padding: 0; display: block; background: none; box-shadow: none; backdrop-filter: none; }
body.mobile #combatCanvas { display: block; image-rendering: pixelated; }
body.mobile #gameBar canvas { touch-action: none; cursor: default; }
/* the mobile grid rule is more specific than #gameBar.hidden, so without this the d-pad + action/menu
   bar would stay visible while the player has no control (e.g. the opening cutscene). Re-assert hidden. */
body.mobile #gameBar.hidden { display: none; }

/* Landscape: the screen is short, so put all three clusters on ONE bottom row — d-pad bottom-left,
   weapons bottom-right, action bar between them — instead of stacking the d-pad/weapons above the bar.
   This anchors the d-pad and weapon buttons at the very bottom of the screen (and frees vertical space).
   (mobileBarAvail() in app.js sizes the action bar to fit between the flanking clusters in landscape.) */
@media (orientation: landscape) {
  body.mobile #gameBar { grid-template-areas: "dpad action combat"; align-items: end; }   /* one bottom row; the .8 opacity is shared with portrait now */
}

/* editor view on a phone (after exiting immersive): stack the sidebar under the map, slim the topbar */
body.mobile #topbar { gap: 10px 12px; padding: 8px 10px; }
body.mobile .brand p { display: none; }
body.mobile .brand h1 { font-size: 13px; }
body.mobile:not(.immersive) main { flex-direction: column; }
body.mobile:not(.immersive) #sidebar {
  width: 100%; flex: 0 0 auto; max-height: 46vh;
  border-left: 0; border-top: 1px solid var(--line);
}

/* resource browser stacks vertically on small screens */
body.mobile #modalBody { flex-direction: column; }
body.mobile #resGrid { width: 100%; flex: 0 0 auto; max-height: 36vh; border-right: 0; border-bottom: 1px solid var(--line); }
body.mobile #resView .meta { right: 12px; bottom: 12px; }
