:root {
  --bg: #0d1117;
  --panel: #161b22;
  --ink: #e6edf3;
  --dim: #9aa4b2;
  --line: #30363d;
  --accent: #f0b429;
  --good: #3fb950;
  --bad: #f85149;
  --safe: #58a6ff;
  --player: #ffd700;
  /* The quiet stat colours, shared by the status bar and the level list: low in saturation, each at least 4.5:1 on
     the panel and the page. */
  --stat-heart: #f29b93;
  --stat-gold: #e3c068;
  --stat-teal: #7cc8bd;
  --stat-good: #8fd19e;
  --stat-amber: #e8a95c;
  --stat-parchment: #e6d6ad;
}

* { box-sizing: border-box; }

html, body { height: 100%; margin: 0; overflow: hidden; overscroll-behavior: none; }

body {
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif;
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

button {
  background: var(--accent);
  color: #1a1a1a;
  border: none;
  border-radius: 6px;
  padding: 0.45rem 0.8rem;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}
button:hover { filter: brightness(1.08); }
button:focus-visible { outline: 3px solid var(--safe); outline-offset: 2px; }
button:disabled { opacity: 0.45; cursor: default; }

/* The frame fills the window: status bar, maze, control strip. It is a size
   container, which the kit's key tabs and the phone layouts below ask. */
#frame {
  position: fixed;
  inset: 0;
  container: frame / size;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  background: var(--bg);
  overflow: hidden;
}
#title-root, #help-root, #look-root, #menu-root, #chapter-root, #levels-root, #start-root, #story-root, #end-root, #lore-root,
#dict-root, #meet-root, #banner-root, #demo-root { display: contents; }

/* ---- status bar ---- */
.status {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 6px 10px;
  border-bottom: 1px solid var(--line);
}
.hud { display: flex; flex: 1 1 auto; flex-wrap: wrap; gap: 2px 14px; min-width: 0; margin: 0; }
.stat { display: flex; gap: 0.35rem; align-items: baseline; white-space: nowrap; }
.stat dt { color: var(--dim); font-size: 0.8rem; }
.stat dd { margin: 0; font-weight: 700; font-variant-numeric: tabular-nums; }
/* Each stat's number in its quiet colour; the labels stay dim and Moves plain. Best is soft green while a perfect
   clear is still possible and amber once the moves are past it, where its words say by how many. */
.stat-hearts dd { color: var(--stat-heart); }
.stat-relics dd { color: var(--stat-gold); }
.stat-gear dd { color: var(--stat-teal); }
.stat-best dd { color: var(--stat-good); }
.stat-best.over dd { color: var(--stat-amber); }
/* "Ch. 1 • Level 3/10" stays on one line. */
.stat #hud-trial { white-space: nowrap; }
/* A tool's effect at work: a chip each, stone grey for Medusa's stone, warm for the cow standing. */
.stat-effects dd { display: flex; flex-wrap: wrap; gap: 4px; }
.fx-chip {
  padding: 0 0.5rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.78rem;
  line-height: 1.4;
  white-space: nowrap;
}
.fx-short { display: none; }
.fx-stone { color: #d7dbe2; border-color: #8a93a3; background: rgba(138, 147, 163, 0.18); }
.fx-cow { color: #f0cf9a; border-color: #b9894b; background: rgba(185, 137, 75, 0.18); }

/* Buttons that carry a key tab are positioned, so the tab pins to their corner. */
.menu-btn, .strip button {
  position: relative;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
}
.menu-btn:hover, .strip button:hover { border-color: var(--accent); filter: none; }
.menu-btn, .strip button { --kit-key-tab-right: 0; }
.menu-btn { flex: none; min-height: 36px; }
.strip button[aria-pressed="true"] { border-color: var(--accent); color: var(--accent); }

/* ---- maze ---- */
/* The board holds the frame's middle row by name: the start card stands in that row too, over it, and an item placed
   by the grid would otherwise move the board down a row while the card is up. */
.board {
  grid-row: 2;
  grid-column: 1;
  position: relative;
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  padding: 6px;
  overflow: hidden;
}
/* A new level fades in as soon as it is drawn, under its start card; Demo's board waits hidden for its first level. */
.board.board-wait > .stage-view, .board.board-wait > .modern-area { opacity: 0; }
.board.board-in-a > .stage-view, .board.board-in-a > .modern-area { animation: board-in-a 400ms ease-out both; }
.board.board-in-b > .stage-view, .board.board-in-b > .modern-area { animation: board-in-b 400ms ease-out both; }
@keyframes board-in-a { from { opacity: 0; } }
@keyframes board-in-b { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .board.board-in-a > .stage-view, .board.board-in-a > .modern-area,
  .board.board-in-b > .stage-view, .board.board-in-b > .modern-area { animation: none; }
}
/* The classic board's view fills the board's space. Its sheet (src/sheet-board.ts) lies at the view's top-left and a
   CSS transform from src/sheet.ts turns, tilts, scales and places it; the figures stand on a canvas over the whole
   view. Nothing scrolls: a zoomed view pans by moving the sheet. */
.stage-view {
  grid-area: 1 / 1;
  position: relative;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  touch-action: none;
}
.stage-view .stage.sheet { position: absolute; left: 0; top: 0; transform-origin: 0 0; }
.stage-view .stage-figures { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
/* The item bubble (src/item-bubble.ts): a small thought bubble by the Minotaur's head showing the item under him, in
   the board's look, over the board and under its controls. It fades in and out gently, at once under reduced motion. */
.item-bubbles { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.item-bubble { position: absolute; inset: 0; opacity: 0; transition: opacity 160ms ease-out; }
.item-bubble.shown { opacity: 1; }
.item-bubble-cloud, .item-bubble-puff {
  position: absolute;
  box-sizing: border-box;
  border-radius: 50%;
  background: rgba(255, 252, 240, 0.95);
  border: 1.5px solid rgba(20, 14, 6, 0.88);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}
.item-bubble-cloud { overflow: hidden; }
.item-bubble-pic { position: absolute; inset: 0; background-repeat: no-repeat; }
.item-bubbles[data-look="classic"] .item-bubble-pic { background-image: url(fx/sprites/tiles.png); }
.item-bubbles[data-look="modern"] .item-bubble-pic { background-image: url(fx/sprites/modern-icons.webp); }
@media (prefers-reduced-motion: reduce) { .item-bubble { transition: none; } }
/* The classic board's camera buttons and compass wear the modern board's look, over the view. */
.board > .classic-overlay { grid-area: 1 / 1; position: relative; inset: auto; }
.board.look-modern .stage-view, .board.look-modern .classic-overlay { display: none; }
/* The board is a canvas: src/ui.ts has it sized in whole device pixels (src/board.ts) to the largest cell that
   shows the whole level, or to the zoomed cell, and the browser never rescales it. */
.stage {
  display: block;
  image-rendering: auto;
  user-select: none;
  touch-action: manipulation;
}

/* The modern look (src/main.ts) hides the classic canvas: its own canvas and the layer over it fill the board's
   space inside the board's padding, and nothing scrolls. */
.board:not(.look-modern) .modern-area { display: none; }
.modern-area {
  position: absolute;
  inset: 0;
  box-sizing: border-box;
  padding: inherit;
  display: grid;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
}
.modern-area > * { grid-area: 1 / 1; min-width: 0; min-height: 0; width: 100%; height: 100%; }
.modern-area > .modern-overlay { position: relative; inset: auto; }
.stage3d { display: block; user-select: none; }

/* The modern look's layer over its canvas (src/modern/controls.ts, src/modern/minimap.ts): the compass at the
   bottom-right and the mini map at the bottom-left while the Mini map setting is on. Only its controls take the pointer; the canvas under
   the rest does. */
.modern-overlay { position: absolute; inset: 0; pointer-events: none; }
.modern-overlay .modern-ui[hidden] { display: none; }
.modern-overlay button, .modern-overlay .minimap { pointer-events: auto; }
.modern-overlay .minimap {
  position: absolute;
  left: 10px;
  bottom: 10px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: #0d0b0a;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.6);
  overflow: hidden;
  line-height: 0;
  cursor: pointer;
}
.modern-overlay .minimap[hidden] { display: none; }
.modern-overlay .minimap canvas { display: block; touch-action: none; }
.modern-overlay #minimap-view { position: absolute; left: 0; top: 0; }

.toast {
  position: absolute;
  left: 50%;
  top: 10px;
  transform: translateX(-50%);
  max-width: min(92%, 34rem);
  width: max-content;
  margin: 0;
  padding: 0.35rem 0.9rem;
  /* A long line (what a tool does) wraps rather than being cut short. */
  white-space: normal;
  text-align: center;
  font-size: 0.9rem;
  line-height: 1.3;
  background: rgba(1, 4, 9, 0.9);
  border: 1px solid var(--line);
  border-radius: 1rem;
  opacity: 0;
  transition: opacity 0.4s;
  pointer-events: none;
}
/* The toast sits in the board's row of the frame, not inside #board, so a scrolling board does not carry it away. */
#frame > #toast { grid-row: 2; grid-column: 1; }
.toast.show { opacity: 1; pointer-events: auto; cursor: pointer; }
.toast.good { border-color: var(--good); }
.toast.bad { border-color: var(--bad); }
.toast.info { border-color: var(--safe); }
/* A tool's button named in the line by its own picture, 1.25 times the text, centred on the line. */
.toast-pic { display: inline-block; vertical-align: middle; margin: -0.2em 0.1em 0; line-height: 0; }
.toast-pic .sprite { display: block; }

/* Demo's strip (src/ui/demo.tsx): a quiet pill at the foot of the board, over it and under every card, between the
   mini map and the compass. It takes no pointer: a tap anywhere ends Demo. */
.demo-strip {
  position: absolute;
  left: 50%;
  bottom: 12px;
  z-index: 5;
  transform: translateX(-50%);
  width: max-content;
  max-width: min(64%, 30rem);
  padding: 0.3rem 0.9rem 0.35rem;
  text-align: center;
  background: rgba(1, 4, 9, 0.72);
  border: 1px solid var(--line);
  border-radius: 12px;
  pointer-events: none;
  user-select: none;
}
.demo-strip p { margin: 0; }
.demo-line { font-size: 0.88rem; font-weight: 700; line-height: 1.3; color: var(--stat-parchment); font-variant-numeric: tabular-nums; }
.demo-hint { font-size: 0.75rem; color: var(--dim); }

/* ---- control strip ---- */
/* The move pad is one connected cross at the strip's left edge, or its right one while the frame wears pad-right (the
   Arrows setting; the actions take the other side): four arms that touch an inert centre square, so no two buttons
   are apart. An arm's tab sits at the cross's outer edge, clear of its neighbours. */
.strip {
  grid-row: 3;
  grid-column: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 14px 10px;
  border-top: 1px solid var(--line);
}
.strip button { min-width: 44px; min-height: 44px; padding: 0 0.8rem; }
.pad {
  display: grid;
  grid-template-columns: repeat(3, 44px);
  grid-template-rows: repeat(3, 44px);
  grid-template-areas: ". up ." "left hub right" ". down .";
  gap: 0;
  flex: none;
  /* A finger held or slid on the pad moves Theseus (src/pad.ts): never a scroll, a zoom, a selection or a menu. */
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}
.pad button, .strip .pad button { min-width: 44px; min-height: 44px; padding: 0; border-radius: 0; }
.pad button:focus-visible { outline-offset: -3px; z-index: 2; }
.pad button:active:not(:disabled) { background: var(--line); }
.pad-hub { grid-area: hub; background: var(--bg) url(fx/sprites/theseus-face.png) center / 78% no-repeat; image-rendering: pixelated; border: 1px solid var(--line); }
#frame.look-modern .pad-hub { background-image: url(fx/sprites/theseus-face-modern.png); background-size: 92%; image-rendering: auto; }
.mv-up { grid-area: up; border-radius: 10px 10px 0 0; }
.mv-left { grid-area: left; border-radius: 10px 0 0 10px; }
.mv-right { grid-area: right; border-radius: 0 10px 10px 0; }
.mv-down { grid-area: down; border-radius: 0 0 10px 10px; }
.mv-left .kit-key-tab { right: auto; left: 0; }
.mv-down .kit-key-tab { top: auto; bottom: -7px; }
.actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 10px 14px; }
.turn, .thread, .tools, .view { display: flex; gap: 8px; }
.strip .strip-menu { display: none; }
#frame.pad-right .strip { flex-direction: row-reverse; }
#frame.pad-right .actions { justify-content: flex-start; }
/* A phone's Thread button and its panel, which floats over the board's foot on the actions' side, clear of the pad. */
.strip .thread-btn.on { border-color: var(--accent); color: var(--accent); }
.strip .thread-btn[aria-expanded="true"] { background: var(--line); }
.thread-panel {
  position: absolute;
  z-index: 5;
  right: 8px;
  bottom: calc(100% + 6px);
  display: flex;
  gap: 8px;
  padding: 8px;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.5);
}
.thread-panel[hidden] { display: none; }
.strip .thread-panel button { min-width: 64px; }
#frame.pad-right .thread-panel { right: auto; left: 8px; }
/* A tool button: the tool's picture in the board's look (src/ui/sprite.tsx) and its count. Held, an accent border;
   none held, the picture greyed and dark; picked up, a glow round the button and a wiggle of the picture, twice
   together, then still (src/ui.ts PICKUP_MS waits them out). */
.strip .tool { display: inline-flex; align-items: center; justify-content: center; min-height: 52px; padding: 0 0.7rem 0 0.4rem; }
.tool-pic { display: inline-flex; flex: none; }
.tool .n { margin-left: 0.3rem; font-weight: 700; font-size: 1.05rem; }
.strip .tool.held { border: 1.5px solid var(--accent); }
.strip .tool.empty:disabled { opacity: 1; filter: grayscale(1) brightness(0.55); }
.tool-glow { position: absolute; inset: -1.5px; border-radius: inherit; pointer-events: none; animation: tool-glow 1.1s ease-in-out 2; }
.tool.got .tool-pic { animation: tool-wiggle 1.1s ease-in-out 2; }
@keyframes tool-glow {
  0%, 100% { box-shadow: 0 0 0 0 rgba(240, 180, 41, 0); }
  50% { box-shadow: 0 0 20px 5px rgba(240, 180, 41, 0.7); }
}
@keyframes tool-wiggle {
  0%, 100% { transform: rotate(0deg); }
  15% { transform: rotate(-14deg); }
  30% { transform: rotate(12deg); }
  45% { transform: rotate(-9deg); }
  60% { transform: rotate(6deg); }
  75% { transform: rotate(-3deg); }
}
@media (prefers-reduced-motion: reduce) {
  .tool-glow { display: none; }
  .tool.got .tool-pic { animation: none; }
}

/* ---- cards: title, menu, story, ending ---- */
.veil {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: grid;
  place-items: center;
  padding: 1rem;
  background: rgba(1, 4, 9, 0.78);
}
.veil[hidden] { display: none; }
/* The title card stands at the top of the Labyrinth's entrance (fx/blender/title_card.py): the picture's dark sky
   holds the card, the door and its fire show below it. A landscape frame gets the wide framing, a portrait frame
   (a phone) the tall one, each covering the frame from its foot so the door stays in view. The scrim darkens the
   sky behind the card and leaves the door's glow almost untouched. */
#title-veil {
  place-items: start center;
  padding-top: clamp(0.75rem, 5cqh, 3rem);
  background:
    linear-gradient(to bottom, rgba(1, 4, 9, 0.55), rgba(1, 4, 9, 0.2) 55%, rgba(1, 4, 9, 0.1) 80%, rgba(1, 4, 9, 0.45)),
    url("fx/title/title-wide.webp") center bottom / cover no-repeat,
    #020308;
}
@container frame (orientation: portrait) {
  #title-veil {
    background:
      linear-gradient(to bottom, rgba(1, 4, 9, 0.5), rgba(1, 4, 9, 0.15) 55%, rgba(1, 4, 9, 0.1) 80%, rgba(1, 4, 9, 0.45)),
      url("fx/title/title-tall.webp") center bottom / cover no-repeat,
      #020308;
  }
}
/* Over the picture the card is a touch translucent, still dark enough for its text. */
#title-veil .card { background: rgba(22, 27, 34, 0.9); }
.card {
  position: relative;
  width: 100%;
  max-width: 34rem;
  max-height: 100%;
  overflow-y: auto;
  padding: 1.25rem 1.4rem;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: 12px;
}
.card h2 { margin: 0.2rem 0 0.5rem; }
.card .kit-dialog-head { margin: 0.2rem 0 0.5rem; }
.card .kit-dialog-head h2 { margin: 0; }
.kicker { margin: 0; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; font-size: 0.8rem; }
.runstats { color: var(--dim); font-size: 0.9rem; }
.title-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.8rem; }
.title-install { margin-top: 0.8rem; }
/* The title card's buttons (src/ui/title.tsx): one column, every button its full width or half of it, the same gap
   between all. The way in is filled and taller; the rest are outlined, two to a row, a lone last one across both.
   Each name starts at the button's left and its key tab sits at the right, so names and tabs line up down the
   column. */
.title-menu { display: grid; gap: 0.5rem; margin-top: 1rem; }
.title-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.5rem; }
.title-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
.title-menu button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  min-width: 0;
  min-height: 44px;
  padding: 0 0.9rem;
  text-align: left;
}
.title-menu button .kit-key-inline { margin: 0; top: 0; }
.title-menu button.title-primary { min-height: 52px; font-size: 1.1rem; }
/* The Endless card: its seed box beside Play This Seed (stacked on a narrow phone), and the search's progress bar. */
.endless-seed { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; margin-top: 0.8rem; }
.endless-seed label { color: var(--dim); font-size: 0.9rem; }
.endless-seed input { flex: 1 1 8rem; min-width: 0; font: inherit; font-size: 16px; background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 4px; padding: 0.35rem 0.5rem; }
.endless-bar { height: 8px; margin-top: 0.6rem; overflow: hidden; background: var(--bg); border-radius: 4px; }
.endless-bar span { display: block; height: 100%; background: var(--accent); border-radius: 4px; transition: width 0.3s ease; }
@media (prefers-reduced-motion: reduce) { .endless-bar span { transition: none; } }
/* The start card sits in the board's row of the frame, so the status bar and the strip stay clear and usable. */
.veil-start {
  position: relative;
  inset: auto;
  grid-row: 2;
  grid-column: 1;
  align-self: start;
  padding: 0.5rem;
  background: none;
  pointer-events: none;
}
.veil-start .card { max-width: 22rem; max-height: none; padding: 0.9rem 1rem; pointer-events: auto; }
.start h2 { font-size: 1.05rem; margin: 0.1rem 0 0.3rem; }
.start p { margin: 0 0 0.6rem; font-size: 0.88rem; line-height: 1.3; }
.start .start-hint { margin-top: -0.3rem; font-size: 0.8rem; font-style: italic; opacity: 0.72; }
.story-text { margin: 0 0 0.7rem; }
.chapter .story { color: var(--dim); }
.chapter-quote { margin: 0.8rem 0; padding: 0.5rem 0.8rem; border-left: 3px solid var(--accent); font-style: italic; }
.chapter-quote cite { display: block; margin-top: 0.4rem; color: var(--dim); font-size: 0.8rem; font-style: normal; }
.chapter-ending { margin: 0.8rem 0; padding: 0.6rem 0.8rem; border: 1px solid var(--accent); border-radius: 6px; }
.chapter-ending h3 { margin: 0.2rem 0 0.4rem; font-size: 1rem; }
.chapter-ending .story { margin: 0; }
.chapter-tabs { display: flex; gap: 4px; flex-wrap: wrap; margin: 0.6rem 0; }
.chapter-tab { min-height: 32px; padding: 0 0.5rem; font-size: 0.78rem; font-weight: 600; background: var(--bg); color: var(--dim); border: 1px solid var(--line); }
.chapter-tab[aria-pressed="true"] { border-color: var(--accent); color: var(--ink); }
.chapter-tab:disabled { opacity: 0.45; }
.level-list { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 6px; }
.level-pick {
  width: 100%;
  display: grid;
  grid-template-columns: 1.6rem 1fr;
  grid-template-areas: "n name" "n status";
  column-gap: 0.5rem;
  align-items: baseline;
  text-align: left;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--line);
}
.level-pick[aria-pressed="true"] { border-color: var(--accent); }
.level-n { grid-area: n; color: var(--accent); font-variant-numeric: tabular-nums; }
.level-name { grid-area: name; }
.level-status { grid-area: status; color: var(--dim); font-size: 0.8rem; font-weight: 400; }
/* The level list's marks, in the status bar's colours, each with its words: a tick by cleared, a star by perfect. */
.mark-clear { color: var(--stat-good); }
.mark-clear::before { content: "✓ "; }
.mark-perfect { color: var(--stat-gold); }
.mark-perfect::before { content: "★ "; }
.mark-over { color: var(--stat-amber); }
.mark-page { color: var(--stat-parchment); }
.lore h3 { margin: 0.8rem 0 0.3rem; font-size: 1rem; color: var(--accent); }
.lore .story { color: var(--dim); }
.lore-entries { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.lore-pick { width: 100%; display: flex; justify-content: space-between; gap: 0.5rem; text-align: left; background: var(--bg); color: var(--ink); border: 1px solid var(--line); }
.lore-pick:disabled { opacity: 0.6; }
.lore-where { color: var(--dim); font-size: 0.8rem; font-weight: 400; }
.lore-soon { margin: 0.5rem 0 0; color: var(--dim); font-size: 0.85rem; }

/* A picture from the Classic atlas (src/ui/sprite.tsx): each layer is one atlas cell, scaled to the picture's size. */
.sprite { position: relative; display: inline-block; flex: none; overflow: hidden; }
.sprite-layer { position: absolute; left: 0; top: 0; transform-origin: 0 0; background: url(fx/sprites/tiles.png) no-repeat; }
.sprite.locked .sprite-layer:not(.sprite-floor) { filter: brightness(0); opacity: 0.8; }
.sprite.locked .sprite-floor { opacity: 0.35; }
.sprite-family { display: inline-flex; flex: none; flex-wrap: wrap; align-content: flex-start; }
/* A Modern icon (fx/sprites/modern-icons.webp): one cell of the sheet, sized to the picture. */
.modern-layer { background-image: url(fx/sprites/modern-icons.webp); transform: none; }

/* The first card: picture beside its words. */
.card.meet { max-width: 26rem; }
.meet-body { display: flex; gap: 0.9rem; align-items: flex-start; }
.meet-words { min-width: 0; }
.meet-lore { margin: 0 0 0.6rem; color: var(--dim); font-style: italic; }
.meet-effect { margin: 0 0 0.4rem; }
.meet-note { margin: 0.2rem 0 0.8rem; color: var(--dim); font-size: 0.85rem; }

/* The Dictionary: two tabs, then rows of picture and words. */
.card.dict { max-width: 34rem; }
.dict-tabs { margin-bottom: 0.6rem; }
.dict-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.dict-row { display: flex; gap: 0.7rem; align-items: flex-start; padding: 0.5rem 0.6rem; background: var(--bg); border: 1px solid var(--line); border-radius: 8px; }
.dict-row.locked { align-items: center; color: var(--dim); }
.dict-words { min-width: 0; }
.dict-name { display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem; margin: 0; font-weight: 700; }
.dict-count { color: var(--accent); }
.dict-lore { margin: 0.2rem 0 0; color: var(--dim); font-style: italic; font-size: 0.85rem; }
.dict-effect { margin: 0.2rem 0 0; font-size: 0.88rem; }
.dict-group h3 { margin: 0.9rem 0 0.4rem; font-size: 0.8rem; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; }
.dict-tally, .dict-empty { margin: 0; color: var(--dim); font-size: 0.85rem; }

/* The banner on a later pickup: in the board's row under the toast, over the board and under every card. It takes no
   pointer, so play goes on beneath it. It slides in, holds and fades in BANNER_MS (src/notices.ts). */
.banner {
  position: absolute;
  grid-row: 2;
  grid-column: 1;
  left: 50%;
  top: 48px;
  z-index: 5;
  width: max-content;
  max-width: min(92%, 26rem);
  transform: translateX(-50%);
  pointer-events: none;
}
.banner-box {
  display: grid;
  gap: 4px;
  padding: 0.4rem 0.7rem;
  background: rgba(1, 4, 9, 0.92);
  border: 1px solid var(--accent);
  border-radius: 10px;
  animation: banner 2.5s ease-out both;
}
.banner-row { display: flex; align-items: center; gap: 0.5rem; margin: 0; font-size: 0.88rem; line-height: 1.25; }
.banner-name { font-weight: 700; white-space: nowrap; }
.banner-short { color: var(--dim); }
.banner-heart { color: var(--bad); font-size: 1.1rem; }
@keyframes banner {
  0% { opacity: 0; transform: translateY(-120%); }
  12% { opacity: 1; transform: none; }
  80% { opacity: 1; }
  100% { opacity: 0; }
}
@keyframes banner-still {
  0%, 80% { opacity: 1; }
  100% { opacity: 0; }
}
/* The rule tip (src/rule-tips.ts), under the banner: a line and Got It. Only it takes a pointer; it holds play (the
   pad and the keys that play wait) until Got It, Enter or Space, while the camera and the menu go on working. */
.tip-box {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 6px 10px;
  padding: 0.45rem 0.6rem 0.45rem 0.75rem;
  background: rgba(1, 4, 9, 0.92);
  border: 1px solid var(--safe);
  border-left-width: 4px;
  border-radius: 10px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
  pointer-events: auto;
  touch-action: manipulation;
  animation: tip-in 0.3s ease-out both;
}
.banner-box + .tip-box { margin-top: 6px; }
.tip-text { flex: 1 1 14rem; margin: 0; font-size: 0.92rem; line-height: 1.3; }
.tip-ok { min-height: 36px; padding: 0.3rem 0.8rem; font-size: 0.88rem; }
@keyframes tip-in { from { opacity: 0; transform: translateY(-8px); } }
/* A press the tip holds back nudges it once: a soft swell of its edge and of Got It, so the player sees why nothing
   moved. Two names, so each nudge starts the pulse again. */
.tip-box.nudge-a { animation: tip-nudge-a 0.5s ease-out; }
.tip-box.nudge-b { animation: tip-nudge-b 0.5s ease-out; }
@keyframes tip-nudge-a { 40% { box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.45), 0 4px 14px rgba(0, 0, 0, 0.5); transform: scale(1.015); } }
@keyframes tip-nudge-b { 40% { box-shadow: 0 0 0 3px rgba(88, 166, 255, 0.45), 0 4px 14px rgba(0, 0, 0, 0.5); transform: scale(1.015); } }

/* Quieter buttons: outlined, not filled. A danger button is outlined in red. */
button.quiet { background: var(--bg); color: var(--ink); border: 1px solid var(--line); font-weight: 600; }
button.quiet:hover { border-color: var(--accent); filter: none; }
button.danger { background: transparent; color: #ff7b72; border: 1px solid var(--bad); min-height: 44px; padding: 0 1.1rem; }
button.danger:hover { background: rgba(248, 81, 73, 0.12); filter: none; }

/* The two looks as pictures side by side (the new-game card and the menu's Board section). */
.look-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.look-tile {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 5px;
  padding: 5px 5px 8px;
  background: var(--bg);
  color: var(--ink);
  border: 2px solid var(--line);
  border-radius: 9px;
}
.look-tile:hover { border-color: var(--dim); filter: none; }
.look-tile[aria-pressed="true"] { border-color: var(--accent); }
.look-tile img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 5px; background: var(--panel); }
.look-name { text-align: center; font-size: 0.95rem; }
.look-tile[aria-pressed="true"] .look-name { color: var(--accent); }
.look-blurb { text-align: center; font-size: 0.8rem; font-weight: 400; line-height: 1.3; color: var(--dim); }
.look-pick h2 { font-size: 1.3rem; }
.look-pick .runstats { margin: 0.7rem 0 0; }

/* The menu: sections under small gold headings; two columns when there is room. */
.card.menu { max-width: 30rem; }
/* The open level's name, under the Menu title. */
.menu-level { margin: -0.3rem 0 0.9rem; color: var(--dim); font-style: italic; }
/* During an Endless run: the seed, which a press selects whole, and Copy Seed Link beside it. */
.menu-seed { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 0.8rem; margin: -0.4rem 0 0.9rem; }
.menu-seed p { margin: 0; color: var(--dim); }
.menu-seed-text { color: var(--ink); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 700; user-select: all; -webkit-user-select: all; }
.menu-seed button { min-height: 36px; }
.menu-cols { display: grid; gap: 1.1rem 1.6rem; align-items: start; }
.menu-col { display: grid; gap: 1.1rem; min-width: 0; }
.menu-sec { display: grid; gap: 0.45rem; }
.menu h3 { margin: 0; font-size: 0.8rem; font-weight: 600; color: var(--accent); text-transform: uppercase; letter-spacing: 0.06em; }
/* A list of rows in one bordered box: switches, and the story's entries. */
.menu-list { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: 9px; overflow: hidden; background: var(--bg); }
.menu-list > * + * { border-top: 1px solid var(--line); }
.menu-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  width: 100%;
  min-height: 48px;
  padding: 0.35rem 0.9rem;
  background: transparent;
  color: var(--ink);
  border-radius: 0;
  font-weight: 600;
  text-align: left;
}
.menu-row:hover { background: rgba(240, 180, 41, 0.07); filter: none; }
.menu-row-name { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.menu-row-name small { font-size: 0.78rem; font-weight: 400; color: var(--dim); }
.menu-row-go { color: var(--dim); font-size: 1.2rem; }
.menu-row .kit-key-inline { order: 1; flex: none; margin: 0; top: 0; }
.menu-row .switch, .menu-row-go { order: 2; }
/* A switch: a track with a knob, gold and to the right when on. */
.switch { position: relative; flex: none; width: 46px; height: 26px; border-radius: 13px; background: var(--line); transition: background 0.15s; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--dim); transition: left 0.15s; }
[aria-checked="true"] > .switch { background: var(--accent); }
[aria-checked="true"] > .switch::after { left: 23px; background: var(--bg); }
@media (prefers-reduced-motion: reduce) { .switch, .switch::after { transition: none; } }
/* Walls: one control in three parts; the part chosen is filled gold with dark text. */
.menu-walls { display: flex; align-items: center; gap: 0.8rem; margin-top: 0.2rem; }
.menu-label { flex: none; min-width: 2.8rem; font-weight: 600; }
.seg { flex: 1; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 3px; padding: 3px; background: var(--bg); border: 1px solid var(--line); border-radius: 9px; }
.seg-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.seg-opt { min-height: 38px; padding: 0 0.4rem; background: transparent; color: var(--ink); font-weight: 600; }
.seg-opt:hover { background: rgba(240, 180, 41, 0.1); filter: none; }
.seg-opt[aria-pressed="true"] { background: var(--accent); color: #1a1a1a; }
.menu-fold { padding: 0.7rem 0.9rem; }
.menu-fold h4 { margin: 0 0 0.4rem; font-size: 1rem; }
.menu-empty { margin: 0; color: var(--dim); font-size: 0.88rem; }
.menu-fold summary { min-height: 30px; display: flex; align-items: center; justify-content: space-between; font-weight: 600; cursor: pointer; list-style: none; }
.menu-fold summary::-webkit-details-marker { display: none; }
.menu-fold summary::after { content: "▸"; color: var(--dim); }
.menu-fold[open] summary::after { content: "▾"; }
.menu-fold[open] summary { margin-bottom: 0.4rem; }
.menu-more { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.menu-quit { display: flex; justify-content: flex-end; padding-top: 0.9rem; border-top: 1px solid var(--line); }
@container frame (min-width: 760px) {
  .card.menu { max-width: 54rem; }
  .menu-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .menu-quit { border-top: 0; padding-top: 0; }
}
.help { margin: 0; padding-left: 1.1rem; }
.help li { margin-bottom: 0.35rem; }
.log { list-style: none; margin: 0; padding: 0; max-height: 12rem; overflow-y: auto; display: grid; gap: 0.35rem; }
.log li { border-left: 3px solid var(--line); padding-left: 0.55rem; }
.log li.good { border-color: var(--good); }
.log li.bad { border-color: var(--bad); }
.log li.info { border-color: var(--safe); }

/* ---- phones ---- */
/* Portrait: the status bar in two rows, the strip under the maze: the pad down one edge, and beside it, a gap away,
   three rows: Wait, Undo and Restart; the tools; Hints, then Menu and the look swap, in that order on either side.
   Menu leaves the status bar for the strip, in thumb reach. */
@container frame (max-width: 760px) and (orientation: portrait) {
  .status { align-items: flex-start; gap: 6px; padding: 6px; }
  .hud { display: grid; grid-template-columns: repeat(3, auto); gap: 2px 8px; }
  .menu-btn { padding: 0 0.55rem; }
  .stat { flex-direction: column; align-items: flex-start; gap: 0; }
  /* The level has no label to show, so it takes the first row, over the other five. */
  .stat-trial { grid-row: 1; grid-column: 1 / -1; justify-self: start; }
  /* The effect chips share the level's row, at its right end, on one line no taller than the level's: a chip coming
     or going never changes the bar's height, so the board keeps its size. Two at once on a narrow phone take their
     short words (`Stone: 3`, `Cow`), so both fit beside the longest level. */
  .stat-effects { grid-row: 1; grid-column: 1 / -1; justify-self: end; align-self: center; flex-direction: row; }
  .stat-effects dd { flex-wrap: nowrap; justify-content: flex-end; }
  .fx-chip { line-height: 1.2; }
  .strip {
    position: relative;
    display: grid;
    /* The bottom row's second column is twice the first: it holds Menu and the look swap, the first only Hints. */
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 2fr);
    grid-template-areas: "pad turn turn" "pad tools tools" "pad thread view";
    justify-content: space-between;
    align-items: center;
    gap: 6px 20px;
    padding: 10px 10px 8px;
  }
  #frame.pad-right .strip { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr) auto; grid-template-areas: "turn turn pad" "tools tools pad" "thread view pad"; }
  .strip button { min-width: 0; min-height: 40px; padding: 0 0.3rem; }
  .strip .tool { min-height: 48px; padding: 0 0.3rem 0 0.15rem; }
  .pad { grid-area: pad; }
  .actions { display: contents; }
  .turn, .tools { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
  .turn { grid-area: turn; }
  .tools { grid-area: tools; }
  .view { grid-area: view; }
  .thread { grid-area: thread; }
  .view, .thread { display: grid; }
  .view.with-menu { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .strip .strip-menu { display: inline-block; }
  .status .menu-btn { display: none; }
}
/* Up to 440 px, Menu and the look swap share half a row: a smaller label keeps Classic and Modern whole. */
@container frame (max-width: 440px) and (orientation: portrait) {
  .strip .view.with-menu button { font-size: 0.78rem; padding: 0 0.15rem; }
  #hud-effects:has(> .fx-chip + .fx-chip) .fx-long { display: none; }
  #hud-effects:has(> .fx-chip + .fx-chip) .fx-short { display: inline; }
}
/* The narrowest phones (320 px to 400 px): three stats a row, and a smaller strip. */
@container frame (max-width: 400px) and (orientation: portrait) {
  .hud { grid-template-columns: repeat(3, minmax(0, auto)); gap: 2px 10px; }
  .stat dt { font-size: 0.7rem; }
  .stat dd { font-size: 0.85rem; overflow-wrap: anywhere; white-space: normal; }
  .strip { gap: 6px 12px; padding: 10px 8px 8px; }
  .strip button { padding: 0 0.1rem; font-size: 0.68rem; }
  .turn, .tools, .view.with-menu { gap: 4px; }
  .strip .tool { padding: 0; }
  .tool .n { margin-left: 0.15rem; }
  .strip .view.with-menu button { font-size: 0.68rem; padding: 0 0.1rem; }
  /* Narrower still: the bottom row splits 1 : 3, so Classic and Modern keep their width. */
  .strip { grid-template-columns: auto minmax(0, 1fr) minmax(0, 3fr); }
  #frame.pad-right .strip { grid-template-columns: minmax(0, 1fr) minmax(0, 3fr) auto; }
}

/* Landscape: the pad and the actions sit in the margins either side of the board (the pad on its own side), over the board's row. */
@container frame (orientation: landscape) and (max-height: 500px) {
  .status { padding: 2px 8px; }
  .hud { display: flex; flex-wrap: wrap; gap: 0 10px; }
  .stat { flex-direction: row; align-items: baseline; gap: 0.3rem; }
  .stat dt { font-size: 0.7rem; }
  .stat dd { font-size: 0.85rem; }
  .menu-btn { min-height: 30px; padding: 0 0.6rem; }
  /* The rails the board leaves clear: 148px on the pad's side holds the 3-column pad (3 x 44px) with its
     8px edge, 220px on the other side holds the widest action column ("Restart" with its key-tab chip) with its edge. */
  .board { padding: 4px 220px 4px 148px; }
  .strip {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    align-items: flex-end;
    flex-wrap: nowrap;
    padding: 0 8px 8px;
    border: 0;
    pointer-events: none;
  }
  .strip button { pointer-events: auto; min-width: 40px; min-height: 40px; padding: 0 0.3rem; font-size: 0.8rem; background: rgba(22, 27, 34, 0.92); }
  .strip .tool { min-height: 48px; padding: 0 0.3rem 0 0.15rem; }
  .strip .thread-panel { pointer-events: auto; }
  .actions { flex-direction: column; align-items: flex-end; gap: 4px; }
  .turn, .thread, .tools, .view { gap: 4px; }
  #frame.pad-right .board { padding: 4px 148px 4px 220px; }
  #frame.pad-right .actions { align-items: flex-start; }
}

/* A short frame this wide has room beside the board without reserving rails: the board is limited by height and
   centred, far from the buttons at the frame's edges. */
@container frame (orientation: landscape) and (max-height: 500px) and (min-width: 900px) {
  .board, #frame.pad-right .board { padding: 4px; }
}

/* ---- the level editor: a layer over the whole frame. The bar runs across the top, the board fills the rest and
   the palette sits at its right; under 700px the palette is a drawer the Pieces button opens. ---- */
.editor {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: grid;
  grid-template: "bar bar" auto "board side" minmax(0, 1fr) / minmax(0, 1fr) auto;
  background: var(--bg);
}
.editor[hidden] { display: none; }
#editor-panel { display: contents; }
.editor-bar {
  grid-area: bar;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  align-items: center;
  padding: 6px 8px;
  border-bottom: 1px solid var(--line);
  background: var(--panel);
}
.editor-actions, .editor-size { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
.editor-size label { display: flex; gap: 0.3rem; align-items: center; color: var(--dim); font-size: 0.9rem; }
.editor-size input { width: 4rem; }
.editor-size input, .editor-size select { font: inherit; background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 4px; padding: 0.15rem 0.3rem; }
.editor-pieces { display: none; }
/* The board region: either look's board fills it. */
.editor-board {
  grid-area: board;
  position: relative;
  min-width: 0;
  min-height: 0;
  display: grid;
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  padding: 6px;
  overflow: hidden;
}
/* The Classic look (editor/classic-view.ts): the game's tilted sheet in its view, and its compass over it, filling the
   board region. One finger paints and two fingers move the view, so the browser takes no touch gesture on it. */
.editor-board > .editor-view, .editor-board > .editor-classic-cam { grid-area: 1 / 1; }
.editor-board > .editor-classic-cam { position: relative; inset: auto; }
.editor-view { cursor: crosshair; }
/* The Modern look (editor/modern-view.ts): the 3D board and its compass fill the board region in place of the sheet;
   one finger paints, two fingers move the camera, so the browser takes no touch gesture on it. */
.editor-board.look-modern > .editor-view, .editor-board.look-modern > .editor-classic-cam { display: none; }
.editor-board:not(.look-modern) > .editor-modern { display: none; }
.editor-modern { position: absolute; inset: 0; display: grid; grid-template: minmax(0, 1fr) / minmax(0, 1fr); }
.editor-modern > * { grid-area: 1 / 1; min-width: 0; min-height: 0; width: 100%; height: 100%; }
.editor-modern > .modern-overlay { position: relative; inset: auto; }
.editor-stage3d { touch-action: none; cursor: crosshair; }
.editor-look { display: inline-flex; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; }
.editor-look button { font: inherit; font-size: 0.85rem; padding: 0.2rem 0.55rem; border: 0; background: var(--bg); color: var(--dim); cursor: pointer; }
.editor-look button + button { border-left: 1px solid var(--line); }
.editor-look button[aria-pressed="true"] { background: var(--accent); color: var(--bg); font-weight: 600; }
.editor-side {
  grid-area: side;
  width: 15.5rem;
  overflow-y: auto;
  padding: 6px 8px;
  border-left: 1px solid var(--line);
  background: var(--panel);
}
.editor-help { margin: 0 0 0.6rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--line); font-size: 0.85rem; color: var(--dim); }
.check-panel { margin-bottom: 0.6rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--line); }
.check-panel h3 { margin: 0 0 0.3rem; font-size: 0.8rem; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; }
.check-panel p { margin: 0.3rem 0; font-size: 0.9rem; }
.share-panel { margin-bottom: 0.6rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--line); }
.share-panel h3 { margin: 0 0 0.3rem; font-size: 0.8rem; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; }
.share-panel p { margin: 0.3rem 0; font-size: 0.9rem; }
.share-panel input[type="text"], .share-panel textarea { width: 100%; box-sizing: border-box; }
.check-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.check-bar { position: relative; height: 6px; margin-top: 0.5rem; overflow: hidden; background: var(--bg); border-radius: 3px; }
.check-bar::after { content: ""; position: absolute; inset: 0 auto 0 0; width: 35%; background: var(--accent); border-radius: 3px; animation: check-slide 1.4s ease-in-out infinite alternate; }
@keyframes check-slide { to { transform: translateX(185%); } }
.check-strip { display: none; align-items: center; gap: 0.4rem; min-width: 0; flex-basis: 100%; }
.check-strip .check-bar { flex: 0 0 4rem; margin: 0; }
.check-strip-text { font-size: 0.85rem; color: var(--dim); min-width: 0; overflow-wrap: anywhere; }
.check-strip.stale { opacity: 0.7; }
.check-result.stale { opacity: 0.55; }
.check-stale { color: var(--bad); }
.check-rating { margin-top: 0.4rem; padding-top: 0.35rem; border-top: 1px solid var(--line); }
.check-rating p { margin: 0.2rem 0; }
.check-band-label { color: var(--dim); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; }
.check-score { color: var(--dim); font-size: 0.85rem; }
.check-problems { margin: 0.25rem 0 0; padding-left: 1.1rem; font-size: 0.85rem; color: var(--dim); }
.check-problems li { margin: 0.15rem 0; }
.palette h3 { margin: 0.4rem 0 0.25rem; font-size: 0.8rem; color: var(--accent); text-transform: uppercase; letter-spacing: 0.08em; }
.palette-row { display: flex; flex-wrap: wrap; gap: 4px; }
.palette .brush { position: relative; padding: 2px; background: var(--bg); border: 2px solid var(--line); border-radius: 4px; line-height: 0; }
.palette .brush[aria-pressed="true"] { border-color: var(--accent); }
.swatch { position: relative; display: block; width: 32px; height: 32px; overflow: hidden; }
.swatch-img { display: block; transform-origin: 0 0; background-repeat: no-repeat; }
.brush-dir, .brush-mark {
  position: absolute;
  right: 0;
  bottom: 0;
  padding: 0 2px;
  font-size: 12px;
  line-height: 14px;
  color: var(--ink);
  background: rgba(1, 4, 9, 0.8);
  border-radius: 3px;
}
.brush-mark { font-weight: 700; color: var(--accent); }
.erase-mark { color: var(--bad); }
.brush-rotate { margin-top: 0.6rem; }
@container frame (max-width: 699px) {
  .editor { grid-template: "bar" auto "board" minmax(0, 1fr) / minmax(0, 1fr); }
  .editor-pieces { display: inline-block; }
  .check-strip { display: flex; flex-wrap: wrap; }
  /* The drawer lies over the board's right side, under the bar. */
  .editor-side {
    grid-area: board;
    justify-self: end;
    z-index: 1;
    max-width: 85%;
    box-shadow: -4px 0 16px rgba(0, 0, 0, 0.5);
  }
  .editor-side:not(.open) { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .toast { transition: none; }
  .banner-box { animation-name: banner-still; }
  .tip-box, .tip-box.nudge-a, .tip-box.nudge-b { animation: none; }
  .tip-box.nudge-a .tip-ok, .tip-box.nudge-b .tip-ok { outline: 3px solid var(--safe); outline-offset: 2px; }
  .check-bar::after { animation: none; width: 100%; opacity: 0.5; }
}

/* The compass (src/modern/controls.ts) at the board's bottom-right shows the view: its needle, red at the north end,
   turns with the heading, its dial squashes as the view tilts (a disc seen at the view's pitch), and a gold ring fills
   from straight down (empty) to 45° (full), --tilt being 0 to 1. A drag on it turns and tilts the view; a tap resets
   it. At 48 × 48 px it is a finger-sized target.
   The view eases, so the needle follows with no transition of its own. */
.modern-overlay .compass {
  position: absolute;
  right: 10px;
  bottom: 10px;
  width: 48px;
  height: 48px;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: rgba(22, 27, 34, 0.84);
  border: 1px solid var(--line);
  touch-action: none;
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  --tilt: 0;
}
.modern-overlay .compass:active { cursor: grabbing; }
.modern-overlay .compass:hover { border-color: var(--accent); }
.modern-overlay .compass > * { grid-area: 1 / 1; }
.modern-overlay .compass svg { width: 34px; height: 34px; pointer-events: none; }
.modern-overlay .compass .dial { fill: rgba(255, 255, 255, 0.06); stroke: rgba(201, 205, 208, 0.45); stroke-width: 1; }
.modern-overlay .compass .n { fill: #e8433a; }
.modern-overlay .compass .s { fill: #c9cdd0; }
.modern-overlay .compass .tilt-ring {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(from 0deg, var(--accent) calc(var(--tilt) * 360deg), transparent 0);
  -webkit-mask: radial-gradient(circle, transparent 19px, #000 19.5px);
  mask: radial-gradient(circle, transparent 19px, #000 19.5px);
}

/* The first-time hint (src/modern/hint.ts): one line beside the compass, fading in after a quiet moment, while the
   compass gives one small wiggle. It never takes a press meant for the board except a tap on the line itself. */
.modern-overlay .view-hint {
  position: absolute;
  right: 68px;
  bottom: 18px;
  max-width: calc(100% - 88px);
  margin: 0;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: rgba(22, 27, 34, 0.9);
  color: var(--ink);
  font-size: 0.85rem;
  line-height: 1.3;
  text-wrap: pretty;
  cursor: pointer;
  opacity: 0;
  translate: 0 4px;
  transition: opacity 0.3s ease, translate 0.3s ease;
}
.modern-overlay .view-hint.on { opacity: 1; translate: 0 0; pointer-events: auto; }
.modern-overlay .compass.wiggle { animation: compass-wiggle 1.2s ease-in-out 1; }
@keyframes compass-wiggle {
  0%, 100% { rotate: 0deg; }
  25% { rotate: -8deg; }
  60% { rotate: 8deg; }
  85% { rotate: -2deg; }
}
@media (prefers-reduced-motion: reduce) {
  .modern-overlay .view-hint { transition: none; translate: none; }
  .modern-overlay .compass.wiggle { animation: none; }
}

/* The Map button (src/ui/strip.tsx): its face is a live crop of the level round Theseus in the look it swaps to
   (main.ts paints it), with a small badge naming the control in the corner farthest from Theseus and the Minotaur. */
.strip .map-btn { position: relative; overflow: hidden; padding: 0; }
@media (min-width: 700px) {
  .strip .map-btn { min-width: 72px; }
}
.strip .map-btn .map-face { position: absolute; inset: 0; display: block; }
.strip .map-btn .map-thumb { display: block; width: 100%; height: 100%; object-fit: cover; }
.strip .map-btn .map-badge {
  position: absolute;
  left: 4px;
  bottom: 3px;
  padding: 0 5px;
  border-radius: 4px;
  background: rgba(13, 17, 23, 0.82);
  color: var(--ink);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.35;
}
.strip .map-btn:has(.map-thumb[data-corner^="top"]) .map-badge { bottom: auto; top: 3px; }
.strip .map-btn:has(.map-thumb[data-corner$="right"]) .map-badge { left: auto; right: 4px; }
.strip .map-btn:hover, .strip .map-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* The touch tour (src/tour.ts): ghost fingertips over the real pad and board, a bold banner low on the board (at the
 * top when the strip is not below it), and the way each fingertip went drawn as a dashed arrow when motion is
 * reduced. Only the banner takes a pointer: a press anywhere else reaches the game and ends the tour. */
.tour { position: fixed; inset: 0; z-index: 60; background: rgb(13 17 23 / 0.18); pointer-events: none; user-select: none; -webkit-user-select: none; }
.tour-dot {
  position: fixed; left: 0; top: 0; width: 38px; height: 38px; border-radius: 50%; opacity: 0;
  background: rgb(255 255 255 / 0.55); border: 2px solid rgb(255 255 255 / 0.95);
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.5); pointer-events: none;
}
.tour-dot.press::after {
  content: ""; position: absolute; inset: -8px; border-radius: 50%; border: 2px solid var(--accent);
  animation: tour-ring 0.9s ease-out infinite;
}
@keyframes tour-ring { from { transform: scale(0.7); opacity: 1; } to { transform: scale(1.5); opacity: 0; } }
.tour-trace { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.tour-trace path { fill: none; stroke: var(--accent); stroke-width: 4; stroke-dasharray: 8 6; stroke-linecap: round; }
.tour-card {
  position: fixed; top: max(12px, env(safe-area-inset-top, 0px)); left: 50%; translate: -50% 0; width: min(calc(100vw - 24px), 440px);
  display: grid; gap: 8px; justify-items: center; padding: 14px 16px 12px; border-radius: 14px;
  background: var(--accent); color: #1a1a1a; border: 3px solid #1a1a1a; pointer-events: auto; touch-action: manipulation;
  box-shadow: 0 0 0 3px var(--accent), 0 10px 32px rgb(0 0 0 / 0.65);
  animation: tour-in 0.35s ease-out, tour-glow 2.4s ease-in-out 0.35s infinite;
}
.tour-card.tour-low { top: auto; }
@keyframes tour-in { from { opacity: 0; transform: translateY(14px) scale(0.96); } }
@keyframes tour-glow { 50% { box-shadow: 0 0 0 7px rgb(240 180 41 / 0.45), 0 10px 32px rgb(0 0 0 / 0.65); } }
.tour-caption { margin: 0; font-size: 1.25rem; font-weight: 800; line-height: 1.25; text-align: center; }
.tour-pips { margin: 0; color: #1a1a1a; letter-spacing: 0.3em; font-size: 1rem; }
.tour-play { margin: 0; font-size: 0.85rem; font-weight: 600; text-align: center; }
.tour-buttons { display: flex; gap: 10px; width: 100%; justify-content: center; }
.tour-buttons button {
  min-height: 52px; min-width: 9rem; padding: 0 22px; font-size: 1.1rem; font-weight: 800; border-radius: 10px;
  background: #1a1a1a; color: #fff; border: 2px solid #1a1a1a;
}
.tour-buttons button:focus-visible { outline: 3px solid #fff; outline-offset: -6px; }
@media (prefers-reduced-motion: reduce) {
  .tour-dot.press::after { animation: none; transform: scale(1.3); }
  .tour-card { animation: none; }
}
.menu-confirm { display: grid; gap: 8px; padding: 10px 12px; }
.menu-confirm p { margin: 0; }
.menu-confirm-buttons { display: flex; gap: 8px; }
