/* Black-and-vector look. The game is always dark; that's the aesthetic.
   Desktop layout fits the window with no page scrolling: controls on the left,
   a square arena in the middle, reference on the right, timeline at the bottom. */

:root {
  --bg: #000;
  --fg: #e8e8e8;
  --muted: #8a8a8a;
  --line: #3a3a3a;
  --enemy: #ff6b6b;
  --shield: #5fd7ff;
  --ram: #ffaa33;
  --thrust: #f4e285;
  --rock: #9a9a9a;
  --won: #7dff9b;
  /* The two scores and their sum. The other hues all mean something already
     (enemy red, ram orange, thrust yellow, won green, shield cyan), so these
     share the free blue-magenta side of the wheel: time a cool periwinkle,
     cost a magenta. On black, colours add as light, so the sum is literally
     time + cost: the two added channel by channel, then scaled back to full
     brightness, which lands on the violet between them. Kept in step with
     COLORS in web/render.js (the GIF export). */
  --time: #7394ff;
  --cost: #ff64e6;
  --sum: #c382ff; /* (#7394ff + #ff64e6) × 255 / max channel */
  --panel: 230px;
  --font: ui-monospace, 'Cascadia Mono', 'SFMono-Regular', Menlo, Consolas, monospace;
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 13px/1.45 var(--font);
}

button {
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 4px 8px;
  min-height: 32px;
  cursor: pointer;
}
button:hover { border-color: var(--fg); }
button:focus-visible { outline: 2px solid var(--fg); outline-offset: 1px; }

kbd {
  font: 11px var(--font);
  color: var(--fg);
  border: 1px solid var(--line);
  padding: 0 4px;
}

h2 {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- page grid ------------------------------------------------------------- */

.app {
  height: 100vh;
  height: 100dvh;
  display: grid;
  grid-template-columns: var(--panel) minmax(0, 1fr) var(--panel);
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    'top   top   top'
    'left  stage right'
    'edit  edit  edit';
  gap: 10px 14px;
  padding: 10px 14px 12px;
  max-width: 1600px;
  margin: 0 auto;
}

.top { grid-area: top; display: flex; align-items: baseline; gap: 16px; }
.top h1 { margin: 0; font-size: 20px; line-height: 1.15; letter-spacing: 0.4em; font-weight: 700; }
/* The title with who makes it, small and quiet underneath. The header lines
   up on the title's baseline, as before. */
.brand { display: flex; flex-direction: column; }
.brand .studio { margin-top: 1px; font-size: 10px; line-height: 1.2; letter-spacing: 0.12em; color: var(--muted); }
/* A link that looks like the buttons (Missions, back to the game). */
.nav-link {
  color: var(--fg);
  text-decoration: none;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 4px 8px;
}
.nav-link:hover { border-color: var(--fg); }
.nav-link:focus-visible { outline: 2px solid var(--fg); outline-offset: 1px; }
/* The version, small and quiet beside the title (web/version.js), on the
   header's baseline. The title's letter spacing already leaves a gap after
   the R, so it sits close without a space. */
.top h1 .version {
  margin-left: -2px;
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.05em;
  color: var(--muted);
}
/* Leaderboard, Missions, Vector+ and Menu, pushed to the right. */
.top-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.top-right .nav-link { display: inline-flex; align-items: center; min-height: 32px; box-sizing: border-box; }
.board-btn.locked { color: var(--muted); border-style: dashed; }
/* Vector+, once it's on sale, for players without it. */
.vplus-btn { border-color: var(--fg); }
.menu { position: relative; }
.menu-icon { margin-left: 2px; }
.menu-btn[aria-expanded='true'] { border-color: var(--fg); }
/* A dot for patch notes this browser hasn't opened yet. */
.menu-btn.unread::after,
.menu-list .unread::after {
  content: '';
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-left: 6px;
  border-radius: 50%;
  background: var(--won);
  vertical-align: middle;
}
.menu-list {
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 20;
  min-width: 170px;
  display: flex;
  flex-direction: column;
  padding: 4px;
  background: var(--bg);
  border: 1px solid var(--line);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.8);
}
.menu-list[hidden] { display: none; }
.menu-list button { border-color: transparent; text-align: left; }
.menu-list button:hover, .menu-list button:focus-visible { border-color: var(--fg); outline: none; }
.menu-list button[hidden] { display: none; }
/* Terms & privacy: a link, dressed like the buttons around it. */
.menu-list a { color: var(--fg); text-decoration: none; border: 1px solid transparent; border-radius: 2px;
  padding: 4px 8px; min-height: 32px; display: flex; align-items: center; }
.menu-list a:hover, .menu-list a:focus-visible { border-color: var(--fg); outline: none; }
/* Who made the game, under the items: not one of them. */
.menu-credit { margin: 6px 8px 2px; padding-top: 6px; border-top: 1px solid var(--line); color: var(--muted);
  font-size: 11px; white-space: nowrap; }

/* The loading screen: a ship turning in 45° steps, firing after each turn. */
.boot {
  position: fixed;
  inset: 0;
  z-index: 10;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 16px;
}
.boot-ship { width: 128px; height: 128px; overflow: visible; }
.boot-ship path {
  fill: none;
  stroke: var(--fg);
  stroke-width: 1.5;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.boot-shot { fill: var(--fg); }
.boot-turn { animation: boot-turn 4s steps(8) infinite; }
.boot-shot { animation: boot-shot 0.5s ease-out infinite; }
@keyframes boot-turn { to { transform: rotate(360deg); } }
@keyframes boot-shot {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-20px); opacity: 0; }
}
/* Only if loading never finishes. */
.boot-help {
  max-width: 34em;
  margin: 0;
  color: var(--muted);
  text-align: center;
  opacity: 0;
  animation: boot-help 0.4s 8s forwards;
}
.boot code { color: var(--fg); }
@keyframes boot-help { to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) {
  .boot-turn, .boot-shot { animation: none; }
}

.panel { overflow-y: auto; min-height: 0; }
.panel section { margin-bottom: 14px; }
.panel-left { grid-area: left; }
.panel-right { grid-area: right; }

/* --- arena: the largest square that fits -------------------------------------- */

.stage-wrap {
  grid-area: stage;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

/* Over the arena, as wide as it (resize in web/app.js): enemies left on the
   left, the mission's number and date on the right. */
.arena-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  max-width: 100%;
}
.puzzle-name { color: var(--muted); text-align: right; }
/* Enemies left: the goal, always in view. */
.enemies-left {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--line);
  color: var(--muted);
  cursor: help;
}
.enemies-left .label { font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; }
.enemies-left b { font-size: 18px; color: var(--enemy); min-width: 1ch; text-align: center; }
.enemies-left.clear b { color: var(--won); }
.enemy-icons { display: flex; gap: 2px; }
.enemy-icons canvas { width: 22px; height: 22px; transition: opacity 0.3s; }
.enemy-icons canvas.down { opacity: 0.2; }
.stage { position: relative; }
.stage canvas { display: block; background: var(--bg); }

.result {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: rgba(0, 0, 0, 0.72);
  text-align: center;
}
.result[hidden] { display: none; }
.result-title { font-size: 26px; letter-spacing: 0.3em; font-weight: 700; }
.result[data-status='won'] .result-title { color: var(--won); }
.result[data-status='lost'] .result-title { color: var(--enemy); }
.result-actions { display: flex; gap: 8px; }
.share-status { color: var(--muted); min-height: 1.5em; white-space: pre-line; user-select: text; -webkit-user-select: text; }
/* Off-screen text for copying (copyByCommand); 16px so iOS doesn't zoom. */
.copy-buffer { position: fixed; top: 0; left: -9999px; width: 1px; height: 1px; font-size: 16px; opacity: 0; }

/* --- left panel ------------------------------------------------------------- */

/* The score: time and cost, big. */
.status { font-size: 13px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
/* Empty until the run's end is revealed, but still a line tall, so the
   metrics under it never move. */
.status:empty::before { content: '\00a0'; }
.status.won { color: var(--won); }
.status.lost { color: var(--enemy); }
.metrics { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin: 6px 0; }
.metric { border: 1px solid var(--line); padding: 6px 10px 4px; cursor: help; }
.metric .label { display: block; font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; color: var(--muted); }
.metric b { display: block; font-size: 34px; line-height: 1.1; font-weight: 700; color: var(--muted); }
.metrics.won .metric { border-color: var(--won); }
.metrics.won .metric b { color: var(--fg); }
.metric.time .label { color: var(--time); }
.metric.cost .label { color: var(--cost); }
.metrics.won .metric.time b { color: var(--time); }
.metrics.won .metric.cost b { color: var(--cost); }
.c-time { color: var(--time); }
.c-cost { color: var(--cost); }
.now { color: var(--muted); font-size: 12px; }
.now b { color: var(--fg); font-weight: 600; }
.now b#hud-tick { color: var(--time); }
.now b#hud-cost { color: var(--cost); }

.controls { display: grid; grid-template-columns: repeat(6, 1fr); gap: 4px; }
.controls button { padding: 4px 0; }

.palette { display: flex; flex-direction: column; gap: 4px; }
.action {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  text-align: left;
}
.action .glyph {
  flex: 0 0 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
}
.action .name { flex: 1; color: var(--fg); }
/* Price badge: every action shows what it costs. */
.action .price {
  min-width: 3.2em;
  padding: 1px 6px;
  border: 1px solid #6a6a6a;
  color: var(--cost);
  font-size: 14px;
  font-weight: 700;
  text-align: center;
}
.action .price.free { border-color: var(--line); color: var(--muted); font-size: 11px; font-weight: 400; }
.action kbd { color: var(--muted); }

.tools { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }

/* --- right panel ------------------------------------------------------------ */

.legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.legend li { display: grid; grid-template-columns: 34px 1fr; gap: 10px; align-items: center; cursor: help; }
.legend canvas { width: 34px; height: 34px; }
.legend b { display: block; font-size: 14px; letter-spacing: 0.08em; }
.legend .hint { font-size: 15px; line-height: 1.2; }

/* Symbol rows: a big glyph and a small note. */
.sym { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; font-size: 17px; }
.sym li { display: grid; grid-template-columns: 1.2em 4.5em 1.2em; align-items: baseline; gap: 6px; cursor: help; }
.sym .note { text-align: center; }

.note { color: var(--muted); font-size: 12px; }
.c-shield { color: var(--shield); }
.c-ram { color: var(--ram); }

/* --- scrollbars ------------------------------------------------------------ */

/* Every scrollbar (the timeline's, the side panel's, dialogs', the page's) is
   drawn like the rest of the game: a thin flat bar in the line colour on
   black, brightening under the pointer. Chrome and Safari use the
   ::-webkit-scrollbar rules (Chrome ignores them if scrollbar-color is set, so
   that's only given to browsers without them, i.e. Firefox). */
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: var(--bg); }
::-webkit-scrollbar-track:horizontal { border-top: 1px solid #1c1c1c; }
::-webkit-scrollbar-track:vertical { border-left: 1px solid #1c1c1c; }
::-webkit-scrollbar-thumb { background: var(--line); border: solid var(--bg); }
::-webkit-scrollbar-thumb:horizontal { border-width: 3px 0 2px; }
::-webkit-scrollbar-thumb:vertical { border-width: 0 2px 0 3px; }
::-webkit-scrollbar-thumb:hover { background: var(--muted); }
::-webkit-scrollbar-thumb:active { background: var(--fg); }
::-webkit-scrollbar-button,
::-webkit-scrollbar-corner { display: none; }
@supports not selector(::-webkit-scrollbar) {
  * { scrollbar-width: thin; scrollbar-color: var(--line) var(--bg); }
}

/* --- timeline --------------------------------------------------------------- */

.editor { grid-area: edit; min-width: 0; }
.timeline {
  border: 1px solid var(--line);
  padding: 4px 6px 6px;
  overflow-x: auto;
  user-select: none;
}
.tl-inner { position: relative; }

/* Tick numbers; click or drag here to scrub. */
.tl-ruler {
  position: relative;
  height: 22px;
  cursor: ew-resize;
  touch-action: none;
}
.tl-ruler span {
  position: absolute;
  top: 3px;
  padding-left: 3px;
  font-size: 11px;
  color: #555;
  border-left: 1px solid #262626;
  line-height: 16px;
  pointer-events: none;
}
.tl-ruler span.major { color: var(--muted); border-left-color: var(--line); }

.track { display: flex; }
.slot {
  flex: 0 0 40px; /* SLOT_W in timeline.js */
  width: 40px;
  height: 52px;
  border: 1px solid #1c1c1c;
  font-size: 22px;
  line-height: 50px;
  text-align: center;
  overflow: hidden;
  cursor: pointer;
  touch-action: pan-x;
}
.slot.filled { border-color: var(--line); cursor: grab; touch-action: none; }
.slot.selected { background: #1f2a33; }
.slot.cursor { outline: 1px solid var(--fg); outline-offset: -1px; position: relative; z-index: 1; }
.slot.drop { background: #333; outline: 1px dashed var(--fg); outline-offset: -1px; }
/* The tick the run ends on, and slots that never run because of it. */
.slot.end-won { box-shadow: inset 0 -4px 0 var(--won); }
.slot.end-lost { box-shadow: inset 0 -4px 0 var(--enemy); }
.slot.end-timeout { box-shadow: inset 0 -4px 0 var(--muted); }
.slot.after-end { opacity: 0.35; }

/* Ticks the ram or shield is switched on. */
.tl-bands { position: relative; height: 7px; margin-top: 3px; }
.band-ram, .band-shield { position: absolute; top: 0; height: 6px; }
.band-ram { background: var(--ram); }
.band-shield { background: var(--shield); }

/* Where playback is, across ruler, slots and bands. */
.tl-playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 2px;
  margin-left: -1px;
  background: var(--fg);
  box-shadow: 0 0 4px rgba(255, 255, 255, 0.6);
  pointer-events: none;
  z-index: 2;
}
/* A grab tab on the ruler, so it's clear the playhead can be dragged. The ruler
   underneath takes the pointer. */
.tl-playhead::before {
  content: '';
  position: absolute;
  top: 0;
  left: -6px;
  width: 14px;
  height: 16px;
  background: var(--fg);
  clip-path: polygon(0 0, 100% 0, 100% 60%, 50% 100%, 0 60%);
}

.a-wait { color: var(--muted); }
.a-rot { color: var(--fg); }
.a-thrust { color: var(--thrust); }
.a-fire { color: var(--fg); }
/* The bullet dot is a small glyph: draw it bigger wherever it appears. */
.dot { font-size: 1.5em; line-height: 0.8; }
.slot.a-fire { font-size: 34px; }
.action.a-fire .glyph { font-size: 26px; }
.a-shield { color: var(--shield); }
.a-ram { color: var(--ram); }

/* --- help dialog ------------------------------------------------------------ */

.help {
  max-width: 640px;
  background: var(--bg);
  color: var(--fg);
  border: 1px solid var(--line);
  padding: 20px 24px;
}
.help::backdrop { background: rgba(0, 0, 0, 0.7); }
.help h2 { font-size: 13px; color: var(--fg); }
.help h3 { margin: 14px 0 4px; font-size: 12px; color: var(--muted); font-weight: 600; }
.help p, .help ul { margin: 0 0 6px; color: #c8c8c8; }
.help ul { padding-left: 18px; }

/* --- patch notes dialog ----------------------------------------------------- */

.notes { width: min(560px, calc(100vw - 32px)); }
.notes-list { max-height: 60vh; overflow-y: auto; margin: 0 0 12px; }
.notes-list h3 b { color: var(--fg); }
.notes-list h3:first-child { margin-top: 8px; }

/* --- leaderboard dialog ------------------------------------------------------ */

.board { width: min(860px, calc(100vw - 32px)); max-width: none; }
.board-msg { color: var(--muted); }
.board-msg[hidden] { display: none; }
.board-name[hidden], .board-you[hidden] { display: none; }
.board-name { margin: 0 0 12px; }
.board-name label { display: block; margin-bottom: 4px; color: #c8c8c8; }
.board-name-row { display: flex; gap: 8px; }
.board-name input {
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--line);
  padding: 4px 8px;
  min-height: 32px;
  width: 16em;
}
.board-name input:focus { outline: 2px solid var(--fg); outline-offset: 1px; }
.board-name-error { color: var(--enemy); min-height: 1.5em; }
.board-you { color: #c8c8c8; }
button.link { border: none; min-height: 0; padding: 0 4px; color: var(--muted); text-decoration: underline; }
button.link:hover { color: var(--fg); }
.board-count { color: var(--muted); margin: 0 0 10px; }
.board-note { color: var(--muted); margin: -4px 0 10px; }
.board-cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; margin-bottom: 14px; }
/* Each table in its score's colour: --metric is read by the histogram too. */
.board-time { --metric: var(--time); --other: var(--cost); }
.board-cost { --metric: var(--cost); --other: var(--time); }
.board-sum { --metric: var(--sum); }
.board-col h3 { margin: 0 0 6px; color: var(--metric); }
.board-chart { display: block; width: 100%; height: 64px; border-bottom: 1px solid var(--line); }
.board-axis { display: flex; justify-content: space-between; color: var(--muted); font-size: 11px; }
.board-rank { margin: 4px 0 8px; color: var(--metric); }
/* Fixed layout: the numbers' columns are as wide in every table whatever
   they hold, so a name gets the same room in the time and cost tables and
   wraps in both or neither. Sized for ranks and scores up to 4 characters;
   the widths include the padding (fixed layout with collapsed borders). */
.board table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.board td { padding: 2px 4px; border-top: 1px solid #1c1c1c; }
.board td.rank { color: var(--muted); width: calc(4ch + 8px); }
.board td.name { overflow-wrap: anywhere; }
.board td.value { text-align: right; width: calc(4ch + 8px); white-space: nowrap; }
.board tr.you td { color: var(--metric); }
/* The other score of the run behind a best time or cost, dimmed. */
.board td.also, .board tr.you td.also {
  color: color-mix(in srgb, var(--other) 50%, var(--bg));
  text-align: right;
  width: calc(4ch + 12px);
  white-space: nowrap;
  padding-left: 8px;
}


/* --- name fonts and badges (web/looks.js) ------------------------------------- */

/* The fonts achievements unlock (sim/achievements.js), from web/fonts/ (see its
   LICENSE.txt). A browser only downloads one when a name on screen uses it.
   Each is sized so its lower case is as tall as the game's monospace, measured
   from the font files, and a 16-character name is never much wider. */
@font-face { font-family: 'Vector Major Mono Display'; src: url('fonts/founding.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Vector Share Tech Mono'; src: url('fonts/first.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Vector Turret Road'; src: url('fonts/week.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Vector VT323'; src: url('fonts/streak.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Vector Workbench'; src: url('fonts/centurion.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Vector Zen Dots'; src: url('fonts/topten.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Vector Wallpoet'; src: url('fonts/pacifist.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Vector Doto'; src: url('fonts/archivist.woff2') format('woff2'); font-weight: 700; font-display: swap; }
@font-face { font-family: 'Vector Tektur'; src: url('fonts/practice.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Vector Micro 5'; src: url('fonts/triple.woff2') format('woff2'); font-weight: 400; font-display: swap; }

.font-founding { font-family: 'Vector Major Mono Display', var(--font); font-size: 0.79em; font-weight: 400; }
.font-first { font-family: 'Vector Share Tech Mono', var(--font); font-size: 1.09em; font-weight: 400; }
.font-week { font-family: 'Vector Turret Road', var(--font); font-size: 1.14em; font-weight: 500; }
.font-streak { font-family: 'Vector VT323', var(--font); font-size: 1.37em; font-weight: 400; }
.font-centurion { font-family: 'Vector Workbench', var(--font); font-size: 0.89em; font-weight: 400; }
.font-topten { font-family: 'Vector Zen Dots', var(--font); font-size: 1.01em; font-weight: 400; }
.font-pacifist { font-family: 'Vector Wallpoet', var(--font); font-size: 1.08em; font-weight: 400; }
.font-archivist { font-family: 'Vector Doto', var(--font); font-size: 1.05em; font-weight: 700; }
.font-practice { font-family: 'Vector Tektur', var(--font); font-size: 0.98em; font-weight: 500; }
.font-triple { font-family: 'Vector Micro 5', var(--font); font-size: 1.5em; font-weight: 400; }

.badges { display: inline-flex; gap: 2px; margin-left: 5px; vertical-align: -2px; }
.badge { flex: none; fill: none; stroke: currentColor; stroke-linecap: round; stroke-linejoin: round; }
.badge-time { color: var(--time); }
.badge-cost { color: var(--cost); }
.badge-sum { color: var(--sum); }

/* --- pop-ups (web/popup.js): over the game, not stopping it ------------------- */

.popup {
  position: fixed;
  right: 16px;
  bottom: 16px;
  z-index: 20;
  width: min(340px, calc(100vw - 32px));
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  padding: 14px 16px;
  background: var(--bg);
  border: 1px solid var(--fg);
  box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.7);
}
.popup[hidden] { display: none; }
.popup p { margin: 0 0 6px; }
.popup-kicker { color: var(--won); font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; }
.popup-item { margin: 0 0 10px; }
.popup-title { font-size: 22px; line-height: 1.25; color: var(--fg); overflow-wrap: anywhere; }
.popup-launch { font-size: 17px; }
/* Sign in sits beside OK. */
.popup-action { float: left; margin: 0 8px 0 0; border-color: var(--fg); }
.popup-first { font-size: 15px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.popup-rule, .popup-hint { color: var(--muted); }
.popup-sample { color: #c8c8c8; font-size: 15px; }
.board-lead { color: var(--fg); }
/* Signed out: the board is private, and says so in a box with the sign-in
   buttons in it, so nobody has to go looking for the Account dialog. */
.board-signin { border: 1px solid var(--fg); border-radius: 2px; padding: 12px 16px; margin: 0 0 16px; }
.board-signin h3 { margin: 0 0 6px; }
.board-signin p { margin: 0 0 8px; }
.board-signin > p:not(.board-lead):not(.board-fine) { color: var(--muted); }
.board-providers { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 8px; }
.board-providers a {
  padding: 8px 14px;
  border: 1px solid var(--line);
  border-radius: 2px;
  color: var(--fg);
  text-decoration: none;
}
.board-providers a:hover { border-color: var(--fg); }
.board-providers a:focus-visible { outline: 2px solid var(--fg); outline-offset: 1px; }
.board-signin .board-fine { color: var(--muted); font-size: 12px; margin: 0; }
.board-signin .board-fine a { color: var(--muted); }

/* --- narrow screens: stack, and let the page scroll ------------------------------ */

@media (max-width: 900px) {
  .app {
    height: auto;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    grid-template-areas: 'top' 'score' 'stage' 'edit';
  }
  .top { flex-wrap: wrap; row-gap: 6px; }
  .panel { overflow: visible; }
  /* The score goes above the arena. The rest of the left panel follows the
     timeline in its own order (play, then the actions and edits a tap on a
     slot needs, so they're on screen with it), then the reference. */
  .panel-left { display: contents; }
  .panel-left .score { grid-area: score; }
  .panel-left section { margin-bottom: 0; }
  .panel-right { grid-area: auto; }
  /* The actions in the keyboard's two rows, Q W E / A S D. */
  .palette { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .action { min-height: 44px; justify-content: center; }
  .action .name, .action kbd { display: none; }
  .controls button, .tools button { min-height: 44px; }
  /* Legend and stances side by side when there's room. */
  .panel-right { display: flex; flex-wrap: wrap; column-gap: 32px; }
  .result { padding: 8px; }
  .result-actions { flex-wrap: wrap; justify-content: center; }
  .board-cols { grid-template-columns: minmax(0, 1fr); }
}

/* A phone held sideways: the controls beside the arena and timeline, which
   resize in web/app.js sizes to fit on screen together. */
@media (max-width: 900px) and (orientation: landscape) and (max-height: 540px) {
  .app {
    grid-template-columns: minmax(0, 1fr) minmax(230px, 36%);
    grid-template-areas: 'top top' 'stage left' 'edit left' '. left' 'right right';
    grid-template-rows: auto auto auto 1fr auto;
  }
  .panel-left { display: block; }
  .panel-left section { margin-bottom: 14px; }
  .panel-right { grid-area: right; }
  .metric b { font-size: 24px; }
}

/* --- account dialog ---------------------------------------------------------- */

/* Signed out it's a short note and the sign-in buttons; signed in it widens
   to a header (name, Vector+ or not) over two columns of boxed sections, like
   the Time and Cost boxes. Phones get one column (see the end of this part).
   Signed in, Close sits at the top right, level with the title, so the whole
   window fits without scrolling; on phones (and signed out, where it's
   short) it's at the bottom, after everything. */
.account { position: relative; width: min(460px, calc(100vw - 32px)); }
.account.signed-in .account-close { position: absolute; top: 14px; right: 24px; }
.account.signed-in { width: min(900px, calc(100vw - 32px)); max-width: none; }
.account-providers { display: flex; flex-direction: column; gap: 8px; margin: 12px 0 16px; }
.account-providers a {
  display: block;
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: 2px;
  color: var(--fg);
  text-decoration: none;
  text-align: center;
}
.account-providers a:hover { border-color: var(--fg); }
.account-providers a:focus-visible { outline: 2px solid var(--fg); outline-offset: 1px; }
#account a, #vplus a { color: var(--fg); }
#account-none[hidden], #account-out[hidden], #account-in[hidden], #account-nick[hidden], #account-unnamed[hidden],
#vplus-buy[hidden], #vplus-signin[hidden] { display: none; }
.help .account-note { color: var(--muted); font-size: 12px; }

.acct-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  flex-wrap: wrap;
  margin: 10px 0 12px;
  padding: 10px 14px;
  border: 1px solid var(--line);
}
.acct-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.acct-label { color: var(--muted); font-size: 11px; letter-spacing: 0.15em; text-transform: uppercase; }
.acct-nick { font-size: 20px; line-height: 1.3; overflow-wrap: anywhere; }
.acct-nick .badges { gap: 4px; margin-left: 10px; vertical-align: 0; }
.acct-unnamed { color: #c8c8c8; }
.acct-tier { flex: none; padding: 4px 10px; color: var(--muted); font-size: 12px; }
.acct-tier:hover { color: var(--fg); }
.acct-tier.on { border-color: var(--fg); color: var(--fg); }

.acct-cols { display: grid; grid-template-columns: minmax(0, 300px) minmax(0, 1fr); gap: 12px; align-items: start; }
.acct-col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.acct-box { border: 1px solid var(--line); padding: 10px 12px 12px; }
.help .acct-box h3 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin: 0 0 8px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
}
.acct-count { letter-spacing: 0.05em; color: var(--fg); font-weight: 400; }
.help .acct-box p:last-child, .help .acct-box ul:last-child { margin-bottom: 0; }


/* Sign-ins, Sign out and Delete: one strip across the bottom. */
.acct-strip { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 24px; margin-top: 12px; padding: 8px 12px; }
.help .acct-strip h3 { margin: 0; }
.help .account-signins { list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap; gap: 4px 24px; }
.account-signins li { display: flex; align-items: center; gap: 10px; min-height: 28px; }
.account-signins .note { color: var(--muted); }
.acct-actions { display: flex; align-items: center; gap: 8px 16px; flex-wrap: wrap; margin-left: auto; }
button.link.danger:hover { color: var(--enemy); }

/* Name fonts: tiles, two a row, the name in each. */
.account-fonts { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; margin-top: 8px; }
.account-fonts label { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: 0 8px;
  padding: 6px 8px; border: 1px solid #1c1c1c; border-radius: 2px; cursor: pointer; }
.account-fonts label:has(input:checked) { border-color: var(--fg); }
.account-fonts label:focus-within { outline: 2px solid var(--fg); outline-offset: 1px; }
.account-fonts input { grid-row: span 2; margin: 0; }
.account-fonts .sample { font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.account-fonts .which { color: var(--muted); font-size: 11px; }
.account-fonts.locked label { cursor: default; opacity: 0.6; }

/* Badges: one row per table, lit once it's been won. */
.account-badges { display: grid; gap: 4px; }
.acct-badge { display: flex; align-items: center; gap: 10px; padding: 5px 8px; border: 1px solid #1c1c1c;
  color: var(--muted); }
.acct-badge .badge { opacity: 0.35; }
.acct-badge .what { font-size: 12px; }
.acct-badge .days { margin-left: auto; font-size: 11px; }
.acct-badge.won { border-color: var(--line); }
.acct-badge.won .badge { opacity: 1; }
.acct-badge.won .what, .acct-badge.won .days { color: var(--fg); }
.help .acct-badges .account-note { margin: 8px 0 0; }

/* Achievements: two a row, earned ones lit and in the font they unlock. */
.help .account-achievements { list-style: none; padding: 0; margin: 0; display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
.account-achievements li { display: grid; grid-template-columns: 1.1em minmax(0, 1fr); align-content: start; gap: 1px 6px;
  padding: 5px 8px; border: 1px solid #1c1c1c; color: var(--muted); }
.account-achievements li.earned { border-color: var(--line); color: var(--fg); }
.account-achievements .mark { grid-row: span 2; color: var(--line); }
.account-achievements li.earned .mark { color: var(--won); }
.account-achievements .rule { grid-column: 2; font-size: 11px; line-height: 1.35; color: var(--muted); }

/* Phones: one column, in reading order, sign-ins last. */
@media (max-width: 720px) {
  .account.signed-in { padding: 16px 14px; }
  .acct-cols { display: flex; flex-direction: column; gap: 10px; }
  .acct-col { display: contents; }
  .account.signed-in .account-close { position: static; margin-top: 12px; }
  .acct-font { order: 1; }
  .acct-badges { order: 2; }
  .acct-achievements { order: 3; }
  .acct-strip { flex-direction: column; align-items: stretch; margin-top: 10px; }
  .help .account-signins { flex-direction: column; gap: 0; }
  .acct-actions { margin-left: 0; justify-content: space-between; }
  .help .account-achievements { grid-template-columns: minmax(0, 1fr); }
  .account-fonts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --- Vector+ dialog ---------------------------------------------------------- */

/* Why the account has it (or doesn't), what it unlocks (ticked once it's
   yours), and the button to get it. */
.vplus { width: min(480px, calc(100vw - 32px)); }
.help .vplus-status { margin: 10px 0 12px; color: var(--fg); }
.help .vplus-perks { list-style: none; padding: 0; margin: 0 0 12px; display: grid; gap: 6px; }
.vplus-perks li { display: grid; grid-template-columns: 1.1em minmax(0, 1fr); gap: 1px 8px; padding: 6px 10px;
  border: 1px solid var(--line); }
.vplus-perks li::before { content: '+'; grid-row: span 2; color: var(--muted); }
.vplus.has .vplus-perks li::before { content: '✓'; color: var(--won); }
.vplus-perks b { font-weight: 600; color: var(--fg); }
.vplus-perks span { color: var(--muted); font-size: 12px; line-height: 1.4; }
.account-buy { margin: 0 0 12px; }
.account-buy button { width: 100%; border-color: var(--fg); }
.help .account-buy .account-note { margin: 8px 0 0; }

/* --- saves dialog ------------------------------------------------------------ */

.tools .wide { grid-column: 1 / -1; }
.saves { width: min(520px, calc(100vw - 32px)); }
#saves-locked[hidden], #saves-in[hidden], #saves-empty[hidden] { display: none; }
#saves-locked, #saves-in { margin-bottom: 12px; }
.board-msg.error { color: var(--enemy); }
.help .saves-list { list-style: none; padding: 0; margin: 0 0 8px; max-height: 50vh; overflow-y: auto; }
.saves-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  padding: 6px 0;
  border-top: 1px solid #1c1c1c;
}
.saves-info { display: flex; flex-direction: column; min-width: 0; }
.saves-info b { overflow-wrap: anywhere; font-weight: 600; }
.saves-info .note { color: var(--muted); font-size: 11px; }
.saves-actions { display: flex; flex-wrap: wrap; }
.saves-rename { display: flex; gap: 8px; align-items: center; width: 100%; }
.saves-rename input, .saves .board-name input {
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--line);
  padding: 4px 8px;
  min-height: 32px;
  flex: 1;
  min-width: 0;
}
.saves-rename input:focus { outline: 2px solid var(--fg); outline-offset: 1px; }

/* --- mission library (library.html) -------------------------------------------- */

body.lib { height: auto; }
.lib-top { max-width: 1600px; margin: 0 auto; padding: 10px 14px 0; align-items: baseline; }
.lib-top .nav-link { margin-left: auto; }
.lib-main { max-width: 1600px; margin: 0 auto; padding: 12px 14px 40px; }
.lib-bar { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; margin-bottom: 10px; }
.lib-search {
  font: inherit;
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 4px 8px;
  min-height: 32px;
  flex: 1 1 22em;
  max-width: 36em;
}
.lib-search:focus { outline: 2px solid var(--fg); outline-offset: 1px; }
.lib-filters { display: flex; flex-wrap: wrap; gap: 4px; }
.lib-filters button[aria-pressed='true'] { border-color: var(--fg); background: #1f2a33; }
body:not(.premium) .premium-only { display: none; }
.lib-note { color: var(--muted); margin: 0 0 10px; }
.lib-note[hidden] { display: none; }
.lib-note a { color: var(--fg); }
.lib-week { margin: 18px 0 0; }
.lib-week[hidden] { display: none; }
.lib-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 10px;
}
.lib-card { border: 1px solid var(--line); display: flex; flex-direction: column; min-width: 0; }
.lib-card[hidden] { display: none; }
.lib-card:hover, .lib-card:focus-within { border-color: var(--fg); }
.lib-card.today { border-color: var(--won); }
.lib-open { display: flex; flex-direction: column; gap: 2px; padding: 6px 8px 4px; color: var(--fg); text-decoration: none; }
.lib-open:focus-visible { outline: 2px solid var(--fg); outline-offset: -2px; }
.lib-preview { display: block; width: 100%; aspect-ratio: 1; background: var(--bg); margin-bottom: 4px; }
.lib-card.coming { border-style: dashed; color: var(--muted); }
.lib-card.coming:hover { border-color: var(--line); }
.lib-blank {
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px dashed var(--line);
  color: var(--muted);
  font-size: 12px;
}
.lib-card.coming .lib-head b { color: var(--muted); }
.lib-head b { color: var(--fg); }
.lib-contents { color: var(--muted); font-size: 12px; }
.lib-foot { display: flex; align-items: center; gap: 6px; padding: 0 4px 4px 8px; margin-top: auto; min-height: 32px; }
.lib-tags { display: flex; flex-wrap: wrap; gap: 4px; flex: 1; font-size: 11px; }
.lib-tags span { border: 1px solid var(--line); padding: 0 4px; }
.lib-tags .tag-today { color: var(--won); border-color: var(--won); }
.lib-tags .tag-cleared { color: var(--won); }
.lib-tags .tag-saves { color: var(--fg); }
.lib-fav { border: none; font-size: 18px; line-height: 1; padding: 4px 6px; color: var(--muted); }
.lib-fav[hidden] { display: none; }
.lib-fav.on { color: var(--thrust); }
.lib-fav:hover { color: var(--fg); }

@media (max-width: 1100px) { .lib-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 700px) { .lib-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* --- bug report dialog ---------------------------------------------------------- */

.report { width: min(520px, calc(100vw - 32px)); }
.report-form label { display: block; margin-bottom: 4px; color: #c8c8c8; }
.report-form textarea {
  display: block;
  box-sizing: border-box;
  width: 100%;
  font: inherit;
  font-size: max(1em, 16px); /* iOS zooms into smaller text fields */
  color: var(--fg);
  background: var(--bg);
  border: 1px solid var(--line);
  padding: 6px 8px;
  resize: vertical;
}
.report-form textarea:focus { outline: 2px solid var(--fg); outline-offset: 1px; }
.report-count { color: var(--muted); text-align: right; font-size: 11px; margin: 2px 0 8px; }
.report-form .report-check { display: flex; gap: 8px; align-items: baseline; margin-bottom: 8px; }
.report-check[hidden] { display: none; }
.report-sent { width: min(400px, calc(100vw - 32px)); }

/* --- tutorial ------------------------------------------------------------------ */

.tutorial-offer { width: min(460px, calc(100vw - 32px)); }
.tutorial-offer-buttons { display: flex; gap: 8px; margin-top: 14px; }
button.primary { border-color: var(--won); color: var(--won); }

/* The highlight around what a step is about. It never takes clicks, so the
   player can use the highlighted control. With .dim, the rest of the page is
   darkened around it. */
.tour-ring {
  position: fixed;
  z-index: 50;
  border: 2px solid var(--fg);
  border-radius: 4px;
  pointer-events: none;
  transition: left 0.2s, top 0.2s, width 0.2s, height 0.2s;
}
.tour-ring.dim { box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.6); }
.tour-ring[hidden] { display: none; }
.tour-card {
  position: fixed;
  z-index: 51;
  width: min(330px, calc(100vw - 32px));
  background: var(--bg);
  border: 1px solid var(--fg);
  padding: 14px 16px 12px;
  box-shadow: 0 6px 30px rgba(0, 0, 0, 0.8);
}
.tour-card.center { left: 50% !important; top: 50% !important; transform: translate(-50%, -50%); }
.tour-count { color: var(--muted); font-size: 11px; letter-spacing: 0.15em; }
.tour-title { margin: 4px 0 6px; font-size: 13px; color: var(--fg); }
.tour-text { margin: 0 0 8px; color: #c8c8c8; }
.tour-hint { margin: 0 0 8px; color: var(--thrust); }
/* The goal step stands out: in the enemies' red, with their pictures. */
.tour-card.goal { width: min(400px, calc(100vw - 32px)); border: 2px solid var(--enemy); }
.tour-card.goal .tour-title { font-size: 16px; color: var(--enemy); letter-spacing: 0.04em; }
.tour-gallery { list-style: none; margin: 0 0 10px; padding: 0; display: grid; gap: 8px; }
.tour-gallery[hidden] { display: none; }
.tour-gallery li { display: grid; grid-template-columns: 44px 1fr; gap: 10px; align-items: center; }
.tour-gallery canvas { width: 44px; height: 44px; border: 1px solid var(--line); }
.tour-gallery b { display: block; color: var(--enemy); }
.tour-gallery span { color: #c8c8c8; font-size: 12px; }
.tour-hint[hidden] { display: none; }
.tour-buttons { display: flex; gap: 8px; align-items: center; justify-content: flex-end; }
.tour-buttons .link { margin-right: auto; }
.tour-buttons button[hidden] { display: none; }

/* The old address's page while it moves the player to the new one (worker/moved.js). */
.moved { max-width: 32em; margin: 20vh auto 0; padding: 0 16px; }
.moved h1 { font-size: 18px; font-weight: normal; letter-spacing: 0.1em; }
.moved a { color: var(--fg); }

/* --- terms, privacy and refunds (terms.html, privacy.html, refunds.html) ---- */

body.legal-page { height: auto; }
.legal-top { max-width: 760px; margin: 0 auto; padding: 10px 14px 0; flex-wrap: wrap; }
.legal-top h1 a { color: inherit; text-decoration: none; }
.legal-nav { display: flex; gap: 14px; }
.legal-nav a { color: var(--muted); }
.legal-nav a:hover, .legal-nav a[aria-current='page'] { color: var(--fg); }
.legal-top .nav-link { margin-left: auto; }
.legal { max-width: 760px; margin: 0 auto; padding: 16px 14px 56px; font-size: 14px; line-height: 1.6; color: #c8c8c8; }
.legal h2 { margin: 0; font-size: 18px; letter-spacing: 0.05em; text-transform: none; color: var(--fg); }
.legal h3 { margin: 22px 0 6px; font-size: 14px; color: var(--fg); }
.legal p, .legal ul { margin: 0 0 10px; }
.legal ul { padding-left: 20px; }
.legal li { margin-bottom: 6px; }
.legal a { color: var(--fg); }
.legal b { color: var(--fg); }
.legal-date { color: var(--muted); font-size: 12px; }
.legal-foot { max-width: 760px; margin: 0 auto; padding: 0 14px 32px; color: var(--muted); font-size: 12px; }
/* Details the owner still has to fill in. */
.legal .todo { color: var(--ram); }
