/* ============================================================================
   rutaapp.co — the whole stylesheet.

   One file, no build step, no external font, no CDN, no tracker. Everything
   below is either a system font or drawn in CSS/SVG, so the pages render
   instantly and work with no network beyond the HTML itself. The `_headers`
   CSP enforces that in production; this file has to stay honest to it.

   IDENTITY — Option 3 (docs/brand.md, owner-selected 2026-08-01).
     Ruta Orange  #FF451C
     Ruta Navy    #303560
   Black-dominant. Orange is an accent, never a wash: it lights the primary
   action, the live route and the mark, and nothing else.

   CONTRAST — every pair shipped here is measured, not eyeballed:
     #EDEDEF on #0A0A0B ......... 16.9:1   body, dark
     #8A8A95 on #0A0A0B .......... 5.8:1   muted body, dark
     #FF451C on #0A0A0B .......... 5.8:1   accent text + the mark, dark
     #0A0A0B on #FF451C .......... 5.8:1   primary button label
     #FFFFFF on #303560 .......... 11.6:1  type on the navy band
     #FF451C on #303560 .......... 3.4:1   LARGE TEXT / RULES ONLY
     #61616C on #0A0A0B .......... 3.2:1   interactive borders, dark
     #14161A on #F4F2EF ......... 16.2:1   body, light
     #5A5A66 on #F4F2EF .......... 6.1:1   muted body, light
     #C42700 on #F4F2EF .......... 5.2:1   accent TEXT, light (#FF451C is only
                                           3.1:1 on paper — display/graphic use
                                           only, never body copy)
     #8A8479 on #F4F2EF .......... 3.3:1   interactive borders, light
   ========================================================================= */

/* ---------------------------------------------------------------- tokens -- */

:root {
  color-scheme: dark light;

  /* Type. A deliberate two-voice system rather than one default face:
     a tightly-tracked neo-grotesque for the human voice (SF Pro Display /
     Segoe UI Variable / Roboto — whichever the platform has), and a monospace
     for the system voice: indices, labels, coordinates, receipts. It is a
     dispatch platform; the machine should sound like one. */
  --font-sans:
    ui-sans-serif, -apple-system, BlinkMacSystemFont, 'Segoe UI Variable Display',
    'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, sans-serif;
  --font-mono:
    ui-monospace, SFMono-Regular, 'SF Mono', Menlo, 'Cascadia Mono',
    'Roboto Mono', Consolas, monospace;

  /* Brand, fixed. */
  --orange: #ff451c;
  --navy: #303560;
  --navy-lift: #3a4075;

  /* Dark is the default, because the brand is. */
  --bg: #0a0a0b;
  --bg-lift: #101014;
  --surface: #131318;
  --surface-alt: #17171d;
  --border: #24242c;
  --border-strong: #61616c;
  --text: #ededef;
  --text-muted: #8a8a95;
  --accent: #ff451c;
  --accent-text: #ff451c;
  --on-accent: #0a0a0b;
  --grid-line: rgba(48, 53, 96, 0.5);
  --street: #363d72;
  --glow: rgba(48, 53, 96, 0.38);
  --grain-opacity: 0.05;

  --warn-bg: #2a1f00;
  --warn-fg: #ffd166;
  --warn-border: #e0a800;
  --warn-hatch: rgba(224, 168, 0, 0.22);
  --danger-bg: #2c1210;
  --danger-fg: #ff9a8f;
  --danger-border: #d93025;

  --radius: 14px;
  --radius-sm: 8px;
  --measure: 34rem;
  --shadow: 0 1px 0 rgba(255, 255, 255, 0.03) inset, 0 18px 40px rgba(0, 0, 0, 0.45);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-drop: cubic-bezier(0.5, 0, 0.2, 1.35);
}

@media (prefers-color-scheme: light) {
  :root {
    /* Not an inversion — a second, designed state. Warm paper, black ink,
       the same orange, navy for headings. Reads as the printed half of the
       identity rather than "dark mode turned off". */
    --bg: #f4f2ef;
    --bg-lift: #ffffff;
    --surface: #ffffff;
    --surface-alt: #edeae5;
    --border: #dad5ce;
    --border-strong: #8a8479;
    --text: #14161a;
    --text-muted: #5a5a66;
    --accent: #ff451c;
    --accent-text: #c42700; /* body-legible orange; #FF451C is 3.1:1 on paper */
    --on-accent: #0a0a0b;
    --grid-line: rgba(48, 53, 96, 0.14);
    --street: #c9c3ba;
    --glow: rgba(255, 69, 28, 0.1);
    --grain-opacity: 0.035;

    --warn-bg: #fff6dc;
    --warn-fg: #6b4200;
    --warn-border: #b57e00;
    --warn-hatch: rgba(181, 126, 0, 0.2);
    --danger-bg: #fdecea;
    --danger-fg: #a11208;
    --danger-border: #c81e14;

    --shadow: 0 1px 2px rgba(20, 22, 26, 0.06), 0 12px 28px rgba(20, 22, 26, 0.07);
  }
}

/* ------------------------------------------------------------------ base -- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 2rem;
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* A single grain plane over the whole page. Digital black is flat; a little
   noise gives it a surface, and it costs one data URI and no request. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 999;
  pointer-events: none;
  opacity: var(--grain-opacity);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

::selection {
  background: var(--orange);
  color: #0a0a0b;
}

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

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

/* ---------------------------------------------------------------- layout -- */

.wrap {
  width: 100%;
  max-width: 72rem;
  margin: 0 auto;
  padding: 0 clamp(20px, 5vw, 48px);
}

body.doc .wrap {
  max-width: 48rem;
}

.prose {
  max-width: var(--measure);
}

main {
  display: block;
}

body.doc main {
  padding: clamp(32px, 6vw, 56px) 0 8px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
  background: var(--orange);
  color: #0a0a0b;
  font-weight: 700;
  padding: 12px 18px;
  border-radius: 0 0 var(--radius-sm) 0;
}

.skip-link:focus {
  left: 0;
}

/* ---------------------------------------------------------------- header -- */

header.site {
  position: relative;
  z-index: 5;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
}

header.site .wrap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 24px;
  padding-top: 16px;
  padding-bottom: 16px;
}

.brand {
  display: inline-flex;
  align-items: baseline;
  gap: 11px;
  color: var(--text);
  text-decoration: none;
  margin-right: auto;
}

.brand .mark {
  width: auto;
  height: 22px;
  color: var(--orange);
  flex: none;
  align-self: center;
}

.brand .wordmark {
  font-size: 1.32rem;
  font-weight: 800;
  letter-spacing: -0.045em;
  line-height: 1;
}

.brand-locator {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
  align-self: center;
  padding-left: 14px;
  border-left: 1px solid var(--border);
}

@media (max-width: 40rem) {
  .brand-locator {
    display: none;
  }
}

nav.site {
  display: flex;
  gap: 22px;
}

nav.site a {
  color: var(--text-muted);
  text-decoration: none;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 10px 0;
  border-bottom: 2px solid transparent;
  transition: color 0.18s ease, border-color 0.18s ease;
}

nav.site a:hover,
nav.site a:focus-visible {
  color: var(--text);
  border-bottom-color: var(--orange);
}

nav.site a[aria-current='page'] {
  color: var(--text);
  border-bottom-color: var(--orange);
}

/* ------------------------------------------------------------------ type -- */

h1,
h2,
h3,
h4 {
  font-weight: 800;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.display {
  font-size: clamp(2.9rem, 9.5vw, 7.25rem);
  line-height: 0.86;
  letter-spacing: -0.05em;
  margin: 0 0 clamp(20px, 3vw, 30px);
}

.display em {
  font-style: normal;
  color: var(--accent);
}

.h-display {
  font-size: clamp(2.1rem, 6vw, 4.25rem);
  line-height: 0.94;
  letter-spacing: -0.042em;
  margin: 0 0 20px;
}

body.doc h1 {
  font-size: clamp(2.1rem, 7vw, 3.25rem);
  line-height: 1.02;
  letter-spacing: -0.04em;
  margin: 0 0 14px;
}

body.doc h2 {
  font-size: 1.42rem;
  line-height: 1.25;
  margin: 44px 0 14px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}

body.doc h3 {
  font-size: 1.1rem;
  margin: 30px 0 8px;
}

h4 {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  font-weight: 600;
  margin: 22px 0 6px;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.14em;
}

p,
ul,
ol,
dl {
  margin: 0 0 18px;
}

ul,
ol {
  padding-left: 1.3em;
}

li {
  margin-bottom: 9px;
}

li::marker {
  color: var(--accent-text);
}

a {
  color: var(--accent-text);
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
}

a:hover {
  text-decoration-thickness: 2px;
}

strong {
  font-weight: 700;
  color: var(--text);
}

.lede {
  font-size: clamp(1.075rem, 1.9vw, 1.3rem);
  line-height: 1.5;
  color: var(--text-muted);
  max-width: var(--measure);
}

.updated {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--text-muted);
  margin-bottom: 32px;
}

.micro {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  color: var(--text-muted);
  line-height: 1.75;
}

/* The mono "system voice": section indices and eyebrow labels. */
.eyebrow,
.index {
  display: flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 clamp(18px, 2.6vw, 26px);
}

.index .idx-num {
  color: var(--accent-text);
  font-weight: 700;
}

.eyebrow::before {
  content: '';
  width: 26px;
  height: 2px;
  background: var(--orange);
  flex: none;
}

/* --------------------------------------------------------------- buttons -- */

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0 0 22px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-decoration: none;
  padding: 15px 24px;
  border-radius: 100px;
  border: 1px solid transparent;
  transition: transform 0.18s var(--ease-out), background-color 0.18s ease,
    border-color 0.18s ease, color 0.18s ease;
}

/* Near-black label on orange: 5.8:1. White on orange would be 3.4:1 and fail
   for a label at this size — see the contrast table at the top of the file. */
.btn-primary {
  background: var(--orange);
  color: #0a0a0b;
}

.btn-primary:hover,
.btn-primary:focus-visible {
  background: #ff5c37;
  transform: translateY(-2px);
}

.btn-ghost {
  border-color: var(--border-strong);
  color: var(--text);
}

.btn-ghost:hover,
.btn-ghost:focus-visible {
  border-color: var(--orange);
  color: var(--accent-text);
  transform: translateY(-2px);
}

.btn .arrow {
  transition: transform 0.18s var(--ease-out);
}

.btn:hover .arrow {
  transform: translateX(4px);
}

@media (prefers-reduced-motion: reduce) {
  .btn,
  .btn:hover,
  .btn .arrow,
  .btn:hover .arrow {
    transform: none;
    transition: none;
  }
}

/* ------------------------------------------------------------------ hero -- */

.hero {
  position: relative;
  overflow: hidden;
  border-bottom: 1px solid var(--border);
  padding: clamp(40px, 7vw, 88px) 0 clamp(48px, 8vw, 104px);
}

/* Atmosphere: a navy pool bleeding out of the corner the route runs to, and a
   low orange warmth under the pickup point. Kept deliberately faint — the
   ground has to stay black, and the street map below is the real texture. A
   second CSS grid on top of it only muddied both. */
.hero::before {
  content: '';
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 130%;
  background:
    radial-gradient(46% 42% at 74% 40%, var(--glow), transparent 72%),
    radial-gradient(38% 34% at 10% 94%, rgba(255, 69, 28, 0.1), transparent 74%);
  pointer-events: none;
}

.hero-inner {
  position: relative;
  z-index: 2;
  display: grid;
  gap: clamp(28px, 5vw, 56px);
  align-items: center;
}

@media (min-width: 62rem) {
  .hero-inner {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  }
}

.hero-copy .lede {
  margin-bottom: 30px;
}

/* -------------------------------------------------------- the drop stage -- */
/* The mark reads as an r, an exclamation mark and a map pin at once. So it is
   staged as what it most wants to be here: a pin, dropping onto a city, with
   the route drawing out behind it. One orchestrated moment on load — not
   effects scattered down the page. */

.stage {
  position: relative;
  width: 100%;
  max-width: 34rem;
  margin-inline: auto;
  aspect-ratio: 520 / 620;
  max-height: 62vh;
}

@media (max-width: 62rem) {
  .stage {
    max-width: 22rem;
    aspect-ratio: 520 / 460;
    order: -1;
  }
}

.stage-map,
.stage-route {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

/* Both SVGs are drawn with preserveAspectRatio="none" so their coordinate
   space maps 1:1 onto the stage box at any aspect — that is what lets the mark
   be positioned in percentages and still land exactly on the end of the route.
   non-scaling-stroke keeps the line weights honest under that stretch. */
.stage-map path,
.stage-route path {
  vector-effect: non-scaling-stroke;
}

/* Dissolve the street network at its edges. Without this the map reads as a
   rectangular panel dropped on the page; with it, it reads as a field the
   route happens to cross. */
.stage-map {
  mask-image: radial-gradient(72% 62% at 52% 52%, #000 34%, transparent 100%);
  -webkit-mask-image: radial-gradient(72% 62% at 52% 52%, #000 34%, transparent 100%);
}

.stage-map .street {
  fill: none;
  stroke: var(--street);
  stroke-width: 1.25;
}

.stage-map .street-minor {
  stroke-width: 0.75;
  opacity: 0.62;
}

.stage-map .block {
  fill: var(--street);
  opacity: 0.16;
}

.stage-map .river {
  fill: none;
  stroke: var(--navy);
  stroke-width: 7;
  stroke-linecap: round;
  opacity: 0.85;
}

.route-line {
  fill: none;
  stroke: var(--orange);
  stroke-width: 3.5;
  stroke-linecap: round;
}

/* The pickup marker sits at the start of the route — (62, 566) of the 520x620
   field, i.e. 11.9% / 91.3%. Positioned in HTML rather than in the SVG so it
   stays a true circle when the field is stretched. */
.origin {
  position: absolute;
  left: 11.9%;
  top: 91.3%;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--bg);
  border: 3px solid var(--orange);
  transform: translate(-50%, -50%);
}

.origin::after {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--orange);
}

/* The mark itself, offset so its foot-dot centre — (13.5, 99.5) of the 59x113
   artwork, i.e. 22.9% / 88.0% of its own box — lands exactly on the end of
   the route. Percentages are self-relative, so it stays put at every size. */
.stage-mark {
  position: absolute;
  left: 63.5%;
  top: 48.4%;
  width: 27%;
  color: var(--orange);
  transform: translate(-22.9%, -88.05%);
  filter: drop-shadow(0 18px 28px rgba(255, 69, 28, 0.28));
}

.stage-mark svg {
  display: block;
  width: 100%;
  height: auto;
}

.ripple {
  position: absolute;
  left: 63.5%;
  top: 48.4%;
  width: 30%;
  aspect-ratio: 1;
  border-radius: 50%;
  border: 2px solid var(--orange);
  transform: translate(-50%, -50%) scale(0);
  opacity: 0;
  pointer-events: none;
}

/* --- the load sequence. Base styles are the FINAL state, so if animation is
   suppressed (reduced motion, or an engine that skips it) the composition is
   already correct and nothing is left invisible. --- */

@media (prefers-reduced-motion: no-preference) {
  .stage-mark {
    animation: pin-drop 1s var(--ease-drop) 0.15s backwards;
  }

  /* The order tells the story: the pin drops on where you are going, the route
     traces back to where you are standing, and the pickup marker lands last. */
  .route-line {
    animation: route-draw 1.15s ease-out 1.05s backwards;
  }

  .origin {
    animation: origin-in 0.55s var(--ease-drop) 2.05s backwards;
  }

  .ripple {
    animation: ripple-out 1.4s ease-out 1.05s;
  }

  .ripple-2 {
    animation-delay: 1.35s;
  }

  .stage-map {
    animation: fade-in 1.2s ease-out backwards;
  }

  .hero-copy > * {
    animation: rise 0.85s var(--ease-out) backwards;
  }

  .hero-copy > :nth-child(1) {
    animation-delay: 0.1s;
  }
  .hero-copy > :nth-child(2) {
    animation-delay: 0.2s;
  }
  .hero-copy > :nth-child(3) {
    animation-delay: 0.32s;
  }
  .hero-copy > :nth-child(4) {
    animation-delay: 0.44s;
  }
  .hero-copy > :nth-child(5) {
    animation-delay: 0.54s;
  }
}

@keyframes pin-drop {
  from {
    transform: translate(-22.9%, calc(-88.05% - 62vh)) scale(0.86);
    opacity: 0;
  }
  60% {
    opacity: 1;
  }
  to {
    transform: translate(-22.9%, -88.05%) scale(1);
    opacity: 1;
  }
}

/* pathLength="1" normalises the curve, so one unit of dashoffset is the whole
   route regardless of how the field is scaled. A NEGATIVE offset draws from
   the far end backwards — the route retracing itself to the pickup point. */
@keyframes route-draw {
  from {
    stroke-dasharray: 1;
    stroke-dashoffset: -1;
  }
  to {
    stroke-dasharray: 1;
    stroke-dashoffset: 0;
  }
}

@keyframes origin-in {
  from {
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.2);
  }
  to {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
  }
}

@keyframes ripple-out {
  from {
    transform: translate(-50%, -50%) scale(0.15);
    opacity: 0.85;
  }
  to {
    transform: translate(-50%, -50%) scale(2.6);
    opacity: 0;
  }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* ----------------------------------------------------------------- bands -- */

.band {
  position: relative;
  padding: clamp(56px, 9vw, 116px) 0;
  border-bottom: 1px solid var(--border);
}

.band-head {
  margin-bottom: clamp(28px, 4vw, 48px);
}

/* The route arriving at a stop: a hairline that draws in under each index. */
.band-head .index::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--orange), transparent);
  transform-origin: left;
}

.band-navy {
  background: var(--navy);
  color: #ffffff;
  border-bottom-color: var(--navy-lift);
}

.band-navy .index,
.band-navy .lede,
.band-navy .micro {
  color: rgba(255, 255, 255, 0.72);
}

.band-navy .index .idx-num {
  color: #ffffff;
}

.band-navy a {
  color: #ffffff;
}

.band-navy strong {
  color: #ffffff;
}

/* On navy, #FF451C is 3.4:1 — fine as a rule, not as text. Used only as a
   rule and an oversized display word here. */
.band-navy .index::after {
  background: linear-gradient(90deg, var(--orange), transparent);
}

.statement {
  font-size: clamp(2rem, 5.6vw, 4rem);
  font-weight: 800;
  letter-spacing: -0.042em;
  line-height: 1.02;
  margin: 0 0 28px;
  max-width: 20ch;
}

.statement .strike {
  color: var(--orange);
}

.band-navy .statement .strike {
  /* large display type only — 3.4:1 clears the 3:1 large-text threshold */
  color: var(--orange);
}

.two-col {
  display: grid;
  gap: clamp(24px, 4vw, 56px);
}

@media (min-width: 56rem) {
  .two-col {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
  }
}

/* ------------------------------------------------------------ route steps -- */
/* Four stops on one line — the page's own route, drawn literally. */

.route-steps {
  list-style: none;
  counter-reset: stop;
  padding: 0;
  margin: 0;
  display: grid;
  gap: clamp(26px, 3vw, 34px);
  position: relative;
}

.route-steps > li {
  position: relative;
  margin: 0;
  padding-left: 46px;
}

.route-steps > li::before {
  counter-increment: stop;
  content: counter(stop, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 2px;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--orange);
  color: #0a0a0b;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
}

/* the connector */
.route-steps > li::after {
  content: '';
  position: absolute;
  left: 14px;
  top: 32px;
  bottom: calc(-1 * clamp(26px, 3vw, 34px));
  width: 2px;
  background: linear-gradient(180deg, var(--orange), color-mix(in srgb, var(--orange) 25%, transparent));
  transform-origin: top;
}

.route-steps > li:last-child::after {
  display: none;
}

.route-steps h3 {
  font-size: 1.16rem;
  margin: 0 0 6px;
  letter-spacing: -0.02em;
}

.route-steps p {
  margin: 0;
  color: var(--text-muted);
  max-width: 44ch;
}

@media (min-width: 58rem) {
  .route-steps {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 28px;
  }

  .route-steps > li {
    padding-left: 0;
    padding-top: 52px;
  }

  .route-steps > li::before {
    top: 0;
  }

  .route-steps > li::after {
    left: 34px;
    top: 14px;
    bottom: auto;
    right: -28px;
    width: auto;
    height: 2px;
    background: linear-gradient(90deg, var(--orange), color-mix(in srgb, var(--orange) 25%, transparent));
  }
}

/* The 404 uses the same route, but it is three stops in a narrow document
   column — it must stay vertical at every width. */
@media (min-width: 58rem) {
  .route-steps.route-steps-404 {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(26px, 3vw, 34px);
  }

  .route-steps.route-steps-404 > li {
    padding-left: 46px;
    padding-top: 0;
  }

  .route-steps.route-steps-404 > li::before {
    top: 2px;
  }

  .route-steps.route-steps-404 > li::after {
    left: 14px;
    top: 32px;
    right: auto;
    bottom: calc(-1 * clamp(26px, 3vw, 34px));
    width: 2px;
    height: auto;
    background: linear-gradient(
      180deg,
      var(--orange),
      color-mix(in srgb, var(--orange) 25%, transparent)
    );
    /* higher specificity than the horizontal rule inside the @supports block,
       so the scroll-driven draw stays vertical here too */
    animation-name: draw-y;
  }
}

.route-steps h3 a {
  text-decoration: none;
}

.route-steps h3 a:hover {
  text-decoration: underline;
}

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

.tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 18px;
  margin-bottom: 24px;
}

.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 24px 26px;
  margin: 0 0 20px;
}

.card h3:first-child,
.card h2:first-child {
  margin-top: 0;
  border-top: none;
  padding-top: 0;
}

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

/* The three audiences. Staggered on wide screens so the row reads as a route
   climbing, not as three equal boxes. */
.panels {
  display: grid;
  gap: 18px;
  margin: 0;
}

@media (min-width: 58rem) {
  .panels {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 22px;
    align-items: start;
  }

  .panels > :nth-child(2) {
    margin-top: 34px;
  }

  .panels > :nth-child(3) {
    margin-top: 68px;
  }
}

.panel {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 26px 24px 28px;
  overflow: hidden;
  transition: border-color 0.2s ease, transform 0.2s var(--ease-out);
}

.panel::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 2px;
  background: var(--orange);
  transform: scaleX(0.18);
  transform-origin: left;
  transition: transform 0.35s var(--ease-out);
}

.panel:hover {
  border-color: var(--border-strong);
  transform: translateY(-3px);
}

.panel:hover::before {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .panel,
  .panel:hover,
  .panel::before,
  .panel:hover::before {
    transform: none;
    transition: none;
  }
}

.panel h3 {
  font-size: 1.3rem;
  letter-spacing: -0.028em;
  margin: 14px 0 10px;
}

.panel p {
  color: var(--text-muted);
  margin-bottom: 0;
}

.panel .kicker {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent-text);
}

/* --------------------------------------------------------- safety figure -- */

.figure-row {
  display: grid;
  gap: clamp(22px, 3vw, 40px);
  align-items: center;
}

@media (min-width: 50rem) {
  .figure-row {
    grid-template-columns: auto minmax(0, 1fr);
  }
}

.big-number {
  font-size: clamp(5rem, 15vw, 11rem);
  font-weight: 800;
  line-height: 0.8;
  letter-spacing: -0.06em;
  color: var(--orange);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.spec {
  list-style: none;
  padding: 0;
  margin: 0;
  border-top: 1px solid var(--border);
}

.spec > li {
  display: grid;
  gap: 2px 22px;
  padding: 14px 0;
  margin: 0;
  border-bottom: 1px solid var(--border);
}

@media (min-width: 40rem) {
  .spec > li {
    grid-template-columns: 12rem minmax(0, 1fr);
    align-items: baseline;
  }
}

.spec dt,
.spec .spec-key {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.spec .spec-val {
  margin: 0;
}

.band-navy .spec,
.band-navy .spec > li {
  border-color: rgba(255, 255, 255, 0.18);
}

.band-navy .spec .spec-key {
  color: rgba(255, 255, 255, 0.66);
}

/* --------------------------------------------------------------- callouts -- */

.note {
  border-left: 3px solid var(--orange);
  background: var(--surface);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: 16px 20px;
  margin: 0 0 22px;
}

.note.alert {
  border-left-color: var(--danger-border);
  background: var(--danger-bg);
  color: var(--danger-fg);
}

.note.alert strong {
  color: var(--danger-fg);
}

/* An open point that a lawyer, not an engineer, has to close. Amber rather
   than red: the page is publishable and everything in it is true — this marks
   the one clause whose *legal* determination is still outstanding, so it must
   read as a caveat, not as an error. */
.note.legal {
  border-left-color: var(--warn-border);
  background: var(--warn-bg);
  color: var(--warn-fg);
}

.note.legal strong {
  color: var(--warn-fg);
}

.note :last-child {
  margin-bottom: 0;
}

/* The numbered how-to lists inside the document pages. */
.steps {
  counter-reset: step;
  list-style: none;
  padding-left: 0;
}

.steps li {
  position: relative;
  padding-left: 42px;
  margin-bottom: 14px;
}

.steps li::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 0;
  top: 2px;
  width: 27px;
  height: 27px;
  border-radius: 50%;
  background: var(--orange);
  color: #0a0a0b;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ------------------------------------------------------ table of contents -- */

/* Only the privacy policy is long enough to need one. Deliberately quiet: a
   panel of links in the system voice, so it reads as apparatus rather than
   competing with the document it indexes. */
.toc {
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: var(--radius);
  padding: 18px 22px 22px;
  margin: 0 0 34px;
}

/* Specific enough to beat `body.doc h2`, which adds a top rule and 44px of
   margin to every section heading — correct in the document, wrong inside a
   panel that is itself a section marker. */
body.doc .toc h2 {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--text-muted);
  margin: 0 0 12px;
  padding-top: 0;
  border-top: none;
}

.toc ol {
  list-style: none;
  counter-reset: toc;
  margin: 0;
  padding: 0;
  columns: 2;
  column-gap: 32px;
}

/* Flex, not a margin on the ::before — a two-line entry has to hang under its
   own text, not wrap back under the number. */
.toc li {
  counter-increment: toc;
  break-inside: avoid;
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin: 0 0 6px;
  font-size: 0.94rem;
}

.toc li::before {
  content: counter(toc) '.';
  flex: none;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--text-muted);
}

@media (max-width: 40rem) {
  .toc ol {
    columns: 1;
  }
}

/* ---------------------------------------------------------------- tables -- */

.table-scroll {
  overflow-x: auto;
  margin: 0 0 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}

table {
  border-collapse: collapse;
  width: 100%;
  font-size: 0.94rem;
}

th,
td {
  text-align: left;
  vertical-align: top;
  padding: 11px 15px;
  border-bottom: 1px solid var(--border);
}

thead th {
  background: var(--surface-alt);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-muted);
  white-space: nowrap;
}

tbody tr:last-child td {
  border-bottom: none;
}

/* --------------------------------------------------------------- contact -- */

.contact {
  display: grid;
  grid-template-columns: max-content minmax(0, 1fr);
  gap: 10px 24px;
  margin: 0 0 20px;
}

.contact dt {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding-top: 3px;
}

.contact dd {
  margin: 0;
}

@media (max-width: 40rem) {
  .contact {
    grid-template-columns: 1fr;
    gap: 4px;
  }

  .contact dd {
    margin-bottom: 16px;
  }
}

/* ---------------------------------------------------------------- footer -- */

footer.site {
  background: var(--bg-lift);
  border-top: 1px solid var(--border);
  padding: clamp(36px, 5vw, 56px) 0 clamp(40px, 6vw, 64px);
  color: var(--text-muted);
  font-size: 0.92rem;
}

footer.site .foot-top {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px 32px;
  padding-bottom: 26px;
  margin-bottom: 26px;
  border-bottom: 1px solid var(--border);
}

footer.site .foot-mark {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  color: var(--text);
  text-decoration: none;
}

footer.site .foot-mark .mark {
  height: 30px;
  width: auto;
  color: var(--orange);
}

footer.site .foot-mark .wordmark {
  font-size: 1.5rem;
  font-weight: 800;
  letter-spacing: -0.045em;
}

footer.site nav {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
}

footer.site nav a,
footer.site .foot-links a {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}

footer.site nav a:hover,
footer.site nav a:focus-visible {
  color: var(--text);
  border-bottom-color: var(--orange);
}

footer.site p {
  margin: 0 0 12px;
  max-width: 60ch;
}

footer.site p:last-child {
  margin-bottom: 0;
}

footer.site a {
  color: var(--accent-text);
}

.disclaimer {
  font-size: 0.86rem;
  line-height: 1.6;
}

/* ------------------------------------------- the owner-confirm placeholder --
   Deliberately impossible to miss: a page that still holds one of these is not
   publishable. The marker text lives in the HTML, not in this file, so the
   placeholder is still obvious with CSS disabled, in a text-only reader, and
   to `scripts/check-placeholders.mjs` — which fails the deploy on it. */

.owner-confirm {
  display: inline-block;
  background-color: var(--warn-bg);
  background-image: repeating-linear-gradient(
    45deg,
    var(--warn-hatch),
    var(--warn-hatch) 10px,
    rgba(0, 0, 0, 0) 10px,
    rgba(0, 0, 0, 0) 20px
  );
  color: var(--warn-fg);
  border: 2px dashed var(--warn-border);
  border-radius: 6px;
  padding: 3px 9px;
  margin: 2px 0;
  font-weight: 700;
  font-family: var(--font-mono);
  font-size: 0.82em;
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
}

.owner-confirm::before {
  content: '⚠ ';
  font-weight: 800;
}

/* The banner is injected by placeholder-guard.js when — and only when — at
   least one .owner-confirm survives on the page. It removes itself the moment
   the last placeholder is filled in, so nobody has to remember to delete it. */

#draft-banner {
  position: sticky;
  top: 0;
  z-index: 900;
  background: #d93025; /* white on this = 4.8:1 */
  color: #ffffff;
  padding: 13px 20px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: center;
  line-height: 1.45;
}

#draft-banner small {
  display: block;
  font-weight: 400;
  letter-spacing: 0.02em;
  text-transform: none;
  opacity: 0.94;
  margin-top: 3px;
}

/* --------------------------------------------- scroll-driven, where it is --
   Sections settle into place as they enter the viewport. Pure CSS, so there is
   no script to load and nothing to block rendering; browsers without
   scroll-driven animations simply get the finished composition, which is the
   correct fallback rather than a degraded one.

   NOTE — these reveals move, they do NOT fade. An earlier draft animated
   opacity from 0 with `fill: both`, and any condition that left an element
   outside its range left it INVISIBLE: a full-page screenshot (the tool
   expands the viewport, so `view()` never resolves normally), printing, and
   any engine that resolves the timeline late. Body copy on a public page must
   never depend on an animation resolving. Transform-only is unconditionally
   safe: worst case the text sits 20px low, and it is still readable. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .band-head,
    .reveal,
    .panels > * {
      animation: rise-scroll 0.7s linear both;
      animation-timeline: view();
      animation-range: entry 8% cover 28%;
    }

    .band-head .index::after,
    .route-steps > li::after {
      animation: draw-x 1s linear both;
      animation-timeline: view();
      animation-range: entry 12% cover 34%;
    }

    .route-steps > li::after {
      animation-name: draw-y;
    }

    @media (min-width: 58rem) {
      .route-steps > li::after {
        animation-name: draw-x;
      }
    }
  }
}

@keyframes rise-scroll {
  from {
    transform: translateY(20px);
  }
  to {
    transform: none;
  }
}

@keyframes draw-x {
  from {
    transform: scaleX(0);
  }
  to {
    transform: scaleX(1);
  }
}

@keyframes draw-y {
  from {
    transform: scaleY(0);
  }
  to {
    transform: scaleY(1);
  }
}

/* ------------------------------------------------------------------ print -- */

@media print {
  :root {
    --bg: #ffffff;
    --bg-lift: #ffffff;
    --surface: #ffffff;
    --surface-alt: #ffffff;
    --border: #cccccc;
    --text: #000000;
    --text-muted: #333333;
    --accent-text: #000000;
  }

  body {
    background: #ffffff;
    color: #000000;
    font-size: 11pt;
  }

  body::after,
  .hero::before,
  .hero::after,
  .stage,
  nav.site,
  .cta-row {
    display: none !important;
  }

  .band,
  .band-navy {
    background: #ffffff !important;
    color: #000000 !important;
    padding: 12pt 0;
  }

  a {
    color: #000000;
  }

  /* Printing a page with placeholders must still show them. */
  .owner-confirm {
    border: 2px dashed #000000;
    background: none;
    color: #000000;
  }

  #draft-banner {
    background: #000000;
    color: #ffffff;
  }
}
