/* The quest page and the game (.gm); loaded after reader.css. */
:root body[data-id="GM"] article { padding-top: 24px; }
:root body[data-id="GM"] .pagehead { margin-bottom: 20px; padding-bottom: 16px; }
:root body[data-id="GM"] .pagehead h1 { margin: 6px 0; }
:root body[data-id="GM"] .pagehead .eyebrow { display: none; }
:root body[data-id="GM"] .pagehead .sum { margin: 0; }
.quest-layout { display: grid; grid-template-columns: minmax(0, 1fr) 160px; align-items: start; gap: 24px; }
.quest-layout #play { grid-column: 1; grid-row: 1; border: 0; margin: 0; min-width: 0; }
:root .quest-layout #play > .phdr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); padding: 0; margin: 0; }
:root .quest-layout #play > .pbody { padding: 0; }
.quest-layout .quest-stats { grid-column: 2; grid-row: 1; position: sticky; top: 90px; display: flex; flex-direction: column; margin: 0; border: 0; }
:root .quest-stats .stat { display: flex; flex-direction: column; align-items: flex-start; padding: 18px 0; gap: 6px; }
:root .quest-stats .stat:first-child { padding-top: 4px; }
:root .quest-stats .stat .val { font-size: 24px; text-align: left; margin-left: 0; }
.quest-stats .stat .u { display: block; margin: 4px 0 0; font-size: 11px; }
.quest-stats .stat .lbl { text-transform: uppercase; letter-spacing: 1px; }
.gm {
  --accent-dim: #286582; --warn-dim: #aa7950;
  --gm-item-min: 200px; --gm-item-gap: 6px;
  --gm-window: linear-gradient(155deg, var(--surface), var(--ink) 65%);
  --gm-rim: var(--accent);
  position: relative; font-family: var(--sans); font-size: 14px; line-height: 1.5; color: var(--paper);
  max-width: 1200px; margin: 0 auto;
  padding: 16px; background: var(--ink-sunk);
  border: 1px solid var(--rule-2); border-radius: 8px;
  box-shadow: 0 16px 48px #0004, inset 0 0 0 3px var(--ink);
}
.gm[data-palette="light"] {
  --accent-dim: #377794; --warn-dim: #ab8352;
}
.gm [hidden] { display: none !important; }
.gm *:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ── the stage: canvas under, windows over ─────────────────── */
.gm-stage {
  position: relative; width: 100%; aspect-ratio: 8 / 5; background: var(--ink-sunk);
  border: 3px double var(--gm-rim); box-shadow: 0 4px 0 var(--shadow), inset 0 0 0 1px var(--ink-sunk); overflow: hidden;
  border-radius: 4px;
  outline-offset: 3px;
}
/* the map is 30 by 19 tiles; the stage takes that shape so no art pixel is stretched */
.gm-stage.gm-map { aspect-ratio: 30 / 19; max-width: calc(var(--gm-fit-height, 1000px) * 30 / 19); margin: 0 auto; }
.gm-stage > canvas {
  display: block; width: 100%; height: 100%;
  image-rendering: pixelated; image-rendering: crisp-edges;
}
.gm-stage.gm-focus { border-color: var(--accent); }

/* Beveled charcoal windows with a gold outer rim and a dark inner rule. */
.gm-win {
  position: absolute; background: var(--ink); background-image: var(--gm-window); border: 3px double var(--gm-rim); color: var(--paper);
  border-radius: 4px; box-shadow: 2px 3px 0 #0008, inset 0 0 0 1px var(--ink-sunk);
  padding: 12px 14px; font-size: 14.5px; line-height: 1.5;
}
.gm-hud {
  left: 8px; top: 8px; padding: 6px 10px; font-family: var(--mono); font-size: 12px; color: var(--paper-2);
  display: flex; gap: 12px; align-items: center; pointer-events: none;
}
.gm-hud b { color: var(--paper); font-weight: 500; }
.gm-hud .hp { display: inline-flex; gap: 2px; align-items: center; }
.gm-hud .hp i { display: block; width: 7px; height: 7px; background: var(--bad); }
.gm-hud .hp i.off { background: var(--surface-3); }
.gm-hud .g { color: var(--warn); }
.gm-hud .lv { color: var(--accent); }

.gm-dialog { left: 12px; right: 12px; bottom: 12px; max-height: 60%; overflow: auto; z-index: 4; animation: gm-dialog-in .18s ease-out; }
.gm-dialog .who { font-family: var(--sans); font-weight: 700; color: var(--accent); font-size: 13px; letter-spacing: .3px; margin-bottom: 4px; }
.gm-dialog .txt { color: var(--paper); }
.gm-dialog .txt code { font-family: var(--mono); font-size: .9em; color: var(--accent-lit); }
.gm-dialog .more { text-align: right; font-family: var(--mono); font-size: 11px; color: var(--paper-3); margin-top: 6px; }
.gm-dialog .more button { margin-left: 8px; }
/* the right-hand column: the where window, then the minimap under it, whatever height the window runs to; capped
   so a long signpost wraps rather than running into the hud on a narrow stage */
.gm-side { position: absolute; right: 8px; top: 8px; max-width: 58%; display: flex; flex-direction: column; align-items: flex-end; gap: 6px; pointer-events: none; }
.gm-side > .gm-win { position: static; }
.gm-where { padding: 4px 8px; font-family: var(--mono); font-size: 11px; color: var(--paper-3); text-align: right; }
/* the signpost: where next, its steps and its way, under where you are; the accent's lit shade, which reads on the
   ink ground (the ring on the minimap is the accent itself) */
.gm-where .nx { display: block; color: var(--accent-lit); }
/* the minimap: the whole map at a pixel a tile, under the where window; the dot blinks on the beat and a frame shows
   the tiles the map holds (paper, the accent while the stage has focus, like the stage's border); the canvas's
   backing is scaled for the screen. The box's width is the custom property, which game.js reads once for the
   backing store, so the two cannot drift; the height follows the map's aspect, so a minimap pixel is always square */
.gm-mini { padding: 4px; --gm-mini-w: 120px; }
.gm-mini canvas { display: block; width: var(--gm-mini-w); height: auto; image-rendering: pixelated; image-rendering: crisp-edges; }
@media (max-width: 560px) { .gm-mini { display: none; } }

/* ── screens: a scene over the whole stage ─────────────────── */
.gm-screen {
  position: absolute; inset: 0; background: var(--ink); background-image: var(--gm-window); color: var(--paper); overflow: auto;
  display: flex; flex-direction: column; padding: 18px; gap: 10px;
}
.gm-title {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; border-bottom: 1px solid var(--rule-2); padding-bottom: 8px; margin-bottom: 10px;
}
.gm-title h3 { margin: 0; font-family: var(--mono); font-size: 22px; font-weight: 500; color: var(--paper); text-shadow: 1px 2px 0 var(--ink-sunk); }
.gm-title .sub { font-family: var(--serif); font-style: italic; color: var(--paper-3); font-size: 14px; }
.gm-title .right { margin-left: auto; font-family: var(--mono); font-size: 11.5px; color: var(--paper-3); }
.gm-body { flex: 1; display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); min-height: 0; }
.gm-body.one { grid-template-columns: minmax(0, 1fr); }
.gm-col { min-width: 0; display: flex; flex-direction: column; gap: 10px; }

/* the FF menu: a column of buttons with a pointer */
.gm-menu { display: flex; flex-direction: column; gap: 2px; margin: 0; padding: 0; list-style: none; }
.gm-menu button, .gm-menu a {
  display: flex; align-items: baseline; gap: 10px; width: 100%; text-align: left; cursor: pointer;
  font-family: var(--sans); font-weight: 600; font-size: 14px; letter-spacing: .2px; line-height: 1.3;
  background: transparent; color: var(--paper); border: 1px solid transparent; padding: 11px 10px 11px 26px; position: relative;
  min-height: 44px;
  text-decoration: none;
}
.gm-menu button::before, .gm-menu a::before { content: "▶"; position: absolute; left: 8px; color: var(--accent); opacity: 0; font-size: 11px; top: 14px; }
.gm-menu button:hover, .gm-menu a:hover, .gm-menu button:focus-visible, .gm-menu a:focus-visible { border-color: var(--rule-2); background: var(--tint-hi); }
.gm-menu button:hover::before, .gm-menu a:hover::before, .gm-menu button:focus-visible::before, .gm-menu a:focus-visible::before { opacity: 1; }
.gm-menu button:disabled { color: var(--paper-3); cursor: default; }
.gm-menu button:disabled:hover { background: none; border-color: transparent; }
.gm-menu button:disabled:hover::before { opacity: 0; }
.gm-menu .k { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--paper-3); font-weight: 400; }
.gm-menu .d { font-family: var(--sans); font-weight: 400; font-size: 12.5px; color: var(--paper-3); }
.gm-menu .done { color: var(--ok); font-family: var(--mono); font-size: 11px; }
.gm-menu button.new { color: var(--accent-lit); }
.gm-menu .cmd { font-family: var(--mono); font-weight: 400; font-size: 12px; color: var(--paper-2); }
.gm-menu button.sel { border-color: var(--accent); background: var(--accent-fill); }
.gm-menu button.sel::before { opacity: 1; }

/* Complete scene canvases are scaled sharply; each scene layout sets their size. */
.gm-scene { display: block; width: 100%; height: auto; image-rendering: pixelated; image-rendering: crisp-edges; border: 1px solid var(--rule); border-radius: 3px; }

.gm-note { font-size: 13.5px; color: var(--paper-2); line-height: 1.5; margin: 0; }
.gm-note.ok { color: var(--ok); } .gm-note.bad { color: var(--bad); } .gm-note.warn { color: var(--warn); }
.gm-lines { font-size: 14.5px; line-height: 1.55; color: var(--paper); }
.gm-lines p { margin: 0 0 8px; } .gm-lines p:last-child { margin: 0; }
.gm-lines code, .gm-q code, .gm-opt code, .gm-ticket code { font-family: var(--mono); font-size: .88em; color: var(--accent-lit); background: none; padding: 0; border: none; }
.gm-lines .teach { font-family: var(--mono); font-size: 12px; color: var(--ok); border-top: 1px solid var(--rule); padding-top: 8px; margin-top: 8px; }

/* ── the trial ────────────────────────────────────────────── */
.gm-q { font-family: var(--serif); font-size: 16.5px; line-height: 1.5; color: var(--paper); margin: 0 0 8px; }
.gm-opts { display: flex; flex-direction: column; gap: 4px; }
.gm-opt {
  text-align: left; cursor: pointer; background: transparent; color: var(--paper-2); border: 1px solid var(--rule);
  padding: 12px 14px 12px 38px; font-family: var(--sans); font-size: 14px; line-height: 1.5; position: relative;
  border-radius: 3px; min-height: 48px;
}
.gm-opt .n { position: absolute; left: 12px; top: 14px; font-family: var(--mono); font-size: 12px; color: var(--accent); }
.gm-opt:hover, .gm-opt:focus-visible { border-color: var(--rule-2); color: var(--paper); }
.gm-opt.right { border-color: var(--ok); background: var(--ok-fill); color: var(--paper); }
.gm-opt.wrong { border-color: var(--bad); background: var(--bad-fill); }
.gm-opt:disabled { cursor: default; }
.gm-prog { display: flex; gap: 4px; height: 8px; flex: none; margin-bottom: 10px; }
.gm-prog i { flex: 1; background: var(--surface-3); display: block; }
.gm-prog i.hit { background: var(--ok); } .gm-prog i.miss { background: var(--bad); } .gm-prog i.now { background: var(--paper-3); }

/* ── the battle ───────────────────────────────────────────── */
.gm-enemy { display: flex; gap: 12px; align-items: flex-start; position: relative; }
.gm-enemy canvas { width: 96px; height: 96px; flex: none; image-rendering: pixelated; border: 1px solid var(--rule); background: var(--ink-sunk); }
.gm-enemy .side { flex: 1; min-width: 0; }
.gm-enemy .nm { font-family: var(--sans); font-weight: 700; font-size: 17px; color: var(--paper); }
.gm-enemy .lv { font-family: var(--mono); font-size: 11px; color: var(--warn); }
/* the blows: a hit shakes the figure and flashes it red, evidence makes it stagger, a fall lays it low */
@keyframes gm-shake { 0%, 100% { transform: translate(0, 0); } 20% { transform: translate(-4px, 1px); } 40% { transform: translate(4px, -1px); } 60% { transform: translate(-3px, 0); } 80% { transform: translate(3px, 1px); } }
@keyframes gm-flash { 0%, 100% { background: var(--ink-sunk); } 30% { background: var(--bad); } }
@keyframes gm-stagger { 0%, 100% { transform: scale(1, 1); } 35% { transform: scale(1.08, .9) translate(0, 4px); } 70% { transform: scale(.96, 1.04); } }
@keyframes gm-fall { 0% { transform: none; opacity: 1; } 60% { transform: translate(0, 10px) rotate(6deg); opacity: .4; } 100% { transform: none; opacity: 1; } }
.gm-enemy.fx-hit canvas { animation: gm-shake .4s ease-out, gm-flash .4s ease-out; }
.gm-enemy.fx-stagger canvas { animation: gm-stagger .45s ease-out; }
.gm-enemy.fx-win canvas { animation: gm-fall .9s ease-in-out; }
/* each fault family falls its own way: the figure carries data-family */
@keyframes gm-fall-workload { 0% { transform: none; opacity: 1; } 55% { transform: translate(6px, 14px) rotate(24deg); opacity: .8; } 80% { transform: translate(10px, 40px) rotate(88deg); opacity: .2; } 100% { transform: none; opacity: 1; } }
@keyframes gm-fall-networking { 0% { transform: none; opacity: 1; } 30% { transform: scale(1.1, .9) translate(0, 3px); } 70% { transform: scale(.15, 1.3) translate(0, -6px); opacity: .5; } 90% { transform: scale(.02, 1.6); opacity: 0; } 100% { transform: none; opacity: 1; } }
@keyframes gm-fall-storage { 0% { transform: none; opacity: 1; } 50% { transform: scale(1.15, .55) translate(0, 22px); opacity: .9; } 85% { transform: scale(1.3, .08) translate(0, 46px); opacity: .1; } 100% { transform: none; opacity: 1; } }
@keyframes gm-fall-gitops { 0% { transform: none; opacity: 1; } 60% { transform: rotate(300deg) scale(.55); opacity: .7; } 90% { transform: rotate(540deg) scale(.05); opacity: 0; } 100% { transform: none; opacity: 1; } }
@keyframes gm-fall-ci { 0% { transform: none; opacity: 1; } 15% { transform: translate(-4px, 0); } 30% { transform: translate(4px, 0); } 45% { transform: translate(-3px, 2px); } 60% { transform: translate(3px, 4px) skew(-4deg, 0); } 88% { transform: translate(0, 44px) skew(-10deg, 0); opacity: .1; } 100% { transform: none; opacity: 1; } }
@keyframes gm-fall-crossplane { 0% { transform: none; opacity: 1; filter: none; } 60% { transform: scale(1.12); opacity: .5; filter: blur(2px); } 90% { transform: scale(1.3); opacity: 0; filter: blur(5px); } 100% { transform: none; opacity: 1; filter: none; } }
@keyframes gm-fall-observability { 0% { opacity: 1; } 20% { opacity: .2; } 35% { opacity: .9; } 50% { opacity: .1; } 65% { opacity: .6; } 90% { opacity: 0; transform: translate(0, 8px); } 100% { opacity: 1; transform: none; } }
@keyframes gm-fall-security { 0% { transform: none; opacity: 1; } 40% { transform: skew(8deg, 0) translate(0, 4px); } 70% { transform: skew(-14deg, 0) scale(1, .7) translate(0, 24px); opacity: .6; } 90% { transform: skew(-20deg, 0) scale(1, .1) translate(0, 46px); opacity: .1; } 100% { transform: none; opacity: 1; } }
.gm-enemy.fx-win[data-family="workload"] canvas { animation: gm-fall-workload .9s ease-in; }
.gm-enemy.fx-win[data-family="networking"] canvas { animation: gm-fall-networking .9s ease-in-out; }
.gm-enemy.fx-win[data-family="storage"] canvas { animation: gm-fall-storage .9s ease-in; }
.gm-enemy.fx-win[data-family="gitops"] canvas { animation: gm-fall-gitops .9s ease-in; }
.gm-enemy.fx-win[data-family="ci"] canvas { animation: gm-fall-ci .9s ease-in; }
.gm-enemy.fx-win[data-family="crossplane"] canvas { animation: gm-fall-crossplane .9s ease-out; }
.gm-enemy.fx-win[data-family="observability"] canvas { animation: gm-fall-observability .9s linear; }
.gm-enemy.fx-win[data-family="security"] canvas { animation: gm-fall-security .9s ease-in; }
/* evidence shakes the guard bar and flashes its track: the guard is what the evidence chips at */
@keyframes gm-bar-shake { 0%, 100% { transform: translate(0, 0); } 25% { transform: translate(-3px, 0); } 50% { transform: translate(3px, 0); } 75% { transform: translate(-2px, 0); } }
@keyframes gm-bar-flash { 0%, 100% { background: var(--surface-3); } 30% { background: var(--warn); } }
.gm-bar.fx-shake { animation: gm-bar-shake .35s ease-out, gm-bar-flash .35s ease-out; }
/* a hit flashes the stage's edge: the blow lands on the screen, not only on the figure */
@keyframes gm-edge { 0% { box-shadow: inset 0 0 0 6px var(--bad); } 100% { box-shadow: inset 0 0 0 0 var(--bad); } }
.gm-screen.fx-flash { animation: gm-edge .3s ease-out; }
/* a number that floats up and fades: the damage over the monster, the xp over the guard bar */
@keyframes gm-float { 0% { transform: translate(0, 0); opacity: 0; } 15% { opacity: 1; } 100% { transform: translate(0, -30px); opacity: 0; } }
.gm-float {
  position: absolute; pointer-events: none; font-family: var(--sans); font-weight: 700; font-size: 16px; line-height: 1;
  text-shadow: 1px 1px 0 var(--ink), -1px 1px 0 var(--ink), 1px -1px 0 var(--ink), -1px -1px 0 var(--ink);
  animation: gm-float 1.1s ease-out forwards;
}
.gm-enemy > .gm-float { left: 30px; top: 26px; }
.gm-float.hit { color: var(--bad-lit); }
.gm-float.gain { color: var(--ok-lit); right: 0; top: -16px; font-size: 13px; }
.gm-bar { height: 6px; background: var(--surface-3); position: relative; margin-top: 4px; }
.gm-bar i { display: block; height: 100%; background: var(--bad); transition: width .35s ease-out; }
.gm-bar.hp i { background: var(--ok); }
.gm-bar.hp.low i { background: var(--warn); }
.gm-bar.hp.crit i { background: var(--bad); }
.gm-barlbl { font-family: var(--mono); font-size: 11px; color: var(--paper-3); display: flex; justify-content: space-between; margin-top: 3px; }
.gm-ticket {
  font-family: var(--serif); font-style: italic; font-size: 14px; color: var(--paper-2); line-height: 1.5;
  border-left: 2px solid var(--warn); padding: 2px 0 2px 12px; margin: 0;
}
.gm-ticket b { font-style: normal; font-family: var(--sans); color: var(--warn); font-size: 12px; letter-spacing: .3px; }

.gm-term { display: flex; flex-direction: column; min-height: 0; flex: 1; background: var(--ink-sunk); border: 3px double var(--rule-2); border-radius: 4px; }
.gm-term .bar { display: flex; gap: 10px; padding: 4px 10px; font-family: var(--mono); font-size: 11px; color: var(--paper-3); border-bottom: 1px solid var(--rule); }
.gm-term .bar .spacer { flex: 1; }
.gm-term .bar .turn { color: var(--paper-2); }
.gm-term pre {
  margin: 0; padding: 10px 12px; flex: 1; overflow: auto; min-height: 120px; max-height: 260px;
  font-family: var(--mono); font-size: 12px; line-height: 1.55; color: var(--code-fg); white-space: pre-wrap; word-break: break-word;
}
.gm-term pre .in { color: var(--paper); }
.gm-term pre .in::before { content: "$ "; color: var(--accent); }
.gm-term pre .tell { background: var(--warn-fill); color: var(--warn-lit); border-bottom: 1px solid var(--warn); }
.gm-term pre .sys { color: var(--paper-3); font-style: italic; }
.gm-term pre .hit { color: var(--bad); } .gm-term pre .gain { color: var(--ok); } .gm-term pre .crit { color: var(--warn-lit); font-weight: 600; }
.gm-term pre .t-cmd { color: var(--accent); } .gm-term pre .t-flag { color: var(--paper-2); } .gm-term pre .t-str { color: var(--syn-str); }
.gm-term pre .t-key { color: var(--syn-key); } .gm-term pre .t-num { color: var(--syn-num); } .gm-term pre .t-cm { color: var(--syn-cm); }
.gm-term form { display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-top: 1px solid var(--rule); }
.gm-term form .ps { font-family: var(--mono); color: var(--accent); font-size: 13px; }
.gm-term input {
  flex: 1; min-width: 0; background: transparent; border: none; outline: none; color: var(--paper);
  font-family: var(--mono); font-size: 13px; padding: 4px 0;
}
.gm-term input::placeholder { color: var(--paper-3); }
.gm-acts { display: flex; gap: 6px; flex-wrap: wrap; }
.gm-acts button, .gm-btn {
  font-family: var(--sans); font-weight: 600; font-size: 13px; letter-spacing: .2px; cursor: pointer;
  background: var(--surface); color: var(--paper); border: 1px solid var(--rule-2); padding: 10px 14px; line-height: 1.25;
  min-height: 42px; border-radius: 3px; box-shadow: inset 0 1px 0 #ffffff16, 0 2px 0 var(--ink-sunk);
}
.gm-acts button:hover, .gm-btn:hover { background: var(--paper); color: var(--ink); }
.gm-acts button.ghost, .gm-btn.ghost { color: var(--paper-2); border-color: var(--rule-2); }
.gm-acts button.sel { background: var(--accent); color: var(--ink); border-color: var(--accent); }
.gm-acts button:disabled { color: var(--paper-3); border-color: var(--rule); cursor: default; background: none; }
.gm-sub { border: 1px solid var(--rule); padding: 6px; max-height: 220px; overflow: auto; }
.gm-sub .hd { font-family: var(--mono); font-size: 11px; color: var(--paper-3); padding: 2px 10px 6px; }

/* the end-of-battle card */
.gm-result { text-align: center; padding: 26px 12px; max-width: 760px; margin: auto; width: 100%; }
.gm-result h4 { font-family: var(--sans); font-size: 26px; margin: 0 0 6px; color: var(--paper); }
.gm-result h4.win { color: var(--ok); } .gm-result h4.crit { color: var(--warn); } .gm-result h4.lose { color: var(--bad); }
.gm-result .gain { font-family: var(--mono); font-size: 13px; color: var(--paper-2); margin: 0 0 12px; }
.gm-result .gain b { color: var(--paper); font-weight: 500; }
.gm-result .ans { text-align: left; font-family: var(--serif); font-size: 14px; color: var(--paper-2); border-top: 1px solid var(--rule); padding-top: 12px; margin: 12px auto 0; max-width: 60ch; line-height: 1.55; }

/* ── the shop and the pack ─────────────────────────────────── */
.gm-items { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(var(--gm-item-min), 100%), 1fr)); gap: var(--gm-item-gap); }
.gm-item { border: 1px solid var(--rule); padding: 14px; display: flex; flex-direction: column; gap: 8px; background: var(--ink); text-align: left; color: var(--paper); cursor: pointer; border-radius: 4px; }
.gm-item:hover { border-color: var(--rule-2); }
.gm-item:disabled { cursor: default; color: var(--paper-3); }
.gm-item .nm { font-family: var(--sans); font-weight: 600; font-size: 14px; display: flex; justify-content: space-between; gap: 8px; }
.gm-item .nm .p { font-family: var(--mono); font-weight: 400; font-size: 11.5px; color: var(--warn); }
.gm-item .nm .h { font-family: var(--mono); font-weight: 400; font-size: 11.5px; color: var(--ok); }
.gm-item .ab { font-size: 12.5px; color: var(--paper-3); line-height: 1.45; }

/* ── touch controls ───────────────────────────────────────── */
.gm-pad { display: flex; justify-content: space-between; align-items: center; margin-top: 12px; gap: 12px; }
/* two rows, not three: up over the middle, and down between left and right, so the pad is a T and not a cross with a hole in it */
.gm-dpad { display: grid; grid-template-columns: repeat(3, 40px); grid-template-rows: repeat(2, 40px); gap: 2px; }
.gm-dpad button, .gm-ab button {
  display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1;
  font-family: var(--mono); font-size: 14px; cursor: pointer; background: var(--surface); color: var(--paper-2);
  border: 1px solid var(--rule-2); padding: 0; touch-action: manipulation; user-select: none; -webkit-user-select: none;
}
.gm-dpad button:active, .gm-ab button:active { background: var(--paper); color: var(--ink); }
.gm-dpad .u { grid-column: 2; grid-row: 1; } .gm-dpad .l { grid-column: 1; grid-row: 2; }
.gm-dpad .r { grid-column: 3; grid-row: 2; } .gm-dpad .dn { grid-column: 2; grid-row: 2; }
.gm-ab { display: flex; gap: 8px; }
.gm-ab button { width: 52px; height: 52px; font-family: var(--sans); font-weight: 700; font-size: 15px; }
.gm-ab button b { display: block; margin-top: 3px; font-family: var(--mono); font-weight: 400; font-size: 9.5px; color: var(--paper-3); }
/* the fullscreen toggle: the same key as A and B, narrower, since it is pressed once a session and not once a step */
.gm-fs[aria-pressed="true"] { border-color: var(--accent); color: var(--paper); }
.gm-keys { font-family: var(--mono); font-size: 11.5px; color: var(--paper-3); flex: 1; text-align: center; }
.gm-keys b { font-weight: 400; color: var(--paper-2); line-height: 2; }
@media (max-width: 560px) { .gm-keys { display: none; } }

.gm-toolbar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; padding: 2px 2px 18px; }
.gm-brand { display: flex; align-items: center; gap: 16px; }
.gm-brand strong { display: block; font-family: var(--serif); font-size: 24px; line-height: 1.2; letter-spacing: 2px; color: var(--paper); }
.gm-overline { display: block; font-family: var(--mono); font-size: 9px; letter-spacing: 1.5px; color: var(--accent); line-height: 2; text-transform: uppercase; }
.gm-emblem { display: block; width: 22px; height: 34px; flex: none; background: linear-gradient(115deg, #f6e8bd 0 25%, #d6bd86 25% 48%, #897044 48% 70%, #e2cd9f 70%); clip-path: polygon(50% 0, 100% 35%, 75% 83%, 50% 100%, 25% 83%, 0 35%); }
.gm-tools { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
.gm-tools .gm-btn { font-size: 12px; }
.gm-tools [aria-pressed="true"] { color: var(--accent); border-color: var(--accent); }
.gm-tools .gm-btn:disabled { opacity: .55; cursor: default; background: transparent; color: var(--paper-3); }
.gm-page-number { float: right; font-family: var(--mono); color: var(--paper-3); font-size: 10px; }
.gm-stage:not(.gm-map) { aspect-ratio: auto; height: var(--gm-fit-height, 740px); }
.gm-stage[data-scene="town"] > .gm-screen { padding: 0; }
.gm-town { display: grid; grid-template-columns: minmax(180px, .8fr) minmax(0, 2fr); grid-template-rows: auto minmax(0, 1fr) auto; height: 100%; min-height: 0; padding: 12px; gap: 12px; }
.gm-town > .gm-scene { grid-column: 2; grid-row: 2; width: 100%; height: 100%; min-height: 0; object-fit: contain; background: var(--ink-sunk); border: 1px solid var(--rule); border-radius: 4px; }
.gm-town > .gm-title { grid-column: 1 / -1; grid-row: 1; padding: 10px 14px; margin: 0; background: var(--ink); background-image: var(--gm-window); border: 3px double var(--gm-rim); border-radius: 4px; box-shadow: 2px 3px 0 #0008; }
.gm-town > .gm-body > .gm-col { padding: 10px; border: 3px double var(--gm-rim); border-radius: 4px; background: var(--ink); background-image: var(--gm-window); box-shadow: 2px 3px 0 #0008; min-height: 0; overflow: auto; }
.gm-town > .gm-body { display: contents; }
.gm-town > .gm-body > .gm-col:first-child { grid-column: 1; grid-row: 2; align-self: stretch; }
.gm-town > .gm-body > .gm-col:first-child .gm-menu button,
.gm-town > .gm-body > .gm-col:first-child .gm-menu a { min-height: 38px; padding-top: 8px; padding-bottom: 8px; font-family: var(--mono); font-size: 13px; }
.gm-town .gm-menu button::before, .gm-town .gm-menu a::before { top: 11px; }
.gm-town > .gm-body > .gm-col:last-child { grid-column: 1 / -1; grid-row: 3; min-height: 180px; overflow: visible; padding: 16px 18px; }
.gm-conversation .gm-lines { padding: 0; }
.gm-conversation .gm-acts { align-items: center; }
.gm-dialogue-next { margin-left: auto; }
.gm-conversation .gm-speech { font-size: 15px; line-height: 1.6; }
.gm-conversation .gm-lines .teach { padding: 8px 12px; }
.gm-stage[data-scene="town"] { height: var(--gm-fit-height, 640px); }
.quest-guide { margin-top: 24px; padding: 16px 0; border-top: 1px solid var(--rule); font-size: 14px; }
.quest-guide summary { cursor: pointer; font-weight: 600; color: var(--paper-2); }
.quest-guide p { max-width: 80ch; margin: 14px 0 0; }
.gm-lines { padding: 8px 2px; }
.gm-lines .teach { padding: 14px; border: 1px solid var(--ok); background: var(--ok-fill); border-radius: 3px; }
.gm-feedback { padding: 12px 16px; border-left: 3px solid currentColor; margin: 4px 0; font-size: 14px; background: var(--ink-sunk); }
.gm-feedback.ok { color: var(--ok); }
.gm-feedback.bad { color: var(--bad); }

/* The battlefield is separate from the command windows, like a turn-based RPG. */
.gm-battle { display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.gm-battle > .gm-title { margin-bottom: 0; }
.gm-arena { position: relative; height: 230px; flex: none; overflow: hidden; border: 3px double var(--gm-rim); border-radius: 4px; background: #18384d; isolation: isolate; }
.gm-arena > .gm-scene { width: 100%; height: 100%; object-fit: cover; border: 0; border-radius: 0; }
.gm-arena .gm-enemy { position: absolute; inset: 0; display: block; pointer-events: none; }
.gm-arena .gm-enemy > canvas { position: absolute; width: 128px; height: 128px; left: 12%; bottom: 22px; background: transparent; border: 0; filter: drop-shadow(3px 5px 0 #09192580); transform-origin: 50% 90%; }
.gm-arena .gm-enemy .side { position: absolute; right: 10px; bottom: 10px; width: 30%; min-width: 165px; padding: 10px 12px; border: 3px double var(--gm-rim); border-radius: 3px; background: var(--ink); background-image: var(--gm-window); box-shadow: 2px 3px 0 #0006; }
.gm-arena .gm-enemy .nm { font-size: 15px; line-height: 1.3; }
.gm-arena .gm-enemy .lv { font-size: 10px; }
.gm-arena .gm-enemy > .gm-float { left: 20%; top: 40%; font-size: 24px; z-index: 3; }
.gm-arena .gm-bar { height: 7px; margin-top: 8px; box-shadow: 0 0 0 1px var(--ink-sunk); }
.gm-bar i { background-image: linear-gradient(0deg, #0002, #fff3); }
.gm-action { position: absolute; top: 10px; left: 50%; transform: translateX(-50%); max-width: calc(100% - 20px); padding: 7px 14px; border: 1px solid var(--accent); background: var(--ink); color: var(--accent-lit); font: 11px var(--mono); text-align: center; width: max-content; border-radius: 3px; z-index: 2; }
.gm-party { position: absolute; left: 49%; bottom: 22px; display: flex; flex-direction: column; align-items: center; gap: 3px; }
.gm-party canvas { width: 64px; height: 64px; image-rendering: pixelated; filter: drop-shadow(2px 4px 0 #09192590); }
.gm-party span { font: 9px var(--mono); color: var(--accent-lit); background: var(--ink); padding: 2px 6px; }
.gm-arena::after { content: ""; position: absolute; left: 18%; right: 42%; top: 58%; height: 3px; pointer-events: none; opacity: 0; background: #d9fcff; box-shadow: 0 0 12px 5px #8be8eb; transform-origin: right center; }
.gm-arena.fx-cast::after { animation: gm-spell .5s ease-out; }
.gm-arena.fx-cast .gm-party canvas { animation: gm-lunge .45s ease-out; }
.gm-arena.fx-retaliate .gm-party canvas { animation: gm-shake .4s ease-out; }
.gm-arena.fx-resolve::after { animation: gm-spell .6s ease-out; background: #fff0aa; box-shadow: 0 0 16px 8px #f2cc7777; }
.gm-battle .gm-ticket { padding: 10px 12px; background: var(--ink); border: 1px solid var(--rule); border-left: 3px solid var(--warn); border-radius: 3px; }
.gm-battle .gm-acts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.gm-battle .gm-acts button { text-align: left; }
.gm-execute { flex: none; color: var(--accent); }
.gm-sub { background: var(--ink); border-radius: 3px; }
.gm-result > .gm-emblem { margin: 0 auto 10px; width: 34px; height: 52px; }
.gm-result h4 { font-family: var(--serif); font-size: 34px; }
.gm-rewards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 24px auto; }
.gm-rewards > div { padding: 16px 8px; border: 3px double var(--rule-2); border-radius: 4px; background: var(--ink); }
.gm-rewards b { display: block; font: 25px var(--serif); color: var(--accent); }
.gm-rewards span { display: block; margin-top: 5px; font: 10px var(--mono); color: var(--paper-3); }
.gm-level-up { color: var(--accent); font: 15px var(--mono); padding: 10px; border: 1px solid var(--accent); background: var(--accent-fill); }
.gm-journal { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; margin: 10px 0; }
.gm-region { padding: 14px; border: 3px double var(--rule-2); border-radius: 4px; background: var(--ink); }
.gm-region h4 { margin: 0 0 8px; font: 20px var(--serif); color: var(--paper); display: flex; align-items: center; gap: 10px; }
.gm-region-number { font: 11px var(--mono); color: var(--accent); }
.gm-region progress { width: 100%; height: 7px; margin: 10px 0; accent-color: var(--ok); }
.gm-region .gm-menu button { flex-wrap: wrap; }
.gm-region .gm-menu .k { white-space: nowrap; }

.gm-transition { position: absolute; inset: 0; z-index: 8; pointer-events: none; display: flex; align-items: center; justify-content: center; text-align: center; padding: 24px; background: var(--ink-sunk); color: var(--accent-lit); font: 24px var(--serif); letter-spacing: 2px; animation: gm-travel .65s ease-out both; }
.gm-transition.encounter { background: repeating-linear-gradient(160deg, var(--ink-sunk) 0 30px, var(--surface) 30px 60px); animation-name: gm-encounter; }
.gm-transition.reward, .gm-transition.rest { background: var(--ink); }
@keyframes gm-travel { 0% { opacity: .96; } 35% { opacity: .9; } 100% { opacity: 0; } }
@keyframes gm-encounter { 0% { clip-path: inset(0); opacity: 1; } 40% { clip-path: inset(0); opacity: 1; } 100% { clip-path: inset(50% 0); opacity: 0; } }
@keyframes gm-dialog-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes gm-spell { 0% { opacity: 0; transform: scaleX(0); } 35% { opacity: 1; transform: scaleX(1); } 100% { opacity: 0; transform: scaleX(1); } }
@keyframes gm-lunge { 40% { transform: translateX(-10px); } 100% { transform: none; } }
.gm-result.fx-reward { animation: gm-dialog-in .5s ease-out; }

/* ── fullscreen: the quest over the whole window ───────────
   A trial's four answers run to a paragraph each and a battle's terminal keeps a
   log, so the pad's ⛶ (or f) lifts the quest out of the page: the host covers the
   window, the stage takes the height the pad leaves, and the screens scroll inside
   it as they always have. The browser's own fullscreen is asked for as well where
   it has one for an element; this is what the page looks like either way. */
.gm-full {
  position: fixed; inset: 0; z-index: 90; margin: 0; padding: 8px;
  max-width: none; border-radius: 0;
  background: var(--ink-sunk); display: flex; flex-direction: column; justify-content: center;
  /* iOS resolves inset against the layout viewport, which is taller than the window the browser's bars leave */
  height: 100dvh;
  /* the pad is the only control a touch device has: if it ever outgrows the room left (a browser's minimum font
     size, text-only zoom), the box scrolls to it rather than centring it off the bottom of a page that cannot scroll */
  overflow: auto;
  justify-content: safe center;
}
html.gm-full-lock, html.gm-full-lock body { overflow: hidden; }
/* .wrap is a stacking context of the page's own (style.css: body > * { z-index: 1 }), so no z-index of the quest's can
   reach over the topbar from inside it. Nothing of the page shows over the quest while it holds the window: the topbar
   goes, and the palette and the help card (.overlay) stay above it deliberately, so both still open over the quest. */
html.gm-full-lock .topbar { display: none; }
.gm-full .gm-stage { flex: 1 1 auto; min-height: 0; aspect-ratio: auto; box-shadow: none; }
/* the map keeps its 30 by 19 so no art pixel is stretched: it is capped to the height the pad leaves (its two
   rows of 40, the gap over them and this box's own padding) and centered in what is left */
.gm-full .gm-stage.gm-map {
  flex: 0 0 auto; aspect-ratio: 30 / 19; margin: 0 auto;
  max-width: calc((100vh - 182px) * 30 / 19);
  max-width: calc((100dvh - 182px) * 30 / 19);
}
/* a screen scrolls in place, as on a wide page: on a narrow one the stage is no longer the tall box the phone rules make it */
.gm-full .gm-screen { position: absolute; inset: 0; min-height: 0; }
/* and a line of a trial's answer stays a line, not the width of a monitor */
.gm-full .gm-body { width: 100%; max-width: 1200px; margin: 0 auto; }
.gm-full .gm-pad { flex: none; margin-top: 8px; }
.gm-full .gm-toolbar { flex: none; padding-bottom: 10px; min-height: 60px; }
.gm-full .gm-stage:not(.gm-map) { height: auto; }
/* The trial hangs its body straight on the screen, so .gm-body's flex: 1 fills it. A battle and a town wrap theirs in a
   box of their own, which is content-tall: without this the screen grows and the fight stays the size it was, the log
   clipped at its 260px with half a window empty under it. Give the wrapper the height, and the log the room. */
.gm-full .gm-battle { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.gm-full .gm-town { flex: 1 1 auto; min-height: 0; }
.gm-full .gm-term pre { max-height: none; }
/* a phone held on its side has no height to spare, so fullscreen there gives the pad's back to the screen */
@media (max-height: 560px) {
  .gm-full { padding: 4px; }
  .gm-full .gm-toolbar { min-height: 44px; padding: 0 0 4px; }
  .gm-full .gm-brand .gm-overline { display: none; }
  .gm-full .gm-arena { height: 160px; }
  .gm-full .gm-pad { margin-top: 4px; }
  .gm-full .gm-dpad { grid-template-columns: repeat(3, 32px); grid-template-rows: repeat(2, 32px); }
  .gm-full .gm-ab button { width: 44px; height: 44px; }
  .gm-full .gm-stage.gm-map {
    max-width: calc((100vh - 132px) * 30 / 19);
    max-width: calc((100dvh - 132px) * 30 / 19);
  }
}

/* ── responsive ───────────────────────────────────────────── */
@media (min-width: 721px) and (hover: hover) and (pointer: fine) {
  .gm-pad, .gm-full .gm-pad { display: none; }
  .gm-full .gm-stage.gm-map { max-width: calc((100dvh - 92px) * 30 / 19); }
}
@media (max-width: 1000px) {
  .quest-layout { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .quest-layout .quest-stats { grid-column: 1; grid-row: 1; position: static; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
  .quest-layout #play { grid-row: 2; }
  :root .quest-stats .stat, :root .quest-stats .stat:first-child { padding: 0; border: 0; }
  :root .quest-stats .stat .val { font-size: 18px; }
  :root .quest-stats .stat .lbl { font-size: 9px; letter-spacing: 0; }
  .quest-stats .stat .u { font-size: 9px; }
  :root body[data-id="GM"] .reading-menu { margin-bottom: 14px; }
}
@media (max-width: 720px) {
  .gm { padding: 8px; }
  .gm-toolbar { flex-wrap: wrap; gap: 12px; padding: 4px 4px 14px; }
  .gm-brand strong { font-size: 21px; }
  .gm-tools { justify-content: flex-start; }
  .gm-body { grid-template-columns: minmax(0, 1fr); }
  .gm-town { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto auto; height: auto; gap: 8px; padding: 8px; }
  .gm-town > .gm-title { padding: 8px; }
  .gm-town > .gm-scene { grid-column: 1; grid-row: 2; height: auto; aspect-ratio: 480 / 304; }
  .gm-town > .gm-body > .gm-col:first-child { grid-column: 1; grid-row: 3; }
  .gm-town > .gm-body > .gm-col:last-child { grid-column: 1; grid-row: 4; padding: 12px; min-height: 0; }
  .gm-stage { aspect-ratio: auto; min-height: 420px; }
  .gm-stage:not(.gm-map) { height: auto; }
  .gm-stage.gm-map { aspect-ratio: 30 / 19; min-height: 0; }
  .gm-screen { position: relative; inset: auto; min-height: 420px; padding: 12px; }
  /* off the map the screen is in the flow, so the canvas under it must give its box back too: hidden, it would
     hold a phone's first half-screen of a trial empty (on a wide page the screen covers it, and it can stay) */
  .gm-stage:not(.gm-map) > canvas { display: none; }
  .gm-enemy canvas { width: 64px; height: 64px; }
  .gm-term pre { max-height: 200px; }
  .gm-town > .gm-body > .gm-col:first-child > .gm-menu { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gm-town > .gm-body > .gm-col:first-child .gm-menu button, .gm-town > .gm-body > .gm-col:first-child .gm-menu a { flex-wrap: wrap; gap: 4px; height: 100%; }
  .gm-town > .gm-body > .gm-col:first-child .gm-menu .k { margin-left: 0; width: 100%; font-size: 10px; }
  .gm-arena { height: 210px; }
  .gm-arena .gm-enemy > canvas { width: 96px; height: 96px; left: 5%; bottom: 32px; }
  .gm-arena .gm-enemy .side { width: 44%; min-width: 0; font-size: 10px; padding: 8px; right: 6px; bottom: 6px; }
  .gm-arena .gm-enemy .nm { font-size: 13px; }
  .gm-arena .gm-enemy .lv { display: none; }
  .gm-arena .gm-barlbl { font-size: 9px; }
  .gm-party { left: 39%; bottom: 66px; }
  .gm-party canvas { width: 48px; height: 48px; }
  .gm-action { font-size: 9px; padding: 6px 8px; }
  .gm-journal { grid-template-columns: minmax(0, 1fr); }
  .gm-full .gm-stage.gm-map { max-width: calc((100dvh - 230px) * 30 / 19); }
  .gm-full .gm-battle, .gm-full .gm-town { flex: none; }
  .gm-full .gm-term pre { max-height: 260px; }
}
@media (max-width: 460px) {
  .gm-brand .gm-overline { display: none; }
  .gm-toolbar { gap: 8px; }
  .gm-hud { gap: 6px; padding: 5px; font-size: 10px; left: 5px; top: 5px; }
  .gm-hud .hp { gap: 1px; }
  .gm-hud .hp i { width: 3px; height: 6px; }
  .gm-side { right: 5px; top: 5px; max-width: 51%; }
  .gm-where { font-size: 9px; padding: 4px; }
  .gm-dialog { inset: auto 5px 5px; max-height: 92%; padding: 8px; font-size: 12px; }
  .gm-dialog .who { font-size: 11px; }
  .gm-pad { gap: 6px; }
  .gm-ab { gap: 4px; }
  .gm-dpad { grid-template-columns: repeat(3, 36px); grid-template-rows: repeat(2, 40px); }
  .gm-ab button { width: 44px; height: 48px; }
  .gm-rewards { gap: 4px; }
  .gm-rewards b { font-size: 20px; }
  .gm-transition { font-size: 18px; letter-spacing: 1px; }
}
@media (prefers-reduced-motion: reduce) {
  .gm *, .gm *::before, .gm *::after { animation: none !important; transition: none !important; }
}
