/* OverHalo — public site design system
   Night-valet palette taken from the concept photography: near-black ground,
   machined-aluminium text, warm lobby light as the only accent. */

:root {
  --ink:        #07080a;
  --ink-2:      #0d0f13;
  --ink-3:      #14171c;
  --line:       #23272e;
  --line-soft:  #1a1d23;
  --alum:       #c8cdd4;
  --alum-dim:   #8b9199;
  /* Was #5d636b, which measured 2.96:1 on --ink-3 and 3.30:1 on --ink — well
     under the 4.5:1 AA floor for normal text, and this token carries the
     captions, the fine print and the stage times. Same failure as the zone
     diagram whose labels could not be read: text that is present, selectable
     and effectively invisible. Lightened along the same neutral ramp to the
     first value clearing 4.5:1 on ALL THREE backgrounds (worst case 4.57 on
     --ink-3), so nothing else in the palette has to move. */
  --alum-faint: #7b8189;
  --white:      #f4f6f8;
  --gold:       #e0bd88;
  --gold-dim:   #a98a5c;
  --glass:      #9fd4e8;
  --ok:         #62c08a;
  --warn:       #e2b356;
  --bad:        #e0705f;

  /* Without this, a phone in dark mode paints its OWN dark colour into the
     regions outside the body background — the overscroll area, the surround
     behind a collapsing address bar — and the edges of the page go black
     against a site that is nearly-black but not quite. Declaring the scheme
     makes the UA use our background there instead, and it also darkens form
     controls and scrollbars to match rather than rendering them light. */
  color-scheme: dark;

  --gut: clamp(20px, 5vw, 64px);
  --maxw: 1280px;
  --narrow: 780px;

  --t-display: 300 clamp(2.6rem, 6.4vw, 5.2rem)/1.02 'Inter', system-ui, sans-serif;
  --t-h2:      300 clamp(1.9rem, 3.4vw, 3rem)/1.1 'Inter', system-ui, sans-serif;
  --t-h3:      500 clamp(1.05rem, 1.5vw, 1.25rem)/1.3 'Inter', system-ui, sans-serif;
  --track:     0.34em;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ink);
  color: var(--alum);
  font: 400 16px/1.65 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, video, svg { max-width: 100%; height: auto; display: block; }
a { color: inherit; }

.wrap { max-width: var(--maxw); margin: 0 auto; padding-inline: var(--gut); }
.narrow { max-width: var(--narrow); }

/* Present to a screen reader and to the document outline, absent on screen.
   Used for the section headings the design deliberately renders as a small
   eyebrow rather than an h2 — without them the outline jumps h1 to h3 and a
   grid of cards appears to belong to nothing. Clipped rather than
   display:none, because display:none removes it from the outline too. */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* ----------------------------------------------------------- typography */
h1, h2, h3, h4 { color: var(--white); font-weight: 300; margin: 0 0 .6em; }
h1 { font: var(--t-display); letter-spacing: -0.015em; }
h2 { font: var(--t-h2); letter-spacing: -0.01em; }
h3 { font: var(--t-h3); letter-spacing: 0; }
p { margin: 0 0 1.1em; max-width: 68ch; }
strong { color: var(--white); font-weight: 500; }

.wordmark {
  font-weight: 300;
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--white);
}
.eyebrow {
  font-size: .688rem;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 1.2em;
  font-weight: 500;
}
.eyebrow.muted { color: var(--alum-faint); }
.lede { font-size: clamp(1.02rem, 1.5vw, 1.2rem); color: var(--alum); max-width: 62ch; }
.fine { font-size: .8rem; color: var(--alum-faint); line-height: 1.6; }
.mono { font-family: ui-monospace, 'Cascadia Mono', 'SF Mono', Consolas, monospace; font-size: .85em; }

/* --------------------------------------------------------------- header */
/* No backdrop-filter. A blur filter on a sticky header promotes the whole
   scrolling area to a composited layer, and on several GPUs the text beneath
   it is then rasterised at the wrong scale and renders soft. A near-opaque
   background looks the same and costs nothing. */
.site-head {
  position: sticky; top: 0; z-index: 50;
  background: rgba(7,8,10,.94);
  border-bottom: 1px solid var(--line-soft);
}

/* THE HEADER IS STICKY, SO ANCHORS HAVE TO CLEAR IT.
   A jump to #deploy-section scrolls that element to y=0 — directly underneath
   a 68px header that is painted on top of it. Reported as "when I click watch
   it's not even taking me to the right spot", and it was true of every
   in-page link on every page. `scroll-margin-top` moves the resting position
   down by the header's height plus a little breathing room, and
   `scroll-behavior` makes the jump readable rather than instant. */
html { scroll-behavior: smooth; scroll-padding-top: 88px; }
:target,
[id] { scroll-margin-top: 88px; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
.site-head .bar {
  max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gut);
  height: 68px; display: flex; align-items: center; gap: 28px;
}
.site-head a { text-decoration: none; }
.brand { font-size: 1.02rem; letter-spacing: .3em; white-space: nowrap; }
.nav { display: flex; gap: 26px; margin-left: auto; align-items: center; }
/* :not(.btn) matters. `.nav a` is specificity (0,1,1) and `.btn` is (0,1,0),
   so without it the nav rule wins and paints the solid white Reserve button's
   label --alum-dim on --white: about 2.6:1, unreadable. `.btn.ghost` is
   (0,2,0) and survives, which is why Sign In looked right and Reserve did
   not — the two buttons disagreeing was the tell. */
.nav a:not(.btn) {
  font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--alum-dim); padding: 6px 0; border-bottom: 1px solid transparent;
}
.nav a:not(.btn):hover, .nav a:not(.btn)[aria-current] {
  color: var(--white); border-bottom-color: var(--gold);
}
.nav-tools { display: flex; gap: 14px; align-items: center; margin-left: 8px; }
#navtoggle { display: none; }
.burger { display: none; }

@media (max-width: 900px) {
  .nav {
    position: fixed; inset: 68px 0 auto 0; flex-direction: column; gap: 0;
    background: var(--ink-2); border-bottom: 1px solid var(--line);
    padding: 8px var(--gut) 24px; align-items: stretch;
    max-height: calc(100dvh - 68px); overflow-y: auto;
    transform: translateY(-120%); transition: transform .28s ease; margin-left: 0;
  }
  #navtoggle:checked ~ .nav { transform: translateY(0); }
  .nav a:not(.btn) { padding: 14px 0; border-bottom: 1px solid var(--line-soft); font-size: .84rem; }
  .nav-tools .btn { flex: 1; justify-content: center; }
  .nav-tools { margin: 14px 0 0; }
  .burger {
    display: block; margin-left: auto; width: 44px; height: 44px; cursor: pointer;
    position: relative; border: 1px solid var(--line); border-radius: 2px;
  }
  .burger i, .burger::before, .burger::after {
    content: ''; position: absolute; left: 12px; right: 12px; height: 1px;
    background: var(--alum); transition: .25s;
  }
  .burger::before { top: 16px; } .burger i { top: 21px; } .burger::after { top: 26px; }
  #navtoggle:checked ~ .burger::before { top: 21px; transform: rotate(45deg); }
  #navtoggle:checked ~ .burger::after  { top: 21px; transform: rotate(-45deg); }
  #navtoggle:checked ~ .burger i { opacity: 0; }
}

/* -------------------------------------------------------------- buttons */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 13px 24px; border: 1px solid var(--white); background: var(--white);
  color: var(--ink); font: 500 .78rem/1 'Inter', sans-serif;
  letter-spacing: .14em; text-transform: uppercase; text-decoration: none;
  cursor: pointer; transition: .2s; border-radius: 1px;
}
.btn:hover { background: var(--gold); border-color: var(--gold); color: var(--ink); }
.btn.ghost { background: transparent; color: var(--white); border-color: var(--line); }
.btn.ghost:hover { border-color: var(--gold); color: var(--gold); background: transparent; }
.btn.sm { padding: 9px 16px; font-size: .7rem; }
.btn[disabled] { opacity: .45; pointer-events: none; }
.btn-row { display: flex; flex-wrap: wrap; gap: 14px; margin: 2rem 0 0; }

/* ----------------------------------------------------------------- hero */
.hero { position: relative; min-height: min(78vh, 700px); display: flex; align-items: flex-end; overflow: hidden; }
.hero-media { position: absolute; inset: 0; }
/* Centred, not 62%. The car is the subject and it sits mid-frame; pushing the
   focal point right cropped it out and left the headline over empty sky. */
.hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 46%; }
/* The scrim exists to keep the headline legible, not to hide the photograph.
   At .94/.72 across the left 42% it was erasing the car entirely — the hero
   read as a black band with text on it. Legibility is carried by the bottom
   gradient and the left falloff is now gentle enough to see through. */
.hero-media::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(to right, rgba(7,8,10,.78) 0%, rgba(7,8,10,.42) 38%, rgba(7,8,10,0) 72%),
    linear-gradient(to top, rgba(7,8,10,.92) 0%, rgba(7,8,10,.30) 42%, rgba(7,8,10,0) 68%);
}
.hero-body { position: relative; padding: 130px 0 62px; width: 100%; }
.hero h1 { margin-bottom: .35em; }
/* .4em suited the old two-word mark, where the space did the splitting.
   OVERHALO is one eight-letter word, and at .4em it stretched past the width
   of the headline beneath it. The logotype stays uppercase; prose says
   OverHalo. */
.hero h1 .wordmark { display: block; font-size: clamp(1.6rem,3.2vw,2.3rem); letter-spacing: .26em; margin-bottom: .5rem; color: var(--gold); }
.hero .lede { margin-bottom: 0; }
.hero-price { margin-top: 2.4rem; font-size: .8rem; letter-spacing: .1em; color: var(--alum-dim); }
.hero-price b { color: var(--white); font-weight: 500; }

.modes-strip {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--line-soft); border-block: 1px solid var(--line-soft);
}
.modes-strip a {
  background: var(--ink); padding: 26px var(--gut); text-decoration: none;
  display: block; transition: background .25s;
}
.modes-strip a:hover { background: var(--ink-2); }
.modes-strip b { display: block; color: var(--white); letter-spacing: .2em; font-size: .8rem; font-weight: 500; }
.modes-strip span { font-size: .78rem; color: var(--alum-faint); }
@media (max-width: 760px) { .modes-strip { grid-template-columns: repeat(2, 1fr); } }

/* -------------------------------------------------------------- section */
.section { padding: clamp(64px, 9vw, 130px) 0; border-top: 1px solid var(--line-soft); }
.section.tight { padding-block: clamp(44px, 6vw, 80px); }
.section.alt { background: var(--ink-2); }
.section-head { max-width: 62ch; margin-bottom: clamp(32px, 4vw, 56px); }

.grid { display: grid; gap: clamp(18px, 2.4vw, 32px); }
.g2 { grid-template-columns: repeat(2, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 980px) { .g3, .g4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .g2, .g3, .g4 { grid-template-columns: 1fr; } }

.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(28px, 5vw, 72px); align-items: center; }
@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }

/* Every card states its own colours. A card that inherits them from the band
   it sits in turns invisible the first time the band changes. */
.card {
  background: var(--ink-2); border: 1px solid var(--line-soft);
  color: var(--alum); padding: clamp(20px, 2.6vw, 30px); border-radius: 2px;
}
.section.alt .card { background: var(--ink-3); }
.card h3 { color: var(--white); margin-bottom: .5em; }
.card p:last-child { margin-bottom: 0; }
.card .num { font-size: .7rem; letter-spacing: .2em; color: var(--gold); display: block; margin-bottom: 1.2em; }

.figure { border: 1px solid var(--line-soft); background: var(--ink-2); border-radius: 2px; overflow: hidden; }
.figure img { width: 100%; }
.figure figcaption { padding: 14px 18px; font-size: .78rem; color: var(--alum-faint); border-top: 1px solid var(--line-soft); }

/* --------------------------------------------------------- spec tables */
.spec { width: 100%; border-collapse: collapse; font-size: .9rem; }
.spec th, .spec td { text-align: left; padding: 13px 16px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
.spec th { color: var(--alum-dim); font-weight: 400; width: 42%; }
.spec td { color: var(--white); }
.spec tr:last-child th, .spec tr:last-child td { border-bottom: 0; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 18px; font-size: .88rem; }
.kv dt { color: var(--alum-faint); }
.kv dd { margin: 0; color: var(--white); }

/* --------------------------------------------------------------- pills */
.pill {
  display: inline-block; padding: 4px 11px; border: 1px solid var(--line);
  border-radius: 100px; font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--alum-dim); background: var(--ink-3);
}
.pill.ok   { color: var(--ok);   border-color: rgba(98,192,138,.35); }
.pill.warn { color: var(--warn); border-color: rgba(226,179,86,.35); }
.pill.bad  { color: var(--bad);  border-color: rgba(224,112,95,.35); }
.pill.gold { color: var(--gold); border-color: var(--gold-dim); }

/* -------------------------------------------------------- deploy scrub */
.deploy { display: grid; grid-template-columns: 300px 1fr; gap: clamp(24px, 4vw, 56px); align-items: start; }
@media (max-width: 900px) { .deploy { grid-template-columns: 1fr; } }
.deploy-steps { list-style: none; margin: 0; padding: 0; }
/* The tab buttons became plain list items: they controlled a caption panel
   that no longer exists, so pressing one did nothing. Selectors retargeted
   from .deploy-steps button to .deploy-steps li. */
.deploy-steps li { border-left: 1px solid var(--line); }
.deploy-steps li {
  display: block; width: 100%; text-align: left; background: none; border: 0;
  border-left: 2px solid transparent; margin-left: -1px; cursor: pointer;
  padding: 14px 0 14px 20px; color: var(--alum-dim); font: inherit; transition: .2s;
}
/* :hover removed — the list is not interactive any more. */
.deploy-steps li:first-child { border-left-color: var(--gold); color: var(--white); }
.deploy-steps b { display: block; font-size: .78rem; letter-spacing: .18em; text-transform: uppercase; font-weight: 500; }
.deploy-steps span { font-size: .8rem; color: var(--alum-faint); }
.deploy-steps li:first-child span { color: var(--alum-dim); }
.deploy-stage { background: var(--ink-2); border: 1px solid var(--line-soft); border-radius: 2px; padding: clamp(14px,2vw,24px); }
.deploy-cap { display: flex; justify-content: space-between; gap: 16px; align-items: baseline; margin-top: 16px; font-size: .82rem; color: var(--alum-faint); flex-wrap: wrap; }
.deploy-bar { height: 2px; background: var(--line); margin-top: 14px; }
.deploy-bar i { display: block; height: 100%; background: var(--gold); width: 20%; transition: width .45s ease; }

/* ------------------------------------------------------------- filmstrip */
.strip { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
@media (max-width: 760px) { .strip { grid-template-columns: repeat(2, 1fr); } }
.strip figure { margin: 0; border: 1px solid var(--line-soft); background: var(--ink-2); }
.strip figcaption { padding: 9px 11px; font-size: .64rem; letter-spacing: .14em; text-transform: uppercase; color: var(--alum-faint); }

/* ----------------------------------------------------------------- forms */
.form { display: grid; gap: 18px; }
.form .row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 620px) { .form .row2 { grid-template-columns: 1fr; } }
label { display: block; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase; color: var(--alum-dim); margin-bottom: 8px; }
input[type=text], input[type=email], input[type=tel], input[type=number],
input[type=password], input[type=search], select, textarea {
  width: 100%; padding: 12px 14px; background: var(--ink-3); color: var(--white);
  border: 1px solid var(--line); border-radius: 2px; font: inherit; font-size: .94rem;
}
select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--alum-dim) 50%), linear-gradient(135deg, var(--alum-dim) 50%, transparent 50%); background-position: right 18px center, right 13px center; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; padding-right: 36px; }
textarea { min-height: 120px; resize: vertical; }
input:focus, select:focus, textarea:focus { outline: 2px solid var(--gold); outline-offset: 1px; border-color: var(--gold); }
.check { display: flex; gap: 12px; align-items: flex-start; }
.check input { margin-top: 4px; accent-color: var(--gold); width: 16px; height: 16px; flex: none; }
.check label { text-transform: none; letter-spacing: 0; font-size: .85rem; color: var(--alum); margin: 0; }
.field-err { color: var(--bad); font-size: .78rem; margin-top: 6px; }

.notice { border: 1px solid var(--line); border-left: 2px solid var(--gold); background: var(--ink-2); padding: 16px 20px; border-radius: 2px; color: var(--alum); }
.notice.ok  { border-left-color: var(--ok); }
.notice.bad { border-left-color: var(--bad); }
.notice p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- footer */
.site-foot { border-top: 1px solid var(--line-soft); padding: clamp(48px,6vw,72px) 0 40px; background: var(--ink-2); }
/* Was an <h4>. Every page's outline ended on a jump from h2 straight to h4,
   because nothing on the page sits at h3 level just before the footer. These
   are top-level headings within the footer landmark, so h2 is the honest
   level; the class keeps the small type the h4 was providing. */
.foot-h {
  font: 500 .72rem/1.4 'Inter', system-ui, sans-serif;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--alum-dim); margin: 0 0 1.1em;
}
.foot-grid { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 36px; }
@media (max-width: 880px) { .foot-grid { grid-template-columns: 1fr 1fr; } }

/* THE FOOTER ON A PHONE.
   Collapsing four columns to one left three link lists stacked in a single
   narrow strip with the same 36px gap between them as between desktop
   columns — a very long, very loose ribbon of text with no separation
   between one list and the next, and the brand paragraph running the full
   width above it. On a phone the columns want to be close together, visually
   grouped, and divided. */
@media (max-width: 520px) {
  .foot-grid { grid-template-columns: 1fr; gap: 0; }
  .foot-grid > div + div {
    border-top: 1px solid var(--line-soft);
    padding-top: 22px; margin-top: 22px;
  }
  .foot-grid > div:first-child p { max-width: none; }
  /* Two-up link lists read far better than one long column on a narrow
     screen, and halve the height of the footer. */
  .site-foot ul { grid-template-columns: 1fr 1fr; gap: 12px 18px; }
  .site-foot a { font-size: .9rem; }
  .foot-h { margin-bottom: .9em; }
  .foot-legal { margin-top: 30px; gap: 10px; }
}
.site-foot h4 { font-size: .7rem; letter-spacing: .2em; text-transform: uppercase; color: var(--alum-faint); font-weight: 500; }
.site-foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.site-foot a { color: var(--alum-dim); text-decoration: none; font-size: .86rem; }
.site-foot a:hover { color: var(--gold); }
.foot-legal { margin-top: 46px; padding-top: 24px; border-top: 1px solid var(--line-soft); display: flex; flex-wrap: wrap; gap: 14px 28px; justify-content: space-between; }

/* ------------------------------------------------------------- utilities */
.center { text-align: center; }
.center p, .center .lede { margin-inline: auto; }
.stack > * + * { margin-top: 1.1em; }
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: var(--gut); top: 10px; z-index: 100; background: var(--white); color: var(--ink); padding: 10px 16px; }

/* Opacity only. Animating transform on a block full of text keeps it on a
   GPU layer for the duration and leaves sub-pixel text rendering disabled,
   which reads as permanently slightly-blurry copy. */
.reveal { opacity: 0; transition: opacity .55s ease; }
.reveal.in { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; transition: none; }
  .deploy-bar i { transition: none; }
}

/* =================================================== deployment drawing */
.bx { width: 100%; background: transparent; }
.bx text { font: 400 10px 'Inter', sans-serif; letter-spacing: .14em; fill: var(--alum-faint); text-transform: uppercase; }
.bx-label { letter-spacing: .24em; fill: var(--alum-dim); }
.bx-ground { stroke: var(--line); stroke-width: 1; }
.bx-divider { stroke: var(--line-soft); stroke-width: 1; }
.bx-car { fill: #1b1f25; stroke: #3a4048; stroke-width: 1.2; }
/* the side elevation's vehicle is the canonical one; do not re-fill it */
.bx-tyre { fill: #0b0d10; stroke: #2c3138; stroke-width: 1; }
.bx-cass-l rect, .bx-cass-r rect { fill: #454b53; stroke: #6a717a; stroke-width: 1; }
.bx-joint { fill: #878e97; stroke: none; }
.bx-arch rect:first-child { stroke: #7b828b; stroke-width: 1; }
.bx-panel path { stroke: #9fd4e8; stroke-width: .9; stroke-opacity: .55; }
.bx-seg { stroke: #9fd4e8; stroke-width: .6; stroke-opacity: .34; }
.bx-panelf { fill: url(#bxGlass); stroke: none; }
.bx-archf-line { fill: none; stroke: #767d86; stroke-width: 4; stroke-linecap: round; }
.bx-spine { fill: none; stroke: var(--gold); stroke-width: 1.6; stroke-dasharray: 5 4; }
.bx-lock { fill: var(--gold); }
.bx-dim line { stroke: var(--gold-dim); stroke-width: .8; }
.bx-dim text { fill: var(--gold); letter-spacing: .08em; }
.bx-leader { stroke-dasharray: 2 3; }
.bx-dim-sub { fill: var(--alum-faint) !important; letter-spacing: .1em; }
.bx-air path { fill: none; stroke: var(--glass); stroke-width: 1.2; stroke-dasharray: 3 5; stroke-linecap: round; }
.bx-air text { fill: var(--glass); letter-spacing: .12em; }
.bx-seal line { stroke: var(--ok); stroke-width: 2; }
.bx-seal text { fill: var(--ok); }

/* Animated parts. Origin is the cassette face, so everything grows out of
   the module it is stowed in rather than floating into place. */
.bx-arch, .bx-panel, .bx-archf, .bx-cass-l, .bx-cass-r {
  transform-box: fill-box; transform-origin: bottom;
  transition: transform .85s cubic-bezier(.33,.02,.2,1) var(--d, 0ms), opacity .5s ease var(--d, 0ms);
}
.bx-cass-l, .bx-cass-r { transform-origin: center; }
.bx-spine, .bx-lock, .bx-seal, .bx-air, .bx-dim {
  transition: opacity .6s ease .2s; opacity: 0;
}

/* stage 1 — retracted: modules flush, nothing standing */
.bx[data-stage="1"] .bx-arch,
.bx[data-stage="2"] .bx-arch { transform: scaleY(.035); }
.bx[data-stage="1"] .bx-archf,
.bx[data-stage="2"] .bx-archf { transform: scaleY(.05); opacity: .35; }
.bx[data-stage="1"] .bx-panel,
.bx[data-stage="2"] .bx-panel,
.bx[data-stage="3"] .bx-panel { transform: scaleY(0); opacity: 0; }

/* stage 2 — the modules translate outward for mirror and body clearance */
.bx[data-stage="1"] .bx-cass-l { transform: translateX(0); }
.bx[data-stage="1"] .bx-cass-r { transform: translateX(0); }
.bx[data-stage="2"] .bx-cass-l, .bx[data-stage="3"] .bx-cass-l,
.bx[data-stage="4"] .bx-cass-l, .bx[data-stage="5"] .bx-cass-l { transform: translateX(-28px); }
.bx[data-stage="2"] .bx-cass-r, .bx[data-stage="3"] .bx-cass-r,
.bx[data-stage="4"] .bx-cass-r, .bx[data-stage="5"] .bx-cass-r { transform: translateX(28px); }

/* stage 3 — arches telescope up and lock into the spine */
.bx[data-stage="3"] .bx-spine, .bx[data-stage="4"] .bx-spine, .bx[data-stage="5"] .bx-spine { opacity: 1; }
.bx[data-stage="3"] .bx-dim, .bx[data-stage="4"] .bx-dim, .bx[data-stage="5"] .bx-dim { opacity: 1; }

/* stage 4 — clear segments deploy between the arches */
.bx[data-stage="4"] .bx-lock, .bx[data-stage="5"] .bx-lock { opacity: 1; }

/* stage 5 — seals close, locks hold, climate runs */
.bx[data-stage="5"] .bx-seal, .bx[data-stage="5"] .bx-air { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .bx-arch, .bx-panel, .bx-archf, .bx-cass-l, .bx-cass-r { transition: none; }
}

/* ================================================== security zone rings */
.bz { width: 100%; }
.bz-ring { fill: none; stroke-width: 1; }
.bz-1 { stroke: rgba(224,112,95,.55); stroke-dasharray: 2 4; }
.bz-2 { stroke: rgba(226,179,86,.45); stroke-dasharray: 3 6; }
.bz-3 { stroke: rgba(159,212,232,.35); stroke-dasharray: 4 8; }
.bz-car { fill: #1b1f25; stroke: #3a4048; stroke-width: 1.2; }
.bz-tyre { fill: #0b0d10; stroke: #2c3138; }
.bz-node circle { fill: var(--glass); }
.bz-ping { fill: none; stroke: var(--glass); transform-box: fill-box; transform-origin: center; animation: bzping 3.4s ease-out infinite; }
@keyframes bzping { 0% { transform: scale(1); opacity: .7; } 70%, 100% { transform: scale(5); opacity: 0; } }
.bz-t { font: 400 9px 'Inter', sans-serif; letter-spacing: .24em; fill: var(--alum-faint); text-anchor: middle; }
.bz-t-in { fill: var(--bad); }
@media (prefers-reduced-motion: reduce) { .bz-ping { animation: none; opacity: 0; } }

/* ==================================================== platform envelopes */
.bp { width: 100%; }
.bp-name { font: 500 11px 'Inter', sans-serif; letter-spacing: .18em; fill: var(--white); }
.bp-dim  { font: 400 10px 'Inter', sans-serif; letter-spacing: .1em; fill: var(--alum-faint); }
.bp-env { fill: rgba(159,212,232,.08); stroke: rgba(159,212,232,.35); stroke-width: 1; }
.bp-min { fill: rgba(224,189,136,.14); stroke: var(--gold-dim); stroke-width: 1; }

/* ============================================ the arrival film (hero) ===
   One 17s clock. Every group animates against the same duration so the
   sequence stays in step. The stagger is baked into the keyframe percentages
   rather than animation-delay — a delay shifts an element's whole loop and
   the groups drift apart after a few cycles. */
.ar { width: 100%; display: block; }
/* superseded: fill now comes from the inline gradient in geometry.js */
.ar-glass  { stroke: #6d757f; stroke-width: 1; opacity: .95; }
.ar-crease { fill: none; stroke: #aab2bc; stroke-width: 1; opacity: .38; }
.ar-shadow { fill: #000; opacity: .5; }
.ar-headlight { fill: #fdf3dc; }
.ar-tail   { fill: #e0705f; }
.ar-cass rect { fill: #454b53; stroke: #767d86; stroke-width: 1; }
.ar-rail rect { fill: #3a4047; stroke: #6d757f; }
.ar-foot { fill: #8d959f !important; stroke: #b6bdc6 !important; }
.ar-pv     { fill: #1d2b3a !important; stroke: #2f4256 !important; }
.ar-joint  { fill: #8c939c; stroke: none !important; }
/* The near-side arch legs stand BETWEEN the viewer and the car, so they are
   drawn translucent — solid legs read as if the structure passes through the
   bodywork rather than in front of it. */
.ar-arch rect:first-child { fill: #23272d; fill-opacity: .55; stroke: #8b939d; stroke-width: 1; }
.ar-panel path { stroke: #9fd4e8; stroke-width: .9; stroke-opacity: .5; }
.ar-seg    { stroke: #9fd4e8; stroke-width: .6; stroke-opacity: .3; }
.ar-spine  { fill: none; stroke: var(--gold); stroke-width: 1.8; stroke-dasharray: 6 5; }
.ar-lock   { fill: var(--gold); }
.ar-seal line { stroke: var(--ok); stroke-width: 2.4; }
.ar-cap text { font: 500 13px 'Inter', sans-serif; letter-spacing: .42em; fill: var(--gold); text-anchor: middle; opacity: 0; }

.ar-car, .ar-sys-back, .ar-sys-front, .ar-cass-near, .ar-arch, .ar-panel, .ar-spine, .ar-lock,
.ar-seal, .ar-spin, .ar-headlight, .ar-tail, .ar-cap text {
  animation-duration: 17s;
  animation-iteration-count: infinite;
  animation-timing-function: linear;
}
.ar-arch, .ar-panel { transform-box: fill-box; transform-origin: bottom; }
.ar-cass-near { transform-box: fill-box; transform-origin: center; }

.ar-car        { animation-name: ar-drive; }
.ar-rail       { animation-name: ar-railout; animation-duration: 17s; animation-iteration-count: infinite; animation-timing-function: linear; transform-box: fill-box; transform-origin: center; }
.ar-sys-back, .ar-sys-front { animation-name: ar-drive; }
.ar-spin       { animation-name: ar-spin; }
.ar-headlight  { animation-name: ar-head; }
.ar-tail       { animation-name: ar-brake; }
.ar-cass-near  { animation-name: ar-cass; }
.ar-a          { animation-name: ar-arch-a; }
.ar-b          { animation-name: ar-arch-b; }
.ar-c          { animation-name: ar-arch-c; }
.ar-p1         { animation-name: ar-panel-1; }
.ar-p2         { animation-name: ar-panel-2; }
.ar-spine, .ar-lock { animation-name: ar-lockin; }
.ar-seal       { animation-name: ar-sealin; }

/* Nose points left, so leftward travel is FORWARD in both directions — it
   arrives forward and it leaves forward, never reversing. The per-keyframe
   easing is what stops it reading as a robot: it coasts in and settles, then
   pulls away rather than teleporting at a constant rate. */
@keyframes ar-drive {
  0%   { transform: translateX(820px); animation-timing-function: cubic-bezier(.16,.74,.3,1); }
  7%   { transform: translateX(4px);   animation-timing-function: cubic-bezier(.3,0,.5,1); }
  9%   { transform: translateX(0); }
  89%  { transform: translateX(0);     animation-timing-function: cubic-bezier(.6,0,.85,.4); }
  98%  { transform: translateX(-880px); }
  100% { transform: translateX(-880px); }
}
/* Rolling left is counter-clockwise, i.e. negative in SVG. Matched to the
   eased drive curve so the wheels stop turning exactly when the car stops. */
@keyframes ar-spin {
  0%   { transform: rotate(0deg); animation-timing-function: cubic-bezier(.16,.74,.3,1); }
  7%   { transform: rotate(-940deg); }
  9%   { transform: rotate(-950deg); }
  89%  { transform: rotate(-950deg); animation-timing-function: cubic-bezier(.6,0,.85,.4); }
  98%  { transform: rotate(-1900deg); }
  100% { transform: rotate(-1900deg); }
}
@keyframes ar-head {
  0%, 7% { opacity: 1; }
  11%    { opacity: .18; }
  88%    { opacity: .18; }
  91%    { opacity: 1; }
  100%   { opacity: 1; }
}
@keyframes ar-brake {
  0%    { opacity: .35; }
  4%    { opacity: 1; }
  9%    { opacity: 1; }
  12%   { opacity: .25; }
  88%   { opacity: .25; }
  92%   { opacity: 1; }
  100%  { opacity: .6; }
}

/* modules translate outward for clearance, and back in at the end */
@keyframes ar-cass {
  0%, 11%   { transform: translateY(0) scaleX(1); }
  17%       { transform: translateY(6px) scaleX(1.06); }
  86%       { transform: translateY(6px) scaleX(1.06); }
  90%, 100% { transform: translateY(0) scaleX(1); }
}

/* three arch groups, rising outer-first */
@keyframes ar-arch-a {
  0%, 18%   { transform: scaleY(.03); }
  32%       { transform: scaleY(1); }
  80%       { transform: scaleY(1); }
  86%, 100% { transform: scaleY(.03); }
}
@keyframes ar-arch-b {
  0%, 20%   { transform: scaleY(.03); }
  34%       { transform: scaleY(1); }
  79%       { transform: scaleY(1); }
  85%, 100% { transform: scaleY(.03); }
}
@keyframes ar-arch-c {
  0%, 22%   { transform: scaleY(.03); }
  36%       { transform: scaleY(1); }
  78%       { transform: scaleY(1); }
  84%, 100% { transform: scaleY(.03); }
}

/* panels close after the structure is locked */
@keyframes ar-panel-1 {
  0%, 37%   { transform: scaleY(0); opacity: 0; }
  40%       { opacity: 1; }
  51%       { transform: scaleY(1); opacity: 1; }
  73%       { transform: scaleY(1); opacity: 1; }
  78%       { transform: scaleY(0); opacity: 0; }
  100%      { transform: scaleY(0); opacity: 0; }
}
@keyframes ar-panel-2 {
  0%, 40%   { transform: scaleY(0); opacity: 0; }
  43%       { opacity: 1; }
  54%       { transform: scaleY(1); opacity: 1; }
  72%       { transform: scaleY(1); opacity: 1; }
  77%       { transform: scaleY(0); opacity: 0; }
  100%      { transform: scaleY(0); opacity: 0; }
}
@keyframes ar-lockin {
  0%, 30%   { opacity: 0; }
  36%       { opacity: 1; }
  80%       { opacity: 1; }
  84%, 100% { opacity: 0; }
}
@keyframes ar-sealin {
  0%, 55%   { opacity: 0; }
  59%       { opacity: 1; }
  72%       { opacity: 1; }
  75%, 100% { opacity: 0; }
}

/* captions ride the same clock */
.ar-cap-1 { animation-name: ar-cap-1; }
.ar-cap-2 { animation-name: ar-cap-2; }
.ar-cap-3 { animation-name: ar-cap-3; }
.ar-cap-4 { animation-name: ar-cap-4; }
.ar-cap-5 { animation-name: ar-cap-5; }
.ar-cap-6 { animation-name: ar-cap-6; }
@keyframes ar-cap-1 { 0%,1%{opacity:0} 4%{opacity:1} 9%{opacity:1} 12%,100%{opacity:0} }
@keyframes ar-cap-2 { 0%,12%{opacity:0} 15%{opacity:1} 18%{opacity:1} 21%,100%{opacity:0} }
@keyframes ar-cap-3 { 0%,21%{opacity:0} 24%{opacity:1} 33%{opacity:1} 36%,100%{opacity:0} }
@keyframes ar-cap-4 { 0%,36%{opacity:0} 39%{opacity:1} 51%{opacity:1} 55%,100%{opacity:0} }
@keyframes ar-cap-5 { 0%,55%{opacity:0} 59%{opacity:1} 71%{opacity:1} 74%,100%{opacity:0} }
@keyframes ar-cap-6 { 0%,74%{opacity:0} 78%{opacity:1} 87%{opacity:1} 90%,100%{opacity:0} }

/* Reduced motion: hold the finished state rather than animating to it. */
@media (prefers-reduced-motion: reduce) {
  .ar-car, .ar-sys-back, .ar-sys-front, .ar-cass-near, .ar-arch, .ar-panel, .ar-spine, .ar-lock,
  .ar-seal, .ar-spin, .ar-headlight, .ar-tail, .ar-cap text { animation: none; }
  .ar-cap text { opacity: 0; }
  .ar-cap-5 { opacity: 1; }
  .ar-seal, .ar-spine, .ar-lock { opacity: 1; }
}

.ar-stage {
  position: relative; background: var(--ink-2);
  border-block: 1px solid var(--line-soft); overflow: hidden;
}
.ar-stage .ar { max-width: 1500px; margin: 0 auto; }

/* ------------------------------------------- arrival legend + ownership */
.ar-legend {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 28px; flex-wrap: wrap; margin-top: -8px;
}
.ar-legend h2 { font-size: clamp(1.5rem, 2.6vw, 2.2rem); }
@media (max-width: 760px) { .ar-legend { align-items: flex-start; } }

.card-featured { border-color: var(--gold-dim); position: relative; }
.card-featured::before {
  content: ''; position: absolute; inset: -1px; border-radius: 2px;
  box-shadow: 0 0 0 1px var(--gold-dim), 0 24px 60px -30px rgba(224,189,136,.55);
  pointer-events: none;
}
.ticks { list-style: none; margin: 1.4em 0 0; padding: 0; display: grid; gap: 9px; }
.ticks li {
  position: relative; padding-left: 22px; font-size: .88rem; color: var(--alum);
}
.ticks li::before {
  content: ''; position: absolute; left: 0; top: .52em;
  width: 11px; height: 6px; border-left: 1.5px solid var(--gold);
  border-bottom: 1.5px solid var(--gold); transform: rotate(-45deg);
}

@keyframes ar-railout {
  0%, 11%   { transform: scaleX(.12); opacity: 0; }
  13%       { opacity: 1; }
  18%       { transform: scaleX(1); opacity: 1; }
  87%       { transform: scaleX(1); opacity: 1; }
  91%       { transform: scaleX(.12); opacity: 0; }
  100%      { transform: scaleX(.12); opacity: 0; }
}
/* ============================ arrival film — material detail ========== */
.ar-body     { stroke: #848c96; stroke-width: 1.1; }
.ar-glass    { stroke: #7d858f; stroke-width: 1; }
.ar-glasshl  { fill: #aebecb; opacity: .13; }
.ar-sheen    { fill: none; stroke: #e8edf2; stroke-width: 2; opacity: .5; }
.ar-sheen2   { fill: none; stroke: #aab3bd; stroke-width: 1.2; opacity: .3; }
.ar-intake   { fill: #0c0f13; stroke: #6f7883; stroke-width: 1; }
.ar-shut     { fill: none; stroke: #9aa3ad; stroke-width: .9; opacity: .5; }
.ar-mirror   { fill: #3c434b; stroke: #8b939d; stroke-width: 1; }
.ar-arch-trim{ fill: none; stroke: #0b0d10; stroke-width: 5; opacity: .85; }
.ar-reflect  { opacity: .5; }
.ar-collar   { fill: #9aa2ac; stroke: none !important; }
.ar-led      { fill: #e0bd88 !important; stroke: none !important; opacity: .75; }
.ar-spec     { fill: #ffffff; opacity: .07; }
.ar-lock circle:first-child { fill: var(--gold); }

.ar-call line   { stroke: var(--gold-dim); stroke-width: 1; stroke-dasharray: 3 3; }
.ar-call circle { fill: var(--gold); }
.ar-call text   { font: 500 12px 'Inter', sans-serif; letter-spacing: .2em; fill: var(--gold); }
.ar-call-sub    { font: 400 11px 'Inter', sans-serif !important; letter-spacing: .06em !important; fill: var(--alum-dim) !important; }
.ar-call { opacity: 0; animation-duration: 17s; animation-iteration-count: infinite; animation-timing-function: linear; }
.ar-c-extend  { animation-name: ar-cap-2; }
.ar-c-rise    { animation-name: ar-cap-3; }
.ar-c-enclose { animation-name: ar-cap-4; }
.ar-c-secure  { animation-name: ar-cap-5; }
@media (prefers-reduced-motion: reduce) {
  .ar-call { animation: none; }
  .ar-c-secure { opacity: 1; }
}

/* ================================ security perimeter, rebuilt ========= */
.bz { width: 100%; }
.bz-cone   { fill: url(#bzCone); }
.bz-ring   { fill: none; stroke-width: 1.2; }
.bz-1      { stroke: rgba(224,112,95,.65); stroke-dasharray: 3 4; }
.bz-2      { stroke: rgba(226,179,86,.5);  stroke-dasharray: 4 6; }
.bz-3      { stroke: rgba(159,212,232,.4); stroke-dasharray: 5 8; }
.bz-car    { fill: #1c2027; stroke: #59616b; stroke-width: 1.4; }
.bz-screen { fill: #0b0e12; stroke: #4a525b; stroke-width: 1; }
.bz-mod    { fill: #6b737d; stroke: #949ca6; stroke-width: 1; }
.bz-node rect { fill: #454d56; stroke: #99a1ab; stroke-width: 1; }
.bz-ping   { fill: none; stroke: var(--glass); stroke-width: 1.2;
             transform-box: fill-box; transform-origin: center;
             animation: bzping 3.6s ease-out infinite; }
@keyframes bzping { 0% { transform: scale(.5); opacity: .8; } 75%, 100% { transform: scale(4.2); opacity: 0; } }
.bz-person      { fill: var(--bad); }
.bz-person-halo { fill: none; stroke: var(--bad); stroke-width: 1.2;
                  transform-box: fill-box; transform-origin: center;
                  animation: bzping 2.4s ease-out infinite; }
.bz-walk { animation: bzwalk 11s cubic-bezier(.4,0,.5,1) infinite; }
@keyframes bzwalk {
  0%   { transform: translate(742px, 452px); }
  26%  { transform: translate(618px, 376px); }
  52%  { transform: translate(540px, 318px); }
  76%  { transform: translate(506px, 286px); }
  88%  { transform: translate(506px, 286px); }
  100% { transform: translate(742px, 452px); }
}
.bz-label line { stroke: var(--line); stroke-width: 1; }`n.bz-label circle { fill: var(--alum-faint); }
.bz-t    { font: 500 11px 'Inter', sans-serif; letter-spacing: .24em; fill: var(--alum); }
.bz-t-in { fill: var(--bad); }
.bz-sub  { font: 400 10.5px 'Inter', sans-serif; letter-spacing: .05em; fill: var(--alum-faint); }
.bz-foot { font: 400 10.5px 'Inter', sans-serif; letter-spacing: .12em; fill: var(--alum-faint); }
@media (prefers-reduced-motion: reduce) {
  .bz-ping, .bz-person-halo { animation: none; opacity: 0; }
  .bz-walk { animation: none; transform: translate(540px, 318px); }
}

/* ---------------- side elevation: shared geometry, shared materials ---- */
.bx-collar  { fill: #9aa2ac; stroke: none; }
.bx-railx   { fill: #3a4047; stroke: #6d757f; stroke-width: 1.2; }
.bx-seal-t  { font: 400 10px 'Inter', sans-serif; letter-spacing: .14em;
              fill: var(--ok); text-transform: uppercase; }
.bx-lock circle:first-child { fill: var(--gold); }
.bx-spine   { stroke-width: 2.2; }
/* The side elevation renders the canonical car, so it inherits the ar-* paint
   treatment. Only the wheels must not spin here — this drawing is stationary. */
.bx .ar-spin { animation: none; }
.bx .ar-shadow { opacity: .35; }

/* The shell's leading edge. Two jobs: make the top of the glass legible so
   the enclosure visibly reaches over the roof, and give the deployed state a
   hard line to read against the car behind it. */
.ar-lip, .bx-lip {
  fill: none; stroke: #d7eefb; stroke-width: 2.2; stroke-linecap: round;
  stroke-opacity: .85;
}
.bx-lip { stroke-width: 3; }
.ar-panel path:first-child, .bx-panel path:first-child { stroke: none; }

/* ------------------------------------------------------------- the app cue
   The vector person that stood here has been removed. A crude human figure
   beside photoreal renders is worse than no human: the eye lands on it and
   concludes the whole page is a sketch. What remains is the phone itself,
   which is the only part that carried meaning — the tap is what starts the
   sequence. A real person belongs in this frame as photography. */
.ar-phone-cue rect:first-child { fill: #14181d; stroke: #8b939d; stroke-width: 1.4; }
.ar-phone-screen { fill: #e0bd88 !important; stroke: none !important; }
.ar-tap circle { fill: none; stroke: var(--gold); stroke-width: 1.1; }

.ar-phone-cue, .ar-tap {
  animation-duration: 17s; animation-iteration-count: infinite;
  animation-timing-function: linear;
}
.ar-phone-cue { animation-name: ar-arrive-phone; opacity: 0; }
.ar-tap       { animation-name: ar-tap-ping; opacity: 0;
                transform-box: fill-box; transform-origin: center; }

/* Appears just after the car settles, stays through deployment, gone before
   the car pulls away. */
@keyframes ar-arrive-phone {
  0%, 8%    { opacity: 0; transform: translateY(10px); }
  12%       { opacity: 1; transform: translateY(0); }
  80%       { opacity: 1; transform: translateY(0); }
  86%       { opacity: 0; transform: translateY(8px); }
  100%      { opacity: 0; transform: translateY(8px); }
}
@keyframes ar-tap-ping {
  0%, 11%   { opacity: 0; transform: scale(.4); }
  13%       { opacity: .9; transform: scale(.7); }
  16%       { opacity: 0; transform: scale(1.5); }
  100%      { opacity: 0; transform: scale(1.5); }
}
@media (prefers-reduced-motion: reduce) {
  .ar-phone-cue { animation: none; opacity: 1; }
  .ar-tap { animation: none; opacity: 0; }
}

/* ------------- authored climate + dimensions drawings (replace concept art) */
.bf, .bd { width: 100%; }
.bf-ground, .bd-ground { stroke: var(--line); stroke-width: 1.2; }
.bf-arch rect:first-child, .bd-arch rect:first-child { stroke: #7b828b; stroke-width: 1; }
.bf-panel path, .bd-panel path { stroke: none; }
.bf-lip, .bd-lip { fill: none; stroke: #d7eefb; stroke-width: 2; stroke-opacity: .8; }
.bf-spine, .bd-spine { fill: none; stroke: var(--gold); stroke-width: 1.8; stroke-dasharray: 6 5; }
.bf-lock circle:first-child, .bd-lock circle:first-child { fill: var(--gold); }
.bf-seg, .bd-seg { stroke: #9fd4e8; stroke-width: .5; stroke-opacity: .28; }
.bf-collar, .bd-collar { fill: #9aa2ac; }

.bf-intake-port { fill: #16202b; stroke: #4f6070; stroke-width: 1; }
.bf-vent { fill: #16202b; stroke: #5a6b7a; stroke-width: 1; }
.bf-in path, .bf-gap path, .bf-out path {
  fill: none; stroke: var(--glass); stroke-width: 1.6;
  stroke-dasharray: 4 6; stroke-linecap: round;
  animation: bfflow 2.6s linear infinite;
}
.bf-out path { stroke: #e2b356; }
@keyframes bfflow { to { stroke-dashoffset: -40; } }
@media (prefers-reduced-motion: reduce) { .bf-in path, .bf-gap path, .bf-out path { animation: none; } }
.bf-note text { font: 500 11px 'Inter', sans-serif; letter-spacing: .18em; fill: var(--glass); }
.bf-sub { font: 400 10.5px 'Inter', sans-serif !important; letter-spacing: .04em !important; fill: var(--alum-faint) !important; }

.bd-stall { fill: rgba(224,189,136,.05); stroke: var(--gold-dim); stroke-width: 1; stroke-dasharray: 5 5; }
.bd-stall-t { font: 500 10px 'Inter', sans-serif; letter-spacing: .2em; fill: var(--gold-dim); }
.bd-dim line { stroke: var(--gold-dim); stroke-width: 1; }
.bd-leader { stroke-dasharray: 2 3; }
.bd-dim text { font: 500 11px 'Inter', sans-serif; letter-spacing: .14em; fill: var(--gold); }
.bd-note { font: 400 11px 'Inter', sans-serif; letter-spacing: .04em; fill: var(--alum-dim); }

/* ============================================================ animated diagrams
   Every illustration on the site loops rather than playing once, because most
   of them sit below the fold: a draw-in that fires at page load has finished
   before anyone scrolls to it. Looping costs nothing and means the drawing is
   always alive whenever you happen to look at it.

   All of this is CSS. The Content-Security-Policy is script-src 'self', so an
   inline animation driver would be blocked silently — the diagrams would just
   sit still and nothing would say why. */

/* ---- dimensions: the stall, the envelope, the clearance ---- */
.bd-stall { animation: bd-march 7s linear infinite; }
@keyframes bd-march { to { stroke-dashoffset: -40; } }

.bd-dim line:first-of-type {
  stroke-dasharray: 460;
  animation: bd-draw 6s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes bd-draw {
  0%       { stroke-dashoffset: 460; }
  28%,88%  { stroke-dashoffset: 0; }
  100%     { stroke-dashoffset: 0; }
}

/* the two end ticks land after the run-out reaches them */
.bd-dim line:nth-of-type(2), .bd-dim line:nth-of-type(3) {
  transform-box: fill-box; transform-origin: center;
  animation: bd-tick 6s ease-out infinite;
}
.bd-dim line:nth-of-type(3) { animation-delay: .35s; }
@keyframes bd-tick {
  0%,6%   { opacity: 0; transform: scaleY(.2); }
  30%     { opacity: 1; transform: scaleY(1); }
  88%     { opacity: 1; transform: scaleY(1); }
  100%    { opacity: 1; transform: scaleY(1); }
}

.bd-dim text { animation: bd-fade 6s ease-out infinite; }
@keyframes bd-fade { 0%,22% { opacity: 0; } 42%,100% { opacity: 1; } }

/* the clearance callout is the number people actually came for */
.bd-leader { animation: bd-leader 6s ease-in-out infinite; }
@keyframes bd-leader {
  0%,40%  { opacity: 0; stroke-dashoffset: 30; }
  58%     { opacity: 1; stroke-dashoffset: 0; }
  92%     { opacity: 1; }
  100%    { opacity: 1; }
}
.bd-note { animation: bd-fade 6s ease-out infinite; animation-delay: .5s; }

/* ---- platforms: each envelope wipes out to its real length ---- */
.bp-env, .bp-min {
  transform-box: fill-box; transform-origin: left center;
  animation: bp-grow 5.5s cubic-bezier(.22,1,.36,1) infinite;
}
.bp-min { animation-name: bp-grow-min; }
@keyframes bp-grow {
  0%      { transform: scaleX(0); opacity: .2; }
  34%,86% { transform: scaleX(1); opacity: 1; }
  100%    { transform: scaleX(1); opacity: 1; }
}
@keyframes bp-grow-min {
  0%,8%   { transform: scaleX(0); opacity: 0; }
  44%,86% { transform: scaleX(1); opacity: 1; }
  100%    { transform: scaleX(1); opacity: 1; }
}
.bp-row:nth-child(2) .bp-env, .bp-row:nth-child(2) .bp-min { animation-delay: .12s; }
.bp-row:nth-child(3) .bp-env, .bp-row:nth-child(3) .bp-min { animation-delay: .24s; }
.bp-row:nth-child(4) .bp-env, .bp-row:nth-child(4) .bp-min { animation-delay: .36s; }
.bp-row:nth-child(5) .bp-env, .bp-row:nth-child(5) .bp-min { animation-delay: .48s; }
.bp-row:nth-child(6) .bp-env, .bp-row:nth-child(6) .bp-min { animation-delay: .60s; }
.bp-dim { animation: bd-fade 5.5s ease-out infinite; }

/* ---- step boxes ---- */
/* The selected step charges its own rule. It reads as the stage running rather
   than as a tab that happens to be highlighted. */
.deploy-steps li { position: relative; overflow: hidden; }
.deploy-steps li:first-child::before {
  content: ""; position: absolute; left: -1px; top: 0; width: 2px; height: 100%;
  background: var(--gold);
  transform-origin: top; animation: ds-charge 2.6s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes ds-charge {
  0%      { transform: scaleY(0); opacity: 1; }
  55%     { transform: scaleY(1); opacity: 1; }
  100%    { transform: scaleY(1); opacity: .35; }
}

/* a slow gold wash across the active step, low enough not to fight the text */
.deploy-steps li:first-child::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(100deg, transparent 0%, rgba(224,189,136,.09) 45%,
                              rgba(224,189,136,.14) 52%, transparent 100%);
  background-size: 260% 100%;
  animation: ds-wash 5.2s ease-in-out infinite;
}
@keyframes ds-wash { 0% { background-position: 130% 0; } 60%,100% { background-position: -70% 0; } }

.deploy-steps li { position: relative; transition: padding-left .26s cubic-bezier(.22,1,.36,1); }


@media (prefers-reduced-motion: reduce) {
  .bd-stall, .bd-dim line, .bd-dim text, .bd-leader, .bd-note,
  .bp-env, .bp-min, .bp-dim,
  .deploy-steps li:first-child::before,
  .deploy-steps li:first-child::after {
    animation: none !important;
  }
  .bd-dim line, .bd-dim text, .bd-leader, .bd-note, .bp-dim { opacity: 1 !important; }
  .bd-dim line { stroke-dashoffset: 0 !important; }
  .bp-env, .bp-min { transform: none !important; opacity: 1 !important; }
  
}

/* ---- deployment scrubber: photoreal frames -------------------------------
   Replaces the vector stage drawing. site.js sets data-stage on `.bx`; these
   rules show the matching frame and hide the rest, so the existing scrubber
   logic drives real photography with no JS change. */
/* Frames are STACKED and cross-faded, never display:none'd.
   `display: none` did two damaging things. A lazy <img> inside a
   display:none subtree is never fetched at all, so on a real visit only
   frame 1 had downloaded - measured in the browser, naturalWidth 0 on frames
   2 to 5 - and every stage change hit an unloaded image and flashed an empty
   box. That is what "the animation does not work" looked like. It also made
   each change a hard cut, because there is nothing to transition between when
   the outgoing element stops existing.
   Stacking them absolutely keeps all five in the render tree, so all five
   load, and opacity gives a real continuous cross-dissolve. */
.bx-frames { position: relative; width: 100%; }
.bx-frame {
  margin: 0;
  position: absolute; inset: 0;
  opacity: 0;
  transition: opacity .55s ease;
  pointer-events: none;
}
/* The first frame also sets the box height, since the rest are absolute. */
.bx-frame[data-frame="1"] { position: relative; }
.bx-frame img { width: 100%; height: auto; display: block; border-radius: 2px; }
/* Enumerated past the current stage count on purpose. STAGES grew from five
   to six when the nose-and-tail close was added, and a list that stopped at
   five would have left the new last stage permanently at opacity 0 — a blank
   box at the end of the sequence, with nothing in the markup looking wrong. */
.bx-frames[data-stage="1"] .bx-frame[data-frame="1"],
.bx-frames[data-stage="2"] .bx-frame[data-frame="2"],
.bx-frames[data-stage="3"] .bx-frame[data-frame="3"],
.bx-frames[data-stage="4"] .bx-frame[data-frame="4"],
.bx-frames[data-stage="5"] .bx-frame[data-frame="5"],
.bx-frames[data-stage="6"] .bx-frame[data-frame="6"],
.bx-frames[data-stage="7"] .bx-frame[data-frame="7"],
.bx-frames[data-stage="8"] .bx-frame[data-frame="8"] { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .bx-frame { transition: none; } }

/* ---- arrival reel: the five real frames, replacing the vector film ------- */
/* One establishing frame, full width, NO horizontal scroll.
   The scrolling five-up reel this replaces had 10px of bottom padding and a
   visible scrollbar, so the scrollbar drew straight through the eyebrow line
   below it - the "text is cut off" report. It also parked stage 05 off the
   right edge and clipped the last caption mid-word. None of that is fixable
   by padding: a strip that scrolls sideways is the wrong component here,
   because the animated sequence lower down already tells the story bigger. */
/* THE HERO REEL — four photographs of one shot, cross-faded.
   Same car, same camera, same forecourt, four moments. A single still read as
   "a car with a cover on it"; this reads as the thing working. Stacked
   absolutely so all four occupy one box and all four LOAD — the old sequence
   used display:none, and a lazy image inside it never downloads, so every
   transition landed on an empty frame. */
/* No background image, no scrim: the reel IS the picture. */
.hero-reel-stage { min-height: 0; display: block; overflow: visible; }
.hero-reel-stage .hero-body { padding: 26px 0 56px; }
.hero-reel-wrap {
  margin: 0 0 30px; max-width: 1180px;
  border-radius: 2px; overflow: hidden;
}
/* The Pod film. 16:9 box reserved before the video loads, so nothing jumps;
   the poster (frame 1) fills it immediately. */
.hero-film { position: relative; width: 100%; aspect-ratio: 16 / 9; background: var(--ink-2); }
.hero-film-v { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* 2.1:1, not the plate's native 1.81:1. At native ratio a 1040px-wide reel
   stands 575px tall, and on a 652px viewport that pushed the car below the
   fold — the visible strip was sky. Cropping to a wider band keeps the whole
   frame above the fold and takes the crop out of the empty sky and the
   foreground paving rather than out of the car. */
.hero-reel { position: relative; width: 100%; aspect-ratio: 2.1 / 1; }
/* JS-DRIVEN, not four staggered CSS animations.
   The CSS version used four `animation-delay` values with negative offsets on
   one 16s keyframe. That is fragile exactly where it matters: iOS throttles
   or drops long-running CSS animations in Low Power Mode, and if the phone
   has Reduce Motion switched on — which is common — the whole thing stops
   dead and the hero becomes one still frame with no indication anything was
   meant to move.
   site.js now steps `data-on` on the container, so the transition is a plain
   opacity change with a known start and end. It pauses off-screen, and the
   no-JS state below still shows a real frame. */
.hero-reel-f {
  position: absolute; inset: 0; margin: 0;
  opacity: 0; transition: opacity .9s ease-in-out;
}
/* Without JS, the last frame is the one on show — a sealed car beats a blank
   box, and it is the single most representative plate. */
/* `!important` deliberately. The active-frame rule already outranks the base
   by specificity, and it still lost — the computed opacity stayed 0 on an
   element that `matches()` confirmed the selector. Rather than keep
   bisecting the cascade on a page I can only inspect through a flaky remote
   browser, this takes the question off the table: exactly one frame is lit,
   and nothing can quietly outrank it later. */
.hero-reel:not([data-on]) .hero-reel-f[data-f="3"] { opacity: 1 !important; }
.hero-reel[data-on="1"] .hero-reel-f[data-f="1"],
.hero-reel[data-on="2"] .hero-reel-f[data-f="2"],
.hero-reel[data-on="3"] .hero-reel-f[data-f="3"] { opacity: 1 !important; }
/* `cover` with the focal point ON THE CAR. The plates are 1.81:1 and the band
   is 2.1:1, so the crop is ~14% off the vertical — taken from sky at the top
   and wet paving at the bottom, not from either end of the car. That is the
   distinction that matters: cropping is only a fault when it cuts the
   subject, and `contain` here would letterbox instead and reintroduce the
   height problem it was meant to solve. */
.hero-reel-f img {
  width: 100%; height: 100%; display: block;
  object-fit: cover; object-position: 50% 58%;
}
@media (max-width: 760px) {
  .hero-reel-stage .hero-body { padding: 24px 0 40px; }
  .hero-reel-wrap { margin: 20px 0 24px; }
}
/* The caption sits over wet stone that is, in every plate, the brightest part
   of the frame. Gold type on a lit reflection is unreadable, so the band
   carries its own gradient. */
.hero-reel-caps {
  position: absolute; left: 0; right: 0; bottom: 0; height: 90px;
  background: linear-gradient(to top, rgba(7,8,10,.86) 0%, rgba(7,8,10,.45) 45%, rgba(7,8,10,0) 100%);
  pointer-events: none;
}
.hero-reel-cap {
  position: absolute; left: 20px; bottom: 16px; white-space: nowrap;
  font: 500 .72rem/1.4 ui-monospace, monospace; letter-spacing: .2em;
  text-transform: uppercase; color: var(--gold);
  opacity: 0; transition: opacity .5s ease;
}
.hero-reel:not([data-on]) .hero-reel-cap[data-f="3"] { opacity: 1 !important; }
.hero-reel[data-on="1"] .hero-reel-cap[data-f="1"],
.hero-reel[data-on="2"] .hero-reel-cap[data-f="2"],
.hero-reel[data-on="3"] .hero-reel-cap[data-f="3"] { opacity: 1 !important; }
@media (max-width: 700px) {
  .hero-reel-caps { height: 70px; }
  .hero-reel-cap { left: 14px; bottom: 12px; font-size: .62rem; letter-spacing: .14em; }
}
/* Four orphan `animation-delay` declarations lived here, left over from the
   CSS-animation version. Harmless with no animation-name, but they are
   exactly the kind of residue that makes a later reader think an animation
   is still driving this. */
/* Reduced motion removes the CROSS-FADE, not the sequence. Killing the whole
   thing left a phone with Reduce Motion switched on — which is common —
   looking at one still frame of a product whose entire pitch is that it
   moves. The frames still change; they just cut instead of dissolving. */
@media (prefers-reduced-motion: reduce) {
  .hero-reel-f, .hero-reel-cap { transition: none; }
}

/* THE HERO IS THE FILM.
   The photograph behind it drops to an atmosphere plate — it sets the place
   and the light, and the moving drawing on top of it is the subject. The
   scrim goes much heavier because the film needs a quiet ground to read
   against, which a full-strength photograph is not. */
.hero-film { min-height: 0; align-items: stretch; }
.hero-film .hero-media img { opacity: .34; }
.hero-film .hero-media::after {
  background:
    linear-gradient(to top, rgba(7,8,10,.97) 0%, rgba(7,8,10,.72) 46%, rgba(7,8,10,.62) 100%);
}
.hero-film .hero-body { padding: 96px 0 56px; }
.hero-film-stage { margin: 26px 0 30px; max-width: 1040px; }
.hero-film-stage svg { width: 100%; height: auto; display: block; }
@media (max-width: 760px) {
  .hero-film .hero-body { padding: 26px 0 38px; }
  .hero-film-stage { margin: 18px 0 22px; }
}

/* The six stages as type, for the page that already shows the film. */
.stage-list { list-style: none; margin: 0; padding: 0; }
.stage-list li {
  display: grid; grid-template-columns: 44px 1fr auto; gap: 18px;
  align-items: start;
  padding: 22px 0; border-top: 1px solid var(--line-soft);
}
.stage-list li:last-child { border-bottom: 1px solid var(--line-soft); }
.stage-list b { color: var(--gold); font-weight: 500; font-size: .95rem; letter-spacing: .1em; }
.stage-list h3 { margin: 0 0 .4em; font-size: 1.05rem; }
.stage-list p { margin: 0; color: var(--alum-dim); }
.stage-t { color: var(--alum-faint); font-size: .78rem; white-space: nowrap; }
@media (max-width: 700px) {
  .stage-list li { grid-template-columns: 34px 1fr; }
  .stage-t { grid-column: 2; margin-top: .4em; }
}

/* The deployment film, directly under the headline. It is the first thing on
   the page that moves, and it carries the whole product story, so it gets the
   full content width and room to breathe rather than being a card. */
.film { margin: 40px 0 0; }
.film svg { width: 100%; height: auto; display: block; }
.film-note {
  margin: 14px 0 0; text-align: center;
  letter-spacing: .04em; color: var(--alum-faint);
}
@media (max-width: 700px) { .film { margin-top: 26px; } }

.ar-hero { margin: 44px 0 0; }
.ar-hero img { width: 100%; height: auto; border-radius: 2px; display: block; }
.ar-hero figcaption {
  margin-top: 12px; font-size: .72rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--alum-dim);
  display: flex; gap: 16px; align-items: baseline; flex-wrap: wrap;
}
.ar-hero figcaption b { color: var(--gold); font-weight: 500; margin-right: .5em; }
/* `margin-left:auto` on a flex child with no wrap was what clipped the time
   value on a narrow column. Pushing right is a nicety; showing the whole
   string is not. */
.ar-hero-time { color: var(--alum-faint); margin-left: auto; }
@media (max-width: 700px) { .ar-hero-time { margin-left: 0; } }

/* ---- brand lockup: mark + wordmark ---------------------------------------
   The mark is inline SVG using currentColor, so it inherits the header text
   colour and recolours for free on a light background. A raster logo could do
   none of that. */
.brand { display: inline-flex; align-items: center; gap: 11px; }
.brandmark { width: 26px; height: 24px; flex: none; color: var(--gold); display: block; }
.brand span { display: inline-block; }
@media (max-width: 420px) { .brandmark { width: 22px; height: 20px; } .brand { gap: 8px; } }

/* A full-width deployment frame on pages that previously had no photography. */
.wide-figure { margin: 0 0 2.6rem; }
.wide-figure img { width: 100%; height: auto; border-radius: 2px; }
.figure figcaption { margin-top: 10px; font-size: .78rem; color: var(--alum-faint); line-height: 1.55; }

/* ---- technical silhouette ------------------------------------------------
   Overrides the old shaded-car rules. The car in these diagrams is now a flat
   silhouette: one tone, one outline, no gradients and no fake reflections.
   It is a drawing and it should look like one, because it sits beside real
   photography and any attempt at realism loses that comparison. */
.ar-body  { fill: #2a2f36 !important; stroke: #6f7883 !important; stroke-width: 1.4 !important; }
.ar-glass { fill: #171b21 !important; stroke: #6f7883 !important; stroke-width: 1.2 !important; opacity: 1 !important; }
.ar-wheel circle { fill: #14171c; stroke: #6f7883; stroke-width: 1.4; }
.ar-wheel .ar-hub { fill: #2a2f36; stroke: #6f7883; stroke-width: 1.2; }

/* The brand lockup added width to the header and pushed the nav into wrapping
   ("HOW IT WORKS" and "SIGN IN" both broke onto two lines). The wordmark was
   tracked at .3em, which suited a bare text logo with nothing beside it. */
.brand { letter-spacing: .16em; font-size: .98rem; }
.site-head .bar { gap: 20px; }
.nav { gap: 20px; }
.nav a:not(.btn) { white-space: nowrap; }
.nav-tools .btn { white-space: nowrap; }
@media (max-width: 1100px) { .nav { gap: 15px; } .nav a:not(.btn) { font-size: .73rem; letter-spacing: .08em; } }

/* Deployment frames were rendering at full container width, which made a
   460x350 crop fill most of a 1500px viewport and pushed the caption off
   screen. Cap them. */
/* DELETED: `.bx-frame img, .ar-reel-frame img { max-height: 420px;
   object-fit: cover }`. Both classes were removed when the photo sequence
   became the film, so the rule was dead — but it is exactly the shape that
   crops an image in half (a hard max-height plus `cover`), and leaving a
   loaded gun like that in the stylesheet is how the next figure that happens
   to pick up one of those class names ends up sliced. */
.bx-frames { max-width: 900px; }

/* ---- telescope detail ----------------------------------------------------
   Shows the two things the photography keeps getting wrong: the posts come
   OUT OF the beam, and the beam hangs clear of the road. Animated so the
   telescoping is visible rather than asserted. */
.ts { width: 100%; height: auto; }
.ts-ground { stroke: var(--line); stroke-width: 1.4; }
.ts-wheel { fill: #14171c; stroke: #6f7883; stroke-width: 1.4; }
.ts-hub   { fill: #2a2f36; stroke: #6f7883; stroke-width: 1.2; }
.ts-body  { fill: #2a2f36; stroke: #6f7883; stroke-width: 1.4; }
.ts-beam  { fill: url(#tsAlu), #9aa2ac; fill: #9aa2ac; stroke: #cfd6de; stroke-width: 1.4; }
.ts-led   { stroke: var(--gold); stroke-width: 2.6; stroke-linecap: round; opacity: .9; }
.ts-slot  { fill: #14171c; stroke: #6f7883; stroke-width: .8; }
.ts-bolt  { fill: #6f7883; }
.ts-seg rect { fill: #3a4149; stroke: #aab3bd; stroke-width: 1.2; }
.ts-collar { fill: #6f7883 !important; }

.ts-seg { transform-box: fill-box; transform-origin: bottom center; }
.ts-seg-1 { animation: ts-rise 6s cubic-bezier(.3,0,.2,1) infinite; }
.ts-seg-2 { animation: ts-rise 6s cubic-bezier(.3,0,.2,1) infinite; animation-delay: .35s; }
.ts-seg-3 { animation: ts-rise 6s cubic-bezier(.3,0,.2,1) infinite; animation-delay: .7s; }
@keyframes ts-rise {
  0%, 6%   { transform: scaleY(0); opacity: 0; }
  34%      { transform: scaleY(1); opacity: 1; }
  82%      { transform: scaleY(1); opacity: 1; }
  96%,100% { transform: scaleY(0); opacity: 0; }
}

.ts-gap line { stroke: var(--gold-dim); stroke-width: 1; }
.ts-gap text { font: 500 10px 'Inter', sans-serif; letter-spacing: .16em; fill: var(--gold); }
.ts-note text { font: 500 11px 'Inter', sans-serif; letter-spacing: .14em; fill: var(--white); }
.ts-sub { font: 400 10px 'Inter', sans-serif !important; letter-spacing: .04em !important; fill: var(--alum-faint) !important; }
.ts-leader { stroke: var(--line); stroke-width: 1; stroke-dasharray: 2 3; }
@media (prefers-reduced-motion: reduce) {
  .ts-seg { animation: none !important; transform: scaleY(1) !important; opacity: 1 !important; }
}

/* ---- airflow diagram: make the enclosure read as enclosed ----------------
   The shell was a dashed crown line with nothing under it, so the drawing
   never looked covered. The glaze fills the enclosed volume; the car sits
   inside it and is lightened so it reads against the dark ground. */
.bf-glaze { fill: rgba(159,212,232,.10); stroke: rgba(159,212,232,.42); stroke-width: 1.4; }
.bf .ar-body  { fill: #39414a !important; stroke: #98a2ae !important; }
.bf .ar-glass { fill: #202730 !important; stroke: #98a2ae !important; }
.bf .ar-wheel circle { stroke: #98a2ae; }
.bf-beam { fill: #9aa2ac; stroke: #d3dae2; stroke-width: 1.3; }
.bf-beam-led { stroke: var(--gold); stroke-width: 2.4; stroke-linecap: round; opacity: .85; }

/* All diagram airflow animates on its own - no click, no hover. */
.bf-in path, .bf-gap path, .bf-out path { stroke-dasharray: 7 9; animation: bfflow 2.6s linear infinite; }
.bf-gap path { animation-duration: 3.4s; }
.bf-out path { animation-duration: 2s; }
@media (prefers-reduced-motion: reduce) {
  .bf-in path, .bf-gap path, .bf-out path { animation: none; }
}

/* Diagrams must not run away with a section. A viewBox-only SVG in a wide
   container will scale to whatever width it is given; /how-it-works had two
   of them in one section and that section alone was over 5,000 px tall. */
.card > svg, .figure > svg { max-height: 460px; width: 100%; height: auto; display: block; margin: 0 auto; }
.ts { max-height: 400px; }

/* Investor-facing hero: the headline was landing on the car's nose, so both
   the type and the subject got harder to read. Give the text a column on the
   left and push the image's focal point right, instead of stacking them. */
.hero-body .wrap { max-width: var(--maxw); }
.hero h1, .hero .lede, .hero .eyebrow, .hero .btn-row, .hero-price { max-width: 46ch; }
.hero-media img { object-position: 62% 48%; }
.hero-media::after {
  background:
    linear-gradient(to right, rgba(7,8,10,.90) 0%, rgba(7,8,10,.68) 34%, rgba(7,8,10,.12) 66%, rgba(7,8,10,0) 100%),
    linear-gradient(to top, rgba(7,8,10,.88) 0%, rgba(7,8,10,.24) 40%, rgba(7,8,10,0) 66%);
}
@media (max-width: 900px) {
  .hero h1, .hero .lede, .hero .eyebrow, .hero .btn-row, .hero-price { max-width: none; }
  .hero-media::after { background: linear-gradient(to top, rgba(7,8,10,.94) 0%, rgba(7,8,10,.58) 52%, rgba(7,8,10,.22) 100%); }
}

/* ON A PHONE THE HERO STOPS BEING AN OVERLAY.
   `object-fit: cover` on a box that is min(78vh, 700px) tall means a 1600x823
   landscape photograph is sliced down to a narrow vertical strip — you see a
   sixth of the car and the rest is cropped away. Reported as "on mobile the
   first image is half there", and that is exactly what it is.
   A portrait viewport cannot show a wide photograph AND hold text over it.
   So below 760px the picture gets its own full-width frame at its real
   proportions, and the headline sits underneath it where there is room to
   read. No crop, no scrim fighting the subject. */
@media (max-width: 760px) {
  .hero {
    display: block;
    min-height: 0;
    overflow: visible;
  }
  .hero-media {
    position: relative;
    inset: auto;
    aspect-ratio: 16 / 9;
    width: 100%;
  }
  .hero-media img {
    height: 100%;
    object-position: 50% 50%;
  }
  /* The scrim was there to protect text that is no longer on top of the
     image. Left in place it just greys the photograph out. */
  .hero-media::after {
    background: linear-gradient(to top, rgba(7,8,10,.55) 0%, rgba(7,8,10,0) 42%);
  }
  .hero-body { padding: 26px 0 40px; }
}

/* ---------------------------------------------------------------------------
   Sales pitch (rev 8, 2026-09-23): stats, venue scenario boards, app phones,
   climate-in-action diagram, seal sequence, venue calculator, money flow.
   --------------------------------------------------------------------------- */
.h3like { font: var(--t-h3); color: var(--white); margin: 0 0 .4em; }

.stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; }
.stat { border: 1px solid var(--line); border-radius: 14px; padding: 26px 22px; background: var(--ink-2); }
.stat b { display: block; font: 300 clamp(2.2rem, 4.4vw, 3.4rem)/1 'Inter', system-ui, sans-serif; color: var(--gold); letter-spacing: -.01em; }
.stat span { display: block; margin-top: 12px; color: var(--alum); font-size: .95rem; line-height: 1.45; }
@media (max-width: 900px) { .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .stats { grid-template-columns: 1fr; } }

.scene { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); gap: clamp(24px, 4vw, 56px); align-items: start; padding: clamp(28px, 4vw, 48px) 0; border-top: 1px solid var(--line-soft); }
.scene:first-child { border-top: 0; padding-top: 0; }
.scene-h { font: 300 clamp(1.4rem, 2.4vw, 2rem)/1.2 'Inter', system-ui, sans-serif; color: var(--white); }
.scene.flip > .stack { order: 2; }
@media (max-width: 900px) { .scene { grid-template-columns: 1fr; } .scene.flip > .stack { order: 0; } }

.board { border: 1px solid var(--line); border-radius: 14px; background: var(--ink-2); overflow: hidden; }
.board-head { display: flex; justify-content: space-between; gap: 12px; padding: 14px 18px; border-bottom: 1px solid var(--line); color: var(--gold); font-size: .78rem; letter-spacing: .18em; text-transform: uppercase; }
.board .spec { margin: 0; }
.board-t th, .board-t td { white-space: nowrap; }
.board-foot { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--line); }
.board-foot div { padding: 16px 18px; }
.board-foot div + div { border-left: 1px solid var(--line); }
.board-foot b { display: block; color: var(--white); font-size: 1.35rem; font-weight: 500; }
.board-foot span { display: block; color: var(--alum-dim); font-size: .8rem; margin-top: 4px; }
@media (max-width: 520px) { .board-foot { grid-template-columns: 1fr; } .board-foot div + div { border-left: 0; border-top: 1px solid var(--line); } }

table.money thead th { color: var(--alum-dim); font-weight: 500; font-size: .8rem; letter-spacing: .08em; text-transform: uppercase; }
table.money td b { color: var(--gold); font-weight: 500; }

/* phones */
.phones { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 22px; }
.phones.two { grid-template-columns: repeat(2, minmax(0, 290px)); }
@media (max-width: 1100px) { .phones { grid-template-columns: repeat(2, minmax(0, 290px)); } }
@media (max-width: 620px) { .phones, .phones.two { grid-template-columns: minmax(0, 320px); justify-content: center; } }
.phone { margin: 0; }
.phone-frame { border: 1px solid #3a3f47; border-radius: 34px; padding: 10px; background: linear-gradient(160deg, #1b1e24, #0b0c0f); box-shadow: 0 30px 60px -30px rgba(0,0,0,.8), inset 0 0 0 1px rgba(255,255,255,.04); }
.phone-screen { border-radius: 26px; background: #0a0c10; min-height: 470px; padding: 18px 16px 16px; display: flex; flex-direction: column; gap: 8px; overflow: hidden; }
.ph-top { display: flex; justify-content: space-between; font-size: .68rem; letter-spacing: .2em; text-transform: uppercase; color: var(--alum-dim); padding-bottom: 6px; }
.ph-top span:last-child { color: var(--gold); }
.ph-title { color: var(--white); font-size: 1.15rem; font-weight: 500; margin: 2px 0 6px; }
.ph-row { display: flex; justify-content: space-between; gap: 10px; padding: 8px 10px; background: #12151b; border-radius: 10px; font-size: .84rem; }
.ph-row span { color: var(--alum-dim); }
.ph-row b { color: var(--white); font-weight: 500; text-align: right; }
.ph-row.ph-big b { color: var(--gold); font-size: 1rem; }
.ph-note { color: var(--alum-dim); font-size: .78rem; margin: 2px 2px 0; }
.ph-cta { margin-top: auto; text-align: center; padding: 12px; border-radius: 12px; background: var(--gold); color: #1a1408; font-weight: 600; font-size: .9rem; }
.ph-tick { display: flex; align-items: center; gap: 10px; font-size: .84rem; color: var(--alum); padding: 5px 2px; }
.ph-tick i { width: 16px; height: 16px; border-radius: 50%; border: 2px solid var(--alum-faint); flex: none; }
.ph-tick.done i { background: var(--ok); border-color: var(--ok); }
.ph-tick.now i { border-color: var(--gold); border-top-color: transparent; animation: ph-spin 1s linear infinite; }
.ph-tick.now { color: var(--white); }
.ph-tick.next { color: var(--alum-faint); }
@keyframes ph-spin { to { transform: rotate(360deg); } }
.ph-cam { position: relative; height: 130px; border-radius: 12px; background: url('/img/roll-4-560.webp') center/cover, #111; }
.ph-cam span { position: absolute; left: 10px; top: 10px; background: var(--bad); color: #fff; font-size: .62rem; font-weight: 600; letter-spacing: .14em; padding: 3px 7px; border-radius: 6px; }
.ph-stick { height: 150px; border-radius: 50%; width: 150px; margin: 6px auto; border: 1px solid var(--line); background: radial-gradient(circle, #151922 60%, #0d1016); position: relative; }
.ph-stick i { position: absolute; width: 54px; height: 54px; left: 48px; top: 30px; border-radius: 50%; background: var(--gold); box-shadow: 0 0 24px rgba(224,189,136,.4); animation: ph-nudge 2.4s ease-in-out infinite; }
@keyframes ph-nudge { 50% { transform: translateY(-14px); } }
.ph-lanes { height: 120px; border-radius: 12px; background: #0e1116; display: flex; justify-content: center; align-items: stretch; gap: 26px; padding: 10px; }
.ph-lanes i { width: 3px; background: #3dff7a; box-shadow: 0 0 10px #3dff7a; border-radius: 2px; }
.ph-lanes b { width: 70px; border-radius: 16px 16px 8px 8px; background: linear-gradient(#b3262b, #6d1316); }

/* seal sequence */
.seal { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.seal li { display: flex; align-items: center; gap: 8px; padding: 9px 14px; border: 1px solid var(--line); border-radius: 999px; font-size: .88rem; color: var(--alum); animation: seal-on 9s infinite; }
.seal li i { width: 10px; height: 10px; border-radius: 50%; background: var(--alum-faint); animation: seal-dot 9s infinite; animation-delay: inherit; }
@keyframes seal-on { 0%, 8% { color: var(--alum-faint); border-color: var(--line); } 12%, 92% { color: var(--white); border-color: var(--gold-dim); } 100% { color: var(--alum-faint); } }
@keyframes seal-dot { 0%, 8% { background: var(--alum-faint); } 12%, 92% { background: var(--ok); } 100% { background: var(--alum-faint); } }

/* climate diagram */
.climate { margin: 0; }
.climate svg { width: 100%; height: auto; display: block; background: var(--ink-2); border: 1px solid var(--line); border-radius: 14px; }
.climate figcaption { margin-top: 12px; color: var(--alum-dim); font-size: .9rem; }
.cv-ground { stroke: var(--line); stroke-width: 2; }
.cv-box { fill: #5a4630; stroke: #8a6c48; }
.cv-brand { fill: var(--white); font-size: 9px; letter-spacing: .12em; }
.cv-shell { fill: rgba(159,212,232,.07); stroke: rgba(159,212,232,.6); stroke-width: 3; }
.cv-car { fill: #2a2f38; stroke: #4a515c; }
.cv-wheel { fill: #111; stroke: #555; stroke-width: 3; }
.cv-fan circle { fill: #221b12; stroke: #8a6c48; }
.cv-blades { fill: var(--alum); transform-box: fill-box; transform-origin: center; animation: cv-spin .8s linear infinite; }
@keyframes cv-spin { to { transform: rotate(360deg); } }
.cv-air { fill: none; stroke-width: 3.2; stroke-linecap: round; stroke-dasharray: 10 14; animation: cv-flow 1.2s linear infinite; }
.cv-ret { stroke: var(--alum-dim); }
.cv-out { stroke: #e0705f; }
@keyframes cv-flow { from { stroke-dashoffset: 48; } to { stroke-dashoffset: 0; } }
.cv-vent { fill: var(--gold); }
.cv-lock rect { fill: var(--ok); }
.cv-lock path { fill: none; stroke: var(--ok); stroke-width: 2.4; }
.cv-l { fill: var(--alum-dim); font-size: 12px; }
.cv-read rect { fill: rgba(7,8,10,.85); stroke: var(--line); }
.cv-read text { fill: var(--white); font-size: 15px; font-weight: 500; }
.cv-read .cv-sub { fill: var(--gold); font-size: 10px; letter-spacing: .08em; font-weight: 400; }
.cv-sun circle { fill: #f2c46b; filter: drop-shadow(0 0 12px #f2c46b); }
.cv-snow { fill: #e8f2ff; animation: cv-fall 5s linear infinite; }
@keyframes cv-fall { to { transform: translateY(300px); } }

/* venue calculator */
.calc { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); gap: clamp(20px, 4vw, 48px); border: 1px solid var(--line); border-radius: 14px; padding: clamp(20px, 3vw, 34px); background: var(--ink-2); }
.calc-in { display: grid; gap: 22px; align-content: start; }
.calc-in label { display: grid; gap: 10px; color: var(--alum); }
.calc-in output { color: var(--gold); font-weight: 600; float: right; }
.calc-in input[type=range] { width: 100%; accent-color: var(--gold); }
.calc-out { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px; }
.calc-out div { border: 1px solid var(--line); border-radius: 12px; padding: 18px; }
.calc-out b { display: block; font: 300 clamp(1.6rem, 3vw, 2.4rem)/1 'Inter', system-ui, sans-serif; color: var(--gold); }
.calc-out span { display: block; margin-top: 8px; color: var(--alum-dim); font-size: .85rem; }
@media (max-width: 800px) { .calc { grid-template-columns: 1fr; } }
@media (max-width: 420px) { .calc-out { grid-template-columns: 1fr; } }

/* money flow */
.flow { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 18px; align-items: stretch; }
.flow-in, .flow-out div { border: 1px solid var(--line); border-radius: 14px; padding: 22px; background: var(--ink-2); }
.flow-in { border-color: var(--gold-dim); }
.flow-out { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
.flow b { display: block; font: 300 clamp(1.8rem, 3.4vw, 2.8rem)/1 'Inter', system-ui, sans-serif; color: var(--gold); }
.flow span { display: block; margin-top: 10px; color: var(--alum); font-size: .9rem; }
@media (max-width: 800px) { .flow, .flow-out { grid-template-columns: 1fr; } }

@media (prefers-reduced-motion: reduce) {
  .cv-air, .cv-blades, .cv-snow, .seal li, .seal li i, .ph-stick i, .ph-tick.now i { animation: none; }
  .seal li { color: var(--white); } .seal li i { background: var(--ok); }
}

/* venue scene sequence: four frames under the text and the board */
.scene-seq { grid-column: 1 / -1; margin-top: 8px; }
.scene-seq .figure figcaption { font-size: .8rem; }
@media (max-width: 1000px) { .scene-seq.g4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 520px) { .scene-seq.g4 { grid-template-columns: 1fr; } }
/* venue showcase film (tools/build-venue-film.mjs) */
.venue-film { margin: 0 0 clamp(28px, 4vw, 48px); border: 1px solid var(--line); border-radius: 14px; overflow: hidden; background: #000; }
.venue-film-v { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; }