/* ════════════════════════════════════════════════════════════════════
   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; }

/* Even 6-col grid: six 2-col cards, three per row (2-2-2 / 2-2-2). The old
   asymmetric 3-over-2 split died when the sixth card (nobody knows where
   the bus is) arrived — six cards read best as a balanced 3×2. */
.problem-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 20px;
  margin-top: 56px;
}
.problem-card { grid-column: span 2; }

.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; }
  /* Equal specificity to the span rule above; later + in-media wins. Six
     cards fill a 2-col grid exactly (3 rows), so no hole to patch. */
  .problem-card { grid-column: auto; }
}
@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; }
/* Wide enough for "The bus engineering workflow, end to end." to sit on ONE
   line at desktop — a second heading line eats into the 100svh pin budget. */
#cycle .h2 { max-width: 24em; }

.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 (ON THE ROAD / WORKSHOP) hang ~42 SVG units
   outboard of the viewBox — ON THE ROAD is the longest label this ring has
   carried, so the old 1200px boundary clipped it at 1201–1320px where the
   page margin alone (as little as 24px) can't absorb the hang. 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: 1320px) {
  .cycle-ring {
    width: calc(100% - 26px);
    margin-left: 26px;
  }
}

/* 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; }

/* ── The branch tree (right column) ──────────────────────────────────
   Each stage is a diagram, not a paragraph: hub (title + tagline) → a
   vertical rail → horizontal spurs → glass feature cards, then an
   optional mechanism rule-strip and a handoff arrow flowing out of the
   rail. Grammar: neutral cards = workflow pages; cyan spur + cyan card
   (or borderless italic fact) = live telematics; gradient-ticked strip =
   a rule of the system; elbow-arrow = what this stage hands to the next.
   Base styles paint every tree COMPLETE — the no-JS / reduced-motion /
   mobile fallback reads top-to-bottom as the full lifecycle. */
.cycle-stages { display: grid; gap: 72px; }
.tree-hub h3 { font-size: 1.35rem; line-height: 1.25; margin-bottom: 6px; }
/* Gradient tick above each stage title — same rule language as .dive-payoff.
   In enhanced mode this tick swings to the LEFT of the title and becomes the
   landing pad the ring→hub connector draws into. */
.tree-hub h3::before {
  content: '';
  display: block;
  width: 28px;
  height: 2px;
  border-radius: 1px;
  background: var(--lb-gradient);
  margin-bottom: 16px;
}
.tree-tagline { color: var(--lb-text-dim); line-height: 1.5; max-width: 34em; }

.cycle-tree {
  position: relative;
  margin-top: 22px;
  padding-left: 46px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* The rail — real element (not a pseudo) so the scrub can grow it. Runs from
   under the hub to just past the last row; the handoff elbow continues it. */
.tree-rail {
  position: absolute;
  left: 11px;
  top: -12px;
  bottom: -14px;
  width: 2px;
  border-radius: 1px;
  background: linear-gradient(180deg, rgba(0, 213, 174, 0.65), rgba(0, 164, 245, 0.3));
}
.tree-row { position: relative; }
.tree-spur {
  position: absolute;
  left: -35px;
  top: 50%;
  margin-top: -1px;
  width: 35px;
  height: 2px;
  border-radius: 1px;
  background: rgba(255, 255, 255, 0.16);
}
.tree-card {
  padding: 9px 16px 10px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.13);
  border-radius: 14px;
}
.tree-name {
  display: block;
  font: 600 0.92rem var(--font-tech);
  letter-spacing: 0.04em;
  color: var(--lb-text);
}
.tree-role {
  display: block;
  margin-top: 2px;
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--lb-text-dim);
}

/* Cyan family — telematics. Desaturated cyan text + cyan spur; the same
   live-data cue as the section caption below the ring. */
.tree-cyan .tree-spur {
  background: rgba(0, 201, 240, 0.45);
  box-shadow: 0 0 8px rgba(0, 201, 240, 0.35);
}
.tree-cyan .tree-card {
  border-color: rgba(0, 201, 240, 0.28);
  background: rgba(0, 201, 240, 0.05);
}
.tree-cyan .tree-name { color: rgba(151, 216, 240, 0.95); }
.tree-cyan .tree-role { color: rgba(151, 216, 240, 0.66); }
/* Cyan LINE — a telematics fact on the tree, no card chrome. */
.tree-fact {
  padding-block: 3px;
  font-size: 0.88rem;
  font-style: italic;
  line-height: 1.5;
  color: rgba(151, 216, 240, 0.85);
  max-width: 36em;
}

/* Mechanism — "a rule of the system", not a feature: no spur, a quiet
   tinted strip hanging off the rail with the site's gradient-tick cue. */
.tree-rule {
  position: relative;
  padding: 8px 14px 8px 16px;
  font-size: 0.88rem;
  font-style: italic;
  line-height: 1.5;
  color: var(--lb-text-dim);
  background: linear-gradient(90deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0) 78%);
  border-radius: 0 10px 10px 0;
  max-width: 40em;
}
.tree-rule::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  border-radius: 1px;
  background: var(--lb-gradient);
}

/* Handoff — the rail turns into an arrow and flows to the next stage
   (stage 6's variant bends back up toward the start of the cycle). */
.tree-handoff {
  position: relative;
  margin-top: 16px;
  padding-left: 58px;
  min-height: 26px;
  display: flex;
  align-items: center;
}
.handoff-glyph {
  position: absolute;
  left: 10px;
  top: -2px;
  overflow: visible;
}
.handoff-glyph path {
  fill: none;
  stroke: var(--lb-teal);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  /* pathLength="1" (markup) + dasharray 1 → offset 0 (the CSS default)
     paints the arrow complete for the fallback; the scrub draws it. */
  stroke-dasharray: 1;
  filter: drop-shadow(0 0 6px rgba(0, 213, 174, 0.35));
}
.tree-handoff p {
  font-size: 0.95rem;
  line-height: 1.5;
  color: rgba(234, 242, 255, 0.82);
  max-width: 36em;
}

/* Connector overlay — created by cycle.js in enhanced mode only; draws the
   line from the active ring node out to the stage hub. */
.cycle-connectors {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
}
.connector-path {
  fill: none;
  stroke: url(#lbgrad-conn);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 1; /* pathLength="1" normalises each path */
  filter: drop-shadow(0 0 6px rgba(0, 201, 240, 0.35));
}

/* Two sentences on two rendered lines (the <br> in markup); balance still
   earns its keep when either sentence wraps at narrow widths. */
.cycle-config { margin-top: 56px; text-wrap: balance; }
.cycle-config strong { color: var(--lb-text); font-weight: 600; }
/* Quiet closing caption — the telematics undertone under the config line,
   cyan-dashed like the tree's live-data rows. Revealed late in enhanced mode. */
.cycle-caption {
  position: relative;
  margin-top: 16px;
  padding-left: 26px;
  font-size: 0.9rem;
  line-height: 1.55;
  color: rgba(151, 216, 240, 0.6);
}
.cycle-caption::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 16px;
  height: 2px;
  border-radius: 1px;
  background: var(--lb-cyan);
  box-shadow: 0 0 8px rgba(0, 201, 240, 0.55);
}

/* 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 48px; /* headroom under the fixed nav */
}
#cycle.cycle-enhanced .cycle-stage-area {
  /* vh cap keeps header + ring + tree + config inside one viewport on short
     screens; the ring gives up width to buy the tree its height budget. */
  grid-template-columns: minmax(300px, min(400px, 44vh)) 1fr;
  align-items: center;
  margin-top: clamp(24px, 4vh, 48px);
  position: relative; /* the connector overlay spans this box */
}
#cycle.cycle-enhanced .cycle-stages { display: grid; gap: 0; }
/* Stages stack in one cell and crossfade; the cell is as tall as the
   tallest tree, so every stage's hub anchors at the same y. */
#cycle.cycle-enhanced .cycle-stage { grid-area: 1 / 1; align-self: start; }
#cycle.cycle-enhanced .tree-hub h3 {
  font-size: 1.6rem;
  position: relative;
}
/* The tick becomes the connector's landing pad: absolute to the title's
   left, vertically centred on the text line. */
#cycle.cycle-enhanced .tree-hub h3::before {
  position: absolute;
  left: -40px;
  top: 50%;
  margin: -1px 0 0;
}
#cycle.cycle-enhanced .cycle-config { margin-top: clamp(20px, 3.2vh, 48px); }
#cycle.cycle-enhanced .cycle-caption { margin-top: clamp(10px, 1.6vh, 16px); }
/* Height governor for short viewports (e.g. 1280×800): tighten the tree's
   vertical rhythm before anything clips. */
@media (max-height: 840px) {
  #cycle.cycle-enhanced .cycle-tree { gap: 9px; margin-top: 16px; }
  #cycle.cycle-enhanced .tree-card { padding: 7px 14px 8px; }
  #cycle.cycle-enhanced .tree-hub h3 { font-size: 1.45rem; }
  #cycle.cycle-enhanced .tree-handoff { margin-top: 12px; }
  #cycle.cycle-enhanced .cycle-stages { gap: 0; }
}

/* 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; }
  /* 300px (was 340): the end-anchored ON THE ROAD label hangs ~40 SVG units
     outboard of the viewBox; at 340px it clipped the edge on 390px phones. */
  .cycle-ring { max-width: 300px; margin-inline: auto; }
  .cycle-config { margin-top: 48px; }
  .cycle-stages { gap: 56px; }
}

/* ── #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;
}
