:root {
  --ap-ink: #0b1a2a;
  --ap-deep: #071321;
  --ap-panel: rgba(12, 28, 46, 0.92);
  --ap-line: rgba(160, 200, 255, 0.18);
  --ap-text: #eef4ff;
  --ap-dim: #9fb2cc;
  --ap-mint: #7cf2c4;
  --ap-ice: #8fd3ff;
  --ap-gold: #ffcf5a;
  --ap-warm: #ffb86b;
  --ap-rose: #ff7e9d;
  --header-h: 48px;
  /* The screen's safe areas (docs/PLATFORMS.md, "Layout"): under a notch, a cut-out or the
     home indicator. Everything the player reads or touches stays inside them. The tests set
     these to try insets the browsers here don't have. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  /* The smallest text: 14 px on a desktop, 15 on a tablet, 13 on a phone. main.js reads it
     for the labels drawn on the field. */
  --t-min: 14px;
  /* How far controls keep from the screen's edges: on a touch screen, 16 px past the safe
     area, so a thumb on a control never starts the system's edge gestures. */
  --edge: 8px;
}

/* A tablet: a touch screen at least 600 px each way. */
@media (pointer: coarse) {
  :root {
    --t-min: 15px;
  }
}

/* A phone: a touch screen under 600 px one way or the other. */
@media (pointer: coarse) and (max-width: 599px), (pointer: coarse) and (max-height: 599px) {
  :root {
    --t-min: 13px;
  }
}

@media (any-pointer: coarse) {
  :root {
    --edge: 16px;
  }
}

html,
body {
  margin: 0;
  background: var(--ap-deep);
  color: var(--ap-text);
  font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}

.site-header {
  height: var(--header-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 16px;
  border-bottom: 1px solid var(--ap-line);
  box-sizing: border-box;
}
.site-header a {
  color: var(--ap-text);
}

.page {
  padding: 8px max(8px, var(--safe-r)) 40px max(8px, var(--safe-l));
}

/* No scrolling, zooming, selection or long-press menu in play (docs/PLATFORMS.md): the HUD
   and the field take no touch gestures, the menus scroll themselves (.ap-overlay), and
   main.js prevents Safari's pinch gesture and the context menu over the game. */
.game-root {
  position: relative;
  margin: 0 auto;
  width: 100%;
  max-width: 1280px;
  border-radius: 14px;
  overflow: hidden;
  overscroll-behavior: none;
  border: 1px solid var(--ap-line);
  background: var(--ap-ink);
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  display: flex;
  flex-direction: column;
}

/* Full screen (the site's button; main.js sets .ap-full): the game fills the screen edge to
   edge, with everything in it inside the safe areas. The sides take the larger inset both
   ways, so the middle of the HUD is the middle of the screen, where the site puts
   "Leave full screen". */
.game-root.ap-full {
  --safe-x: max(var(--safe-l), var(--safe-r));
  max-width: none;
  border: 0;
  border-radius: 0;
  padding: var(--safe-t) var(--safe-x) var(--safe-b);
  box-sizing: border-box;
}

/* The room the game has, for the layout to follow (main.js): the root's width on the page,
   and its whole box in full screen. The stage's height never changes it. */
.ap-sizer {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 0;
  visibility: hidden;
  pointer-events: none;
}
.game-root.ap-full .ap-sizer {
  height: auto;
  bottom: 0;
}

/* Reads the dynamic viewport's height (it follows the browser's moving bars) and the safe
   areas, for the layout (main.js). */
.ap-probe {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 100vh;
  height: 100dvh;
  padding: var(--safe-t) var(--safe-r) var(--safe-b) var(--safe-l);
  box-sizing: content-box;
  visibility: hidden;
  pointer-events: none;
}

/* ---------- HUD ---------- */
/* Two halves: the course on the left (pause, hint, its name and goals), the tools on the
   right (the boost, the kept paths, start again, sound). In full screen a gap between them
   keeps the middle of the screen clear for "Leave full screen". */
.ap-hud {
  /* Its own height always, never squeezed by the stage under it (main.js sets the stage's). */
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px max(var(--edge), 8px);
  background: linear-gradient(180deg, rgba(17, 38, 62, 0.98), rgba(11, 26, 42, 0.98));
  border-bottom: 1px solid var(--ap-line);
  min-height: 52px;
  box-sizing: border-box;
  touch-action: none;
}
.ap-hud[hidden] {
  display: none;
}
.ap-hside {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.ap-hl {
  flex: 1 1 auto;
}
.ap-hr {
  flex: none;
}
.ap-hgap {
  display: none;
  flex: none;
  width: 48px;
}
.ap-hbtn {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  border: 1px solid var(--ap-line);
  background: rgba(255, 255, 255, 0.05);
  color: var(--ap-text);
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  touch-action: manipulation;
}
.ap-hbtn:hover {
  background: rgba(255, 255, 255, 0.1);
}
.ap-hbtn:focus-visible,
.ap-btn:focus-visible,
.ap-kbtn:focus-visible,
.ap-chip:focus-visible,
.ap-cell:focus-visible,
.ap-mini:focus-visible {
  outline: 2px solid var(--ap-mint);
  outline-offset: 2px;
}
.ap-hbtn svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}
.ap-hbtn .ap-wave,
.ap-hbtn .ap-x {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
}
.ap-hbtn .ap-x {
  display: none;
}
.ap-hbtn.ap-muted .ap-wave {
  display: none;
}
.ap-hbtn.ap-muted .ap-x {
  display: inline;
}
/* The course's name and goals wrap rather than hide when the HUD is narrow. */
.ap-hinfo {
  flex: 1 1 auto;
  min-width: 0;
  line-height: 1.15;
  overflow-wrap: anywhere;
}
.ap-hname {
  font-weight: 700;
  font-size: max(15px, var(--t-min));
}
.ap-hsub {
  font-size: var(--t-min);
  color: var(--ap-dim);
  display: flex;
  flex-wrap: wrap;
  gap: 2px 10px;
}
.ap-goals {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 2px 8px;
}
.ap-goal {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}
.ap-goal i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.5px solid var(--ap-dim);
  display: inline-block;
  box-sizing: border-box;
}
.ap-goal.ap-got i {
  background: var(--ap-gold);
  border-color: var(--ap-gold);
}
.ap-goal.ap-now i {
  border-color: var(--ap-mint);
}
.ap-goal.ap-lost {
  opacity: 0.55;
}
.ap-goal.ap-target {
  color: var(--ap-mint);
  font-weight: 700;
}
.ap-goal.ap-target svg {
  width: 15px;
  height: 15px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* The tools: one boost per launch, three paths in all. Icon and count, nothing more. */
.ap-tool {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  height: 44px;
  padding: 0 7px 0 5px;
  border-radius: 10px;
  border: 1px solid rgba(255, 196, 92, 0.45);
  background: rgba(255, 196, 92, 0.1);
  color: var(--ap-gold);
  font-weight: 800;
  font-size: max(15px, var(--t-min));
  box-sizing: border-box;
  transition: opacity 0.2s, filter 0.2s;
}
.ap-tool[hidden],
.ap-paths[hidden] {
  display: none;
}
.ap-tool svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}
.ap-tool.ap-used {
  opacity: 0.45;
  filter: grayscale(1);
}
.ap-count {
  align-self: center;
  min-width: 12px;
  text-align: center;
  font-size: max(15px, var(--t-min));
  font-weight: 800;
  color: var(--ap-mint);
}
.ap-count.ap-none {
  color: var(--ap-dim);
}
.ap-chip.ap-old {
  color: #c9b79a;
  border-color: rgba(201, 183, 154, 0.55);
}
.ap-paths {
  flex: none;
  display: flex;
  align-items: center;
  gap: 8px;
}
.ap-chip {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  border: 1px dashed rgba(160, 200, 255, 0.3);
  background: transparent;
  color: var(--ap-dim);
  padding: 0;
  cursor: default;
  position: relative;
  display: grid;
  place-items: center;
  touch-action: manipulation;
}
.ap-chip svg {
  width: 30px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  stroke-linecap: round;
}
.ap-chip.ap-full {
  border-style: solid;
  cursor: pointer;
  background: rgba(255, 255, 255, 0.06);
}
.ap-chip.ap-bridge {
  color: var(--ap-mint);
}
.ap-chip.ap-ramp {
  color: var(--ap-ice);
}
.ap-chip.ap-rail {
  color: var(--ap-gold);
}
.ap-chip.ap-full::after {
  content: '×';
  position: absolute;
  top: -1px;
  right: 3px;
  font-size: 14px;
  color: var(--ap-dim);
}
.ap-chip.ap-full:hover {
  background: rgba(255, 126, 157, 0.14);
}
.ap-chip.ap-pulse {
  animation: ap-pulse 0.9s ease-in-out 2;
}
@keyframes ap-pulse {
  50% {
    border-color: var(--ap-rose);
    box-shadow: 0 0 0 3px rgba(255, 126, 157, 0.35);
  }
}

/* A narrow screen held upright (phones, and tablets under 680 px): the HUD takes two rows,
   the course and its controls above, the tools below, so nothing is squeezed or hidden. */
@media (max-width: 679px) and (orientation: portrait), (max-width: 559px) {
  .ap-hud {
    flex-wrap: wrap;
    row-gap: 8px;
    padding-top: 6px;
    padding-bottom: 6px;
  }
  .ap-hl,
  .ap-hr {
    flex: 1 1 100%;
  }
  .ap-hr #btn-restart {
    margin-left: auto;
  }
  .ap-hname {
    font-size: max(14px, var(--t-min));
  }
}

/* In full screen the HUD's halves are as wide as each other, with a gap between them, so the
   gap is the middle of the screen: "Leave full screen" sits in it, clear of the HUD. A half
   too narrow for its tools lets them take a second row rather than cross the middle. */
.game-root.ap-full .ap-hl,
.game-root.ap-full .ap-hr {
  flex: 1 1 0;
}
.game-root.ap-full .ap-hr {
  justify-content: flex-end;
  flex-wrap: wrap;
  row-gap: 8px;
}
.game-root.ap-full .ap-hgap {
  display: block;
}
/* On a touch screen in full screen the HUD meets the screen's top corners, which a phone
   rounds off: its buttons keep 24 px from them. */
@media (any-pointer: coarse) {
  .game-root.ap-full .ap-hud {
    padding-left: max(var(--edge), calc(24px - var(--safe-x)));
    padding-right: max(var(--edge), calc(24px - var(--safe-x)));
  }
}
/* Upright and narrow, the HUD keeps its two rows under a band of its own for
   "Leave full screen": there the course is held by the width, so the band costs it nothing. */
@media (max-width: 679px) and (orientation: portrait), (max-width: 559px) {
  .game-root.ap-full .ap-hl,
  .game-root.ap-full .ap-hr {
    flex: 1 1 100%;
  }
  .game-root.ap-full .ap-hr {
    flex-wrap: nowrap;
  }
  .game-root.ap-full .ap-hgap {
    display: none;
  }
  .game-root.ap-full .ap-hud {
    padding-top: calc(max(8px - var(--safe-t), 0px) + 56px);
  }
}

/* ---------- Stage ---------- */
.ap-stage {
  flex: none;
  position: relative;
  width: 100%;
  touch-action: none;
  overflow: hidden;
  background: var(--ap-ink);
}
.ap-stage canvas {
  display: block;
  width: 100%;
  height: 100%;
  outline: none;
  touch-action: none;
  cursor: crosshair;
}
.ap-tip {
  position: absolute;
  left: 50%;
  top: 10px;
  transform: translateX(-50%);
  max-width: calc(100% - 24px);
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(7, 19, 33, 0.72);
  color: var(--ap-text);
  font-size: var(--t-min);
  text-align: center;
  pointer-events: none;
  transition: opacity 0.25s;
  box-sizing: border-box;
}
.ap-tip:empty {
  opacity: 0;
}
.ap-stage.ap-coached .ap-tip {
  top: 64px;
}
/* With no HUD over it (watching a workshop model) in full screen, the tip goes under
   "Leave full screen". */
.game-root.ap-full .ap-hud[hidden] + .ap-stage .ap-tip {
  top: calc(max(8px - var(--safe-t), 0px) + 56px);
}

/* ---------- Tutorial coach: a few words, the right keys, then gone ---------- */
.ap-coach {
  position: absolute;
  left: 50%;
  top: 10px;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: calc(100% - 24px);
  padding: 7px 14px 7px 8px;
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(14, 34, 58, 0.86), rgba(7, 19, 33, 0.86));
  border: 1px solid rgba(124, 242, 196, 0.38);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.35), 0 0 18px rgba(124, 242, 196, 0.12);
  color: var(--ap-text);
  pointer-events: none;
  box-sizing: border-box;
  animation: ap-coach-in 0.35s ease-out;
  z-index: 2;
}
.ap-coach[hidden] {
  display: none;
}
.ap-ci {
  flex: none;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: rgba(124, 242, 196, 0.14);
  color: var(--ap-mint);
}
.ap-ci svg {
  width: 20px;
  height: 20px;
  fill: currentColor;
}
.ap-ct {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.ap-ct b {
  font-size: max(15px, var(--t-min));
  letter-spacing: 0.01em;
}
.ap-ct small {
  font-size: var(--t-min);
  color: var(--ap-dim);
}
.ap-caps {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
  font-size: var(--t-min);
  color: var(--ap-dim);
}
.ap-caps kbd {
  display: inline-block;
  min-width: 1.5em;
  margin-right: 4px;
  padding: 1px 5px;
  border-radius: 5px;
  border: 1px solid rgba(238, 244, 255, 0.35);
  border-bottom-width: 2px;
  background: rgba(238, 244, 255, 0.08);
  color: var(--ap-text);
  font: 700 var(--t-min) / 1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  text-align: center;
}
.ap-coach[data-lesson='drift'],
.ap-coach[data-lesson='cargo'],
.ap-coach[data-lesson='magnet'],
.ap-coach[data-lesson='zone'],
.ap-coach[data-lesson='shift'] {
  border-color: rgba(255, 207, 90, 0.45);
}
.ap-coach[data-lesson='drift'] .ap-ci,
.ap-coach[data-lesson='cargo'] .ap-ci,
.ap-coach[data-lesson='magnet'] .ap-ci,
.ap-coach[data-lesson='zone'] .ap-ci,
.ap-coach[data-lesson='shift'] .ap-ci {
  background: rgba(255, 207, 90, 0.14);
  color: var(--ap-gold);
}
.ap-coach.ap-got {
  border-color: var(--ap-mint);
  animation: ap-coach-got 0.9s ease-out forwards;
}
.ap-coach.ap-got .ap-ci {
  background: var(--ap-mint);
  color: var(--ap-deep);
}
@keyframes ap-coach-in {
  from {
    opacity: 0;
    transform: translate(-50%, -8px);
  }
}
@keyframes ap-coach-got {
  0% {
    box-shadow: 0 0 0 0 rgba(124, 242, 196, 0.55);
  }
  40% {
    box-shadow: 0 0 0 10px rgba(124, 242, 196, 0);
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -6px);
  }
}
.ap-kbtn.ap-hint {
  animation: ap-hint 1.3s ease-in-out infinite;
  border-color: var(--ap-mint);
}
.ap-paths.ap-hint .ap-chip {
  animation: ap-pulse 1.3s ease-in-out infinite;
}
@keyframes ap-hint {
  50% {
    box-shadow: 0 0 0 4px rgba(124, 242, 196, 0.32), 0 0 18px rgba(124, 242, 196, 0.35);
  }
}
.ap-toast {
  position: absolute;
  left: 50%;
  top: 38%;
  transform: translate(-50%, -50%);
  max-width: calc(100% - 24px);
  box-sizing: border-box;
  padding: 10px 18px;
  border-radius: 14px;
  background: rgba(7, 19, 33, 0.82);
  border: 1px solid var(--ap-line);
  font-weight: 700;
  font-size: 18px;
  pointer-events: none;
  text-align: center;
}
.ap-toast[hidden] {
  display: none;
}

.ap-toast small {
  display: block;
  margin-top: 4px;
  font-size: max(14px, var(--t-min));
  font-weight: 600;
  color: var(--ap-dim, #b9c8dc);
}

/* Keep sheet: its buttons keep 16 px from the screen's edges on a touch screen, and 16 px
   over the bottom of the stage, which ends above the home indicator. */
.ap-keep {
  position: absolute;
  left: 50%;
  bottom: 8px;
  transform: translateX(-50%);
  width: min(560px, calc(100% - 2 * var(--edge)));
  background: var(--ap-panel);
  border: 1px solid var(--ap-line);
  border-radius: 14px;
  padding: 8px;
  box-sizing: border-box;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
  touch-action: none;
}
.ap-keep[hidden],
.ap-kbtn[hidden] {
  display: none;
}
.ap-keep-note {
  font-size: var(--t-min);
  color: var(--ap-dim);
  text-align: center;
  margin: 0 4px 6px;
  min-height: 1em;
}
.ap-keep-note b {
  color: var(--ap-text);
}
.ap-keep-row {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 8px;
}
.ap-kbtn {
  border-radius: 10px;
  border: 1px solid var(--ap-line);
  background: rgba(255, 255, 255, 0.05);
  color: var(--ap-text);
  padding: 6px 4px;
  min-height: 48px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font: inherit;
  touch-action: manipulation;
}
.ap-kbtn b {
  font-size: max(14px, var(--t-min));
}
.ap-kbtn small {
  font-size: var(--t-min);
  color: var(--ap-dim);
}
.ap-kbtn:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.11);
}
.ap-kbtn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.ap-kbtn.ap-sel {
  border-color: var(--ap-text);
  background: rgba(255, 255, 255, 0.14);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.35) inset;
}
.ap-keep-note.ap-bad {
  color: #ff8fa8;
}
.ap-sw {
  width: 30px;
  height: 5px;
  border-radius: 3px;
  display: block;
}
.ap-sw-bridge {
  background: var(--ap-mint);
}
.ap-sw-ramp {
  background: var(--ap-ice);
}
.ap-sw-rail {
  background: repeating-linear-gradient(90deg, var(--ap-gold) 0 6px, transparent 6px 9px);
}
.ap-kskip {
  justify-content: center;
}

/* ---------- Overlay (menus, results, workshop) ---------- */
.ap-overlay {
  position: absolute;
  inset: 0;
  z-index: 5;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y;
  background: radial-gradient(120% 90% at 50% 0%, rgba(40, 60, 110, 0.55), rgba(7, 19, 33, 0.94) 70%);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 18px max(14px, var(--edge)) 22px;
  box-sizing: border-box;
  text-align: center;
}
.ap-overlay[hidden] {
  display: none;
}
/* Centred when it fits, and scrolled from its top when it doesn't (never cut off above). */
.ap-overlay.ap-clear {
  background: rgba(7, 19, 33, 0.55);
}
.ap-overlay.ap-clear > :first-child {
  margin-top: auto;
}
.ap-overlay.ap-clear > :last-child {
  margin-bottom: auto;
}
/* In full screen the menus fill the screen: their contents keep inside the safe areas and
   start under "Leave full screen". */
.game-root.ap-full .ap-overlay {
  padding: calc(max(8px, var(--safe-t)) + 56px) calc(var(--safe-x) + max(14px, var(--edge))) calc(var(--safe-b) + 22px);
}
.ap-overlay h2 {
  margin: 6px 0 4px;
  font-size: 26px;
  letter-spacing: 0.02em;
}
.ap-overlay p {
  margin: 4px 0;
  color: var(--ap-dim);
  max-width: 560px;
  line-height: 1.4;
}
.ap-logo {
  font-size: clamp(34px, 7vw, 64px);
  font-weight: 900;
  letter-spacing: 0.08em;
  margin: 4px 0 2px;
  background: linear-gradient(90deg, var(--ap-mint), var(--ap-ice) 50%, var(--ap-gold));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.ap-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin: 12px 0 4px;
}
.ap-btn {
  min-height: 44px;
  min-width: 44px;
  padding: 0 18px;
  border-radius: 12px;
  border: 1px solid var(--ap-line);
  background: rgba(255, 255, 255, 0.07);
  color: var(--ap-text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
  touch-action: manipulation;
}
.ap-btn:hover {
  background: rgba(255, 255, 255, 0.13);
}
.ap-btn.ap-primary {
  background: linear-gradient(180deg, #8ff7d0, #54d9a8);
  color: #062016;
  border-color: transparent;
}
.ap-btn.ap-primary:hover {
  filter: brightness(1.06);
}
.ap-panel {
  background: rgba(12, 28, 46, 0.86);
  border: 1px solid var(--ap-line);
  border-radius: 14px;
  padding: 12px 14px;
  margin: 8px 0;
  max-width: 560px;
  width: 100%;
  box-sizing: border-box;
}
.ap-stats {
  display: flex;
  justify-content: center;
  gap: 18px;
  font-size: max(14px, var(--t-min));
  color: var(--ap-dim);
  flex-wrap: wrap;
}
.ap-stats b {
  color: var(--ap-text);
  font-size: 18px;
  display: block;
}

/* Course map */
.ap-worlds {
  width: 100%;
  max-width: 980px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 8px;
}
.ap-world {
  text-align: left;
  background: rgba(12, 28, 46, 0.7);
  border: 1px solid var(--ap-line);
  border-radius: 14px;
  padding: 10px 12px;
}
.ap-world h3 {
  margin: 0 0 2px;
  font-size: 16px;
  display: flex;
  justify-content: space-between;
  gap: 8px;
}
.ap-world h3 span {
  color: var(--ap-dim);
  font-weight: 500;
  font-size: var(--t-min);
}
.ap-world p {
  margin: 0 0 8px;
  font-size: var(--t-min);
}
.ap-world.ap-locked {
  opacity: 0.55;
}
.ap-cells {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(118px, 1fr));
  gap: 8px;
}
.ap-cell {
  min-height: 56px;
  border-radius: 10px;
  border: 1px solid var(--ap-line);
  background: rgba(255, 255, 255, 0.05);
  color: var(--ap-text);
  font: inherit;
  text-align: left;
  padding: 6px 8px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  touch-action: manipulation;
}
.ap-cell:hover:not(:disabled) {
  background: rgba(255, 255, 255, 0.11);
}
.ap-cell:disabled {
  cursor: not-allowed;
  opacity: 0.5;
}
.ap-cell b {
  font-size: var(--t-min);
  color: var(--ap-dim);
  font-weight: 600;
}
.ap-cell span {
  font-size: max(13.5px, var(--t-min));
  font-weight: 600;
  line-height: 1.2;
}
.ap-cell.ap-done {
  border-color: rgba(124, 242, 196, 0.5);
}
.ap-cell.ap-next {
  border-color: var(--ap-gold);
  box-shadow: 0 0 0 2px rgba(255, 207, 90, 0.25);
}
.ap-marks {
  display: inline-flex;
  gap: 3px;
  margin-top: 3px;
}
.ap-marks i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1.5px solid var(--ap-dim);
  box-sizing: border-box;
}
.ap-marks i.ap-on {
  background: var(--ap-gold);
  border-color: var(--ap-gold);
}

/* Results */
.ap-goallist {
  list-style: none;
  padding: 0;
  margin: 6px 0 0;
  text-align: left;
}
.ap-goallist li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 0;
  color: var(--ap-dim);
}
.ap-goallist li i {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid var(--ap-dim);
  box-sizing: border-box;
  flex: none;
}
.ap-goallist li.ap-on {
  color: var(--ap-text);
}
.ap-goallist li.ap-on i {
  background: var(--ap-gold);
  border-color: var(--ap-gold);
}
.ap-goallist li em {
  font-style: normal;
  font-size: var(--t-min);
  color: var(--ap-mint);
  margin-left: auto;
}

/* Workshop */
.ap-shop {
  width: 100%;
  max-width: 1100px;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 10px;
  margin-top: 10px;
}
.ap-mini {
  border-radius: 14px;
  border: 1px solid var(--ap-line);
  background: rgba(12, 28, 46, 0.75);
  overflow: hidden;
  text-align: left;
  cursor: pointer;
  padding: 0;
  color: var(--ap-text);
  font: inherit;
  touch-action: manipulation;
}
.ap-mini:hover {
  border-color: rgba(124, 242, 196, 0.55);
}
.ap-mini canvas {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  height: auto;
}
.ap-mini div {
  padding: 6px 10px 8px;
  font-size: var(--t-min);
  display: flex;
  justify-content: space-between;
  gap: 6px;
}
.ap-mini div span {
  color: var(--ap-dim);
}
.ap-mini.ap-empty {
  cursor: default;
  opacity: 0.5;
}
.ap-mini.ap-empty canvas {
  filter: grayscale(1) brightness(0.6);
}

.ap-small {
  font-size: var(--t-min);
  color: var(--ap-dim);
}

.ap-rotate {
  display: none;
}

/* ---------- About ---------- */
.about {
  max-width: 760px;
  margin: 24px auto 0;
  padding: 0 12px;
  line-height: 1.55;
  color: #d5e2f5;
}
.about h1 {
  font-size: 26px;
  margin: 0 0 8px;
  color: var(--ap-text);
}
.about h2 {
  font-size: 18px;
  margin: 22px 0 6px;
  color: var(--ap-text);
}
.about kbd {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: max(13px, var(--t-min));
  padding: 1px 6px;
  border-radius: 5px;
  border: 1px solid var(--ap-line);
  background: rgba(255, 255, 255, 0.06);
}

@media (max-width: 560px) {
  .page {
    padding: 0 var(--safe-r) 40px var(--safe-l);
  }
  .game-root {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
  }
  .ap-kbtn small {
    display: none;
  }
}

@media (pointer: coarse) {
  .ap-btn,
  .ap-cell,
  .ap-kbtn {
    min-height: 48px;
  }
}

@media (orientation: portrait) and (pointer: coarse) {
  .ap-rotate {
    display: block;
    font-size: var(--t-min);
    color: var(--ap-dim);
    margin-top: 6px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ap-chip.ap-pulse,
  .ap-coach,
  .ap-coach.ap-got,
  .ap-kbtn.ap-hint,
  .ap-paths.ap-hint .ap-chip {
    animation: none;
  }
  .ap-tip {
    transition: none;
  }
}

/* Phones held sideways: in play the site's header steps aside and the game takes the whole
   height (main.js sets .ap-playing on the body while a course is in play); every menu, the
   pause menu included, brings it back with "Full screen". The keep bar is compact. */
@media (orientation: landscape) and (max-height: 540px) {
  body.ap-playing .site-header {
    display: none;
  }
  body.ap-playing .page {
    padding-top: 0;
  }
  body.ap-playing .game-root:not(.ap-full) {
    border-radius: 0;
    border-width: 0 0 1px;
  }
  /* With the header gone the HUD meets the screen's top corners: its buttons keep 24 px
     from them (the page's padding already holds the side insets). */
  body.ap-playing .game-root:not(.ap-full) .ap-hud {
    padding-left: max(var(--edge), calc(24px - var(--safe-l)));
    padding-right: max(var(--edge), calc(24px - var(--safe-r)));
  }
  .ap-keep {
    bottom: 8px;
    padding: 6px;
  }
  .ap-keep-note {
    margin-bottom: 3px;
  }
  .ap-kbtn {
    min-height: 44px;
    padding: 3px 4px;
  }
  .ap-kbtn small {
    display: none;
  }
  .ap-overlay {
    padding-top: 10px;
    padding-bottom: 12px;
  }
  .ap-overlay h2 {
    font-size: 22px;
    margin: 2px 0;
  }
  .ap-row {
    margin-top: 8px;
  }
}
