/* Map quiz. Layers, bottom to top: the map (#map: inline SVG, zoomed and
   panned by main.js; the page background is its sea, and the context land
   fades out at the edge of the drawn extent), the question card, the
   controls, the optional attribution line, and the transient toast and
   misclick label.
   Shared map-quiz engine file: the source is shared/map-quiz/site/, images
   get byte-identical copies (python3 shared/sync.py). Edit the source; an
   image overrides tokens (colours) in a stylesheet of its own, linked after
   this one.

   Pieces and answers (main.js): a round's answers are pieces or groups
   of them; a piece in no answer of the round is inert (.inert: drawn as
   context land). A round with line overlays (rounds[].lines) sets
   .seamless on the regions: each piece outlines itself in its own fill,
   so no hairline shows inside a group; the lines (#overlays .line) draw
   the outlines that count, and .off hides the ones another round shows.

   Two layouts (LANDSCAPE in main.js is the same media query):
   - default (portrait, square-ish): card across the top, controls across
     the bottom; main.js fits the map into the band between them.
   - landscape: card top right, controls in a column bottom right (under
     390 px high: its two groups side by side, clear of the card); the map
     uses the full height (at the full view the card covers a corner of it:
     keep that corner to context land, as Russia in europe-quiz).

   Theme: light tokens on :root, dark tokens for prefers-color-scheme: dark
   unless <html data-theme="light">, and for <html data-theme="dark"> (set
   by theme.js, which also handles the toggle). Dark mode: the round
   colours (A, B, their hovers, the misclick) are dark fills under a light
   border line, so the line stays visible between two neighbours of the
   same colour (contrast ≥ 2:1 against every fill). */

:root {
  color-scheme: light;
  --sea: #bfd9e7;
  --land: #e2ddd1;
  --land-line: #b5ad9e;
  --region: #fbf8f0;
  --region-hover: #efe7d6;
  --border: #7f8b91;
  --a: #74bf8f;
  --a-hover: #62b080;
  --b: #f2b661;
  --b-hover: #e7a74b;
  --pulse: #ffffff;
  --miss: #e35b4b;
  --ring: #33434b;
  --ring-halo: rgba(255, 255, 255, 0.85);
  --fg: #1d2a30;
  --muted: #5d6c73;
  --ok: #2c8a57;
  --bad: #c4473a;
  --panel: rgba(255, 253, 248, 0.93);
  --panel-line: rgba(60, 70, 80, 0.12);
  --shadow: 0 2px 10px rgba(30, 45, 55, 0.16);
  --btn-hover: rgba(255, 255, 255, 1);
  --label-bg: rgba(29, 42, 48, 0.92);
  --label-fg: #ffffff;
  --focus: #2f7fae;
  --water: var(--sea); /* overlays (rivers, lakes) … */
  --overlay-stroke: 0; /* … and their outline, map units */
  --inert: var(--land); /* pieces in no answer of the round … */
  --inert-line: var(--land-line); /* … and their outline */
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --sea: #0d1e2a;
    --land: #1a2932;
    --land-line: #2e414c;
    --region: #2b3e48;
    --region-hover: #375058;
    --border: #9ab2bd;
    --a: #20774f;
    --a-hover: #278460;
    --b: #a3530f;
    --b-hover: #b8600f;
    --pulse: #f0fff8;
    --miss: #c44a3f;
    --ring: #e4eef2;
    --ring-halo: rgba(4, 11, 17, 0.8);
    --fg: #e4eef2;
    --muted: #8ea4ae;
    --ok: #5fd39e;
    --bad: #ff8c7a;
    --panel: rgba(13, 27, 37, 0.9);
    --panel-line: rgba(160, 200, 220, 0.12);
    --shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
    --btn-hover: rgba(24, 46, 60, 1);
    --label-bg: rgba(236, 244, 247, 0.95);
    --label-fg: #0d1e2a;
    --focus: #7cc4e8;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --sea: #0d1e2a;
  --land: #1a2932;
  --land-line: #2e414c;
  --region: #2b3e48;
  --region-hover: #375058;
  --border: #9ab2bd;
  --a: #20774f;
  --a-hover: #278460;
  --b: #a3530f;
  --b-hover: #b8600f;
  --pulse: #f0fff8;
  --miss: #c44a3f;
  --ring: #e4eef2;
  --ring-halo: rgba(4, 11, 17, 0.8);
  --fg: #e4eef2;
  --muted: #8ea4ae;
  --ok: #5fd39e;
  --bad: #ff8c7a;
  --panel: rgba(13, 27, 37, 0.9);
  --panel-line: rgba(160, 200, 220, 0.12);
  --shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
  --btn-hover: rgba(24, 46, 60, 1);
  --label-bg: rgba(236, 244, 247, 0.95);
  --label-fg: #0d1e2a;
  --focus: #7cc4e8;
}

html,
body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--sea);
  color: var(--fg);
  font: 15px/1.3 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Touches pan and zoom the map: no page scrolling, zooming, selection
     or callouts. */
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

p {
  margin: 0;
}

/* ── Map ─────────────────────────────────────────────────────────────── */

#map {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

#map svg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

#map svg.over {
  cursor: pointer;
}

#map svg.panning {
  cursor: grabbing;
}

/* Strokes keep their width in screen pixels at any zoom. */
#map path,
#map rect,
#map circle {
  vector-effect: non-scaling-stroke;
}

/* Fade at the edge of the drawn extent: land dissolves into the sea. */
#fade {
  pointer-events: none;
}

#fade stop {
  stop-color: var(--sea);
}

.fade-1 {
  stop-opacity: 0.84;
}

.fade-2 {
  stop-opacity: 0.5;
}

.fade-3 {
  stop-opacity: 0.16;
}

.fade-4 {
  stop-opacity: 0;
}

#fade-t {
  fill: url(#fade-gt);
}

#fade-b {
  fill: url(#fade-gb);
}

#fade-l {
  fill: url(#fade-gl);
}

#fade-r {
  fill: url(#fade-gr);
}

/* Overlays (map.svg's #overlays, e.g. rivers): above the regions, never
   hit: clicks and hover go to what lies beneath. Fill and an outline of
   the same colour, its width in map units (it scales with the map, so it
   closes the same gaps, e.g. under bridges, at any zoom): --water and
   --overlay-stroke, both per image; style one overlay by its id. */
#overlays {
  pointer-events: none;
}

#overlays path {
  fill: var(--water);
  stroke: var(--water);
  stroke-width: var(--overlay-stroke);
  stroke-linejoin: round;
  vector-effect: none;
}

/* Line overlays (rounds[].lines: coasts, borders between groups; open
   lines along the region edges): a stroke only, the region outline's
   hairline, shown in the rounds that list them. */
#overlays path.line {
  fill: none;
  stroke: var(--border);
  stroke-width: 0.75px;
  stroke-linejoin: round;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

#overlays path.off {
  display: none;
}

#land {
  fill: var(--land);
  stroke: var(--land-line);
  stroke-width: 0.6px;
  stroke-linejoin: round;
  pointer-events: none;
}

/* Regions (main.js adds class "regions" to their group in map.svg).
   --fill: the region's resting colour (the blink returns to it). */
.regions path {
  --fill: var(--region);
  fill: var(--fill);
  stroke: var(--border);
  stroke-width: 0.75px;
  stroke-linejoin: round;
}

.regions path.hover {
  --fill: var(--region-hover);
}

.regions path.c1 {
  --fill: var(--a);
}

.regions path.c1.hover {
  --fill: var(--a-hover);
}

.regions path.c2 {
  --fill: var(--b);
}

.regions path.c2.hover {
  --fill: var(--b-hover);
}

/* A correct answer: the new colour fades in from a bright flash. */
.regions path.pulse {
  animation: pulse 0.7s ease-out;
}

/* A misclick: the picked region blinks twice. */
.regions path.flash {
  animation: flash 0.5s linear 2;
}

@keyframes pulse {
  from {
    fill: var(--pulse);
  }
}

@keyframes flash {
  0%,
  55% {
    fill: var(--miss);
  }
  65%,
  100% {
    fill: var(--fill);
  }
}

/* A round with line overlays: each piece outlines itself in its own fill
   (closing hairline seams between the pieces of a group); the line
   overlays above draw the outlines. Pulse and blink animate the outline
   with the fill. */
.regions.seamless path {
  stroke: var(--fill);
  stroke-width: 0.6px;
}

.regions.seamless path.pulse {
  animation-name: pulse-seamless;
}

.regions.seamless path.flash {
  animation-name: flash-seamless;
}

@keyframes pulse-seamless {
  from {
    fill: var(--pulse);
    stroke: var(--pulse);
  }
}

@keyframes flash-seamless {
  0%,
  55% {
    fill: var(--miss);
    stroke: var(--miss);
  }
  65%,
  100% {
    fill: var(--fill);
    stroke: var(--fill);
  }
}

/* A piece in no answer of the round: context land for that round (never
   hit, never hovered; its colour from earlier rounds comes back with it). */
.regions path.inert {
  --fill: var(--inert);
  stroke: var(--inert-line);
  stroke-width: 0.6px;
}

/* Rings for regions too small to tap at the full view (main.js hides a
   ring once its region is big enough on screen). The hit area is larger
   than the ring and handled in main.js. */
#markers {
  pointer-events: none;
}

#markers .off {
  display: none;
}

.marker-halo {
  fill: none;
  stroke: var(--ring-halo);
  stroke-width: 4px;
}

.marker {
  fill: var(--region);
  fill-opacity: 0;
  stroke: var(--ring);
  stroke-width: 1.5px;
}

.marker.c1 {
  fill: var(--a);
  fill-opacity: 1;
}

.marker.c2 {
  fill: var(--b);
  fill-opacity: 1;
}

.marker.hover {
  stroke-width: 2.5px;
}

.marker.flash {
  animation: flash-ring 0.5s linear 2;
}

@keyframes flash-ring {
  0%,
  55% {
    fill: var(--miss);
    fill-opacity: 1;
    stroke: var(--miss);
  }
}

/* ── Question card ───────────────────────────────────────────────────── */

#card,
#controls {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  width: min(520px, calc(100% - 24px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px)));
  box-sizing: border-box;
}

#card {
  top: calc(env(safe-area-inset-top, 0px) + 10px);
  padding: 9px 16px 10px;
  border-radius: 14px;
  background: var(--panel);
  border: 1px solid var(--panel-line);
  box-shadow: var(--shadow);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.card-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  height: 20px;
}

.round {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12.5px;
  font-weight: 650;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.swatch {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--a);
  box-shadow: 0 0 0 1px var(--panel-line);
}

/* Odd rounds colour with B (main.js). */
.swatch.b {
  background: var(--b);
}

/* Round picker (config.roundPicker): main.js wraps #round in .picker and
   lays a native <select> over it, invisible and larger than the label
   (about 38 px high, inside the card), so the label keeps its look, the
   platform draws the list, and the card keeps its size. The chevron after
   the label says it opens; it costs the row about 9 px (where the row
   overflows, the card fits it: "Top row" below). */
.picker {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-radius: 4px;
}

.picker::after {
  content: "";
  width: 4px;
  height: 4px;
  margin-top: -3px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg);
}

#round-picker {
  position: absolute;
  top: -10px;
  left: -8px;
  width: calc(100% + 16px);
  height: calc(100% + 22px);
  box-sizing: border-box;
  margin: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  font-size: 16px; /* iOS zooms in on focus into smaller form fields */
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

@media (hover: hover) {
  .picker:hover {
    color: var(--fg);
  }
}

.picker:has(#round-picker:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

/* Without :has() (Firefox before 121): the ring on any focus. */
@supports not selector(:has(*)) {
  .picker:focus-within {
    outline: 2px solid var(--focus);
    outline-offset: 3px;
  }
}

#progress {
  color: var(--fg);
  letter-spacing: 0.02em;
}

.score {
  display: flex;
  gap: 12px;
  font-size: 14px;
  white-space: nowrap;
}

.ok {
  color: var(--ok);
}

.bad {
  color: var(--bad);
}

.num {
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

#prompt {
  height: 36px;
  margin-top: 3px;
  font-size: clamp(21px, 5.8vw, 28px);
  line-height: 36px;
  font-weight: 700;
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Optional second line (rounds[].sub; main.js adds it and :root.has-sub
   when a round has one): the same height in every round, so the card
   never changes size. */
#prompt-sub {
  height: 18px;
  font-size: 13.5px;
  line-height: 18px;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Top row where it overflows (a 320 px phone, a long label, big counters,
   the round picker's chevron): main.js fitRow tries these on #card in
   turn and keeps the first that fits. .row-tight narrows the round
   label's letter-spacing; .row-wide (landscape: --card-min) gives the card
   at least 260 px; .row-wrap puts the counters on a line of their own, so the
   card grows by 20 px and the toast moves down with it. Where the row
   fits, none applies. */
#card.row-tight #round {
  letter-spacing: 0.03em;
}

#card.row-wrap .card-row {
  flex-wrap: wrap;
  row-gap: 0;
  height: auto;
}

#card.row-wrap .round,
#card.row-wrap .score {
  height: 20px;
  align-items: center;
}

#card.row-wrap .score {
  margin-left: auto;
  position: relative; /* above the round picker's larger target */
  z-index: 1;
}

#card.row-wrap ~ #toast {
  --row-grow: 20px;
}

/* ── Toast and misclick label ────────────────────────────────────────── */

/* Just below the card: 82 px from its top, 100 px with the sub-line, 20 px
   more when the card's top row takes two lines (--row-grow, .row-wrap).
   Centred as wide as its text needs, up to max-width of the whole window
   (left: 50% with a translate would let it shrink into the right half). */
#toast {
  position: fixed;
  left: 0;
  right: 0;
  margin: 0 auto;
  box-sizing: border-box;
  top: calc(env(safe-area-inset-top, 0px) + 10px + 82px + var(--row-grow, 0px));
  width: fit-content;
  max-width: min(480px, calc(100% - 40px));
  padding: 7px 14px;
  border-radius: 10px;
  background: var(--panel);
  border: 1px solid var(--panel-line);
  box-shadow: var(--shadow);
  font-size: 14px;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.25s, visibility 0s 0.25s;
}

:root.has-sub #toast {
  top: calc(env(safe-area-inset-top, 0px) + 10px + 100px + var(--row-grow, 0px));
}

#toast.show {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.25s;
}

#label {
  position: fixed;
  top: 0;
  left: 0;
  max-width: calc(100vw - 16px);
  padding: 5px 11px;
  border-radius: 8px;
  background: var(--label-bg);
  color: var(--label-fg);
  font-size: 15px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: var(--shadow);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.2s, visibility 0s 0.2s;
}

#label.show {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.12s;
}

/* ── Attribution (optional: config.attribution) ──────────────────────── */

/* Portrait: a line under the controls, which move up to make room.
   Landscape (below): the bottom-left corner, clear of the controls column. */
#attribution {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 5px);
  transform: translateX(-50%);
  max-width: calc(100% - 24px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  box-sizing: border-box;
  padding: 1px 7px;
  border-radius: 6px;
  background: var(--panel);
  color: var(--muted);
  font-size: 11px;
  line-height: 15px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

:root.has-attribution #controls {
  bottom: calc(env(safe-area-inset-bottom, 0px) + 28px);
}

/* ── Controls ────────────────────────────────────────────────────────── */

#controls {
  bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
  display: flex;
  justify-content: space-between;
  pointer-events: none;
}

.group {
  display: flex;
  gap: 8px;
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: 44px;
  height: 44px;
  padding: 0 10px;
  border: 1px solid var(--panel-line);
  border-radius: 12px;
  background: var(--panel);
  box-shadow: var(--shadow);
  color: var(--fg);
  font: inherit;
  font-weight: 650;
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.btn:hover {
  background: var(--btn-hover);
}

.btn:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Zoom limit reached (aria-disabled keeps the button focusable). */
.btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: default;
}

.btn[aria-disabled="true"]:hover {
  background: var(--panel);
}

.icon {
  width: 22px;
  height: 22px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-sun,
:root[data-theme="dark"] .icon-moon {
  display: none;
}

:root[data-theme="dark"] .icon-sun {
  display: block;
}

.btn-text {
  display: none;
}

/* Reset asks once: the first press arms it for a few seconds. */
#reset.armed {
  color: var(--bad);
  border-color: currentColor;
}

#reset.armed .btn-text {
  display: inline;
}

@media (pointer: fine) {
  .btn {
    min-width: 40px;
    height: 40px;
  }
}

/* ── Landscape ───────────────────────────────────────────────────────── */

@media (min-aspect-ratio: 4/3) {
  #card,
  #toast {
    left: auto;
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    transform: none;
    width: max(var(--card-min, 0px), min(340px, 36vw));
  }

  /* Top row: a card wide enough for it (36vw is 204 px on a 568 px screen). */
  #card.row-wide,
  #card.row-wide ~ #toast {
    --card-min: 260px;
  }

  #card {
    top: calc(env(safe-area-inset-top, 0px) + 12px);
  }

  #prompt {
    font-size: clamp(19px, 2.4vw, 26px);
  }

  #toast {
    top: calc(env(safe-area-inset-top, 0px) + 12px + 82px + var(--row-grow, 0px));
    margin: 0;
    max-width: none;
  }

  :root.has-sub #toast {
    top: calc(env(safe-area-inset-top, 0px) + 12px + 100px + var(--row-grow, 0px));
  }

  #controls {
    left: auto;
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    transform: none;
    width: auto;
    flex-direction: column;
    align-items: flex-end;
    gap: 14px;
  }

  .group {
    flex-direction: column;
    align-items: flex-end;
  }

  .group:last-child {
    flex-direction: column-reverse;
  }

  #attribution {
    left: calc(env(safe-area-inset-left, 0px) + 12px);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
    transform: none;
    /* the controls column: 12 px margin, up to 44 px buttons, a gap */
    max-width: calc(100% - 88px - env(safe-area-inset-left, 0px) - env(safe-area-inset-right, 0px));
  }

  :root.has-attribution #controls {
    bottom: calc(env(safe-area-inset-bottom, 0px) + 12px);
  }
}

/* Short landscape (phones held sideways, under 390 px high): one column of
   five buttons (258 px with touch-sized ones) would reach up into the card
   (up to 110 px from the top with a sub-line), so the two groups stand side
   by side, three buttons high. */
@media (min-aspect-ratio: 4/3) and (max-height: 389px) {
  #controls {
    flex-direction: row;
  }
}

/* … and up to 409 px high while the card's top row takes two lines (a
   20 px taller card). */
@media (min-aspect-ratio: 4/3) and (max-height: 409px) {
  #card.row-wrap ~ #controls {
    flex-direction: row;
  }
}

/* ── Reduced motion: no transitions, no pulse; a misclick is a steady
   highlight instead of a blink (main.js removes it with the label). ── */

@media (prefers-reduced-motion: reduce) {
  #toast,
  #toast.show,
  #label,
  #label.show {
    transition: none;
  }

  .regions path.pulse {
    animation: none;
  }

  .regions path.flash {
    animation: none;
    fill: var(--miss);
  }

  .regions.seamless path.pulse {
    animation: none;
  }

  .regions.seamless path.flash {
    animation: none;
    fill: var(--miss);
    stroke: var(--miss);
  }

  .marker.flash {
    animation: none;
    fill: var(--miss);
    fill-opacity: 1;
    stroke: var(--miss);
  }
}

/* ── Misc ────────────────────────────────────────────────────────────── */

/* Safe-area insets (notches, home indicator), read by main.js. */
#safe {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px)
    env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
  visibility: hidden;
  pointer-events: none;
}

.noscript {
  position: fixed;
  top: 50%;
  left: 0;
  right: 0;
  text-align: center;
}

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