/* ════════════════════════════════════════════════════════════════════
   Section styles — one block per landmark, in page order.

   RESPONSIVE SCALE — three shared breakpoints; add per-section queries
   on these values only:
     ≤1024px  tablet collapse — dives/stat-grid go single-column,
              problem grid drops to 2-col (parallax also gates off
              ≥1025px in motion.js — keep in step)
     ≤840px   nav switches to the <details> disclosure menu,
              onboarding paths + timeline stack
     ≤560px   phone — single-column problem grid, type/padding trims
   EXCEPTION: #cycle keeps its 900px CSS queries because cycle.js pins
   at (min-width: 901px) (off-limits JS); its CSS boundary must stay
   consistent with the JS one, so it deliberately sits off-scale.
   ════════════════════════════════════════════════════════════════════ */

/* Fixed nav sits over every section; anchored scrolls need headroom. */
main section { scroll-margin-top: 84px; }

/* ── #nav — fixed, transparent at top, glass once scrolled ─────────── */
#nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 1000;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background 0.35s ease, border-color 0.35s ease;
}
#nav.scrolled {
  background: rgba(0, 12, 35, 0.72);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border-bottom: 1px solid var(--lb-glass-border);
}
.nav-inner {
  display: flex;
  align-items: center;
  gap: 40px;
  height: 72px;
}
.nav-logo {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
}
.nav-links {
  display: flex;
  gap: clamp(22px, 3vw, 38px);
  margin-inline: auto;
}
.nav-links a {
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--lb-text-dim);
  text-decoration: none;
  transition: color 0.2s;
}
.nav-links a:hover { color: var(--lb-text); }
.nav-cta {
  flex-shrink: 0;
  padding: 10px 24px;
  font-size: 0.95rem;
}
/* Mobile disclosure menu — hidden on desktop, shown ≤840. Panel is
   absolutely positioned so the bar itself stays 72px tall at every width
   (scroll-margin-top: 84px + motion.js offset: -84 both depend on that). */
.nav-mobile { display: none; position: relative; flex-shrink: 0; }
.nav-mobile summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;  /* thumb target */
  height: 44px;
  border: 1px solid var(--lb-glass-border);
  border-radius: 12px;
  color: var(--lb-text);
  cursor: pointer;
  transition: border-color 0.2s, background 0.2s;
}
.nav-mobile summary::-webkit-details-marker { display: none; }
.nav-mobile summary:hover { border-color: rgba(255, 255, 255, 0.25); }
.nav-mobile[open] summary { background: rgba(255, 255, 255, 0.06); }
.nav-mobile .icon-close { display: none; }
.nav-mobile[open] .icon-burger { display: none; }
.nav-mobile[open] .icon-close { display: block; }
.nav-mobile-panel {
  position: absolute;
  top: calc(100% + 16px);
  right: 0;
  min-width: 224px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px;
  background: rgba(0, 12, 35, 0.92);
  -webkit-backdrop-filter: blur(18px);
  backdrop-filter: blur(18px);
  border: 1px solid var(--lb-glass-border);
  border-radius: 16px;
  box-shadow: 0 24px 60px -20px rgba(0, 0, 0, 0.75);
}
.nav-mobile-panel a {
  padding: 12px 16px;
  border-radius: 10px;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--lb-text-dim);
  text-decoration: none;
  transition: color 0.2s, background 0.2s;
}
.nav-mobile-panel a:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--lb-text);
}
@media (max-width: 840px) {
  .nav-links { display: none; }         /* desktop links → disclosure below */
  .nav-inner { gap: 16px; }
  /* nav-links carried the auto-margin spacer; keep the CTA pinned right */
  .nav-cta { margin-left: auto; min-height: 44px; }
  .nav-mobile { display: block; }
}

/* ── #hero ──────────────────────────────────────────────────────────── */
#hero {
  min-height: 100vh; /* fallback for browsers without svh */
  min-height: 100svh;
  padding-top: clamp(150px, 19vh, 216px);
}
.hero-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.hero-inner .eyebrow { margin-bottom: 28px; }
/* Centered context: mirror the eyebrow's dash so the label sits dead-centre */
.hero-inner .eyebrow::after {
  content: '';
  width: 28px;
  height: 1px;
  background: var(--lb-gradient);
}
.hero-inner .h1 {
  /* Sized so the copy breaks as two balanced lines on desktop:
     "The first system built around how a / UK bus garage actually runs." */
  font-size: clamp(2.5rem, 4.7vw, 4.2rem);
  max-width: 19em;
}
.hero-inner .lead {
  margin-top: 26px;
  margin-inline: auto;
  max-width: 46em;
  text-wrap: balance;
}
/* NOTE: also consumed by #cta's finale row — keep responsive tweaks generic
   or split into a shared component class first. */
.hero-ctas {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 44px;
}
.hero-frame {
  position: relative;
  width: 100%;
  max-width: 1080px;
  margin-top: 72px;
  /* Depth shadow + soft brand glow. A shadow paints outside the box, so it
     survives .frame's overflow:hidden and Task 8's tilt transform — a
     ::before glow with z-index:-1 provably painted zero pixels here. */
  box-shadow:
    0 40px 90px -30px rgba(0, 0, 0, 0.7),
    0 0 140px 12px rgba(0, 201, 240, 0.12),
    0 0 60px 4px rgba(0, 213, 174, 0.08);
}

/* Blooms (hero + cta) are a fixed 900px square in components.css; cap them
   to ~the viewport so a phone doesn't carry 500px of invisible overflow.
   (Scoped override here because components.css is shared/frozen; the inline
   styles on the elements set position only, never size.) */
#hero .bloom,
#cta .bloom {
  width: min(900px, 120vw);
  height: min(900px, 120vw);
}
/* A bloom wider than the viewport (≤900px screens) must not register as
   document overflow — clip the x-axis at the hosting section. Visually a
   no-op (the section spans the full viewport, and body{overflow-x:clip}
   already clipped painting there); y stays visible for shadows/parallax. */
#hero,
#cta { overflow-x: clip; }

@media (max-width: 840px) {
  #hero { padding-top: clamp(120px, 16vh, 160px); }
  .hero-frame { margin-top: 52px; }
}
@media (max-width: 560px) {
  /* Base clamp floors at 2.5rem → five ragged lines at 390px. Refloor for
     phones: ~2rem at 390px reads as three balanced lines. */
  .hero-inner .h1 { font-size: clamp(1.85rem, 8.2vw, 2.5rem); }
  .hero-inner .lead { margin-top: 20px; }
  .hero-ctas { margin-top: 32px; }
  .hero-frame { margin-top: 44px; }
}

/* ── #problem — "paper and memory" vignettes ────────────────────────── */
/* Left-aligned (a deliberate contrast with the centred hero). */
#problem .eyebrow { margin-bottom: 16px; }
#problem .h2 { max-width: 15em; }

/* Asymmetric 6-col grid: three 2-col cards on top, two 3-col cards below —
   deliberately not a uniform 3×N bootstrap grid. */
.problem-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 20px;
  margin-top: 56px;
}
.problem-card:nth-child(1),
.problem-card:nth-child(2),
.problem-card:nth-child(3) { grid-column: span 2; }
.problem-card:nth-child(4),
.problem-card:nth-child(5) { grid-column: span 3; }

.problem-card {
  position: relative;
  overflow: hidden;
  padding: 32px;
  transition: background 0.25s ease, border-color 0.25s ease;
}
/* A faint warm hairline down the leading edge — a subtle "friction" cue
   against the otherwise cool brand palette; restraint, not a colour shift. */
.problem-card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 2px;
  background: linear-gradient(180deg, rgba(255, 176, 102, 0.5), rgba(255, 122, 89, 0.12));
}
.problem-card:hover {
  background: rgba(255, 168, 92, 0.04);
  border-color: rgba(255, 168, 92, 0.16);
}
.problem-card h3 {
  font-size: 1.15rem;   /* not the huge .h3 clamp; weight/tracking inherit from base.css */
  line-height: 1.2;
  margin-bottom: 12px;
}
.problem-card p {
  color: var(--lb-text-dim);
  line-height: 1.6;
}

.problem-close {
  margin-top: 48px;
  max-width: 52em;
}
.problem-close strong { color: var(--lb-text); font-weight: 600; }

@media (max-width: 1024px) {
  .problem-grid { grid-template-columns: 1fr 1fr; }
  /* :nth-child(n) matches every card at equal specificity to the span rules
     above and, being later + in-media, wins to reset the asymmetry. */
  .problem-card:nth-child(n) { grid-column: auto; }
  /* Five cards on a 2-col grid leave a hole next to the last one — let it
     span the row instead (same specificity as the reset above; later wins).
     No-op at ≤560 where the grid is single-column anyway. */
  .problem-card:last-child { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .problem-grid { grid-template-columns: 1fr; }
}

/* ── #cycle — pinned 24-hour cycle set-piece ────────────────────────── */
/* Base styles double as the reduced-motion / no-JS fallback: a calm
   vertical read with the ring drawn complete (every stage lit) — it must
   look intentional, never broken. cycle.js opts INTO the pinned treatment
   by adding .cycle-enhanced to the section (desktop + motion only). */
#cycle .eyebrow { margin-bottom: 16px; }
#cycle .h2 { max-width: 16em; }

.cycle-stage-area {
  display: grid;
  grid-template-columns: minmax(300px, 400px) 1fr;
  gap: 72px;
  align-items: start;
  margin-top: 56px;
}
.cycle-ring {
  width: 100%;
  height: auto;
  overflow: visible; /* node labels sit just outside the viewBox edges */
}
/* The end-anchored node labels (INSPECT / WORKSHOP) hang ~29px outboard of
   the viewBox. Below the container max (1200px, NOT a layout breakpoint —
   the page margin is a fixed 24px there) that hang crosses the viewport
   edge and clips. Inset the ring off the left edge to re-buy the room; the
   ≤900 fallback re-centres with margin-inline:auto further down, which
   overrides this margin-left in the cascade. */
@media (max-width: 1200px) {
  .cycle-ring {
    width: calc(100% - 22px);
    margin-left: 22px;
  }
}

/* SVG internals. Defaults paint the COMPLETED cycle (full arc, all nodes
   lit) for the static fallback; cycle.js resets these inline and lets the
   scrub earn them back. */
.cycle-track { fill: none; stroke: rgba(255, 255, 255, 0.08); stroke-width: 3; }
.cycle-arc {
  fill: none;
  stroke: url(#lbgrad);
  stroke-linecap: round;
  stroke-dasharray: 1; /* pathLength="1" normalises the circumference */
  stroke-width: 3;
  filter: drop-shadow(0 0 6px rgba(0, 201, 240, 0.35));
}
.node-base { fill: #0a1730; stroke: rgba(255, 255, 255, 0.25); stroke-width: 1.5; }
.node-lit { fill: url(#lbgrad); filter: drop-shadow(0 0 12px rgba(0, 201, 240, 0.6)); }
.node-label {
  font: 600 12.5px var(--font-tech);
  letter-spacing: 0.14em;
  fill: rgba(234, 242, 255, 0.85);
}
/* Centre stage counter — enhanced mode only (meaningless in a static list). */
.cycle-ring-idx { font: 700 52px var(--font-tech); fill: url(#lbgrad); opacity: 0; }
.cycle-ring-of {
  font: 600 13px var(--font-tech);
  letter-spacing: 0.2em;
  fill: var(--lb-text-dim); /* -faint is ~3:1 here; free contrast margin */
  opacity: 0;
}
#cycle.cycle-enhanced .cycle-ring-idx,
#cycle.cycle-enhanced .cycle-ring-of { opacity: 1; }

.cycle-stages { display: grid; gap: 36px; }
.cycle-stage h3 { font-size: 1.35rem; line-height: 1.25; margin-bottom: 10px; }
/* Gradient tick above each stage title — same rule language as .dive-payoff. */
.cycle-stage h3::before {
  content: '';
  display: block;
  width: 28px;
  height: 2px;
  border-radius: 1px;
  background: var(--lb-gradient);
  margin-bottom: 16px;
}
.cycle-stage p { color: var(--lb-text-dim); line-height: 1.65; max-width: 34em; }

.cycle-config { margin-top: 56px; text-wrap: balance; } /* avoids a "— not ours." widow line */
.cycle-config strong { color: var(--lb-text); font-weight: 600; }

/* Enhanced (JS + ≥901px): the pinned full-viewport composition. */
#cycle.cycle-enhanced { padding-block: 0; }
#cycle.cycle-enhanced .cycle-pin {
  min-height: 100vh; /* fallback for browsers without svh */
  min-height: 100svh;
  display: grid;
  align-items: center;
  padding-block: 104px 56px; /* headroom under the fixed nav */
}
#cycle.cycle-enhanced .cycle-stage-area {
  /* vh cap keeps header + ring + config inside one viewport on short screens */
  grid-template-columns: minmax(320px, min(440px, 48vh)) 1fr;
  align-items: center;
  margin-top: clamp(28px, 4.5vh, 56px);
}
#cycle.cycle-enhanced .cycle-stages { display: grid; gap: 0; }
#cycle.cycle-enhanced .cycle-stage { grid-area: 1 / 1; }
#cycle.cycle-enhanced .cycle-stage h3 { font-size: 1.85rem; }
#cycle.cycle-enhanced .cycle-stage p { font-size: 1.1rem; }
#cycle.cycle-enhanced .cycle-config { margin-top: clamp(24px, 4vh, 56px); }

/* Deliberately 900px, NOT the shared 1024 scale — cycle.js pins at
   (min-width: 901px); this fallback layout must engage exactly where the
   pin disengages. See the scale note at the top of this file. */
@media (max-width: 900px) {
  .cycle-stage-area { grid-template-columns: 1fr; gap: 48px; }
  .cycle-ring { max-width: 340px; margin-inline: auto; }
  .cycle-config { margin-top: 48px; }
}

/* ── #features — deep-dives ─────────────────────────────────────────── */
#features .eyebrow { margin-bottom: 16px; }
#features .h2 { max-width: 15em; }

.dive {
  display: grid;
  grid-template-columns: 5fr 7fr;
  gap: 64px;
  align-items: center;
  padding-block: 72px;
}
/* Header → first dive rhythm mirrors #problem (h2 → grid at ~56–64px). */
.dive:first-of-type { padding-top: 64px; }
/* Alternate dives flip visually only — copy stays first in DOM for reading
   order. No direction:rtl tricks: wider track first + order on the copy. */
.dive.reverse { grid-template-columns: 7fr 5fr; }
.dive.reverse .dive-copy { order: 2; }

.dive-kicker {
  font: 600 0.8rem var(--font-tech);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--lb-text-dim); /* -faint fails WCAG AA (3.25:1) at this size */
  margin-bottom: 14px;
}
.dive-copy .h3 { margin-bottom: 16px; }
.dive-body { color: var(--lb-text-dim); line-height: 1.65; }
.dive-payoff {
  margin-top: 22px;
  color: var(--lb-teal);
  font-weight: 600;
}
/* border-top can't take a gradient; a small gradient block reads as a rule. */
.dive-payoff::before {
  content: '';
  display: block;
  width: 28px;
  height: 2px;
  border-radius: 1px;
  background: var(--lb-gradient);
  margin-bottom: 12px;
}

/* Paired-shot dives (04, 06): primary frame with a smaller secondary card
   overlapping its lower corner. Offsets are inset/padding based, NEVER
   transform — Task 8's parallax force-sets y transforms on .dive .frame
   and would clobber a transform offset. */
.frame-pair {
  position: relative;
  /* Reserves the band the secondary hangs into, so it can't collide with
     the next dive's content. */
  padding-bottom: 56px;
}
.pair-primary { width: 88%; }
.pair-secondary {
  position: absolute;
  right: 0;
  bottom: 0;
  width: 55%;
  z-index: 1;
  /* Heavier, tighter shadow than .frame's default so it reads as a card
     stacked above the primary. */
  box-shadow: 0 34px 70px -16px rgba(0, 0, 0, 0.85);
}

/* Tablet collapse: copy above frame, one column. Parallax is gated off at
   the same boundary in motion.js (≥1025px) — ±40px of scrub travel would
   shove frames into the copy stacked above/below them. */
@media (max-width: 1024px) {
  .dive,
  .dive.reverse {
    grid-template-columns: 1fr;
    gap: 40px;
    padding-block: 48px;
  }
  .dive.reverse .dive-copy { order: 0; } /* copy back above the frame */
  .dive:first-of-type { padding-top: 48px; }
  /* Overlap survives the collapse (both members are %-of-column), just
     shallower: the hang-band shrinks so the stack doesn't tower on phones. */
  .frame-pair { padding-bottom: 40px; }
  .pair-secondary { width: 52%; }
}

/* ── defect-flow (inside dive 04) ───────────────────────────────────── */
/* A vertical mini-timeline of one defect's night: report → unfit → night
   crew → fit. Base styles ARE the reduced-motion / no-JS fallback — every
   dot lit and the connector fully drawn, so it reads as an intentional
   finished state. defect-flow.js opts INTO the scrub by adding
   .flow-enhanced and resetting the starting state inline (line collapsed,
   dots dark); the scroll then earns the line + lights the dots 1→4.
   Vertical, not horizontal: the copy is long and the slot lives in the
   narrow 5fr copy column (~473px), where a stacked read wins outright. */
.defect-flow {
  position: relative;
  margin-top: 28px;
  display: grid;
  gap: 16px;
}
.flow-node {
  position: relative;
  display: grid;
  grid-template-columns: 20px 1fr;
  column-gap: 14px;
  align-items: start;
}
.flow-node p {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--lb-text-dim);
}
.flow-time {
  font: 600 0.8rem var(--font-tech);
  letter-spacing: 0.02em;
  color: var(--lb-teal);
  margin-right: 7px;
}
/* Dot default = LIT (the completed fallback). justify-self centres it on the
   line at x=10px; margin-top drops its centre onto the first text line. */
.flow-dot {
  justify-self: center;
  margin-top: 4px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  z-index: 1;
  background: #00d5ae;
  box-shadow: 0 0 14px rgba(0, 213, 174, 0.6);
}
/* Node 2 is the safety moment — bus marked unfit. It lights the app's
   danger tone so the read is unmistakable, in fallback and enhanced alike. */
.flow-node:nth-child(2) .flow-dot {
  background: #ff4545;
  box-shadow: 0 0 14px rgba(255, 69, 69, 0.6);
}
/* Connector: 2px gradient rail behind the dots (span from ~dot1 centre to
   ~dot4 centre — both end nodes are single-line, so 11px insets land true).
   transform-origin:top so the enhanced scaleY draws top-down. */
.flow-line {
  position: absolute;
  top: 11px;
  bottom: 11px;
  left: 9px;
  width: 2px;
  border-radius: 1px;
  background: linear-gradient(180deg, #00d5ae 0%, #00c9f0 100%);
  transform-origin: 50% 0%;
  z-index: 0;
}

/* ── #copilot — spoken commands ─────────────────────────────────────── */
/* Centred (echoes the hero) as a deliberate breath after the left-aligned
   feature deep-dives. */
.copilot-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.copilot-inner .eyebrow { margin-bottom: 18px; }
/* Mirror the hero's trailing dash so the label sits dead-centre. */
.copilot-inner .eyebrow::after {
  content: '';
  width: 28px;
  height: 1px;
  background: var(--lb-gradient);
}
.copilot-inner .h2 { max-width: 14em; }

/* Command pills: left-aligned text inside a centred column so each line
   reads like a spoken instruction on a terminal. */
.copilot-chips {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
  width: 100%;
  max-width: 620px;
  margin: 44px auto 0;
}
.chip {
  position: relative;
  overflow: hidden;
  background: var(--lb-glass);
  border: 1px solid var(--lb-glass-border);
  border-radius: 14px;
  padding: 18px 28px;
  text-align: left;
  font: 500 0.95rem/1.5 var(--font-tech);
  letter-spacing: 0.01em;
  color: var(--lb-text);
}
/* Brand gradient down the leading edge — the "voice heard" cue. */
.chip::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--lb-gradient);
}
.copilot-inner .lead {
  margin-top: 34px;
  margin-inline: auto;
  max-width: 44em;
  text-wrap: balance;
}

/* ── #economics — the arithmetic ────────────────────────────────────── */
/* Left-aligned, back to the feature-section rhythm. */
#economics .eyebrow { margin-bottom: 16px; }
#economics .h2 { max-width: 16em; }
#economics .lead { margin-top: 24px; }

.stat-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-top: 56px;
}
.stat { padding: 32px; }
/* Gradient-clip the whole numeral (covers "80%", "15%" and "every").
   The child data-count span inherits the transparent fill, so the gradient
   paints across the full glyph run. */
.stat .stat-num {
  display: block;
  background: var(--lb-gradient);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  line-height: 1.05;
}
.stat p {
  margin-top: 12px;
  color: var(--lb-text-dim);
  font-size: 0.95rem;
  line-height: 1.55;
}
/* HARD SPEC RULE: the attribution line is never dropped. -dim (not -faint)
   so it stays legible at this size. */
.stat-source {
  margin-top: 20px;
  color: var(--lb-text-dim);
  font-size: 0.85rem;
}

@media (max-width: 1024px) {
  /* Three-across turns cramped below ~1024 (cards ≲300px against a 4rem
     numeral); a single stacked column keeps the big-number rhythm. */
  .stat-grid { grid-template-columns: 1fr; margin-top: 48px; }
}

/* ── #onboarding — live in an hour ──────────────────────────────────── */
#onboarding .eyebrow { margin-bottom: 16px; }
#onboarding .h2 { max-width: 16em; }

.onboard-paths {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  margin-top: 56px;
}
.path-card { padding: 32px; }
.path-card h3 {
  font-size: 1.15rem;
  line-height: 1.2;
  margin-bottom: 12px;
}
.path-card p {
  color: var(--lb-text-dim);
  line-height: 1.6;
}
.path-card strong { color: var(--lb-text); font-weight: 600; }

/* Horizontal 4-step rail. Times label the steps, so no list markers. */
.onboard-timeline {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: 48px;
}
.onboard-timeline li {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 36px 16px 0;
  color: var(--lb-text-dim);
  font-size: 0.95rem;
  line-height: 1.5;
  text-wrap: balance; /* step 1 wraps to two lines — balance beats an orphaned "BODS" */
}
/* Connecting rail (a border-top can't hold a gradient). Trim the overhang
   at the two ends so the line runs dot-to-dot, not off the edges. */
.onboard-timeline li::before {
  content: '';
  position: absolute;
  top: 6px;
  left: 0;
  right: 0;
  height: 2px;
  background: var(--lb-gradient);
  opacity: 0.55;
}
.onboard-timeline li:first-child::before { left: 50%; }
.onboard-timeline li:last-child::before { right: 50%; }
/* Node marker sitting on the rail. */
.onboard-timeline li::after {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--lb-cyan);
  box-shadow: 0 0 0 5px rgba(0, 201, 240, 0.14);
}
.t-time {
  display: block;
  font: 700 1.15rem var(--font-tech);
  color: var(--lb-teal);
  margin-bottom: 6px;
}
.onboard-close {
  margin-top: 40px;
  max-width: 44em;
}

/* Was 720px; folded onto the shared 840 step — paths at 720–840 were
   already tight (~330px cards), and the 4-across rail steps drop under
   190px each there, so both stack together at the nav breakpoint. */
@media (max-width: 840px) {
  .onboard-paths { grid-template-columns: 1fr; }
  /* Rail turns vertical: stack the steps, drop the horizontal connector. */
  .onboard-timeline { grid-template-columns: 1fr; gap: 24px; }
  .onboard-timeline li {
    flex-direction: row;
    align-items: baseline;
    text-align: left;
    gap: 12px;
    padding: 0;
  }
  .onboard-timeline li::before,
  .onboard-timeline li::after { display: none; }
  .t-time { margin-bottom: 0; flex-shrink: 0; }
}

/* ── #cta — the finale ──────────────────────────────────────────────── */
.cta-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
/* A touch more breathing room than a standard section — this is the close. */
#cta { padding-block: clamp(120px, 15vw, 208px); }
.cta-inner .lead {
  margin-top: 22px;
  margin-inline: auto;
  max-width: 40em;
}
.cta-inner .hero-ctas { margin-top: 40px; }
.cta-scope {
  margin-top: 40px;
  margin-inline: auto;
  max-width: 46em;
  color: var(--lb-text-dim);
  font-size: 0.95rem;
  line-height: 1.6;
  text-wrap: balance; /* two even lines; pairs with the nowrap on "rip-and-replace" */
}

/* ── #footer — modest close, not a full section ─────────────────────── */
#footer {
  border-top: 1px solid var(--lb-glass-border);
  padding-block: 48px;
}
.footer-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 12px;
}
.footer-inner img { opacity: 0.9; }
.footer-inner > p:not(.footer-legal) {
  color: var(--lb-text-dim);
  font-size: 0.95rem;
}
.footer-inner a[data-email] {
  color: var(--lb-text);
  text-decoration: none;
}
.footer-inner a[data-email]:hover { text-decoration: underline; }
.footer-legal {
  color: var(--lb-text-dim);
  font-size: 0.85rem;
}
