/* =========================================================================
   Bhavani Thekkada Nanjunda — athlete site
   Tokens derived from the photographs. See DESIGN_PLAN.md.
   ========================================================================= */

:root {
  /* Ground, coldest to warmest. The page descends through these. */
  --ink: #06090f;
  --ink-warm: #14110c;
  --ink-cool: #0a1016;
  --ink-deep: #04070c;
  --navy: #0e1c33;
  --navy-2: #14294a;

  /* Sampled from her kit and equipment */
  --india: #2056de;
  --india-lift: #6b98f7;
  --glacier: #9dccf3;
  --snow: #e6eff4;
  --snow-hi: #f6fafc;
  --race: #c6e82b;

  /* Kodagu warm neutrals */
  --stone: #8e8474;
  --moss: #5e735b;
  --saffron: #e4761b;

  /* Per-section, reassigned down the page */
  --ground: var(--ink);
  --fg: var(--snow);
  --fg-dim: #93a3b4;
  --rule: rgba(157, 204, 243, 0.16);
  --accent: var(--race);

  --display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --text: "Newsreader", Georgia, "Times New Roman", serif;
  --mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;

  --col: min(1180px, 100% - 3rem);
  --rail: 76px;
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);

  /*
   * One grade for every photograph on the site. The portfolio images are vivid,
   * high-saturation blue and the page is deep ink, so ungraded they read as a
   * different website pasted in. Applied in one place so they cannot drift.
   */
  --grade: saturate(0.78) contrast(1.04) brightness(0.95);

  --step--1: clamp(0.75rem, 0.72rem + 0.14vw, 0.83rem);
  --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.14rem);
  --step-1: clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
  --step-2: clamp(1.6rem, 1.35rem + 1.2vw, 2.4rem);
  --step-3: clamp(2.1rem, 1.6rem + 2.4vw, 3.6rem);
  --step-4: clamp(2.8rem, 1.7rem + 5vw, 6rem);
  /* Capped so the wordmark cannot reach the hero photograph. See .hero-inner. */
  --step-5: clamp(3rem, 0.8rem + 9.5vw, 7.5rem);
}

/* ---------------------------------------------------------------- reset */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--fg);
  font-family: var(--text);
  font-size: var(--step-0);
  line-height: 1.62;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

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

a {
  color: inherit;
  text-underline-offset: 0.22em;
  text-decoration-thickness: from-font;
}

h1,
h2,
h3,
h4 {
  font-family: var(--display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: -0.015em;
  margin: 0;
  text-wrap: balance;
}

p {
  margin: 0 0 1em;
  text-wrap: pretty;
}

:focus-visible {
  outline: 2px solid var(--race);
  outline-offset: 3px;
  border-radius: 1px;
}

::selection {
  background: var(--race);
  color: var(--ink);
}

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

.skip {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 200;
  padding: 0.75rem 1.25rem;
  background: var(--race);
  color: var(--ink);
  font-family: var(--mono);
  font-size: var(--step--1);
  transform: translateY(-110%);
}

.skip:focus {
  transform: none;
}

/* ------------------------------------------------------------- primitives */

.wrap {
  width: var(--col);
  margin-inline: auto;
}

/*
 * Section rhythm.
 *
 * Every section used to pay a full pad at the top and again at the bottom, so
 * the gap between any two of them was double: 137px + 137px = 274px of nothing,
 * which read as a layout fault after the archive and after the press list. The
 * pad is now half the intended gap, and two adjacent sections add up to it.
 */
section {
  background: var(--ground);
  color: var(--fg);
  position: relative;
  padding-block: clamp(2.4rem, 4.5vw, 4.5rem);
  transition: background-color 600ms linear;
}

/* The last section before the footer has nothing beneath it to share with. */
main > section:last-of-type {
  padding-bottom: clamp(4rem, 7vw, 7rem);
}

/*
 * Sections abut as flat colour blocks, which turns the temperature descent into
 * a row of hard steps. Carrying a short band of the previous section's ground
 * into the top of each one makes the change read as a slope instead of a cut.
 * `--from` is the ground of whatever sits above.
 */
section:not(.hero)::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: clamp(90px, 13vh, 200px);
  background: linear-gradient(to bottom, var(--from, transparent), transparent);
  pointer-events: none;
  z-index: 0;
}

section:not(.hero) > .wrap {
  position: relative;
  z-index: 1;
}

/* Temperature ladder. Warm at the origin, Arctic at the end. */
#story {
  --from: var(--ink);
}

#career {
  --from: var(--ink-warm);
}

#footprint {
  --from: var(--ink-cool);
}

#beyond {
  --from: var(--navy);
}

#record {
  --from: var(--ink-cool);
}

#media {
  --from: var(--ink);
}

#partners {
  --from: var(--ink-deep);
}

#contact {
  --from: var(--navy);
}

#story {
  --ground: var(--ink-warm);
  --rule: rgba(142, 132, 116, 0.26);
  --fg-dim: #a89c89;
}

#career {
  --ground: var(--ink-cool);
}

#footprint {
  --ground: var(--navy);
  --rule: rgba(157, 204, 243, 0.2);
}

#beyond {
  --ground: var(--ink-cool);
}

#record {
  --ground: var(--ink);
}

#media {
  --ground: var(--ink-deep);
}

#gallery {
  --ground: var(--ink-deep);
}

#partners {
  --ground: var(--navy);
  --rule: rgba(157, 204, 243, 0.2);
}

#contact {
  --ground: var(--ink-deep);
}

.eyebrow {
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-dim);
  margin: 0;
}

.section-head {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0 1.5rem;
  align-items: baseline;
  padding-top: 1.25rem;
  margin-bottom: clamp(2.5rem, 5vw, 4.5rem);
}

/* The rule is a pseudo-element rather than a border so it can be drawn, which
   echoes the track being cut rather than simply appearing. */
.section-head::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  background: var(--rule);
  transform-origin: left center;
}

.section-head .idx {
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--accent);
  letter-spacing: 0.1em;
}

.section-head h2 {
  font-size: var(--step-3);
  font-stretch: 88%;
  max-width: 18ch;
}

.section-head .lede {
  grid-column: 2;
  margin-top: 1rem;
  max-width: 58ch;
  color: var(--fg-dim);
  font-size: var(--step-1);
  line-height: 1.5;
}

.rule {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 0;
}

.mono {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------ track */

.track-rail {
  position: fixed;
  inset-block: 0;
  left: 0;
  width: var(--rail);
  z-index: 40;
  pointer-events: none;
  display: none;
}

.rail-svg {
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

/* Before she reaches snow there is no cut track, only a line of travel. */
.track-rail .approach {
  stroke: rgba(157, 204, 243, 0.3);
  stroke-width: 1;
  stroke-dasharray: 1 6;
  stroke-linecap: round;
  fill: none;
}

.track-rail .groove {
  stroke: rgba(157, 204, 243, 0.2);
  stroke-width: 1.25;
  fill: none;
}

/* Distance markers, on the international stretch only. */
.track-rail .ticks line {
  stroke: rgba(157, 204, 243, 0.22);
  stroke-width: 1;
}

.track-rail .cut {
  stroke: var(--glacier);
  stroke-width: 1.5;
  fill: none;
  opacity: 0.8;
}

/* The two skis. They trade the lead as you scroll, which is the stride. */
.track-rail .ski {
  stroke: var(--race);
  stroke-width: 2.5;
  stroke-linecap: round;
  fill: none;
}

.rail-nodes {
  position: absolute;
  inset: 0;
}

.track-rail .node {
  position: absolute;
  left: 0;
  width: 100%;
  height: 0;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  /* Centres the dot on x=38, between the two grooves at 30 and 46. */
  padding-left: 38px;
  transform: translateY(-50%);
}

.track-rail .node i {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  margin-left: -3.5px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 1.25px rgba(157, 204, 243, 0.45);
  transition: background-color 240ms var(--ease), box-shadow 240ms var(--ease),
    transform 240ms var(--ease);
}

.track-rail .node[data-passed="true"] i {
  background: var(--glacier);
  box-shadow: 0 0 0 1.25px var(--glacier);
}

.track-rail .node[data-current="true"] i {
  background: var(--race);
  box-shadow: 0 0 0 1.25px var(--race);
  transform: scale(1.35);
}

.track-rail .rail-label {
  font-size: 0.55rem;
  letter-spacing: 0.14em;
  color: var(--fg-dim);
  text-transform: uppercase;
  white-space: nowrap;
  /* The label runs past the 76px rail and over the page, so it carries its own
     ground rather than relying on whatever is behind it. */
  text-shadow: 0 0 7px var(--ink), 0 0 3px var(--ink), 0 0 2px var(--ink);
  opacity: 0;
  transform: translateX(-4px);
  transition: opacity 240ms var(--ease), transform 240ms var(--ease),
    color 240ms var(--ease);
}

.track-rail .node[data-current="true"] .rail-label {
  opacity: 1;
  transform: none;
  color: var(--race);
}

@media (min-width: 1080px) {
  .track-rail {
    display: block;
  }

  body {
    padding-left: var(--rail);
  }
}

/* -------------------------------------------------------------------- nav */

.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.85rem clamp(1rem, 3vw, 2rem);
  /* Transparent over the hero. An 82%-opaque ink bar over an ink background
     still shows a seam across the top of the page. */
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: border-color 300ms var(--ease), background-color 300ms var(--ease);
}

.nav[data-stuck="true"] {
  background: color-mix(in srgb, var(--ink) 86%, transparent);
  backdrop-filter: blur(10px);
}

@media (min-width: 1080px) {
  .nav {
    left: var(--rail);
  }
}

.nav[data-stuck="true"] {
  border-bottom-color: var(--rule);
}

.nav-mark {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 75%;
  font-size: var(--step-0);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  line-height: 1;
}

.nav-mark span {
  display: block;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.6rem;
  letter-spacing: 0.18em;
  color: var(--fg-dim);
  margin-top: 0.28rem;
}

.nav-links {
  display: none;
  gap: clamp(1rem, 2.4vw, 2.25rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 900px) {
  .nav-links {
    display: flex;
  }
}

.nav-links a {
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--fg-dim);
  padding-block: 0.35rem;
  border-bottom: 1px solid transparent;
  transition: color 160ms var(--ease), border-color 160ms var(--ease);
}

.nav-links a:hover,
.nav-links a[aria-current="true"] {
  color: var(--fg);
  border-bottom-color: var(--race);
}

.nav-toggle {
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-right: -0.6rem;
}

@media (min-width: 900px) {
  .nav-toggle {
    display: none;
  }
}

.nav-toggle span,
.nav-toggle span::before,
.nav-toggle span::after {
  content: "";
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--fg);
  transition: transform 240ms var(--ease), opacity 160ms var(--ease);
}

.nav-toggle span::before {
  transform: translateY(-7px);
}

.nav-toggle span::after {
  transform: translateY(5.5px);
}

.nav-toggle[aria-expanded="true"] span {
  background: transparent;
}

.nav-toggle[aria-expanded="true"] span::before {
  transform: rotate(45deg);
}

.nav-toggle[aria-expanded="true"] span::after {
  transform: translateY(-1.5px) rotate(-45deg);
}

.nav-panel {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--ink);
  display: grid;
  align-content: center;
  padding: 6rem 2rem 2rem;
  gap: 0.25rem;
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform 380ms var(--ease), visibility 380ms;
}

.nav-panel[data-open="true"] {
  transform: none;
  visibility: visible;
}

.nav-panel a {
  font-family: var(--display);
  font-size: var(--step-2);
  font-stretch: 80%;
  font-weight: 700;
  text-transform: uppercase;
  text-decoration: none;
  padding-block: 0.5rem;
  border-bottom: 1px solid var(--rule);
}

/* ------------------------------------------------------------------ hero */

.hero {
  --ground: var(--ink);
  min-height: 100svh;
  display: grid;
  align-content: end;
  padding-block: 6rem 2.25rem;
  overflow: hidden;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 26%;
}

.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(6, 9, 15, 0.82) 0%, rgba(6, 9, 15, 0.35) 34%, rgba(6, 9, 15, 0.92) 82%, var(--ink) 100%),
    linear-gradient(90deg, rgba(6, 9, 15, 0.86) 0%, rgba(6, 9, 15, 0.2) 62%, rgba(6, 9, 15, 0.5) 100%);
}

@media (min-width: 900px) {
  .hero-media {
    left: auto;
    right: 0;
    width: 44%;
  }

  .hero-media::after {
    background:
      linear-gradient(90deg, var(--ink) 0%, rgba(6, 9, 15, 0.55) 38%, rgba(6, 9, 15, 0.12) 100%),
      linear-gradient(180deg, rgba(6, 9, 15, 0.5) 0%, transparent 30%, rgba(6, 9, 15, 0.75) 100%);
  }
}

.hero-inner {
  position: relative;
  z-index: 1;
}

/*
 * The photograph occupies the right 44% from 900px up, so the text is capped to
 * stop short of it. Without this the wordmark runs across her body, which is
 * the one thing the hero must not do.
 *
 * The cap goes on the children, not on .hero-inner. .hero-inner is a .wrap and
 * carries margin-inline:auto, so capping it centres the whole block and breaks
 * the left edge the rest of the page aligns to.
 */
@media (min-width: 900px) {
  .hero-inner > * {
    max-width: min(34rem, 100%);
  }

  .hero-inner > .hero-ctas {
    max-width: min(40rem, 100%);
  }
}

.hero h1 {
  font-size: var(--step-5);
  font-stretch: 70%;
  font-weight: 800;
  letter-spacing: -0.022em;
  line-height: 0.86;
  text-transform: uppercase;
  margin: 0.75rem 0 0;
  /* No max-width here. Both lines are block spans so nothing wraps, and a
     `.hero h1` rule outranks the `.hero-inner > *` cap that keeps the wordmark
     clear of the photograph. */
}

.hero h1 span {
  display: block;
}

.hero h1 .l2 {
  color: var(--glacier);
}

.hero-line {
  font-size: var(--step-2);
  line-height: 1.24;
  max-width: 19ch;
  margin: 1.25rem 0 0;
  font-weight: 400;
  color: var(--snow-hi);
}

.hero-standfirst {
  max-width: 46ch;
  margin: 0.9rem 0 0;
  color: var(--fg-dim);
  font-size: var(--step-0);
}

.hero-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1rem;
  margin-top: 1.85rem;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.8rem 1.35rem;
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  border: 1px solid var(--rule);
  color: var(--fg);
  transition: background-color 180ms var(--ease), color 180ms var(--ease),
    border-color 180ms var(--ease);
}

.btn:hover {
  border-color: var(--glacier);
}

.btn-primary {
  background: var(--race);
  color: var(--ink);
  border-color: var(--race);
  font-weight: 500;
}

.btn-primary:hover {
  background: var(--snow-hi);
  border-color: var(--snow-hi);
}

.btn-ghost {
  border-color: transparent;
  padding-inline: 0;
  color: var(--fg-dim);
  text-decoration: underline;
}

.btn-ghost:hover {
  color: var(--fg);
  border-color: transparent;
}

/* ------------------------------------------------------- proof / startlist */

.proof {
  --ground: var(--ink);
  padding-block: 0 clamp(1.5rem, 3vw, 2.75rem);
}

/*
 * The three latitudes behind the heading's number. They also give the section
 * head's empty right-hand side something to do, which every other section head
 * on the page still lacks.
 */
.anchors {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.9rem;
  align-self: start;
}

@media (min-width: 900px) {
  .section-head[data-aside="true"] {
    grid-template-columns: auto minmax(0, 1fr) minmax(220px, 0.5fr);
  }

  .section-head[data-aside="true"] .lede {
    grid-column: 2;
  }

  .anchors {
    grid-row: 2 / span 2;
    grid-column: 3;
    padding-left: clamp(1.5rem, 3vw, 3rem);
    border-left: 1px solid var(--rule);
  }
}

.anchors li {
  display: grid;
  grid-template-columns: 3.6rem 1fr;
  gap: 0.1rem 0.9rem;
  align-items: baseline;
}

.anch-lat {
  font-size: 0.95rem;
  color: var(--snow-hi);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.anch-place {
  font-size: 0.9rem;
  color: var(--fg);
}

.anch-place i {
  font-style: normal;
  color: var(--fg-dim);
  margin-left: 0.4rem;
  font-size: 0.78rem;
}

.anch-note {
  grid-column: 2;
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

/* ---- Season calendar, in the partnership section ---- */

.calendar {
  margin: 0 0 clamp(2.5rem, 5vw, 4rem);
  padding-bottom: 0.5rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.cal-note {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
  padding-bottom: 0.85rem;
  border-bottom: 1px solid var(--rule);
}

.cal-scale,
.cal-bands {
  min-width: 520px;
}

.cal-scale {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  padding: 0.7rem 0 0.9rem;
}

.cal-month {
  font-size: 0.62rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
  border-left: 1px solid var(--rule);
  padding-left: 0.5rem;
}

.cal-bands {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.55rem;
}

/* Each band is placed by month index, so the bar and its label share a row and
   the label never detaches from the span it describes. */
.cal-band {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  padding-left: var(--from);
  min-height: 2.9rem;
}

.cal-bar {
  display: block;
  width: var(--span);
  height: 3px;
  background: var(--glacier);
}

.cal-band[data-kind="train"] .cal-bar {
  background: var(--stone);
}

.cal-band[data-kind="home"] .cal-bar {
  background: var(--saffron);
}

.cal-band[data-kind="race"] .cal-bar {
  background: var(--race);
}

.cal-label {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: var(--fg);
  white-space: nowrap;
}

.cal-need {
  display: block;
  margin-top: 0.15rem;
  font-size: 0.6rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-dim);
  white-space: nowrap;
}

/*
 * Race bibs. Every plate carries a count and a noun in the same slot, so the
 * eye can read down the row and compare like with like. The previous version
 * put "3 venues" above "10 km · sprint" above "Sprint quarter-final" in one
 * column, which compares nothing.
 */
.bibs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.75rem;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 700px) {
  .bibs {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 1080px) {
  .bibs {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0.5rem;
  }
}

.bib {
  height: 100%;
  display: flex;
  flex-direction: column;
  padding: 1.1rem 1rem 1.15rem;
  border: 1px solid var(--rule);
  background: rgba(255, 255, 255, 0.014);
  transition: border-color 220ms var(--ease), background 220ms var(--ease);
}

.bib:hover {
  border-color: var(--rule-strong);
  background: rgba(255, 255, 255, 0.03);
}

.bib-count {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 80%;
  font-size: clamp(2.6rem, 5vw, 3.4rem);
  line-height: 0.85;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--snow-hi);
}

.bib-unit {
  margin-top: 0.5rem;
  font-size: 0.62rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--accent);
}

/* The perforation line across a bib. */
.bib-rule {
  display: block;
  margin: 0.85rem 0;
  height: 1px;
  background-image: linear-gradient(
    to right,
    var(--rule-strong) 0 3px,
    transparent 3px 7px
  );
  background-size: 7px 1px;
}

.bib-label {
  font-family: var(--display);
  font-weight: 600;
  font-stretch: 88%;
  font-size: 0.95rem;
  line-height: 1.15;
  margin: 0;
}

.bib-detail {
  margin: 0.45rem 0 0;
  font-size: 0.78rem;
  line-height: 1.45;
  color: var(--fg-dim);
}

.bib-year {
  margin-top: auto;
  padding-top: 0.9rem;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
}

/* ----------------------------------------------------------------- story */

.beats {
  display: grid;
  gap: clamp(3rem, 6vw, 5.5rem);
}

.beat {
  display: grid;
  gap: 1.25rem 2.5rem;
  align-items: start;
}

@media (min-width: 860px) {
  .beat {
    grid-template-columns: 7rem minmax(0, 1fr) minmax(0, 0.85fr);
  }

  .beat[data-noimage="true"] {
    grid-template-columns: 7rem minmax(0, 1fr);
  }
}

.beat-year {
  font-family: var(--mono);
  font-size: var(--step--1);
  letter-spacing: 0.08em;
  color: var(--accent);
  padding-top: 0.4rem;
  border-top: 1px solid var(--rule);
}

.beat h3 {
  font-size: var(--step-2);
  font-stretch: 90%;
  margin-bottom: 0.7rem;
  max-width: 20ch;
}

.beat p {
  max-width: 54ch;
  color: var(--fg-dim);
  margin: 0;
}

.beat figure {
  margin: 0;
}

.beat figure img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  filter: var(--grade);
}

/* Wide sources keep enough width to hold their subject. */
.beat figure[data-orient="landscape"] img {
  aspect-ratio: 1 / 1;
}

.beat figure[data-orient="pano"] img {
  aspect-ratio: 4 / 3;
}

.beat figcaption {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  margin-top: 0.6rem;
}

/* ----------------------------------------------------------- career track */

.career-track {
  position: relative;
  display: grid;
  gap: 0;
}

.career-track::before {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 6px;
  width: 10px;
  border-left: 1.25px solid var(--rule);
  border-right: 1.25px solid var(--rule);
}

@media (min-width: 860px) {
  .career-track::before {
    left: 7.5rem;
  }
}

.milestone {
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.4rem;
  padding: 1.6rem 0 1.6rem 2.75rem;
  border-bottom: 1px solid var(--rule);
}

@media (min-width: 860px) {
  .milestone {
    grid-template-columns: 6rem minmax(0, 1fr) minmax(0, 15rem);
    gap: 0.35rem 2.5rem;
    align-items: baseline;
    padding: 1.5rem 0 1.5rem 0;
  }
}

.milestone::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 2.1rem;
  width: 15px;
  height: 15px;
  background: var(--ground);
  border: 1.5px solid var(--glacier);
  border-radius: 50%;
  transition: background-color 260ms var(--ease), border-color 260ms var(--ease),
    transform 260ms var(--ease);
}

@media (min-width: 860px) {
  .milestone::after {
    left: calc(7.5rem - 3px);
    top: 1.85rem;
  }
}

.milestone[data-phase="origin"]::after {
  border-color: var(--stone);
}

.milestone[data-phase="mountain"]::after {
  border-color: var(--moss);
}

.milestone[data-phase="worldcup"]::after {
  background: var(--race);
  border-color: var(--race);
}

.milestone[data-inview="true"]::after {
  transform: scale(1.25);
}

.milestone-year {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--step-1);
  color: var(--accent);
  letter-spacing: 0.02em;
}

.milestone h3 {
  font-size: var(--step-1);
  font-stretch: 92%;
  font-weight: 600;
  margin-bottom: 0.35rem;
}

.milestone .place {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
  display: block;
  margin-bottom: 0.55rem;
}

.milestone p {
  margin: 0;
  color: var(--fg-dim);
  font-size: calc(var(--step-0) * 0.96);
  max-width: 52ch;
}

.milestone .result {
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--fg);
  letter-spacing: 0.04em;
  align-self: baseline;
}

@media (min-width: 860px) {
  .milestone .result {
    text-align: right;
  }
}

.milestone .src {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.65rem;
  letter-spacing: 0.08em;
  color: var(--fg-dim);
  opacity: 0.75;
  text-transform: uppercase;
  text-decoration: none;
  /* Keeps the hit area at the 24px WCAG 2.2 minimum without moving the rule. */
  padding-block: 0.4rem;
  border-bottom: 0;
  text-decoration: underline;
  text-underline-offset: 0.3em;
  text-decoration-thickness: 1px;
}

.milestone .src:hover {
  opacity: 1;
  color: var(--race);
}

/* -------------------------------------------------------- signature stat */

.latstat {
  display: grid;
  gap: 1.5rem 3rem;
  margin-top: clamp(3rem, 6vw, 5rem);
  padding-top: 2.5rem;
  border-top: 1px solid var(--rule);
}

@media (min-width: 860px) {
  .latstat {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
  }
}

.latstat h3 {
  font-size: var(--step-3);
  font-stretch: 85%;
  max-width: 15ch;
}

.latstat p {
  color: var(--fg-dim);
  max-width: 48ch;
  margin: 0;
}

.latstat .figs {
  display: flex;
  gap: 2.5rem;
  margin-top: 1.5rem;
  font-family: var(--mono);
}

.latstat .figs div {
  display: grid;
  gap: 0.3rem;
}

.latstat .figs b {
  font-size: var(--step-2);
  font-weight: 500;
  color: var(--race);
  letter-spacing: -0.02em;
}

.latstat .figs span {
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

/* ------------------------------------------------------------- footprint */

/* ---- The atlas -------------------------------------------------------------
 *
 * Equirectangular, so latitude stays linear and the named parallels remain
 * straight lines. The coastline is Natural Earth 110m, simplified to a single
 * inline path by tools/gen_worldmap.py. No tiles, no mapping library, no
 * network call at runtime.
 */

/*
 * Map and detail panel sit side by side rather than the panel floating over the
 * map. A floating card had to live inside the horizontally scrolling map box,
 * and `overflow-x: auto` forces the vertical axis to clip too, so any card
 * positioned above its own marker was cut off at the top edge. Docking it also
 * gives the photographs a full-width slot instead of a 268px sliver.
 */
.atlas {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 310px);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  align-items: start;
}

.atlas-scroll {
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  padding-bottom: 0.5rem;
}

.atlas-map {
  width: 100%;
  min-width: 620px;
  height: auto;
  display: block;
}

@media (max-width: 900px) {
  .atlas {
    grid-template-columns: 1fr;
  }
}

/* Land sits just above the section ground: present, never competing with the
   markers. Country borders are deliberately absent, they add political noise
   to what is a record of races. */
.atlas-map .land {
  fill: rgba(157, 204, 243, 0.09);
  stroke: rgba(157, 204, 243, 0.28);
  stroke-width: 0.35;
  stroke-linejoin: round;
}

.atlas-map .grat {
  stroke: rgba(157, 204, 243, 0.08);
  stroke-width: 0.3;
}

.atlas-map .grat-named {
  stroke: rgba(157, 204, 243, 0.26);
  stroke-width: 0.35;
  stroke-dasharray: 1.6 1.6;
}

.atlas-map .grat-label {
  font-family: var(--mono);
  font-size: 3.1px;
  letter-spacing: 0.09em;
  fill: var(--fg-dim);
  text-transform: uppercase;
}

.atlas-map .pin {
  cursor: pointer;
}

/* Invisible, and the only reason a 5px dot is a usable target. */
.atlas-map .halo {
  fill: transparent;
}

.atlas-map .dot {
  fill: var(--glacier);
  stroke: var(--ground);
  stroke-width: 0.7;
  transition: fill 180ms var(--ease), r 180ms var(--ease);
}

.atlas-map .pin[data-kind="origin"] .dot {
  fill: var(--saffron);
}

.atlas-map .pin[data-kind="podium"] .dot,
.atlas-map .pin[data-kind="worldcup"] .dot {
  fill: var(--race);
}

.atlas-map .pin[data-kind="domestic"] .dot {
  fill: var(--stone);
}

.atlas-map .pin:hover .dot,
.atlas-map .pin:focus-visible .dot,
.atlas-map .pin[data-active="true"] .dot {
  fill: var(--snow-hi);
  r: 2.9;
}

.atlas-map .pin-label {
  font-family: var(--mono);
  font-size: 3.4px;
  letter-spacing: 0.04em;
  fill: var(--fg);
  paint-order: stroke;
  stroke: var(--ground);
  stroke-width: 1.1px;
  stroke-linejoin: round;
  pointer-events: none;
}

.atlas-map .pin:focus {
  outline: none;
}

.atlas-map .pin:focus-visible .halo {
  fill: rgba(215, 242, 94, 0.16);
  stroke: var(--race);
  stroke-width: 0.5;
}

/* ---- The card that opens off a marker ---- */

/* Reserves the tallest card's height so switching markers does not shunt the
   table below up and down. */
.atlas-panel {
  border: 1px solid var(--rule);
  background: rgba(255, 255, 255, 0.015);
  position: relative;
}

/* Holds the tallest card's height. Without it the panel grows when a card
   carries a photograph and shunts the whole results table down the page. */
@media (min-width: 901px) {
  .atlas-panel {
    min-height: 432px;
  }
}

.atlas-card[hidden] {
  display: none;
}

.atlas-card {
  animation: card-in 320ms var(--ease) both;
}

.atlas-card.is-resting .card-event {
  color: var(--fg-soft);
}

@keyframes card-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

@media (prefers-reduced-motion: reduce) {
  .atlas-card {
    animation: none;
  }
}

.card-shot {
  margin: 0;
}

.card-shot img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  filter: var(--grade);
}

/* The venue's own geography, for the ten places with no photograph. Reuses the
   single land path through <use>, so it adds no weight to the page. */
.card-mini svg {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--ink-deep);
}

.card-mini .land,
.card-mini use {
  fill: rgba(157, 204, 243, 0.17);
  stroke: rgba(157, 204, 243, 0.5);
  stroke-width: 0.16;
  stroke-linejoin: round;
}

.card-mini .mini-dot {
  fill: var(--race);
}

.card-mini .mini-ring {
  fill: none;
  stroke: var(--race);
  stroke-width: 0.3;
  opacity: 0.55;
}

.card-mini figcaption {
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  color: var(--fg-dim);
  padding: 0.5rem 0.95rem 0;
}

.card-shot figcaption {
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  padding: 0.4rem 0.85rem 0;
  text-transform: uppercase;
}

.card-body {
  padding: 0.85rem 0.95rem 0.95rem;
}

.card-place {
  font-family: var(--display);
  font-size: 1.15rem;
  line-height: 1.1;
  margin: 0;
}

.card-place span {
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  color: var(--fg-dim);
  text-transform: uppercase;
  display: block;
  margin-top: 0.25rem;
}

.card-event {
  margin: 0.55rem 0 0;
  font-size: 0.82rem;
  color: var(--fg-soft);
}

.card-best {
  margin: 0.35rem 0 0;
  font-size: 0.9rem;
  color: var(--snow-hi);
}

.card-meta {
  margin: 0.6rem 0 0;
  font-size: 0.62rem;
  letter-spacing: 0.1em;
  color: var(--fg-dim);
}

.atlas .plot-legend {
  margin-top: 1rem;
}

/*
 * The map says it better, so the table is folded away. It cannot simply be
 * deleted: it is the map's non-visual equivalent, and a screen reader user has
 * no other route to the same information.
 */
.atlas-list {
  margin-top: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--rule);
}

.atlas-list > summary {
  cursor: pointer;
  padding: 1rem 0;
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-dim);
  transition: color 160ms var(--ease);
}

.atlas-list > summary:hover,
.atlas-list > summary:focus-visible {
  color: var(--snow-hi);
}

.atlas-list[open] > summary {
  color: var(--fg);
}

.plot-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: 1.25rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-dim);
  list-style: none;
  padding: 0;
}

.plot-legend li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.plot-legend i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--glacier);
}

.plot-legend i[data-kind="origin"] {
  background: var(--saffron);
}

.plot-legend i[data-kind="race"] {
  background: var(--race);
}

.plot-legend i[data-kind="domestic"] {
  background: var(--stone);
}

.plot-readout {
  margin-top: 1.25rem;
  min-height: 3.2rem;
  border-top: 1px solid var(--rule);
  padding-top: 1rem;
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--fg-dim);
}

.plot-readout b {
  color: var(--fg);
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Fallback list. Always in the DOM, hidden only when the plot is usable. */
.plot-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--mono);
  font-size: var(--step--1);
  margin-top: 2rem;
}

.plot-table th,
.plot-table td {
  text-align: left;
  padding: 0.55rem 0.75rem 0.55rem 0;
  border-bottom: 1px solid var(--rule);
  color: var(--fg-dim);
}

.plot-table th {
  color: var(--fg);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.68rem;
}

/* ------------------------------------------------------- mountain / beyond */

.peaks {
  display: grid;
  gap: 2rem;
  margin-bottom: clamp(3rem, 6vw, 4.5rem);
}

@media (min-width: 760px) {
  .peaks {
    grid-template-columns: 1fr 1fr;
    gap: 3rem;
  }
}

.peak {
  display: grid;
  gap: 0.75rem;
  align-content: start;
}

.peak img {
  width: 100%;
  aspect-ratio: 16 / 7;
  object-fit: cover;
  filter: var(--grade);
}

/*
 * The altitude reads as a measured rule, not as a block. An earlier version used
 * a 200px filled bar, which at this column width became a large gradient slab
 * that looked like decoration and outweighed the photograph beside it.
 */
.peak .scale {
  height: 2px;
  background: var(--rule);
  margin-top: -0.35rem;
}

.peak .scale i {
  display: block;
  height: 100%;
  background: var(--race);
  transition: width 800ms var(--ease);
}

.peak .metres {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--step-2);
  color: var(--race);
  letter-spacing: -0.02em;
}

.peak h3 {
  font-size: var(--step-1);
  font-stretch: 92%;
}

.peak .country {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

.peak p {
  color: var(--fg-dim);
  margin: 0;
  max-width: 40ch;
  font-size: calc(var(--step-0) * 0.96);
}

/*
 * The training route, in four steps.
 *
 * Seven certificates in two even columns read as a CV dump and hid the only
 * interesting thing in the data: climbing qualified her to instruct,
 * instructing put her on skis, and skiing took her abroad.
 */
.croute {
  list-style: none;
  margin: 1.25rem 0 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--rule);
  border-block: 1px solid var(--rule);
}

@media (min-width: 820px) {
  .croute {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.cstep {
  background: var(--ground);
  padding: 1.4rem 1.25rem 1.5rem;
  display: flex;
  flex-direction: column;
}

.cstep-idx {
  font-size: 0.62rem;
  letter-spacing: 0.16em;
  color: var(--accent);
}

.cstep h4 {
  margin: 0.6rem 0 0;
  font-family: var(--display);
  font-weight: 600;
  font-stretch: 88%;
  font-size: var(--step-1);
  line-height: 1.1;
}

.cstep-note {
  margin: 0.45rem 0 1.1rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: var(--fg-dim);
}

.cstep-items {
  list-style: none;
  margin: auto 0 0;
  padding: 0;
  display: grid;
  gap: 0.85rem;
}

.cstep-items li {
  padding-top: 0.85rem;
  border-top: 1px solid var(--rule);
}

.cstep-items b {
  display: block;
  font-size: 0.9rem;
  line-height: 1.25;
  font-weight: 500;
}

.cstep-items span {
  display: block;
  margin-top: 0.3rem;
  font-family: var(--mono);
  font-size: 0.64rem;
  letter-spacing: 0.06em;
  line-height: 1.5;
  color: var(--fg-dim);
}

/* --------------------------------------------------------------- results */

.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-bottom: 1.75rem;
}

.filters button {
  padding: 0.5rem 1rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
  transition: color 160ms var(--ease), border-color 160ms var(--ease),
    background-color 160ms var(--ease);
}

.filters button:hover {
  color: var(--fg);
  border-color: var(--glacier);
}

.filters button[aria-pressed="true"] {
  background: var(--snow-hi);
  border-color: var(--snow-hi);
  color: var(--ink);
}

.results {
  width: 100%;
  border-collapse: collapse;
  font-size: calc(var(--step-0) * 0.95);
}

.results caption {
  text-align: left;
  color: var(--fg-dim);
  font-size: var(--step--1);
  font-family: var(--mono);
  padding-bottom: 1rem;
  max-width: 62ch;
  line-height: 1.6;
}

.results th {
  text-align: left;
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--fg-dim);
  font-weight: 400;
  padding: 0 0.9rem 0.7rem 0;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}

.results td {
  padding: 0.85rem 0.9rem 0.85rem 0;
  border-bottom: 1px solid var(--rule);
  vertical-align: baseline;
}

.results tbody tr {
  transition: background-color 140ms var(--ease);
}

.results tbody tr:hover {
  background: rgba(157, 204, 243, 0.045);
}

.results .c-year,
.results .c-mark {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: var(--step--1);
  white-space: nowrap;
}

.results .c-year {
  color: var(--accent);
  width: 4rem;
}

.results .c-event {
  font-family: var(--display);
  font-stretch: 92%;
  font-weight: 600;
}

.results .c-event small {
  display: block;
  font-family: var(--mono);
  font-weight: 400;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  margin-top: 0.2rem;
}

.results .c-place {
  color: var(--fg-dim);
  font-family: var(--mono);
  font-size: var(--step--1);
}

.results .c-medal {
  width: 2.5rem;
}

.medal-dot {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: transparent;
  border: 1px solid var(--fg-dim);
}

.medal-dot[data-medal="gold"] {
  background: #e7b74a;
  border-color: #e7b74a;
}

.medal-dot[data-medal="silver"] {
  background: #b9c4cc;
  border-color: #b9c4cc;
}

.medal-dot[data-medal="bronze"] {
  background: #b0763f;
  border-color: #b0763f;
}

/* A marker used to trail unverified rows here. Provenance is tracked in the
   content model, not printed beside her results. */

.src-flag {
  display: inline-block;
  /* Short source labels like "FIS" would otherwise be a 20px-wide target. */
  min-width: 1.5rem;
  padding-block: 0.4rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
  opacity: 0.7;
  white-space: nowrap;
}

a.src-flag:hover {
  opacity: 1;
  color: var(--race);
}

/* Six columns need real width. Below the layout's main 900px breakpoint the
   table becomes one card per result instead of compressing. */
@media (max-width: 899px) {
  .results thead {
    display: none;
  }

  .results,
  .results tbody,
  .results tr,
  .results td {
    display: block;
    width: 100%;
  }

  .results tr {
    padding: 1rem 0;
    border-bottom: 1px solid var(--rule);
    position: relative;
  }

  .results td {
    border: 0;
    padding: 0 0 0.25rem;
  }

  .results .c-medal {
    position: absolute;
    top: 1.15rem;
    right: 0;
    width: auto;
  }
}

.record-more {
  margin-top: 1.75rem;
}

/* ----------------------------------------------------------------- media */

.press-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
}

.press-list li {
  border-bottom: 1px solid var(--rule);
}

.press-list a {
  display: grid;
  gap: 0.3rem 2rem;
  padding: 1.5rem 0;
  text-decoration: none;
  transition: opacity 160ms var(--ease);
}

@media (min-width: 860px) {
  .press-list a {
    grid-template-columns: 12rem minmax(0, 1fr) auto;
    align-items: baseline;
  }
}

.press-list a:hover {
  opacity: 0.72;
}

.press-pub {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--accent);
}

.press-title {
  font-family: var(--display);
  font-stretch: 92%;
  font-weight: 600;
  font-size: var(--step-1);
  line-height: 1.2;
}

.press-context {
  grid-column: 2;
  color: var(--fg-dim);
  font-size: calc(var(--step-0) * 0.94);
  margin-top: 0.35rem;
  max-width: 56ch;
}

@media (max-width: 859px) {
  .press-context {
    grid-column: 1;
  }
}

.press-date {
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--fg-dim);
  white-space: nowrap;
}

/* --------------------------------------------------------------- gallery */

.gal {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0.5rem;
}

@media (min-width: 760px) {
  .gal {
    grid-template-columns: repeat(4, 1fr);
    gap: 0.75rem;
  }
}

.gal button {
  position: relative;
  display: block;
  padding: 0;
  overflow: hidden;
  background: var(--ink);
}

.gal button img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 3 / 4;
  transition: transform 500ms var(--ease), filter 300ms var(--ease);
  filter: var(--grade);
}

.gal button:hover img,
.gal button:focus-visible img {
  transform: scale(1.035);
  filter: none;
}

.gal button[hidden] {
  display: none;
}

.gal-cat {
  position: absolute;
  left: 0.6rem;
  bottom: 0.6rem;
  font-family: var(--mono);
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--snow-hi);
  background: rgba(6, 9, 15, 0.7);
  padding: 0.28rem 0.5rem;
  opacity: 0;
  transition: opacity 200ms var(--ease);
}

.gal button:hover .gal-cat,
.gal button:focus-visible .gal-cat {
  opacity: 1;
}

/* lightbox */
.lb {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(4, 7, 12, 0.97);
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: 1rem;
  opacity: 0;
  visibility: hidden;
  transition: opacity 240ms var(--ease), visibility 240ms;
}

.lb[data-open="true"] {
  opacity: 1;
  visibility: visible;
}

.lb-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--fg-dim);
  letter-spacing: 0.08em;
}

.lb-stage {
  display: grid;
  place-items: center;
  min-height: 0;
  padding: 1rem 0;
}

.lb-stage img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

.lb-foot {
  display: grid;
  gap: 0.4rem 2rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--rule);
}

@media (min-width: 760px) {
  .lb-foot {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
  }
}

.lb-cap {
  max-width: 68ch;
  color: var(--fg);
  font-size: calc(var(--step-0) * 0.95);
  margin: 0;
}

.lb-credit {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

.lb-nav {
  display: flex;
  gap: 0.5rem;
}

.lb-nav button,
.lb-close {
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  color: var(--fg);
  transition: border-color 160ms var(--ease), background-color 160ms var(--ease);
}

.lb-nav button:hover,
.lb-close:hover {
  border-color: var(--glacier);
}

.lb-nav button[disabled] {
  opacity: 0.3;
  cursor: default;
}

/* -------------------------------------------------------------- partners */

.areas {
  display: grid;
  gap: 0;
  border-top: 1px solid var(--rule);
}

.area {
  display: grid;
  gap: 0.4rem 2.5rem;
  padding: 1.75rem 0;
  border-bottom: 1px solid var(--rule);
}

@media (min-width: 860px) {
  .area {
    grid-template-columns: 4rem minmax(0, 16rem) minmax(0, 1fr);
    align-items: baseline;
  }
}

.area .idx {
  font-family: var(--mono);
  font-size: var(--step--1);
  color: var(--accent);
  letter-spacing: 0.1em;
}

.area h3 {
  font-size: var(--step-1);
  font-stretch: 92%;
  font-weight: 600;
}

.area p {
  margin: 0;
  color: var(--fg-dim);
  max-width: 54ch;
  font-size: calc(var(--step-0) * 0.96);
}

.partner-note {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--fg-dim);
  max-width: 60ch;
  margin-top: 2rem;
  line-height: 1.75;
  border-left: 1px solid var(--rule);
  padding-left: 1.25rem;
}

/* --------------------------------------------------------------- contact */

.contact-grid {
  display: grid;
  gap: 2.5rem 4rem;
}

@media (min-width: 860px) {
  .contact-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
}

.contact-lines {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
}

.contact-lines li {
  border-bottom: 1px solid var(--rule);
}

.contact-lines a {
  display: grid;
  grid-template-columns: 6.5rem 1fr;
  gap: 1rem;
  align-items: baseline;
  padding: 1.15rem 0;
  text-decoration: none;
  transition: color 160ms var(--ease);
}

.contact-lines a:hover {
  color: var(--race);
}

.contact-lines .k {
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

.contact-lines .v {
  font-family: var(--display);
  font-stretch: 92%;
  font-weight: 600;
  font-size: var(--step-1);
  overflow-wrap: anywhere;
}

.enquiry {
  display: grid;
  gap: 0.9rem;
  align-content: start;
}

.enquiry label {
  display: grid;
  gap: 0.4rem;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--fg-dim);
}

.enquiry input,
.enquiry textarea {
  font: inherit;
  font-size: calc(var(--step-0) * 0.95);
  color: var(--fg);
  background: rgba(157, 204, 243, 0.05);
  border: 1px solid var(--rule);
  padding: 0.75rem 0.9rem;
  width: 100%;
}

.enquiry textarea {
  min-height: 7rem;
  resize: vertical;
}

.enquiry .btn {
  justify-self: start;
}

.enquiry .note {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.06em;
  line-height: 1.7;
  color: var(--fg-dim);
  text-transform: none;
}

/* ---------------------------------------------------------------- footer */

.foot {
  background: var(--ink-deep);
  color: var(--fg-dim);
  padding-block: 3rem;
  border-top: 1px solid var(--rule);
}

.foot-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2.5rem;
  justify-content: space-between;
  align-items: baseline;
  font-family: var(--mono);
  font-size: 0.68rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.foot a {
  display: inline-block;
  padding-block: 0.35rem;
  text-decoration: none;
  border-bottom: 1px solid var(--rule);
}

.foot a:hover {
  color: var(--fg);
}

/* -------------------------------------------------------- motion, entrance */

/*
 * Motion.
 *
 * The base state of everything here is *visible*. Motion is opted into by the
 * `js` class, which an inline script in <head> sets synchronously, and the
 * hidden-to-visible states are keyframes rather than a class the page has to
 * arrive at later. That ordering matters: an earlier version gated visibility
 * on a class added inside requestAnimationFrame, which left the athlete's name
 * and every revealed block permanently invisible in any context where rAF is
 * starved — a background tab, a prerender, a screenshotting bot.
 */
@media (prefers-reduced-motion: no-preference) {
  /*
   * Scroll reveals. Two moves only, and deliberately so.
   *
   *   up     text, rows and cards rise 16px and fade in
   *   clip   photographs wipe up from their lower edge
   *
   * Rules that keep it from becoming noise: each element runs once, nothing
   * scales or rotates or blurs, the stagger is 55ms and caps at six steps, and
   * nothing at all animates in the hero beyond its single entrance sequence.
   */
  .js [data-anim] {
    --i: 0;
    transition:
      opacity 620ms var(--ease),
      transform 620ms var(--ease),
      clip-path 780ms var(--ease);
    transition-delay: calc(var(--i) * 55ms);
    will-change: opacity, transform;
  }

  .js [data-anim="up"] {
    opacity: 0;
    transform: translateY(16px);
  }

  .js [data-anim="clip"] {
    opacity: 0;
    clip-path: inset(0 0 22% 0);
  }

  .js [data-anim][data-shown="true"] {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 0 0);
    will-change: auto;
  }

  /* The section rule draws left to right as the heading arrives. */
  .js .section-head::before {
    transform: scaleX(0);
    transition: transform 900ms var(--ease) 80ms;
  }

  .js .section-head[data-shown="true"]::before {
    transform: scaleX(1);
  }

  .js .hero h1 span {
    animation: line-up 900ms var(--ease) both;
  }

  .js .hero h1 .l2 {
    animation-delay: 110ms;
  }

  .js .hero-media img {
    animation: settle 1600ms var(--ease) both;
  }

  @keyframes line-up {
    from {
      clip-path: inset(0 0 105% 0);
    }
    to {
      clip-path: inset(0 0 -10% 0);
    }
  }

  @keyframes settle {
    from {
      transform: scale(1.06);
    }
    to {
      transform: none;
    }
  }
}

/*
 * Escape hatch for a document that is not compositing. Neither transitions nor
 * animations advance while the page is hidden, so any state they were meant to
 * arrive at is never reached and the content they hide stays hidden. When that
 * is the case we drop the motion entirely and jump to the end state.
 */
.anim-off *,
.anim-off *::before,
.anim-off *::after {
  animation: none !important;
  transition: none !important;
}

.anim-off [data-anim] {
  opacity: 1 !important;
  transform: none !important;
  clip-path: none !important;
}

.anim-off .section-head::before {
  transform: none !important;
}

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

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
