/* Where the Music Travelled — HUD styling.
 *
 * Palette and type follow apps/web/src/app/globals.css: the warm near-black
 * ground, cream foreground and amber accent are the site's own tokens. The one
 * addition is `--void`, a colder blue-black for the space behind the globe, so
 * the planet reads as somewhere out there and the chrome reads as glass in
 * front of it.
 *
 * Deliberately single-theme: the subject is a night sky, and there is no light
 * mode of a night sky. Every colour is painted explicitly so the page holds on
 * whatever ground the host paints behind it.
 */

/* Fonts are self-hosted rather than linked from Google: the site's CSP allows
   `font-src 'self' data:` only, so a linked stylesheet would be blocked at
   /globe and the page would silently fall back. Latin subsets, from Google
   Fonts (Inter is SIL Open Font License 1.1). */

@font-face {
  font-family: "Inter var";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter-variable.woff2") format("woff2");
}

:root {
  --ink: #0d0b07;
  --void: #05070d;
  --cream: #fffaf0;
  --muted: rgba(255, 250, 240, 0.66);
  --faint: rgba(255, 250, 240, 0.4);
  --line: rgba(255, 250, 240, 0.14);
  --glass: rgba(13, 11, 7, 0.62);
  --amber: #ffb340;
  --amber-deep: #f7a51d;
  --jade: #4fd07e;

  /* One face, the site's. The globe used to run on Instrument Serif for its
     titles and a system monospace for every label — neither of which appears
     anywhere else on jamaicamusicatlas.com, so arriving here from /paths read
     as arriving at a different site. Both are gone.

     What is left is Inter, set the way the site sets it: titles heavy and
     tightly tracked like `.hero h1`, labels heavy and widely tracked like
     `.micro`. Sizes stay generous — this is a full-screen installation, not a
     page — but they come down from where the serif had them, because Inter at
     these weights sets a good deal wider.

     Three names for one stack, kept apart because the roles are: a title, body
     copy and a label want different weights and tracking even when they share
     a face, and naming them separately is what makes those rules readable. */
  --display: "Inter var", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --sans: "Inter var", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --label: "Inter var", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;

  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --pad: clamp(1rem, 2.4vw, 2.25rem);
  color-scheme: dark;
}

* { box-sizing: border-box; }

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

body {
  background: var(--void);
  overscroll-behavior: none;
  touch-action: manipulation;
  color: var(--cream);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

#stage {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* The globe has its own pinch-zoom, so the browser must not also page-zoom:
     on iOS that shifted the whole HUD off the left edge. */
  touch-action: none;
}

/* A light hand only. This used to take the corners down by 72%, which dimmed
   most of the globe on a phone where it fills the frame; the HUD panels carry
   their own glass background, so they do not need the whole page darkened. */
.vignette {
  position: fixed;
  inset: 0;
  pointer-events: none;
  background:
    radial-gradient(125% 95% at 50% 45%, transparent 62%, rgba(5, 7, 13, 0.34) 100%),
    linear-gradient(to top, rgba(5, 7, 13, 0.42), transparent 26%),
    linear-gradient(to bottom, rgba(5, 7, 13, 0.34), transparent 22%);
}

.tabular { font-variant-numeric: tabular-nums; }

.eyebrow {
  margin: 0;
  font-family: var(--label);
  font-size: 0.66rem;
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber);
}

/* Anything drawn straight onto the globe carries its own shadow, so it holds
   over bright ocean and desert as well as over night. */
.hud__identity,
.hud__itinerary,
.hud__timeline {
  text-shadow: 0 1px 12px rgba(5, 7, 13, 0.95), 0 0 4px rgba(5, 7, 13, 0.85);
}

/* ---------------------------------------------------------------- *
 * Site strip — the atlas's own bar, above everything
 * ---------------------------------------------------------------- */

.site-strip {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  /* Clears a notch without eating the whole bar on a phone. */
  padding: max(0.5rem, env(safe-area-inset-top)) clamp(0.85rem, 2.4vw, 1.5rem) 0.5rem;
  background: linear-gradient(180deg, rgba(5, 7, 13, 0.92), rgba(5, 7, 13, 0));
  pointer-events: none;
}

.site-strip a,
.site-strip button {
  pointer-events: auto;
}

.site-strip a {
  text-decoration: none;
}

.site-strip__brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--cream);
  font-family: var(--display);
  font-size: 1rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.site-strip__mark {
  width: 15px;
  height: 15px;
  border: 2px solid var(--amber);
  border-radius: 50%;
  box-shadow: inset 0 0 0 3px rgba(13, 11, 7, 0.9), inset 0 0 0 5px var(--amber);
}

.site-strip__back {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.42rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: blur(14px);
  color: var(--muted);
  /* The same small-caps pill the site puts in this corner on every other
     page — see .back-link in apps/web/src/app/globals.css. */
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 200ms var(--ease), border-color 200ms var(--ease);
}

.site-strip__back:hover,
.site-strip__back:focus-visible {
  color: var(--cream);
  border-color: rgba(255, 250, 240, 0.3);
}

/* The explore toggle used to sit in its own column over the globe, in a size
   scaled for standing alone there. It lives in the header now, between the
   wordmark and Exit, so it takes .site-strip__back's own scale — same pill,
   same size as its neighbours — rather than arriving oversized next to them.
   The amber "pressed" state (.ghost-button[aria-pressed="true"]) still
   applies on top of this, unchanged. */
.site-strip .ghost-button {
  padding: 0.42rem 0.85rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Very narrow: the wordmark shortens to its mark rather than wrapping, which
   is what makes room for the explore toggle to keep its full label here
   instead of fighting the brand text for space. */
@media (max-width: 460px) {
  .site-strip__brand {
    font-size: 0;
    gap: 0;
  }
  .site-strip__mark {
    width: 18px;
    height: 18px;
  }
}

/* ---------------------------------------------------------------- *
 * Overture
 * ---------------------------------------------------------------- */

.overture {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* `safe` keeps the top reachable once the shelves make the card taller
     than a laptop viewport; the overflow picks up the rest. */
  justify-content: safe center;
  gap: 0.9rem;
  /* Clears the site strip; the strip itself is ~52px including its safe-area
     padding, and the overture scrolls when the shelves outgrow the viewport. */
  padding: calc(var(--pad) + 44px) var(--pad) var(--pad);
  overflow-y: auto;
  text-align: center;
  background: radial-gradient(120% 80% at 50% 50%, rgba(13, 11, 7, 0.55), rgba(5, 7, 13, 0.92) 70%);
  transition: opacity 900ms var(--ease), visibility 900ms;
}

.overture[hidden] {
  display: flex;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.overture__eyebrow {
  margin: 0;
  font-family: var(--label);
  font-size: 0.7rem;
  font-weight: 900;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--amber);
}

.overture__title {
  margin: 0;
  font-family: var(--display);
  /* `.hero h1` on the site is 950 at -0.09em; this is the same recipe eased off
     for one centred line rather than three ragged ones, and the size comes down
     because Inter at this weight sets far wider than the serif it replaces. */
  font-weight: 900;
  font-size: clamp(2.1rem, 5.6vw, 4rem);
  line-height: 0.95;
  letter-spacing: -0.045em;
  text-wrap: balance;
}

.overture__dek {
  margin: 0;
  max-width: 46ch;
  color: var(--muted);
  text-wrap: pretty;
}

.overture__stats {
  margin: 0.4rem 0 0;
  font-family: var(--label);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
  color: var(--faint);
}

.begin {
  margin-top: 1rem;
  padding: 0.85rem 2.6rem;
  border: 1px solid var(--amber);
  border-radius: 999px;
  background: transparent;
  color: var(--amber);
  font: inherit;
  font-weight: 500;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 240ms var(--ease), color 240ms var(--ease), transform 240ms var(--ease);
}

.begin:hover:not(:disabled),
.begin:focus-visible:not(:disabled) {
  background: var(--amber);
  color: var(--ink);
  transform: translateY(-1px);
}

.begin:disabled {
  opacity: 0.35;
  cursor: progress;
}

/* --- The shelves: the collection, the way the story goes ---------- */

.shelves {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  width: min(1060px, 100%);
  margin-top: 1.3rem;
  text-align: left;
}

.shelf__label {
  margin: 0 0 0.55rem;
  font-family: var(--label);
  font-weight: 800;
  font-size: 0.68rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--faint);
}

.shelf__cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(205px, 1fr));
  gap: 0.7rem;
}

.walk-card {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.75rem 0.8rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 14px;
  background: var(--glass);
  backdrop-filter: blur(14px);
  color: var(--cream);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 200ms var(--ease), transform 200ms var(--ease);
}

.walk-card:hover:not(:disabled),
.walk-card:focus-visible:not(:disabled) {
  border-color: rgba(255, 179, 64, 0.55);
  transform: translateY(-2px);
}

.walk-card:disabled { opacity: 0.45; cursor: progress; }

.walk-card svg {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
  background: rgba(5, 7, 13, 0.6);
}

/* Below the single-column breakpoint the thumbnail has nothing beside it to
   compare against, so it is pure scroll height — a phone stacks eleven of
   these, each nearly as tall as its own card just for a scatter of lines. From
   480px up, where cards sit next to each other, the same shape is what lets a
   reader pick "crosses an ocean" from "stays in Kingston" before reading a
   word, at no extra height. So hide it only below that width, the same cut
   .walk-card__title's two-line reserve already uses. Placed after the base
   rule above: both match .walk-card svg at equal specificity, so source order
   is what lets this one win at narrow widths. */
@media (max-width: 479px) {
  .walk-card svg { display: none; }
}

.walk-card__title {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.015em;
  line-height: 1.2;
  text-wrap: balance;
}

/* Cards sit in a row from about here up, and Inter sets wider than the serif it
   replaced, so more of these titles now run to two lines. Reserve both, or a
   one-line title walks its meta out of step with the card beside it. Below this
   the shelf is a single column, where there is nothing to line up against and
   the reserve would only be dead space — the same rule the site follows for
   `.result-card strong`. */
@media (min-width: 480px) {
  .walk-card__title {
    min-height: calc(1.2em * 2);
  }
}

.walk-card__meta {
  font-family: var(--label);
  font-weight: 600;
  font-size: 0.63rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--faint);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- *
 * HUD frame
 * ---------------------------------------------------------------- */

.hud {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto 1fr auto auto;
  grid-template-areas:
    "identity  readout"
    "narration itinerary"
    "timeline  timeline"
    "transport transport";
  gap: var(--pad);
  /* The identity block and the readout start below the site strip rather than
     behind it; everything else follows from the grid. */
  padding: calc(var(--pad) + 44px) var(--pad) var(--pad);
  pointer-events: none;
  opacity: 0;
  transition: opacity 700ms var(--ease);
}

.hud[hidden] { display: none; }
.hud.is-live { opacity: 1; }

.hud button,
.hud select,
.hud a { pointer-events: auto; }

:where(.hud) :focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------------------------------------------------------------- *
 * Identity + readout
 * ---------------------------------------------------------------- */

.hud__identity {
  grid-area: identity;
  max-width: 34ch;
}

.journey-title {
  margin: 0.3rem 0 0;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(1.6rem, 2.7vw, 2.35rem);
  line-height: 1.02;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

.journey-era {
  margin: 0.35rem 0 0;
  font-family: var(--label);
  font-weight: 700;
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.12em;
  color: var(--muted);
}

.hud__readout {
  grid-area: readout;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.75rem;
}

.ghost-button {
  white-space: nowrap;
  padding: 0.5rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: blur(10px);
  color: var(--muted);
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
  transition: color 200ms var(--ease), border-color 200ms var(--ease);
}

.ghost-button:hover { color: var(--cream); border-color: rgba(255, 250, 240, 0.3); }
.ghost-button[aria-pressed="true"] { color: var(--amber); border-color: var(--amber); }

.readout {
  display: flex;
  gap: 1.1rem;
  margin: 0;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--glass);
  backdrop-filter: blur(10px);
}

.readout div { display: flex; flex-direction: column; align-items: flex-end; gap: 1px; }

.readout dt {
  font-family: var(--label);
  font-weight: 800;
  font-size: 0.58rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--faint);
}

.readout dd {
  margin: 0;
  font-family: var(--label);
  font-weight: 600;
  font-size: 0.82rem;
  /* Was monospace, where a changing number could not shift the ones beside it.
     Inter has to be asked. */
  font-variant-numeric: tabular-nums;
  color: var(--cream);
}

/* ---------------------------------------------------------------- *
 * Itinerary rail
 * ---------------------------------------------------------------- */

.hud__itinerary {
  grid-area: itinerary;
  align-self: end;
  justify-self: end;
  max-height: min(46vh, 30rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
  mask-image: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
}

.hud__itinerary ol {
  margin: 0;
  padding: 0.5rem 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: right;
}

.stop-button {
  pointer-events: auto;
  width: 100%;
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 0.28rem 0.1rem 0.28rem 0.7rem;
  border: 0;
  border-right: 2px solid transparent;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 0.83rem;
  text-align: right;
  cursor: pointer;
  transition: color 200ms var(--ease), border-color 200ms var(--ease);
}

.stop-button:hover { color: var(--cream); }
.stop-button .idx { font-family: var(--label); font-size: 0.62rem; letter-spacing: 0.08em; opacity: 0.7; }
.stop-button .cc { font-family: var(--label); font-size: 0.62rem; letter-spacing: 0.1em; opacity: 0.55; }

.stop-button.is-done { color: var(--muted); border-right-color: rgba(79, 208, 126, 0.5); }
.stop-button.is-current {
  color: var(--cream);
  border-right-color: var(--amber);
}
.stop-button.is-current .name { color: var(--amber); }

/* ---------------------------------------------------------------- *
 * Narration
 * ---------------------------------------------------------------- */

.hud__narration {
  grid-area: narration;
  align-self: end;
  max-width: 62ch;
  padding: 1rem 1.2rem 1.15rem;
  border: 1px solid var(--line);
  border-left: 2px solid var(--amber);
  border-radius: 4px 14px 14px 4px;
  background: var(--glass);
  backdrop-filter: blur(14px);
  transition: opacity 420ms var(--ease), transform 420ms var(--ease);
}

.hud__narration.is-swapping {
  opacity: 0;
  transform: translateY(8px);
}

/* Mid-leg the card is only its destination line, so the arc being drawn and the
   pin it lands on are not hidden behind text that cannot be read yet. */
.hud__narration.is-flying {
  padding-top: 0.7rem;
  padding-bottom: 0.7rem;
  max-width: 46ch;
}

.hud__narration.is-flying .beat-heading,
.hud__narration.is-flying .beat-body,
.hud__narration.is-flying .beat-entity,
.hud__narration.is-flying .beat-link,
.hud__narration.is-flying .beat-placing {
  display: none;
}

.beat-heading {
  margin: 0.3rem 0 0.45rem;
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -0.025em;
  font-size: clamp(1.25rem, 2.1vw, 1.75rem);
  line-height: 1.12;
  text-wrap: balance;
}

.beat-body {
  margin: 0;
  color: var(--muted);
  font-size: clamp(0.9rem, 1.05vw, 1rem);
  line-height: 1.55;
  text-wrap: pretty;
  /* Four lines, whichever mode is on. Enough to say what this pin is doing in
     the walk, short enough to read inside the 9.5s a highlight holds, and it
     keeps the card one size instead of one size per step — a card that grows to
     the longest narration in the deck is a card that jumps every time the camera
     lands. The whole narration is a tap away on the written walk. */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
}

.beat-entity {
  margin: 0.7rem 0 0;
  padding-top: 0.55rem;
  border-top: 1px solid var(--line);
  font-family: var(--label);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

.beat-entity strong { color: var(--jade); font-weight: 500; }

.beat-link {
  margin: 0.55rem 0 0;
  font-size: 0.8rem;
}

.beat-link a {
  color: var(--amber);
  text-decoration: none;
  border-bottom: 1px solid rgba(255, 179, 64, 0.35);
  transition: border-color 200ms var(--ease);
}

.beat-link a:hover { border-bottom-color: var(--amber); }

/* Shown only where the stop's coordinates were derived rather than recorded, so
   an inferred pin is never mistaken for one the research placed. */
.beat-placing {
  margin: 0.5rem 0 0;
  font-size: 0.72rem;
  line-height: 1.4;
  color: var(--faint);
  font-style: italic;
}

/* ---------------------------------------------------------------- *
 * Transport
 * ---------------------------------------------------------------- */

.hud__transport {
  grid-area: transport;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}

.transport {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Two labelled groups ride in this pill now; on a narrow frame they wrap
     onto a second row rather than pushing out through the rounded edge. */
  flex-wrap: wrap;
  gap: 0.4rem;
  max-width: 100%;
  padding: 0.35rem;
  border: 1px solid var(--line);
  border-radius: 22px;
  background: var(--glass);
  backdrop-filter: blur(14px);
}

.icon-button {
  display: grid;
  place-items: center;
  /* Icon-only today, so nothing shows — but it was the one control left on the
     UA's own font, and the moment anyone puts a character in it that would be
     Arial against the page's Inter. */
  font: inherit;
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
  transition: background 200ms var(--ease), color 200ms var(--ease);
}

.icon-button:hover { background: rgba(255, 250, 240, 0.09); color: var(--cream); }

.icon-button svg {
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.icon-button--primary { background: var(--amber); color: var(--ink); }
.icon-button--primary:hover { background: var(--cream); color: var(--ink); }
.icon-button--primary svg { stroke-width: 2; }
.icon-button--primary .i-play { display: none; }
.icon-button--primary.is-paused .i-play { display: block; }
.icon-button--primary.is-paused .i-pause { display: none; }
/* The play triangle reads as an outline at this weight; fill it. */
.icon-button--primary .i-play path { fill: currentColor; }

.speed,
.mode {
  display: flex;
  gap: 1px;
  margin-left: 0.35rem;
  padding-left: 0.5rem;
  border-left: 1px solid var(--line);
}

.mode button,
.speed button {
  padding: 0.32rem 0.55rem;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--faint);
  font-family: var(--label);
  font-size: 0.7rem;
  line-height: 1.4;
  white-space: nowrap;
  cursor: pointer;
  transition: color 200ms var(--ease), background 200ms var(--ease);
}

.mode button:hover,
.speed button:hover { color: var(--cream); }
.mode button.is-on,
.speed button.is-on { background: rgba(255, 179, 64, 0.16); color: var(--amber); }

.walks {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  /* On a phone this row shares the width with nothing else, so let the select
     take what is left rather than squeezing the button onto two lines. */
  flex: 1 1 auto;
  min-width: 0;
}

.walks select {
  flex: 1 1 auto;
  min-width: 0;
}

.walks select {
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--glass);
  backdrop-filter: blur(14px);
  color: var(--cream);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  max-width: min(46vw, 22rem);
}

.walks select option { background: var(--ink); color: var(--cream); }

/* ---------------------------------------------------------------- *
 * Timeline
 * ---------------------------------------------------------------- */

.hud__timeline {
  grid-area: timeline;
  display: flex;
  align-items: center;
  gap: 0.9rem;
  padding: 0 0.2rem;
}

.tl-era {
  flex: none;
  font-family: var(--label);
  font-size: 0.64rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.tl-track {
  position: relative;
  flex: 1 1 auto;
  height: 2px;
  border-radius: 2px;
  background: rgba(255, 250, 240, 0.12);
}

.tl-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  border-radius: 2px;
  background: linear-gradient(90deg, rgba(79, 208, 126, 0.85), var(--amber));
  transition: width 200ms linear;
}

.tl-head {
  position: absolute;
  top: 50%;
  left: 0;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 0 3px rgba(255, 179, 64, 0.22), 0 0 14px rgba(255, 179, 64, 0.75);
  transition: left 200ms linear;
}

.tl-ticks {
  position: absolute;
  inset: 0;
}

.tl-tick {
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
  padding: 10px 6px;
  border: 0;
  background: none;
  cursor: pointer;
  pointer-events: auto;
}

.tl-dot {
  display: block;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255, 250, 240, 0.35);
  transition: background 240ms var(--ease), transform 240ms var(--ease);
}

.tl-tick:hover .tl-dot { background: var(--cream); transform: scale(1.4); }
.tl-tick.is-done .tl-dot { background: var(--jade); }
.tl-tick.is-current .tl-dot { background: var(--amber); transform: scale(1.5); }

/* Stop names ride under the track, and surface on hover so a dense walk stays
   readable rather than turning into a wall of overlapping labels. */
.tl-name {
  position: absolute;
  top: calc(50% + 10px);
  left: 50%;
  transform: translateX(-50%);
  max-width: 12ch;
  overflow: hidden;
  font-size: 0.62rem;
  line-height: 1.2;
  white-space: nowrap;
  text-overflow: ellipsis;
  color: var(--faint);
  opacity: 0;
  transition: opacity 220ms var(--ease);
  pointer-events: none;
}

.tl-tick:hover .tl-name,
.tl-tick:focus-visible .tl-name {
  opacity: 1;
  color: var(--cream);
  max-width: 22ch;
  z-index: 2;
}

.tl-tick.is-current .tl-name { opacity: 1; color: var(--amber); }

/* Attribution for the close-up tiles, required whenever they are visible. */
.map-credit {
  position: fixed;
  right: 0.5rem;
  bottom: 0.35rem;
  z-index: 30;
  margin: 0;
  padding: 0.15rem 0.45rem;
  border-radius: 5px;
  background: rgba(13, 11, 7, 0.6);
  font-family: var(--label);
  font-size: 0.56rem;
  letter-spacing: 0.06em;
  color: var(--muted);
  pointer-events: none;
  opacity: 0;
  transition: opacity 400ms var(--ease);
}

.map-credit.is-visible { opacity: 1; }

/* ---------------------------------------------------------------- *
 * Floating map labels
 * ---------------------------------------------------------------- */

#labels {
  position: fixed;
  inset: 0;
  z-index: 15;
  pointer-events: none;
  overflow: hidden;
}

.pin-label {
  position: absolute;
  transform: translate(14px, -50%);
  white-space: nowrap;
  font-size: 0.78rem;
  line-height: 1.25;
  color: var(--cream);
  text-shadow: 0 1px 10px rgba(5, 7, 13, 0.95), 0 0 3px rgba(5, 7, 13, 0.9);
  opacity: 0;
  transition: opacity 320ms var(--ease);
}

.pin-label.is-visible { opacity: 1; }

.pin-label::before {
  content: "";
  position: absolute;
  left: -10px;
  top: 50%;
  width: 7px;
  height: 1px;
  background: var(--amber);
  opacity: 0.75;
}

.pin-label.is-past { color: var(--muted); font-size: 0.72rem; }
.pin-label.is-past::before { background: var(--jade); opacity: 0.5; }

.pin-label b { font-weight: 500; }

/* Follows the pointer over the archive's pins while exploring. */
.place-tip {
  position: absolute;
  transform: translate(16px, -50%);
  padding: 0.42rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(13, 11, 7, 0.88);
  backdrop-filter: blur(8px);
  white-space: nowrap;
  font-size: 0.78rem;
  line-height: 1.3;
  color: var(--cream);
  opacity: 0;
  transition: opacity 140ms var(--ease);
}

.place-tip.is-visible { opacity: 1; }
.place-tip b { display: block; font-weight: 500; }

.place-tip i {
  display: block;
  font-family: var(--label);
  font-style: normal;
  font-size: 0.58rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--faint);
}

.pin-label i {
  display: block;
  font-family: var(--label);
  font-style: normal;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--faint);
}

/* ---------------------------------------------------------------- *
 * Narrow screens: the rail and readout give way to the story
 * ---------------------------------------------------------------- */

@media (max-width: 880px) {
  .hud {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto 1fr auto auto;
    grid-template-areas:
      "identity"
      "readout"
      "narration"
      "timeline"
      "transport";
    gap: 0.7rem;
  }

  /* Era captions eat the track on a phone; the ticks carry the sequence. */
  .tl-era { display: none; }
  .tl-name { display: none; }

  /* Two more words than a phone has room for. The transport row has to hold the
     three transport buttons and the speed control before it holds anything
     else, and "Highlights / Full walk" pushed that row onto two lines over a
     globe that wants the screen. The full walk is the default now, which is the
     setting worth having; the choice stays on a wider screen. */
  .mode { display: none; }

  /* The lat/lng panel and the itinerary list don't earn their space on a
     phone. The explore toggle used to live here too, in a row layout kept
     just to hold it — it lives in the site header now, so this can go quiet
     along with the rest of it. */
  .hud__readout,
  .hud__itinerary { display: none; }

  .hud__narration { max-height: 38vh; overflow-y: auto; }
  .hud__transport { justify-content: center; }
  .walks select { max-width: 78vw; }
}

@media (max-width: 560px) {
  .journey-title { font-size: 1.55rem; }
  .beat-heading { font-size: 1.15rem; }
  .beat-body { font-size: 0.86rem; }
  .mode button,
  .speed button { padding: 0.28rem 0.4rem; }
}

/* Long narration on a short screen must not push the transport off-screen. */
@media (max-height: 620px) {
  .hud__narration { max-height: 34vh; overflow-y: auto; }
  .journey-title { font-size: 1.5rem; }
}

@media (prefers-reduced-motion: reduce) {
  .overture,
  .hud,
  .hud__narration,
  .pin-label,
  .hud__progress span { transition-duration: 1ms; }
}
