/* Adthletics - landing page only. Loads after site.css (tokens, type,
   buttons, header and footer). */

/* ---------- Hero: athletes | lightning bolt | brands ---------- */

.hero {
  position: relative; /* the storm overlay covers exactly this section */
  padding-block: clamp(48px, 7vw, 88px) 96px;
}

/* A real athlete left of the athletes' half: the athletes' card photo, with
   its white mapped to the page cream instead (img/athlete-cyclist-hero.webp),
   laid over the hero without changing it. .hero-photo covers the hero and
   clips; its ::before is the photo at 150% of the hero's height (a sixth
   cut off top and bottom), touching the screen's left edge, its left side
   cropped off-screen (part of the rider too) so its right side, uncropped,
   runs only a little under the text. The fades are long and eased so no
   edge shows: out over the trees right of the rider (40-68% across), and
   in under the header (::after, the page colour). From 1360px only:
   narrower, too much of the rider would be off-screen. */
.hero-photo { display: none; }

@media (min-width: 1360px) {
  .hero > .wrap { position: relative; } /* painted after the photo: text on top */

  .hero-photo {
    display: block;
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
  }

  .hero-photo::before {
    content: "";
    position: absolute;
    top: -25%;
    left: 0;
    height: 150%;
    aspect-ratio: 2 / 3;
    /* Cropped on the left: the rider's right edge at 50vw - 654px, about
       the page content's left edge - 67px (100vw counts the scrollbar), so
       less of the photo's right side runs under the text; but never more
       than ~55% of the rider off-screen (-57%), and never right of 0, so
       the photo always touches the screen's edge. */
    transform: translateX(min(0px, max(-57%, calc(50vw - 654px - 67.8%))));
    background: url("/img/athlete-cyclist-hero.webp") center / cover no-repeat;
    /* The right side uncropped, eased out over the trees right of the
       rider. One mask only: two composited masks left a 1px line. */
    -webkit-mask-image: linear-gradient(to right, #000 67%, rgba(0, 0, 0, 0.97) 70.1%, rgba(0, 0, 0, 0.9) 73.2%, rgba(0, 0, 0, 0.78) 76.3%, rgba(0, 0, 0, 0.63) 79.4%, rgba(0, 0, 0, 0.5) 82.5%, rgba(0, 0, 0, 0.37) 85.6%, rgba(0, 0, 0, 0.22) 88.7%, rgba(0, 0, 0, 0.1) 91.8%, rgba(0, 0, 0, 0.03) 94.9%, transparent 98%);
    mask-image: linear-gradient(to right, #000 67%, rgba(0, 0, 0, 0.97) 70.1%, rgba(0, 0, 0, 0.9) 73.2%, rgba(0, 0, 0, 0.78) 76.3%, rgba(0, 0, 0, 0.63) 79.4%, rgba(0, 0, 0, 0.5) 82.5%, rgba(0, 0, 0, 0.37) 85.6%, rgba(0, 0, 0, 0.22) 88.7%, rgba(0, 0, 0, 0.1) 91.8%, rgba(0, 0, 0, 0.03) 94.9%, transparent 98%);
  }

  /* Fades in under the header: the page colour over the photo's top. */
  .hero-photo::after {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 22%;
    background: linear-gradient(to bottom, var(--page), rgba(246, 239, 224, 0.97) 10%, rgba(246, 239, 224, 0.9) 20%, rgba(246, 239, 224, 0.78) 30%, rgba(246, 239, 224, 0.63) 40%, rgba(246, 239, 224, 0.5) 50%, rgba(246, 239, 224, 0.37) 60%, rgba(246, 239, 224, 0.22) 70%, rgba(246, 239, 224, 0.1) 80%, rgba(246, 239, 224, 0.03) 90%, rgba(246, 239, 224, 0));
  }
}

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(56px, 7vw, 100px) minmax(0, 1fr);
  column-gap: clamp(16px, 3vw, 44px);
}

.half {
  container-type: inline-size;
  display: grid;
  align-content: start;
  justify-items: start;
  gap: 22px;
}

.half-eyebrow { color: var(--ink-soft); }

/* Side by side, the athletes half is right-aligned so both texts sit the same
   distance from the bolt (left-aligned, its ragged lines left a wide gap).
   Stacked (860px and below) both halves are left-aligned. */
@media (min-width: 861px) {
  .split > .half:first-child {
    justify-items: end;
    text-align: right;
  }
}

/* Sized by the half's own width (cqi), so each title always breaks into two
   lines, with the emphasised words kept together on the second: the widest
   line, "competes too." / "también compite.", is about 9.2 / 11 times the
   font size. */
.half-title { font-size: clamp(32px, 10.1cqi, 60px); }
:lang(es) .half-title { font-size: clamp(28px, 8.6cqi, 50px); }
/* The second line is italic ink; only its key word (.accent, set by
   landing.js per language) is accent colour. */
.half-title em {
  display: inline-block;
  color: inherit;
}

.half-title .accent { color: var(--accent); }

.half-lead {
  max-width: 54ch; /* two lines in Spanish too */
  font-size: 18px;
  color: var(--ink-soft);
}

.half .btn { margin-top: 4px; }

.hero-note {
  margin-top: -8px;
  font-size: 14px;
  color: var(--ink-soft);
}

/* The bolt stretches to the height of the halves (preserveAspectRatio none)
   while its stroke keeps a constant width. Below 860px the halves stack and a
   horizontal bolt takes over. It sits above the storm overlay (z-index). */
.bolt {
  position: relative;
  z-index: 21;
}

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

/* A filled ribbon with pointed ends (js/bolt-shape.js), not a stroke. */
.bolt polygon { fill: var(--ink); }

/* The glow copy of the shape: its fill is a radial gradient that
   landing.js centres on the mouse, so only the stretch of bolt under the
   cursor lights up. Fades in while the mouse is over the hero. */
.bolt .bolt-glow {
  opacity: 0;
  transition: opacity 0.25s ease;
}

.bolt-v .bolt-glow { fill: url(#bolt-glow-v); }
.bolt-h .bolt-glow { fill: url(#bolt-glow-h); }

.bolt.is-lit .bolt-glow { opacity: 0.6; } /* subtle: the ink shows through */

.bolt-v { display: block; }
.bolt-h { display: none; }

/* ---------- Lightning strike ----------
   The hero darkens, the bolt strikes glowing white with a double flash, then
   the colours come back and the bolt cools to ink. Only the hero section:
   the header and the sections below are untouched. It plays once per visit
   (the inline script in index.html's <head> adds .strike to <html> on the
   first landing of the browser session) and only when motion is allowed.
   Every piece runs on the same 1.8s clock, so the percentages line up:
     0-22%   darken                 (0-400ms)
     22-28%  hold dark              (400-500ms)
     28-31%  the bolt strikes       (500-560ms)
     31-43%  two flashes            (560-775ms: under 3 flashes a second)
     31-100% back to normal colour  (560-1800ms) */

.storm {
  display: none;
  position: absolute;
  inset: 0;
  z-index: 20;
  pointer-events: none;
  background: radial-gradient(90% 70% at 50% 30%, #17223b 0%, #06080f 80%);
  opacity: 0;
}

.storm::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(70% 60% at 50% 35%, #ffffff 0%, #e3f7ff 55%, #c4ecff 100%);
  opacity: 0;
}

@media (prefers-reduced-motion: no-preference) {
  .strike .storm { display: block; animation: storm-dark 1.8s both; }
  .strike .storm::after { animation: storm-flash 1.8s linear both; }
  .strike .bolt-v { animation: bolt-strike-down 1.8s linear both, bolt-glow 1.8s ease-out both; }
  .strike .bolt-h { animation: bolt-strike-across 1.8s linear both, bolt-glow 1.8s ease-out both; }
  .strike .bolt polygon:not(.bolt-glow) { animation: bolt-cool 1.8s ease-out both; }
}

@keyframes storm-dark {
  0%   { opacity: 0; animation-timing-function: cubic-bezier(0.5, 0, 1, 1); }
  22%  { opacity: 0.9; }
  31%  { opacity: 0.9; animation-timing-function: cubic-bezier(0.1, 0, 0.3, 1); }
  100% { opacity: 0; }
}

@keyframes storm-flash {
  0%, 30%   { opacity: 0; }
  31%       { opacity: 0.9; }
  34%       { opacity: 0.05; }
  37%       { opacity: 0.5; }
  43%, 100% { opacity: 0; }
}

/* Drawn in 60ms. The negative insets leave room for the glow. */
@keyframes bolt-strike-down {
  0%, 28%   { clip-path: inset(-48px -48px calc(100% + 48px) -48px); }
  31%, 100% { clip-path: inset(-48px); }
}

@keyframes bolt-strike-across {
  0%, 28%   { clip-path: inset(-48px calc(100% + 48px) -48px -48px); }
  31%, 100% { clip-path: inset(-48px); }
}

@keyframes bolt-glow {
  0%, 31% { filter: drop-shadow(0 0 3px #ffffff) drop-shadow(0 0 12px var(--accent-bright)) drop-shadow(0 0 28px var(--accent-light)); }
  100%    { filter: none; }
}

@keyframes bolt-cool {
  0%, 37% { fill: #ffffff; }
  100%    { fill: var(--ink); }
}

/* ---------- Sports strip ---------- */

/* A ticker that runs forever: landing.js repeats the list (--copies times in
   the track) and adds .is-live; the track then slides left by exactly one copy
   per cycle, so the loop is seamless. Every name, the last one too, ends in a
   slash, so the copies join like the names inside them. Paused on hover.
   Without JS, or with reduced motion, it is a static list. */

.strip {
  padding-block: 24px 26px;
  color: var(--cream);
  background: var(--ink);
}

.strip-label {
  margin-bottom: 10px;
  color: var(--cream-soft);
}

.strip-ticker {
  overflow: hidden;
  padding-inline: max(20px, calc((100% - 1160px) / 2)); /* static: lines up with .wrap */
}

.strip-track { display: flex; }

.strip ul {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 0;
  font-family: var(--display);
  font-weight: 800;
  font-style: italic;
  font-stretch: 118%;
  font-size: clamp(20px, 2.4vw, 28px);
  line-height: 1.2;
  text-transform: uppercase;
  white-space: nowrap;
}

.strip li::after {
  content: "/";
  margin-inline: 16px;
  color: var(--accent-light);
}

.strip-ticker:not(.is-live) li:last-child::after { content: none; }

@media (prefers-reduced-motion: no-preference) {
  .strip-ticker.is-live {
    padding-inline: 0;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
    mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  }
  .strip-ticker.is-live .strip-track {
    width: max-content;
    animation: strip-run 24s linear infinite;
  }
  .strip-ticker.is-live ul { flex: none; flex-wrap: nowrap; }
  .strip-ticker.is-live:hover .strip-track { animation-play-state: paused; }
}

@media (prefers-reduced-motion: reduce) {
  .strip-ticker [aria-hidden="true"] { display: none; }
  .strip-ticker li:last-child::after { content: none; }
}

@keyframes strip-run {
  to { transform: translateX(calc(-100% / var(--copies, 1))); }
}

/* ---------- 3D spot tour ---------- */

.spin {
  position: relative;
  color: var(--cream);
  background: var(--ink);
  border-top: 1px solid var(--cream-line);
}

.spin-stage {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  height: 100vh;
  height: 100svh;
  overflow: hidden;
  background:
    radial-gradient(42% 58% at 67% 52%, rgba(0, 119, 255, 0.30), rgba(0, 119, 255, 0) 72%),
    var(--ink);
}

.spin-stage canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.spin-body {
  position: absolute;
  top: 24px;
  right: max(20px, calc((100% - 1160px) / 2));
  z-index: 3;
  display: inline-flex;
  padding: 4px;
  border: 1px solid var(--cream-line);
  border-radius: 999px;
  background: rgba(17, 17, 17, 0.6);
}

.spin-body button {
  padding: 8px 16px;
  border: 0;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  color: var(--cream-soft);
  background: transparent;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.spin-body button:hover { color: var(--cream); }

.spin-body button[aria-pressed="true"] {
  color: var(--ink);
  background: var(--cream);
}

/* Sport picker: under the body toggle, one row per sport with the number of
   spots its kit leaves bare. On narrow screens: a scrolling row of chips. */
.spin-sport {
  position: absolute;
  top: 84px;
  right: max(20px, calc((100% - 1160px) / 2));
  z-index: 3;
  width: 212px;
  padding: 10px 8px 8px;
  border: 1px solid var(--cream-line);
  border-radius: 18px;
  background: rgba(17, 17, 17, 0.6);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.sport-head {
  display: flex;
  justify-content: space-between;
  padding: 0 10px 6px;
}

.sport-head .eyebrow {
  font-size: 11px;
  color: var(--cream-faint);
}

.sport-list { display: grid; gap: 2px; }

.sport-list button {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 700;
  line-height: 1.3;
  text-align: left;
  color: var(--cream-soft);
  background: transparent;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.sport-list button:hover {
  color: var(--cream);
  background: var(--cream-tint);
}

.sport-list button[aria-pressed="true"] {
  color: var(--ink);
  background: var(--cream);
}

.sport-n {
  font-variant-numeric: tabular-nums;
  color: var(--cream-faint);
}

.sport-list button[aria-pressed="true"] .sport-n { color: var(--ink-soft); }

.sport-kit {
  margin: 8px 2px 0;
  padding: 10px 8px 2px;
  border-top: 1px solid var(--cream-line);
  font-size: 13px;
  line-height: 1.45;
  color: var(--cream-soft);
}

.spin-loading {
  position: absolute;
  top: 50%;
  left: 67%;
  font-size: 14px;
  font-weight: 600;
  color: var(--cream-soft);
  transform: translate(-50%, -50%);
  animation: breathe 1.4s ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 1; }
}

.spin-tag {
  position: absolute;
  top: 0;
  left: 0;
  display: flex;
  align-items: center;
  opacity: 0;
  pointer-events: none;
  will-change: transform, opacity;
}

.spin-tag.flip { flex-direction: row-reverse; }

.tag-dot {
  flex: none;
  width: 14px;
  height: 14px;
  border: 2px solid var(--accent-bright);
  border-radius: 50%;
  background: rgba(0, 212, 255, 0.25);
}

.tag-line {
  flex: none;
  width: 40px;
  height: 2px;
  background: var(--accent-bright);
}

.tag-label {
  display: grid;
  padding: 8px 13px;
  border-radius: 10px;
  line-height: 1.25;
  white-space: nowrap;
  color: var(--ink);
  background: var(--accent-bright);
}

.tag-label strong { font-size: 15px; font-weight: 800; }
.tag-label span { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; }

/* The chosen sport's kit covers this spot. */
.spin-tag.is-covered .tag-dot { border-color: var(--cream-faint); background: rgba(244, 241, 234, 0.15); }
.spin-tag.is-covered .tag-line { background: var(--cream-faint); }
.spin-tag.is-covered .tag-label {
  border: 1px solid var(--cream-faint);
  color: var(--cream);
  background: var(--ink);
}

/* "Skip the tour": right above the orbit dial (on phones: under the sport
   chips). Fades out once the last panel is on screen. */
.spin-skip {
  position: absolute;
  right: calc((max(20px, (100% - 1160px) / 2) + 28px) / 2);
  bottom: 116px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1px solid var(--cream-line);
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  color: var(--cream-soft);
  background: rgba(17, 17, 17, 0.6);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, opacity 0.2s ease, visibility 0.2s;
}

.spin-skip:hover {
  color: var(--cream);
  border-color: var(--cream-faint);
}

.spin-skip.is-done {
  opacity: 0;
  visibility: hidden;
}

/* Orbit dial and spot counter: bottom right, halfway between the content
   column's edge and the stage corner (28px). */
.spin-hud {
  position: absolute;
  right: calc((max(20px, (100% - 1160px) / 2) + 28px) / 2);
  bottom: 28px;
  display: flex;
  align-items: center;
  gap: 14px;
}

.dial { width: 72px; height: 72px; }
.dial-track { fill: none; stroke: var(--cream-line); stroke-width: 1.5; }
.dial-hit { fill: transparent; }
.dial-stop { cursor: pointer; }
.dial-tick { fill: var(--cream-faint); transition: fill 0.15s ease; }
.dial-stop:hover .dial-tick:not(.is-on) { fill: var(--cream); }
.dial-tick.is-off { fill: var(--cream-line); }
.dial-tick.is-on { fill: var(--accent-bright); }
.dial-body { fill: var(--cream); }
.dial-cam { fill: var(--accent-light); stroke: var(--ink); stroke-width: 2; pointer-events: none; } /* never blocks a dot */

.hud-text { display: grid; line-height: 1.2; }

.hud-count {
  font-family: var(--display);
  font-weight: 800;
  font-style: italic;
  font-stretch: 115%;
  font-size: 24px;
  font-variant-numeric: tabular-nums;
}

.hud-name { color: var(--cream-soft); }

.spin-steps {
  position: relative;
  z-index: 2;
  margin-top: -100vh;
  margin-top: -100svh;
  pointer-events: none;
}

.step-panel {
  display: flex;
  align-items: center;
  min-height: 76vh;
  min-height: 76svh;
}

.step-panel.is-edge {
  min-height: 100vh;
  min-height: 100svh;
}

.step-panel > .wrap { width: 100%; }

.panel-card {
  display: grid;
  justify-items: start;
  gap: 12px;
  max-width: 400px;
  padding: 26px 28px;
  border: 1px solid var(--cream-line);
  border-radius: 20px;
  background: rgba(17, 17, 17, 0.62);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  pointer-events: auto;
}

/* A spot card pops up (js/landing.js adds .is-in as it reaches the middle
   of the screen): it rises and grows past its size, then settles. The wrap
   moves, not the card, so the phones' fade under the tour controls (an
   animation on the card) stays separate. */
.step-panel[data-spot] > .wrap {
  opacity: 0;
  transform: translateY(48px) scale(0.86);
  transform-origin: left center;
  transition:
    opacity 0.3s ease,
    transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.step-panel[data-spot] > .wrap.is-in {
  opacity: 1;
  transform: none;
}

.panel-card.is-open {
  max-width: 430px;
  padding: 0;
  border: 0;
  background: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.panel-card .eyebrow { color: var(--accent-bright); }
.spin .display em { color: var(--accent-light); }

.spin-title { font-size: clamp(38px, 4.8vw, 64px); }

.panel-intro {
  font-size: 18px;
  color: var(--cream-soft);
}

.scroll-hint {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--cream-soft);
}

.scroll-hint span:last-child {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 1.5px solid var(--cream-faint);
  border-radius: 50%;
  animation: nudge 1.6s ease-in-out infinite;
}

@keyframes nudge {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(4px); }
}

.panel-idx { color: var(--accent-bright); }

.panel-card h3 {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 115%;
  font-size: clamp(30px, 3.2vw, 40px); /* "Abdominales" fits the 400px card */
  line-height: 1;
  letter-spacing: -0.015em;
  hyphens: auto;
}

.panel-size {
  display: inline-flex;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  background: var(--accent-light);
}

/* The print: its outline to scale (0.26 px per mm), the max size, and
   "left + right" for paired spots. */
.panel-print {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 10px;
}

.print-shape {
  flex: none;
  width: calc(var(--w) * 0.26px);
  height: calc(var(--h) * 0.26px);
  border: 1.5px dashed var(--accent-bright);
  border-radius: calc(min(var(--w), var(--h)) * var(--round) * 0.26px);
  background: rgba(0, 168, 255, 0.22);
}

.panel-pair {
  padding: 5px 11px;
  border: 1px solid var(--cream-line);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 700;
  color: var(--cream-soft);
}

.panel-note { font-size: 17px; color: var(--cream-soft); }

.panel-covered { display: none; }

.panel-sports {
  display: grid;
  gap: 8px;
  width: 100%;
  margin-top: 4px;
  padding-top: 14px;
  border-top: 1px solid var(--cream-line);
}

.panel-card .panel-sports .eyebrow {
  font-size: 11px;
  color: var(--cream-faint);
}

.panel-sports ul {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.panel-sports li {
  padding: 3px 10px;
  border: 1px solid var(--cream-line);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 700;
  color: var(--cream-soft);
}

.panel-sports li.is-on {
  border-color: var(--accent-bright);
  color: var(--ink);
  background: var(--accent-bright);
}

/* Covered in the chosen sport: greyed print, and a line that says so. */
.panel-card.is-covered .print-shape {
  border-color: var(--cream-faint);
  background: none;
}

.panel-card.is-covered .panel-size {
  color: var(--cream-soft);
  background: var(--cream-line);
}

.panel-card.is-covered .panel-covered {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  font-weight: 700;
}

.panel-card.is-covered .panel-covered::before {
  content: "";
  flex: none;
  width: 12px;
  height: 12px;
  border: 1.5px dashed var(--cream-faint);
  border-radius: 3px;
}

.panel-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 8px;
}

/* Without WebGL (or if three.js fails to load) the cards read as a plain list. */
.spin.no-webgl .spin-stage { display: none; }
.spin.no-webgl .spin-steps { margin-top: 0; padding-block: 48px; }
.spin.no-webgl .step-panel { min-height: 0; padding-block: 10px; }

/* ---------- Sections ---------- */

.sec { padding-block: clamp(64px, 9vw, 112px); }

/* Right after the dark tour the colour fades from ink to the page over
   --edge-fade instead of changing on a line: a long, gentle fade (the user
   asked for more height on 2026-09-28). It takes the place of the section's
   top padding, so this gap is taller than between the other sections.
   Mixed in oklab (no muddy grey half way) and eased at both ends (smoothstep:
   no visible line where it starts or stops). */
.spin + .sec {
  --edge-fade: clamp(200px, 24vw, 360px);
  padding-top: calc(var(--edge-fade) + clamp(8px, 1.5vw, 20px));
  background: linear-gradient(to bottom, var(--ink), var(--page) var(--edge-fade)); /* older browsers */
  background:
    linear-gradient(
    color-mix(in oklab, var(--page) 0.0%, var(--ink)) 0%,
    color-mix(in oklab, var(--page) 2.8%, var(--ink)) 10%,
    color-mix(in oklab, var(--page) 10.4%, var(--ink)) 20%,
    color-mix(in oklab, var(--page) 21.6%, var(--ink)) 30%,
    color-mix(in oklab, var(--page) 35.2%, var(--ink)) 40%,
    color-mix(in oklab, var(--page) 50.0%, var(--ink)) 50%,
    color-mix(in oklab, var(--page) 64.8%, var(--ink)) 60%,
    color-mix(in oklab, var(--page) 78.4%, var(--ink)) 70%,
    color-mix(in oklab, var(--page) 89.6%, var(--ink)) 80%,
    color-mix(in oklab, var(--page) 97.2%, var(--ink)) 90%,
    color-mix(in oklab, var(--page) 100.0%, var(--ink)) 100%
    ) top / 100% var(--edge-fade) no-repeat,
    var(--page);
}

.sec.flush-top { padding-top: 0; }

.sec-head {
  display: grid;
  gap: 16px;
  max-width: 760px;
  margin-bottom: clamp(36px, 5vw, 56px);
}

.sec-head .eyebrow { color: var(--accent); }

.h2 { font-size: clamp(34px, 4.6vw, 60px); }

/* How it works */

.steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 28px;
  counter-reset: step;
}

.step {
  display: grid;
  align-content: start;
  gap: 10px;
  padding-top: 20px;
  border-top: 2px solid var(--ink);
  counter-increment: step;
}

.step::before {
  content: counter(step);
  font-family: var(--display);
  font-weight: 800;
  font-style: italic;
  font-stretch: 115%;
  font-size: 60px;
  line-height: 1;
  color: var(--accent);
}

.step h3 {
  font-family: var(--display);
  font-weight: 700;
  font-stretch: 110%;
  font-size: 22px;
  line-height: 1.15;
}

.step p { font-size: 16px; color: var(--ink-soft); }

/* The steps as a lap on a running track (js/how-track.js draws the track
   through the cards' centres). Wide screens: 1 2 on the top straight, the
   loop's line in the infield, 4 3 on the bottom one (clockwise). Phones: the
   cards stack and the track runs round them. Without the track (no JS) the
   same grid reads as a plain list. */
.track {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-areas:
    "s1 s2"
    "loop loop"
    "s4 s3";
  column-gap: clamp(80px, 18vw, 260px);
  row-gap: 0;
  counter-reset: step; /* the list is display: contents */
  padding-inline: clamp(24px, 6vw, 90px);
}

.track .steps { display: contents; }

.track .step:nth-child(1) { grid-area: s1; }
.track .step:nth-child(2) { grid-area: s2; }
.track .step:nth-child(3) { grid-area: s3; }
.track .step:nth-child(4) { grid-area: s4; }

.track .step {
  position: relative;
  z-index: 1;
  align-self: center;
  justify-self: center;
  width: 100%;
  max-width: 330px;
  padding: 20px 22px 22px;
  border: 1.5px solid var(--ink);
  border-radius: 20px;
  background: #fffdf8;
  box-shadow: 0 14px 30px -22px rgba(17, 17, 17, 0.5);
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.35s ease, border-color 0.2s ease;
}

.track .step::before {
  font-size: 44px;
  color: var(--ink);
}

/* The step the runner is at: it lifts, with a heavier outline and shadow. */
.track .step.is-live {
  box-shadow: 0 0 0 2px var(--ink), 0 24px 40px -20px rgba(17, 17, 17, 0.55);
  transform: translateY(-6px) scale(1.03);
}

/* The infield: after step 4 the lap starts again. */
.track-loop {
  grid-area: loop;
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: clamp(150px, 16vw, 210px);
  margin: 0;
  font-family: var(--display);
  font-weight: 800;
  font-style: italic;
  font-stretch: 115%;
  font-size: clamp(22px, 2.6vw, 34px);
  text-align: center;
  color: var(--ink);
}

.track-loop-mark { font-style: normal; }

.track-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

/* A clay track: a warm brown band (it sits well on the cream page, and the
   black ball stands out on it), white lane lines, a start line, the ball. */
.track {
  --track-clay: #c9926a;
}

.track-band { fill: none; stroke: var(--track-clay); }
.track-edge { fill: none; stroke: #ffffff; stroke-width: 2.5; }
.track-lane { fill: none; stroke: rgba(255, 255, 255, 0.85); stroke-width: 1.5; }
.track-start { stroke: #ffffff; stroke-width: 5; stroke-dasharray: 5 5; }
.track-path { fill: none; stroke: none; }
.runner-dot { fill: var(--ink); }

/* Fade-ins below the tour (js/landing.js marks the items .reveal and adds
   .is-shown when their group scrolls into view). The rise uses `translate`,
   so the track cards keep `transform` for lighting up. */
.reveal { opacity: 0; }

.reveal.is-shown {
  animation: reveal-in 0.7s cubic-bezier(0.2, 0.7, 0.2, 1) var(--reveal-delay, 0s) both;
}

@keyframes reveal-in {
  from { opacity: 0; translate: 0 28px; }
  to { opacity: 1; translate: 0 0; }
}

/* Athletes / brands */

.sides {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
}

.side {
  display: grid;
  align-content: start;
  gap: 22px;
  padding: clamp(28px, 4vw, 48px);
  border-radius: 22px;
}

.side-athlete {
  color: var(--cream);
  background: var(--ink);
}

/* A paper card, like the steps above it: after the track, a solid blue card
   was too much blue (2026-09-28). Blue stays in the small eyebrow only. */
.side-brand {
  color: var(--ink);
  border: 1.5px solid var(--ink);
  background: #fffdf8;
}

.side-athlete .eyebrow { color: var(--accent-bright); }
.side-brand .eyebrow { color: var(--accent); }

/* The athletes' button in cream, not bright blue, on the ink card. */
.side-athlete .btn { color: var(--ink); background: var(--cream); }
.side-athlete .btn:hover { background: #ffffff; }

/* Sized by the card's own width (cqi), so a long word (Catalan
   "l'esdeveniment.") never runs past the card's edge. */
.side { container-type: inline-size; }
.side .h2 { font-size: clamp(30px, 9.6cqi, 52px); }

.side ul {
  display: grid;
  gap: 12px;
  max-width: 44ch;
}

/* Plain bullets, in the text colour. */
.side ul {
  padding-left: 1.1em;
  list-style: disc;
}

.side .btn {
  justify-self: start;
  margin-top: 8px;
}

/* FAQ */

.faq {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

.faq .sec-head { margin-bottom: 0; }

.faq details { border-bottom: 1px solid var(--ink-line); }
.faq details:first-child { border-top: 1px solid var(--ink-line); }

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-block: 22px;
  font-size: 19px;
  font-weight: 600;
  line-height: 1.35;
  list-style: none;
  cursor: pointer;
}

.faq summary::-webkit-details-marker { display: none; }

.plus {
  position: relative;
  flex: none;
  width: 32px;
  height: 32px;
  border: 1.5px solid var(--ink);
  border-radius: 50%;
  transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.plus::before,
.plus::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 12px;
  height: 2px;
  background: var(--ink);
  transform: translate(-50%, -50%);
}

.plus::after { transform: translate(-50%, -50%) rotate(90deg); }

.faq details[open] .plus {
  border-color: var(--accent);
  background: var(--accent);
  transform: rotate(45deg);
}

.faq details[open] .plus::before,
.faq details[open] .plus::after { background: var(--cream); }

.faq details p {
  max-width: 58ch;
  padding-bottom: 24px;
  color: var(--ink-soft);
}

/* ---------- Race calendar shortcut (hero, js/mini-calendar.js) ----------
   Wide screens: a card floating over the hero's bottom-left corner, half on
   the sports strip below (above the storm overlay too). Narrower: centred
   under the two halves. */

.hero-cal {
  width: 292px;
  margin: 48px auto 0;
  padding: 16px 16px 14px;
  border: 1.5px solid var(--ink);
  border-radius: 20px;
  color: var(--ink);
  background: #fffdf8;
  box-shadow: 0 28px 50px -30px rgba(17, 17, 17, 0.55);
}

@media (min-width: 1200px) {
  .hero-cal {
    position: absolute;
    bottom: 0;
    /* Halfway between the screen edge gutter and the page content (the logo). */
    left: calc((clamp(24px, 2.8vw, 48px) + max(20px, (100% - 1200px) / 2 + 20px)) / 2);
    z-index: 22;
    margin: 0;
    /* ~72px above the hero's edge (clear of the athletes note), the rest over the strip. */
    transform: translateY(calc(100% - 72px));
  }
}

.mcal-head { display: grid; gap: 8px; }

.hero-cal .eyebrow { color: var(--accent); }

.mcal-nav {
  display: flex;
  align-items: center;
  gap: 8px;
}

.mcal-nav button {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1.5px solid var(--ink);
  border-radius: 999px;
  font-size: 14px;
  color: var(--ink);
  background: transparent;
  cursor: pointer;
}

.mcal-nav button:hover:not(:disabled) { color: var(--cream); background: var(--ink); }
.mcal-nav button:disabled { opacity: 0.25; cursor: not-allowed; }

.mcal-month {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 110%;
  font-size: 17px;
  text-align: center;
  white-space: nowrap;
}

.mcal-weekdays,
.mcal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
}

.mcal-weekdays {
  margin-top: 10px;
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.mcal-grid { margin-top: 5px; }

.mcal-day {
  position: relative;
  display: grid;
  place-items: center;
  height: 29px;
  border-radius: 8px;
  font-size: 13.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  color: var(--ink);
}

a.mcal-day:hover { color: var(--cream); background: var(--ink); }

.mcal-day.has-races { background: rgba(0, 119, 255, 0.08); }

.mcal-bang {
  position: absolute;
  top: 1px;
  right: 1px;
  display: grid;
  place-items: center;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  font-size: 9px;
  font-weight: 900;
  line-height: 1;
  color: #ffffff;
  background: var(--accent);
}

.mcal-day.is-today { box-shadow: inset 0 0 0 2px var(--accent); }

.mcal-day.is-past { color: rgba(17, 17, 17, 0.25); }

.mcal-link {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px solid var(--ink-line);
  font-size: 14px;
  font-weight: 700;
  text-decoration: none;
  color: var(--ink);
}

.mcal-link:hover { color: var(--accent); }

/* ---------- Responsive ---------- */

@media (max-width: 980px) {
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 40px; }
}

@media (max-width: 899px) {
  .spin-stage {
    background:
      radial-gradient(70% 45% at 50% 34%, rgba(0, 119, 255, 0.30), rgba(0, 119, 255, 0) 72%),
      var(--ink);
  }
  .spin-hud { top: 20px; right: 20px; bottom: auto; }
  .spin-skip { top: 136px; right: auto; bottom: auto; left: 20px; padding: 6px 12px; font-size: 13px; }
  .spin-body { top: 20px; right: auto; left: 20px; }
  .spin-sport {
    top: 92px;
    right: 0;
    left: 0;
    width: auto;
    padding: 0;
    border: 0;
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .sport-head,
  .sport-kit { display: none; }
  .sport-list {
    display: flex;
    gap: 6px;
    padding-inline: 20px;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .sport-list::-webkit-scrollbar { display: none; }
  .sport-list button {
    flex: none;
    width: auto;
    padding: 6px 12px;
    border: 1px solid var(--cream-line);
    border-radius: 999px;
    font-size: 13px;
    background: rgba(17, 17, 17, 0.6);
  }
  .spin-loading { top: 36%; left: 50%; }
  .step-panel { align-items: flex-end; padding-bottom: 5svh; }
  .panel-card,
  .panel-card.is-open {
    max-width: none;
    width: 100%;
    padding: 22px;
    border: 1px solid var(--cream-line);
    background: rgba(17, 17, 17, 0.84);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }
  /* Shorter cards, so the figure keeps the top half of the screen. */
  .panel-card { gap: 10px; }
  .panel-note { font-size: 15px; }
  .panel-sports { display: block; padding-top: 12px; }
  .panel-card .panel-sports .eyebrow { display: inline; margin-right: 6px; }
  .panel-sports ul { display: inline; }
  .panel-sports li {
    display: inline-block;
    margin: 0 2px 4px 0;
    padding: 2px 9px;
    font-size: 12px;
  }
}

/* Phones: the cards scroll up over the figure. Before one reaches the tour
   controls at the top (body switch, sport chips, skip: the top ~170px) it
   fades out and stops taking taps, so the controls stay usable. Where
   scroll-driven animations are missing, the cards simply pass over them. */
@media (max-width: 899px) {
  @supports (animation-timeline: view()) {
    .panel-card {
      animation: card-under-controls linear both;
      animation-timeline: view(block 250px 0px);
      animation-range: exit 0% exit 25%;
    }
  }
}

@keyframes card-under-controls {
  to { opacity: 0; pointer-events: none; }
}

@media (max-width: 860px) {
  .sides,
  .faq { grid-template-columns: 1fr; }
  .split { grid-template-columns: minmax(0, 1fr); row-gap: 24px; }
  .bolt { height: clamp(44px, 12vw, 64px); }
  .bolt-v { display: none; }
  .bolt-h { display: block; }
}

@media (max-width: 760px) {
  /* The cards stack; the track runs down their right edge and back up the left. */
  .track {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "s1" "s2" "s3" "s4" "loop";
    row-gap: 28px;
    padding: 110px 30px 40px;
  }
  .track .step { max-width: none; }
  .track-loop { min-height: 0; padding-bottom: 24px; }
}

@media (max-width: 560px) {
  .steps { grid-template-columns: 1fr; }
  .half .btn { justify-self: stretch; }
  .dial { width: 60px; height: 60px; }
  .panel-card .btn { flex: 1 1 100%; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; }
  .reveal.is-shown { animation: none; }
  .step-panel[data-spot] > .wrap { transform: none; transition: opacity 0.3s ease; }
  .track .step { transition: none; }
  .track .step.is-live { transform: none; }
  .scroll-hint span:last-child, .spin-loading { animation: none; }
  .plus { transition: none; }
}
