/* Public entry point: the shared base plus the home page sections and the registration flow.
   Served as ONE file: config/initializers/propshaft_css_imports.rb inlines every @import below.
   To add a stylesheet, add one @import line in the right layer. Do not link it separately. */
/* Shared base, imported by public.css and admin.css (layouts link only those). Layer order is the
   cascade; selector specificity only matters inside one layer. This file declares the order first. */
@layer reset, tokens, base, layout, components, sections, admin, utilities;

@layer tokens {
/* Self-hosted latin subsets (SIL OFL), fetched from Google Fonts. Inter is one variable file. */
@font-face {
  font-family: "Anton";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/anton-400-latin-e6b09352.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;
}

@font-face {
  font-family: "Barlow Condensed";
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/barlow-condensed-700i-latin-e52edfb1.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;
}

@font-face {
  font-family: "Barlow Condensed";
  font-style: italic;
  font-weight: 800;
  font-display: swap;
  src: url("/assets/barlow-condensed-800i-latin-d8a86280.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;
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("/assets/inter-variable-latin-1f021a24.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;
}

/* Metric-matched fallbacks: while a web font loads (font-display: swap) the local face is scaled so
   text occupies the same space, which keeps the swap from shifting the layout (CLS). Values come from
   the font files: size-adjust = weighted average advance width of the webfont / the local face,
   ascent/descent-override = webfont ascent/descent / size-adjust. They are only used before the
   webfont arrives, or when it fails. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("ArialMT");
  size-adjust: 107.5%;
  ascent-override: 90.1%;
  descent-override: 22.4%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Barlow Condensed Fallback";
  font-style: italic;
  font-weight: 700 800;
  src: local("Arial Bold Italic"), local("Arial-BoldItalicMT");
  size-adjust: 75%;
  ascent-override: 133.3%;
  descent-override: 26.7%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Anton Fallback";
  src: local("Impact");
  size-adjust: 99.3%;
  ascent-override: 118.4%;
  descent-override: 33.1%;
  line-gap-override: 0%;
}
}
@layer tokens {
:root {
  /* Colour: the Generic KV palette (spec §1). White ground, orange-to-amber speed streaks with
     royal-blue slashes, ink type, cream cards. Ink panels are accents only.
     Contrast: orange (#F15A24) takes white or ink type only at large sizes (white 3.4:1, ink
     5.1:1); small text uses --color-orange-deep (5.2:1 on white, 4.9:1 on cream, white on it
     5.2:1). Amber is decoration only (white on it 2.3:1; ink 7.5:1). White on blue 8.4:1. */
  --color-orange: #F15A24;
  --color-amber: #F7941D;
  --color-blue: #1E4A9C;
  --color-ink: #1B1B1F;
  --color-cream: #FFF6EE;
  --color-white: #FFFFFF;
  --gradient-kv: linear-gradient(100deg, var(--color-orange), var(--color-amber));

  --color-orange-deep: #C2410C;
  --color-ink-soft: #55555D; /* 7.4:1 on white, 6.8:1 on cream */
  --color-line: #EDE3D8; /* hairlines and card borders on white and cream */
  --color-ink-line: #34343B; /* hairlines on ink */
  --color-on-ink-soft: #C8C8D0; /* secondary text on ink: 10.3:1 */
  --color-orange-glow: rgb(241 90 36 / 0.4);
  --color-shine: rgb(255 255 255 / 0.5);

  /* Programme surface (blue-deep): white on it 10.4:1; the soft tints below are for text on it. */
  --color-blue-deep: #1C3F74;
  --color-on-blue-soft: #D6E0F2; /* secondary text on blue-deep: 7.85:1, 6.80:1 on the tinted table */
  --color-amber-soft: #FFC266; /* amber text on blue-deep: 6.5:1 (plain amber is 4.6:1), 5.5:1 on the tinted table */

  /* Slanted edges of the cream home sections (layout.css): a 4vw rise across the width; those
     sections keep at least this much extra padding at each edge. */
  --seam-slant: 4vw;

  /* Route map (night theme): purple km badges (white 7.1:1), dark forest green belts, the pond. */
  --color-purple: #7B2CBF;
  --color-map-green: #17331F;
  --color-map-water: var(--color-blue-deep);

  /* Shape: KV cards are softly rounded; buttons and bars stay sharp and skewed (-12deg). */
  --radius-card: 0.75rem;

  /* Type */
  --font-display: "Anton", "Anton Fallback", Impact, "Arial Narrow Bold", sans-serif; /* big numerals and date lines */
  --font-headline: "Barlow Condensed", "Barlow Condensed Fallback", "Arial Narrow", sans-serif; /* 700/800 italic: headlines, eyebrows */
  --font-body: "Inter", "Inter Fallback", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  --step--1: clamp(0.8rem, 0.78rem + 0.1vw, 0.875rem);
  --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
  --step-1: clamp(1.2rem, 1.1rem + 0.5vw, 1.5rem);
  --step-2: clamp(1.45rem, 1.25rem + 0.95vw, 2rem);
  --step-3: clamp(1.75rem, 1.4rem + 1.75vw, 2.75rem);
  --step-4: clamp(2.1rem, 1.5rem + 3vw, 4rem);
  --step-5: clamp(2.6rem, 1.6rem + 5vw, 5.5rem);
  --step-6: clamp(3.2rem, 1.8rem + 7vw, 8rem);

  /* Space */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  --space-6: clamp(1.75rem, 1.5rem + 1vw, 2.5rem);
  --space-7: clamp(2.5rem, 2rem + 2vw, 4rem);
  --space-8: clamp(4rem, 3rem + 4vw, 6rem);
  --space-9: clamp(6rem, 12vw, 11rem);

  /* Layout */
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --container-max: 72rem;
  --measure: 60ch;
  --nav-height: 4.5rem; /* the fixed top bar's height (nav.css) and the hero's offset under it */
  --countdown-bar-height: 4rem; /* countdown bar: under the nav below 64rem, bottom-fixed from 64rem (countdown_bar.css) */

  /* ---- Semantic tier: components consume these, never the primitives above. ----
     Breakpoints (min-width first; custom properties cannot be used in media queries):
     36rem (576px), 48rem (768px), 64rem (1024px), 80rem (1280px). */

  /* Text */
  --color-text: var(--color-ink);
  --color-text-muted: var(--color-ink-soft); /* 7.4:1 on white, 6.8:1 on cream */
  --color-text-accent: var(--color-orange-deep); /* 5.2:1 on white, 4.9:1 on cream */
  --color-link: var(--color-blue); /* 8.4:1 on white, 7.8:1 on cream */

  /* Surfaces */
  --color-surface: var(--color-white);
  --color-surface-raised: var(--color-cream);
  --color-surface-inverse: var(--color-ink);
  --color-surface-brand: var(--color-blue-deep);

  /* Borders: hairline is decoration (1.3:1); strong is for control edges (7.4:1 on white, 3:1 needed) */
  --color-border: var(--color-line);
  --color-border-strong: var(--color-ink-soft);

  /* Status pairs: foreground contrast on white / cream / its own -bg tint (all at least 4.5:1) */
  --color-danger: #B3261E; /* 6.5:1 / 6.1:1 / 5.7:1 */
  --color-danger-bg: #FDECEA;
  --color-success: #1E6B34; /* 6.5:1 / 6.1:1 / 5.8:1 */
  --color-success-bg: #E6F4EA;
  --color-warning: #8A4B00; /* 6.8:1 / 6.4:1 / 6.0:1 */
  --color-warning-bg: #FFF0D6;
  --color-info: var(--color-blue); /* 8.4:1 / 7.8:1 / 7.2:1 */
  --color-info-bg: #E8EEF9;

  /* Focus ring: orange-deep 5.2:1 on white, 4.9:1 on cream (3:1 needed). Surface classes in
     base.css swap it on dark grounds. */
  --focus-color: var(--color-orange-deep);
  --focus-width: 3px;
  --focus-offset: 3px;

  /* Shape and depth */
  --radius-sm: 0.375rem;
  --radius-pill: 999px;
  --shadow-1: 0 1px 2px rgb(27 27 31 / 0.08), 0 1px 3px rgb(27 27 31 / 0.06);
  --shadow-2: 0 4px 12px rgb(27 27 31 / 0.1), 0 2px 4px rgb(27 27 31 / 0.06);
  --shadow-3: 0 12px 32px rgb(27 27 31 / 0.16), 0 4px 8px rgb(27 27 31 / 0.08);

  /* Layers */
  --z-dropdown: 100;
  --z-sticky: 200;
  --z-overlay: 300;
  --z-modal: 400;
  --z-skip: 500;

  /* Controls and tap targets */
  --control-h-sm: 2.75rem;
  --control-h-md: 3rem;
  --tap-min: 2.75rem;

  /* Widths */
  --width-form: 36rem;
  --width-admin: 90rem;

  /* Motion */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --duration-instant: 80ms;
  --duration-fast: 200ms;
  --duration-base: 450ms;
  --duration-slow: 900ms;
  --duration-reveal: 600ms; /* the signature diagonal rise (reveal, hero load-in) */
  --reveal-offset: 1.5rem; /* 24px left and down; list items use 1rem */
  --shine-band: linear-gradient(110deg, transparent 35%, rgb(255 255 255 / 0.9) 50%, transparent 65%);
  --parallax-x: 12px;
  --parallax-y: 8px;
  --parallax-scroll: 32px;
}

@media (min-width: 48rem) {
  :root {
    --countdown-bar-height: 4.75rem;
  }
}

/* BUKAK_KEDAI=false renders no nav (layouts/application), so it takes no room: the countdown bar
   sits at the top edge and nothing is offset for the nav. */
:root.without-site-nav {
  --nav-height: 0rem;
}
}
@layer base {
/* Light only: the app has no dark theme (the night admin is its own surface). */
:root {
  color-scheme: light;
}

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

html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--nav-height) + var(--space-4));
}

/* With JS the countdown bar is fixed under the nav, so in-page anchors land below both. */
html.js {
  scroll-padding-top: calc(var(--nav-height) + var(--countdown-bar-height) + var(--space-4));
}

/* From 64rem the bar sits at the bottom of the viewport instead (countdown_bar.css). */
@media (min-width: 64rem) {
  html.js {
    scroll-padding-top: calc(var(--nav-height) + var(--space-4));
  }
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

html.nav-open {
  overflow: hidden;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--color-white);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 400;
  line-height: 1.6;
  overflow-x: clip;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, ul, ol, dl, dd, figure {
  margin: 0;
}

ul, ol {
  padding: 0;
  list-style: none;
}

img, svg {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

a {
  color: inherit;
}

button {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: var(--focus-width) solid var(--focus-color);
  outline-offset: var(--focus-offset);
}

/* Dark grounds reassign the semantic text, border and focus tokens for their subtree. */
.surface-inverse {
  --color-text: var(--color-white);
  --color-text-muted: var(--color-on-ink-soft);
  --color-border: var(--color-ink-line);
  --focus-color: var(--color-amber);
}

.surface-brand {
  --color-text: var(--color-white);
  --color-text-muted: var(--color-on-blue-soft);
  --color-border: rgb(255 255 255 / 0.2);
  --focus-color: var(--color-white);
}

::selection {
  background: var(--color-orange);
  color: var(--color-white);
}

.skip-link {
  position: fixed;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 100;
  padding: var(--space-3) var(--space-4);
  background: var(--color-ink);
  color: var(--color-white);
  font-weight: 600;
  transform: translateY(-200%);
  transition: transform var(--duration-fast) var(--ease-out);
}

.skip-link:focus {
  transform: none;
}

/* Scroll reveal: content is only hidden once JS has booted (html.js). */
.js [data-controller~="reveal"] {
  opacity: 0;
  transform: translate(calc(var(--reveal-offset) * -1), var(--reveal-offset));
  transition:
    opacity var(--duration-reveal) var(--ease-out) var(--reveal-delay, 0ms),
    transform var(--duration-reveal) var(--ease-out) var(--reveal-delay, 0ms);
}

.js [data-controller~="reveal"].is-revealed {
  opacity: 1;
  transform: none;
}

/* Lists reveal item by item: the list itself stays put and its items rise in turn (--i). */
.js :is(.features, .cards, .steps, .stats, .kit-items)[data-controller~="reveal"] {
  opacity: 1;
  transform: none;
}

.js :is(.features, .cards, .steps, .stats, .kit-items)[data-controller~="reveal"] > li {
  opacity: 0;
  transform: translate(-1rem, 1rem);
  transition:
    opacity var(--duration-reveal) var(--ease-out) calc(var(--reveal-delay, 0ms) + var(--i, 0) * 90ms),
    transform var(--duration-reveal) var(--ease-out) calc(var(--reveal-delay, 0ms) + var(--i, 0) * 90ms);
}

.js :is(.features, .cards, .steps, .stats, .kit-items).is-revealed > li {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .js [data-controller~="reveal"],
  .js [data-controller~="reveal"] > li {
    opacity: 1;
    transform: none;
  }
}

/* The skip link lands on <main tabindex="-1">: it takes focus so reading and Tab continue from there,
   but it is a landing point, not a control, so it shows no ring. */
main:focus {
  outline: none;
}
}
@layer layout {
.container {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Home sections alternate white and cream, so each keeps its own padding inside its colour. */
.section {
  padding-block: var(--space-8);
}

/* Cream sections cross the page on a slant like the KV's speed slashes: the top and bottom edges
   rise --seam-slant across the width (clip-path), and the white body shows through the clipped
   corners, so the white hero above meets the first band on a diagonal. Extra padding keeps the
   content clear of the slant. */
.section--cream {
  position: relative;
  background: var(--color-cream);
  clip-path: polygon(0 var(--seam-slant), 100% 0, 100% calc(100% - var(--seam-slant)), 0 100%);
}

.section.section--cream {
  padding-block: calc(var(--space-8) + var(--seam-slant));
}

/* The deep-blue band (the programme) reuses the cream slant. It sits between two cream sections,
   so it overlaps each by the --seam-slant wedge (negative margin) and the edges meet exactly
   instead of showing white corners. Declared after .section so its padding wins on order. */
.section--blue-deep {
  position: relative;
  margin-block: calc(var(--seam-slant) * -1);
  padding-block: calc(var(--space-8) + var(--seam-slant));
  background: var(--color-blue-deep);
  color: var(--color-white);
  clip-path: polygon(0 var(--seam-slant), 100% 0, 100% calc(100% - var(--seam-slant)), 0 100%);
}

/* A KV streak accent at the section's edge (kv/streaks_*.webp), from 64rem where the margins
   beside the container leave room for it. Decorative only. */
.section--streak {
  position: relative;
}

.section--streak > .container {
  position: relative;
}

.section__streak {
  display: none;
}

@media (min-width: 64rem) {
  .section__streak {
    display: block;
    position: absolute;
    top: calc(var(--seam-slant) + var(--space-6));
    right: 0;
    width: clamp(5rem, 10vw, 11rem);
    height: auto;
    mix-blend-mode: multiply; /* the art's white ground takes the section's cream */
    pointer-events: none;
  }

  .section--streak-left .section__streak {
    right: auto;
    left: 0;
  }
}

.nowrap {
  white-space: nowrap;
}

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


/* With JS the nav is fixed and overlays the top of the page, so every page's content starts below
   it. Pages that draw their own full-bleed top under the nav (the home hero) opt out
   with content_for :main_class, "main--flush" and pad themselves. */
.js .main--below-nav {
  padding-top: var(--nav-height);
}
}
@layer components {
/* Buttons. The base .button is a plain square-edged control that works anywhere, public or admin:
   --primary (solid orange), --secondary (outlined), --quiet (text only), --danger, sized with
   --sm and --lg. --brand adds the KV treatment on top: a skewed parallelogram with a thin offset
   edge in the other brand colour, the label counter-skewed so it stays upright, in Barlow
   Condensed italic caps. Only --brand is skewed.
   Contrast: white on --color-orange-deep is 5.2:1. The brand primary's default size is large text
   (21.6px 800), so white on the gradient's lightest end (#F15A24, 3.4:1) passes; its small size
   goes solid deep orange. */
.button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  max-width: 100%;
  min-height: var(--control-h-md);
  padding: var(--space-2) var(--space-5);
  border: 2px solid transparent;
  border-radius: 0;
  background: var(--color-orange-deep);
  color: var(--color-white);
  font: inherit;
  font-weight: 700;
  line-height: 1.1;
  text-decoration: none;
  text-wrap: balance; /* long phase labels ("Registration Opening Soon") may wrap on phones */
  cursor: pointer;
  transition:
    transform var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

.button--primary {
  background: var(--color-orange-deep);
  color: var(--color-white);
}

.button--secondary {
  border-color: var(--color-ink);
  background: transparent;
  color: var(--color-ink);
}

.button--secondary:hover:not(:disabled, [aria-disabled="true"]) {
  background: var(--color-ink);
  color: var(--color-white);
}

.button--quiet {
  min-height: var(--tap-min);
  padding-inline: var(--space-3);
  background: transparent;
  color: var(--color-orange-deep);
  text-decoration: underline;
}

.button--quiet:hover:not(:disabled, [aria-disabled="true"]) {
  background: var(--color-cream);
}

/* On a blue band (.surface-brand) the quiet link turns white. */
.surface-brand .button--quiet {
  color: var(--color-white);
}

.surface-brand .button--quiet:hover:not(:disabled, [aria-disabled="true"]) {
  background: rgb(255 255 255 / 0.12);
}

.button--danger {
  background: var(--color-danger);
  color: var(--color-white);
}

.button--sm {
  min-height: var(--control-h-sm);
  padding: var(--space-1) var(--space-4);
  font-size: var(--step--1);
}

.button--lg {
  min-height: 3.5rem;
  padding-inline: var(--space-6);
  font-size: var(--step-1);
}

.button__content {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}

.button__icon {
  width: 1.1em;
  height: 1.1em;
  flex: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

/* Not available: a form is busy (Turbo sets aria-busy on it while it submits), the control is
   disabled, or registration is closed (lib/registration_links.js sets aria-disabled). */
.button:disabled,
.button[aria-disabled="true"],
form[aria-busy="true"] .button[type="submit"],
form[aria-busy="true"] button[type="submit"].button {
  opacity: 0.55;
  cursor: not-allowed;
}

/* Brand: the KV treatment. */
.button--brand {
  --skew: -12deg;
  --edge: 0.375rem;
  --edge-color: var(--color-blue);
  min-height: 3.5rem;
  padding: var(--space-2) var(--space-6);
  border: 0;
  font-family: var(--font-headline);
  font-size: 1.35rem;
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
  box-shadow: calc(var(--edge) * -1) var(--edge) 0 var(--edge-color);
}

.button--brand.button--primary {
  background: linear-gradient(100deg, var(--color-orange-deep), var(--color-orange) 70%);
}

/* The default blue edge vanishes on a blue band, so the edge there is amber. */
.surface-brand .button--brand {
  --edge-color: var(--color-amber-soft);
}

.button--brand.button--secondary {
  --edge-color: var(--color-orange);
  background: var(--color-blue);
  color: var(--color-white);
}

.button--brand .button__content {
  transform: skewX(calc(var(--skew) * -1));
}

/* Shine sweep. The edge is a shadow, so the button can't clip overflow; the sweep moves its
   gradient across a box that stays put instead. */
.button--brand::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 40%, var(--color-shine) 50%, transparent 60%) 120% 0 / 250% 100% no-repeat;
  transition: background-position 700ms var(--ease-out);
  pointer-events: none;
}

.button--brand:hover,
.button--brand:focus-visible {
  transform: skewX(var(--skew)) translate(2px, -2px);
  box-shadow:
    calc(var(--edge) * -1.75) calc(var(--edge) * 1.75) 0 var(--edge-color),
    0 1rem 1.5rem -0.75rem var(--color-orange-glow);
}

.button--brand:hover::before,
.button--brand:focus-visible::before {
  background-position: -20% 0;
}

.button--brand:hover .button__icon,
.button--brand:focus-visible .button__icon {
  transform: translateX(0.35rem);
}

.button--brand:active {
  transform: skewX(var(--skew)) translate(-1px, 1px) scale(0.98);
  box-shadow: calc(var(--edge) * -0.5) calc(var(--edge) * 0.5) 0 var(--edge-color);
  transition-duration: 80ms;
}

.button--brand.button--sm {
  --edge: 0.25rem;
  min-height: var(--control-h-sm);
  padding: var(--space-1) var(--space-5);
  font-size: 1.05rem;
  letter-spacing: 0.04em;
}

/* Below the large-text size white needs the deeper orange behind the whole label. */
.button--brand.button--primary.button--sm {
  background: var(--color-orange-deep);
}

.button--brand.button--lg {
  --edge: 0.5rem;
  min-height: 4.25rem;
  padding: var(--space-2) var(--space-6);
  font-size: 1.5rem;
}

@media (min-width: 48rem) {
  .button--brand.button--lg {
    padding-inline: var(--space-7);
    font-size: 1.75rem;
  }
}

/* Registration not open: the brand button stays as a status label: flat ink-soft, no arrow, no
   hover or press. */
.button--brand[aria-disabled="true"],
.button--brand[aria-disabled="true"]:hover,
.button--brand[aria-disabled="true"]:active {
  --edge-color: var(--color-line);
  background: var(--color-ink-soft);
  color: var(--color-white);
  box-shadow: calc(var(--edge) * -1) var(--edge) 0 var(--edge-color);
  opacity: 1;
  cursor: not-allowed;
  transform: skewX(var(--skew));
}

.button--brand[aria-disabled="true"]::before,
.button--brand[aria-disabled="true"] .button__icon,
.button--brand[aria-disabled="true"] .visually-hidden {
  display: none;
}

/* The "fewer than N places left" line under a registration button (shared/_places_left). Callers
   add a modifier only to change the colour. */
.places-left {
  margin: 0;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

/* On a blue band the line takes the soft on-blue text colour (7.85:1). */
.surface-brand .places-left {
  color: var(--color-text-muted);
}
}
@layer components {
/* Registration form and the organiser sign-in and password pages, on the KV:
   a section-heading page head, cream cards for field groups, white fields with an ink-soft rule
   that turns orange on focus. Phone first, usable at 320px.
   The page rules are scoped under .form-page so they never depend on the cascade order of the other
   component files: where they restyle .callout or .button they win on specificity, not position.
   The field component (.field and friends) is shared and sits at the end of this file. */
.form-page {
  --form-error: var(--color-danger); /* 6.5:1 on white, 6.1:1 on paper */
  padding-block: var(--space-7) var(--space-8);
}

.form-page :where(h1, h2, p, ul, figure) {
  min-width: 0;
  overflow-wrap: anywhere;
}

.form-page .form-page__head {
  margin-block-end: var(--space-6);
}

.form-page .form-page__lede {
  margin-block: var(--space-2) var(--space-5);
  color: var(--color-ink-soft);
}

.form-page .form-page__heading {
  margin-block: var(--space-6) var(--space-3);
  font-family: var(--font-headline);
  font-size: var(--step-3);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
}

/* Callouts: the shared box, tightened for a phone. */
.form-page .callout {
  max-width: 36rem;
  margin: 0 0 var(--space-5);
  padding: var(--space-4) var(--space-5);
  font-weight: 600;
}

/* Form */
.form-page .registration-form {
  display: grid;
  gap: var(--space-5);
  max-width: 36rem;
}

/* The participant cards, the reassurance strip, the page states and the race wallet (/r/:token)
   live in registration.css (the sections layer, so they sit above the shared .card rules). */

/* The skew and the offset edge reach past the box: an inset keeps them inside the gutter. */
.form-page .registration-form .button {
  justify-self: start;
  max-width: calc(100% - 1rem);
  margin-inline: 0.75rem 0.25rem;
}

.form-page .registration-form .registration-form__submit {
  justify-self: stretch;
}

/* Honeypot: off-screen, not display:none, so simple bots still fill it. */
.form-page .honeypot {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Organiser sign-in and password forms */
.form-page .auth-form {
  display: grid;
  gap: var(--space-5);
  max-width: 28rem;
  padding: var(--space-5);
  background: var(--color-cream);
  border: 1px solid var(--color-line);
  border-top: 4px solid var(--color-orange);
  border-radius: var(--radius-card);
}

.form-page .auth-form .button {
  justify-self: start;
  margin-inline-start: 0.5rem; /* the skew and edge */
}

.form-page .auth-form__aside {
  margin-block-start: var(--space-5);
  font-weight: 600;
}

.form-page .auth-form__aside a {
  color: var(--color-orange-deep);
}

/* Field component: a label, a control, an optional hint and error. Used by the public forms and
   the organiser forms alike. */
.field {
  display: grid;
  gap: var(--space-1);
  min-width: 0;
}

.field[hidden] {
  display: none;
}

/* Rails wraps an invalid field's label and input in .field_with_errors: let them lay out as the
   .field's own children. */
.field .field_with_errors {
  display: contents;
}

.field label {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* 16px minimum stops iOS from zooming the page when a field is focused. */
.field :where(input:not([type="checkbox"], [type="radio"], [type="file"]), select, textarea) {
  width: 100%;
  min-width: 0;
  min-height: var(--control-h-md);
  padding: var(--space-2) var(--space-3);
  background: var(--color-white);
  border: 2px solid var(--color-border-strong); /* 7.4:1, the field's edge is clearly visible */
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  font: inherit;
  font-size: max(1rem, 16px);
  line-height: 1.3;
}

.field :where(input, select, textarea):focus-visible {
  border-color: var(--color-orange);
  outline-offset: 2px;
}

.field :where(input, select, textarea)[aria-invalid="true"] {
  border-color: var(--color-danger);
  box-shadow: inset 4px 0 0 var(--color-danger);
}

.field__hint {
  margin: 0;
  color: var(--color-ink-soft);
  font-size: var(--step--1);
}

/* A text button under a password field that shows or hides what was typed. */
.field__toggle {
  justify-self: start;
  min-height: var(--tap-min);
  padding: 0 var(--space-2);
  background: none;
  border: 0;
  color: var(--color-orange-deep);
  font: inherit;
  font-size: var(--step--1);
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

.field__toggle[aria-pressed="true"] {
  color: var(--color-ink);
}

.field__error {
  margin: 0;
  color: var(--color-danger);
  font-size: var(--step--1);
  font-weight: 700;
}

/* A live reading of what was typed (the MyKad date of birth). Empty until there is something to
   say, so it takes no room. */
.field__check {
  margin: 0;
  color: var(--color-text-accent);
  font-size: var(--step--1);
  font-weight: 700;
}

.field__check:empty {
  display: none;
}

/* "Did you mean …?" under an email field, with a text button that applies it. */
.field__suggestion {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 var(--space-3);
  color: var(--color-text);
  font-size: var(--step--1);
  font-weight: 600;
}

.field__suggestion:has(> :not(:empty, [hidden])) {
  min-height: var(--tap-min);
}

.field__suggestion-apply {
  min-height: var(--tap-min);
  padding: 0;
  background: none;
  border: 0;
  color: var(--color-link);
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

.field__suggestion-apply[hidden] {
  display: none;
}

/* Turbo's page-load bar in the KV gradient. Turbo injects its own unlayered style, which beats any
   layered rule, so the colour and height need !important here. */
.turbo-progress-bar {
  height: 4px !important;
  background: var(--gradient-kv) !important;
}

.field--sm :where(input:not([type="checkbox"], [type="radio"], [type="file"]), select, textarea) {
  min-height: var(--control-h-sm);
}

/* Checkbox or radio with its label: a 1.25rem box and a label that fills the row, so the whole
   row is the tap target. */
.check {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap-min);
}

.check input[type="checkbox"],
.check input[type="radio"] {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0;
  accent-color: var(--color-orange-deep);
}

.check label {
  flex: 1;
  padding-block: var(--space-2);
  letter-spacing: normal;
  text-transform: none;
  cursor: pointer;
}

.field input[type="file"] {
  width: 100%;
  min-width: 0;
  padding: var(--space-2);
  background: var(--color-white);
  border: 2px dashed var(--color-border-strong);
  border-radius: var(--radius-sm);
  color: var(--color-ink);
  font: inherit;
  font-size: var(--step--1);
}

.field input[type="file"]::file-selector-button {
  min-height: var(--control-h-sm);
  margin-inline-end: var(--space-3);
  padding: var(--space-1) var(--space-4);
  border: 2px solid var(--color-ink);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-ink);
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

.field input[type="file"]::file-selector-button:hover {
  background: var(--color-ink);
  color: var(--color-white);
}
}
@layer components {
/* Callout: a boxed message with an icon, a coloured rule down its left edge and a visually hidden
   prefix, so the tone is never colour alone. .notice is the older cream box with an orange rule
   and stays until the pages using it move to .callout. */
.notice,
.callout {
  max-width: 56rem;
  margin-block-start: var(--space-7);
  padding: var(--space-6);
  background: var(--color-cream);
  border: 1px solid var(--color-line);
  border-inline-start: 5px solid var(--color-orange);
  border-radius: var(--radius-card);
}

@media (min-width: 48rem) {
  .notice,
  .callout {
    padding: var(--space-6) var(--space-7);
  }
}

.callout {
  --callout-color: var(--color-info);
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-block-start: 0;
  padding: var(--space-4);
  background: var(--color-info-bg);
  border-color: var(--color-info);
  border-inline-start-color: var(--callout-color);
  color: var(--color-ink);
}

@media (min-width: 48rem) {
  .callout {
    padding: var(--space-4) var(--space-5);
  }
}

.callout--info {
  --callout-color: var(--color-info);
  background: var(--color-info-bg);
}

.callout--success {
  --callout-color: var(--color-success);
  background: var(--color-success-bg);
  border-color: var(--color-success);
}

.callout--warning {
  --callout-color: var(--color-warning);
  background: var(--color-warning-bg);
  border-color: var(--color-warning);
}

.callout--danger {
  --callout-color: var(--color-danger);
  background: var(--color-danger-bg);
  border-color: var(--color-danger);
}

.callout__icon {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--callout-color);
}

.callout__body {
  min-width: 0;
  overflow-wrap: anywhere;
}

.callout__body > :where(p) {
  margin: 0;
}

.callout__title {
  font-weight: 800;
}

/* Error summary (shared/error_summary): a danger callout with a heading over a list of links to
   the fields. It takes focus after a failed submit, so its focus ring must show. */
.error-summary {
  flex-direction: column;
  gap: var(--space-2);
}

.error-summary h2 {
  margin: 0;
  font-size: var(--step-1);
  font-weight: 800;
  line-height: 1.2;
}

.error-summary ul {
  display: grid;
  gap: var(--space-1);
  margin: 0;
  padding-inline-start: 1.25em;
  list-style: disc;
}

.error-summary a {
  color: var(--color-danger);
  font-weight: 700;
}
}
@layer components {
/* Status badge: a short label in a tinted pill. The words carry the meaning; the tone is only
   reinforcement. Each pair is at least 4.5:1 (see tokens.css). */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 0.125rem var(--space-3);
  border: 1px solid currentColor;
  border-radius: var(--radius-pill);
  font-size: var(--step--1);
  font-weight: 700;
  line-height: 1.4;
  white-space: nowrap;
}

.badge--neutral {
  background: var(--color-cream);
  color: var(--color-ink-soft);
}

.badge--success {
  background: var(--color-success-bg);
  color: var(--color-success);
}

.badge--warning {
  background: var(--color-warning-bg);
  color: var(--color-warning);
}

.badge--danger {
  background: var(--color-danger-bg);
  color: var(--color-danger);
}

.badge--info {
  background: var(--color-info-bg);
  color: var(--color-info);
}
}
@layer components {
/* Data table. Wrap it in .table-wrap so a wide table scrolls inside its own box instead of
   pushing the page sideways. The header sticks to the top of that box. .table--stack turns each
   row into a card below 48rem, with every cell showing its data-label. */
.table-wrap {
  position: relative;
  overflow-x: auto;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--step--1);
}

.table :where(th, td) {
  padding: var(--space-2) var(--space-3);
  border-block-end: 1px solid var(--color-border);
  text-align: start;
  vertical-align: middle;
}

.table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--color-cream);
  font-weight: 800;
  white-space: nowrap;
}

.table .num {
  font-variant-numeric: tabular-nums;
  text-align: end;
}

.table__empty {
  padding-block: var(--space-6);
  color: var(--color-ink-soft);
  text-align: center;
}

.table--stack thead {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

.table--stack :where(tbody, tr, td) {
  display: block;
}

.table--stack tr {
  padding-block: var(--space-2);
  border-block-end: 1px solid var(--color-ink-soft);
}

.table--stack td {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  border: 0;
  text-align: end;
}

.table--stack td::before {
  content: attr(data-label);
  font-weight: 800;
  text-align: start;
}

.table--stack td:not([data-label])::before {
  content: none;
}

@media (min-width: 48rem) {
  .table--stack thead {
    position: static;
    inline-size: auto;
    block-size: auto;
    overflow: visible;
    clip-path: none;
  }

  .table--stack tbody {
    display: table-row-group;
  }

  .table--stack tr {
    display: table-row;
    padding-block: 0;
    border-block-end: 0;
  }

  .table--stack td {
    display: table-cell;
    border-block-end: 1px solid var(--color-border);
    text-align: start;
  }

  .table--stack td::before {
    content: none;
  }

  .table--stack td.num {
    text-align: end;
  }
}
}
@layer components {
/* Orange round icon badge from the KV content slides: a line icon (IconHelper, currentColor)
   centred in an orange disc. White on orange is 3.4:1, above the 3:1 needed for graphics.
   --outline: an orange line icon on no ground ("What makes it special").
   --soft: a pale orange disc with a deep orange icon ("What you need").
   --large: a bigger disc for the lead cards. */
.icon-badge {
  --badge-size: 3.5rem;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: var(--badge-size);
  height: var(--badge-size);
  border-radius: 50%;
  background: var(--color-orange);
  color: var(--color-white);
  box-shadow: 0 0.75rem 1.25rem -0.75rem var(--color-orange-glow);
}

.icon-badge svg {
  width: 52%;
  height: 52%;
}

.icon-badge--large {
  --badge-size: 4.5rem;
}

.icon-badge--outline {
  background: none;
  color: var(--color-orange);
  box-shadow: none;
}

.icon-badge--outline svg {
  width: 80%;
  height: 80%;
}

.icon-badge--soft {
  background: color-mix(in srgb, var(--color-orange) 12%, var(--color-white));
  color: var(--color-orange-deep);
  box-shadow: none;
}

/* Isometric illustrations (iso_icon, 240x240) beside the text that names them. The element keeps
   its width and height attributes for layout; each section sets --iso-size where it uses one.
   They are decorative and static, so there is no motion to reduce. */
:is(.card__icon, .step__icon, .feature__icon, .cta__icon) {
  display: block;
  flex: none;
  width: var(--iso-size, 6rem);
  height: var(--iso-size, 6rem);
}
}
@layer components {
/* Section heading in the KV's content-slide language: a small tracked eyebrow led by two
   slashes, orange then blue ("// REGISTRATION MECHANISM"), then a heavy italic condensed
   headline in caps with the key word picked out in orange: <em class="section-heading__accent">.
   Orange on white is 3.4:1, fine at headline size (large text). */
.section-heading {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
  margin-block-end: var(--space-7);
}

.section-heading__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-headline);
  font-size: 1rem;
  font-style: italic;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

.section-heading__eyebrow::before {
  content: "";
  flex: none;
  width: 3px;
  height: 1.1em;
  margin-inline-end: calc(var(--space-3) + 6px); /* clears the blue twin drawn 8px to the right */
  background: var(--color-orange);
  transform: skewX(-12deg);
  box-shadow: 8px 0 0 var(--color-blue);
}

.section-heading__title {
  font-family: var(--font-headline);
  font-size: clamp(2.4rem, 1.6rem + 3.6vw, 4.5rem);
  font-style: italic;
  font-weight: 800;
  line-height: 0.92;
  letter-spacing: -0.005em;
  text-transform: uppercase;
  text-wrap: balance;
}

.section-heading__accent {
  font-style: inherit;
  color: var(--color-orange);
}

.section-heading__text {
  max-width: var(--measure);
  color: var(--color-ink-soft);
}

/* A heading inside a section (h3): the same voice, a size down. */
.section-heading--sub {
  margin-block-end: var(--space-6);
}

.section-heading--sub .section-heading__title {
  font-size: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
}

/* On ink panels. */
.section-heading--light .section-heading__eyebrow {
  color: var(--color-on-ink-soft);
}

.section-heading--light .section-heading__title {
  color: var(--color-white);
}

/* The blue twin of the eyebrow slashes vanishes on ink and on blue-deep: it turns white. */
.section-heading--light .section-heading__eyebrow::before {
  box-shadow: 8px 0 0 var(--color-white);
}

.section--blue-deep .section-heading__accent {
  color: var(--color-amber-soft);
}

.section--blue-deep .section-heading__text {
  color: var(--color-on-blue-soft);
}
}
@layer components {
/* Site nav on the Generic KV: a white bar with the POWER UP RUN 20/26 lock-up as the home link,
   ink links with an orange underline for hover, focus and the current section, and the orange
   registration button. A thin orange-to-amber rule runs along its bottom edge.
   Without JS: logo plus a wrapping row of links and the registration button. With JS (html.js):
   a full-screen white overlay menu with the KV streaks below 80rem, inline links and button from
   80rem (nav_controller's DESKTOP_QUERY matches). Six links plus the button need the wider bar. */
.site-nav {
  position: relative; /* no JS: sits in the flow so wrapped links never cover content */
  z-index: 50;
  background: var(--color-white);
  transition: box-shadow var(--duration-base) var(--ease-out);
}

/* The KV rule along the bottom edge. */
.site-nav::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  z-index: 3;
  height: 3px;
  background: var(--gradient-kv);
  pointer-events: none;
}

.js .site-nav {
  position: fixed;
  inset: 0 0 auto 0;
}

.js .site-nav.is-scrolled {
  box-shadow: 0 0.5rem 1.25rem -0.75rem rgb(27 27 31 / 0.35);
}

.site-nav__bar {
  position: relative;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  min-height: var(--nav-height);
  padding-block: var(--space-2);
}

/* Fixed with JS: exactly --nav-height tall, so the hero's offset and the countdown bar below it
   line up at every width (the overlay menu is out of flow; only the logo and burger, or the
   one-row desktop menu, sit in the bar). */
.js .site-nav__bar {
  height: var(--nav-height);
}

/* Home link: the lock-up. */
.site-nav__brand {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  text-decoration: none;
  transition: transform var(--duration-fast) var(--ease-out);
}

.site-nav__brand:hover,
.site-nav__brand:focus-visible {
  transform: translateY(-2px) rotate(-2deg);
}

.site-nav__logo {
  width: auto;
  height: 3.5rem;
}

/* Burger (JS only) */
.site-nav__toggle {
  position: relative;
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
}

.js .site-nav__toggle {
  display: block;
}

.site-nav__toggle-bar {
  position: absolute;
  left: 0.6875rem;
  width: 1.375rem;
  height: 3px;
  background: var(--color-ink);
  transition:
    transform var(--duration-base) var(--ease-out),
    background-color var(--duration-fast) var(--ease-out);
}

.site-nav__toggle-bar:nth-child(1) {
  top: 1rem;
}

.site-nav__toggle-bar:nth-child(2) {
  top: 1.625rem;
}

.site-nav__toggle:hover .site-nav__toggle-bar {
  background: var(--color-orange);
}

.site-nav.is-open .site-nav__toggle-bar:nth-child(1) {
  transform: translateY(0.3125rem) rotate(45deg);
}

.site-nav.is-open .site-nav__toggle-bar:nth-child(2) {
  transform: translateY(-0.3125rem) rotate(-45deg);
}

/* Menu: no-JS base is a plain wrapping row */
.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--space-4);
}

.site-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--color-ink);
  transition: color var(--duration-fast) var(--ease-out);
}

.site-nav__link::after {
  content: "";
  position: absolute;
  inset: auto 0 0.4rem 0;
  height: 3px;
  background: var(--color-orange);
  transform: scaleX(0) skewX(-12deg);
  transform-origin: right center;
  transition: transform var(--duration-base) var(--ease-out);
}

/* Small orange text needs the deeper orange (AA); the underline carries the KV orange. */
.site-nav__link:hover,
.site-nav__link:focus-visible,
.site-nav__link[aria-current="true"] {
  color: var(--color-orange-deep);
}

.site-nav__link:hover::after,
.site-nav__link:focus-visible::after,
.site-nav__link[aria-current="true"]::after {
  transform: scaleX(1) skewX(-12deg);
  transform-origin: left center;
}

/* Overlay menu on small screens: white, with the KV streaks in the bottom-right corner. */
.js .site-nav__menu {
  position: fixed;
  inset: 0;
  z-index: -1; /* inside .site-nav__bar's stacking context: under the brand and burger */
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: calc(var(--nav-height) + var(--space-5)) var(--gutter) var(--space-7);
  background:
    url("/assets/kv/streaks_right-752a6898.webp") right bottom / auto min(55vh, 30rem) no-repeat,
    var(--color-white);
  overflow-y: auto;
  visibility: hidden;
  opacity: 0;
  transform: translateY(-100%);
  transition:
    transform var(--duration-base) var(--ease-out),
    opacity var(--duration-base) var(--ease-out),
    visibility 0s linear var(--duration-base);
}

.js .site-nav.is-open .site-nav__menu {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition-delay: 0s;
}

.js .site-nav__list {
  flex-direction: column;
  gap: var(--space-1);
}

.js .site-nav__link {
  min-height: 3.25rem;
  font-family: var(--font-headline);
  font-size: var(--step-4);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0;
}

.js .site-nav__link::after {
  inset: auto auto 0.1rem 0;
  width: 4rem;
  height: 5px;
}

.js .site-nav__item {
  opacity: 0;
  transform: translateY(1.5rem);
  transition:
    opacity var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}

.js .site-nav.is-open .site-nav__item {
  opacity: 1;
  transform: none;
  transition-delay: calc(150ms + var(--i, 0) * 60ms);
}

.site-nav__item:nth-child(2) { --i: 1; }
.site-nav__item:nth-child(3) { --i: 2; }
.site-nav__item:nth-child(4) { --i: 3; }
.site-nav__item:nth-child(5) { --i: 4; }
.site-nav__item:nth-child(6) { --i: 5; }
.site-nav__item:nth-child(7) { --i: 6; }
.site-nav__item:nth-child(8) { --i: 7; }

/* Registration button: after the links. In the overlay it fades in with them. */
.site-nav__menu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
}

.site-nav__cta {
  padding-inline-start: 0.5rem; /* offsets the skew */
}

.js .site-nav__menu {
  flex-wrap: nowrap; /* the overlay scrolls; it must not wrap into a second column */
  justify-content: safe center; /* short screens: start at the top so nothing is cut off */
  align-items: flex-start;
}

.js .site-nav__cta {
  margin-block-start: var(--space-5);
  opacity: 0;
  transform: translateY(1.5rem);
  transition:
    opacity var(--duration-base) var(--ease-out),
    transform var(--duration-base) var(--ease-out);
}

.js .site-nav.is-open .site-nav__cta {
  opacity: 1;
  transform: none;
  transition-delay: 510ms;
}

@media (min-width: 48rem) {
  .site-nav__logo {
    height: 3.75rem;
  }
}

@media (min-width: 80rem) {
  .site-nav__bar {
    flex-wrap: nowrap;
    max-width: 90rem;
  }

  .site-nav__cta .button {
    white-space: nowrap;
  }

  .js .site-nav__cta {
    margin-block-start: 0;
    opacity: 1;
    transform: none;
    transition: none;
  }

  .site-nav__toggle,
  .js .site-nav__toggle {
    display: none;
  }

  .site-nav__list,
  .js .site-nav__list {
    flex-direction: row;
    gap: 0 var(--space-5); /* logo + six links + button fit one row from 80rem (1280px) */
  }

  .js .site-nav__menu {
    position: static;
    inset: auto;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--space-6);
    padding: 0;
    background: transparent;
    overflow: visible;
    visibility: visible;
    opacity: 1;
    transform: none;
    transition: none;
  }

  .js .site-nav__item {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .site-nav__link,
  .js .site-nav__link {
    min-height: 2.75rem;
    font-family: var(--font-body);
    font-size: var(--step--1);
    font-style: normal;
    font-weight: 600;
    letter-spacing: 0.12em;
  }

  .js .site-nav__link::after {
    inset: auto 0 0.4rem 0;
    width: auto;
    height: 3px;
  }
}

@media (forced-colors: active) {
  .site-nav__toggle-bar,
  .site-nav__toggle:hover .site-nav__toggle-bar {
    background: CanvasText;
  }

  .site-nav__cta .button {
    border: 2px solid ButtonText;
  }
}
}
@layer components {
/* Signature motion helpers shared across the home page: the top-edge shine that plays on hosts
   marked data-reveal-edge once reveal_controller adds `.is-revealed`. */
:where(.js [data-reveal-edge]) {
  position: relative;
}

.reveal__edge {
  position: absolute;
  inset: 0 var(--radius-card) auto;
  height: 3px;
  overflow: hidden;
  pointer-events: none;
}

.reveal__edge::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 40%;
  background: linear-gradient(110deg, transparent, var(--color-amber) 45%, var(--color-white) 55%, transparent);
  transform: translateX(-100%);
}

/* The delay is constant: reveal_controller drops --reveal-delay on the first transitionend, and a
   changed animation-delay would make the running animation jump. */
.is-revealed > .reveal__edge::after {
  animation: reveal-edge 700ms var(--ease-out) 250ms both;
}

@keyframes reveal-edge {
  to {
    transform: translateX(250%);
  }
}

@keyframes hero-logo-shine {
  from {
    transform: translateX(-150%);
  }

  to {
    transform: translateX(150%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .reveal__edge {
    display: none;
  }
}
}
@layer components {
/* Footer = 11 Contact & Footer. First the KV sign-off on white: the partner logos (KTPC, Kulim
   Hi-Tech Park, NUR Power), "Gear up. Run together." and the royal-blue tagline bar, framed by
   the KV streaks at both edges. Then an ink panel with the contact copy and organiser details
   beside the event name, registration button, quick links and social status, then the legal
   line. Unconfirmed details show a "To Be Confirmed" marker (.tbc). */
.footer {
  background: var(--color-ink);
  color: var(--color-white);
}

/* ---- Sign-off ---- */
.footer__signoff {
  position: relative;
  padding-block: var(--space-8);
  background:
    url("/assets/kv/streaks_left-24842820.webp") left top / auto 55% no-repeat,
    url("/assets/kv/streaks_right-752a6898.webp") right bottom / auto 55% no-repeat,
    var(--color-white);
  border-block-start: 1px solid var(--color-line);
  color: var(--color-ink);
}

.footer__signoff-inner {
  display: grid;
  justify-items: center;
  gap: var(--space-5);
  text-align: center;
}

.footer__partners {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-4) var(--space-6);
}

.footer__partner {
  width: auto;
}

.footer__partner--ktpc {
  height: 1.75rem;
}

.footer__partner--khtp {
  height: 3rem;
}

.footer__partner--nur {
  height: 2.5rem;
}

.footer__signoff-line {
  font-family: var(--font-headline);
  font-size: clamp(2.6rem, 1.6rem + 4.4vw, 5.25rem);
  font-style: italic;
  font-weight: 800;
  line-height: 0.92;
  text-transform: uppercase;
  text-wrap: balance;
}

.footer__signoff-accent {
  display: block;
  font-style: inherit;
  color: var(--color-orange); /* large text: 3.4:1 */
}

/* The KV tagline bar: white italic caps on a slanted royal-blue bar with an orange edge. */
.footer__tagline {
  max-width: calc(100% - 0.75rem);
  margin-inline-start: 0.75rem; /* room for the edge */
  padding: var(--space-2) var(--space-4);
  background: var(--color-blue);
  color: var(--color-white);
  font-family: var(--font-headline);
  font-size: clamp(0.8rem, 0.55rem + 1.25vw, 1.35rem); /* one line from 320px, as on the KV */
  font-style: italic;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transform: skewX(-12deg);
  box-shadow: -0.375rem 0.375rem 0 var(--color-orange);
}

.footer__tagline-text {
  display: block;
  transform: skewX(12deg);
}

@media (min-width: 48rem) {
  .footer__tagline {
    padding-inline: var(--space-5);
  }

  .footer__signoff {
    background-size: auto 100%, auto 100%, auto;
  }

  .footer__partner--ktpc {
    height: 2.25rem;
  }

  .footer__partner--khtp {
    height: 3.75rem;
  }

  .footer__partner--nur {
    height: 3.25rem;
  }
}

/* ---- Contact and aside (ink panel) ---- */
.footer__main {
  display: grid;
  gap: var(--space-8);
  padding-block: var(--space-8);
}

.footer__contact {
  display: grid;
  align-content: start;
}

.footer__contact .section-heading {
  margin-block-end: var(--space-6);
}

.footer__intro {
  display: grid;
  gap: var(--space-3);
  max-width: var(--measure);
  color: var(--color-on-ink-soft);
}

.footer__intro-lead {
  font-size: var(--step-1);
  font-weight: 600;
  color: var(--color-white);
}

.footer__subtitle {
  margin-block: var(--space-7) var(--space-4);
  font-family: var(--font-headline);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 800;
  line-height: 1.1;
  text-transform: uppercase;
  color: var(--color-white);
}

.organiser {
  display: grid;
  margin: 0;
  border-block-start: 1px solid var(--color-ink-line);
}

.organiser__row {
  display: grid;
  gap: var(--space-1);
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--color-ink-line);
}

.organiser__label {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-on-ink-soft);
}

.organiser__value {
  margin: 0;
  font-weight: 600;
}

@media (min-width: 48rem) {
  .organiser__row {
    grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
    align-items: center;
    gap: var(--space-5);
  }
}

/* Aside: event name, CTA, quick links, social status */
.footer__aside {
  display: grid;
  align-content: start;
  gap: var(--space-6);
}

.footer__brand {
  display: grid;
  gap: var(--space-2);
}

.footer__brand-name {
  font-family: var(--font-headline);
  font-size: var(--step-3);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
}

.footer__brand-year {
  color: var(--color-orange); /* 5.1:1 on ink */
}

.footer__organised {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--color-on-ink-soft);
}

/* Tighter than the default button so the longest phase label ("Registration Opening Soon")
   stays on one line in the footer column from 48rem; on phones it wraps beside the arrow. */
.footer__cta .button {
  margin-inline-start: 0.75rem; /* offsets the skew and edge so the left edges line up */
  padding-inline: var(--space-5);
}

.footer__label {
  display: block;
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-on-ink-soft);
}

.footer__nav .footer__label {
  margin-block-end: var(--space-2);
}

.footer__nav-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: var(--space-5);
}

.footer__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  text-decoration: none;
  color: var(--color-white);
}

.footer__link::after {
  content: "";
  position: absolute;
  inset: auto 0 0.5rem 0;
  height: 2px;
  background: var(--color-orange);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--duration-base) var(--ease-out);
}

.footer__link:hover::after,
.footer__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left center;
}

.footer__social {
  display: grid;
  justify-items: start;
  gap: var(--space-2);
}

.footer__legal {
  padding-block: var(--space-5);
  border-top: 1px solid var(--color-ink-line);
  font-size: var(--step--1);
  color: var(--color-on-ink-soft);
}

.footer__legal-inner {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2) var(--space-6);
}

.footer__legal-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
}

.footer__legal-list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}

@media (min-width: 48rem) {
  .footer__nav-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 64rem) {
  .footer__main {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-8);
  }

  .footer__nav-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
}
@layer components {
/* Countdown bar (countdown_bar_controller): the KV lock-up, a run of speed slashes and four
   italic orange numerals on blue label plates counting down to race day. Always shown on the public pages
   that render it (layouts/application), in both BUKAK_KEDAI modes; without the nav it sits at
   the top edge (--nav-height is 0). The visible timer is aria-hidden; screen readers get its
   once-a-minute summary. Without JS it is never displayed, since only the controller can fill in
   the numerals.
   Below 64rem: a white strip fixed directly under the nav. Below 48rem the phase heading is
   dropped; below 30rem the labels shorten to D/H/M/S.
   From 64rem: pinned to the bottom of the viewport as a white panel in the bottom-right corner,
   its left edge slanted like the KV streaks, with the slashes running along that edge. The bar
   itself is transparent there and lets clicks through. */
.countdown-bar {
  display: none;
}

.js .countdown-bar {
  position: fixed;
  inset: var(--nav-height) 0 auto 0;
  z-index: 40; /* under the nav (50), so the menu overlay covers it */
  display: block;
  height: var(--countdown-bar-height);
  background: var(--color-white);
  box-shadow:
    inset 0 -1px 0 var(--color-line),
    0 0.75rem 1.25rem -0.75rem rgb(27 27 31 / 0.3);
  color: var(--color-ink);
}

/* Room for the bar under the nav, so it never covers the top of a page. */
@media (max-width: 63.99rem) {
  .js .countdown-bar ~ .main--below-nav {
    padding-top: calc(var(--nav-height) + var(--countdown-bar-height));
  }
}

.countdown-bar__inner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: 100%;
}

.countdown-bar__logo {
  flex: none;
  width: 3rem;
}

.countdown-bar__logo img {
  width: 100%;
}

/* Speed streaks: a window onto the KV's own left-hand streak art (its 240px band from y = 180 of
   1080: an orange and a blue slash pointing in), scaled to the element's height. On phones they
   come in from the left edge of the screen and fade out towards the dials. */
.countdown-bar__streaks {
  flex: 1 1 auto;
  align-self: stretch;
  max-width: 10rem;
  margin-block: 0.5rem;
  margin-inline-start: calc(var(--gutter) * -1);
  background: url("/assets/kv/streaks_left-24842820.webp") 0 21.4% / auto 450% no-repeat;
  -webkit-mask: linear-gradient(90deg, var(--color-ink) 55%, transparent);
  mask: linear-gradient(90deg, var(--color-ink) 55%, transparent);
}

/* Under the nav the lock-up is already on screen right above, so the strip leaves it out. */
@media (max-width: 63.99rem) {
  :root:not(.without-site-nav) .countdown-bar__logo {
    display: none;
  }
}

/* Hero-only mode: the logo leads, so the streaks follow it. */
.without-site-nav .countdown-bar__streaks {
  margin-inline-start: 0;
}

.countdown-bar__timer {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-width: 0;
  margin-inline-start: auto;
}

.countdown-bar__heading {
  display: none;
  font-family: var(--font-headline);
  font-size: 1.1rem;
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.countdown-bar__units {
  display: flex;
  gap: var(--space-2);
}

.countdown-bar__unit {
  display: grid;
  justify-items: center;
  gap: 0.125rem;
}

/* Numerals: Barlow Condensed italic in KV orange with a white keyline (the stroke is centred, so
   paint-order puts only its outer half on show) and an ink offset shadow. The controller fills
   .dial__value with two or more flipping digits. */
.countdown-bar {
  --digit-size: 1.9rem;
  --digit-shadow: 2px;
}

.dial {
  display: grid;
  justify-items: center;
}

.dial__value {
  display: flex;
  font-family: var(--font-headline);
  font-size: var(--digit-size);
  font-style: italic;
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: 0.01em;
  padding-inline-end: 0.08em;
}

.dial__digit {
  display: inline-grid;
  justify-items: center;
  min-width: 0.5em;
  perspective: 3em;
}

.dial__glyph {
  grid-area: 1 / 1;
  color: var(--color-orange);
  -webkit-text-stroke: 0.12em var(--color-white);
  paint-order: stroke fill;
  text-shadow: var(--digit-shadow) var(--digit-shadow) 0 var(--color-ink);
  backface-visibility: hidden;
}

@supports not (paint-order: stroke fill) {
  .dial__glyph {
    -webkit-text-stroke: 0;
    text-shadow:
      1px 0 0 var(--color-white),
      -1px 0 0 var(--color-white),
      0 1px 0 var(--color-white),
      0 -1px 0 var(--color-white),
      var(--digit-shadow) var(--digit-shadow) 0 var(--color-ink);
  }
}

/* Label plate: a blue slash behind white text (8.4:1); the inner span undoes the skew. */
.countdown-bar__label {
  display: block;
  margin-block-start: 0.1rem;
  padding: 0.15rem 0.55rem;
  background: var(--color-blue);
  transform: skewX(-8deg);
}

.countdown-bar__label-text {
  display: block;
  color: var(--color-white);
  font-family: var(--font-headline);
  font-size: 0.8125rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  transform: skewX(8deg);
}

.countdown-bar__label-long {
  display: none;
}

@media (min-width: 30rem) {
  .countdown-bar {
    --digit-size: 2.1rem;
    --digit-shadow: 3px;
  }

  .countdown-bar__units {
    gap: var(--space-3);
  }

  .countdown-bar__label-long {
    display: inline;
  }

  .countdown-bar__label-short {
    display: none;
  }
}

@media (min-width: 48rem) {
  .countdown-bar__logo {
    width: 3.75rem;
  }

  .countdown-bar {
    --digit-size: 2.5rem;
  }

  .countdown-bar__heading {
    display: block;
  }
}

/* Desktop: pinned to the bottom of the viewport as a corner panel. */
@media (min-width: 64rem) {
  .js .countdown-bar {
    inset: auto 0 0 0;
    background: none;
    box-shadow: none;
    pointer-events: none;
    filter: drop-shadow(0 -0.25rem 0.75rem rgb(27 27 31 / 0.2));
  }

  /* The panel: hugs the right edge, slanted left edge (2rem across the bar's height), the KV
     gradient rule along its top, the slashes filling the slant. */
  .countdown-bar__inner {
    width: max-content;
    max-width: none;
    margin-inline: auto 0;
    padding-inline: 0 var(--gutter);
    gap: var(--space-4);
    background:
      var(--gradient-kv) top / 100% 3px no-repeat,
      var(--color-white);
    clip-path: polygon(2rem 0, 100% 0, 100% 100%, 0 100%);
  }

  .countdown-bar__streaks,
  .without-site-nav .countdown-bar__streaks {
    order: -1;
    flex: none;
    width: 7rem;
    margin: 0;
    -webkit-mask: none;
    mask: none;
  }

  .countdown-bar__logo {
    width: 4.25rem;
  }

  /* Room under the footer and the hero (its scroll cue) so the panel never covers their last
     line. */
  .js .countdown-bar ~ .footer {
    padding-block-end: var(--countdown-bar-height);
  }
}
}

@layer sections {
/* Hero on the Generic KV (slide 33): a white ground with the KV speed streaks coming in from the
   left and right edges (kv/streaks_*.webp, full hero height), and a centred stack with nothing
   behind it: the partner logos, the POWER UP RUN 20/26 lock-up (the h1), "12 DECEMBER 2026" in
   Anton and the venue between orange rules, then (when the site is open) the registration
   button, period and places-left lines and the scroll cue.
   The brand stack takes one width (--hero-stack) and sizes its type and gaps in cqi from it, so
   it keeps the KV's proportions at every size.
   Fixed chrome: --hero-top is what covers the top of the hero (the nav with JS, plus the
   countdown bar under it below 64rem) and --hero-bottom what covers the bottom (the countdown
   bar's corner panel from 64rem); the rules below set them where the countdown bar is shown (this file's layer
   is later than countdown_bar.css's, so these cannot live there). The content
   is padded clear of both; the streaks start below the top one.
   Height: a full screen, capped so very tall viewports do not produce a mostly empty hero. */
.hero {
  --hero-top: 0rem;
  --hero-bottom: 0rem;
  --hero-stack: 15rem;
  --streak-width: clamp(2.5rem, 14vw, 4.5rem);
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  min-height: min(100vh, 68rem);
  min-height: min(100svh, 68rem);
  padding-block: calc(var(--hero-top) + var(--space-6)) calc(var(--hero-bottom) + var(--space-3));
  overflow: clip;
  background: var(--color-white);
  color: var(--color-ink);
}

.js .hero {
  --hero-top: var(--nav-height);
}

@media (max-width: 63.99rem) {
  .js .countdown-bar ~ main .hero {
    --hero-top: calc(var(--nav-height) + var(--countdown-bar-height));
  }
}

@media (min-width: 64rem) {
  .js .countdown-bar ~ main .hero {
    --hero-bottom: var(--countdown-bar-height);
  }
}

/* BUKAK_KEDAI=false: the hero is the whole page, so it fills the viewport with no height cap. */
.hero.hero--only {
  --hero-stack: 17rem;
  min-height: 100vh;
  min-height: 100svh;
  padding-block-end: calc(var(--hero-bottom) + var(--space-6));
}

/* Streaks: each image covers a band at its edge, the full hero height. Below 64rem the bands are
   narrower than the art and show the streaks' dense outer ends, fading out towards the centre;
   from 64rem they are about the art's natural width and keep the tips pointing inward. */
.hero__streaks {
  position: absolute;
  inset: var(--hero-top) 0 0;
  z-index: -1;
  pointer-events: none;
}

.hero__streak {
  position: absolute;
  top: 0;
  width: var(--streak-width);
  height: 100%;
  max-width: none;
  object-fit: cover;
}

.hero__streak--left {
  left: 0;
  object-position: 0 50%;
  -webkit-mask: linear-gradient(90deg, var(--color-ink) 45%, transparent);
  mask: linear-gradient(90deg, var(--color-ink) 45%, transparent);
}

.hero__streak--right {
  right: 0;
  object-position: 100% 50%;
  -webkit-mask: linear-gradient(270deg, var(--color-ink) 45%, transparent);
  mask: linear-gradient(270deg, var(--color-ink) 45%, transparent);
}

/* Above-the-fold content loads in with CSS alone rather than scroll reveal, so it shows on first
   paint without waiting for any module (and without JS). */
@media (prefers-reduced-motion: no-preference) {
  .hero__load-in {
    animation: hero-load-in var(--duration-reveal) var(--ease-out) var(--load-delay, 0ms) both;
  }

  .hero__streak--left {
    animation: hero-streak-in-left var(--duration-slow) var(--ease-out) both;
  }

  .hero__streak--right {
    animation: hero-streak-in-right var(--duration-slow) var(--ease-out) both;
  }

  /* One shine pass over the logo, once the 100ms-delayed load-in has settled. */
  .hero__title::after {
    animation: hero-logo-shine 1100ms var(--ease-out) 900ms both;
  }

  .hero__scroll-icon {
    animation: hero-nudge 1.8s var(--ease-out) 3;
  }
}

/* Parallax (parallax_controller): the individual `translate` property, not `transform`, so it
   composes with the load-in and streak keyframes above, which animate `transform`. Depth 1 (the
   logo) travels at most --parallax-x sideways and --parallax-y + --parallax-scroll vertically. */
.hero.is-parallax [data-parallax-target="layer"] {
  translate:
    calc(var(--px, 0) * var(--depth, 0) * var(--parallax-x))
    calc(var(--py, 0) * var(--depth, 0) * var(--parallax-y) + var(--sy, 0) * var(--depth, 0) * var(--parallax-scroll));
  will-change: translate;
}

/* The streaks (depth 0.3) are flush with the hero's side edges, so drifting them inward would show
   a white sliver; they bleed outward by their largest travel at depth 0.3: sideways
   (--parallax-x) and, top and bottom, vertical (--parallax-y + --parallax-scroll). */
.hero.is-parallax .hero__streak {
  top: calc((var(--parallax-y) + var(--parallax-scroll)) * -0.3);
  height: calc(100% + (var(--parallax-y) + var(--parallax-scroll)) * 0.6);
}

.hero.is-parallax .hero__streak--left {
  left: calc(var(--parallax-x) * -0.3);
}

.hero.is-parallax .hero__streak--right {
  right: calc(var(--parallax-x) * -0.3);
}

.hero__inner {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);
  padding-inline: calc(var(--streak-width) + var(--space-3));
}

/* Brand stack: partners, lock-up, date, venue. */
.hero__brand {
  container-type: inline-size;
  display: grid;
  justify-items: center;
  width: min(var(--hero-stack), 100%);
  text-align: center;
}

.hero__partners {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-2) 6cqi;
  margin-block-end: 5cqi;
}

.hero__partner {
  width: auto;
}

.hero__partner--ktpc {
  height: 9cqi;
}

.hero__partner--khtp {
  height: 15cqi;
}

.hero__partner--nur {
  height: 12cqi;
}

.hero__title,
.hero__logo {
  width: 100%;
}

/* Depth: a tight contact shadow plus a soft drop, on the img itself so the h1 needs no overflow. */
.hero__logo {
  filter: drop-shadow(0 2px 2px rgb(27 27 31 / 0.18)) drop-shadow(0 14px 18px rgb(27 27 31 / 0.16));
}

/* The shine band is white, so it only shows over logo pixels on the white ground. The clip keeps
   it off the streak art beside the logo; 0.5rem above, 1.5rem sideways and 2.5rem below stay
   open so the drop shadow (about 2rem below) is not cut. */
.hero__title {
  position: relative;
  clip-path: inset(-0.5rem -1.5rem -2.5rem);
}

.hero__title::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--shine-band);
  pointer-events: none;
  transform: translateX(-150%);
}

.hero__when {
  display: grid;
  justify-items: center;
  margin-block-start: 5cqi;
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
  white-space: nowrap;
}

.hero__date {
  font-size: 2.25rem; /* without container query units */
  font-size: 12.2cqi;
  letter-spacing: -0.005em;
}

/* Venue between short orange rules. */
.hero__venue {
  display: flex;
  align-items: center;
  gap: 0.45em;
  margin-block-start: 1.5cqi;
  font-size: 1.4rem;
  font-size: 7.6cqi;
  letter-spacing: 0.01em;
}

.hero__venue::before,
.hero__venue::after {
  content: "";
  width: 1.4em;
  height: 0.15em;
  background: var(--color-orange);
}

/* Registration: the skewed button, centred, with the period and places-left lines under it. */
.hero__register {
  display: grid;
  justify-items: center;
  gap: var(--space-3);
  text-align: center;
}

.hero__cta {
  display: grid;
  justify-content: center;
}

.hero__period {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--color-ink);
}

.hero__period strong {
  font-weight: 800;
}

/* Scroll cue */
.hero__scroll {
  align-self: center;
  display: grid;
  justify-items: center;
  gap: var(--space-1);
  min-width: 2.75rem;
  min-height: 2.75rem;
  margin-block-start: var(--space-5);
  padding: var(--space-1);
  color: var(--color-ink);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-decoration: none;
  transition: color var(--duration-fast) var(--ease-out);
}

.hero__scroll:hover,
.hero__scroll:focus-visible {
  color: var(--color-orange-deep);
}

.hero__scroll-icon {
  width: 1.5rem;
  height: 1.5rem;
}

@media (min-width: 48rem) {
  .hero {
    --hero-stack: clamp(18rem, 48vh - 6rem, 24rem);
    --streak-width: 24%;
  }

  .hero.hero--only {
    --hero-stack: clamp(20rem, 56vh - 6rem, 26rem);
  }

  .hero__inner {
    padding-inline: var(--gutter);
  }
}

/* Desktop: the streaks at about their natural width (600 and 665 of 1080 tall), and the stack
   sized to the viewport height so the whole hero, scroll cue included, fits above the countdown
   bar on screens down to 720px tall. */
@media (min-width: 64rem) {
  .hero {
    --hero-stack: clamp(13rem, 70vh - 17rem, 21rem);
    --streak-width: 34%;
  }

  .hero__streak--left,
  .hero__streak--right {
    -webkit-mask: none;
    mask: none;
  }

  .hero__streak--left {
    object-position: 100% 50%;
  }

  .hero__streak--right {
    width: calc(var(--streak-width) * 1.1);
    object-position: 0 50%;
  }

  .hero.hero--only {
    --hero-stack: clamp(18rem, 62vh - 6rem, 27rem);
  }
}

@keyframes hero-load-in {
  from {
    opacity: 0;
    transform: translate(-1.5rem, 1.5rem);
  }
}

@keyframes hero-streak-in-left {
  from {
    opacity: 0;
    transform: translateX(-25%);
  }
}

@keyframes hero-streak-in-right {
  from {
    opacity: 0;
    transform: translateX(25%);
  }
}

@keyframes hero-nudge {
  0%,
  100% {
    opacity: 0.55;
    transform: translateY(-3px);
  }

  50% {
    opacity: 1;
    transform: translateY(4px);
  }
}
}
@layer sections {
/* Shared content blocks: running copy (.prose), a two-column copy + details split, the
   sub-section heading (.subhead: "— KEY PILLARS"), small print (.note), the skewed status tag
   and the "To Be Confirmed" marker. */

.prose {
  display: grid;
  gap: var(--space-4);
  max-width: var(--measure);
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

.prose__lead {
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-ink);
}

.prose strong {
  color: var(--color-ink);
  font-weight: 800;
}

.split {
  display: grid;
  gap: var(--space-7);
  align-items: start;
}

@media (min-width: 64rem) {
  .split {
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
    gap: var(--space-8);
  }
}

/* Sub-section heading in the eyebrow style, led by an orange dash; the accent word is deep
   orange (small text: 5.2:1 on white, 4.9:1 on cream). */
.subhead {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block: var(--space-8) var(--space-6);
  font-family: var(--font-headline);
  font-size: 1rem;
  font-style: italic;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.subhead::before {
  content: "";
  flex: none;
  width: 1.75rem;
  height: 3px;
  background: var(--color-orange);
}

.subhead__accent {
  color: var(--color-orange-deep);
}

/* Small print under a block: "subject to change" and the like. */
.note {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  max-width: var(--measure);
  margin-block-start: var(--space-5);
  font-size: var(--step--1);
  color: var(--color-ink-soft);
}

.note__icon {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  color: var(--color-orange-deep);
}

.section--blue-deep .note {
  color: var(--color-on-blue-soft);
}

.section--blue-deep .note__icon {
  color: var(--color-amber-soft);
}

/* Skewed label, e.g. "Coming Soon" beside a heading. */
.tag {
  --skew: -12deg;
  display: inline-block;
  padding: var(--space-1) var(--space-4);
  background: var(--color-ink);
  color: var(--color-amber);
  font-size: var(--step--1);
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transform: skewX(var(--skew));
}

/* A detail the organiser has not confirmed yet. Dashed outline + text, never colour alone. */
.tbc {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.1em 0.6em;
  border: 2px dashed var(--color-orange-deep);
  color: var(--color-orange-deep);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 800;
  letter-spacing: 0.08em;
  line-height: 1.5;
  text-transform: uppercase;
}

.tbc--night {
  border-color: var(--color-amber);
  color: var(--color-amber);
}
}
@layer sections {
/* Shared content blocks for the home sections, in the KV's content-slide language.
   .features: icon badge + title + text, in columns (default), centred (--center) with hairlines
   between the columns once they share a row (--divided), or as rows with the badge on the left
   (--rows).
   .cards: cream cards (white on cream sections) in a grid: --2 and --4 set the column counts.
   .details: a definition list of label/value rows, each label led by a small badge. */

/* Blocks that follow one another inside a section keep apart. */
:is(.cards, .features, .steps) + :is(.cards, .features, .steps) {
  margin-block-start: var(--space-6);
}

/* ---- Features ---- */
.features {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: var(--space-6);
}

.feature {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--space-2);
}

.feature > .icon-badge {
  margin-block-end: var(--space-2);
}

.feature__title,
.card__title {
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  text-wrap: balance;
}

.feature__text,
.card__text {
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

.features--center .feature {
  justify-items: center;
  text-align: center;
}

.features--divided {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-6) var(--space-4);
}

@media (min-width: 64rem) {
  .features--divided {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0;
  }

  .features--divided .feature {
    padding-inline: var(--space-5);
  }

  .features--divided .feature + .feature {
    border-inline-start: 1px solid var(--color-line);
  }
}

.features--rows {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  gap: var(--space-5) var(--space-6);
}

.features--rows .feature {
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--space-4);
  align-items: start;
}

.features--rows .feature > .icon-badge {
  margin-block-end: 0;
}

/* Rows led by an isometric item: one icon column so the text lines up whether a row has an
   illustration or a badge. */
.features--iso .feature {
  grid-template-columns: 5rem minmax(0, 1fr);
}

.features--iso .feature > .icon-badge {
  justify-self: center;
}

.features--iso .feature > .feature__icon {
  --iso-size: 5rem;
  margin-block: -0.75rem;
}

.feature__body {
  display: grid;
  gap: var(--space-1);
}

/* ---- Cards ---- */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-4);
}

@media (min-width: 36rem) {
  .cards--4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 48rem) {
  .cards--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
  }
}

@media (min-width: 48rem) {
  .cards--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-5);
  }
}

@media (min-width: 64rem) {
  .cards--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.card {
  display: grid;
  align-content: start;
  justify-items: start;
  gap: var(--space-2);
  padding: var(--space-5);
  background: var(--color-cream);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
}

.section--cream .card {
  background: var(--color-white);
}

.card > .icon-badge {
  margin-block-end: var(--space-2);
}

/* The isometric scenes are drawn with room for their ground shadow, so they run larger than a badge. */
.card > .card__icon {
  --iso-size: 9rem;
  margin-block: calc(var(--space-4) * -1) calc(var(--space-3) * -1);
}

/* Small tracked label above a card title ("Station 1"). Deep orange: 4.9:1 on cream. */
.card__kicker {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-orange-deep);
}

/* Phones: the four-up cards turn into compact rows (badge left), so eight of them don't make a
   long stack. */
@media (max-width: 35.99rem) {
  .cards--4 .card {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--space-4);
    padding: var(--space-4);
  }

  .cards--4 .card > .icon-badge {
    grid-row: span 3;
    margin-block-end: 0;
  }

  .cards--4 .card > .card__icon {
    --iso-size: 6.5rem;
    grid-row: span 3;
    align-self: center;
    margin-block: 0;
  }
}

/* Badge on the left, title and bullets on the right (stacked on phones). */
.card--row {
  padding: var(--space-6);
}

@media (min-width: 36rem) {
  .card--row {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--space-5);
  }

  .card--row > .icon-badge {
    margin-block-end: 0;
  }
}

.card__body {
  display: grid;
  gap: var(--space-3);
}

.card__body > p {
  margin: 0;
  color: var(--color-ink-soft);
}

.card__list {
  display: grid;
  gap: var(--space-2);
}

.card__list > li {
  position: relative;
  padding-inline-start: var(--space-5);
  color: var(--color-ink-soft);
}

.card__list > li::before {
  content: "";
  position: absolute;
  top: 0.6em;
  left: 0.2rem;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--color-orange);
}

/* ---- Details (dl) ---- */
.details {
  display: grid;
  gap: var(--space-5);
}

.detail {
  display: grid;
  gap: var(--space-1);
}

.detail__label {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

.detail__label .icon-badge {
  --badge-size: 2.5rem;
}

.detail__value {
  padding-inline-start: calc(2.5rem + var(--space-3)); /* under the label text, clear of the badge */
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.15;
  text-transform: uppercase;
}

.details.card {
  padding: var(--space-6);
}
}
@layer sections {
/* Numbered steps (registration, MELP "how it works", lucky draw). Each step is numbered in an
   orange circle (a CSS counter: the <ol> already gives assistive tech the numbering), with its
   icon in orange line, a title and a line of text. Phones: one column, the circles joined by a
   vertical line. Wider: a grid; when every step shares one row (--4 from 64rem, --7 from 80rem)
   a horizontal line runs from each circle to the next. The lines draw in when revealed. */
.steps {
  --number-size: 3rem;
  --steps-gap: var(--space-6);
  display: grid;
  gap: var(--steps-gap);
  counter-reset: step;
}

.step {
  position: relative;
  display: grid;
  grid-template-columns: var(--number-size) minmax(0, 1fr);
  column-gap: var(--space-4);
  row-gap: var(--space-1);
  align-content: start;
  counter-increment: step;
}

.step::before {
  content: counter(step, decimal-leading-zero);
  grid-row: 1 / span 3;
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--number-size);
  height: var(--number-size);
  border-radius: 50%;
  background: var(--color-orange);
  color: var(--color-white);
  font-family: var(--font-display);
  font-size: 1.25rem;
  line-height: 1;
  box-shadow: 0 0 0 0.3rem var(--step-ring, var(--color-white));
}

.section--cream .step {
  --step-ring: var(--color-cream);
}

/* Connector to the next step. */
.step:not(:last-child)::after {
  content: "";
  position: absolute;
  top: var(--number-size);
  left: calc(var(--number-size) / 2 - 1px);
  width: 2px;
  height: calc(100% - var(--number-size) + var(--steps-gap));
  background: linear-gradient(var(--color-orange), var(--color-amber));
  transform-origin: top center;
  transition: transform 600ms var(--ease-out) calc(200ms + var(--i, 0) * 150ms);
}

.js .steps:not(.is-revealed) > .step::after {
  transform: scaleY(0);
}

.step > .icon-badge {
  --badge-size: 2.25rem;
  background: none;
  color: var(--color-orange);
  box-shadow: none;
}

.step > .icon-badge svg {
  width: 100%;
  height: 100%;
}

/* Steps led by an isometric scene: every step reserves the same icon height so the titles line
   up, and a step that keeps a flat badge centres it in that height. */
.steps--iso .step > .step__icon {
  --iso-size: 6rem;
  margin-block: -1.25rem;
}

.steps--iso .step > .icon-badge {
  --badge-size: 2.25rem;
  height: 3.5rem;
  margin-block: 0.25rem;
}

.step__title {
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.05;
  text-transform: uppercase;
  text-wrap: balance;
}

.step__text {
  max-width: 34ch;
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

.step__text strong {
  color: var(--color-ink);
  font-weight: 800;
}

/* Grid layouts: the circle sits on top of the step; no connectors while the grid wraps. */
@media (min-width: 36rem) {
  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-5);
  }

  .step {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-2);
  }

  .step::before {
    grid-row: auto;
    margin-block-end: var(--space-2);
  }

  .step:not(:last-child)::after {
    display: none;
  }
}

@media (min-width: 64rem) {
  .steps--4,
  .steps--7 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .steps--4 > .step:not(:last-child)::after {
    display: block;
    top: calc(var(--number-size) / 2 - 1px);
    left: calc(var(--number-size) + var(--space-3));
    width: calc(100% - var(--number-size) - var(--space-3) * 2 + var(--steps-gap));
    height: 2px;
    background: linear-gradient(90deg, var(--color-orange), var(--color-amber));
    transform-origin: left center;
  }

  .js .steps--4:not(.is-revealed) > .step::after {
    transform: scaleX(0);
  }
}

@media (min-width: 80rem) {
  .steps--7 {
    --steps-gap: var(--space-4);
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }

  .steps--7 > .step:not(:last-child)::after {
    display: block;
    top: calc(var(--number-size) / 2 - 1px);
    left: calc(var(--number-size) + var(--space-2));
    width: calc(100% - var(--number-size) - var(--space-2) * 2 + var(--steps-gap));
    height: 2px;
    background: linear-gradient(90deg, var(--color-orange), var(--color-amber));
    transform-origin: left center;
  }

  .js .steps--7:not(.is-revealed) > .step::after {
    transform: scaleX(0);
  }

  .steps--7 .step__title {
    font-size: 1.15rem;
  }

  .steps--7 .step__text {
    font-size: var(--step--1);
  }
}
}
@layer sections {
/* About (The Big Idea): heading beside the project background from 64rem, then the key pillars
   (filled badges) and what makes it special (line icons), four across with hairlines. */
.about__intro {
  display: grid;
  gap: var(--space-5);
}

.about__intro .section-heading {
  margin-block-end: 0;
}

@media (min-width: 64rem) {
  .about__intro {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-8);
    align-items: start;
  }
}
}
@layer sections {
/* Event overview: six key facts in a cream panel split by hairlines (2 across on phones, 3 from
   48rem), the eligibility cards, and the diagonal orange slash panel ("5KM. All ages. One
   community."). The panel's type is large text: white is 3.4:1 or better across the gradient.
   The "All ages." accent is blue with a white outline: blue alone is under 3:1 on the orange
   gradient, so the outline (8.4:1 against the blue) carries the contrast and separates the
   glyphs from the panel. */
.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  overflow: hidden;
  background: var(--color-line);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
}

.stat {
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-1);
  padding: var(--space-5) var(--space-3);
  background: var(--color-cream);
  text-align: center;
}

.stat > .icon-badge {
  margin-block-end: var(--space-2);
}

.stat__value {
  font-family: var(--font-display);
  font-size: clamp(1.35rem, 1.1rem + 1.1vw, 2.25rem);
  line-height: 1.05;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.stat__label {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--color-ink-soft);
}

@media (min-width: 48rem) {
  .stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .stat {
    padding: var(--space-6) var(--space-5);
  }
}

.eligibility {
  margin-block-start: var(--space-8);
}

/* ---- Slash panel ---- */
.slash-panel {
  position: relative;
  isolation: isolate;
  margin: var(--space-8) var(--space-3) 0;
  padding: var(--space-6) var(--space-5);
  color: var(--color-white);
  text-align: center;
}

/* The skewed orange panel and a royal-blue slash across its right end, as on the KV. */
.slash-panel::before,
.slash-panel::after {
  content: "";
  position: absolute;
  z-index: -1;
  transform: skewX(-12deg);
}

.slash-panel::before {
  inset: 0;
  background: linear-gradient(100deg, var(--color-orange-deep), var(--color-orange));
}

.slash-panel::after {
  inset-block: -0.5rem;
  right: 10%;
  width: 0.6rem;
  background: var(--color-blue);
  box-shadow: 1.1rem 0 0 -0.15rem var(--color-white);
}

.slash-panel__text {
  display: block;
  font-family: var(--font-headline);
  font-size: clamp(1.9rem, 1.1rem + 3.6vw, 4rem);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  text-wrap: balance;
}

.slash-panel__text em {
  font-style: inherit;
  color: var(--color-blue);
  -webkit-text-stroke: 4px var(--color-white); /* centred, so 2px shows outside the fill */
  paint-order: stroke fill;
}

@supports not (paint-order: stroke fill) {
  .slash-panel__text em {
    -webkit-text-stroke: 0;
    text-shadow:
      2px 0 0 var(--color-white),
      -2px 0 0 var(--color-white),
      0 2px 0 var(--color-white),
      0 -2px 0 var(--color-white),
      2px 2px 0 var(--color-white),
      -2px 2px 0 var(--color-white),
      2px -2px 0 var(--color-white),
      -2px -2px 0 var(--color-white);
  }
}
}
@layer sections {
/* Race kit: the race-pack render on a skewed orange slash, beside the "All participants: complete
   race pack" banner and the four kit items (two across, icon on top). Stacked below 64rem. */
.race-kit {
  display: grid;
  gap: var(--space-7);
  align-items: center;
}

.race-kit__art {
  position: relative;
  isolation: isolate;
  justify-self: center;
  width: min(100%, 26rem);
}

.race-kit__art::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 14% 12% 6%;
  background: var(--gradient-kv);
  transform: skewX(-12deg);
}

.race-kit__render {
  width: 100%;
  height: auto;
  filter: drop-shadow(0 1.5rem 1.5rem rgb(27 27 31 / 0.18));
}

.race-kit__banner {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--color-white);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
}

.race-kit__banner-text {
  display: grid;
  gap: var(--space-1);
  font-family: var(--font-headline);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
}

.race-kit__banner-kind {
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-style: normal;
  font-weight: 600;
  letter-spacing: 0.18em;
  color: var(--color-orange-deep);
}

.kit-items {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
  margin-block-start: var(--space-3);
}

.kit-item {
  display: grid;
  align-content: start;
  justify-items: center;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-3);
  background: var(--color-white);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
  text-align: center;
}

/* The isometric drawings leave room for their ground shadow, so they run larger than a flat icon would. */
.kit-item__icon {
  width: 6.5rem;
  height: 6.5rem;
}

.kit-item__name {
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.05;
  text-transform: uppercase;
}

.kit-item__text {
  font-size: var(--step--1);
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

@media (min-width: 48rem) {
  .kit-items {
    gap: var(--space-4);
  }

  .kit-item {
    padding-inline: var(--space-5);
  }

  .kit-item__icon {
    width: 8rem;
    height: 8rem;
  }

  .kit-item__text {
    font-size: var(--step-0);
  }
}

@media (min-width: 64rem) {
  .race-kit {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: var(--space-8);
  }
}
}
@layer sections {
/* Registration: the four steps (steps.css), what you need, and the CTA with the period and the
   places-left line. */
.registration__needs {
  margin-block-start: var(--space-7);
}

.registration__cta {
  display: grid;
  justify-items: start;
  gap: var(--space-3);
  margin-block-start: var(--space-8);
  padding-inline-start: 0.75rem; /* offsets the skew so the button's left edge looks aligned */
}

.registration__cta-note {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-soft);
}

.registration__places {
  color: var(--color-orange-deep);
}

/* ---- /register ----
   The form page on the KV: streaks at the page edges from 64rem, the eligibility line and a
   reassurance strip under the heading, one cream card with an orange top rule per participant,
   and a state card in place of the form before opening, when full and after closing. These rules
   are in the sections layer, above the shared .card (features.css), and win on specificity. */
.registration-page {
  position: relative;
  overflow-x: clip; /* the streaks never widen the page */
}

.registration-page__streak {
  display: none;
}

@media (min-width: 64rem) {
  .registration-page__streak {
    display: block;
    position: absolute;
    top: var(--space-6);
    width: clamp(5rem, 9vw, 10rem);
    height: auto;
    pointer-events: none;
  }

  .registration-page__streak--left {
    left: 0;
  }

  .registration-page__streak--right {
    right: 0;
    top: auto;
    bottom: var(--space-8);
  }
}

/* From 64rem the head sits in a sticky column beside the form, so the wide screen reads as one
   composed spread instead of a phone column pinned to the left. */
.registration-page__main {
  min-width: 0;
}

@media (min-width: 64rem) {
  .registration-page__layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--width-form));
    column-gap: var(--space-8);
    align-items: start;
  }

  .registration-page__intro {
    position: sticky;
    top: calc(var(--nav-height) + var(--space-6));
  }

  .form-page .registration-page__intro .reassurance {
    flex-direction: column;
    margin-block-start: 0;
  }
}

.form-page .registration-eligibility {
  max-width: var(--measure);
  color: var(--color-text);
  font-weight: 600;
}

/* Reassurance strip: three small soft badges with a short line each, wrapping on phones. */
.form-page .reassurance {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  max-width: var(--width-form);
  margin: calc(var(--space-6) * -0.5) 0 var(--space-6);
  padding: 0;
  list-style: none;
}

.form-page .reassurance__item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text);
}

.form-page .reassurance__item .icon-badge {
  --badge-size: 2.25rem;
}

/* Participant card: a cream card with an orange top rule. The legend is pulled into the card
   (floated, so it lays out as a grid item) with the Remove button on its right. */
.form-page .participant.card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  justify-items: stretch;
  gap: var(--space-4);
  min-width: 0; /* fieldsets default to min-content width, which overflows a 320px screen */
  margin: 0;
  padding: var(--space-5) var(--space-4);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-top: 4px solid var(--color-orange);
  border-radius: var(--radius-card);
}

@media (min-width: 36rem) {
  .form-page .participant.card {
    padding: var(--space-5);
  }
}

.form-page .participant.card > :not(legend, .participant__remove) {
  grid-column: 1 / -1;
}

.form-page .participant__legend {
  float: left;
  min-width: 0;
  padding: 0;
  font-family: var(--font-headline);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.form-page .participant__remove {
  justify-self: end;
  min-height: var(--tap-min);
  padding: var(--space-1) var(--space-3);
  background: none;
  border: 0;
  color: var(--color-danger);
  font: inherit;
  font-size: var(--step--1);
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

.form-page .registration-form__others,
.form-page .registration-form__list {
  display: grid;
  gap: var(--space-4);
}

.form-page .registration-form__list:empty {
  display: none;
}

.form-page .registration-form__hint {
  color: var(--color-text-muted);
  font-size: var(--step--1);
  font-weight: 600;
}

/* PDPA and winners lines just above Register. */
.form-page .registration-form__legal {
  display: grid;
  gap: var(--space-1);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--color-border);
  color: var(--color-text-muted);
  font-size: var(--step--1);
}

.form-page .registration-form__legal a {
  color: var(--color-link);
  font-weight: 700;
}

/* State card (upcoming, full, closed): what happens next, and the way back. */
.form-page .registration-state.card {
  justify-items: start;
  gap: var(--space-4);
  max-width: var(--width-form);
  padding: var(--space-6) var(--space-5);
  background: var(--color-surface-raised);
  border-top: 4px solid var(--color-orange);
}

.form-page .registration-state__text {
  font-size: var(--step-1);
  font-weight: 700;
  line-height: 1.35;
}

.form-page .registration-state__aside {
  color: var(--color-text-muted);
}

.form-page .registration-state .button {
  margin-inline-start: 0.5rem; /* the skew and edge */
}

/* ---- Group entry ----
   The count and Register stay in reach on phones while a long group scrolls; from 48rem the bar sits in the
   page flow. */
.form-page .registration-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.form-page .registration-bar__count {
  font-size: var(--step--1);
  font-weight: 700;
}

@media (max-width: 47.99rem) {
  /* A focused field scrolls clear of the sticky bar. */
  html:has(.registration-bar) {
    scroll-padding-bottom: 6rem;
  }

  .form-page .registration-bar {
    position: sticky;
    bottom: 0;
    z-index: var(--z-sticky);
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface-raised);
    border-block-start: 1px solid var(--color-border);
  }

  .form-page .registration-bar .registration-form__submit {
    width: auto;
    flex: none;
  }
}

/* Without JavaScript nothing can add a card: hide Add and say what to do instead. */
.form-page .registration-form__nojs {
  display: none;
}

html:not(.js) [data-participants-target="add"] {
  display: none;
}

html:not(.js) .form-page .registration-form__nojs {
  display: block;
}

/* ---- /r/:token race wallet ----
   The reference, what happens next and the participants, then the check-in codes: one column on
   phones, two from 64rem with the codes on a cream panel to the right. Every code is a button
   that opens it full size in the qr-zoom dialog. Print rules are in print.css. */
@media (min-width: 64rem) {
  .wallet {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: var(--space-8);
    align-items: start;
  }
}

.wallet__details {
  min-width: 0;
}

/* The reference: the string people read out at the desk, in ink (not orange) for legibility,
   led by the KV's orange slash. */
.form-page .wallet-reference {
  display: grid;
  gap: var(--space-1);
}

.form-page .wallet-reference__label,
.form-page .wallet-reference__event {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.form-page .wallet-reference__code {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-display);
  font-size: var(--step-5);
  line-height: 1.05;
  letter-spacing: 0.04em;
  color: var(--color-text);
  overflow-wrap: normal;
  white-space: nowrap;
}

/* Half the container from 64rem: a size down keeps the reference on one line. */
@media (min-width: 64rem) {
  .form-page .wallet-reference__code {
    font-size: var(--step-4);
  }
}

.form-page .wallet-reference__code::before {
  content: "";
  flex: none;
  width: 0.45rem;
  height: 0.8em;
  background: var(--gradient-kv);
  transform: skewX(-12deg);
}

.form-page .wallet-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-5);
}

/* What happens next: numbered orange circles joined by a line, like the home page steps. */
.form-page .wallet-timeline {
  --number-size: 2.25rem;
  display: grid;
  gap: var(--space-5);
  max-width: var(--width-form);
  counter-reset: wallet-step;
}

.form-page .wallet-timeline__step {
  position: relative;
  display: grid;
  grid-template-columns: var(--number-size) minmax(0, 1fr);
  column-gap: var(--space-4);
  row-gap: var(--space-1);
  counter-increment: wallet-step;
}

.form-page .wallet-timeline__step::before {
  content: counter(wallet-step);
  grid-row: 1 / span 2;
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: var(--number-size);
  height: var(--number-size);
  border-radius: 50%;
  background: var(--color-orange-deep);
  color: var(--color-white);
  font-family: var(--font-display);
  font-size: 1.1rem;
  line-height: 1;
}

.form-page .wallet-timeline__step:not(:last-child)::after {
  content: "";
  position: absolute;
  top: var(--number-size);
  bottom: calc(var(--space-5) * -1);
  left: calc(var(--number-size) / 2 - 1px);
  width: 2px;
  background: linear-gradient(var(--color-orange), var(--color-amber));
}

.form-page .wallet-timeline__title {
  align-self: center;
  min-height: var(--number-size);
  display: flex;
  align-items: center;
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.05;
  text-transform: uppercase;
}

.form-page .wallet-timeline__text {
  color: var(--color-text-muted);
}

.form-page .wallet-timeline__text strong {
  color: var(--color-text);
  font-weight: 700;
  overflow-wrap: anywhere;
}

.form-page .wallet-corrections {
  max-width: var(--width-form);
  margin-block-start: var(--space-5);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-raised);
  border-inline-start: 4px solid var(--color-orange);
  border-radius: var(--radius-sm);
  font-size: var(--step--1);
}

.form-page .wallet-corrections a {
  color: var(--color-link);
  font-weight: 700;
}

.form-page .participant-list {
  display: grid;
  max-width: var(--width-form);
}

.form-page .participant-list__item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1) var(--space-4);
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--color-border);
}

.form-page .participant-list__name {
  font-weight: 600;
}

.form-page .participant-list__meta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
}

.form-page .participant-list__category {
  color: var(--color-text-muted);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* A bib: ink tag, number in the display face. */
.wallet-bib {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  padding: 0.1rem var(--space-2);
  background: var(--color-surface-inverse);
  color: var(--color-white);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.wallet-bib strong {
  font-family: var(--font-display);
  font-size: 1.15em;
  font-weight: 400;
  letter-spacing: 0.06em;
}

.wallet-bib--large {
  font-size: var(--step-0);
}

.form-page .wallet-bib-note {
  max-width: var(--width-form);
  margin-block-start: var(--space-3);
  color: var(--color-text-muted);
  font-size: var(--step--1);
}

/* The codes: a cream panel with the orange top rule. The group code leads, larger. */
.form-page .wallet-codes {
  margin-block-start: var(--space-7);
  padding: var(--space-5);
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-top: 4px solid var(--color-orange);
  border-radius: var(--radius-card);
}

@media (min-width: 64rem) {
  .form-page .wallet-codes {
    margin-block-start: 0;
    padding: var(--space-6);
  }
}

.form-page .wallet-codes .form-page__heading {
  margin-block-start: 0;
}

.form-page .wallet-codes__hint {
  color: var(--color-text-muted);
}

.form-page .wallet-codes__lead {
  margin-block: var(--space-5) var(--space-3);
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.1;
  text-transform: uppercase;
  color: var(--color-text-accent);
}

.form-page .qr-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 8.5rem), 1fr));
  gap: var(--space-4);
}

.qr-card {
  display: grid;
  gap: var(--space-2);
  justify-items: center;
  align-content: start;
  min-width: 0;
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-2);
  text-align: center;
}

.qr-card img.qr {
  display: block;
  width: 100%;
  max-width: 12rem;
  height: auto;
  image-rendering: pixelated;
}

.qr-card--group {
  max-width: 22rem;
  padding: var(--space-4);
}

.qr-card--group img.qr {
  max-width: 18rem;
}

/* The whole code is the tap target; the hint under it says what a tap does. */
.qr-card__zoom {
  display: grid;
  gap: var(--space-1);
  justify-items: center;
  width: 100%;
  padding: var(--space-1);
  background: none;
  border: 0;
  border-radius: var(--radius-sm);
  color: var(--color-text-muted);
  font: inherit;
  cursor: zoom-in;
}

.qr-card__zoom-hint {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--step--1);
  font-weight: 700;
}

.qr-card__zoom-hint svg {
  width: 1rem;
  height: 1rem;
}

.qr-card__zoom:hover .qr-card__zoom-hint {
  color: var(--color-text-accent);
}

.qr-card__caption {
  display: grid;
  gap: var(--space-1);
  justify-items: center;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.qr-card__share {
  min-height: var(--tap-min);
}

/* The zoomed code: a modal in the top layer (above the nav and countdown bar), on a dimmed page. */
.qr-zoom {
  width: min(100% - 2 * var(--space-4), 30rem);
  max-height: calc(100dvh - 2 * var(--space-4));
  padding: 0;
  background: var(--color-surface);
  border: 0;
  border-top: 4px solid var(--color-orange);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-3);
  color: var(--color-text);
}

.qr-zoom::backdrop {
  background: color-mix(in srgb, var(--color-ink) 85%, transparent);
}

.qr-zoom__panel {
  display: grid;
  gap: var(--space-3);
  justify-items: center;
  padding: var(--space-5);
  text-align: center;
}

.qr-zoom__image {
  display: block;
  width: 100%;
  max-width: min(26rem, 70dvh);
  height: auto;
  image-rendering: pixelated;
}

.qr-zoom__caption {
  font-family: var(--font-headline);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 800;
  line-height: 1.05;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.qr-zoom__hint {
  color: var(--color-text-muted);
  font-size: var(--step--1);
}

.qr-zoom__close {
  justify-self: stretch;
}

/* ---- /c/:token personal code (signed out) ---- */
.form-page.personal-code {
  display: grid;
  justify-items: center;
  text-align: center;
}

.form-page.personal-code .section-heading {
  justify-items: center;
}

.qr-card--personal {
  width: 100%;
  max-width: 22rem;
  padding: var(--space-5);
  border-top: 4px solid var(--color-orange);
}

.qr-card--personal img.qr {
  max-width: 18rem;
}
}
@layer sections {
/* Programme ("The night's lineup"): heading and the date line beside the programme table
   (stacked below 64rem). The table keeps real table semantics: time in the row header, then the
   item and a line about it. It sits on the deep-blue section (layout.css): white and soft-blue text,
   amber times, and the flag-off row is the key row on the KV orange-to-amber gradient in ink. */
.itinerary {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
  align-items: start;
}

.itinerary__intro .section-heading {
  margin-block-end: var(--space-5);
}

.itinerary__when {
  display: grid;
  gap: var(--space-1);
  padding-inline-start: var(--space-4);
  border-inline-start: 4px solid var(--color-amber);
}

.itinerary__date {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-on-blue-soft);
}

.itinerary__hours {
  color: var(--color-white);
  font-family: var(--font-display);
  font-size: var(--step-3);
  line-height: 1;
  letter-spacing: 0.02em;
}

.programme {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  overflow: hidden;
  background: rgb(255 255 255 / 0.05);
  border: 1px solid rgb(255 255 255 / 0.18);
  border-radius: var(--radius-card);
  font-size: var(--step-0);
}

.programme thead th {
  padding: var(--space-3);
  background: rgb(0 0 0 / 0.3);
  color: var(--color-white);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-align: start;
  text-transform: uppercase;
}

.programme tbody th,
.programme tbody td {
  padding: var(--space-3);
  border-block-start: 1px solid rgb(255 255 255 / 0.14);
  text-align: start;
  vertical-align: baseline;
}

/* Time ranges only break after the dash (nowrap spans in the HTML). */
.programme__time {
  width: 38%;
}

.programme tbody .programme__time {
  font-family: var(--font-display);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: 0.02em;
  color: var(--color-amber-soft);
  font-variant-numeric: tabular-nums;
}

.programme__event {
  display: block;
  color: var(--color-white);
  font-family: var(--font-headline);
  font-size: var(--step-1);
  font-style: italic;
  font-weight: 800;
  line-height: 1.1;
  text-transform: uppercase;
}

.programme__note {
  display: block;
  margin-block-start: var(--space-1);
  font-size: var(--step--1);
  color: var(--color-on-blue-soft);
}

.programme tbody tr {
  transition: background-color var(--duration-fast) var(--ease-out);
}

@media (hover: hover) {
  .programme tbody tr:hover {
    background: rgb(255 255 255 / 0.06);
  }
}

/* The key row is the KV gradient with ink text (5.1:1 on orange, 7.5:1 on amber); a white bar
   marks it. */
.programme .programme__row--key,
.programme .programme__row--key:hover {
  background: var(--gradient-kv);
  color: var(--color-ink);
  box-shadow: inset 0.375rem 0 0 var(--color-white);
}

.programme .programme__row--key .programme__event,
.programme .programme__row--key .programme__time,
.programme .programme__row--key .programme__note {
  color: var(--color-ink);
}

@media (min-width: 48rem) {
  .programme tbody th,
  .programme tbody td,
  .programme thead th {
    padding-inline: var(--space-5);
  }

  .programme__time {
    width: 13rem; /* the longest range ("8:00 PM – 8:15 PM") on one line */
  }

  .programme tbody .programme__time {
    font-size: var(--step-1);
  }
}

@media (min-width: 64rem) {
  .itinerary {
    grid-template-columns: minmax(0, 0.75fr) minmax(0, 1.25fr);
    gap: var(--space-8);
  }

  .itinerary__intro {
    position: sticky;
    top: calc(var(--nav-height) + var(--space-6));
  }
}
}
@layer sections {
/* Route map section: the official 5KM route map card (pages/_route_map, generated by
   bin/route-map-render from lib/route_path.js, animated by route_map_controller) beside the route
   details, then the three route features. The card is night-themed in the KV palette. Without JS
   the full route shows (road bed, ghost, casing and line; runner, trail and chevrons hidden); under
   reduced motion the controller keeps the full route drawn with the runner at the finish. */
.route-section {
  display: grid;
  gap: var(--space-7);
  align-items: center;
}

.route-section__copy {
  display: grid;
  gap: var(--space-6);
}

@media (min-width: 48rem) and (max-width: 63.99rem) {
  .route-section__copy .details {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.route-features {
  margin-block-start: var(--space-8);
}

@media (min-width: 64rem) {
  .route-section {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    gap: var(--space-8);
  }
}

/* ---- Map card ---- */
.route-map {
  display: grid;
  margin-inline-end: 0.5rem; /* room for the hard shadow */
  background: var(--color-ink);
  border: 2px solid var(--color-ink);
  box-shadow: 0.5rem 0.5rem 0 var(--color-orange);
}

/* Inset from the card edge so badges near the map's edge (2 KM sits at the top) are never cut. */
.route-map__stage {
  position: relative;
  aspect-ratio: 5 / 4;
  margin: var(--space-3) var(--space-3) 0;
}

.route-map__svg {
  width: 100%;
  height: 100%;
}

.route-map__ground {
  fill: var(--color-ink);
}

.route-map__area--green {
  fill: var(--color-map-green);
}

.route-map__area--water {
  fill: var(--color-map-water);
}

.route-map__block {
  fill: #26262D;
}

.route-map__road,
.route-map__bed,
.route-map__ghost,
.route-map__casing,
.route-map__line,
.route-map__trail,
.route-map__chevron {
  fill: none;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.route-map__road {
  stroke: var(--color-ink-line);
  stroke-width: 10;
}

/* The road the course uses, readable before the orange line is drawn. */
.route-map__bed {
  stroke: #3A3A42;
  stroke-width: 26;
}

.route-map__ghost {
  stroke: var(--color-orange);
  stroke-width: 3;
  stroke-dasharray: 2 10;
  opacity: 0.45;
}

.route-map__casing {
  stroke: rgb(255 255 255 / 0.25);
  stroke-width: 18;
}

.route-map__line {
  stroke: var(--color-orange);
  stroke-width: 12;
}

/* Trail, chevrons and runner: only once the controller has taken over. */
.route-map__trail {
  stroke: var(--color-amber);
  stroke-width: 6;
  visibility: hidden;
}

.route-map__stage.is-animated .route-map__trail {
  visibility: visible;
}

.route-map__chevron {
  stroke: var(--color-ink);
  stroke-width: 3.5;
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-out);
}

.route-map__stage.is-powered .route-map__chevron {
  opacity: 1;
}

.route-map__runner {
  display: none;
}

.route-map__stage.is-animated .route-map__runner {
  display: inline;
}

.route-map__runner-halo {
  fill: var(--color-orange-glow);
  transform-box: fill-box;
  transform-origin: center;
  animation: route-map-pulse 1.6s var(--ease-out) 3;
}

.route-map__stage.is-powered .route-map__runner-halo {
  animation-duration: 0.7s;
}

.route-map__runner-dot {
  fill: var(--color-amber);
  stroke: var(--color-ink);
  stroke-width: 3;
}

@keyframes route-map-pulse {
  0%, 100% { transform: scale(0.7); opacity: 1; }
  50% { transform: scale(1.25); opacity: 0.5; }
}

/* HTML overlays (stay legible when the SVG scales down on phones). */
.route-map__tick,
.route-map__station,
.route-map__start-finish,
.route-map__label {
  position: absolute;
  left: var(--x);
  top: var(--y);
}

.route-map__tick,
.route-map__station,
.route-map__start-finish {
  display: grid;
  place-content: center;
  justify-items: center;
  border: 2px solid var(--color-ink);
  border-radius: 50%; /* true circle */
  color: var(--color-white);
  transform: translate(-50%, -50%);
  z-index: 1; /* badges over the road names */
}

.route-map__tick {
  width: 2.25rem;
  height: 2.25rem;
  background: var(--color-purple);
  font-size: 0.875rem;
  font-weight: 800;
  line-height: 1;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
}

.route-map__tick small {
  font-size: 0.5625rem;
  letter-spacing: 0.06em;
}

.route-map__tick.is-passed {
  background: var(--color-amber);
  color: var(--color-ink);
  transform: translate(-50%, -50%) scale(1.12);
}

/* Stations sit a few metres from a km badge (0.18 / 1 KM, 0.38 / 2 KM, 0.62 / 3 KM), so each badge
   stands beside the road, towards the inside of the loop (--inside-x/y from the renderer). */
.route-map__station {
  --beside: 1.75rem;
  width: 1.75rem;
  height: 1.75rem;
  background: var(--color-blue);
  /* The offset lives in `translate` so the pulse's `scale` composes around the badge centre. */
  transform: none;
  translate:
    calc(-50% + var(--inside-x) * var(--beside))
    calc(-50% + var(--inside-y) * var(--beside));
}

.route-map__station svg {
  width: 0.875rem;
  height: 0.875rem;
  fill: currentColor;
}

.route-map__station.is-passed {
  animation: route-map-station-pulse 600ms var(--ease-out);
}

@keyframes route-map-station-pulse {
  0%, 100% { scale: 1; }
  50% { scale: 1.35; }
}

.route-map__start-finish {
  width: 2.5rem;
  height: 2.5rem;
  background: var(--color-orange);
}

.route-map__start-finish svg {
  width: 1.5rem;
  height: 1.5rem;
}

.route-map__flag-pole {
  fill: none;
  stroke: var(--color-ink);
  stroke-width: 3;
  stroke-linecap: round;
}

.route-map__flag {
  fill: var(--color-white);
  stroke: var(--color-ink);
  stroke-width: 2;
}

.route-map__flag-check {
  fill: var(--color-ink);
}

.route-map__label {
  line-height: 1.4;
  white-space: nowrap;
  pointer-events: none;
}

/* Start/finish key, skewed ink with a chequered disc that echoes the marker. The marker sits among
   roads, badges and road names, where a label this long would cover them, so on phones the key is a
   line between the map and the caption, and from 48rem it sits in the map's empty top-left corner. */
.route-map__label--start-finish {
  position: static;
  justify-self: start;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-3) var(--space-4);
  padding: var(--space-1) var(--space-2);
  border: 2px solid var(--color-orange);
  background: var(--color-ink);
  box-shadow: 0.1875rem 0.1875rem 0 var(--color-orange);
  color: var(--color-white);
  font-size: 0.6875rem;
  font-weight: 800;
  letter-spacing: 0.08em;
  line-height: 1.3;
  text-transform: uppercase;
  white-space: normal;
  transform: skewX(-12deg);
}

.route-map__label--start-finish::before {
  content: "";
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  border: 2px solid var(--color-orange);
  border-radius: 50%; /* true circle */
  background: repeating-conic-gradient(var(--color-ink) 0 25%, var(--color-white) 0 50%) 50% / 0.375rem 0.375rem;
}

/* Beside the road (--side from the renderer), so the name never hides the route line. */
.route-map__label--road {
  --beside: 0.875rem;
  padding: 0.0625rem 0.375rem;
  border-radius: 999px; /* pill */
  background: rgb(27 27 31 / 0.7);
  color: var(--color-white);
  font-size: max(0.6875rem, 0.625rem);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transform: translate(-50%, -50%) rotate(var(--rotate)) translateY(calc(var(--side) * var(--beside)));
}

.route-map__label--place {
  width: max-content;
  max-width: 5rem;
  color: var(--color-on-ink-soft);
  font-size: max(0.6875rem, 0.625rem);
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  white-space: normal;
  transform: translate(-50%, -50%);
}

/* Phones keep the road names and markers only, sized to the smaller map. */
@media (max-width: 47.99rem) {
  .route-map__label--place,
  .route-map__label--wide-only {
    display: none;
  }

  .route-map__tick {
    width: 2rem;
    height: 2rem;
  }

  .route-map__station {
    width: 1.5rem;
    height: 1.5rem;
  }

  .route-map__start-finish {
    width: 2rem;
    height: 2rem;
  }

  .route-map__start-finish svg {
    width: 1.25rem;
    height: 1.25rem;
  }

  .route-map__label--road {
    --beside: 0.75rem;
    padding-inline: 0.25rem;
    font-size: max(0.6875rem, 0.5625rem);
    letter-spacing: 0.02em;
  }
}

/* The narrowest phones: road names one step smaller so each fits between its badges. */
@media (max-width: 22rem) {
  .route-map__label--road {
    font-size: max(0.6875rem, 0.5rem);
    letter-spacing: 0;
  }

  /* Too narrow to fit every road name at the readable floor: keep the primary ones. */
  .route-map__label--secondary {
    display: none;
  }
}

@media (min-width: 48rem) {
  .route-map {
    position: relative;
  }

  .route-map__label--start-finish {
    position: absolute;
    left: calc(var(--space-3) + var(--space-2));
    top: calc(var(--space-3) + var(--space-2));
    max-width: 11rem;
    margin: 0;
  }
}

.route-map__caption {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-block-start: 2px solid var(--color-ink-line);
  font-size: var(--step--1);
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-white);
}

.route-map__caption::before {
  content: "";
  flex: none;
  width: 0.625rem;
  height: 0.625rem;
  background: var(--color-orange);
  transform: skewX(-12deg);
}

@media (prefers-reduced-motion: reduce) {
  .route-map__runner-halo,
  .route-map__station.is-passed {
    animation: none;
  }
}
}
@layer sections {
/* Race village: the eight highlight cards (cards.css), and the kids and
   games zones side by side from 48rem. */
.zones {
  display: grid;
  gap: var(--space-5);
  margin-block-start: var(--space-8);
}

.zone {
  display: grid;
  align-content: start;
  gap: var(--space-4);
  padding: var(--space-6);
  background: var(--color-cream);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
}

.zone__title {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-headline);
  font-size: var(--step-3);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
}

.zone__title em {
  font-style: inherit;
  color: var(--color-orange);
}

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

.zone__list {
  display: grid;
  gap: var(--space-3);
}

.zone__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: var(--space-3);
  color: var(--color-ink-soft);
}

.zone__icon {
  grid-row: span 2;
  width: 1.75rem;
  height: 1.75rem;
  color: var(--color-orange);
}

.zone__item strong {
  display: block;
  font-weight: 800;
  color: var(--color-ink);
}

@media (min-width: 48rem) {
  .zones {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
}
@layer sections {
/* Participant guidelines (home, race village): four groups of isometric icons, each with its label
   as visible text. What to bring and the prohibited items sit side by side from 48rem, the dress
   code (what to wear, what not to wear) spans both below them. The "don't" groups take a red
   top edge; their icons already carry the red cross disc. */
.guidelines {
  margin-block-start: var(--space-8);
}

.guidelines__grid {
  display: grid;
  gap: var(--space-4);
}

.guideline {
  display: grid;
  align-content: start;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--color-cream);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
}

.guideline--dont {
  border-block-start: 3px solid var(--color-danger);
}

.guideline__title,
.guidelines__attire-title {
  margin: 0; /* the reset stops at h4; the sub-groups are h5 */
  font-family: var(--font-headline);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
  text-wrap: balance;
}

.guideline--dont .guideline__title {
  color: var(--color-danger);
}

.guideline__items {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
  gap: var(--space-5) var(--space-2); /* the icons' negative margins and cross discs need the room */
}

.guideline__item {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: var(--space-1);
  text-align: center;
}

/* The drawings leave room for their ground shadow, so they run larger than the label is wide. */
.guideline__icon {
  display: block;
  width: 6.5rem;
  height: 6.5rem;
  margin-block: -0.75rem;
}

.guideline__label {
  font-size: var(--step--1);
  font-weight: 600;
  line-height: 1.25;
  text-wrap: balance;
}

.guideline__note {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--color-line);
  font-size: var(--step--1);
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

.guideline__note-icon {
  display: block;
  width: 5.5rem;
  height: 5.5rem;
  margin-block: -0.75rem;
}

.guidelines__attire {
  display: grid;
  gap: var(--space-4);
}

.guidelines__attire-grid {
  display: grid;
  gap: var(--space-4);
}

@media (min-width: 48rem) {
  .guidelines__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
  }

  .guideline {
    padding: var(--space-6);
  }

  .guideline__items {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .guideline__icon {
    width: 8rem;
    height: 8rem;
    margin-block: -1rem;
  }

  .guideline__note {
    grid-template-columns: 6.5rem minmax(0, 1fr);
  }

  .guideline__note-icon {
    width: 6.5rem;
    height: 6.5rem;
  }

  .guidelines__attire {
    grid-column: 1 / -1;
  }

  .guidelines__attire-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
  }
}

@media (min-width: 64rem) {
  /* Five and six items sit three across (3 + 2, 3 + 3) rather than leaving one alone on a row. */
  .guideline__items:has(> :nth-child(5)) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .guideline__icon {
    width: 9rem;
    height: 9rem;
    margin-block: -1.25rem;
  }
}
}
@layer sections {
/* Home registration call-to-action, and the quiet "learn more" links into /info. */
.cta {
  text-align: center;
}

.cta__icon {
  --iso-size: 9rem;
  margin-inline: auto;
  margin-block: calc(var(--space-4) * -1) calc(var(--space-5) * -1);
}

@media (min-width: 48rem) {
  .cta__icon {
    --iso-size: 11rem;
  }
}

.cta__actions {
  display: grid;
  justify-items: center;
  gap: var(--space-4);
}

.cta .section-heading {
  justify-items: center;
}

.info-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  margin: var(--space-4) 0 0;
}
}
@layer sections {
/* FAQ accordion on native <details>, in titled groups (one faq_controller spans all groups, so
   one question is open at a time across the whole FAQ). Square rows with a hairline border; the open row gets an
   orange bar on its left edge and the chevron turns. The height animation is done in
   faq_controller (Web Animations API); without JS the rows simply open and close. */

.faq-groups {
  display: grid;
  gap: var(--space-7);
  max-width: 56rem;
}

.faq-group__title {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-block-end: var(--space-4);
  font-family: var(--font-headline);
  font-size: var(--step-2);
  font-style: italic;
  font-weight: 800;
  line-height: 1.1;
  text-transform: uppercase;
}

.faq-group__title::before {
  content: "";
  flex: none;
  width: 1.5rem;
  height: 0.375rem;
  background: var(--color-orange);
  transform: skewX(-12deg);
}

.faq {
  display: grid;
  gap: var(--space-3);
}

.faq-item {
  position: relative;
  background: var(--color-white);
  border: 1px solid var(--color-line);
  transition: border-color var(--duration-fast) var(--ease-out);
}

/* Orange bar, drawn in from the top when the row opens. It sits inside the padding box so the
   overflow clip during the height animation never cuts it. */
.faq-item::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  width: 0.375rem;
  background: var(--color-orange);
  transform: scaleY(0);
  transform-origin: top center;
  transition: transform var(--duration-base) var(--ease-out);
}

.faq-item[open] {
  border-color: var(--color-orange);
}

.faq-item[open]::before {
  transform: scaleY(1);
}

.faq-item__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 3.5rem;
  padding: var(--space-3) var(--space-4) var(--space-3) var(--space-5);
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.35;
  cursor: pointer;
  list-style: none;
  -webkit-tap-highlight-color: transparent;
}

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

.faq-item__summary:focus-visible {
  outline-offset: -3px;
}

.faq-item__chevron {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  color: var(--color-orange-deep);
  transition: transform var(--duration-base) var(--ease-out);
}

.faq-item[open] .faq-item__chevron {
  transform: rotate(180deg);
}

@media (hover: hover) {
  .faq-item__summary:hover .faq-item__question {
    color: var(--color-orange-deep);
  }
}

.faq-item__question {
  transition: color var(--duration-fast) var(--ease-out);
}

.faq-item__answer {
  padding: 0 var(--space-5) var(--space-5);
  color: var(--color-ink-soft);
  text-wrap: pretty;
}

@media (min-width: 48rem) {
  .faq-item__summary {
    min-height: 4rem;
    padding-inline: var(--space-6) var(--space-5);
    font-size: var(--step-1);
  }

  .faq-item__answer {
    padding-inline: var(--space-6);
    padding-block-end: var(--space-5);
  }
}
}
@layer sections {
/* Event Info page (/info): the jump nav of chip links under the heading, the short "along the
   route" intro, the race-day and safety checklists and the closing call-to-action band. The
   moved sections (about, registration, stations) keep their own styles. */
.info-jump {
  margin-block-start: var(--space-6);
}

.info-jump__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.info-jump__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: var(--space-1) var(--space-4);
  border: 2px solid var(--color-ink);
  border-radius: var(--radius-pill);
  color: var(--color-ink);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-decoration: none;
  transition:
    background-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

.info-jump__link:hover {
  background: var(--color-ink);
  color: var(--color-white);
}

/* The intro sits right above the water stations section, so it drops its own bottom padding. */
.info-route {
  padding-block-end: 0;
}

.info-route .section-heading {
  margin-block-end: 0;
}

/* Shared by the /info checklists and the lucky draw "before you drop your entry" list. */
.checklist {
  align-items: start;
}

.checklist .feature {
  padding: var(--space-4);
  border: 1px solid var(--color-line);
  background: var(--color-white);
}

.checklist .feature__title {
  color: var(--color-ink);
}

/* Closing band: the section itself is the blue-deep band (section--blue-deep surface-brand);
   this lays out its content. Light type and the white focus ring come from .surface-brand. */
.info-cta {
  display: grid;
  justify-items: start;
  gap: var(--space-4);
}

.info-cta > .cta__icon {
  --iso-size: 8rem;
  margin-inline: 0;
  margin-block: calc(var(--space-3) * -1) calc(var(--space-4) * -1);
}

.info-cta__title {
  margin: 0;
  font-family: var(--font-headline);
  font-size: var(--step-4);
  font-style: italic;
  font-weight: 800;
  line-height: 1;
  text-transform: uppercase;
}

.info-cta__accent {
  color: var(--color-amber-soft);
}

.info-cta__text {
  margin: 0;
  color: var(--color-text-muted);
}

.info-cta__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin: var(--space-2) 0 0;
  padding: 0;
  list-style: none;
}

.info-cta__links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  font-weight: 700;
  color: var(--color-white);
}
}
@layer sections {
/* Public gallery in the home lucky draw section. */
.prizes {
  margin-block: var(--space-7);
}

.prizes + .features {
  margin-block-start: var(--space-6);
}

.prizes__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
  margin: var(--space-6) 0 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 48rem) {
  .prizes__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 64rem) {
  .prizes__grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}

.prize__photo {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--color-white);
  border: 1px solid var(--color-line);
  border-radius: var(--radius-card);
}

.prize__photo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.prize__placeholder {
  width: 70%;
}

.prize__placeholder img {
  display: block;
  width: 100%;
  height: auto;
}

.prize__name {
  margin: var(--space-3) 0 0;
  overflow-wrap: anywhere;
  font-weight: 600;
}

.prize__rank {
  font-family: var(--font-display);
  color: var(--color-orange-deep);
}

/* The grid stays put and its items rise in turn (--i); base.css only knows its own list classes. */
@media (prefers-reduced-motion: no-preference) {
  .js .prizes__grid[data-controller~="reveal"] {
    opacity: 1;
    transform: none;
  }

  .js .prizes__grid[data-controller~="reveal"] > li {
    opacity: 0;
    transform: translateY(1.5rem);
    transition:
      opacity var(--duration-slow) var(--ease-out) calc(var(--reveal-delay, 0ms) + var(--i, 0) * 90ms),
      transform var(--duration-slow) var(--ease-out) calc(var(--reveal-delay, 0ms) + var(--i, 0) * 90ms);
  }

  .js .prizes__grid.is-revealed > li {
    opacity: 1;
    transform: none;
  }
}

/* "See all prizes" under the home gallery; aligned with the section's left-aligned heading. */
.prizes__more {
  margin: var(--space-5) 0 0;
  text-align: start;
}

/* Public lucky draws page. */
.lucky-draws__progress {
  margin: 0;
  font-weight: 700;
}

.lucky-draws__empty {
  margin-block: var(--space-6);
  font-size: var(--step-1);
}

.lucky-draws .draw-terms {
  margin-block: var(--space-6) 0;
}

.lucky-draws__how,
.lucky-draws__checklist,
.lucky-draws__faq,
.lucky-draws__register {
  margin-block: var(--space-7);
}

.lucky-draws__register {
  display: grid;
  justify-items: start;
  gap: var(--space-4);
}

.lucky-draws__register .subhead,
.lucky-draws__register p {
  margin: 0;
}

.prize__winner {
  display: grid;
  gap: var(--space-1);
  margin: var(--space-2) 0 0;
  padding-inline-start: var(--space-2);
  border-inline-start: 4px solid var(--color-orange-deep);
  overflow-wrap: anywhere;
}

.prize__bib {
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}
}
@layer sections {
/* Print (the race wallet's Print button, and any public page): no site chrome or buttons, the
   page in one column, each code kept whole on its page with a name under it. */
@media print {
  .skip-link,
  .site-nav,
  .countdown-bar,
  .footer,
  .form-page .wallet-actions,
  .form-page .wallet-codes__hint,
  .qr-card__zoom-hint,
  .qr-card__share,
  .qr-zoom {
    display: none;
  }

  .qr-card__zoom {
    outline: 0;
  }

  body {
    background: var(--color-white);
  }

  .js .main--below-nav {
    padding-top: 0;
  }

  .form-page {
    padding-block: 0;
  }

  .form-page .form-page__head {
    margin-block-end: var(--space-4);
  }

  .wallet {
    display: block;
  }

  .form-page .wallet-codes {
    margin-block-start: var(--space-5);
    padding: 0;
    background: none;
    border: 0;
  }

  .qr-card {
    break-inside: avoid;
    box-shadow: none;
    border-color: var(--color-ink);
  }

  .form-page .qr-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .qr-card img.qr {
    max-width: 5cm;
  }

  .qr-card--group img.qr,
  .qr-card--personal img.qr {
    max-width: 7cm;
  }

  .wallet-bib {
    border: 1px solid var(--color-ink);
    print-color-adjust: exact;
  }
}
}
