:root {
  --ink: #06141a;
  --ink-2: #0a1c23;
  --ink-3: #0d242c;
  --jade: #2fb897;
  --jade-dim: rgba(47,184,151,.45);
  --orange: #e2762c;
  --orange-lift: #ef8a4a;
  --bone: #cfe4de;
  --dim: rgba(207,228,222,.58);
  --faint: rgba(207,228,222,.32);
  --line: rgba(47,184,151,.24);
  --c-v: #2fb897;
  --c-z: #3d70d6;
  --beam-1: rgba(255,196,140,.16);
  --beam-2: rgba(210,190,180,.05);
  --ui: "Space Grotesk",-apple-system,BlinkMacSystemFont,sans-serif;

  /* The fixed nav's own height. Everything that has to clear it — the page
     header, the scroll anchor offset — measures from this, so the bar and
     the space under it can never drift apart. */
  --navh: 54px;

  /* Say the page is dark on purpose. Without this a browser is free to decide
     the page needs "fixing" and invert it — which is what turns a dark map and
     a dark pair of logs white while everything else looks roughly right. */
  color-scheme: dark;
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--navh) + 24px);
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--bone);
  font-family: var(--ui);
  font-weight: 300;
  line-height: 1.68;
  font-size: 17px;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 99;
  opacity: .07;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

body.locked {
  overflow: hidden;
}

.wrap {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 30px;
  position: relative;
  z-index: 2;
}

h1,
h2,
h3 {
  font-family: var(--ui);
  font-weight: 700;
  margin: 0;
  line-height: 1.04;
  text-transform: uppercase;
  letter-spacing: .01em;
}

.tab {
  display: inline-block;
  border: 1px solid var(--line);
  color: var(--jade);
  padding: 4px 11px 3px;
  font-weight: 500;
  font-size: .63rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  line-height: 1.2;
}

/* ================= HERO ================= */
.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
  text-align: center;
}

.sky {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: radial-gradient(120% 80% at 50% 92%, #0d2a2e 0%, #07171d 46%, #040f14 100%);
}

.stars {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  fill: #fff;
}

.beam {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: min(20vw,190px);
  height: 82%;
  transform: translateX(-50%);
  z-index: 1;
  opacity: .85;
  filter: blur(13px);
  background: radial-gradient(58% 100% at 50% 100%, var(--beam-1) 0%, var(--beam-2) 38%, transparent 74%);
}

.treeline {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  z-index: 2;
  display: block;
}

.treeline .far {
  fill: #0a222a;
  opacity: .9;
}

.treeline .near {
  fill: #030c11;
}

.hero .wrap {
  width: 100%;
  z-index: 4;
  padding-bottom: 16vh;
}

.kicker {
  display: block;
  font-size: .7rem;
  font-weight: 500;
  letter-spacing: .58em;
  text-transform: uppercase;
  color: var(--jade);
  margin-bottom: 38px;
}

.hero h1 {
  font-size: clamp(2.3rem,7.4vw,5.4rem);
  color: var(--bone);
  line-height: .96;
}

.hero-sub {
  max-width: 46ch;
  margin: 38px auto 0;
  color: rgba(207,228,222,.8);
  font-size: 1.02rem;
}

.hero-sub b {
  color: var(--orange-lift);
  font-weight: 500;
}

/* ---- constellations ---- */
.cst {
  position: absolute;
  z-index: 5;
  width: 118px;
  display: block;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.cst svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.cst .link {
  fill: none;
  stroke: var(--bone);
  stroke-width: .7;
  opacity: .14;
  transition: opacity .45s,stroke .45s;
}

.cst .star {
  fill: #fff;
  opacity: .78;
  transition: opacity .45s;
}

.cst .halo {
  fill: #fff;
  opacity: 0;
  transition: opacity .45s;
}

.cst .cst-label {
  display: block;
  margin-top: 6px;
  text-align: center;
  font-size: .55rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--bone);
  opacity: .3;
  transition: opacity .4s,color .4s;
}

.cst:hover .link,
.cst:focus-visible .link {
  opacity: .62;
  stroke: var(--jade);
}

.cst:hover .star,
.cst:focus-visible .star {
  opacity: 1;
}

.cst:hover .halo,
.cst:focus-visible .halo {
  opacity: .22;
}

.cst:hover .cst-label,
.cst:focus-visible .cst-label {
  opacity: 1;
  color: var(--jade);
}

.cst:focus-visible {
  outline: 1px solid var(--jade);
  outline-offset: 10px;
}

.cst-book {
  left: 4%;
  top: 13%;
}

.cst-flag {
  left: 23.5%;
  top: 6%;
}

.cst-puzzle {
  left: 43%;
  top: 10%;
}

.cst-ring {
  left: 62%;
  top: 5%;
}

.cst-pot {
  left: 82%;
  top: 12.5%;
}

/* ================= NAV ================= */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: flex;
  justify-content: center;
  gap: 4px;
  padding: 0 12px;
  background: rgba(4,16,21,.9);
  border-bottom: 1px solid var(--line);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: transform .4s cubic-bezier(.4,0,.2,1);
}

.nav a {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 16px 14px 14px;
  text-decoration: none;
  color: var(--faint);
  font-size: .6rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  border-bottom: 2px solid transparent;
  transition: color .25s,border-color .25s;
}

.nav a:hover {
  color: var(--bone);
}

.nav a.active {
  color: var(--jade);
  border-bottom-color: var(--jade);
}

.nav a:focus-visible {
  outline: 1px solid var(--jade);
  outline-offset: -4px;
}

.nav svg {
  width: 22px;
  height: 22px;
  display: block;
  overflow: visible;
  flex: none;
}

.nav .link {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
  opacity: .45;
}

.nav .star {
  fill: currentColor;
  opacity: .9;
}

.nav .halo {
  display: none;
}

/* ================= SECTIONS ================= */
section {
  position: relative;
  padding: 104px 0;
}

.sechead {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.sechead h2 {
  font-size: clamp(1.7rem,3.8vw,2.7rem);
  margin-top: 18px;
}

.sechead h2 .o {
  color: var(--jade);
}

.lede {
  color: var(--dim);
  font-size: .95rem;
  margin: 14px auto 0;
  max-width: 52ch;
}

.prose {
  max-width: 60ch;
  margin: 34px auto 0;
  color: var(--dim);
}

.prose p {
  margin: 0 0 18px;
}

.prose b {
  color: var(--bone);
  font-weight: 500;
}

/* ---- ledger ---- */
.ledger-grid {
  display: grid;
  grid-template-columns: repeat(4,1fr);
  border: 1px solid var(--line);
  margin-top: 40px;
}

.panel {
  position: relative;
  border-left: 1px solid var(--line);
  text-align: center;
  padding: 30px 14px 26px;
}

.panel:first-child {
  border-left: 0;
}

.panel .ico {
  display: block;
  margin: 0 auto 16px;
  width: 26px;
  height: 26px;
  color: var(--jade);
  opacity: .85;
}

.panel .v {
  font-size: clamp(1.9rem,4.4vw,3rem);
  line-height: 1;
  color: var(--jade);
  font-weight: 300;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}

.panel .u {
  font-size: .6rem;
  font-weight: 500;
  color: var(--faint);
  margin-left: 7px;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.panel .k {
  margin-top: 14px;
  font-size: .58rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}

.ledger-note {
  margin-top: 20px;
  text-align: center;
  font-size: .68rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--faint);
}

.ledger-note b {
  color: var(--bone);
  font-weight: 500;
}

/* ---- chart ---- */
.toggle {
  display: flex;
  gap: 10px;
  margin-top: 22px;
}

.toggle button {
  appearance: none;
  background: none;
  cursor: pointer;
  border: 1px solid var(--line);
  color: var(--faint);
  padding: 8px 15px;
  font-family: var(--ui);
  font-weight: 500;
  font-size: .62rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  transition: .2s;
}

.toggle button[aria-pressed="true"] {
  background: var(--jade);
  border-color: var(--jade);
  color: #04120e;
}

.toggle button:hover {
  color: var(--bone);
}

.toggle button[aria-pressed="true"]:hover {
  color: #04120e;
}

.toggle button:focus-visible {
  outline: 1px solid var(--orange);
  outline-offset: 3px;
}

.chart {
  position: relative;
  margin-top: 30px;
  padding: 30px 0 0;
  border: 1px solid var(--line);
}

.fsbtn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 6;
  appearance: none;
  display: flex;
  align-items: center;
  gap: 7px;
  background: rgba(6,20,26,.72);
  border: 1px solid var(--line);
  color: var(--dim);
  font-family: var(--ui);
  font-size: .58rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: 7px 11px;
  cursor: pointer;
  transition: color .2s,border-color .2s;
}

.fsbtn svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
}

.fsbtn:hover {
  color: var(--jade);
  border-color: var(--jade);
}

.fsbtn:focus-visible {
  outline: 1px solid var(--orange);
  outline-offset: 3px;
}

/* ---- theater mode ----------------------------------------------------
   Two things at once. assets/map.js asks the browser for real fullscreen, so
   the URL bar and the system chrome go; these rules do the rest, and are also
   the whole effect on a browser that refuses. A scrim covers the page (dimmed
   and blurred, the way a video goes theater) and the chart is lifted on top of
   it. Sits above the nav (60) but below the city overlay (80), so tapping a
   city while expanded still opens the detail on top. */
body.mapfs {
  overflow: hidden;
}

.mapscrim {
  position: fixed;
  inset: 0;
  z-index: 65;
  background: rgba(3,11,15,.94);
  backdrop-filter: blur(14px) saturate(.6);
  -webkit-backdrop-filter: blur(14px) saturate(.6);
  opacity: 0;
  pointer-events: none;
  transition: opacity .38s ease;
}

body.mapfs .mapscrim {
  opacity: 1;
  pointer-events: auto;
}

/* the nav is the one bit of chrome that would still sit over the map */
body.mapfs .nav {
  transform: translateY(-100%);
}

.chart.fs {
  position: fixed;
  inset: 0;
  z-index: 70;
  margin: 0;
  border: 0;
  background: none;
  height: 100vh;
  height: 100dvh;

  /* The top gutter is the Exit button's lane. Without it the map is height-
     fitted flush to the screen edge and the northern border reads as clipped. */
  padding: calc(env(safe-area-inset-top,0px) + 48px) calc(env(safe-area-inset-right,0px) + 10px) calc(env(safe-area-inset-bottom,0px) + 8px) calc(env(safe-area-inset-left,0px) + 10px);
  display: flex;
  flex-direction: column;
  animation: maphone .34s cubic-bezier(.2,.7,.3,1) both;
}

@keyframes maphone {
  from {
    opacity: 0;
    transform: scale(.96);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.chart.fs .corner {
  display: none;
}

/* centred rather than top-aligned: on a phone the map is much wider than it
   is tall, so it letterboxes, and the empty band should sit on both sides */
.chart.fs #race-map {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.chart.fs svg.usmap {
  flex: 1;
  min-height: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.chart.fs .timeline {
  flex: none;
  border-top: 1px solid var(--line);
}

.chart.fs .fsbtn {
  top: calc(env(safe-area-inset-top,0px) + 8px);
}

/* ---- theater on a touch device ----
   No rotation. This block used to lay the panel out landscape and turn it
   ninety degrees so a wide country filled a tall phone, which worked exactly
   until somebody tilted the phone to look at it: the OS rotated too, the two
   rotations added up, and the map came out sideways. Unless the tilt happened
   to be locked, in which case it was right — a coin toss is not a layout.

   So the map fills the screen as the screen actually is. In fullscreen, where
   the browser allows it, assets/map.js asks the phone to turn landscape and
   the phone does it. Where it does not, portrait letterboxes and turning the
   phone fills it, which is the same gesture with one more step.

   Keyed on pointer, not width: a desktop window dragged narrow is still a
   desktop window, and used to get all of this by accident. */
@media (pointer:coarse) and (any-hover:none) and (orientation:landscape) {
  /* Landscape has height to spare across, none to spare down, so the timeline
     goes back to a single row — stacked, it ate a third of what the map just
     won by turning. */
  .chart.fs .timeline {
    flex-direction: row;
    align-items: center;
    gap: 16px;
    padding: 10px 14px;
  }

  .chart.fs .playbtn {
    width: auto;
    height: 34px;
    padding: 0 14px;
  }

  .chart.fs .datebox {
    text-align: right;
  }

  /* Wide frame, so the city detail gets the three-pane layout rather than the
     stacked phone one. */
  body.mapfs .citybox {
    grid-template-columns: minmax(260px,40%) 1fr;
    grid-template-rows: minmax(110px,30%) 1fr;
    grid-template-areas: "photo map" "info map";
  }

  body.mapfs .cphoto,
  body.mapfs .cinfo {
    border-right: 1px solid var(--line);
  }

  body.mapfs .cmap {
    border-bottom: 0;
  }
}

/* Real fullscreen paints its own black behind the page; the site's own ground
   goes over it so nothing shows through at the edges of a letterboxed map. */
/* Two rules, not one selector list: a browser that does not know one of these
   pseudo-classes throws out the whole list it appears in, and the prefixed
   spelling only exists on WebKit. */
:fullscreen body {
  background: var(--ink);
}

:-webkit-full-screen body {
  background: var(--ink);
}

.corner {
  position: absolute;
  width: 34px;
  height: 34px;
  background: var(--jade);
  opacity: .07;
  pointer-events: none;
}

.corner.tl {
  top: 0;
  left: 0;
  border-radius: 0 0 100% 0;
}

.corner.tr {
  top: 0;
  right: 0;
  border-radius: 0 0 0 100%;
}

.corner.bl {
  bottom: 0;
  left: 0;
  border-radius: 0 100% 0 0;
}

.corner.br {
  bottom: 0;
  right: 0;
  border-radius: 100% 0 0 0;
}

svg.usmap {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.land {
  fill: #0b1220;
  stroke: none;
}

.state {
  fill: none;
  stroke: rgba(47,184,151,.10);
  stroke-width: .6;
}

.coast {
  fill: none;
  stroke: rgba(47,184,151,.30);
  stroke-width: .9;
}

.leg {
  fill: none;
  stroke-linecap: round;
  stroke-width: 1.9;
}

.leg.mode-fly {
  stroke-dasharray: 5 8;
  stroke-width: 1.4;
}

.leg.mode-train {
  stroke-dasharray: 1 5.5;
  stroke-width: 2;
}

.leg.mode-hike {
  stroke-dasharray: 2 5;
  stroke-width: 2.3;
}

.leg.p-v {
  stroke: var(--c-v);
}

.leg.p-z {
  stroke: var(--c-z);
}

.cityhit {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.cityhit .hit {
  fill: transparent;
}

.dot {
  fill: var(--ink);
  stroke: var(--c-v);
  stroke-width: 1.4;
  transition: opacity .35s,r .2s,stroke .2s;
}

.dot.solo-z {
  stroke: var(--c-z);
}

/* Filtered to one route: every dot takes that runner's colour, so the
   line and the cities it touches read as one thing. */
.usmap.view-v .dot {
  stroke: var(--c-v);
}

.usmap.view-z .dot {
  stroke: var(--c-z);
}

.cityhit:hover .dot,
.cityhit:focus-visible .dot {
  stroke: var(--orange);
  r: 5;
}

.cityhit:focus-visible {
  outline: none;
}

.cityhit:focus-visible .ring-focus {
  opacity: 1;
}

.ring-focus {
  fill: none;
  stroke: var(--orange);
  stroke-width: 1;
  opacity: 0;
}

.city {
  font-family: var(--ui);
  font-weight: 500;
  font-size: 8.6px;
  letter-spacing: .14em;
  fill: var(--dim);
  text-transform: uppercase;
  transition: opacity .35s,fill .2s;
}

.cityhit:hover .city {
  fill: var(--orange);
}

.passthru {
  pointer-events: none;
}

.passthru .dot {
  stroke-width: 1;
  opacity: .5;
}

.hidden {
  opacity: 0;
  pointer-events: none;
}

.marker {
  pointer-events: none;
  transition: opacity .3s;
}

.marker-core {
  stroke-width: 1.6;
  fill: var(--ink);
}

#mk-v .marker-core {
  stroke: var(--c-v);
}

#mk-z .marker-core {
  stroke: var(--c-z);
}

#glow-v .g0,
#glow-z .g0 {
  stop-color: var(--orange-lift);
  stop-opacity: .6;
}

#glow-v .g1,
#glow-z .g1 {
  stop-color: var(--orange);
  stop-opacity: .2;
}

#glow-v .g2,
#glow-z .g2 {
  stop-color: var(--orange);
  stop-opacity: 0;
}

/* map arming curtain */
.arm {
  position: absolute;
  inset: 30px 0 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 16px;
  z-index: 6;
  background: rgba(6,20,26,.72);
  transition: opacity .5s;
}

.arm.off {
  opacity: 0;
  pointer-events: none;
}

.arm p {
  margin: 0;
  font-size: .66rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}

.armbtn {
  appearance: none;
  background: var(--orange);
  border: 1px solid var(--orange);
  color: #160702;
  padding: 14px 26px;
  cursor: pointer;
  font-family: var(--ui);
  font-weight: 700;
  font-size: .66rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  transition: .2s;
}

.armbtn:hover {
  background: var(--orange-lift);
}

.chartinner {
  opacity: 0;
  transition: opacity .6s;
}

.chartinner.on {
  opacity: 1;
}

.timeline {
  border-top: 1px solid var(--line);
  padding: 20px 24px;
  display: flex;
  gap: 22px;
  align-items: center;
}

.playbtn {
  appearance: none;
  background: var(--orange);
  border: 1px solid var(--orange);
  color: #160702;
  height: 40px;
  padding: 0 20px;
  flex: none;
  cursor: pointer;
  font-family: var(--ui);
  font-weight: 700;
  font-size: .62rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  transition: .2s;
}

.playbtn:hover {
  background: var(--orange-lift);
  border-color: var(--orange-lift);
}

.playbtn:focus-visible {
  outline: 1px solid var(--jade);
  outline-offset: 3px;
}

.track {
  flex: 1;
  min-width: 0;
}

.track input {
  width: 100%;
  appearance: none;
  background: transparent;
  height: 20px;
  margin: 0;
  cursor: pointer;
}

.track input::-webkit-slider-runnable-track {
  height: 1px;
  background: var(--line);
}

.track input::-moz-range-track {
  height: 1px;
  background: var(--line);
}

.track input::-webkit-slider-thumb {
  appearance: none;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--orange);
  margin-top: -5.5px;
  box-shadow: 0 0 14px rgba(226,118,44,.7);
}

.track input::-moz-range-thumb {
  width: 12px;
  height: 12px;
  border: 0;
  border-radius: 50%;
  background: var(--orange);
}

.track input:focus-visible {
  outline: 1px solid var(--orange);
  outline-offset: 5px;
}

/* Under the scrubber, in the seat the live "who is where" readout used to
   have. That changed on every frame, and next to a moving map and a moving
   date it was the third thing in the panel asking to be read. The legend says
   the same colours and never moves. */
.track .key {
  margin-top: 11px;
  justify-content: flex-start;
  gap: 4px 16px;
}

.track .key span {
  border: 0;
  padding: 0;
  gap: 7px;
  font-size: .56rem;
  letter-spacing: .14em;
  color: var(--faint);
  white-space: nowrap;
}

.track .key i {
  width: 14px;
}

.datebox {
  flex: none;
  text-align: right;
  min-width: 132px;
}

.d-day {
  display: block;
  font-size: .56rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--faint);
}

.d-date {
  display: block;
  font-size: .95rem;
  font-weight: 500;
  color: var(--bone);
  letter-spacing: .04em;
}

.key {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
}

.key span {
  display: flex;
  align-items: center;
  gap: 9px;
  border: 1px solid var(--line);
  padding: 6px 12px;
  font-size: .6rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--dim);
}

.key i {
  width: 16px;
  height: 0;
  border-top: 2px solid;
  display: inline-block;
}

.hint {
  margin-top: 16px;
  text-align: center;
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ================= CITY DETAIL ================= */
.overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(2,9,12,.82);
  backdrop-filter: blur(7px);
  -webkit-backdrop-filter: blur(7px);
  display: none;
  align-items: center;
  justify-content: center;
  padding: 22px;
}

.overlay.on {
  display: flex;
}

.citybox {
  width: min(1140px,100%);
  max-height: 90svh;
  background: var(--ink-2);
  border: 1px solid var(--line);
  display: grid;
  grid-template-columns: minmax(320px,44%) 1fr;
  grid-template-rows: minmax(150px,27%) 1fr;
  grid-template-areas: "photo map" "info map";
  gap: 1px;
  position: relative;
  overflow: hidden;
}

.cbar {
  grid-area: photo;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: 5;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  padding: 14px 16px;
  pointer-events: none;
}

.cbar h3 {
  font-size: 1rem;
  letter-spacing: .12em;
  color: var(--bone);
  text-shadow: 0 2px 14px rgba(0,0,0,.8);
}

.chead {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  min-width: 0;
}

/* The two names, over the photo. Same chips as the race map's toggle, but
   they sit on a picture, so they carry their own backing. Each takes the
   colour of that person's line on the map above. */
.whobar {
  margin-top: 0;
  gap: 6px;
  pointer-events: auto;
}

.whobar button {
  background: rgba(6,20,26,.82);
  padding: 6px 12px;
  font-size: .58rem;
  letter-spacing: .16em;
}

.whobar button[data-who="v"][aria-pressed="true"] {
  background: var(--c-v);
  border-color: var(--c-v);
  color: #04120e;
}

.whobar button[data-who="z"][aria-pressed="true"] {
  background: var(--c-z);
  border-color: var(--c-z);
  color: #f2f6ff;
}

.whobar button[disabled] {
  opacity: .34;
  cursor: not-allowed;
  text-decoration: line-through;
}

.whobar button[disabled]:hover {
  color: var(--faint);
}

.closebtn {
  pointer-events: auto;
  appearance: none;
  background: rgba(6,20,26,.8);
  border: 1px solid var(--line);
  color: var(--bone);
  width: 34px;
  height: 34px;
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  flex: none;
  transition: .2s;
}

.closebtn:hover {
  border-color: var(--orange);
  color: var(--orange);
}

.cphoto {
  grid-area: photo;
  position: relative;
  overflow: hidden;
  background: var(--ink-3);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.cphoto img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.cphoto .ph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 8px;
  text-align: center;
  padding: 20px;
  background: repeating-linear-gradient(135deg,rgba(47,184,151,.05) 0 12px,transparent 12px 24px);
}

.cphoto .ph span {
  font-size: .58rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}

.cphoto .cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 12px 16px;
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--bone);
  background: linear-gradient(transparent,rgba(4,14,18,.92));
}

.cinfo {
  grid-area: info;
  overflow-y: auto;
  padding: 24px 26px 30px;
  border-right: 1px solid var(--line);
  -webkit-overflow-scrolling: touch;
}

.cinfo h4 {
  margin: 0 0 8px;
  font-size: .6rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--jade);
}

.cinfo p {
  margin: 0 0 18px;
  font-size: .9rem;
  color: var(--dim);
  line-height: 1.7;
}

.cinfo .stopnote {
  border-left: 1px solid var(--line);
  padding-left: 14px;
  margin-bottom: 18px;
}

.cinfo .stopnote b {
  display: block;
  color: var(--bone);
  font-weight: 500;
  font-size: .8rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  margin-bottom: 4px;
}

/* ---- the city map ----------------------------------------------------
   A tile map built by assets/map.js: a grid of images, a tint over them, the
   route and its pins in SVG on top. `.live` is the class the map adds once it
   has actually mounted; without it this is the old empty dark box, which is
   also what a network with no tiles on it looks like. */
.cmap {
  grid-area: map;
  position: relative;
  background: var(--ink-3);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 18px;
}

.cmap.live {
  display: block;
  padding: 0;
  overflow: hidden;
  cursor: grab;
  touch-action: none;              /* the pane pans; the page underneath does not */
  isolation: isolate;              /* keeps the tint's blend off the rest of the page */
}

.cmap.live.dragging {
  cursor: grabbing;
}

/* OpenStreetMap's standard style is a daytime map, and a white rectangle in
   this panel reads as a hole cut in the page. Inverting it and turning the
   hue back through 180° gives a dark map with its colours roughly where they
   started — water still blue, parks still green — which is the whole reason
   this can use a source that asks for no API key. */
.ctiles {
  position: absolute;
  inset: 0;
  filter: invert(1) hue-rotate(180deg) brightness(.82) contrast(1.1) saturate(.75);
}

.ctile {
  position: absolute;
  width: 256px;
  height: 256px;
  user-select: none;
  -webkit-user-drag: none;
  pointer-events: none;
}

/* A tile that never arrived leaves the dark box showing rather than a broken
   image icon. Losing one tile should not look like a bug. */
.ctile.gone {
  visibility: hidden;
}

/* CARTO's dark basemap is grey, and grey next to this palette reads as dead.
   Blending colour — hue and saturation from here, lightness from the map —
   pulls the streets towards the jade the rest of the site is drawn in without
   flattening anything. */
.ctint {
  position: absolute;
  inset: 0;
  background: #0e3f39;
  mix-blend-mode: color;
  opacity: .42;
  pointer-events: none;
}

.cmap.live .cpins {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.cmap svg {
  width: 100%;
  height: 100%;
  overflow: visible;
}

.croute {
  fill: none;
  stroke: var(--jade);
  stroke-width: 1.6;
  opacity: .55;
  stroke-dasharray: 5 6;
  stroke-linejoin: round;
  pointer-events: none;
}

.cstop {
  cursor: pointer;
}

.cstop circle {
  fill: rgba(6,20,26,.9);
  stroke: var(--jade);
  stroke-width: 1.8;
  transition: .2s;
}

.cstop text {
  pointer-events: none;
}

.cstop .cnum {
  fill: var(--bone);
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 500;
}

.cstop .cname {
  fill: var(--bone);
  font-family: var(--ui);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .08em;
  paint-order: stroke;
  stroke: rgba(3,11,15,.85);
  stroke-width: 3.5px;
  stroke-linejoin: round;
}

/* Whose stops are on the map. Vinny is the jade line on the race map and
   Zoë the blue one; the city map keeps that straight. The selected pin stays
   orange under either, because that is "you are here", not "who". */
.citybox.who-z .croute {
  stroke: var(--c-z);
}

.citybox.who-z .cstop circle {
  stroke: var(--c-z);
}

.cstop.sel circle {
  fill: var(--orange);
  stroke: var(--orange-lift);
  stroke-width: 2.6;
}

.cstop.sel .cnum {
  fill: #0b1a12;
}

.cstop:hover circle {
  stroke: var(--orange);
}

.cstop:focus-visible {
  outline: none;
}

.cstop:focus-visible circle {
  stroke: var(--orange);
  stroke-width: 3;
}

/* Zoom is whole levels — see the note in map.js — so these are the only
   controls, plus the third one that puts every stop back on screen. */
.czoom {
  position: absolute;
  top: 10px;
  right: 10px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  z-index: 3;
}

.czoom button {
  appearance: none;
  width: 30px;
  height: 30px;
  background: rgba(6,20,26,.86);
  border: 1px solid var(--line);
  color: var(--bone);
  font-family: var(--ui);
  font-size: .85rem;
  line-height: 1;
  cursor: pointer;
  transition: .2s;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.czoom button:hover {
  border-color: var(--orange);
  color: var(--orange);
}

/* Required by both OpenStreetMap and CARTO. Not decoration — leave it up. */
.ccredit {
  position: absolute;
  right: 6px;
  bottom: 4px;
  z-index: 3;
  font-size: .5rem;
  letter-spacing: .06em;
  color: var(--faint);
  background: rgba(3,11,15,.55);
  padding: 1px 6px;
}

.ccredit a {
  color: inherit;
  text-decoration: none;
}

.ccredit a:hover {
  color: var(--jade);
}

.cmap .empty {
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: center;
}

/* interactive widgets */
.widget {
  border: 1px solid var(--line);
  padding: 18px;
  margin-bottom: 20px;
}

.widget .wlab {
  font-size: .56rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--orange);
  display: block;
  margin-bottom: 12px;
}

.uvbox {
  position: relative;
  height: 120px;
  border: 1px solid var(--line);
  overflow: hidden;
  background: radial-gradient(80% 120% at 30% 20%, #14302c 0%, #0a1c23 70%);
  cursor: crosshair;
  touch-action: none;
}

.uv-base,
.uv-rev {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  text-align: center;
  font-size: .78rem;
  line-height: 1.5;
}

.uv-base {
  color: var(--faint);
}

.uv-rev {
  color: #9d7bff;
  font-weight: 500;
  text-shadow: 0 0 14px rgba(157,123,255,.8);
  -webkit-mask-image: radial-gradient(circle 60px at var(--mx,-999px) var(--my,-999px),#000 30%,transparent 72%);
  mask-image: radial-gradient(circle 60px at var(--mx,-999px) var(--my,-999px),#000 30%,transparent 72%);
}

.glyphs {
  font-size: 1.5rem;
  letter-spacing: .35em;
  color: var(--jade);
  text-align: center;
  margin-bottom: 14px;
  transition: opacity .45s;
}

.trans {
  text-align: center;
  font-size: .85rem;
  color: var(--bone);
  min-height: 1.4em;
  opacity: 0;
  transition: opacity .45s;
}

.widget.on .glyphs {
  opacity: .25;
}

.widget.on .trans {
  opacity: 1;
}

.wbtn {
  appearance: none;
  width: 100%;
  background: none;
  border: 1px solid var(--line);
  color: var(--jade);
  padding: 10px;
  cursor: pointer;
  font-family: var(--ui);
  font-weight: 500;
  font-size: .6rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  margin-top: 14px;
  transition: .2s;
}

.wbtn:hover {
  border-color: var(--orange);
  color: var(--orange);
}

footer {
  padding: 0 0 72px;
  font-size: .66rem;
  line-height: 2.1;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: center;
}

footer b {
  color: var(--orange);
  font-weight: 500;
}

/* ---- campfire ---- */
.treeline .fire {
  transform-box: fill-box;
}

.fireglow {
  opacity: .7;
  /* Its own box and origin, so pointing at the fire swells the glow from the
     middle of the ember rather than from the corner of the whole treeline. */
  transform-box: fill-box;
  transform-origin: 50% 50%;
  transition: transform .45s cubic-bezier(.2,.7,.3,1);
  animation: emberglowpulse 3.4s ease-in-out infinite alternate;
}

.logs path {
  stroke: #0a1a1e;
  stroke-width: 2.6;
  stroke-linecap: round;
  fill: none;
}

.flames path {
  transform-box: fill-box;
  transform-origin: 50% 100%;
}

.f-outer {
  fill: #f0913f;
}

.f-inner {
  fill: #ffe0a8;
}

.flames {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  animation: flicker 1.7s ease-in-out infinite alternate;
}

.f-inner {
  animation: flicker2 1.1s ease-in-out infinite alternate;
}

.sparks circle {
  fill: #ffc078;
  opacity: 0;
  animation: spark 4.2s linear infinite;
}

.sparks circle:nth-child(2) {
  animation-delay: 1.5s;
}

.sparks circle:nth-child(3) {
  animation-delay: 2.9s;
}

@keyframes flicker {
  0% {
    transform: scale(1.04,.93);
  }

  50% {
    transform: scale(.97,1.05);
  }

  100% {
    transform: scale(1.02,.97);
  }
}

@keyframes flicker2 {
  0% {
    transform: scale(.94,1.04);
    opacity: .85;
  }

  100% {
    transform: scale(1.05,.95);
    opacity: 1;
  }
}

@keyframes emberglowpulse {
  from {
    opacity: .52;
  }

  to {
    opacity: .86;
  }
}

@keyframes spark {
  0% {
    opacity: 0;
    transform: translateY(0);
  }

  12% {
    opacity: .9;
  }

  100% {
    opacity: 0;
    transform: translateY(-26px);
  }
}

@media(max-width:860px) {
  body {
    font-size: 16px;
  }

  section {
    padding: 78px 0;
  }

  .cst {
    width: 15.5vw;
    max-width: 74px;
  }

  .cst .cst-label {
    opacity: .5;
    font-size: .46rem;
    letter-spacing: .14em;
  }

  .cst-book {
    left: 1%;
    top: 12%;
  }

  .cst-flag {
    left: 20.5%;
    top: 5.5%;
  }

  .cst-puzzle {
    left: 40%;
    top: 9%;
  }

  .cst-ring {
    left: 59.5%;
    top: 5%;
  }

  .cst-pot {
    left: 79%;
    top: 11.5%;
  }

  .hero .wrap {
    padding-top: 22vh;
  }

  .ledger-grid {
    grid-template-columns: 1fr 1fr;
  }

  .panel:nth-child(3) {
    border-left: 0;
  }

  .panel:nth-child(n+3) {
    border-top: 1px solid var(--line);
  }

  .city {
    font-size: 12px;
  }

  .timeline {
    flex-direction: column;
    align-items: stretch;
    gap: 14px;
    padding: 18px;
  }

  .playbtn {
    width: 100%;
  }

  .datebox {
    text-align: center;
  }

  .corner {
    width: 22px;
    height: 22px;
  }

  .overlay {
    padding: 0;
  }

  .citybox {
    width: 100%;
    max-height: 100svh;
    height: 100svh;
    grid-template-columns: 1fr;
    /* The map earns a bigger share here than it used to: it is a street map
       now, and a city in 28svh is a postage stamp you cannot read. */
    grid-template-rows: 26svh 34svh 1fr;
    grid-template-areas: "photo" "map" "info";
  }

  .cphoto,
  .cinfo {
    border-right: 0;
  }

  .cmap {
    border-bottom: 1px solid var(--line);
  }

  /* The photo pane is a quarter of a phone screen; the title and the two
     names have to sit on it without eating the picture. */
  .cbar {
    padding: 10px 12px;
  }

  .whobar button {
    padding: 5px 10px;
    font-size: .54rem;
    letter-spacing: .12em;
  }
}

@media(prefers-reduced-motion:reduce) {
  html,
  .reel-track {
    scroll-behavior: auto;
  }

  * {
    transition-duration: .01ms!important;
    animation-duration: .01ms!important;
  }

  .flames,
  .f-inner,
  .fireglow {
    animation: none;
  }

  .sparks circle {
    opacity: 0;
  }
}

/* ---- the campfire, as a button ----
   The trees are drawing only; without this the near treeline, which paints
   after the fire, would take every click meant for it. */
.treeline .far,
.treeline .near {
  pointer-events: none;
}

.hero .treeline .firehit {
  fill: transparent;
  pointer-events: all;
  cursor: pointer;
}

.hero .treeline .fire.lit .fireglow {
  transform: scale(1.75);
}

.hero .treeline .fire.lit .flames {
  animation-duration: .85s;
}

/* Sits a little above the flames, in the constellations' own small caps —
   the same voice as the five names in the sky, because it is the same kind
   of thing: a way further in, written on the scenery. */
.creditsbtn {
  position: absolute;
  left: 50%;
  bottom: clamp(30px,4vw,80px);
  transform: translateX(-50%);
  z-index: 6;
  appearance: none;
  background: none;
  border: 0;
  padding: 8px 16px;
  cursor: pointer;
  font-family: var(--ui);
  font-size: .55rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--bone);
  opacity: .3;
  transition: opacity .4s,color .4s;
  -webkit-tap-highlight-color: transparent;
}

.creditsbtn:hover,
.creditsbtn:focus-visible {
  opacity: 1;
  color: var(--orange-lift);
}

.creditsbtn:focus-visible {
  outline: 1px solid var(--orange);
  outline-offset: 4px;
}

/* ---- the credits panel ---- */
.creditsbox {
  width: min(760px,100%);
  max-height: 86svh;
  overflow-y: auto;
  background: var(--ink-2);
  border: 1px solid var(--line);
  padding: 0 28px 32px;
  -webkit-overflow-scrolling: touch;
}

.crbar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  padding: 22px 0 18px;
  background: var(--ink-2);
  border-bottom: 1px solid var(--line);
}

.crbar h3 {
  margin: 0;
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--jade);
}

.crnote {
  margin: 20px 0 26px;
  font-size: .92rem;
  color: var(--dim);
  line-height: 1.7;
  max-width: 56ch;
}

/* One person per row. Two columns of cards meant the note beside each face
   was a 30-character measure, too narrow to say what anyone actually did;
   a full-width row gives it a real paragraph. The hairline between cards is
   the same divider the ring page's stages use. */
.crgrid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
}

/* Face left, centred against the whole caption rather than sitting on its
   top edge — with a note of any length the two read as one block. */
.crcard {
  margin: 0;
  display: flex;
  gap: 18px;
  align-items: center;
  padding: 28px 0;
  border-top: 1px solid var(--line);
}

.crcard:first-child {
  border-top: 0;
  padding-top: 4px;
}

/* Square in, circle out: any roughly centred photo works, and one that has
   not arrived yet shows initials rather than a broken frame. */
.crface {
  width: 74px;
  height: 74px;
  flex: none;
  border-radius: 50%;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--ink-3);
}

.crface img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.crface.ph {
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(135deg,rgba(47,184,151,.06) 0 10px,transparent 10px 20px);
}

.crface.ph span {
  font-size: .8rem;
  font-weight: 500;
  letter-spacing: .1em;
  color: var(--faint);
}

.crcard figcaption {
  min-width: 0;
}

.crcard b {
  display: block;
  color: var(--bone);
  font-size: .88rem;
  font-weight: 500;
  letter-spacing: .04em;
}

.crrole {
  display: block;
  margin-top: 3px;
  font-size: .55rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--jade);
}

/* capped: a full row inside the 760px box is a wide measure for prose */
.crcard p {
  margin: 10px 0 0;
  max-width: 62ch;
  font-size: .88rem;
  color: var(--dim);
  line-height: 1.7;
}

.crlink {
  display: inline-block;
  margin-top: 10px;
  font-size: .55rem;
  font-weight: 500;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--faint);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
  transition: .2s;
}

.crlink:hover {
  color: var(--orange);
  border-bottom-color: var(--orange);
}

/* ================= SITE CHROME ================= */
.nav {
  justify-content: center;
}

/* A mark and one word. This used to spell out "The long way to Denver", which
   on a phone was a second title arguing with the first one; "Home" beside the
   glyph says what the link does without becoming a sentence. Drawn in the same
   star-and-link language as the rest of the nav, and the label inherits the
   nav's small caps from `.nav a`, so neither needs a rule of its own. */
.nav .navhome {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px;
  border-bottom: 0;
  color: var(--faint);
  transition: color .25s;
}

.nav .navhome:hover {
  color: var(--jade);
}

.nav .navhome svg {
  display: block;
  width: 21px;
  height: 21px;
}

.nav .navhome:focus-visible {
  outline: 1px solid var(--jade);
  outline-offset: -2px;
}

.hero .wrap {
  padding-bottom: 4vh;
}

.pagehead {
  position: relative;
  min-height: 32svh;
  display: flex;
  align-items: flex-end;
  overflow: hidden;
  padding-top: calc(var(--navh) + 8px);
}

.pagehead .sky {
  position: absolute;
  inset: 0;
  z-index: 0;
  background: radial-gradient(120% 90% at 50% 100%, #0d2a2e 0%, #07171d 52%, #040f14 100%);
}

.pagehead .stars {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 1;
  fill: #fff;
  opacity: .85;
}

.pagehead .treeline {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  z-index: 2;
  display: block;
}

.pagehead .far {
  fill: #081b22;
  opacity: .85;
}

.pagehead .wrap {
  z-index: 3;
  padding-bottom: 40px;
  text-align: center;
}

.pagehead h1 {
  font-size: clamp(1.9rem,5.4vw,3.4rem);
  color: var(--bone);
  text-transform: uppercase;
  font-weight: 700;
  letter-spacing: .01em;
  margin-top: 16px;
}

section:first-of-type {
  padding-top: 52px;
}

/* ---- stats row on the title page ---- */
.statsrow {
  display: flex;
  justify-content: center;
  align-items: baseline;
  flex-wrap: nowrap;
  gap: 0;
  margin: 84px auto 0;
  max-width: 840px;
}

.statsrow div {
  display: flex;
  align-items: baseline;
  gap: 9px;
  white-space: nowrap;
  padding: 0 clamp(10px,2.4vw,26px);
  border-left: 1px solid var(--line);
}

.statsrow div:first-child {
  border-left: 0;
}

.statsrow .n {
  font-size: clamp(.92rem,2.4vw,1.3rem);
  font-weight: 300;
  color: var(--jade);
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
}

.statsrow .n em {
  font-style: normal;
  font-size: .58rem;
  color: var(--faint);
  margin-left: 4px;
  letter-spacing: .14em;
  text-transform: uppercase;
}


/* How she travelled, said with a mark instead of a word so the number, its
   unit and its mode still fit on one line at phone widths. */
.statsrow .mico {
  width: clamp(11px,2.6vw,17px);
  height: clamp(11px,2.6vw,17px);
  flex: none;
  align-self: center;
  fill: none;
  stroke: var(--jade);
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: .85;
}

/* ---- prep map (Build page) ---- */
.prep {
  margin-top: 44px;
  border: 1px solid var(--line);
  position: relative;
}

.prep svg.usmap {
  padding: 14px 0 0;
}

.triplist {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 18px 20px;
  border-top: 1px solid var(--line);
}

.triplist button {
  appearance: none;
  background: none;
  border: 1px solid var(--line);
  color: var(--faint);
  padding: 9px 14px;
  cursor: pointer;
  font-family: var(--ui);
  font-weight: 500;
  font-size: .6rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  transition: .2s;
  text-align: left;
}

.triplist button:hover {
  color: var(--bone);
  border-color: var(--jade-dim);
}

.triplist button[aria-pressed="true"] {
  background: var(--orange);
  border-color: var(--orange);
  color: #160702;
}

.triplist button small {
  display: block;
  font-size: .54rem;
  opacity: .7;
  letter-spacing: .1em;
  margin-top: 3px;
}

.prep .leg {
  opacity: .14;
  transition: opacity .35s,stroke .35s;
}

.prep .leg.lit {
  opacity: 1;
}

.prep .dot {
  stroke: var(--jade);
  opacity: .35;
  transition: opacity .35s;
}

.prep .dot.lit {
  opacity: 1;
  stroke: var(--orange);
}

.prep .city {
  opacity: .3;
  transition: opacity .35s;
}

.prep .city.lit {
  opacity: 1;
}

.prepnote {
  padding: 0 20px 18px;
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---- media reel ---- */
.reel {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #050f14;
}

.reel-bg {
  position: absolute;
  inset: -24px;
  background-size: cover;
  background-position: center;
  filter: blur(26px) saturate(.7);
  opacity: .5;
}

/* Every file for the stop, side by side in one scroller. Snapping is what
   makes a drag or a swipe land on a single photo rather than between two;
   the arrows scroll this same track, so there is only one thing to keep
   right. The scrollbar is hidden — the arrows and the counter say there is
   more, and a bar across a photograph does not. */
.reel-track {
  position: absolute;
  inset: 0;
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.reel-track::-webkit-scrollbar {
  display: none;
}

.reel-item {
  position: relative;
  flex: 0 0 100%;
  width: 100%;
  height: 100%;
  scroll-snap-align: center;
  scroll-snap-stop: always;
  display: flex;
  align-items: center;
  justify-content: center;
}

.reel-item img,
.reel-item video {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  display: block;
  position: relative;
}

.reel .ph {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(135deg,rgba(47,184,151,.05) 0 12px,transparent 12px 24px);
}

.reel .ph span {
  font-size: .58rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}

.reel-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  appearance: none;
  background: rgba(5,15,20,.72);
  border: 1px solid var(--line);
  color: var(--bone);
  width: 34px;
  height: 52px;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  transition: .2s;
}

.reel-nav:hover {
  border-color: var(--orange);
  color: var(--orange);
}

.reel-nav.prev {
  left: 0;
  border-left: 0;
}

.reel-nav.next {
  right: 0;
  border-right: 0;
}

.reel-nav[hidden] {
  display: none;
}

.reel-nav[disabled] {
  opacity: .3;
  cursor: default;
}

.reel-nav[disabled]:hover {
  border-color: var(--line);
  color: var(--bone);
}

.reel-count {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 4;
  font-size: .55rem;
  font-weight: 500;
  letter-spacing: .16em;
  color: var(--bone);
  background: rgba(5,15,20,.72);
  padding: 4px 9px;
  border: 1px solid var(--line);
}

.reel .cap {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 3;
  padding: 12px 46px;
  font-size: .62rem;
  font-weight: 500;
  letter-spacing: .12em;
  color: var(--bone);
  text-align: center;
  background: linear-gradient(transparent,rgba(4,14,18,.94));
}

.stopbar {
  display: flex;
  gap: 8px;
  align-items: center;
  margin: 0 0 22px;
}

.stopbar button {
  appearance: none;
  background: none;
  border: 1px solid var(--line);
  color: var(--faint);
  width: 34px;
  height: 34px;
  flex: none;
  cursor: pointer;
  font-size: .85rem;
  transition: .2s;
}

.stopbar button:hover:not(:disabled) {
  border-color: var(--orange);
  color: var(--orange);
}

.stopbar button:disabled {
  opacity: .3;
  cursor: default;
}

/* The count sits between the two arrows, so which way each one goes is said
   by where it is rather than by which way it points. */
.stopbar .of {
  flex: 1;
  text-align: center;
  font-size: .58rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}

.cinfo .why {
  border-bottom: 1px solid var(--line);
  padding-bottom: 20px;
  margin-bottom: 22px;
}

.cinfo h5 {
  margin: 0 0 10px;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--bone);
}

/* ---- long-form pages ---- */
.post {
  max-width: 66ch;
  margin: 0 auto;
}

/* also matched inside a collapsible section, where the paragraphs are no
   longer direct children of .post */
.post > p,
.brkinner > p {
  margin: 0 0 20px;
  color: var(--dim);
}

.post > p.lead,
.brkinner > p.lead {
  color: var(--bone);
  font-size: 1.06rem;
}

.post h3 {
  font-size: clamp(1.15rem,2.4vw,1.5rem);
  margin: 58px 0 16px;
  color: var(--bone);
}

.post h3 .o {
  color: var(--jade);
}

/* ---- section breaks on the long-form pages ----
   A centred .tab chip riding a hairline. It is the same chip used elsewhere
   on the site, so the pages still read as one thing; the rules on either
   side are what actually breaks the column of text up. */
.brk {
  display: flex;
  align-items: center;
  gap: 18px;
  margin: 66px 0 26px;
}

.brk::before,
.brk::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--line);
}

.brk .tab {
  flex: none;
}

/* ---- collapsible sections ----
   The chip is the control for the block under it. The arrow points in while
   the section is shut and turns a quarter down when it opens. Sections are
   authored shut, so nothing flashes open on load; the page carries a
   <noscript> rule that reopens them where the toggle cannot run. */
button.tab {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  appearance: none;
  background: none;
  font-family: var(--ui);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  transition: background .2s, color .2s, border-color .2s;
}

/* Hover is a lift, not the open state. They have to differ: you collapse a
   section with the pointer still on the chip, and if hover looked like open
   the chip would go on reading as open until you moved the mouse away. */
button.tab:hover {
  color: var(--bone);
  border-color: var(--jade-dim);
}

/* open — the same treatment the map's view toggle uses for a pressed button */
button.tab[aria-expanded="true"] {
  background: var(--jade);
  border-color: var(--jade);
  color: #04120e;
}

button.tab[aria-expanded="true"]:hover {
  background: var(--orange-lift);
  border-color: var(--orange-lift);
  color: #160702;
}

button.tab:focus-visible {
  outline: 1px solid var(--orange);
  outline-offset: 3px;
}

.chev {
  width: 8px;
  height: 8px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform .3s cubic-bezier(.4,0,.2,1);
}

button.tab[aria-expanded="true"] .chev {
  transform: rotate(90deg);
}

/* 0fr -> 1fr animates to a height the content decides, with nothing measured
   in JS. The inner element is what clips, and what keeps the paragraph
   margins from collapsing out through the grid. */
.brkbody {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows .4s cubic-bezier(.4,0,.2,1);
}

.brkbody.shut {
  grid-template-rows: 0fr;
}

.brkinner {
  min-height: 0;
  overflow: hidden;
}

/* a shut section leaves only the chip, so it does not need the gap under it */
.brk:has(+ .brkbody.shut) {
  margin-bottom: 0;
}

/* first break after a heading sits closer to it */
.post h3 + .brk {
  margin-top: 26px;
}

.post > h3 {
  text-align: center;
}

/* list items read as paragraphs — same colour, with a little more air between
   them than the line spacing alone gives. The marker stays orange, matching
   the numbering on the ring page's stages. */
.cityflow li::marker {
  color: var(--orange);
}

.post ol,
.post ul {
  margin: 0 0 20px;
  padding-left: 1.5em;
}

.post li {
  color: var(--dim);
  margin-bottom: 18px;
}

.post li:last-child {
  margin-bottom: 0;
}

/* the scheme paragraph is authored as numbered lines; keep the author's
   line breaks instead of collapsing four steps into one block */
.post p.steps {
  white-space: pre-line;
}

.pull {
  border-left: 2px solid var(--orange);
  padding: 2px 0 2px 20px;
  margin: 36px 0;
  color: var(--bone);
  font-size: 1.05rem;
  line-height: 1.6;
}

figure {
  margin: 36px 0;
  border: 1px solid var(--line);
}

figure .ph {
  aspect-ratio: 16/10;
  display: flex;
  align-items: center;
  justify-content: center;
  background: repeating-linear-gradient(135deg,rgba(47,184,151,.05) 0 12px,transparent 12px 24px);
}

figure .ph span {
  font-size: .56rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}

figure img,
figure video {
  display: block;
  width: 100%;
  height: auto;
}

figcaption {
  padding: 11px 14px;
  border-top: 1px solid var(--line);
  font-size: .6rem;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--faint);
}

.figrow {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin: 36px 0;
}

.figrow figure {
  margin: 0;
}

.figrow figure .ph {
  aspect-ratio: 4/5;
}

/* ---- artifacts gallery ----
   Objects, not prose: an auto-filling grid so figures can be added or taken
   out of the page without touching anything here. Captions read as sentences
   rather than the small-caps labels the inline figures use, because these
   are the only text an object gets. */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill,minmax(240px,1fr));
  gap: 20px;
  margin: 44px 0 0;
}

.gallery figure {
  margin: 0;
  display: flex;
  flex-direction: column;
}

.gallery figure .ph {
  aspect-ratio: 4/3;
}

.gallery figcaption {
  flex: 1;
  text-transform: none;
  letter-spacing: .01em;
  font-size: .78rem;
  font-weight: 300;
  line-height: 1.5;
  color: var(--dim);
  padding: 12px 14px 13px;
}

/* ---- numbered stages (the ring) ---- */
.stages {
  max-width: 66ch;
  margin: 44px auto 0;
}

/* Each row is the control for the section under it, so the whole row is the
   button: number, title and summary. The padding lives on the button rather
   than on .stage, which is what makes the entire strip clickable instead of
   just the words in the middle of it. */
.stage {
  border-top: 1px solid var(--line);
}

.stage:last-child {
  border-bottom: 1px solid var(--line);
}

.stagehead,
.faqhead {
  display: grid;
  align-items: start;
  width: 100%;
  appearance: none;
  background: none;
  border: 0;
  text-align: left;
  font-family: var(--ui);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.stagehead {
  grid-template-columns: 3.2rem 1fr 12px;
  gap: 20px;
  padding: 30px 0;
}

.stagehead:focus-visible,
.faqhead:focus-visible {
  outline: 1px solid var(--orange);
  outline-offset: -4px;
}

.stage .no {
  font-size: .64rem;
  font-weight: 500;
  letter-spacing: .2em;
  color: var(--orange);
  padding-top: 6px;
}

.stagetext {
  min-width: 0;
}

.stage .sh {
  display: block;
  margin: 0 0 8px;
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--bone);
  transition: color .2s;
}

.stage .ss {
  display: block;
  color: var(--dim);
  font-size: .93rem;
  line-height: 1.6;
}

/* Hover is a lift, not the open state — the same distinction the chips on the
   other pages make, and for the same reason: you close a row with the pointer
   still on it. */
.stagehead:hover .sh {
  color: var(--jade);
}

.stagehead[aria-expanded="true"] .sh {
  color: var(--jade);
}

.stagehead .chev,
.faqhead .chev {
  margin-top: 9px;
  color: var(--faint);
  transition: transform .3s cubic-bezier(.4,0,.2,1), color .2s;
}

.stagehead:hover .chev,
.stagehead[aria-expanded="true"] .chev,
.faqhead:hover .chev,
.faqhead[aria-expanded="true"] .chev {
  color: var(--jade);
}

.stagehead[aria-expanded="true"] .chev,
.faqhead[aria-expanded="true"] .chev {
  transform: rotate(90deg);
}

/* The opened section lines up under the title, not under the number. Only the
   left pad is set here: a vertical one would still hold the row open by its
   own height while the section is shut. The air underneath comes from the
   last child's margin, which the clip takes away with everything else. */
.stage .brkinner {
  padding-left: calc(3.2rem + 20px);
}

.stage .brkinner > *:last-child {
  margin-bottom: 30px;
}

.stage .brkinner > figure,
.stage .brkinner > .figrow {
  margin-top: 4px;
}

/* ---- FAQ ----
   The same row-as-a-button as the ring page's stages, without the numbering:
   the whole question opens the answer under it. Hairlines between rather than
   boxes around, so a list of seven questions is still a page of text. */
.faq {
  margin-top: 30px;
}

.faqrow {
  border-top: 1px solid var(--line);
}

.faqrow:last-child {
  border-bottom: 1px solid var(--line);
}

.faqhead {
  grid-template-columns: 1fr 12px;
  gap: 18px;
  padding: 20px 0;
}

/* a shorter line than a stage title, so the arrow sits a little higher */
.faqhead .chev {
  margin-top: 7px;
}

.faq .q {
  display: block;
  font-size: .95rem;
  font-weight: 500;
  letter-spacing: .02em;
  color: var(--bone);
  line-height: 1.5;
  transition: color .2s;
}

.faqhead:hover .q,
.faqhead[aria-expanded="true"] .q {
  color: var(--jade);
}

/* The answer is indented off the question by a hair, the way an answer is. */
.faq .brkinner {
  padding-left: 14px;
  border-left: 1px solid var(--line);
  margin-left: 1px;
}

.faq .brkinner > p {
  margin: 0;
  padding-top: 2px;
}

.faq .brkinner > *:last-child {
  margin-bottom: 22px;
}

@media(max-width:860px) {
  /* The home mark stays now that it is a mark rather than a sentence. The bar
     carries a left pad the width of it, so the five links divide what is left
     instead of the first one sliding underneath. */
  .nav .navhome {
    left: 3px;
    padding: 5px;
  }

  .nav .navhome svg {
    display: block;
    width: 18px;
    height: 18px;
  }

  /* the glyph alone here: navhome is absolutely positioned over the row, and
     the word would land on top of the first link */
  .nav .navhome span {
    display: none;
  }

  /* labels only — the glyphs are unreadable at this size and made it fussy.
     min-width:0 is what keeps five links inside the bar: without it a flex
     item will not shrink under its own text, so the row overflowed the
     screen and the labels ran into each other. */
  :root {
    --navh: 44px;
  }

  .nav {
    gap: 0;
    padding: 0 0 0 30px;
  }

  .nav svg {
    display: none;
  }

  .nav a {
    flex: 1 1 0;
    min-width: 0;
    justify-content: center;
    flex-direction: row;
    gap: 0;
    padding: 14px 1px 12px;
    font-size: clamp(.4rem,2.05vw,.55rem);
    letter-spacing: .06em;
    white-space: nowrap;
  }

  .pagehead {
    min-height: 30svh;
    padding-top: var(--navh);
  }

  .pagehead .wrap {
    padding-bottom: 34px;
  }

  .pagehead h1 {
    margin-top: 14px;
  }

  .figrow {
    grid-template-columns: 1fr;
  }

  .gallery {
    grid-template-columns: repeat(auto-fill,minmax(150px,1fr));
    gap: 14px;
  }

  .creditsbox {
    padding: 0 18px 26px;
    max-height: 92svh;
  }

  .crgrid {
    grid-template-columns: 1fr;
    gap: 22px;
  }

  .crface {
    width: 60px;
    height: 60px;
  }

  .gallery figcaption {
    font-size: .72rem;
    padding: 10px 11px 11px;
  }

  .stagehead {
    grid-template-columns: 1fr 12px;
    gap: 6px 14px;
    padding: 24px 0;
  }

  .stage .no {
    grid-column: 1 / -1;
    padding-top: 0;
  }

  .stagehead .chev {
    margin-top: 6px;
  }

  /* No number column to line up under on a phone. */
  .stage .brkinner {
    padding-left: 0;
  }

  .stage .brkinner > *:last-child {
    margin-bottom: 24px;
  }

  .statsrow {
    margin-top: 46px;
  }

  .statsrow div {
    gap: 4px;
    padding: 0 8px;
  }

  .statsrow .n {
    font-size: clamp(.62rem,3vw,.84rem);
  }

  .statsrow .n em {
    font-size: .46rem;
    margin-left: 3px;
  }


  .hero .wrap {
    padding-top: 14vh;
    padding-bottom: 20vh;
    padding-left: 16px;
    padding-right: 16px;
  }

  .triplist button {
    flex: 1 1 46%;
  }
}

/* ---- embedded puzzle pages ---- */
.embed {
  width: 100%;
  height: 340px;
  border: 1px solid var(--line);
  background: #040f13;
  display: block;
}

.widget .wbtn {
  display: block;
  text-align: center;
  text-decoration: none;
}

@media(max-width:860px) {
  .embed {
    height: 260px;
  }
}
