/* Web fonts, self-hosted (copied from Google Fonts: Cinzel v26, Inter v20,
   both variable, so each subset is one file). Serving them from our own
   origin drops the render-blocking fonts.googleapis.com stylesheet and the
   extra connection to fonts.gstatic.com; index.html preloads the two latin
   files so they are usually ready before first paint. */
/* latin-ext */
@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/cinzel-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/cinzel-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../assets/fonts/cinzel-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Cinzel';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../assets/fonts/cinzel-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-greek-ext.woff2) format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-greek.woff2) format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../assets/fonts/inter-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-greek-ext.woff2) format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-greek.woff2) format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../assets/fonts/inter-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-cyrillic-ext.woff2) format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-cyrillic.woff2) format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-greek-ext.woff2) format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-greek.woff2) format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-vietnamese.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(../assets/fonts/inter-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Fallbacks sized to Inter's and Cinzel's metrics, so text laid out before
   the web fonts arrive takes the same space and nothing below it (the Your
   Journey panel) jumps when they swap in. Values follow the Next.js /
   Capsize formula: size-adjust from average glyph width, then ascent,
   descent and line gap scaled by it. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("ArialMT"), local("Liberation Sans");
  size-adjust: 107.12%;
  ascent-override: 90.44%;
  descent-override: 22.52%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Cinzel Fallback";
  src: local("Georgia");
  size-adjust: 124.72%;
  ascent-override: 78.26%;
  descent-override: 29.83%;
  line-gap-override: 0%;
}

:root {
  --bg: #04110d;
  --bg-2: #071a14;
  --mako: #5cf7b1;
  --mako-2: #9dffd6;
  --mako-dim: #1f7a56;
  --teal: #2fd6c8;
  --gold: #f2c766;
  --violet: #b48cff;
  --ash: #6c8a7e;
  --text: #e6f4ee;
  --muted: #9ab8ad;
  --card: rgba(6, 26, 20, 0.88);
  --card-border: rgba(92, 247, 177, 0.18);
  --serif: "Cinzel", "Cinzel Fallback", Georgia, serif;
  --sans: "Inter", "Inter Fallback", system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
/* Phones: no pinch-zoom and no double-tap zoom, but one-finger panning
   (page scrolling) is untouched. pan-x pan-y rather than `manipulation`
   because `manipulation` still allows pinch-zoom. Backed up on iOS Safari,
   which ignores the viewport meta and only partly honours this, by the
   multi-touch guard in app.js. */
html, body { touch-action: pan-x pan-y; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  line-height: 1.6;
  overflow-x: hidden;
}
a { color: var(--mako); text-decoration: none; }
button { font-family: inherit; cursor: pointer; }

#lifestream {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}
.vignette {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(ellipse at 50% 0%, rgba(92, 247, 177, 0.06), transparent 60%),
    linear-gradient(to bottom, rgba(4, 17, 13, 0.2), rgba(4, 17, 13, 0.55));
}

main, header, footer { position: relative; z-index: 2; }

/* ---------- hero ---------- */
.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  /* Fixed spacing rather than a viewport-based height, so tall monitors don't
     open up gaps above the title or below the progress box. */
  padding: 3.5rem 1.25rem 1rem;
  position: relative;
}
.eyebrow {
  font-size: 0.75rem;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  color: var(--mako);
  margin: 0 0 1rem;
  opacity: 0.85;
}
.hero h1 {
  font-family: var(--serif);
  font-weight: 700;
  font-size: clamp(2.6rem, 8vw, 6rem);
  line-height: 1;
  margin: 0;
  letter-spacing: 0.04em;
  color: var(--text);
}
/* "Journey to" sits a step smaller than the gradient "Revelation" line. */
.hero h1 small { font-size: 0.68em; letter-spacing: 0.06em; }
.hero h1 span {
  display: inline-block;
  background: linear-gradient(90deg, var(--mako-2), var(--mako), var(--teal));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 18px rgba(92, 247, 177, 0.45));
}
.lede {
  max-width: 57rem;
  color: var(--muted);
  font-size: 1.05rem;
  margin: 1.6rem auto 2.4rem;
}
.lede strong { color: var(--text); font-weight: 600; }
/* Tighter gap between consecutive hero paragraphs */
.lede:has(+ .lede) { margin-bottom: 0; }
.lede + .lede { margin-top: 0.9rem; }

.countdown {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: 2.2rem;
}
.cd-units {
  display: flex;
  gap: 0.8rem;
  justify-content: center;
  flex-wrap: wrap;
}
.cd-date {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
}
.cd-date .cd-value { font-size: 2.3rem; letter-spacing: 0.04em; }
.cd-now .cd-value { color: var(--gold); text-shadow: 0 0 20px rgba(242, 199, 102, 0.5); }
.cd-unit {
  border: 1px solid var(--card-border);
  background: var(--card);
  border-radius: 12px;
  padding: 0.9rem 1.6rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  min-width: 5.5rem;
}
.cd-label, .cd-sub {
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--muted);
}
.cd-value {
  font-family: var(--serif);
  font-size: 2rem;
  color: var(--mako);
  text-shadow: 0 0 20px rgba(92, 247, 177, 0.5);
  line-height: 1.2;
}

.progress {
  width: min(42rem, 100%);
  border: 1px solid var(--card-border);
  background: var(--card);
  border-radius: 14px;
  padding: 1rem 1.25rem;
}
.progress-head {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
}
.progress-head span:last-child { color: var(--mako); font-weight: 600; }
.progress-bar {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: rgba(92, 247, 177, 0.1);
  margin: 0.6rem 0;
  overflow: hidden;
}
.progress-fill {
  position: absolute;
  inset: 0 auto 0 0;
  z-index: 2;
  height: 100%;
  width: 0%;
  border-radius: inherit;
  /* experienced: gold, to match the Mark experienced button */
  background: linear-gradient(90deg, rgba(242, 199, 102, 0.6), var(--gold), #fff1c2);
  box-shadow: 0 0 14px rgba(242, 199, 102, 0.6);
  transition: width 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
}
/* in progress: the same gold as experienced, at 30% opacity. It sits
   behind the full-strength gold fill and starts from the left edge, so the
   gold keeps its rounded end and the paler gold shows through the gap the
   rounding leaves. */
.progress-fill.wip {
  z-index: 1;
  opacity: 0.3;
}
/* Hours sit directly under the bar (they are what the bar measures); the
   item counts follow below a hairline. */
/* Flex rather than grid so a partly filled last row (when the stats wrap)
   stays centred under the rows above. */
.progress-hours {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}
.progress-hours > div { flex: 1 1 0; min-width: 0; }
.progress-stats {
  display: flex;
  justify-content: space-between;
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 0.9rem;
  padding-top: 0.8rem;
  border-top: 1px solid rgba(92, 247, 177, 0.12);
}
.progress-stats b { color: var(--text); font-weight: 600; }
.progress-hours div { display: flex; flex-direction: column; align-items: center; text-align: center; }
.progress-hours b {
  font-family: var(--serif);
  font-size: 1.25rem;
  color: var(--mako);
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}
.progress-hours span {
  font-size: 0.56rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ash);
  margin-top: 0.15rem;
}
.progress-note { margin: 0.7rem 0 0; font-size: 0.7rem; color: var(--ash); }

/* How-to steps under the journey panel. No cards: each step is a matte
   materia orb with its caption beneath, joined by a faint Lifestream line.
   Phones turn it into a vertical list with the line running down the orbs. */
.how-to {
  list-style: none;
  --how-gap: 1.75rem;
  width: min(72rem, 100%);
  margin: 2.6rem 0 1.6rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--how-gap);
  position: relative;
}
.how-to::before {
  content: "";
  position: absolute;
  top: 1rem;
  /* Runs from the centre of the first column to the centre of the last. */
  left: calc((100% - 4 * var(--how-gap)) / 10);
  right: calc((100% - 4 * var(--how-gap)) / 10);
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--mako-dim) 15%, var(--mako) 50%, var(--mako-dim) 85%, transparent);
  box-shadow: 0 0 8px rgba(92, 247, 177, 0.45);
}
.how-to li {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.85rem;
  line-height: 1.4;
  color: var(--muted);
}
.how-num {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  font-weight: 700;
  font-size: 0.85rem;
  color: var(--text);
  background: linear-gradient(160deg, #2a9a6c, var(--mako-dim));
  box-shadow: 0 0 0 4px var(--bg), 0 0 0 5px rgba(92, 247, 177, 0.3), 0 0 14px rgba(92, 247, 177, 0.3);
  position: relative;
  animation: how-glow 4s ease-in-out infinite;
}
/* A faint aura ring that drifts out from each orb and fades, like the road's
   nodes. Staggered so the ripple travels from step 1 to step 5. */
.how-num::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(92, 247, 177, 0.6);
  box-shadow: 0 0 8px rgba(92, 247, 177, 0.4);
  opacity: 0;
  pointer-events: none;
  animation: how-aura 4s ease-out infinite;
}
.how-to li:nth-child(2) .how-num, .how-to li:nth-child(2) .how-num::after { animation-delay: 0.4s; }
.how-to li:nth-child(3) .how-num, .how-to li:nth-child(3) .how-num::after { animation-delay: 0.8s; }
.how-to li:nth-child(4) .how-num, .how-to li:nth-child(4) .how-num::after { animation-delay: 1.2s; }
.how-to li:nth-child(5) .how-num, .how-to li:nth-child(5) .how-num::after { animation-delay: 1.6s; }
@keyframes how-glow {
  50% { box-shadow: 0 0 0 4px var(--bg), 0 0 0 5px rgba(92, 247, 177, 0.45), 0 0 20px rgba(92, 247, 177, 0.45); }
}
@keyframes how-aura {
  0%   { transform: scale(1); opacity: 0.7; }
  70%, 100% { transform: scale(1.9); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .how-num, .how-num::after { animation: none; }
}
.how-to li > span:last-child { max-width: 13rem; }
.how-to b { color: var(--text); font-weight: 600; }
@media (max-width: 760px) {
  .how-to { grid-template-columns: 1fr; gap: 0.9rem; width: min(24rem, 100%); }
  .how-to::before {
    top: 1rem; bottom: 1rem; left: 1rem; right: auto;
    width: 1px; height: auto;
    background: linear-gradient(180deg, var(--mako-dim), var(--mako), var(--mako-dim));
  }
  .how-to li { flex-direction: row; text-align: left; gap: 0.9rem; }
  .how-to li > span:last-child { max-width: none; }
}

/* ---------- modal ---------- */
/* Small hollow circle icon that leads the control-info ("i") and "how it ties in"
   ("!") buttons. Same ring for both; only the glyph differs. */
.info-i {
  flex: none;
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.45em; height: 1.45em;
  border: 0.12em solid currentColor;
  border-radius: 50%;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 0.95em;
  font-weight: 700;
  font-style: italic;
  line-height: 1;
  text-transform: none;
  letter-spacing: 0;
}
.info-i::before { content: "i"; font-size: 0.78em; padding-top: 0.12em; /* optical centring */ }
/* The "!" keeps its original tighter ring. */
.info-bang {
  width: 1.25em; height: 1.25em;
  border-width: 0.14em;
  font-family: var(--sans);
  font-style: normal;
  font-weight: 800;
}
.info-bang::before { content: "!"; font-size: 1em; padding: 0 0 0.06em; }
/* Same ring and weight as the "!", with a lower-case "i" (control info buttons). */
.info-bang-i::before { content: "i"; }
.guide-modal {
  width: min(60rem, calc(100% - 2rem));
  max-height: calc(100vh - 2rem);
  margin: auto;
  padding: 0;
  border: 1px solid rgba(92, 247, 177, 0.3);
  border-radius: 18px;
  background: var(--bg-2);
  color: var(--text);
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6), 0 0 50px rgba(92, 247, 177, 0.12);
  overflow: hidden;
}
.guide-modal::backdrop { background: rgba(4, 17, 13, 0.78); backdrop-filter: blur(6px); }
/* The body scrolls, not the dialog, so the close button (a sibling) stays put. */
.guide-body { max-height: calc(100vh - 2rem); overflow: auto; overscroll-behavior: contain; padding: 2rem 1.5rem 1.75rem; }
/* While a modal is open the page behind it is frozen: the body is pinned at
   its current scroll offset (set inline by app.js) so touch scrolling only
   moves the modal's own body. */
body.scroll-locked { position: fixed; left: 0; right: 0; overflow: hidden; }
.guide-close {
  position: absolute;
  top: 1rem; right: 1rem;
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 1px solid var(--card-border);
  background: rgba(92, 247, 177, 0.06);
  color: var(--mako);
  font-size: 1.4rem;
  line-height: 1;
  display: grid;
  place-items: center;
  padding: 0 0 2px;
  transition: all 0.2s;
}
.guide-close:hover { background: rgba(92, 247, 177, 0.18); border-color: var(--mako); }

/* ---------- controls ---------- */
/* The dock is what sticks; it holds the filter controls and, hanging off its
   bottom edge, the compact journey bar. The bar is absolutely positioned so
   showing it never shifts the road below. */
.controls-dock {
  position: sticky;
  top: 0;
  z-index: 9;
}
.dock-sentinel { height: 0; }
.controls {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  justify-content: center;
  align-items: center;
  padding: 0.8rem 1rem;
  margin: 0 auto;
  background: rgba(4, 17, 13, 0.85);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-top: 1px solid rgba(92, 247, 177, 0.08);
  border-bottom: 1px solid rgba(92, 247, 177, 0.08);
}
/* Every control shares one height and one text size so the row reads as
   a single set of pills. */
.controls { --ctl-h: 2.3rem; --ctl-fs: 0.78rem; }
/* ---------- journey bar (compact Your Journey, under the stuck controls) ----------
   Collapsed by default: tucked up behind the controls and faded out. While
   the dock is stuck (.controls-dock.stuck, set by app.js) it slides down. */
.journey-bar {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  z-index: 0;
  padding: 0.45rem 1rem;
  background: rgba(4, 17, 13, 0.95);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(92, 247, 177, 0.1);
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.35);
  transform: translateY(-100%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.25s ease, visibility 0s linear 0.3s;
}
.controls-dock.stuck .journey-bar {
  transform: none;
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.25s ease, visibility 0s;
}
.jb-inner {
  display: grid;
  grid-template-columns: auto auto minmax(6rem, 1fr) auto auto;
  align-items: center;
  column-gap: 0.8rem;
  /* Matches the span of the filter controls above (their pills run to about
     77.75rem on desktop), so the bar's contents line up with them. */
  width: min(77.75rem, 100%);
  margin: 0 auto;
  font-size: 0.72rem;
  color: var(--muted);
  white-space: nowrap;
}
.jb-title {
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-size: 0.66rem;
}
.jb-pct { color: var(--mako); font-weight: 600; font-variant-numeric: tabular-nums; }
.jb-bar { height: 6px; margin: 0; }
.jb-stats, .jb-hours { display: flex; gap: 0.7rem; }
.jb-stats b { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
/* Hours come first, next to the bar; the item counts follow after a divider. */
.jb-stats {
  padding-left: 0.8rem;
  border-left: 1px solid rgba(92, 247, 177, 0.14);
}
/* Short labels are for the expanded phone bar only; mid labels for narrow
   tablets. */
.jb-short, .jb-mid { display: none; }
.jb-hours > span {
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ash);
}
.jb-hours b {
  font-family: var(--serif);
  font-size: 0.88rem;
  color: var(--mako);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
  margin-right: 0.15rem;
}
/* Tablets (between the phone layout and the width the controls stop
   wrapping at): the hours stay beside the bar, and the item counts drop to
   their own, centred line once they would squeeze the bar under 8rem. A flex
   row that wraps does this without fixed breakpoints, since the counts are
   the last item; their auto margins only take space when they sit alone on
   a line, because the bar soaks up any spare room on the first. The divider
   is a pseudo-element half a gap to the right of the hours, so when the
   counts wrap it falls past the row's end and is clipped. */
@media (min-width: 761px) and (max-width: 1280px) {
  .jb-inner {
    display: flex;
    flex-wrap: wrap;
    row-gap: 0.35rem;
    overflow-x: clip;
  }
  .jb-bar { flex: 1 1 8rem; min-width: 6rem; }
  .jb-stats {
    margin: 0 auto;
    padding-left: 0;
    border-left: 0;
  }
  .jb-hours { position: relative; }
  .jb-hours::after {
    content: "";
    position: absolute;
    top: 0; bottom: 0;
    right: -0.4rem;
    border-left: 1px solid rgba(92, 247, 177, 0.14);
  }
  /* The taller bar needs more room above an entry jumped to via #id. */
  .entry { scroll-margin-top: 10rem; }
}
/* Narrow tablets: the full hour labels would leave the bar no room, so they
   shorten and tighten, and the counts always take the second line. */
@media (min-width: 761px) and (max-width: 959px) {
  .jb-long { display: none; }
  .jb-mid { display: inline; }
  .jb-hours { gap: 0.55rem; }
  .jb-hours > span { letter-spacing: 0.05em; }
  .jb-bar { flex-basis: 6rem; }
  .jb-stats { flex-basis: 100%; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .journey-bar, .controls-dock.stuck .journey-bar { transition: none; }
}

.control-group {
  display: inline-flex;
  height: var(--ctl-h);
  border: 1px solid var(--card-border);
  border-radius: 999px;
  overflow: hidden;
  background: rgba(6, 26, 20, 0.6);
}
.seg {
  background: transparent;
  border: 0;
  color: var(--muted);
  padding: 0 0.9rem;
  font-size: var(--ctl-fs);
  letter-spacing: 0.04em;
  transition: all 0.2s;
}
.seg + .seg { border-left: 1px solid var(--card-border); }
.seg.active { background: rgba(92, 247, 177, 0.16); color: var(--mako); }
.chips { gap: 0.3rem; padding: 0.2rem; border-radius: 999px; }
/* ---------- control explainer popovers ---------- */
/* Wraps a pill of buttons so a popover can hang below it without being
   clipped by the pill's overflow:hidden. Shown on hover only.
   Used by the scope (Your Journey) and order (Your Order) groups. */
.ctl-wrap { position: relative; display: inline-flex; }
.ctl-pop {
  position: absolute;
  top: calc(100% + 0.7rem);
  left: 0;
  width: min(36rem, calc(100vw - 2rem));
  z-index: 6;
  padding: 0.9rem 1.1rem;
  border: 1px solid rgba(92, 247, 177, 0.4);
  border-radius: 12px;
  background: #071c15;
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55), 0 0 24px rgba(92, 247, 177, 0.15);
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.5;
  text-align: left;
  letter-spacing: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px);
  transition: opacity 0.18s ease-out, transform 0.18s ease-out, visibility 0s linear 0.18s;
}
/* Invisible bridge so the pointer can travel from the bar to the popover. */
.ctl-pop::after {
  content: "";
  position: absolute;
  left: 0; right: 0;
  top: -0.8rem;
  height: 0.8rem;
}
.ctl-wrap:hover .ctl-pop {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0.08s, 0.08s, 0s;
}
/* After an option is picked the popover stays closed until the pointer leaves
   the group, so a selection doesn't leave the explainer hanging open. */
.ctl-wrap.dismissed .ctl-pop { opacity: 0; visibility: hidden; pointer-events: none; }
.ctl-pop-title {
  margin: 0 0 0.2rem;
  font-family: var(--serif);
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--mako);
}
/* One-line explainer under the title: sans, smaller, no caps. */
.ctl-pop-sub {
  margin: 0 0 0.6rem;
  font-family: var(--sans);
  font-size: 0.76rem;
  line-height: 1.4;
  color: var(--muted);
}
.ctl-pop ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.55rem; }
.ctl-pop li {
  cursor: pointer;
  padding: 0.35rem 0.6rem;
  border-left: 2px solid rgba(92, 247, 177, 0.1);
  border-radius: 0 6px 6px 0;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.ctl-pop li b { color: var(--text); }
/* Hovering an entry (or its button in the bar) gives it a faint wash; the
   selected scope keeps the full highlight so the list doubles as a status. */
.ctl-pop li.hot,
.ctl-pop li:hover { background: rgba(92, 247, 177, 0.02); border-left-color: rgba(92, 247, 177, 0.35); }
.ctl-pop li.selected,
.ctl-pop li.selected:hover { background: rgba(92, 247, 177, 0.1); border-left-color: var(--mako); color: var(--text); }
.ctl-shows { display: block; margin-top: 0.15rem; color: var(--mako-2, var(--mako)); font-size: 0.74rem; }
@media (prefers-reduced-motion: reduce) {
  .ctl-pop { transition: none; transform: none; }
}
/* Phone-only "i" next to each pill that opens the explainer in a modal,
   since there is no hover on touch. Hidden entirely on desktop. */
.ctl-info {
  display: none;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--ctl-h); height: var(--ctl-h);
  margin-right: 0.15rem;
  padding: 0;
  border: 0;
  background: transparent;
  /* Colour and size match the "!" in the spoiler (why) button. */
  color: var(--mako-2);
  font-size: 0.66rem;
}
.ctl-modal { width: min(36rem, calc(100% - 2rem)); }
.ctl-modal-body { padding: 2.6rem 1.1rem 1.1rem; }
/* Inside the modal the popover is just content: no hover gating, no
   floating position, no second border. */
.ctl-modal .ctl-pop {
  position: static;
  width: auto;
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: none;
  border: 0;
  padding: 0;
  box-shadow: none;
  background: transparent;
}
.ctl-modal .ctl-pop::after { display: none; }
@media (max-width: 760px) {
  /* Phones: the stuck bar keeps title, percent and the bar; the stats row
     does not fit and is dropped. */
  .jb-hours, .jb-stats { display: none; }
  .jb-stats { padding-left: 0; border-left: 0; }
  .jb-inner { grid-template-columns: auto auto minmax(6rem, 1fr); }
  /* Expanding the controls (chevron) also brings back the hours and the
     counts, each on its own full-width line under the bar. */
  .controls-dock.ctl-expanded .jb-inner { row-gap: 0.5rem; }
  .controls-dock.ctl-expanded .jb-long { display: none; }
  .controls-dock.ctl-expanded .jb-short { display: inline; }
  /* Hours: five columns styled like the hero panel's hours (figure over label). */
  .controls-dock.ctl-expanded .jb-hours {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: repeat(5, 1fr);
    gap: 0.5rem;
  }
  .controls-dock.ctl-expanded .jb-hours > span {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    white-space: normal;
    font-size: 0.56rem;
    letter-spacing: 0.06em;
  }
  .controls-dock.ctl-expanded .jb-hours b { font-size: 1.25rem; line-height: 1.2; margin: 0 0 0.15rem; }
  /* Entry counts: the hero panel's full wording and text style, each line
     centred under the bar. */
  .controls-dock.ctl-expanded .jb-stats {
    display: flex;
    grid-column: 1 / -1;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 1rem;
    font-size: 0.8rem;
  }
  .ctl-info { display: inline-flex; align-self: center; width: 1.5rem; height: 1.75rem; }
  /* One label size for every control, scaling with the viewport so the
     four-track pill plus its "i" and chevron fits a 320px phone. The bar's
     side padding is trimmed to give that row the room. */
  .controls { --ctl-fs: min(0.78rem, 2.8vw); padding-left: 0.6rem; padding-right: 0.6rem; }
  .seg, .chip, .country-label, .reset { letter-spacing: 0.02em; }
  /* Segments sit close together inside a pill, but the outer ends get the
     same breathing room as the Store links pill. In em so the padding
     shrinks with the label on narrow phones. */
  .ctl-wrap .seg { padding: 0 0.5em; white-space: nowrap; }
  .ctl-wrap .seg:first-child { padding-left: 1.1em; }
  .ctl-wrap .seg:last-child { padding-right: 1.1em; }
  /* Touch has no hover; the "i" button opens the explainer instead. Taken
     out of layout entirely so the viewport-wide box cannot widen the page. */
  .ctl-wrap .ctl-pop { display: none; }
}
.chip {
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--ash);
  padding: 0 0.7rem;
  font-size: var(--ctl-fs);
  transition: all 0.2s;
}
.chip.active { color: var(--text); border-color: var(--card-border); background: rgba(92, 247, 177, 0.08); }
.chip-count { opacity: 0.7; font-size: 0.9em; }
.country {
  position: relative;
  height: var(--ctl-h);
  padding: 0 0.7rem 0 0.9rem;
  border: 1px solid var(--card-border);
  border-radius: 999px;
  background: rgba(6, 26, 20, 0.6);
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.country-label {
  font-size: var(--ctl-fs);
  letter-spacing: 0.04em;
  color: var(--muted);
  white-space: nowrap;
  pointer-events: none;
}
.country:hover, .country:focus-within { border-color: var(--mako); box-shadow: 0 0 12px rgba(92, 247, 177, 0.25); }
.country-flag { font-size: 1rem; line-height: 1; pointer-events: none; }
.country select {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  opacity: 0;
  cursor: pointer;
  font-size: 16px; /* keeps iOS from zooming on focus */
}
.reset {
  height: var(--ctl-h);
  border: 1px solid transparent;
  background: transparent;
  color: var(--ash);
  font-size: var(--ctl-fs);
  padding: 0 0.8rem;
  border-radius: 999px;
  transition: all 0.2s;
}
.reset:hover { color: #ff8a8a; border-color: rgba(255, 138, 138, 0.3); }
/* ---------- collapsible controls (phones) ----------
   Desktop: the group is transparent to layout and the toggle is hidden, so
   the bar is exactly the single row it always was. */
.controls-more { display: contents; }
.ctl-toggle { display: none; }
@media (max-width: 760px) {
  /* Chevron-only round button, hugging the right end of the Journey pill. */
  .ctl-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    align-self: center;
    width: 2rem; height: 2rem;
    margin-left: 0.3rem;
    padding: 0;
    border: 1px solid var(--card-border);
    border-radius: 999px;
    background: rgba(6, 26, 20, 0.6);
    color: var(--mako);
    transition: all 0.2s;
  }
  .ctl-toggle[aria-expanded="true"] { background: rgba(92, 247, 177, 0.16); }
  .ctl-toggle-chev {
    width: 0.45rem; height: 0.45rem;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
    transition: transform 0.2s;
  }
  .ctl-toggle[aria-expanded="true"] .ctl-toggle-chev { transform: translateY(1px) rotate(-135deg); }
  /* The pill, its "i" and the chevron share one row. */
  .ctl-wrap[data-ctl="scope"] { max-width: 100%; }
  .ctl-wrap[data-ctl="scope"] .control-group { min-width: 0; }
  /* Collapsed by default; expanding drops the rest of the controls onto
     their own wrapped rows under the Journey pill. */
  .controls-more {
    display: none;
    flex-basis: 100%;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.6rem;
    padding-top: 0.2rem;
  }
  .controls.expanded .controls-more { display: flex; }
}

/* ---------- road ---------- */
.road {
  position: relative;
  max-width: 68rem;
  margin: 0 auto;
  padding: 4rem 1rem 6rem;
}
.spine {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 4px;
  margin-left: -2px;
}
.spine-track {
  position: absolute; inset: 0;
  background: linear-gradient(to bottom, transparent, rgba(92, 247, 177, 0.15) 4%, rgba(92, 247, 177, 0.15) 96%, transparent);
  border-radius: 2px;
}
/* Grown with a real height (set in updateSpine), not scaleY: scaling would
   squash the glow into a blurry block with hard top and bottom edges. The
   gradient is sized to the whole spine so its colours don't slide as it grows,
   and fades in at the top; the glow is a drop-shadow so it follows that fade
   instead of starting with a hard edge. */
.spine-fill {
  position: absolute; top: 0; left: 0; right: 0;
  height: 0;
  background: linear-gradient(to bottom, transparent, var(--mako-2) 4rem, var(--mako) 50%, var(--teal)) no-repeat;
  filter: drop-shadow(0 0 5px var(--mako)) drop-shadow(0 0 12px rgba(92, 247, 177, 0.5));
  border-radius: 2px;
}
.spine-head {
  position: absolute;
  left: 50%; top: 0;
  width: 16px; height: 16px;
  margin-left: -8px; margin-top: -8px;
  will-change: transform;
  border-radius: 50%;
  background: var(--mako-2);
  box-shadow: 0 0 20px var(--mako), 0 0 50px rgba(92, 247, 177, 0.7);
}

/* Closing words beneath the destination, where the road runs out. */
.road-end {
  position: relative;
  margin: 4.5rem auto 0;
  padding: 0 1rem;
  max-width: 34rem;
  text-align: center;
  font-family: var(--serif);
  font-style: normal;
  font-size: clamp(1.15rem, 2.4vw, 1.5rem);
  line-height: 1.5;
  color: var(--gold);
  text-shadow: 0 0 18px rgba(242, 199, 102, 0.45);
}
.road-end p { margin: 0; }
/* Thin gold rule: one 4.5rem above Revelation, one 4.5rem below it (leading
   the closing words), so the destination is bracketed at equal distances. */
.road-end::before, .entry.destination::before {
  content: "";
  display: block;
  width: 3rem;
  height: 1px;
  margin: 0 auto 1.4rem;
  background: linear-gradient(to right, transparent, var(--gold), transparent);
}
.entry.destination { margin-top: 4.5rem; }
.entry.destination::before {
  position: absolute;
  left: 50%;
  top: -4.5rem;
  margin: 0 0 0 -1.5rem;
}

.entries {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 3.2rem;
}
.entry {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 4rem 1fr;
  align-items: center;
}
.entry .card, .entry .node, .entry .gallery {
  opacity: 0;
  transform: translateY(30px);
  /* opacity and transform drive the slow reveal on scroll. The completed
     dimming runs on filter instead, on the status toggle's own 0.2s clock,
     so marking an entry done is one fade rather than the button lighting
     up and then the whole card sinking to 40% over the next 0.7s. */
  transition: opacity 0.7s ease, transform 0.7s cubic-bezier(0.2, 0.8, 0.2, 1),
    filter 0.2s ease, border-color 0.3s;
}
.entry .gallery { transition-delay: 0.15s, 0.15s, 0s, 0s; }
.entry.visible .card, .entry.visible .node, .entry.visible .gallery { opacity: 1; transform: none; }
.entry.hidden { display: none; }
/* Room for the sticky controls + journey bar when an entry is jumped to
   via #id. */
.entry { scroll-margin-top: 7.2rem; }
/* Anchor target: a Mako glow on the card that fades out (class removed by app.js). */
.entry.highlight .card {
  animation: entry-highlight 4s ease-out;
}
@keyframes entry-highlight {
  0%   { box-shadow: 0 0 0 2px var(--mako), 0 0 0 6px rgba(92, 247, 177, 0.25), 0 0 60px rgba(92, 247, 177, 0.55); border-color: var(--mako-2); }
  60%  { box-shadow: 0 0 0 2px var(--mako), 0 0 0 6px rgba(92, 247, 177, 0.18), 0 0 40px rgba(92, 247, 177, 0.35); border-color: var(--mako); }
  100% { box-shadow: none; }
}
.entry.destination.highlight .card {
  animation-name: entry-highlight-gold;
}
@keyframes entry-highlight-gold {
  0%   { box-shadow: 0 0 0 2px var(--gold), 0 0 0 6px rgba(242, 199, 102, 0.25), 0 0 60px rgba(242, 199, 102, 0.55); }
  100% { box-shadow: none; }
}

.entry .card { grid-column: 1; grid-row: 1; }
.entry .node { grid-column: 2; grid-row: 1; justify-self: center; }
.entry .gallery { grid-column: 3; grid-row: 1; }

.node {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2px solid rgba(92, 247, 177, 0.4);
  background: var(--bg);
  display: grid;
  place-items: center;
  padding: 0;
  transition: all 0.3s;
  position: relative;
  z-index: 2;
}
.node-core {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: rgba(92, 247, 177, 0.35);
  transition: all 0.3s;
}
.entry.visible .node {
  border-color: var(--mako);
  box-shadow: 0 0 14px rgba(92, 247, 177, 0.4);
  animation: pulse-soft 2s ease-in-out infinite;
  animation-delay: calc(var(--pulse-offset, 0) * -1s);
}
.entry.done .node { border-color: var(--mako-2); background: var(--mako-dim); box-shadow: 0 0 22px var(--mako); }
.entry.done .node-core { background: var(--mako-2); box-shadow: 0 0 10px var(--mako-2); }

.entry.required .node { width: 40px; height: 40px; border-width: 3px; }
.entry.required .node-core { width: 16px; height: 16px; }
.entry.destination .node {
  cursor: default;
  width: 56px; height: 56px;
  border-color: var(--gold);
  box-shadow: 0 0 30px rgba(242, 199, 102, 0.5);
  animation: pulse 2.5s ease-in-out infinite;
}
.entry.destination .node-core { width: 22px; height: 22px; background: var(--gold); box-shadow: 0 0 16px var(--gold); }

.card {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 1.4rem 1.5rem;
  position: relative;
  transition: border-color 0.3s, box-shadow 0.3s, transform 0.3s;
}
/* Hover only brightens the border. The card used to lift 2px over 0.7s, so
   moving onto a card to click its status toggle meant clicking a target that
   was still sliding by fractions of a pixel, which made its text shimmer. */
.entry.visible .card:hover { border-color: rgba(92, 247, 177, 0.4); }
.entry.required .card {
  border-color: rgba(92, 247, 177, 0.45);
  box-shadow: 0 0 0 1px rgba(92, 247, 177, 0.15), 0 20px 50px rgba(0, 0, 0, 0.4), 0 0 40px rgba(92, 247, 177, 0.08);
}
.entry.destination .card {
  border-color: rgba(242, 199, 102, 0.5);
  box-shadow: 0 0 0 1px rgba(242, 199, 102, 0.15), 0 20px 50px rgba(0, 0, 0, 0.4), 0 0 40px rgba(242, 199, 102, 0.1);
}
.entry.done.visible .card, .entry.done.visible .gallery { filter: opacity(0.4); }

/* ---------- lifestream burst on the node ---------- */
.node-burst {
  position: absolute;
  left: 50%; top: 50%;
  width: 0; height: 0;
  pointer-events: none;
  z-index: 3;
}
.node-burst i {
  position: absolute;
  left: 0; top: 0;
  width: var(--s, 3px); height: var(--s, 3px);
  margin: calc(var(--s, 3px) / -2) 0 0 calc(var(--s, 3px) / -2);
  border-radius: 50%;
  background: var(--mako-2);
  box-shadow: 0 0 6px var(--mako), 0 0 12px rgba(92, 247, 177, 0.6);
  animation: spark var(--t, 900ms) cubic-bezier(0.1, 0.8, 0.3, 1) var(--d, 0ms) both;
}
.node-burst i.gold { background: #fff1c2; box-shadow: 0 0 6px var(--gold), 0 0 12px rgba(242, 199, 102, 0.6); }
.node-burst b {
  position: absolute;
  left: 0; top: 0;
  width: 10px; height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  border: 1.5px solid var(--mako-2);
  box-shadow: 0 0 10px rgba(92, 247, 177, 0.6);
  animation: ring 1100ms ease-out both;
}
@keyframes spark {
  0%   { transform: translate(0, 0) scale(0.4); opacity: 0; }
  12%  { opacity: 1; transform: translate(calc(var(--dx) * 0.25), calc(var(--dy) * 0.25)) scale(1); }
  100% { transform: translate(var(--dx), calc(var(--dy) - 14px)) scale(0); opacity: 0; }
}
@keyframes ring {
  0%   { transform: scale(1); opacity: 0.9; }
  100% { transform: scale(14); opacity: 0; }
}
/* faint motes that keep drifting up from an experienced node */
.entry.done .node::before, .entry.done .node::after {
  content: "";
  position: absolute;
  left: 50%; top: 50%;
  width: 3px; height: 3px;
  margin: -1.5px 0 0 -1.5px;
  border-radius: 50%;
  background: var(--mako-2);
  box-shadow: 0 0 6px var(--mako);
  pointer-events: none;
  animation: mote 4.5s ease-in-out infinite;
}
.entry.done .node::after { animation-delay: 2.2s; animation-duration: 5.5s; --mx: 9px; }
@keyframes mote {
  0%   { transform: translate(0, 0) scale(0.6); opacity: 0; }
  15%  { opacity: 0.9; }
  100% { transform: translate(calc(var(--mx, -8px)), -34px) scale(0.2); opacity: 0; }
}

/* connector from node to card */
.card::before, .gallery::before {
  content: "";
  position: absolute;
  top: 50%;
  width: 2rem;
  height: 1px;
  background: linear-gradient(90deg, rgba(92, 247, 177, 0.5), transparent);
  right: -2rem;
}
.gallery::before {
  right: auto; left: -2rem;
  background: linear-gradient(270deg, rgba(92, 247, 177, 0.35), transparent);
}

/* ---------- gallery ---------- */
.gallery {
  position: relative;
  align-self: center;
  width: min(100%, 30rem);
  margin-left: 0.5rem;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  overflow: hidden;
  transition: border-color 0.3s;
}
.entry.visible .gallery:hover { border-color: rgba(92, 247, 177, 0.4); }
.entry.destination .gallery { border-color: rgba(242, 199, 102, 0.35); }
.gallery-frame {
  position: relative;
  aspect-ratio: 16 / 9; /* matches YouTube embeds */
  overflow: hidden; /* clip zoomed images (see images[].zoom in data.js) to the frame */
  background:
    radial-gradient(ellipse at 50% 60%, rgba(92, 247, 177, 0.1), transparent 70%),
    var(--bg-2);
}
.gallery-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
  transition: opacity 0.5s ease;
}
.gallery-img.fading { opacity: 0; }
.gallery-img.broken { opacity: 0; }
.gallery-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  background: #000;
}
.gallery-play {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}
.gallery-play::before {
  content: "";
  width: 64px; height: 44px;
  border-radius: 12px;
  background: rgba(4, 17, 13, 0.7);
  border: 1px solid rgba(92, 247, 177, 0.45);
  box-shadow: 0 0 18px rgba(92, 247, 177, 0.25);
  transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
}
.gallery-play::after {
  content: "";
  position: absolute;
  width: 0; height: 0;
  margin-left: 4px;
  border-style: solid;
  border-width: 10px 0 10px 18px;
  border-color: transparent transparent transparent var(--mako);
}
.gallery-play:hover::before {
  background: rgba(92, 247, 177, 0.22);
  transform: scale(1.06);
  box-shadow: 0 0 26px rgba(92, 247, 177, 0.45);
}
.gallery-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.4rem 0.5rem;
  border-top: 1px solid rgba(92, 247, 177, 0.1);
}
.gallery-btn {
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid var(--card-border);
  background: rgba(92, 247, 177, 0.06);
  color: var(--mako);
  font-size: 1.2rem;
  line-height: 1;
  display: grid;
  place-items: center;
  padding: 0 0 2px;
  transition: all 0.2s;
}
.gallery-btn:hover { background: rgba(92, 247, 177, 0.18); border-color: var(--mako); }
.gallery-dots { display: flex; gap: 6px; }
.gallery-dots button {
  width: 8px; height: 8px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid rgba(92, 247, 177, 0.35);
  background: rgba(92, 247, 177, 0.12);
  transition: all 0.2s;
}
.gallery-dots button.on { background: var(--mako); box-shadow: 0 0 8px var(--mako); border-color: var(--mako-2); }

.card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem;
  margin-bottom: 0.7rem;
}
.badge {
  font-size: 0.65rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  border: 1px solid;
}
.badge.type { color: var(--muted); border-color: rgba(154, 184, 173, 0.35); }
.badge.track { font-weight: 600; }
.badge.track.required { color: var(--mako); border-color: var(--mako); background: rgba(92, 247, 177, 0.1); }
.badge.track.recommended { color: var(--teal); border-color: var(--teal); }
.badge.track.optional { color: var(--violet); border-color: var(--violet); }
.badge.track.skip { color: var(--ash); border-color: var(--ash); }
.badge.track.destination { color: var(--gold); border-color: var(--gold); background: rgba(242, 199, 102, 0.1); }
/* Track explainer popover: hover (or focus/tap) a track badge to see what
   the track means. The text comes from TRACK_TIPS via data-tip. */
/* The popover hangs off the header (not the badge) so it spans the card's
   width and never runs off a phone screen; the header is lifted above the
   card's later content so nothing paints over it. */
.card-head { position: relative; z-index: 2; }
.badge.track[data-tip] { cursor: help; outline: none; }
.badge.track[data-tip]:focus-visible { box-shadow: 0 0 0 2px rgba(92, 247, 177, 0.5); }
.badge.track[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  top: calc(100% + 0.4rem);
  left: 0;
  width: max-content;
  max-width: min(18rem, 100%);
  padding: 0.55rem 0.75rem;
  border: 1px solid;
  border-color: inherit; /* the badge's track colour */
  border-radius: 10px;
  background: #071c15;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.55);
  color: var(--muted);
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  white-space: normal;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(4px);
  transition: opacity 0.15s ease-out, transform 0.15s ease-out, visibility 0s linear 0.15s;
}
/* Hover only where there is a real pointer: on touch screens :hover sticks
   after a tap and would keep the popover open after a second tap closes it. */
@media (hover: hover) {
  .badge.track[data-tip]:hover::after {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0.05s, 0.05s, 0s;
  }
}
.badge.track[data-tip]:focus::after {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0.05s, 0.05s, 0s;
}
@media (prefers-reduced-motion: reduce) {
  .badge.track[data-tip]::after { transition: none; transform: none; }
}
.year {
  margin-left: auto;
  font-size: 0.72rem;
  color: var(--muted);
  letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
}
.card-title {
  font-family: var(--serif);
  font-size: 1.25rem;
  font-weight: 700;
  margin: 0;
  line-height: 1.25;
  color: var(--text);
}
.entry.required .card-title { font-size: 1.5rem; }
.entry.destination .card-title { font-size: 1.6rem; color: var(--gold); }
.card-sub { margin: 0.2rem 0 0.8rem; color: var(--muted); font-size: 0.85rem; }
.card-blurb { margin: 0 0 0.9rem; font-size: 0.93rem; white-space: pre-line; }
.entry-link { text-decoration: underline; text-decoration-color: rgba(92, 247, 177, 0.45); text-underline-offset: 2px; }
.entry-link:hover { color: var(--mako-2); text-decoration-color: var(--mako-2); }

.why { position: relative; margin-bottom: 0.8rem; }
.why-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid rgba(92, 247, 177, 0.3);
  background: rgba(92, 247, 177, 0.05);
  color: var(--mako-2);
  border-radius: 999px;
  padding: 0.3rem 0.75rem 0.3rem 0.6rem;
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: left;
  transition: all 0.2s;
}
.why-btn:hover, .why-btn.open { border-color: var(--mako); background: rgba(92, 247, 177, 0.15); color: var(--text); }
/* Floating note above the button. Absolutely positioned so opening it never
   changes the card's height (and so never moves the node on the spine). */
.why-pop {
  position: absolute;
  left: 0;
  bottom: calc(100% + 0.7rem);
  width: 100%;
  z-index: 5;
  padding: 0.85rem 1rem;
  border: 1px solid rgba(92, 247, 177, 0.4);
  border-radius: 12px;
  background: rgba(6, 26, 20, 0.97);
  box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55), 0 0 24px rgba(92, 247, 177, 0.15);
  animation: pop-in 0.18s ease-out;
}
.why-pop::after {
  content: "";
  position: absolute;
  left: 1.4rem;
  bottom: -7px;
  width: 12px; height: 12px;
  background: inherit;
  border-right: 1px solid rgba(92, 247, 177, 0.4);
  border-bottom: 1px solid rgba(92, 247, 177, 0.4);
  transform: rotate(45deg);
}
.card-why {
  margin: 0;
  font-size: 0.85rem;
  color: var(--mako-2);
  border-left: 2px solid rgba(92, 247, 177, 0.4);
  padding-left: 0.75rem;
}
@keyframes pop-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
.card-meta {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.6rem;
  margin: 0 0 0.8rem;
  font-size: 0.78rem;
}
.card-where { margin: 0 0 1rem; }
.where-title {
  margin: 0 0 0.45rem;
  color: var(--ash);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-size: 0.62rem;
}
.card-meta dt { color: var(--ash); letter-spacing: 0.15em; text-transform: uppercase; font-size: 0.62rem; }
.card-meta dd { margin: 0; color: var(--muted); }
.card-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
/* Grouped links (Physical / Digital): each group is a full-width row with its
   own small heading, styled like .where-title but slightly smaller. */
.link-group { flex: 1 0 100%; }
.link-group-title {
  margin: 0 0 0.3rem;
  color: var(--ash);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  font-size: 0.55rem;
}
.link-group-links { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.card-links a {
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  color: var(--mako-2);
  border: 1px solid rgba(92, 247, 177, 0.3);
  background: rgba(92, 247, 177, 0.05);
  border-radius: 999px;
  padding: 0.28rem 0.7rem;
  transition: all 0.2s;
}
.card-links a::after { content: " ↗"; opacity: 0.6; }
.card-links a.internal::after { content: none; }
.card-links a:hover { border-color: var(--mako); background: rgba(92, 247, 177, 0.15); color: var(--text); }
.card-links a.unverified { border-style: dashed; }
/* Affiliate button plus its asterisk, which links to the footer disclosure.
   The asterisk drops the pill styling and keeps a finger-sized tap area. */
.affiliate-link { display: inline-flex; align-items: flex-start; }
.card-links a.affiliate-mark,
.card-links a.affiliate-mark:hover {
  border: 0;
  background: none;
  border-radius: 0;
  padding: 0 0.35rem 0.4rem 0.15rem;
  font-size: 0.85rem;
  line-height: 1;
  color: var(--muted);
}
.card-links a.affiliate-mark:hover { color: var(--mako-2); }
.card-links a.affiliate-mark::after { content: none; }
/* Same size and colour as the value under "Length" (.card-meta dd). */
.where-note { margin: 0; font-size: 0.78rem; color: var(--muted); }
/* Status toggle: a three-way segmented control (Not started / In Progress /
   Completed). The selected segment takes the journey bar's colours: the
   same gold gradient as the completed fill, and that gradient at the bar's
   30% opacity for in progress. Not started stays transparent. */
.status-toggle {
  display: grid;
  /* minmax(0, 1fr) keeps the three columns equal and fixed: with plain 1fr
     a longer label could widen its column and nudge the others. */
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border: 1px solid rgba(242, 199, 102, 0.25);
  border-radius: 10px;
  overflow: hidden;
  background: rgba(242, 199, 102, 0.04);
}
.status-btn {
  position: relative;
  isolation: isolate;
  border: 0;
  border-left: 1px solid rgba(242, 199, 102, 0.2);
  background: transparent;
  color: var(--gold);
  padding: 0.55rem 0.25rem;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  /* Every property that changes with the state moves on one shared clock,
     so a click reads as a single fade rather than a few staggered ones. */
  transition: color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease, text-shadow 0.2s ease;
}
.status-btn:first-child { border-left: 0; }
.status-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0;
  background: linear-gradient(90deg, rgba(242, 199, 102, 0.6), var(--gold), #fff1c2);
  transition: opacity 0.2s ease;
}
/* Not started keeps its muted grey text in every state; the only change is
   a faint, slightly transparent grey background while it is the selected
   segment. Selecting In Progress or Completed does not touch it otherwise. */
.status-btn[data-status="none"] { color: var(--muted); background: transparent; }
.status-btn[data-status="none"][aria-checked="true"] { background: rgba(154, 184, 173, 0.07); }
/* Hover tints only with a real pointer: on touch screens :hover sticks to
   the tapped segment and its tint would fade out against the new state.
   In Progress and Completed keep their tint while selected, so clicking a
   hovered segment only fades its gold in on top, never dips then rises. */
@media (hover: hover) {
  .status-btn:not([data-status="none"]):hover { background: rgba(242, 199, 102, 0.1); }
  .status-btn[data-status="none"]:hover:not([aria-checked="true"]) { background: rgba(154, 184, 173, 0.12); }
}
.status-btn[data-status="wip"][aria-checked="true"]::before { opacity: 0.3; }
.status-btn[data-status="done"][aria-checked="true"]::before { opacity: 1; }
.status-btn[data-status="done"][aria-checked="true"] {
  color: var(--bg);
  /* Faux bold via text-shadow rather than font-weight: it fades with the
     rest of the state change, where a weight change would snap the glyphs. */
  text-shadow: 0.3px 0 0 currentColor, -0.3px 0 0 currentColor;
  box-shadow: 0 0 14px rgba(242, 199, 102, 0.5);
}
/* The segments are pointer-only (tabindex="-1" in the template): no focus ring. */
.status-btn:focus, .status-btn:focus-visible { outline: none; }
.entry.unreleased .node { cursor: default; }

/* ---------- about ---------- */
.about {
  max-width: 60rem;
  margin: 0 auto;
  padding: 4rem 1.25rem;
}
.about h2 {
  font-family: var(--serif);
  font-size: 1.8rem;
  letter-spacing: 0.06em;
  margin: 0 0 1.5rem;
  color: var(--mako-2);
}
.tipjar {
  max-width: 60rem;
  margin: 0 auto;
  padding: 0 1.25rem 3rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  text-align: center;
}
.tipjar p { margin: 0; color: var(--muted); font-size: 0.82rem; }
.tip-btn {
  display: inline-block;
  border: 1px solid rgba(242, 199, 102, 0.5);
  background: rgba(242, 199, 102, 0.08);
  color: var(--gold);
  border-radius: 999px;
  padding: 0.5rem 1.1rem;
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: all 0.2s;
}
.tip-btn:hover { background: rgba(242, 199, 102, 0.18); border-color: var(--gold); box-shadow: 0 0 18px rgba(242, 199, 102, 0.3); }

.about { text-align: center; }
.about p { color: var(--muted); max-width: 46rem; margin: 0 auto; font-size: 0.92rem; }
.about p + p { margin-top: 1rem; }
.about em { color: var(--text); font-style: normal; font-weight: 600; }
/* About videos reuse the gallery look (thumbnail + green play button). Two
   sit side by side on desktop, each with a short caption underneath. */
.about-videos {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2.5rem;
  width: min(62rem, 100%);
  margin: 3rem auto 0;
  text-align: left;
}
.about-figure { margin: 0; }
.about-figure figcaption {
  margin-top: 0.7rem;
  font-size: 0.8rem;
  line-height: 1.5;
  color: var(--muted);
  text-align: center;
}
.about-video {
  width: 100%;
  margin: 0;
}
.about-video::before { display: none; } /* no connector line outside the road */
.about-video:hover { border-color: rgba(92, 247, 177, 0.4); }
@media (max-width: 760px) {
  .about-videos { grid-template-columns: 1fr; }
}

.footer {
  padding: 1.5rem;
  font-size: 0.72rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ash);
  border-top: 1px solid rgba(92, 247, 177, 0.08);
}
.footer-made {
  margin: 0;
  text-align: center;
  font-size: 0.7rem;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--muted);
}
.footer-legal { margin-top: 0.5rem; }

/* ---------- animation ---------- */
@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.12); opacity: 0.8; }
}
/* gentler beat for the ordinary nodes along the road; the destination keeps the stronger `pulse` */
@keyframes pulse-soft {
  0%, 100% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.16); opacity: 0.85; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .entry .card, .entry .node { transition: none; opacity: 1; transform: none; }
  .entry .node, .back-fab { animation: none; }
  .entry.done .node::before, .entry.done .node::after { display: none; }
}

/* ---------- back-to-previous-title floating button ----------
   Appears after an in-page [label](#id) entry link is followed, so the reader
   can hop back to the title they came from without hunting for the browser's
   back button. Sits below the sticky bars and the guide modal. */
.back-fab {
  position: fixed;
  left: 50%;
  transform: translateX(-50%);
  bottom: 1rem;
  z-index: 8;
  display: flex;
  align-items: stretch;
  border: 1px solid var(--card-border);
  border-radius: 999px;
  background: rgba(6, 26, 20, 0.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45), 0 0 18px rgba(92, 247, 177, 0.18);
  overflow: hidden;
  animation: back-fab-in 0.25s ease-out;
  max-width: calc(100vw - 2rem);
}
.back-fab[hidden] { display: none; }
.back-fab button {
  border: 0;
  background: transparent;
  color: var(--mako);
  font-family: inherit;
  transition: background 0.2s, color 0.2s;
}
.back-fab button:hover, .back-fab button:focus-visible { background: rgba(92, 247, 177, 0.15); color: var(--mako-2); outline: none; }
.back-fab-go {
  padding: 0.7rem 1rem 0.7rem 1.1rem;
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}
.back-fab .back-fab-close {
  padding: 0 0.85rem 0 0.7rem;
  font-size: 1.25rem;
  line-height: 1;
  border-left: 1px solid var(--card-border);
  color: var(--muted);
}
.back-fab .back-fab-close:hover, .back-fab .back-fab-close:focus-visible { color: var(--text); }
/* Same motion as the entrance, played backwards. Separate keyframes so the
   browser starts a new animation (and fires animationend) rather than
   treating it as the already-finished entrance. */
.back-fab.leaving { animation: back-fab-out 0.25s ease-in forwards; pointer-events: none; }
@keyframes back-fab-in {
  from { opacity: 0; transform: translate(-50%, 0.6rem); }
  to { opacity: 1; transform: translateX(-50%); }
}
@keyframes back-fab-out {
  from { opacity: 1; transform: translateX(-50%); }
  to { opacity: 0; transform: translate(-50%, 0.6rem); }
}

/* ---------- mobile ---------- */
@media (max-width: 760px) {
  /* The node column starts at the screen edge (the list is pulled over the
     road's 1rem padding) and the path runs down its centre. With the card
     starting at twice that distance, every node has equal space on its left
     (to the screen edge) and its right (to the card). */
  .spine { left: 1.8rem; }
  .entries { margin-left: -1rem; }
  /* The gold destination node is scaled down to keep a gap on both sides. */
  .entry.destination .node { width: 44px; height: 44px; }
  .entry.destination .node-core { width: 18px; height: 18px; }
  /* The gold rules bracketing Revelation sit on the path (1.8rem in from
     the road's edge) rather than the page centre; the closing words stay
     centred. The road-end spans the road's content box so the rule's
     offset holds at every phone width. */
  .entry.destination::before { left: 1.8rem; }
  .road-end { max-width: none; margin-left: 0; margin-right: 0; }
  .road-end::before { margin-left: -1.7rem; }
  .entry {
    grid-template-columns: 3.6rem 1fr;
    grid-template-rows: auto auto;
    row-gap: 0.8rem;
  }
  .entry .card { grid-column: 2; grid-row: 1; }
  .entry .node { grid-column: 1; grid-row: 1; align-self: start; margin-top: 1.4rem; }
  .entry .gallery { grid-column: 2; grid-row: 2; width: 100%; margin-left: 0; align-self: start; }
  .card::before, .gallery::before { display: none; }
  .entries { gap: 2.2rem; }
  .entry { scroll-margin-top: 4.5rem; }
  /* Tagline stays on one line: tighter tracking and a width-based size. */
  .eyebrow { font-size: clamp(0.6rem, 2.9vw, 0.75rem); letter-spacing: 0.18em; white-space: nowrap; }
  /* All four countdown boxes share one row. */
  .cd-units { gap: 0.4rem; flex-wrap: nowrap; width: 100%; max-width: 26rem; }
  .cd-unit { flex: 1 1 0; min-width: 0; padding: 0.6rem 0.2rem; }
  .cd-unit .cd-value { font-size: 1.6rem; }
  .cd-unit .cd-label { font-size: 0.58rem; letter-spacing: 0.1em; }
  .progress-stats { flex-wrap: wrap; gap: 0.5rem 1rem; }
  .progress-hours { gap: 0.7rem 0.5rem; }
  .progress-hours > div { flex: 0 0 calc((100% - 1rem) / 3); }
  .back-fab { bottom: 0.75rem; }
}

/* Read by screen readers and search engines, not shown on screen. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
