/* ==========================================================================
   Anaxion AI — Landing Page
   Implements anaxion-ai-design-system.md
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Fonts — self-hosted variable fonts (latin subset), preloaded from
      index.html. One file per family covers every weight the page uses.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("assets/fonts/plus-jakarta-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("assets/fonts/jetbrains-mono-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Colour — one chromatic accent, rationed. */
  --color-signal: #1b44e0;
  --color-signal-halo: #d9e0fb;
  --color-ink: #181a1f;
  --color-slate: #5f6672;
  --color-ash: #8b929e;
  --color-stone: #b8bdc7;
  --color-gridline: #e4e6eb;
  --color-chalk: #f7f8fa;
  --color-paper: #ffffff;

  /* Type */
  --font-display: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system,
    sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --text-caption: 12px;
  --text-label: 13px;
  --text-body-sm: 14px;
  --text-body: 16px;
  --text-body-lg: 18px;
  --text-heading-sm: 22px;
  --text-heading: 28px;
  --text-heading-lg: 40px;
  --text-display: 52px;
  --text-display-xl: 64px;

  /* Spacing — base unit 4px */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
  --space-24: 96px;
  --space-32: 128px;

  --section-gap: 96px;
  --container: 1200px;
  --card-pad: 32px;
  --measure: 68ch;

  /* Radius tiers — never mixed */
  --radius-pill: 999px;
  --radius-card: 12px;
  --radius-field: 8px;
  --radius-flat: 0;

  /* Elevation — layered borders and rings, never > 5% black */
  --lift: rgba(24, 26, 31, 0.03) 0 16px 32px -12px,
    rgba(24, 26, 31, 0.03) 0 4px 8px -2px,
    rgba(24, 26, 31, 0.04) 0 0 0 1px;
  --halo: 0 0 0 5px var(--color-signal-halo);
  --halo-lg: 0 0 0 7px var(--color-signal-halo);
  --ring-ambient: 0 0 0 6px var(--color-chalk);

  /* Motion — one easing curve and one duration across the whole site, so
     reveals, hovers and the process scrub all feel like one system. */
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --reveal-dur: 620ms;
  --reveal-shift: 16px;

  /* 83px matches the Figma hero nav (node 52:762). */
  --nav-h: 83px;
  --bar-h: 68px;
}

@media (max-width: 860px) {
  :root {
    --text-display-xl: 36px;
    --text-display: 32px;
    --text-heading-lg: 28px;
    --section-gap: 64px;
    --card-pad: 24px;
  }
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

/* Lenis smooth scrolling resets */
html.lenis, html.lenis body {
  height: auto;
  width: 100%;
}
html.lenis, html.lenis-smooth {
  scroll-behavior: auto !important;
}
html.lenis.lenis-smooth [data-lenis-prevent] {
  overscroll-behavior: contain;
}
html.lenis.lenis-stopped {
  overflow: hidden;
}
html.lenis.lenis-scrolling iframe {
  pointer-events: none;
}

body {
  margin: 0;
  background: var(--color-paper);
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

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

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

a {
  color: inherit;
  text-decoration: none;
}

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

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

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

/* --------------------------------------------------------------------------
   3. Utilities
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: 24px;
}

@media (max-width: 600px) {
  .container {
    padding-inline: 16px;
  }
}

.section {
  padding-block: var(--section-gap);
}

.section--tight {
  padding-block: calc(var(--section-gap) * 0.66);
}

.band {
  background: var(--color-chalk);
  border-block: 1px solid var(--color-gridline);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--color-ink);
  color: var(--color-paper);
  padding: 12px 20px;
  border-radius: var(--radius-field);
  font-size: var(--text-body-sm);
}

.skip-link:focus {
  left: 16px;
  top: 16px;
}

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

/* Mono / sans binary — mono is the technical-credibility signal. */
.mono {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: 400;
  color: var(--color-ash);
  letter-spacing: 0;
}

.mono--up {
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--text-caption);
}

.accent {
  color: var(--color-signal);
}

/* Unresolved facts from the content doc. Delete this rule to ship. */
.ph {
  border-bottom: 1px dotted var(--color-stone);
}

/* --------------------------------------------------------------------------
   4. Typography roles
   -------------------------------------------------------------------------- */

.display-xl,
.display,
.heading-lg,
.heading,
.heading-sm {
  font-family: var(--font-display);
  font-weight: 600;
  color: var(--color-ink);
}

.display-xl {
  font-size: var(--text-display-xl);
  line-height: 1;
  letter-spacing: -0.02em;
}

.display {
  font-size: var(--text-display);
  line-height: 1.05;
  letter-spacing: -0.015em;
}

.heading-lg {
  font-size: var(--text-heading-lg);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

.heading {
  font-size: var(--text-heading);
  line-height: 1.25;
  letter-spacing: -0.005em;
}

.heading-sm {
  font-size: var(--text-heading-sm);
  line-height: 1.3;
}

.lede {
  font-size: var(--text-body-lg);
  line-height: 1.55;
  color: var(--color-slate);
  max-width: var(--measure);
}

.body-slate {
  color: var(--color-slate);
  max-width: var(--measure);
}

.caption {
  font-size: var(--text-caption);
  line-height: 1.4;
  letter-spacing: 0.02em;
  color: var(--color-ash);
}

/* Section intro blocks */
.section-head {
  margin-bottom: var(--space-12);
}

.section-head--center {
  text-align: center;
  margin-inline: auto;
  max-width: 640px;
}

.section-head--center .lede {
  margin-inline: auto;
}

.section-head .lede {
  margin-top: var(--space-4);
}

/* Numbered section header — only where order is genuinely a sequence. */
.section-index {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  border-left: 2px solid var(--color-signal);
  padding-left: var(--space-4);
  margin-bottom: var(--space-6);
}

.section-index__dot {
  width: 5px;
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
  flex: none;
}

.section-index__text {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-slate);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  padding: 12px 24px;
  border-radius: var(--radius-pill);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 0.16s ease, box-shadow 0.16s ease,
    border-color 0.16s ease, color 0.16s ease;
  text-align: center;
}

.btn--primary {
  background: var(--color-signal);
  color: var(--color-paper);
  box-shadow: var(--halo);
  border-color: rgba(255, 255, 255, 0.2);
}

.btn--primary:hover {
  background: #1a3ecd;
  box-shadow: var(--halo-lg);
}

.btn--glass {
  background: rgba(255, 255, 255, 0.2);
  color: var(--color-paper);
  border-color: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.btn--glass:hover {
  background: rgba(255, 255, 255, 0.3);
}

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

.btn--secondary:hover {
  background: var(--color-chalk);
}
/* Deliberately Ink, not Cobalt — the accent is reserved. */
.btn--whatsapp {
  background: var(--color-ink);
  color: var(--color-paper);
  font-size: var(--text-body-sm);
}

.btn--whatsapp:hover {
  background: #24272e;
}

.btn--block {
  width: 100%;
}

.btn__icon {
  width: 18px;
  height: 18px;
  flex: none;
}

/* Arrow text links */
.link-arrow {
  font-size: 15px;
  font-weight: 500;
  color: var(--color-signal);
}

/* inline-block so the arrow stays with the last word when the label wraps */
.link-arrow::after {
  content: "→";
  display: inline-block;
  margin-left: 6px;
  transition: transform 0.16s ease;
}

.link-arrow:hover::after {
  transform: translateX(3px);
}

.link-ink {
  color: var(--color-ink);
  text-decoration: underline;
  text-decoration-color: var(--color-stone);
  text-underline-offset: 3px;
}

.link-ink:hover {
  text-decoration-color: var(--color-signal);
}

@media (max-width: 600px) {
  .btn {
    padding: 14px 24px;
    font-size: var(--text-body);
  }
}

/* --------------------------------------------------------------------------
   6. Chips
   -------------------------------------------------------------------------- */

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.chip {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-ink);
  background: var(--color-chalk);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-pill);
  padding: 6px 12px;
  line-height: 1.2;
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   7. Photo frames — every photo gets a border and a 12px radius.
      No filters, no tints. Cobalt never touches a photograph.
   -------------------------------------------------------------------------- */

.photo {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  background: var(--color-chalk);
}

.photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.photo--1x1 {
  aspect-ratio: 1 / 1;
}

.photo--16x9 {
  aspect-ratio: 16 / 9;
}

.photo--3x2 {
  aspect-ratio: 3 / 2;
}

/* Honest empty frame. An empty section beats a fake one — no stock, no
   AI-abstract filler. Replace the frame with a real photograph. */
.photo--empty {
  display: grid;
  place-items: center;
  padding: var(--space-6);
  background-image: linear-gradient(
      var(--color-gridline) 1px,
      transparent 1px
    ),
    linear-gradient(90deg, var(--color-gridline) 1px, transparent 1px);
  background-size: 24px 24px;
  background-position: -1px -1px;
}

.photo--empty .photo__note {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  line-height: 1.5;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-ash);
  text-align: center;
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-field);
  padding: 10px 14px;
  max-width: 260px;
}

/* --------------------------------------------------------------------------
   8. Navigation
   -------------------------------------------------------------------------- */

/* Transparent over the hero gradient; goes solid once the hero has scrolled
   away, so the white logo and links stay legible over the light page.
   The Figma frame only specifies the top-of-page state. */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--nav-h);
  background: transparent;
  border-bottom: 1px solid transparent;
  transform: translateY(0);
  transition: background-color 0.2s ease, border-color 0.2s ease,
    transform 0.25s ease;
}

/* Hidden on scroll-down, restored on scroll-up (see script.js). Never
   hidden while the mobile menu is open. */
.nav[data-hidden="true"] {
  transform: translateY(-100%);
}

.nav[data-scrolled="true"],
.nav[data-menu="open"] {
  background: rgba(2, 12, 44, 0.92);
  border-bottom-color: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(12px);
}

@supports not (backdrop-filter: blur(12px)) {
  .nav[data-scrolled="true"] {
    background: #020c2c;
  }
}

.nav__inner {
  height: 100%;
  display: flex;
  align-items: center;
  gap: var(--space-8);
}

.nav__logo {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
  letter-spacing: -0.01em;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex: none;
}

.nav__logo-mark {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  margin-right: auto;
}

/* The nav sits on dark ground at every scroll position, so its text is
   white rather than the page's Ink/Slate pair. */
/* The wordmark's letterforms are `currentColor`; the "AI" accent is
   baked into the SVG as #1EB9FE. */
.nav .nav__logo {
  color: #ffffff;
}

.nav__logo-svg {
  width: 168px;
  height: auto;
  display: block;
}

.nav__link {
  font-size: var(--text-body);
  font-weight: 500;
  color: #ffffff;
  padding: 4px 6px;
  transition: opacity 0.16s ease;
}

.nav__link:hover {
  opacity: 0.72;
}

.nav__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: none;
}

/* Programs dropdown */
.nav__item {
  position: relative;
}

.nav__trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--text-body);
  font-weight: 500;
  color: #ffffff;
  padding: 4px 6px;
  transition: opacity 0.16s ease;
}

.nav__trigger:hover {
  opacity: 0.72;
}

.nav__trigger svg {
  width: 10px;
  height: 10px;
  transition: transform 0.16s ease;
}

.nav__item[data-open="true"] .nav__trigger svg {
  transform: rotate(180deg);
}

.nav__dropdown {
  position: absolute;
  top: calc(100% + 14px);
  left: -16px;
  width: 320px;
  background: #06143c;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-card);
  box-shadow: rgba(0, 0, 0, 0.28) 0 18px 40px -16px;
  padding: var(--space-2);
  display: none;
}

.nav__item[data-open="true"] .nav__dropdown {
  display: block;
}

.nav__dropdown a {
  display: block;
  padding: 10px 12px;
  border-radius: var(--radius-field);
  font-size: var(--text-body-sm);
  color: #ffffff;
}

.nav__dropdown a:hover {
  background: rgba(255, 255, 255, 0.08);
}

.nav__dropdown span {
  display: block;
  font-size: var(--text-caption);
  color: rgba(255, 255, 255, 0.55);
  margin-top: 2px;
}

.nav__toggle {
  display: none;
  width: 40px;
  height: 40px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-radius: var(--radius-pill);
  place-items: center;
}

.nav__toggle span,
.nav__toggle span::before,
.nav__toggle span::after {
  display: block;
  width: 16px;
  height: 1.5px;
  background: #ffffff;
  border-radius: 2px;
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.nav__toggle span::before,
.nav__toggle span::after {
  content: "";
  position: absolute;
}

.nav__toggle span::before {
  transform: translateY(-5px);
}

.nav__toggle span::after {
  transform: translateY(5px);
}

.nav[data-menu="open"] .nav__toggle span {
  background: transparent;
}

.nav[data-menu="open"] .nav__toggle span::before {
  transform: rotate(45deg);
}

.nav[data-menu="open"] .nav__toggle span::after {
  transform: rotate(-45deg);
}

@media (max-width: 940px) {
  /* The CTA never collapses into the menu. */
  .nav__links {
    position: fixed;
    inset: var(--nav-h) 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: #020c2c;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    padding: var(--space-4) 24px var(--space-6);
    max-height: calc(100dvh - var(--nav-h));
    overflow-y: auto;
    display: none;
  }

  .nav[data-menu="open"] .nav__links {
    display: flex;
  }

  .nav__link,
  .nav__trigger {
    font-size: var(--text-body);
    color: #ffffff;
    padding: 14px 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
    width: 100%;
    justify-content: space-between;
  }

  .nav__dropdown {
    position: static;
    width: auto;
    background: transparent;
    border: 0;
    box-shadow: none;
    padding: var(--space-2) 0 var(--space-4);
    border-bottom: 1px solid rgba(255, 255, 255, 0.12);
  }

  .nav__toggle {
    display: grid;
    position: relative;
  }

  .nav__actions .btn--secondary {
    display: none;
  }
}

/* The nav CTA never collapses into the menu, so it has to shrink to fit
   alongside the logo and the toggle at 375px. */
@media (max-width: 600px) {
  :root {
    --nav-h: 64px;
  }

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

  .nav__logo-svg {
    width: 118px;
  }

  /* Doubled-up class so this beats the later .btn-sq mobile rule, which has
     the same specificity but wins on source order. */
  .nav__cta.btn-sq {
    padding: 9px 14px;
    font-size: var(--text-body-sm);
  }

  .nav__toggle {
    width: 36px;
    height: 36px;
  }
}

/* --------------------------------------------------------------------------
   9. Hero — copy left, photograph right. The hero belongs to people.
   -------------------------------------------------------------------------- */

/* Gradient stops, radii, and type sizes below are taken from Figma
   node 52:760 ("Frame 7"). */
.hero {
  position: relative;
  isolation: isolate;
  /* Pulled up so the transparent nav sits on the gradient. The hero box
     therefore starts at y=0 and 100svh fills the screen exactly, with the
     nav floating over its top. */
  margin-top: calc(-1 * var(--nav-h));
  /* Only clears the nav — the flex centring below places the content, so a
     large fixed padding here would push it off-centre on tall screens. */
  padding-top: calc(var(--nav-h) + 32px);
  padding-bottom: 100px;
  /* svh, not vh: on mobile vh is the *large* viewport, so the hero would
     overflow behind the browser chrome and jump when it retracts. */
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: linear-gradient(
    180deg,
    #000000 0%,
    #023bbb 42%,
    #1eb9fe 72.6%,
    #ffffff 98.1%
  );
}

/* WebGL ASCII Background */
.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  opacity: 0.85;
}

/* Base texture overlay */
.hero__texture {
  position: absolute;
  inset: 0;
  z-index: 1;
  opacity: 0.15;
  background-image: radial-gradient(
    circle,
    rgba(255, 255, 255, 0.8) 1.5px,
    transparent 2px
  );
  background-size: 48px 48px;
  pointer-events: none;
}

.hero__inner {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 31px;
  /* Takes all the leftover height, so extra viewport goes into centring the
     copy rather than pooling as dead space under the marquee. */
  flex: 1 1 auto;
}

.hero__badge {
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: 500;
  line-height: 1.25;
  color: #f5f5f5;
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: var(--radius-field);
  padding: 8px 16px;
  /* Frosted pill over the hero shader — -webkit- prefix for Safari. */
  -webkit-backdrop-filter: blur(50px);
  backdrop-filter: blur(50px);
}

.hero__title {
  font-family: var(--font-display);
  font-size: 80px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: #ffffff;
  /* Sized to the longest authored line at 80px (~1001px) so the <br> is the
     only break; the 982px Figma width belonged to the old 56px headline. */
  max-width: 1040px;
}

.hero__sub {
  font-family: var(--font-body);
  font-size: 24px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: #ffffff;
  max-width: 40ch;
}

.hero__actions {
  display: flex;
  gap: 31px;
  flex-wrap: wrap;
  justify-content: center;
}

/* The hero uses square buttons rather than the page's pill tier — kept
   scoped so the rest of the page keeps the design-system radius. */
.btn-sq {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--text-body);
  font-weight: 600;
  line-height: 1.2;
  padding: 10px 24px;
  border: 0;
  border-radius: var(--radius-flat);
  cursor: pointer;
  transition: background-color 0.16s ease, color 0.16s ease;
  text-align: center;
}

.btn-sq--light {
  background: #ffffff;
  color: #0338a4;
}

.btn-sq--light:hover {
  background: #e8eefc;
}

.btn-sq--blue {
  background: #0338a4;
  color: #ffffff;
}

.btn-sq--blue:hover {
  background: #042f89;
}

/* --------------------------------------------------------------------------
   9b. Discipline marquee — sits in the lower, near-white part of the hero
   gradient. White text there measures ~1.7:1 against the bare background —
   invisible — so a dark scrim band (the same navy used for the scrolled nav)
   sits behind it, composited at ~5.5:1, which clears AA for small text.
   -------------------------------------------------------------------------- */

.marquee {
  position: relative;
  margin-top: 112px;
  overflow: hidden;
  border-block: 1px solid rgba(255, 255, 255, 0.14);
  padding-block: 14px;
  /* Feather the ends so items don't hard-clip at the viewport edge. The mask
     applies to the whole element, so the scrim fades out in step with the
     text rather than leaving a hard-edged bar. */
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent 0,
    #000 10%,
    #000 90%,
    transparent 100%
  );
  mask-image: linear-gradient(
    90deg,
    transparent 0,
    #000 10%,
    #000 90%,
    transparent 100%
  );
}

.marquee::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: rgba(2, 12, 44, 0.55);
  pointer-events: none;
}

.marquee__track {
  position: relative;
  z-index: 1;
  display: flex;
  width: max-content;
  animation: marquee-scroll 42s linear infinite;
}

.marquee:hover .marquee__track {
  animation-play-state: paused;
}

.marquee__group {
  display: flex;
  align-items: center;
  flex: none;
}

.marquee__group li {
  display: flex;
  align-items: center;
  gap: 28px;
  padding-right: 28px;
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: #ffffff;
  white-space: nowrap;
}

.marquee__group li::after {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.55);
  flex: none;
}

/* Two identical groups, so one group's width is exactly half the track. */
@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

/* With motion reduced the track can't scroll, so show one group wrapped
   and centred rather than a frozen, clipped row. */
@media (prefers-reduced-motion: reduce) {
  .marquee__track {
    width: 100%;
  }

  /* flex:none in the base rule keeps the group at its intrinsic width, which
     would clip instead of wrap — so it has to be released here. */
  .marquee__group {
    flex: 1 1 auto;
    width: 100%;
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 10px;
  }

  .marquee__group + .marquee__group {
    display: none;
  }

  /* No repeat to separate from, so the trailing dot is noise. */
  .marquee__group li:last-child {
    padding-right: 0;
  }

  .marquee__group li:last-child::after {
    display: none;
  }
}

@media (max-width: 600px) {
  .marquee {
    margin-top: 72px;
    padding-block: 12px;
  }

  .marquee__group li {
    gap: 20px;
    padding-right: 20px;
    font-size: var(--text-caption);
  }
}

/* Trust strip — items divided by hairline rules. */
.trust {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  border-top: 1px solid var(--color-gridline);
  padding-top: var(--space-4);
}

.trust li {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  color: var(--color-ink);
  padding-inline: var(--space-4);
  line-height: 1.9;
}

.trust li:first-child {
  padding-left: 0;
}

.trust li + li {
  border-left: 1px solid var(--color-gridline);
}

/* Between here and 940px the container is narrower than the 80px headline
   needs, so it would wrap mid-sentence. Step down before that happens. */
@media (max-width: 1100px) {
  .hero__title {
    font-size: 64px;
  }
}

@media (max-width: 940px) {
  .hero {
    padding-top: calc(var(--nav-h) + 32px);
    padding-bottom: 100px;
  }

  .hero__title {
    font-size: 40px;
    max-width: none;
  }

  .hero__sub {
    font-size: 20px;
  }

  .hero__actions {
    gap: var(--space-4);
  }
}

@media (max-width: 600px) {
  .hero {
    padding-top: calc(var(--nav-h) + 24px);
    padding-bottom: 86px;
  }

  .hero__inner {
    gap: var(--space-6);
  }

  .hero__badge {
    font-size: var(--text-body-sm);
  }

  .hero__title {
    font-size: 32px;
  }

  .hero__sub {
    font-size: var(--text-body-lg);
  }

  .hero__actions {
    flex-direction: column;
    align-self: stretch;
  }

  .btn-sq {
    padding: 14px 24px;
  }

  /* Two rows on mobile. A grid keeps the dividers between columns instead
     of stranding one at the start of a wrapped line. */
  .trust {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }

  .trust li,
  .trust li + li {
    font-size: var(--text-caption);
    padding-inline: var(--space-3);
    border-left: 0;
  }

  .trust li:nth-child(odd) {
    padding-left: 0;
  }

  .trust li:nth-child(even) {
    border-left: 1px solid var(--color-gridline);
  }
}

/* --------------------------------------------------------------------------
   10. Grids
   -------------------------------------------------------------------------- */

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

.grid--4 {
  grid-template-columns: repeat(4, 1fr);
}

.grid--3 {
  grid-template-columns: repeat(3, 1fr);
}

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

@media (max-width: 1000px) {
  .grid--4 {
    grid-template-columns: repeat(2, 1fr);
  }

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

@media (max-width: 760px) {
  .grid--4,
  .grid--3,
  .grid--2 {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   11. Path selector cards
   -------------------------------------------------------------------------- */

.path {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-chalk);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--card-pad);
  transition: box-shadow 0.18s ease, border-color 0.18s ease,
    transform 0.18s ease;
}

.path:hover {
  box-shadow: var(--lift);
  border-color: rgba(27, 68, 224, 0.3);
  transform: translateY(-2px);
}

.path__icon {
  width: 24px;
  height: 24px;
  color: var(--color-signal);
  margin-bottom: var(--space-2);
}

.path__label {
  font-family: var(--font-display);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  line-height: 1.3;
}

.path__promise {
  color: var(--color-slate);
  font-size: var(--text-body);
  flex: 1;
}

.path__meta {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  color: var(--color-ash);
}

/* --------------------------------------------------------------------------
   11b. The New Graduate Reality — Figma "Frame 3" (node 30:53).
   -------------------------------------------------------------------------- */

.reality__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-12);
  text-align: center;
}

.reality__header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  max-width: 860px;
}

.reality__eyebrow {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-body-lg);
  line-height: 1.4;
  color: #0338a4;
  text-transform: uppercase;
}

.reality__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-heading-lg);
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: var(--color-ink);
}

.reality__lede {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-heading-sm);
  line-height: 1.2;
  letter-spacing: -0.02em;
  color: #4b5563;
  max-width: 760px;
}

.reality__cards {
  display: flex;
  gap: var(--space-6);
  width: 100%;
}

.reality__card {
  flex: 1 0 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  text-align: left;
  background: #0338a4;
  border-radius: 16px;
  padding: var(--card-pad);
  color: #ffffff;
  box-shadow: 0 8px 12px rgba(37, 99, 235, 0.13);
}

.reality__card:nth-child(2) {
  box-shadow: 0 8px 12px rgba(249, 115, 22, 0.13);
}

.reality__card:nth-child(3) {
  box-shadow: 0 8px 12px rgba(13, 148, 136, 0.13);
}

.reality__stat {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 32px;
  line-height: 1.2;
  letter-spacing: -0.64px;
}

.reality__desc {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: var(--text-body);
  line-height: 1.2;
  letter-spacing: -0.32px;
}

@media (max-width: 760px) {
  .reality__cards {
    flex-direction: column;
  }
}

@media (max-width: 600px) {
  .reality__lede {
    font-size: var(--text-body-lg);
  }
}

/* --------------------------------------------------------------------------
   12. Contrast band — why AI-first
   -------------------------------------------------------------------------- */

.contrast {
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--card-pad);
}

.contrast h3 {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-gridline);
}

.contrast li {
  position: relative;
  padding-left: var(--space-6);
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  line-height: 1.5;
}

.contrast li + li {
  margin-top: var(--space-3);
}

.contrast li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 8px;
  width: 8px;
  height: 1px;
  background: var(--color-stone);
}

.contrast--ours {
  border-top: 2px solid var(--color-signal);
}

.contrast--ours li {
  color: var(--color-ink);
}

.contrast--ours li::before {
  background: var(--color-signal);
}

/* --------------------------------------------------------------------------
   12b. Process flow — the four-stage journey.
   A connected grid rather than separate cards, so the rail reads as one
   continuous line. Radius 0 here is deliberate and matches the comparison
   table's treatment: hairline cells, no rounding.
   -------------------------------------------------------------------------- */

.thesis {
  font-family: var(--font-display);
  font-size: var(--text-heading);
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: var(--color-ink);
  margin-top: var(--space-6);
}

.flow {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border: 1px solid var(--color-gridline);
  /* The rails bleed by one card-padding on each side to read as one
     continuous line; clip that spill at the grid's own edges. */
  overflow: hidden;
}

.flow__card {
  display: flex;
  flex-direction: column;
  min-height: 400px;
  padding: var(--space-6);
  border-left: 1px solid var(--color-gridline);
}

.flow__card:first-child {
  border-left: 0;
}

.flow__num {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  color: var(--color-stone);
  transition: color 0.35s ease;
}

.flow__card[data-active="true"] .flow__num {
  color: var(--color-ink);
}

/* Fixed offset from the number so every description starts on the same
   line; the rail below takes the auto margin instead, which keeps it on a
   shared baseline across all four cells regardless of copy length. */
.flow__desc {
  padding-top: var(--space-12);
  margin-bottom: var(--space-6);
  font-size: var(--text-body);
  line-height: 1.55;
  color: var(--color-slate);
  /* Held back until the scroll reaches this card. Faded rather than
     removed from flow, so the rail below keeps its shared baseline. */
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.flow__card[data-active="true"] .flow__desc {
  opacity: 1;
  transform: translateY(0);
}

/* Full-bleed so the rail runs edge to edge and reads as one line
   across all four cells. */
.flow__rail {
  position: relative;
  height: 8px;
  margin-top: auto;
  margin-inline: calc(-1 * var(--card-pad));
  margin-bottom: var(--space-6);
  background-image: radial-gradient(
    circle,
    var(--color-gridline) 1.1px,
    transparent 1.3px
  );
  background-size: 6px 6px;
  background-color: var(--color-chalk);
}

.flow__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--color-signal);
  /* Short, linear — it should track the scroll, not lag behind it. */
  transition: width 0.12s linear;
}

.flow__title {
  font-family: var(--font-display);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-stone);
  transition: color 0.35s ease;
}

.flow__card[data-active="true"] .flow__title {
  color: var(--color-signal);
}

/* ---- illustrations ---- */

.flow__art {
  margin-top: var(--space-6);
  align-self: flex-end;
  opacity: 0;
  transform: translateY(10px);
  /* Right-anchored, so the hover scale grows into the card, not past its edge. */
  transform-origin: 100% 100%;
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

.flow[data-inview="true"] .flow__art {
  opacity: 1;
  transform: translateY(0);
}

/* Hover lift. Scoped to data-inview so it can't fight the entrance, and to
   hover-capable pointers so it doesn't stick after a tap. */
@media (hover: hover) {
  .flow[data-inview="true"] .flow__card:hover .flow__art {
    transform: translateY(-5px) scale(1.05);
    transition-delay: 0s;
  }

  .flow__card:hover .flow__art .f-px {
    fill-opacity: 1;
  }
}

/* Staggered entrance, so the row resolves left to right. */
.flow[data-inview="true"] .flow__card:nth-child(1) .flow__art { transition-delay: 0.05s; }
.flow[data-inview="true"] .flow__card:nth-child(2) .flow__art { transition-delay: 0.13s; }
.flow[data-inview="true"] .flow__card:nth-child(3) .flow__art { transition-delay: 0.21s; }
.flow[data-inview="true"] .flow__card:nth-child(4) .flow__art { transition-delay: 0.29s; }

.flow__art svg {
  display: block;
  width: 92px;
  height: auto;
}

/* Resting state: hairline wireframe, same weight as the page's borders. */
.flow__art .f-top,
.flow__art .f-left,
.flow__art .f-right,
.flow__art .f-px {
  fill: none;
  stroke: var(--color-stone);
  stroke-width: 1.2;
  stroke-linejoin: round;
  transition: fill 0.4s ease, stroke 0.4s ease, fill-opacity 0.4s ease;
}

/* The solid state resolves face by face — shadow, then body, then the
   accent marks — so the block reads as being built rather than switched on. */
.flow__art .f-left { transition-delay: 0s; }
.flow__art .f-right { transition-delay: 0.05s; }
.flow__art .f-top { transition-delay: 0.1s; }
.flow__art .f-px { transition-delay: 0.16s; }

/* Active: solid cobalt, with face opacity carrying the isometric depth. */
.flow__card[data-active="true"] .flow__art .f-top {
  fill: var(--color-signal);
  fill-opacity: 1;
  stroke: var(--color-signal);
}

.flow__card[data-active="true"] .flow__art .f-right {
  fill: var(--color-signal);
  fill-opacity: 0.78;
  stroke: var(--color-signal);
}

.flow__card[data-active="true"] .flow__art .f-left {
  fill: var(--color-signal);
  fill-opacity: 0.5;
  stroke: var(--color-signal);
}

.flow__card[data-active="true"] .flow__art .f-px {
  fill: var(--color-signal);
  fill-opacity: 0.85;
  stroke: var(--color-signal);
}

@media (max-width: 1000px) {
  .flow {
    grid-template-columns: repeat(2, 1fr);
  }

  .flow__card:nth-child(odd) {
    border-left: 0;
  }

  .flow__card:nth-child(n + 3) {
    border-top: 1px solid var(--color-gridline);
  }
}

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

  .flow__card {
    min-height: 0;
    border-left: 0;
  }

  .flow__card + .flow__card {
    border-top: 1px solid var(--color-gridline);
  }

  .flow__desc {
    padding-top: var(--space-8);
  }
}

/* Motion off: show the finished state rather than a frozen half-drawn line. */
@media (prefers-reduced-motion: reduce) {
  /* Accordions snap open; the state change still has to happen, only the
     interpolation is dropped. */
  .phase,
  .faq__item {
    transition: none;
  }

  .phase__body,
  .faq__a {
    transition: visibility 0s;
  }

  .flow[data-inview="true"] .flow__card:hover .flow__art {
    transform: none;
  }

  .flow__art .f-left,
  .flow__art .f-right,
  .flow__art .f-top,
  .flow__art .f-px {
    transition-delay: 0s;
  }

  .flow__desc {
    transform: none;
    transition: opacity 0.2s linear;
  }

  .flow__art {
    opacity: 1;
    transform: none;
  }
}

/* --------------------------------------------------------------------------
   12c. Process — pinned horizontal scroll.
   The default styles above are the vertical fallback and work with no JS.
   JS sets data-pin-active="true" on the section only when pinning is viable
   (motion allowed, viewport tall enough, track actually overflows); these
   rules then take over. Nothing here intercepts scroll events — the stage is
   position:sticky, so native momentum, keyboard, and scrollbar drag all work.
   -------------------------------------------------------------------------- */

/* Dark-navy treatment carried over from the removed "Ecosystem" showcase,
   so the hero -> reality -> process scroll rhythm keeps its blue / white /
   blue beat. Every child below assumed the plain white page background;
   each is re-pointed at a light-on-dark value lifted from the equivalent
   ecosystem element (.ecosystem__header .heading-lg/.lede, .ecosystem__card
   h3/p, .ecosystem__card-step) so nothing here is a new, unproven choice. */
.process {
  background: linear-gradient(180deg, #020c2c 0%, #0a1a4a 50%, #020c2c 100%);
}

.process .heading-lg,
.process .heading-lg .accent {
  color: #ffffff;
}

.process .thesis {
  color: rgba(255, 255, 255, 0.82);
}

.process .section-index__text {
  color: rgba(255, 255, 255, 0.55);
}

.process .section-index__dot {
  background: rgba(140, 195, 255, 0.9);
}

.process .flow__num {
  color: rgba(255, 255, 255, 0.35);
}

.process .flow__card[data-active="true"] .flow__num {
  color: rgba(140, 195, 255, 0.9);
}

.process .flow__title {
  color: rgba(255, 255, 255, 0.4);
}

.process .flow__card[data-active="true"] .flow__title {
  color: #ffffff;
}

.process .flow__desc {
  color: rgba(255, 255, 255, 0.65);
}

.process[data-pin-active="true"] {
  padding-block: 0;
}

/* Spacer height = one screen + the horizontal distance still to travel, so
   1px of vertical scroll maps to 1px of horizontal movement. */
.process[data-pin-active="true"] .process__spacer {
  height: calc(100svh + var(--pin-overflow, 0px));
}

.process[data-pin-active="true"] .process__stage {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}

.process[data-pin-active="true"] .process__head {
  flex: none;
  margin-bottom: clamp(20px, 4svh, 44px);
}

/* Compact the heading so the whole stage fits a short viewport. */
.process[data-pin-active="true"] .heading-lg {
  font-size: clamp(24px, 3.2vw, 40px);
}

.process[data-pin-active="true"] .thesis {
  font-size: clamp(17px, 2vw, 26px);
  margin-top: var(--space-3);
}

.process[data-pin-active="true"] .process__viewport {
  flex: none;
  max-width: none;
  padding-inline: 0;
  overflow: hidden;
}

/* The track: a single row wider than the screen, moved by transform only. */
.process[data-pin-active="true"] .flow {
  display: flex;
  width: max-content;
  grid-template-columns: none;
  margin-left: var(--pin-gutter, 24px);
  border-inline: 1px solid var(--color-gridline);
  will-change: transform;
}

.process[data-pin-active="true"] .flow__card {
  flex: none;
  width: clamp(300px, 34vw, 470px);
  min-height: min(420px, 52svh);
  border-left: 1px solid var(--color-gridline);
  border-top: 0;
}

.process[data-pin-active="true"] .flow__card:first-child {
  border-left: 0;
}

@media (max-width: 660px) {
  .process[data-pin-active="true"] .flow__card {
    width: min(78vw, 340px);
    min-height: min(400px, 54svh);
  }

  .process[data-pin-active="true"] .flow__card + .flow__card {
    border-top: 0;
  }
}

/* The viewport clips the track, so the illustrations' entrance transform
   must not fight it — they only fade in when pinned. */
.process[data-pin-active="true"] .flow__art {
  transform: none;
}

/* --------------------------------------------------------------------------
   13. Program cards
   -------------------------------------------------------------------------- */

.program {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--card-pad);
}

.program__name {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  line-height: 1.25;
}

.program__desc {
  color: var(--color-slate);
}

.program__meta {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  color: var(--color-ash);
}

.program__capstone {
  position: relative;
  padding-left: var(--space-4);
  font-size: var(--text-body-sm);
  color: var(--color-slate);
  line-height: 1.55;
}

.program__capstone::before {
  content: "";
  position: absolute;
  left: 0;
  top: 9px;
  width: 4px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
}

.program__fee {
  font-size: var(--text-body);
  font-weight: 500;
  color: var(--color-ink);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-gridline);
  margin-top: auto;
}

.program__actions {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   14. Curriculum — tabs + the week-indexed spine (signature element)
   -------------------------------------------------------------------------- */

/* Programme picker — one button per track, and the selected track's
   curriculum below. Each panel animates its own 0fr -> 1fr grid row (the
   same technique as the phase and FAQ accordions), so switching tracks eases
   between two different content heights rather than snapping. */

.track-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(228px, 1fr));
  gap: var(--space-3);
  margin-bottom: var(--space-8);
}

.track-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  text-align: left;
  padding: 15px 16px 15px 18px;
  cursor: pointer;
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  background: var(--color-paper);
  color: var(--color-slate);
  transition: border-color 0.24s var(--ease-out), background-color 0.24s var(--ease-out),
    color 0.24s var(--ease-out), box-shadow 0.24s var(--ease-out),
    transform 0.24s var(--ease-out);
}

/* Links to a separate page rather than switching a panel in place, so it
   is dashed and accent-coloured to read as "goes elsewhere" next to the
   solid track tabs that stay on this page. */
.track-btn--all {
  border-style: dashed;
  border-color: var(--color-signal);
  color: var(--color-signal);
  text-decoration: none;
}
.track-btn--all:hover {
  background: var(--color-signal);
  color: #ffffff;
}

.track-btn:hover {
  border-color: var(--color-signal);
  color: var(--color-ink);
  transform: translateY(-2px);
}

.track-btn:focus-visible {
  outline: 2px solid var(--color-signal);
  outline-offset: 3px;
}

.track-btn__label {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 5px;
  min-width: 0;
}

/* Chevron ring, echoing the phase toggles inside the panel. */
.track-btn__sign {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-pill);
  display: grid;
  place-items: center;
  border: 1px solid var(--color-gridline);
  color: var(--color-slate);
  transition: transform 0.42s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.24s var(--ease-out),
    color 0.24s var(--ease-out);
}

.track-btn__sign svg {
  width: 15px;
  height: 15px;
  display: block;
}

.track-btn:hover .track-btn__sign {
  border-color: var(--color-signal);
  color: var(--color-signal);
}

/* On the filled active button the ring flips and goes light. */
.track-btn[aria-expanded="true"] .track-btn__sign {
  transform: rotate(180deg);
  border-color: rgba(255, 255, 255, 0.45);
  color: var(--color-paper);
}

.track-btn__name {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-ink);
  transition: color 0.24s var(--ease-out);
}

.track-btn__meta {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  letter-spacing: 0.02em;
}

/* Selected: solid signal, so the active programme is unmistakable against
   the outlined ones. */
.track-btn[aria-expanded="true"] {
  background: var(--color-signal);
  border-color: var(--color-signal);
  color: rgba(255, 255, 255, 0.78);
  box-shadow: var(--halo);
  transform: none;
}

.track-btn[aria-expanded="true"] .track-btn__name {
  color: var(--color-paper);
}

/* ---- panels ---- */

/* No border here: with every panel closed it would leave a hairline floating
   under the buttons with nothing beneath it. The divider rides on the open
   panel instead, and on the grid container rather than the clipped child,
   since a border on the child would still paint at zero height. */
.track-panels {
  margin-top: calc(-1 * var(--space-2));
}

.track-panel {
  border-top: 1px solid transparent;
  transition: border-color 0.3s ease;
}

.track-panel[data-open="true"] {
  border-top-color: var(--color-gridline);
}

.track-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.44s cubic-bezier(0.22, 1, 0.36, 1);
}

.track-panel[data-open="true"] {
  grid-template-rows: 1fr;
}

/* Clipped by the collapsing row rather than display:none, which cannot
   transition. visibility keeps the hidden curricula out of the a11y tree and
   out of find-in-page, flipping only once the collapse has finished. */
.track-panel__inner {
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  opacity: 0;
  transform: translate3d(0, 6px, 0);
  transition: opacity 0.28s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 0.44s;
}

.track-panel[data-open="true"] .track-panel__inner {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition: opacity 0.34s ease 0.12s, transform 0.44s cubic-bezier(0.22, 1, 0.36, 1) 0.12s, visibility 0s;
}

.track-panel__meta {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  letter-spacing: 0.02em;
  color: var(--color-slate);
  padding-block: var(--space-6) var(--space-4);
}

.track-panel__inner .spine {
  padding-bottom: var(--space-8);
}

/* Four buttons in three columns leaves an orphan on the second row, so the
   tablet range is squared off to 2x2. */
@media (max-width: 1040px) {
  .track-picker {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 660px) {
  .track-picker {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }

  .track-btn {
    padding: 12px 14px 12px 16px;
  }

  .track-btn__sign {
    width: 26px;
    height: 26px;
  }

  .track-btn__name {
    font-size: var(--text-body);
  }

  .track-panel__inner .spine {
    padding-left: 32px;
  }

  .track-panel__inner .spine::before {
    left: 10px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .track-btn,
  .track-btn__sign,
  .track-panel {
    transition: none;
  }

  .track-panel__inner {
    transform: none;
    transition: visibility 0s;
  }
}

.spine {
  padding-top: var(--space-2);
  padding-bottom: var(--space-8);
}

@media (max-width: 660px) {
  .track__toggle {
    gap: var(--space-4);
    padding-block: var(--space-4);
  }

  .track__name {
    font-size: var(--text-body-lg);
  }

  .track__sign {
    width: 28px;
    height: 28px;
  }

  .track__panel .spine {
    padding-left: 32px;
  }

  .track__panel .spine::before {
    left: 10px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .track,
  .track__sign {
    transition: none;
  }

  .track__panel {
    transition: visibility 0s;
  }
}

.spine {
  position: relative;
  padding-left: 56px;
}

/* The hairline rail every phase hangs off. */
.spine::before {
  content: "";
  position: absolute;
  left: 24px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: var(--color-gridline);
}

/* Open/close animates the body's grid row from 0fr to 1fr, so the height
   is interpolated by the engine — no JS measurement, and it stays correct
   when the copy reflows. The ::before dot is absolutely positioned, so the
   two in-flow children (toggle, body) map cleanly onto the two rows. */
.phase {
  position: relative;
  padding-block: var(--space-6);
  display: grid;
  grid-template-rows: auto 0fr;
  transition: grid-template-rows 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

.phase[data-open="true"] {
  grid-template-rows: auto 1fr;
}

.phase + .phase {
  border-top: 1px solid var(--color-gridline);
}

.phase::before {
  content: "";
  position: absolute;
  left: -36px;
  top: 30px;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
  box-shadow: 0 0 0 4px var(--color-paper);
}

.phase__toggle {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  width: 100%;
  text-align: left;
}

.phase__weeks {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  font-weight: 500;
  color: var(--color-slate);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 6px;
}

.phase__name {
  font-family: var(--font-display);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  line-height: 1.3;
}

.phase__sign {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 6px;
  position: relative;
}

.phase__sign::before,
.phase__sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: var(--color-ink);
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.phase__sign::after {
  transform: rotate(90deg);
}

.phase[data-open="true"] .phase__sign::after {
  transform: rotate(0deg);
  opacity: 0;
}

.phase__body {
  /* Clipped by the collapsing row instead of display:none, which cannot
     transition. min-height:0 lets the row actually reach zero; visibility
     keeps collapsed copy out of the a11y tree and out of find-in-page,
     flipping only after the collapse has finished. Padding is not collapsed
     by the 0fr row, so it has to travel with it. */
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  opacity: 0;
  padding-top: 0;
  max-width: var(--measure);
  transition: opacity 0.22s ease, padding-top 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 0.34s;
}

.phase[data-open="true"] .phase__body {
  visibility: visible;
  opacity: 1;
  padding-top: var(--space-4);
  transition: opacity 0.3s ease 0.06s, padding-top 0.34s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s;
}

.phase__body p {
  color: var(--color-slate);
  margin-bottom: var(--space-4);
}

.phase__build {
  position: relative;
  padding-left: var(--space-4);
  margin-top: var(--space-4);
  font-size: var(--text-body);
  font-weight: 500;
  color: var(--color-ink);
}

.phase__build::before {
  content: "";
  position: absolute;
  left: 0;
  top: 10px;
  width: 4px;
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
}

/* "GATE" marker on each phase's exit criterion. */
.phase__build .gate-label {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-signal);
  margin-right: 10px;
}

@media (max-width: 600px) {
  .spine {
    padding-left: 32px;
  }

  .spine::before {
    left: 12px;
  }

  .phase::before {
    left: -23px;
    width: 6px;
    height: 6px;
  }
}

/* Syllabus offer */
.syllabus {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: center;
  margin-top: var(--space-16);
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--card-pad);
}

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

/* --------------------------------------------------------------------------
   15. Code window — curriculum and project sections only. Never the hero.
   -------------------------------------------------------------------------- */

.code {
  background: var(--color-chalk);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-field);
  box-shadow: var(--ring-ambient);
  overflow: hidden;
}

.code__bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  height: 40px;
  padding-inline: var(--space-4);
  border-bottom: 1px solid var(--color-gridline);
}

.code__dots {
  display: flex;
  gap: 6px;
}

.code__dots i {
  width: 6px;
  height: 6px;
  border-radius: var(--radius-pill);
  background: var(--color-gridline);
}

.code__file {
  flex: 1;
  text-align: center;
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-slate);
}

.code__copy {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-ash);
}

.code__copy:hover {
  color: var(--color-ink);
}

.code__body {
  margin: 0;
  padding: 20px;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: var(--text-body-sm);
  line-height: 1.6;
  color: var(--color-ink);
  counter-reset: line;
}

.code__body .ln {
  display: block;
  white-space: pre;
}

.code__body .ln::before {
  counter-increment: line;
  content: counter(line);
  display: inline-block;
  width: 2.5ch;
  margin-right: 20px;
  text-align: right;
  font-size: var(--text-caption);
  color: var(--color-stone);
}

.code__body .kw,
.code__body .str {
  color: var(--color-signal);
}

.code__body .cm {
  color: var(--color-ash);
}

/* --------------------------------------------------------------------------
   16. Project cards
   -------------------------------------------------------------------------- */

.project {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--space-6);
}

.project__name {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
}

.project__desc {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  line-height: 1.55;
  flex: 1;
}

.project__links {
  display: flex;
  gap: var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-gridline);
  font-size: var(--text-body-sm);
}

/* --------------------------------------------------------------------------
   17. Mentor cards — horizontal scroll on mobile with a 16px peek.
   -------------------------------------------------------------------------- */

.mentors {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-6);
}

.mentor {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--space-6);
}

.mentor__photo {
  margin-bottom: var(--space-1);
}

.mentor__name {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
}

.mentor__role {
  font-size: var(--text-body-sm);
  color: var(--color-slate);
}

.mentor__former {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-ash);
}

.mentor__cred {
  font-size: var(--text-body-sm);
  color: var(--color-slate);
  line-height: 1.5;
  flex: 1;
}

.mentor__linkedin {
  width: 16px;
  height: 16px;
  color: var(--color-ink);
}

@media (max-width: 1000px) {
  .mentors {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 760px) {
  .mentors {
    display: flex;
    grid-template-columns: none;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    margin-inline: -16px;
    padding-inline: 16px;
    padding-bottom: var(--space-2);
    scrollbar-width: none;
  }

  .mentors::-webkit-scrollbar {
    display: none;
  }

  .mentor {
    flex: none;
    width: calc(100% - 40px);
    scroll-snap-align: start;
  }
}

/* --------------------------------------------------------------------------
   18. Weekly schedule + stats
   -------------------------------------------------------------------------- */

.schedule {
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.schedule__row {
  display: grid;
  grid-template-columns: 260px 1fr;
  gap: var(--space-6);
  padding: var(--space-6) var(--card-pad);
}

.schedule__row + .schedule__row {
  border-top: 1px solid var(--color-gridline);
}

.schedule__when {
  font-family: var(--font-mono);
  font-size: var(--text-label);
  color: var(--color-ink);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.schedule__what strong {
  display: block;
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
  margin-bottom: 4px;
}

.schedule__what p {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  line-height: 1.55;
}

@media (max-width: 760px) {
  .schedule__row {
    grid-template-columns: 1fr;
    gap: var(--space-2);
  }
}

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: var(--space-12);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.stat {
  padding: var(--card-pad);
}

.stat + .stat {
  border-left: 1px solid var(--color-gridline);
}

.stat__num {
  font-family: var(--font-display);
  font-size: var(--text-heading-lg);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.stat__label {
  font-size: var(--text-body-sm);
  color: var(--color-slate);
  margin-top: var(--space-2);
}

@media (max-width: 760px) {
  .stats {
    grid-template-columns: repeat(2, 1fr);
  }

  .stat:nth-child(odd) {
    border-left: 0;
  }

  .stat:nth-child(n + 3) {
    border-top: 1px solid var(--color-gridline);
  }
}

/* --------------------------------------------------------------------------
   19. Career support list
   -------------------------------------------------------------------------- */

.support {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 0 var(--space-12);
}

.support li {
  display: flex;
  gap: var(--space-4);
  padding-block: var(--space-6);
  border-top: 1px solid var(--color-gridline);
}

.support svg {
  width: 20px;
  height: 20px;
  flex: none;
  color: var(--color-ink);
  margin-top: 3px;
}

.support strong {
  display: block;
  font-weight: 500;
  margin-bottom: 2px;
}

.support p {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  line-height: 1.55;
}

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

/* --------------------------------------------------------------------------
   20. Ecosystem — scroll-driven radial showcase
   -------------------------------------------------------------------------- */

.ecosystem {
  --eco-h: 100svh;
  --eco-scroll: 300svh;
  position: relative;
  padding-block: 0;
  color: #ffffff;
}

.ecosystem__spacer {
  height: var(--eco-scroll);
  position: relative;
}

.ecosystem__stage {
  position: sticky;
  top: 0;
  height: var(--eco-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  z-index: 1;
  background: linear-gradient(180deg, #020c2c 0%, #0a1a4a 50%, #020c2c 100%);
}

/* Dot texture overlay — matching hero */
.ecosystem__stage::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  opacity: 0.08;
  background-image: radial-gradient(
    circle,
    rgba(255, 255, 255, 0.85) 1.1px,
    transparent 1.6px
  );
  background-size: 48px 48px;
  pointer-events: none;
}

/* In flow rather than floating over the arena. Absolutely positioning this
   put it in the same space the top three cards orbit through, so the copy
   and the cards collided; as a flex child of the centred stage it reserves
   its own height and the arena gets what is left. */
.ecosystem__header {
  position: relative;
  text-align: center;
  z-index: 10;
  max-width: 640px;
  width: 100%;
  padding-inline: 24px;
  flex: none;
  margin-bottom: clamp(24px, 3.5svh, 42px);
}

/* In orbit mode the upper two nodes sit level with the heading, so the copy
   is kept narrow enough to stay clear of the columns they occupy. */
.ecosystem[data-eco-layout="orbit"] .ecosystem__header {
  max-width: 560px;
}

.ecosystem__header .heading-lg {
  color: #ffffff;
}

.ecosystem__header .lede {
  color: rgba(255, 255, 255, 0.65);
}

/* ---- Arena: the hub and cards container ---- */

/* The orbit is an ellipse, not a circle: horizontal room is plentiful and
   vertical room is not, so the radii are decoupled. Four nodes sit on the
   diagonals, which keeps the composition symmetrical about both axes and
   leaves the space directly under the heading clear. */
.ecosystem__arena {
  position: relative;
  width: min(1120px, 92vw);
  height: min(540px, 54svh);
  margin: 0 auto;
  flex: none;
}

.ecosystem__nodes {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* ---- concentric orbits ---- */

.ecosystem__rings {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.ecosystem__ring {
  position: absolute;
  top: 50%;
  left: 50%;
  translate: -50% -50%;
  border-radius: 50%;
  border: 1px solid rgba(120, 180, 255, 0.14);
}

.ecosystem__ring--inner {
  width: 32%;
  height: 40%;
  border-color: rgba(120, 180, 255, 0.2);
}

/* Passes exactly through the node centres (2 x the 36%/30% radii), so the
   four stages read as points on one orbit. */
.ecosystem__ring--orbit {
  width: 72%;
  height: 60%;
  border-style: dashed;
  border-color: rgba(120, 180, 255, 0.22);
}

.ecosystem__ring--outer {
  width: 104%;
  height: 96%;
  border-color: rgba(120, 180, 255, 0.08);
}

/* ---- Central hub ---- */

.ecosystem__hub {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 10;
}

.ecosystem__glow {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 460px;
  height: 460px;
  transform: translate(-50%, -50%);
  background: radial-gradient(
    circle,
    rgba(46, 149, 242, 0.55) 0%,
    rgba(30, 185, 254, 0.28) 34%,
    transparent 68%
  );
  border-radius: 50%;
  opacity: 0;
  z-index: 0;
  will-change: opacity;
}

.ecosystem[data-eco-active="true"] .ecosystem__glow {
  opacity: 1;
  transition: opacity 1.2s ease 0.1s;
}

.ecosystem__logo {
  width: 176px;
  height: 176px;
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
  z-index: 2;
  will-change: transform, opacity;
  opacity: 0;
  transform: scale3d(0.7, 0.7, 1);
}

.ecosystem__logo-img {
  width: 100%;
  height: auto;
  object-fit: contain;
  /* Dual drop-shadow: a tight white highlight and a broad blue ambient glow */
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.4)) drop-shadow(0 0 32px rgba(30, 185, 254, 0.8));
}

.ecosystem[data-eco-active="true"] .ecosystem__logo {
  opacity: 1;
  transform: scale3d(1, 1, 1);
  transition: opacity 0.5s ease, transform 0.6s var(--ease-out);
}

/* ---- Connector lines ---- */

.ecosystem__connectors {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.ecosystem__line {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1px;
  height: 0;
  transform-origin: top center;
  background: linear-gradient(
    to bottom,
    rgba(30, 185, 254, 0.35) 0%,
    rgba(27, 68, 224, 0.1) 100%
  );
  will-change: height, opacity;
  opacity: 0;
}

/* Four spokes, one per node, on the diagonals. rotate(0) points down. */
.ecosystem__line[data-line="0"] { transform: rotate(135deg); }
.ecosystem__line[data-line="1"] { transform: rotate(225deg); }
.ecosystem__line[data-line="2"] { transform: rotate(315deg); }
.ecosystem__line[data-line="3"] { transform: rotate(45deg); }

/* ---- Orbiting cards ---- */

.ecosystem__card {
  position: absolute;
  width: clamp(200px, 19vw, 262px);
  padding: 20px 22px 18px;
  /* Rounded well past the card tier so the node reads as part of the orbit
     rather than as another content card. */
  border-radius: 26px;
  background: linear-gradient(
    155deg,
    rgba(255, 255, 255, 0.1) 0%,
    rgba(255, 255, 255, 0.028) 58%,
    rgba(120, 180, 255, 0.05) 100%
  );
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 22px 46px -26px rgba(0, 0, 0, 0.85),
    inset 0 1px 0 rgba(255, 255, 255, 0.14);
  z-index: 3;
  will-change: transform, opacity;
  opacity: 0;
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: border-color 0.35s ease, box-shadow 0.35s ease;
}

.ecosystem__card:hover {
  border-color: rgba(140, 195, 255, 0.42);
  box-shadow: 0 26px 54px -24px rgba(0, 0, 0, 0.9),
    inset 0 1px 0 rgba(255, 255, 255, 0.2),
    0 0 0 1px rgba(120, 180, 255, 0.16),
    0 0 46px -12px rgba(46, 149, 242, 0.5);
}

.ecosystem__card-step {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: rgba(140, 195, 255, 0.75);
  margin-bottom: 10px;
}

.ecosystem__card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  list-style: none;
  margin: 11px 0 0;
  padding: 0;
}

.ecosystem__card-tags li {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.03em;
  color: rgba(255, 255, 255, 0.62);
  padding: 2px 7px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.04);
}

.ecosystem__card h3 {
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  font-weight: 600;
  color: #ffffff;
  margin: 0 0 4px;
  line-height: 1.3;
}

.ecosystem__card p {
  font-family: var(--font-body);
  font-size: var(--text-caption);
  color: rgba(255, 255, 255, 0.55);
  margin: 0;
  line-height: 1.4;
}

.ecosystem__card-icon {
  width: 20px;
  height: 20px;
  color: #1EB9FE;
  margin-bottom: 8px;
  flex: none;
}

/* Four nodes on the diagonals of the ellipse, clockwise from top-left so the
   ring reads Plan -> Build -> Evaluate -> Get Hired. Offsets are 36% of the
   arena horizontally and 30% vertically; the orbit ring uses the same pair.

   These must be left/top, not percentages inside translate(): a percentage in
   a transform resolves against the element's own box, so --eco-x on a 262px
   card gave 94px instead of 36% of the arena. left/top resolve against the
   arena, which is what the script also writes.
   Keep in sync with ECO_CARD_DATA in script.js. */
.ecosystem__card[data-eco-card="0"] {
  left: 14%;
  top: 20%;
  transform: translate(-50%, -50%);
}
.ecosystem__card[data-eco-card="1"] {
  left: 86%;
  top: 20%;
  transform: translate(-50%, -50%);
}
.ecosystem__card[data-eco-card="2"] {
  left: 86%;
  top: 80%;
  transform: translate(-50%, -50%);
}
.ecosystem__card[data-eco-card="3"] {
  left: 14%;
  top: 80%;
  transform: translate(-50%, -50%);
}

/* Card hover effect — subtle lift */
.ecosystem__card:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(30, 185, 254, 0.3);
}

/* --------------------------------------------------------------------------
   Grid fallback — the orbit needs roughly 1000x680 to seat the four nodes
   plus the heading. Below that, rather than degrade the orbit into overlap,
   drop the pin entirely and lay the four stages out as a plain grid.
   Selected in measureEcosystem().
   -------------------------------------------------------------------------- */

.ecosystem[data-eco-layout="grid"] .ecosystem__spacer {
  height: auto;
}

.ecosystem[data-eco-layout="grid"] .ecosystem__stage {
  position: static;
  height: auto;
  padding-block: var(--section-gap);
  overflow: visible;
}

.ecosystem[data-eco-layout="grid"] .ecosystem__arena {
  width: min(1100px, 92vw);
  height: auto;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
}

.ecosystem[data-eco-layout="grid"] .ecosystem__rings {
  display: none;
}

.ecosystem[data-eco-layout="grid"] .ecosystem__card {
  position: static;
  width: auto;
  transform: none !important;
  opacity: 1 !important;
}

/* The hub reads as a mark above the grid rather than a centre to orbit. */
.ecosystem[data-eco-layout="grid"] .ecosystem__hub {
  position: static;
  transform: none;
  margin: 0 auto clamp(24px, 4vw, 44px);
  width: fit-content;
}

.ecosystem[data-eco-layout="grid"] .ecosystem__glow {
  opacity: 0.5 !important;
}

.ecosystem[data-eco-layout="grid"] .ecosystem__connectors {
  display: none;
}

/* ---- Mobile: smaller arena ---- */

@media (max-width: 660px) {
  .ecosystem {
    --eco-scroll: 250svh;
  }

  .ecosystem__header {
    top: clamp(40px, 7svh, 80px);
  }

  .ecosystem__arena {
    width: min(460px, 95vw);
    height: min(420px, 46svh);
  }

  .ecosystem__card {
    width: 110px;
    padding: 10px;
  }

  .ecosystem__card h3 {
    font-size: 11px;
  }

  .ecosystem__card p {
    display: none;
  }

  .ecosystem__logo {
    width: 100px;
    height: 100px;
  }

  .ecosystem__glow {
    width: 200px;
    height: 200px;
  }
}

@media (max-width: 400px) {
  .ecosystem__arena {
    width: min(370px, 95vw);
    height: min(370px, 95vw);
  }

  .ecosystem__logo {
    width: 80px;
    height: 80px;
  }

  .ecosystem__glow {
    width: 160px;
    height: 160px;
  }

  .ecosystem__card {
    width: 95px;
    padding: 8px;
  }

  .ecosystem__card h3 {
    font-size: 10px;
  }

  .ecosystem__card-icon {
    width: 16px;
    height: 16px;
    margin-bottom: 4px;
  }
}

/* ---- Reduced motion: show everything immediately, no pin ---- */

@media (prefers-reduced-motion: reduce) {
  .ecosystem {
    --eco-scroll: auto;
  }

  .ecosystem__spacer {
    height: auto;
  }

  .ecosystem__stage {
    position: relative;
    height: auto;
    min-height: 100svh;
    padding-block: var(--space-16);
  }

  .ecosystem__logo {
    opacity: 1;
    transform: none;
  }

  .ecosystem__card {
    opacity: 1;
  }

  .ecosystem__glow {
    opacity: 1;
  }

  .ecosystem__line {
    display: none;
  }
}

/* --------------------------------------------------------------------------
   21. Founding cohort panel
   -------------------------------------------------------------------------- */

.founding {
  max-width: 720px;
  margin-inline: auto;
  text-align: center;
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--space-12) var(--card-pad);
}

.founding__list {
  display: inline-flex;
  flex-direction: column;
  gap: var(--space-3);
  text-align: left;
  margin-block: var(--space-8);
}

.founding__list li {
  position: relative;
  padding-left: var(--space-6);
  color: var(--color-slate);
}

.founding__list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 11px;
  width: 5px;
  height: 5px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
}

.founding__note {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  max-width: 52ch;
  margin-inline: auto;
  margin-bottom: var(--space-8);
}

/* --------------------------------------------------------------------------
   21. Fees
   -------------------------------------------------------------------------- */

.fee {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--space-6);
}

.fee__track {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
  line-height: 1.3;
}

.fee__meta {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-ash);
}

.fee__amount {
  font-family: var(--font-display);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-gridline);
  margin-top: auto;
}

.fee-notes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6);
  margin-top: var(--space-12);
}

.fee-note {
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--card-pad);
}

.fee-note h3 {
  font-family: var(--font-display);
  font-size: var(--text-body-lg);
  font-weight: 600;
  margin-bottom: var(--space-3);
}

.fee-note p,
.fee-note li {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  line-height: 1.6;
}

.fee-note li + li {
  margin-top: var(--space-2);
}

/* This line gets read closely — give it room. */
.fee-note--refund {
  background: var(--color-chalk);
  border-top: 2px solid var(--color-signal);
}

.fee-note--refund p {
  color: var(--color-ink);
  font-size: var(--text-body);
}

@media (max-width: 760px) {
  .fee-notes {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   22. Admissions steps
   -------------------------------------------------------------------------- */

.steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-6);
  position: relative;
}

.step {
  position: relative;
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-gridline);
}

.step::before {
  content: "";
  position: absolute;
  top: -4px;
  left: 0;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--color-signal);
  box-shadow: 0 0 0 4px var(--color-paper);
}

.step--last {
  border-top-color: var(--color-signal);
}

.step__num {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  color: var(--color-slate);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  display: block;
  margin-bottom: var(--space-2);
}

.step__name {
  font-family: var(--font-display);
  font-size: var(--text-heading-sm);
  font-weight: 600;
  line-height: 1.3;
  margin-bottom: var(--space-2);
}

.step p {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  line-height: 1.55;
}

@media (max-width: 860px) {
  .steps {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
}

/* --------------------------------------------------------------------------
   23. Comparison — table on desktop, stacked cards on mobile.
        Never a horizontally scrolling table.
   -------------------------------------------------------------------------- */

.compare {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.compare th,
.compare td {
  border: 1px solid var(--color-gridline);
  padding: var(--space-4);
  text-align: left;
  vertical-align: top;
  font-size: var(--text-body-sm);
  line-height: 1.5;
  color: var(--color-slate);
}

.compare thead th {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-slate);
}

.compare tbody th {
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 500;
  color: var(--color-ink);
}

.compare th:first-child,
.compare td:first-child {
  border-left: 0;
}

.compare th:last-child,
.compare td:last-child {
  border-right: 0;
}

.compare .col-ours {
  background: var(--color-chalk);
  color: var(--color-ink);
}

.compare thead .col-ours {
  border-top: 2px solid var(--color-signal);
  color: var(--color-ink);
}

.compare-cards {
  display: none;
  gap: var(--space-6);
}

.compare-card {
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--space-6);
}

.compare-card--ours {
  background: var(--color-chalk);
  border-top: 2px solid var(--color-signal);
}

.compare-card h3 {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-slate);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-gridline);
  margin-bottom: var(--space-4);
}

.compare-card dt {
  font-size: var(--text-label);
  font-weight: 500;
  color: var(--color-ash);
}

.compare-card dd {
  font-size: var(--text-body-sm);
  color: var(--color-ink);
  line-height: 1.5;
  margin-bottom: var(--space-4);
}

.compare-card dd:last-child {
  margin-bottom: 0;
}

@media (max-width: 860px) {
  .compare {
    display: none;
  }

  .compare-cards {
    display: grid;
  }
}

/* --------------------------------------------------------------------------
   24. FAQ accordion — no card container, divided by hairlines.
   -------------------------------------------------------------------------- */

.faq {
  max-width: 760px;
  margin-inline: auto;
  border-top: 1px solid var(--color-gridline);
}

.faq__item {
  border-bottom: 1px solid var(--color-gridline);
  display: grid;
  grid-template-rows: auto 0fr;
  transition: grid-template-rows 0.34s cubic-bezier(0.22, 1, 0.36, 1);
}

.faq__item[data-open="true"] {
  grid-template-rows: auto 1fr;
}

.faq__q {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  width: 100%;
  text-align: left;
  padding-block: 20px;
  font-size: 17px;
  font-weight: 500;
  color: var(--color-ink);
  line-height: 1.45;
}

.faq__sign {
  flex: none;
  position: relative;
  width: 16px;
  height: 16px;
  margin-top: 5px;
}

.faq__sign::before,
.faq__sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: var(--color-ink);
  transition: transform 0.18s ease, opacity 0.18s ease;
}

.faq__sign::after {
  transform: rotate(90deg);
}

.faq__item[data-open="true"] .faq__sign::after {
  transform: rotate(0deg);
  opacity: 0;
}

.faq__a {
  overflow: hidden;
  min-height: 0;
  visibility: hidden;
  opacity: 0;
  padding-bottom: 0;
  color: var(--color-slate);
  max-width: var(--measure);
  transition: opacity 0.22s ease, padding-bottom 0.34s cubic-bezier(0.22, 1, 0.36, 1),
    visibility 0s linear 0.34s;
}

.faq__item[data-open="true"] .faq__a {
  visibility: visible;
  opacity: 1;
  padding-bottom: 20px;
  transition: opacity 0.3s ease 0.06s, padding-bottom 0.34s cubic-bezier(0.22, 1, 0.36, 1), visibility 0s;
}

/* --------------------------------------------------------------------------
   25. Forms
   -------------------------------------------------------------------------- */

.form {
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--card-pad);
}

.field + .field {
  margin-top: var(--space-4);
}

.field label {
  display: block;
  font-size: var(--text-body-sm);
  font-weight: 500;
  color: var(--color-ink);
  margin-bottom: 6px;
}

.field input,
.field select {
  width: 100%;
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-field);
  padding: 14px 16px;
  font-family: var(--font-body);
  /* 16px minimum — anything smaller triggers iOS auto-zoom. */
  font-size: 16px;
  line-height: 1.4;
  color: var(--color-ink);
  transition: border-color 0.16s ease, box-shadow 0.16s ease;
  appearance: none;
}

.field input::placeholder {
  color: var(--color-stone);
}

.field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%235F6672' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  background-size: 12px 8px;
  padding-right: 40px;
}

.field input:focus,
.field select:focus {
  outline: none;
  border-color: var(--color-signal);
  box-shadow: 0 0 0 3px var(--color-signal-halo);
}

/* Errors use Ink and a thicker rule. No red — no second chromatic colour. */
.field[data-error="true"] input,
.field[data-error="true"] select {
  border-width: 2px;
  border-color: var(--color-ink);
}

.field__error {
  display: none;
  font-size: var(--text-label);
  font-weight: 500;
  color: var(--color-ink);
  margin-top: 6px;
}

.field[data-error="true"] .field__error {
  display: block;
}

.form__submit {
  margin-top: var(--space-6);
}

.form__reassure {
  font-size: var(--text-label);
  color: var(--color-ash);
  text-align: center;
  margin-top: var(--space-3);
}

.form__success {
  display: none;
  font-size: var(--text-body-sm);
  color: var(--color-ink);
  font-weight: 500;
  border: 1px solid var(--color-gridline);
  border-left: 2px solid var(--color-signal);
  border-radius: var(--radius-field);
  padding: 12px 16px;
  margin-top: var(--space-4);
}

.form[data-sent="true"] .form__success {
  display: block;
}

.form--inline {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.form--inline .field + .field {
  margin-top: 0;
}

.form--inline .form__foot {
  grid-column: 1 / -1;
}

@media (max-width: 600px) {
  .form--inline {
    grid-template-columns: 1fr;
  }
}

/* --------------------------------------------------------------------------
   26. Final CTA band
   -------------------------------------------------------------------------- */

.cta-band {
  border-top: 1px solid var(--color-gridline);
  background: var(--color-chalk);
  padding-block: var(--section-gap);
}

.cta-band__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-16);
  align-items: start;
}

@media (max-width: 940px) {
  .cta-band__inner {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
}

/* --------------------------------------------------------------------------
   27. Footer
   -------------------------------------------------------------------------- */

.footer {
  border-top: 1px solid var(--color-gridline);
  padding-top: var(--section-gap);
  /* Padded so the sticky mobile bar never covers content. */
  padding-bottom: calc(var(--space-12) + var(--bar-h));
}

.footer__grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: var(--space-12);
}

.footer__brand p {
  color: var(--color-slate);
  font-size: var(--text-body-sm);
  margin-top: var(--space-3);
  max-width: 34ch;
}

.footer h3 {
  font-family: var(--font-mono);
  font-size: var(--text-caption);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-ash);
  margin-bottom: var(--space-4);
}

.footer__list li + li {
  margin-top: var(--space-3);
}

.footer__list a,
.footer__list span {
  font-size: var(--text-body-sm);
  color: var(--color-slate);
}

.footer__list a:hover {
  color: var(--color-ink);
}

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-top: var(--space-16);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-gridline);
}

.footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.footer__legal a,
.footer__copy {
  font-size: var(--text-label);
  color: var(--color-ash);
}

.footer__social {
  display: flex;
  gap: var(--space-4);
}

.footer__social a {
  color: var(--color-slate);
}

.footer__social a:hover {
  color: var(--color-ink);
}

.footer__social svg {
  width: 18px;
  height: 18px;
}

@media (max-width: 940px) {
  .footer__grid {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-8);
  }
}

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

/* --------------------------------------------------------------------------
   28. Persistent elements
   -------------------------------------------------------------------------- */

/* Sticky mobile action bar — appears after 400px of scroll. */
.action-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 90;
  display: none;
  gap: var(--space-3);
  background: var(--color-paper);
  border-top: 1px solid var(--color-gridline);
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  transform: translateY(100%);
  transition: transform 0.22s ease;
}

.action-bar[data-visible="true"] {
  transform: translateY(0);
}

.action-bar .btn {
  flex: 1 1 50%;
  min-width: 0;
  padding: 12px 12px;
  font-size: 15px;
}

/* Floating WhatsApp — desktop; on mobile the action bar carries it. */
.wa-float {
  position: fixed;
  right: 24px;
  bottom: 24px;
  z-index: 90;
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-pill);
  background: var(--color-ink);
  color: var(--color-paper);
  box-shadow: var(--lift);
}

.wa-float svg {
  width: 24px;
  height: 24px;
}

@media (max-width: 760px) {
  .action-bar {
    display: flex;
  }

  .wa-float {
    display: none;
  }
}

/* Exit intent — offers the syllabus, not a second request for a call. */
.exit {
  position: fixed;
  inset: 0;
  z-index: 150;
  display: none;
  place-items: center;
  padding: 24px;
  background: rgba(24, 26, 31, 0.28);
}

.exit[data-open="true"] {
  display: grid;
}

.exit__panel {
  position: relative;
  width: 100%;
  max-width: 440px;
  background: var(--color-paper);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  padding: var(--space-8);
  box-shadow: var(--lift);
}

.exit__close {
  position: absolute;
  top: 16px;
  right: 16px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: var(--radius-pill);
  color: var(--color-slate);
  font-size: 18px;
  line-height: 1;
}

.exit__close:hover {
  background: var(--color-chalk);
  color: var(--color-ink);
}

/* --------------------------------------------------------------------------
   29. Scroll reveals
   The hidden state is gated behind html.js-reveal, which an inline script in
   <head> only adds when IntersectionObserver exists AND motion is allowed.
   So with no JS, an old browser, or reduced motion, none of this applies and
   every element renders normally — content can never be stranded invisible.

   The hero is deliberately excluded: its heading is the LCP element, and
   fading it in would push Largest Contentful Paint back by the full duration.

   Selector list is mirrored by REVEAL_SELECTOR in script.js — keep in sync.
   -------------------------------------------------------------------------- */

.js-reveal .reality__card,
.js-reveal .section-head > *,
.js-reveal .path,
.js-reveal .contrast,
.js-reveal .program,
.js-reveal .project,
.js-reveal .mentor,
.js-reveal .schedule__row,
.js-reveal .stat,
.js-reveal .support li,
.js-reveal .founding,
.js-reveal .fee,
.js-reveal .fee-note,
.js-reveal .step,
.js-reveal .compare,
.js-reveal .compare-card,
.js-reveal .faq__item,
.js-reveal .syllabus,
.js-reveal .track-picker,
.js-reveal .cta-band__inner > div,
.js-reveal .cta-band__inner > form,
.js-reveal .footer__grid > div {
  opacity: 0;
}

/* `backwards` holds the start frame through the stagger delay, then releases
   cleanly on finish — no forwards fill left behind to override hover
   transforms on cards that lift. */
/* Attribute repeated to raise specificity to (0,3,0). Several hidden rules
   above end in a type selector (`.support li`, `.footer__grid > div`), which
   scores (0,2,1) and would otherwise keep those elements at opacity 0 even
   after they were revealed. */
.js-reveal [data-revealed][data-revealed] {
  opacity: 1;
  animation: reveal-up var(--reveal-dur) var(--ease-out)
    var(--reveal-delay, 0ms) backwards;
}

/* Media gets a touch of scale on top of the rise. */
.js-reveal .project[data-revealed],
.js-reveal .mentor[data-revealed],
.js-reveal .path[data-revealed] {
  animation-name: reveal-rise;
}

@keyframes reveal-up {
  from {
    opacity: 0;
    transform: translate3d(0, var(--reveal-shift), 0);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes reveal-rise {
  from {
    opacity: 0;
    transform: translate3d(0, var(--reveal-shift), 0) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Interaction states share the reveal's easing but stay fast, so hover never
   feels like it inherited a 620ms entrance. */
.path,
.program,
.project {
  transition: box-shadow 0.22s var(--ease-out),
    border-color 0.22s var(--ease-out), transform 0.22s var(--ease-out);
}

.project:hover {
  box-shadow: var(--lift);
  transform: translateY(-2px);
}

.btn,
.btn-sq {
  transition: background-color 0.18s var(--ease-out),
    box-shadow 0.18s var(--ease-out), border-color 0.18s var(--ease-out),
    color 0.18s var(--ease-out), transform 0.18s var(--ease-out);
}

.btn:active,
.btn-sq:active {
  transform: translateY(1px);
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* Remove stroke from primary blue buttons in nav and hero */
.nav__cta.btn--primary,
.hero__actions .btn--primary {
  border-color: transparent;
}

/* Explicitly override halo variables for dark backgrounds to ensure correct resolution */
.hero, .nav {
  --halo: 0 0 0 5px rgba(255, 255, 255, 0.1);
  --halo-lg: 0 0 0 7px rgba(255, 255, 255, 0.1);
}

/* --------------------------------------------------------------------------
   26. Learning pillars — auto-cycling showcase
   Figma: node 105:334. Colours, type and the 420px / 16px card geometry come
   from that node. One card is expanded at a time; the row is a flex line and
   the widths are flex-grow weights (548 open / 147 resting, straight from the
   Figma widths), so one card opening is the same operation as its neighbours
   closing and the line always fills exactly.

   State lives entirely on [data-active], so the timer and a click drive the
   identical transition and there is nothing to keep in sync.
   -------------------------------------------------------------------------- */

.pillars {
  --pillar-blue: #0338a4;
  --pillar-grad-a: #023bbb;
  --pillar-grad-b: #2e95f2;
  --pillar-rail: #eaeaea;
  --pillar-ease: cubic-bezier(0.65, 0, 0.35, 1);
  --pillar-open: 0.85s;
}

.pillars__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  text-align: center;
  margin-bottom: var(--space-8);
}

.pillars__eyebrow {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--pillar-blue);
  text-transform: uppercase;
}

.pillars__title {
  font-family: var(--font-display);
  font-size: var(--text-heading-lg);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.8px;
  color: #484848;
}

.pillars__row {
  display: flex;
  align-items: stretch;
  gap: var(--space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.pillar {
  position: relative;
  flex: 147 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* The width transition is armed only after the first frame. The script flips
   data-mode static->cycle on load, and without this gate that flip animates
   every card out from equal widths, which reads as a glitch rather than an
   entrance. */
.pillars[data-ready="true"] .pillar {
  transition: flex-grow var(--pillar-open) var(--pillar-ease);
}

.pillar[data-active="true"] {
  flex-grow: 548;
}

/* Whole-card click target, so the card reads as one control without wrapping
   the heading in a button. */
.pillar__hit {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  border-radius: 16px;
}

.pillar__hit:focus-visible {
  outline: 2px solid var(--pillar-blue);
  outline-offset: 4px;
}

.pillar[data-active="true"] .pillar__hit {
  cursor: default;
}

/* ---- panel ---- */

.pillar__panel {
  position: relative;
  height: clamp(260px, 30vw, 420px);
  border-radius: 16px;
  overflow: hidden;
  background-image: linear-gradient(
    137.77deg,
    var(--pillar-grad-a) 0%,
    var(--pillar-grad-b) 100%
  );
  isolation: isolate;
}

/* Halftone texture exported from the Figma node, at its 22% / lighten
   treatment. Oversized so the pointer parallax has room inside the clip. */
.pillar__texture {
  position: absolute;
  inset: -8% -12%;
  background: url("assets/pillar-texture.webp") center / cover no-repeat;
  mix-blend-mode: lighten;
  opacity: 0.22;
  transform: translate3d(calc(var(--px, 0px) * 0.5), calc(var(--py, 0px) * 0.5), 0);
}

.pillar__glow {
  position: absolute;
  left: 50%;
  top: 42%;
  width: 120%;
  aspect-ratio: 1;
  translate: -50% -50%;
  background: radial-gradient(
    circle at center,
    rgba(255, 255, 255, 0.42) 0%,
    rgba(255, 255, 255, 0.12) 38%,
    transparent 68%
  );
  opacity: 0.18;
  transform: scale3d(0.72, 0.72, 1);
  transition: opacity var(--pillar-open) ease,
    transform var(--pillar-open) var(--pillar-ease);
}

.pillar[data-active="true"] .pillar__glow {
  opacity: 0.72;
  transform: scale3d(1, 1, 1);
}

/* ---- drifting particles ---- */

.pillar__sparks i {
  position: absolute;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  opacity: 0;
  transition: opacity 0.6s ease;
  animation: pillar-drift 9s ease-in-out infinite;
}

.pillar[data-active="true"] .pillar__sparks i {
  opacity: 0.75;
  transition-delay: 0.25s;
}

.pillar__sparks i:nth-child(1) { left: 18%; top: 28%; animation-delay: -0.4s; }
.pillar__sparks i:nth-child(2) { left: 72%; top: 18%; animation-delay: -2.9s; width: 4px; height: 4px; }
.pillar__sparks i:nth-child(3) { left: 34%; top: 74%; animation-delay: -5.1s; width: 3px; height: 3px; }
.pillar__sparks i:nth-child(4) { left: 84%; top: 62%; animation-delay: -7.3s; }

@keyframes pillar-drift {
  0%,
  100% {
    transform: translate3d(0, 0, 0);
  }
  50% {
    transform: translate3d(6px, -16px, 0);
  }
}

/* ---- illustration ---- */

.pillar__art {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #ffffff;
  opacity: 0;
  transform: scale3d(0.9, 0.9, 1);
  transition: opacity 0.5s ease, transform 0.7s var(--pillar-ease);
}

/* Opens a beat after the width starts moving, so the card widens and then
   fills rather than doing both at once. */
.pillar[data-active="true"] .pillar__art {
  opacity: 1;
  transform: scale3d(1, 1, 1);
  transition-delay: 0.18s;
}

.pillar__art svg {
  width: min(78%, 320px);
  height: auto;
  overflow: visible;
}

/* Per-layer pointer parallax: each <g> carries its own --m depth multiplier. */
.pillar__art svg g {
  transform: translate3d(calc(var(--px, 0px) * var(--m, 1)), calc(var(--py, 0px) * var(--m, 1)), 0);
}

/* ---- dwell rail ---- */

.pillar__rail {
  position: relative;
  height: 2px;
  border-radius: 100px;
  background: var(--pillar-rail);
  overflow: hidden;
  flex: none;
}

/* The active card's rail is the countdown to the next card. scaleX keeps it
   on the compositor; --dwell is set once from the script. */
.pillar__fill {
  position: absolute;
  inset: 0;
  width: 100%;
  background: var(--pillar-blue);
  border-radius: 27px;
  transform: scaleX(0);
  transform-origin: left center;
}

.pillar[data-active="true"] .pillar__fill {
  animation: pillar-timer var(--dwell, 5200ms) linear forwards;
}

.pillars[data-paused="true"] .pillar__fill {
  animation-play-state: paused;
}

@keyframes pillar-timer {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

/* ---- copy ---- */

/* overflow: hidden clips the copy, which is laid out at the open card's final
   width (see .pillar__desc below) and would otherwise spill into the next
   card while this one is still widening. */
.pillar__meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-height: 0;
  overflow: hidden;
}

.pillar__name {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  line-height: 1.4;
  color: #1e1e1e;
  word-break: break-word;
}

.pillar__desc {
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: 1.4;
  color: #000000;
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition: opacity 0.45s ease, transform 0.55s var(--pillar-ease);
}

/* Last step of the stagger: width, then illustration, then copy. */
.pillar[data-active="true"] .pillar__desc {
  opacity: 1;
  transform: translate3d(0, 0, 0);
  transition-delay: 0.3s;
}

/* Nothing inside a card may re-wrap while its width animates: a paragraph
   that reflows on every frame of the 0.85s transition reads as jitter.

   So the copy is laid out at the OPEN card's final width from the start.
   --pillar-open-w is set by measurePillars() in script.js (exact arithmetic
   from the flex-grow weights, not a measurement of a moving card). The
   resting card clips it via .pillar__meta and it is invisible anyway at
   opacity 0; the opening card reveals it as a wipe while the width catches
   up. Line breaks never change, so nothing shifts.

   A compressed card must not reserve room for copy it is not showing, hence
   absolute at rest and static once open. */
.pillars[data-mode="cycle"] .pillar__desc {
  position: absolute;
  bottom: 0;
  width: var(--pillar-open-w, min(100%, 46ch));
  max-width: none;
  pointer-events: none;
}

.pillars[data-mode="cycle"] .pillar[data-active="true"] .pillar__desc {
  position: static;
  pointer-events: auto;
}

/* Names wrap to two lines in a 147px resting card and snap to one line
   partway through opening, which would shove the copy up a line mid-
   transition. Reserving two lines keeps the copy's vertical position fixed
   in both states. */
.pillars[data-mode="cycle"] .pillar__name {
  min-height: 2.8em; /* 2 lines at line-height 1.4 */
}

/* --------------------------------------------------------------------------
   Static fallback — narrow viewports. Every card open, in a plain grid, with
   the timer and the click behaviour both switched off.
   -------------------------------------------------------------------------- */

.pillars[data-mode="static"] .pillars__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-8) var(--space-4);
}

.pillars[data-mode="static"] .pillar {
  flex-grow: 1;
}

.pillars[data-mode="static"] .pillar__hit {
  display: none;
}

.pillars[data-mode="static"] .pillar__panel {
  height: 260px;
}

.pillars[data-mode="static"] .pillar__art,
.pillars[data-mode="static"] .pillar__desc {
  opacity: 1;
  transform: none;
}

.pillars[data-mode="static"] .pillar__glow {
  opacity: 0.72;
  transform: scale3d(1, 1, 1);
}

.pillars[data-mode="static"] .pillar__sparks i {
  opacity: 0.75;
}

.pillars[data-mode="static"] .pillar__fill {
  transform: scaleX(1);
  animation: none;
}

@media (max-width: 640px) {
  .pillars__eyebrow {
    font-size: var(--text-body);
  }

  .pillars__title {
    font-size: var(--text-heading);
    letter-spacing: -0.4px;
  }

  .pillars[data-mode="static"] .pillar__panel {
    height: 220px;
  }
}

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

  .pillar__art svg g,
  .pillar__texture {
    transform: none;
  }

  /* No autoplay under reduced motion, so the rail must not imply a countdown. */
  .pillar[data-active="true"] .pillar__fill {
    animation: none;
    transform: scaleX(1);
  }
}

/* =====================================================================
   All Courses page (courses.html) — a scalable card catalogue so the
   front-page track-picker never has to grow to fit every future track.
   ===================================================================== */
.course-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-6);
  margin-top: var(--space-8);
}

.course-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--card-pad);
  border: 1px solid var(--color-gridline);
  border-radius: var(--radius-card);
  background: var(--color-paper);
}

.course-card__meta {
  font-family: var(--font-mono, monospace);
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-signal);
}

.course-card__name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  line-height: 1.25;
  color: var(--color-ink, #111);
}

.course-card__desc {
  color: var(--color-slate);
  font-size: 15px;
  line-height: 1.5;
  flex: 1 0 auto;
}

.course-card__cta {
  align-self: flex-start;
  margin-top: var(--space-3);
}

.course-card--more {
  border-style: dashed;
  border-color: var(--color-signal);
  background: transparent;
}
