/* Factosaur shared styles. One deliberate look, tuned for an iPad in landscape:
   big touch targets, high contrast, nothing that rewards precision. */

:root {
  --bg: #0f172a;
  --surface: #1b2438;
  --surface-lift: #26314a;
  --line: #33415c;
  --text: #f1f5f9;
  --muted: #94a3b8;
  --accent: #60a5fa;
  --land: #47557a;
  --land-hover: #5b6b94;
  /* The atlas palette: blue water and one muted colour per region (c0..c4,
     stamped on each path by the map generators, neighbours never matching).
     Shared with the quiz-Short pipeline (video/render.py PALETTE, which a
     test pins against this file) -- change them together or the videos stop
     matching the app. Muted on purpose: --answer/--correct/--accent must
     never look like map colours. */
  --water: #1b3a5c;
  --map-0: #64749e;
  --map-1: #467a83;
  --map-2: #7a6899;
  --map-3: #8a7a55;
  --map-4: #96637a;
  --correct: #34d399;
  --wrong: #f87171;
  --answer: #fbbf24;
  --radius: 18px;
  --tap: 56px;
}

* { box-sizing: border-box; }

html, body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 ui-rounded, "SF Pro Rounded", system-ui, -apple-system, sans-serif;
  /* No double-tap zoom, no text selection, no rubber-band: this is a game. */
  touch-action: manipulation;
  -webkit-user-select: none;
  user-select: none;
  overscroll-behavior: none;
}

button {
  font: inherit;
  color: inherit;
  cursor: pointer;
  border: 0;
  background: none;
}

/* ---------------------------------------------------------------- home ---- */

.home {
  max-width: 720px;
  margin: 0 auto;
  padding: 48px 24px;
}

.home h1 {
  margin: 0 0 4px;
  font-size: 34px;
  letter-spacing: -0.02em;
}

.home .tagline {
  margin: 0 0 36px;
  color: var(--muted);
}

.home .footer {
  margin: 40px 0 0;
  font-size: 14px;
  color: var(--muted);
}

.home .footer a {
  color: var(--muted);
}

/* ----------------------------------------------------------- documents ---- */
/* privacy.html: prose, so text is selectable again — the body rule above is
   for the game surfaces, where selection only gets in the way of a tap. */

.doc {
  max-width: 720px;
  margin: 0 auto;
  padding: 48px 24px;
  -webkit-user-select: text;
  user-select: text;
}

.doc h1 {
  margin: 0 0 4px;
  font-size: 34px;
  letter-spacing: -0.02em;
}

.doc .updated {
  margin: 0 0 28px;
  color: var(--muted);
}

.doc h2 {
  margin: 32px 0 8px;
  font-size: 20px;
}

.doc a {
  color: var(--accent);
}

.doc .summary {
  padding: 16px 20px;
  background: var(--surface);
  border-radius: var(--radius);
}

.doc footer {
  margin-top: 40px;
  color: var(--muted);
}

.pack-card {
  display: block;
  width: 100%;
  text-align: left;
  padding: 22px 24px;
  margin-bottom: 14px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 1px solid var(--line);
  transition: background 0.15s, transform 0.1s;
}

.pack-card:hover { background: var(--surface-lift); }
.pack-card:active { transform: scale(0.99); }

.pack-card h2 {
  margin: 0 0 4px;
  font-size: 20px;
}

.pack-card p {
  margin: 0;
  color: var(--muted);
  font-size: 15px;
}

.bar {
  height: 8px;
  margin: 16px 0 8px;
  border-radius: 999px;
  background: var(--bg);
  overflow: hidden;
}

.bar-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--correct);
  transition: width 0.4s ease;
}

.bar-label {
  font-size: 14px;
  color: var(--muted);
}

.chip-badge {
  display: inline-block;
  margin-left: 4px;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--bg);
  color: var(--muted);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.mode-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 16px;
}

.mode-chip {
  padding: 10px 16px;
  min-height: 44px;
  border-radius: 999px;
  background: var(--surface-lift);
  border: 1px solid var(--line);
  font-size: 15px;
}

.mode-chip:hover { border-color: var(--accent); }
.mode-chip[disabled] { opacity: 0.4; cursor: default; }
.mode-chip[disabled]:hover { border-color: var(--line); }

/* ---------------------------------------------------------------- play ---- */

.play {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 14px 18px 18px;
  gap: 12px;
}

.play-bar {
  display: flex;
  align-items: center;
  gap: 16px;
  flex: none;
}

/* Free play has no questions to count, so the bar carries only the way out. */
.play-bar.bare .progress,
.play-bar.bare .tally {
  display: none;
}

.back {
  width: var(--tap);
  height: var(--tap);
  flex: none;
  border-radius: 50%;
  font-size: 22px;
  color: var(--muted);
  background: var(--surface);
}

.back:hover { color: var(--text); background: var(--surface-lift); }

.progress {
  flex: 1;
  height: 10px;
  border-radius: 999px;
  background: var(--surface);
  overflow: hidden;
}

.progress-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--correct);
  transition: width 0.35s ease;
}

.tally {
  flex: none;
  min-width: 4.5ch;
  text-align: right;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* The speed test: the count where the bar starts, the clock where the tally was,
   and the bar itself drains rather than fills. */
.play-bar .score {
  flex: none;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.play-bar .score b {
  color: var(--text);
  font-weight: 600;
}

.play-bar.timed .progress-fill {
  background: var(--accent);
  transition: width 0.25s linear;
}

.prompt {
  flex: none;
  margin: 0;
  min-height: 1.6em;
  text-align: center;
  font-size: clamp(24px, 4.2vw, 40px);
  font-weight: 600;
  letter-spacing: -0.02em;
}

.stage {
  flex: 1;
  min-height: 0;
  display: flex;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Centred when it fits, scrollable when it doesn't.
 *
 * `align-items: center` cannot do the second: a flex item taller than its
 * container overflows in *both* directions, and the part above the top edge is
 * unreachable by scrolling. On a phone the section menu was tall enough to print
 * its own heading over the prompt. Auto margins centre the same way and leave the
 * overflow scrollable. */
.stage > * {
  margin: auto;
}

.stage svg {
  width: 100%;
  height: 100%;
  max-height: 100%;
  /* A framed wall map: ocean behind the land, rounded card edges. */
  background: var(--water);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* ----------------------------------------------------------------- map ---- */

.region {
  fill: var(--land); /* fallback; every generated path carries a c0..c4 class */
  stroke: var(--bg);
  stroke-width: 1;
  stroke-linejoin: round;
  transition: fill 0.18s, filter 0.18s;
}

.region.c0 { fill: var(--map-0); }
.region.c1 { fill: var(--map-1); }
.region.c2 { fill: var(--map-2); }
.region.c3 { fill: var(--map-3); }
.region.c4 { fill: var(--map-4); }

/* Regions the active pack doesn't include (DC in the 50-states pack). Visible,
   because the map should still look like the country -- but not answerable. */
.region.inert {
  fill: #2b3550;
  pointer-events: none;
}

/* Inert keeps its atlas colour, pulled most of the way to the background --
   the map stays whole while the askable regions pop. Derived from the live
   tokens (38% colour = 62% toward --bg, matching the video pipeline's
   INERT_PULL), so a palette retune can't strand stale baked blends. :where()
   keeps these at .region.inert's own specificity, so the state classes
   (correct/wrong/answer, declared later) still win on an inert region. */
.region.inert:where(.c0) { fill: color-mix(in srgb, var(--map-0) 38%, var(--bg)); }
.region.inert:where(.c1) { fill: color-mix(in srgb, var(--map-1) 38%, var(--bg)); }
.region.inert:where(.c2) { fill: color-mix(in srgb, var(--map-2) 38%, var(--bg)); }
.region.inert:where(.c3) { fill: color-mix(in srgb, var(--map-3) 38%, var(--bg)); }
.region.inert:where(.c4) { fill: color-mix(in srgb, var(--map-4) 38%, var(--bg)); }

/* Enlarged tap targets for the states too small to hit with a finger. Invisible
   but hit-testable; `fill: none` would make them transparent to pointers too. */
.hit {
  fill: transparent;
  cursor: pointer;
}

.hit.inert { pointer-events: none; }

/* Hover brightens whatever colour the region wears -- a fill swap can't,
   now that there are five. */
svg:not(.locked) .region:not(.inert):hover { filter: brightness(1.18); }

.region.correct { fill: var(--correct); }
.region.wrong { fill: var(--wrong); }

.region.answer {
  fill: var(--answer);
  animation: pulse 0.6s ease-in-out 2;
}

@keyframes pulse {
  /* Dips toward a bright amber glow, never leaving the answer's colour
     family -- the old slate midpoint read as one more map colour on the
     atlas palette. 45% answer + 55% white = the video pipeline's PULSE_GLOW
     (blend toward white at 0.55), derived so a retuned --answer keeps them
     matched. */
  50% { fill: color-mix(in srgb, var(--answer) 45%, white); }
}

svg.locked .region, svg.locked .hit { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .region, .progress-fill { transition: none; }
  .region.answer { animation: none; }
}

/* -------------------------------------------------------------- choice ---- */

.choices {
  display: grid;
  /* Always 2x2. auto-fit reflowed to 3+1 on a tablet, which reads as a ranking
     rather than a set of four equal options -- the shape should be the same
     every question so the eye knows where to go. */
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  width: min(680px, 100%);
}

.choice {
  padding: 26px 20px;
  min-height: 104px;
  border-radius: var(--radius);
  background: var(--surface);
  border: 2px solid var(--line);
  font-size: clamp(19px, 2.6vw, 27px);
  font-weight: 600;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}

.choice:hover { background: var(--surface-lift); border-color: var(--accent); }
.choice:active { transform: scale(0.98); }

.choices.locked .choice { pointer-events: none; }

.choice.correct {
  background: var(--correct);
  border-color: var(--correct);
  color: #06281c;
}

.choice.wrong {
  background: var(--wrong);
  border-color: var(--wrong);
  color: #3a0b0b;
}

@media (prefers-reduced-motion: reduce) {
  .choice { transition: none; }
}

/* --------------------------------------------------------------- done ----- */

.done {
  text-align: center;
  padding: 24px;
}

.done h2 {
  margin: 0 0 8px;
  font-size: clamp(28px, 5vw, 44px);
}

.done p {
  margin: 0 0 28px;
  color: var(--muted);
  font-size: 18px;
}

.done p.overall {
  margin-top: -18px;
  font-size: 15px;
  color: var(--accent);
}

/* The facts a speed test missed, under the score. */
.done p.missed {
  margin-top: -18px;
  font-size: 15px;
}

.done-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

.btn {
  padding: 16px 30px;
  min-height: var(--tap);
  border-radius: 999px;
  font-size: 17px;
  font-weight: 600;
  background: var(--surface-lift);
  border: 1px solid var(--line);
}

.btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #0b1220;
}

/* The picker is a list first and a headline second — the heading competes with it
   for a phone screen, so it is sized to ask the question and get out of the way. */
.done.picker {
  padding: 8px 12px 12px;
  width: 100%;
}

.done.picker h2 {
  font-size: clamp(20px, 3.4vw, 30px);
  color: var(--muted);
  font-weight: 600;
}

/* The section menu. A grid rather than a row: nine US divisions wrap into an
   even block, and every target is a full-width tap on a phone. */
.sections {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px;
  margin-top: 20px;
  text-align: left;
}

.sections .btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 14px 20px;
  font-size: 16px;
}

/* The whole map is the last level, so it reads as the one at the end rather than
   as one more equal choice. */
.sections .btn.whole {
  grid-column: 1 / -1;
  border-style: dashed;
  border-color: var(--accent);
}

.sections .btn[disabled] { opacity: 0.5; }

.btn:active { transform: scale(0.98); }

/* ------------------------------------------------------------ type-in ----- */

/* One column: the fact above, the keys below, sized so the whole thing fits a
   phone in portrait without scrolling and every key stays a finger's width. */
.typein {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  width: min(380px, 100%);
}

.equation {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.35em;
  font-size: clamp(30px, 6vw, 56px);
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  /* One line, always. The column is sized to the keypad, and "11 × 11 = 121" is
     wider than that at desktop size, so the "=" used to wrap under the fact. The
     equation may be wider than the keys; the floor is set so the widest case on a
     phone -- a struck-out miss beside the right answer -- still fits at 375px. */
  white-space: nowrap;
  width: max-content;
}

/* The answer slot: an underline to type into, coloured by the verdict. */
.equation .typed {
  min-width: 2.4ch;
  padding: 0 0.15em;
  text-align: center;
  border-bottom: 4px solid var(--accent);
}
.equation .typed.empty { color: var(--muted); }
.equation .typed.correct { color: var(--correct); border-color: var(--correct); }
.equation .typed.wrong {
  color: var(--wrong);
  border-color: var(--wrong);
  text-decoration: line-through;
}
.equation .answer { color: var(--answer); }

.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  width: 100%;
}

.key {
  min-height: var(--tap);
  padding: 14px 0;
  border-radius: var(--radius);
  background: var(--surface);
  border: 2px solid var(--line);
  font-size: clamp(22px, 3vw, 28px);
  font-weight: 600;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}

.key:hover { background: var(--surface-lift); border-color: var(--accent); }
.key:active { transform: scale(0.96); }
.key.del { color: var(--muted); }
.key.ok { background: var(--accent); border-color: var(--accent); color: #0b1220; }
.key.ok[disabled] { opacity: 0.35; cursor: default; }
.key.ok[disabled]:hover { background: var(--accent); }

.typein.locked .key { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
  .key { transition: none; }
}
