*{box-sizing:border-box;margin:0;padding:0}
/* Colour tokens. The four "content" tokens below are pinned to WCAG AA against every
   background the site actually uses (--paper #FBF8F1, --cream #F5F0E5, --mist #FAF5EA and
   white); see docs/stress/04 §1.1 and 03 §H5/M1. Only lightness/alpha was changed — hues
   are the original navy/teal/gold. Recompute with tools-free python if you touch them:
     --faint  rgba(11,43,60,.66) → 4.71:1 on cream (worst case), was .42 → 2.44:1
     --teal-deep #0E7380         → 4.88:1 on cream,              was #0F7A88 → 4.44:1
     --price-accent #856502      → 4.79:1 on cream, was var(--mustard) #E8C547 → 1.48:1.
                                   4.5 (not 3.0) because the "$" in `.big sup` is .32em of
                                   a font-size that clamps to 72px on phones = 23.04px,
                                   i.e. just UNDER the 24px large-text exemption. Picking a
                                   3:1 gold would only pass on desktop.
   --mustard itself is unchanged: it is only used on navy now (8.78:1) and as the focus
   ring colour for dark sections. --focus is redefined per-section in responsive.css §2.

   --rule-ui (A-02, SC 1.4.11): --rule rgba(11,43,60,.14) composites to 1.31:1 on --paper
   and 1.39:1 on #fff, but an EMPTY input's border is the only thing that shows where the
   field begins and ends, and 1.4.11 wants 3:1 for that. .55 (not the .50 the audit
   suggested) because .50 lands on exactly 3.00:1 against --cream — no margin at all, and
   the calculator sits on cream. Measured composited: white 3.56 / paper 3.50 / cream 3.43
   / mist 3.48. --rule itself is UNCHANGED and stays on decorative hairlines and
   separators, which 1.4.11 exempts. */
:root{color-scheme:light;--navy:#0B2B3C;--navy-deep:#061822;--teal:#1BA4B6;--teal-deep:#0E7380;--cream:#F5F0E5;--mist:#FAF5EA;--paper:#FBF8F1;--mustard:#E8C547;--ink:#0B2B3C;--dim:rgba(11,43,60,.68);--faint:rgba(11,43,60,.66);--rule:rgba(11,43,60,.14);--rule-soft:rgba(11,43,60,.08);--rule-ui:rgba(11,43,60,.55);--accent:var(--teal);--price-accent:#856502;--focus:var(--teal-deep);--maxw:1280px;--pad:clamp(20px,4vw,56px);--sans:'Instrument Sans','Instrument Sans Fallback',system-ui,sans-serif;--serif:'Instrument Serif','Instrument Serif Fallback',Georgia,serif;--display:var(--serif)}
html[data-type="grotesk"]{--display:var(--sans)}
html[data-type="grotesk"] .em{font-family:var(--sans);font-style:normal;font-weight:500;letter-spacing:-.04em}
/* bare --teal is 2.63:1 on cream — the teal price variant must use the AA-safe deep teal */
html[data-price="teal"]{--price-accent:var(--teal-deep)}
html{scroll-behavior:smooth}
/* A-03 / SC 1.4.12: `overflow-x:hidden` USED TO BE HERE and it is deliberately gone.
   On <body> that value propagates to the viewport, so the page could not be scrolled
   horizontally by any means — verified: with the WCAG text-spacing override at 375px,
   /es/fleet had documentElement.scrollWidth 422 but scrollLeft stayed pinned at 0 after
   both `el.scrollLeft=200` and `window.scrollTo(200,0)`. The overflowing half of the <h1>
   was clipped and UNREACHABLE, which is a loss of content, not just a missing scrollbar.
   The real causes are fixed below (heading/long-token wrapping) and in the nav row; the
   decorative bleeds that this rule used to swallow are each clipped at their own section
   instead — .hero{overflow-x:clip} (mascot/sky), .cta{overflow:hidden} (van),
   .keyless{overflow:hidden} (phone glow). Re-verified with no net at all: 216 page/width
   combinations (9 page types x EN/FR/ES x 320/375/768/1100/1101/1280/1920/2560) and 126
   more under the 1.4.12 override all report scrollWidth === clientWidth.
   DO NOT reinstate it to paper over a new overflow — fix the element that overflows. */
body{font-family:var(--sans);background:var(--paper);color:var(--ink);-webkit-font-smoothing:antialiased;font-size:16px;line-height:1.5;text-wrap:pretty}
a{color:var(--ink);text-decoration:none}a:hover{color:var(--teal-deep)}
/* A-03 / SC 1.4.12 — display type must be able to break.
   `overflow-wrap:anywhere`, NOT `break-word`: only `anywhere` counts the break opportunity
   when the browser computes min-content, and min-content is what sizes the grid track the
   heading sits in. Measured on /es/fleet at 375px under the text-spacing override, <h1>
   "Disponibilidad,": min-content 401.8px -> break-word 115.6px -> anywhere 40.1px; the page
   still overflowed by 41px with break-word at 320px and is clean with anywhere. Rendering
   at normal spacing is identical either way — both only break a word that cannot fit.
   `hyphens:auto` gives real hyphenated breaks instead of mid-word chops; every page already
   carries a correct `lang`, so FR/ES hyphenate properly. */
h1,h2,h3,.kicker,.lead,blockquote,.stat b,.big,.row .name,.ledger-note,.disclaimer{
  overflow-wrap:anywhere;word-break:normal;hyphens:manual
}
/* hyphens stays MANUAL on purpose: `auto` hyphenated ordinary words at normal spacing
   ("not ear-ly, right on time" in the home lead). `overflow-wrap:anywhere` alone satisfies
   1.4.12 — it only breaks a word that cannot fit. */
/* Long unbreakable tokens in running text — mostly e-mail addresses — are the other thing
   that forces a track past the viewport under the 1.4.12 override (measured: the
   `investors@aperiomobility.com` .arrow link pushed /contact 10px over at 320px). */
.arrow{overflow-wrap:anywhere}
::selection{background:var(--navy);color:var(--cream)}
img{display:block;max-width:100%}
.wrap{max-width:var(--maxw);margin:0 auto;padding-inline:var(--pad)}
.em{font-family:var(--display);font-style:italic;font-weight:400;letter-spacing:-.01em}
.kicker{font-size:12px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--dim)}
.kicker b{color:var(--teal-deep);font-weight:600}
h2{font-weight:500;font-size:clamp(34px,4.2vw,58px);line-height:1.02;letter-spacing:-.035em;text-wrap:balance}
h3{font-weight:500;font-size:22px;letter-spacing:-.02em;line-height:1.2}
.lead{font-size:clamp(17px,1.35vw,20px);line-height:1.5;color:var(--dim);max-width:52ch}
.btn{display:inline-flex;align-items:center;gap:10px;height:48px;padding:0 22px;border-radius:6px;font:inherit;font-weight:600;font-size:15px;border:1px solid transparent;cursor:pointer;transition:background .2s,color .2s,border-color .2s,transform .2s;white-space:nowrap}
.btn:active{transform:translateY(1px)}
.btn-navy{background:var(--navy);color:var(--cream)}.btn-navy:hover{background:#123A4E;color:var(--cream)}
.btn-cream{background:var(--cream);color:var(--navy)}.btn-cream:hover{background:#fff;color:var(--navy)}
.btn-line{background:transparent;color:var(--ink);border-color:var(--rule)}.btn-line:hover{border-color:var(--ink);color:var(--ink)}
.arrow{display:inline-flex;align-items:center;gap:8px;font-weight:600;font-size:15px;color:var(--ink)}
.arrow svg{transition:transform .25s}.arrow:hover svg{transform:translateX(4px)}
.arrow:hover{color:var(--ink)}
/* NAV */
.nav{position:sticky;top:0;z-index:50;background:color-mix(in srgb,var(--paper) 88%,transparent);backdrop-filter:blur(18px) saturate(140%);border-bottom:1px solid var(--rule-soft)}
/* Nav row sizing: every item is nowrap and the three gaps were tightened (32/30/22 →
   28/24/18) so the FRENCH label set — the longest — fits on one line down to ~1067px.
   Without nowrap "Comment ça marche" and "Pour les entreprises" broke onto 2–3 lines and
   doubled the bar's height between 901 and ~1100px (03 §B3). Do not re-widen these gaps
   without re-measuring /fr and moving the burger breakpoint in responsive.css §6. */
/* A-03 / SC 1.4.12: `height:68px` was a FIXED height on a row of text. Under the WCAG
   text-spacing override the row's content grows (letter-spacing .12em + word-spacing .16em
   on "Book service" / "Agendar servicio") and a fixed height cannot absorb it. min-height
   keeps the 68px bar identical at normal spacing — measured 68px at 320/360/375/480/768/
   1100/1101/1280/1920 in all three languages, before and after — and simply lets it grow
   if a user's own spacing ever needs it.
   DO NOT add `flex-wrap:wrap` here. It was tried and reverted: the FR bar needs 1015px of
   the 1013px available at exactly 1101px (one pixel above the burger breakpoint, where the
   full desktop nav is still showing), so wrapping was allowed to trigger at NORMAL spacing
   and the bar silently became a 102px two-row block on /fr and /es. The row must stay on
   one line; the narrow-width shrink in responsive.css §6 is what absorbs the text-spacing
   growth instead. */
.nav .wrap{display:flex;align-items:center;justify-content:space-between;min-height:68px;gap:28px}
.logo{display:flex;align-items:center;gap:10px;font-weight:600;font-size:20px;letter-spacing:-.02em;white-space:nowrap}
.logo-mark{width:28px;height:28px;background:var(--navy);color:var(--cream);border-radius:5px;display:grid;place-items:center;font-weight:700;font-size:16px;flex-shrink:0}
.nav-links{display:flex;gap:24px;flex-shrink:0}
.nav-links a{font-size:14.5px;font-weight:500;color:var(--dim);white-space:nowrap}.nav-links a:hover{color:var(--ink)}
.nav-right{display:flex;align-items:center;gap:18px;flex-shrink:0}
.nav-right .login{font-size:14.5px;font-weight:500;color:var(--dim)}
.nav .btn{height:40px;padding:0 18px;font-size:14px}
/* HERO */
.hero{padding:clamp(48px,7vw,104px) 0 0;overflow-x:clip}
.hero .wrap{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,1fr);gap:clamp(32px,5vw,80px);align-items:end}
.hero-copy>*{opacity:1}
.hero-tag .dot{animation:pulse 2.2s 1.6s infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 3px rgba(94,235,183,.2)}50%{box-shadow:0 0 0 7px rgba(94,235,183,0)}}
.hero h1{font-weight:500;font-size:clamp(52px,7.4vw,112px);line-height:.94;letter-spacing:-.045em;margin:22px 0 28px}
.hero h1 .em{color:var(--teal-deep)}
.hero .lead{margin-bottom:36px}
/* A-01 + A-02. The `--focus` reset is the important half: `.cta`/`.ph.dark` set
   --focus:var(--mustard) for their navy background, and because --focus is an INHERITED
   custom property the white address pill nested inside them was drawing a mustard ring on
   white at 1.68:1. The token is reset HERE, on the element that owns the light background,
   rather than in a list of "light things inside dark things" — a component that declares
   its own surface must declare the focus ring that goes with it, or the next component
   added inside a navy section re-opens this exact bug. Descendant beats inherited, so file
   order and specificity against responsive.css §2 are irrelevant. --teal-deep on #fff is
   5.55:1. --rule-ui: see :root. */
.addr{display:flex;align-items:center;gap:8px;background:#fff;--focus:var(--teal-deep);border:1px solid var(--rule-ui);border-radius:8px;padding:6px 6px 6px 16px;max-width:560px;box-shadow:0 1px 0 rgba(11,43,60,.04),0 20px 50px -30px rgba(11,43,60,.35);transition:border-color .2s}
.addr:focus-within{border-color:var(--navy)}
.addr svg{color:var(--teal-deep);flex-shrink:0}
.addr input{flex:1;min-width:0;border:0;outline:0;background:transparent;font:inherit;font-size:16px;color:var(--ink);height:44px}
.addr input::placeholder{color:var(--faint)}
.addr .btn{height:44px}
.proof{display:flex;gap:28px;margin-top:22px;font-size:13.5px;color:var(--dim);flex-wrap:wrap}
.proof b{color:var(--ink);font-weight:600}
.hero-art{position:relative;aspect-ratio:4/4.6;border-radius:10px;overflow:hidden;background:var(--cream)}
.hero-art img{width:100%;height:100%;object-fit:cover;object-position:62% 50%}
.hero-art .mascot{display:none;object-fit:contain;object-position:center bottom;padding:8% 4% 0;background:linear-gradient(180deg,var(--cream),#EAE3D3)}
html[data-hero="mascot"] .hero-art .photo{display:none}html[data-hero="mascot"] .hero-art .mascot{display:block}
.hero-tag{position:absolute;left:18px;bottom:18px;display:flex;align-items:center;gap:10px;background:rgba(6,24,34,.72);color:var(--cream);backdrop-filter:blur(12px);border:1px solid rgba(245,240,229,.14);border-radius:6px;padding:10px 14px;font-size:13px;line-height:1.3}
.hero-tag .dot{width:7px;height:7px;border-radius:50%;background:#5EEBB7;box-shadow:0 0 0 3px rgba(94,235,183,.2)}
/* .85, was .6 → 3.53:1 once composited over the chip's own rgba(6,24,34,.72). Not a live
   bug today (.hero-tag is display:none under data-hero="live", which every shipped page
   uses) — fixed so the photo/mascot hero variants are AA if they are ever switched on. */
.hero-tag span span{display:block;color:rgba(245,240,229,.85);font-size:11.5px}
.hero-rule{margin-top:clamp(56px,7vw,110px);border-top:1px solid var(--rule)}
/* HOW */
.how{padding:clamp(72px,8vw,128px) 0}
.how .head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:40px;align-items:end;margin-bottom:clamp(40px,5vw,72px)}
.how .head .lead{justify-self:end}
.steps{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;border-top:1px solid var(--rule)}
.step{padding:32px 32px 0 0;border-right:1px solid var(--rule-soft);padding-right:36px}
.step:last-child{border-right:0}.step+.step{padding-left:36px}
.step .num{font-family:var(--display);font-style:italic;font-size:46px;line-height:1;color:var(--teal-deep);margin-bottom:56px}
html[data-type="grotesk"] .step .num{font-style:normal;font-weight:500;letter-spacing:-.04em}
.step h3{margin-bottom:10px}
.step p{color:var(--dim);font-size:15.5px}
.how-photo{margin-top:clamp(48px,6vw,80px);display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);gap:20px}
.how-photo .slot-a{aspect-ratio:16/9}.how-photo .slot-b{aspect-ratio:auto}
.how-photo image-slot{width:100%;height:100%}
/* INCLUDED — section-scoped. `.incl` is ALSO the class of the <ul> "what's included" list
   on every city×service SEO page (seo.css:24), which was picking up the cream background,
   the 72–128px block padding and both hairline borders from these rules. Section rules in
   this file must always carry their element so they cannot land on a component. */
section.incl{padding:clamp(72px,8vw,128px) 0;background:var(--cream);border-block:1px solid var(--rule-soft)}
section.incl .wrap{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.3fr);gap:clamp(32px,6vw,96px)}
section.incl h2{margin:14px 0 20px}
section.incl .lead{margin-bottom:30px}
.ledger{border-top:1px solid var(--rule)}
.row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:20px;align-items:baseline;padding:18px 0;border-bottom:1px solid var(--rule)}
.row .name{font-size:19px;font-weight:500;letter-spacing:-.015em}
.row .name small{display:block;font-size:14px;color:var(--dim);font-weight:400;margin-top:3px;letter-spacing:0}
.row .when{font-size:13px;color:var(--dim);letter-spacing:.06em;text-transform:uppercase;font-weight:500;text-align:right;white-space:nowrap}
.row.addon .when{color:var(--faint)}
.ledger-note{font-size:13.5px;color:var(--dim);margin-top:18px}
/* KEYLESS */
.keyless{background:var(--navy);color:var(--cream);padding:clamp(80px,9vw,140px) 0;overflow:hidden}
.keyless .wrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(32px,6vw,96px);align-items:center}
.keyless .kicker{color:rgba(245,240,229,.6)}.keyless .kicker b{color:var(--teal)}
.keyless h2{color:var(--cream);margin:14px 0 22px}.keyless .em{color:var(--teal)}
.keyless .lead{color:rgba(245,240,229,.72)}
.klist{margin-top:34px;border-top:1px solid rgba(245,240,229,.14)}
.klist div{display:grid;grid-template-columns:32px minmax(0,1fr);gap:14px;padding:16px 0;border-bottom:1px solid rgba(245,240,229,.14);font-size:15.5px;color:rgba(245,240,229,.85)}
.klist div span:first-child{color:var(--teal);font-size:12px;letter-spacing:.1em;font-weight:600;padding-top:3px}
.phone-wrap{display:flex;justify-content:center;position:relative}
.phone-wrap::before{content:'';position:absolute;inset:10% -10%;background:radial-gradient(ellipse at center,rgba(27,164,182,.22),transparent 65%);pointer-events:none}
.phone{position:relative;width:300px;background:#09202D;border-radius:40px;padding:10px;border:1px solid rgba(245,240,229,.14);box-shadow:0 50px 100px -30px rgba(0,0,0,.7)}
/* --focus reset (A-01): .keyless is navy and sets --focus:var(--mustard); this phone
   screen is a LIGHT surface inside it, and #unlockBtn / .d inside .notif were drawing a
   mustard ring on white at 1.68:1. Same rule as .addr — the surface owns its ring. */
.screen{background:#F6F5EF;--focus:var(--teal-deep);color:var(--navy);border-radius:32px;overflow:hidden;min-height:560px;position:relative}
.island{position:absolute;top:12px;left:50%;transform:translateX(-50%);width:96px;height:26px;background:#000;border-radius:14px}
/* The phone mock's iOS-style status bar and the SEO/marketing stat TILE (pages.css:100)
   both use `.stat`. pages.css loads later, so the tile's `padding:22px 0 18px`,
   `border-bottom`, `:nth-child(odd){border-right}` and `.stat span{display:block;12.5px;
   uppercase;margin-top:8px}` were all landing on "9:41 ●●●" — a 68px band with a hairline
   under it instead of a 36px status row. Scoping to .screen wins on specificity (0,2,0)
   regardless of file order; the span reset needs .screen too (0,2,1 vs pages' 0,1,1). */
.screen .stat{display:flex;justify-content:space-between;padding:16px 26px 8px;font-size:12px;font-weight:600;border:0}
.screen .stat span{display:inline;font-size:12px;font-weight:600;color:inherit;margin:0;letter-spacing:normal;text-transform:none}
/* the tile's :nth-child(odd/even) padding/border rules are (0,2,0) too, so they need an
   explicit (0,3,0) answer or the status bar keeps a 24px inset and a right hairline */
.screen .stat:nth-child(odd),.screen .stat:nth-child(even){padding-left:26px;padding-right:26px;border-right:0}
.lock{text-align:center;padding:28px 20px 10px;font-size:13px;color:var(--dim);letter-spacing:.08em;text-transform:uppercase;font-weight:500}
.lock b{display:block;font-size:44px;font-weight:500;letter-spacing:-.04em;color:var(--navy);margin-top:4px;text-transform:none}
.notif{margin:22px 12px 0;background:#fff;border-radius:18px;padding:14px;box-shadow:0 10px 30px -14px rgba(11,43,60,.3);animation:nIn .7s .3s cubic-bezier(.2,.9,.3,1.2) backwards}
@keyframes nIn{from{opacity:0;transform:translateY(-16px) scale(.97)}to{opacity:1;transform:none}}
.notif-head{display:flex;align-items:center;gap:8px;font-size:12px;color:var(--dim);margin-bottom:8px}
.notif-head .logo-mark{width:20px;height:20px;font-size:11px;border-radius:5px}
.notif-head time{margin-left:auto}
.notif p{font-size:14px;line-height:1.4}
.notif p b{font-weight:600}
.notif .acts{display:flex;gap:8px;margin-top:12px}
.notif .acts button{flex:1;height:40px;border-radius:10px;border:0;font:inherit;font-weight:600;font-size:13.5px;cursor:pointer}
.notif .acts .u{background:var(--navy);color:var(--cream)}
.notif .acts .d{background:rgba(11,43,60,.06);color:var(--navy);flex:0 0 auto;padding:0 16px}
.notif .sec{margin-top:10px;font-size:11px;color:var(--faint);display:flex;align-items:center;gap:6px}
.notif.done .acts,.notif.done .sec{display:none}
.tl{margin:18px 12px 0;padding:0 6px}
.tl div{display:grid;grid-template-columns:18px minmax(0,1fr) auto;gap:10px;align-items:center;font-size:13px;padding:9px 0;border-bottom:1px solid var(--rule-soft);color:var(--dim)}
.tl div i{width:8px;height:8px;border-radius:50%;background:var(--rule);justify-self:center}
.tl div.on{color:var(--navy)}.tl div.on i{background:var(--teal)}
.tl time{font-size:12px;color:var(--faint);font-variant-numeric:tabular-nums}
/* ---- KEYLESS DEMO: the looping four-beat story (app.js) --------------------------
   The owner asked for "a live thing like the Aperio Cloud thing — step one, then next,
   then next, then next", watched the first cut and said it "moves way too fast through
   unlock/lock, and it needs to replay automatically". Three rules follow:

   1. NO ENGLISH LEAKS. All four notification messages are real text nodes in home.html,
      so the build's dictionary translates them like any other copy; app.js only moves the
      `.on` class between them and reads each timeline row's timestamp from `data-at`.
      Nothing is written from a string literal in JS.
   2. NO CLS, IN THREE LANGUAGES. The messages are stacked absolutely inside `.notif-body`,
      whose min-height holds the tallest message in that language. The phone is a fixed
      300px box at every viewport (measured identical at 320px and 1280px), so one number
      per language covers all widths: EN's longest message is 3 lines (59px), FR's and ES's
      beat-1 card runs to 4 (78px). Reserving 78px everywhere would put 19px of dead white
      in the EN card at every beat, so the reserve is language-scoped off <html lang>.
      Separately, `.notif.done` drops `.acts` (40 + 12 margin) and `.sec` (33 + 10) at beat
      2 — 95px. That exact height is handed back as padding under the timeline, so the
      screen keeps its height and the empty space lands where a lock screen has empty space
      anyway, instead of as a hole inside the white card.
   3. A PAUSE CONTROL THAT DOES NOT TAKE OVER. The loop runs indefinitely, so WCAG 2.2.2
      owes the visitor a pause — but the owner has already rejected a big pause button on
      the hero. So it is one 12.5px text toggle under the phone, Pause/Play, in the same dim
      cream as `.keyless .lead` (7.4:1 on navy, AA at any size), >=24px tall, in space
      reserved from first paint so revealing it never pushes the section around. It appears
      only once the loop is actually running. */
.notif-body{position:relative;min-height:59px}
html[lang^="fr"] .notif-body,html[lang^="es"] .notif-body{min-height:78px}
.notif-body .nmsg{position:absolute;left:0;top:0;width:100%;opacity:0;transform:translateY(5px);transition:opacity .26s cubic-bezier(.2,.7,.2,1),transform .26s cubic-bezier(.2,.7,.2,1)}
.notif-body .nmsg.on{opacity:1;transform:none}
.notif.done ~ .tl{padding-bottom:95px}
/* beat 2: the button presses itself before the card changes */
.notif .acts .u{transition:transform .16s ease,background-color .16s ease}
.notif .acts .u.press{transform:scale(.955);background:var(--navy-deep)}
/* beats 2-4: each row lights rather than snapping. The timestamp column is reserved: the
   grid's third track is `auto`, so a row swapping "—" for "7:58" used to steal ~19px from
   the label and wrap "Service complete · photos sent" onto a second line, growing the phone
   mid-story. Widest string here is "7:58" at 12px tabular. */
.tl div{transition:color .34s ease}
.tl div i{transition:background-color .34s ease}
.tl time{min-width:32px;text-align:right;transition:color .34s ease}
/* end of a loop: both cards dim for ~.6s and come back at beat 1, so the restart reads as a
   breath rather than a jump cut */
.screen .notif,.screen .tl{transition:opacity .34s ease}
.screen.resetting .notif,.screen.resetting .tl{opacity:.12;transition:opacity .6s ease}
/* the phone is one column now: mock, then the pause/play line under it */
.phone-wrap{flex-direction:column;align-items:center}
.kl-foot{display:flex;align-items:center;justify-content:center;min-height:28px;margin-top:12px}
.kl-toggle{display:inline-flex;align-items:center;justify-content:center;min-height:24px;padding:4px 10px;background:none;border:0;font:inherit;font-size:12.5px;line-height:1.3;letter-spacing:.01em;color:rgba(245,240,229,.72);cursor:pointer;opacity:0;visibility:hidden;transition:opacity .26s ease,color .16s ease}
.kl-toggle.on{opacity:1;visibility:visible}
.kl-toggle:hover{color:var(--cream)}
.kl-lab{display:inline-flex;align-items:center;gap:6px}
.kl-lab svg{flex:0 0 auto;opacity:.8}
/* only one label is in the DOM box at a time, so the button's name from content is exactly
   "Pause" or "Play" — no aria-label needed and nothing for the two to disagree about */
.kl-toggle .kl-lab-play,.kl-toggle[aria-pressed="true"] .kl-lab-pause{display:none}
.kl-toggle[aria-pressed="true"] .kl-lab-play{display:inline-flex}
/* the one sentence that describes the illustration to a screen reader; the mock itself is
   aria-hidden, and the toggle is the only focusable thing outside that subtree */
.kl-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
/* PRICE — section-scoped. `.price` is ALSO the class of the price CELL in every .veh-row
   (2,142 spans) and every model spec table (2,914 <td>s), so the unscoped section padding
   was adding 80–140px of block padding to each of them at ≥921px (where the price column
   is visible), blowing /vehicles/mercedes-benz up from 15k to 71k px tall. See 03 §B1.
   `.price-card` / `.price-line` / `.price-note` are distinct classes and stay unscoped. */
section.price{padding:clamp(80px,9vw,140px) 0}
section.price .wrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:clamp(32px,6vw,96px);align-items:center}
section.price h2{margin:14px 0 20px}
.big{font-weight:500;font-size:clamp(88px,12vw,168px);line-height:.9;letter-spacing:-.06em;display:flex;align-items:flex-start;gap:6px}
.big sup{font-size:.32em;margin-top:.22em;color:var(--price-accent);font-family:var(--display);font-style:italic;font-weight:400;letter-spacing:0}
html[data-type="grotesk"] .big sup{font-style:normal;font-family:var(--sans);font-weight:500}
.big .per{font-family:var(--display);font-style:italic;font-size:.22em;letter-spacing:-.01em;color:var(--dim);align-self:flex-end;margin:0 0 .18em 4px;font-weight:400}
html[data-type="grotesk"] .big .per{font-style:normal;font-weight:400}
/* The headline price must never break mid-number (final QA B1). `.big` is a flex row and
   every child defaults to `flex:0 1 auto`, so a long `.per` caption ("per vehicle / year,
   billed annually" and its FR/ES equivalents) squeezed the figure below its natural width;
   the global `overflow-wrap:anywhere` on `.big` then broke it INSIDE the digits — "$19 / 9"
   at 320px and at every width from ~901px up. The currency mark and the figure are now
   unshrinkable and unbreakable; the caption is the only child that gives way (it wraps, or
   drops below the figure at narrow widths). */
.big>sup,.big>.n,.big>[data-count]{flex:0 0 auto}
.big [data-count],.big .n{white-space:nowrap;overflow-wrap:normal;word-break:keep-all}
.big .per{min-width:0}
.price-card{border-top:2px solid var(--price-accent);padding-top:22px}
section.price ul{list-style:none;margin:26px 0 30px;display:grid;gap:12px}
section.price li{display:flex;gap:12px;font-size:16px;align-items:flex-start}
section.price li::before{content:'';width:18px;height:18px;flex-shrink:0;margin-top:3px;border-radius:50%;background:var(--price-accent);-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='12' fill='%23000'/%3E%3Cpath d='M7 12.5l3 3 7-7' stroke='%23fff' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='12' fill='%23000'/%3E%3Cpath d='M7 12.5l3 3 7-7' stroke='%23fff' stroke-width='2.4' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat}
section.price .ctas{display:flex;gap:12px;flex-wrap:wrap;align-items:center}
section.price .fine{font-size:13px;color:var(--faint);margin-top:18px}
/* COVERAGE */
.cov{padding:clamp(72px,8vw,128px) 0;background:var(--cream);border-block:1px solid var(--rule-soft)}
.cov .head{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:40px;align-items:end;margin-bottom:clamp(40px,5vw,64px)}
.cov .head .lead{justify-self:end}
.regions{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:40px;border-top:1px solid var(--rule)}
/* min-width:0 — a grid item's automatic minimum is min-content, and .cities below is a
   multicolumn box whose min-content was 883px, so .region used to blow past its track no
   matter how narrow the track was. */
.region{padding-top:24px;min-width:0}
.region .kicker{display:flex;justify-content:space-between;margin-bottom:18px;gap:12px}
.region .kicker span{color:var(--teal-deep)}
.cities{columns:2;column-gap:24px;font-size:15px;line-height:1.85;color:var(--ink);min-width:0}
/* The "coming 2026" region lists its cities as bare <span>s with no whitespace between
   them (`</span><span>`), so as inline boxes they formed ONE unbreakable ~860px run:
   .cities' min-content width became 883px and the home/FR-home page overflowed the
   viewport horizontally at EVERY width — invisible only because body{overflow-x:hidden}
   swallows the scrollbar. They must lay out one-per-line like the linked cities do. */
.cities a,.cities>span{display:block;color:inherit}
.cities a{color:var(--ink)}.cities a:hover{color:var(--teal-deep)}
.region.soon .cities{color:var(--dim)}
.region .more{display:inline-block;margin-top:14px;font-size:14px;font-weight:600}
/* QUOTE */
.quote{padding:clamp(72px,8vw,128px) 0}
.quote .wrap{max-width:900px}
blockquote{font-family:var(--display);font-style:italic;font-size:clamp(28px,3.4vw,46px);line-height:1.18;letter-spacing:-.02em;text-wrap:balance}
html[data-type="grotesk"] blockquote{font-style:normal;font-weight:500;letter-spacing:-.03em}
.quote cite{display:flex;align-items:center;gap:14px;margin-top:32px;font-style:normal;font-size:14px;color:var(--dim)}
.quote cite b{display:block;color:var(--ink);font-weight:600}
.quote .ph{font-family:ui-monospace,Menlo,monospace;font-size:12px;color:var(--faint);margin-top:14px}
/* FAQ */
.faq{padding:clamp(72px,8vw,128px) 0;border-top:1px solid var(--rule-soft)}
.faq .wrap{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1.4fr);gap:clamp(32px,6vw,96px)}
.faq h2{margin-top:14px}
.faq p.mail{margin-top:18px;color:var(--dim);font-size:15px}
details{border-top:1px solid var(--rule)}details:last-child{border-bottom:1px solid var(--rule)}
summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;gap:20px;align-items:center;padding:22px 0;font-size:19px;font-weight:500;letter-spacing:-.015em}
summary::-webkit-details-marker{display:none}
summary::after{content:'+';font-family:var(--serif);font-size:30px;line-height:0;color:var(--teal-deep);transition:transform .25s}
details[open] summary::after{transform:rotate(45deg)}
details p{padding:0 0 24px;max-width:60ch;color:var(--dim);font-size:16px}
/* B2B */
.b2b{background:var(--cream);border-block:1px solid var(--rule-soft)}
.b2b .wrap{display:flex;justify-content:space-between;align-items:center;gap:24px;padding-block:28px;flex-wrap:wrap}
.b2b p{font-size:17px}.b2b p b{font-weight:600}
.b2b .links{display:flex;gap:28px;flex-wrap:wrap}
html[data-b2b="off"] .b2b{display:none}
/* CTA */
.cta{background:var(--navy);color:var(--cream);padding:clamp(96px,11vw,170px) 0;position:relative;overflow:hidden}
.cta .wrap{position:relative;z-index:1;display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:40px;align-items:end}
.cta h2{color:var(--cream);font-size:clamp(44px,6vw,92px);letter-spacing:-.045em}
.cta .em{color:var(--teal)}
.cta .addr{margin-top:0;box-shadow:none}
.cta .van{position:absolute;right:-6%;bottom:-8%;width:min(46vw,620px);opacity:.28;filter:saturate(.6);pointer-events:none;mix-blend-mode:luminosity}
/* FOOTER */
footer{padding:56px 0 36px;font-size:14px}
.foot{display:grid;grid-template-columns:minmax(0,1.6fr) repeat(3,minmax(0,1fr));gap:40px;padding-bottom:40px;border-bottom:1px solid var(--rule)}
.foot p{color:var(--dim);max-width:30ch;margin-top:14px}
/* .foot-h replaced the <h5> column headings (they were an h2→h5 level skip, 01-L2);
   same look, no heading semantics. R-CSS-2. */
.foot h5,.foot .foot-h{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);font-weight:600;margin-bottom:14px;max-width:none;margin-top:0}
.foot a{display:block;color:var(--ink);margin-bottom:9px}.foot a:hover{color:var(--teal-deep)}
.foot-bottom{display:flex;justify-content:space-between;align-items:center;gap:20px;padding-top:24px;color:var(--faint);font-size:13px;flex-wrap:wrap}
/* A-04 — SC 1.4.1 Use of Color (Level A). Links sitting inside a sentence were told apart
   from the text around them by COLOUR ALONE. Measured before:
     .foot-bottom  link --ink #0B2B3C vs surrounding --faint rgba(11,43,60,.66) = 2.87:1
     "Privacy settings" (button.linklike) vs the same sentence                   = 1.00:1
     .crumbs links vs their "/" separators                                       = 1.00:1
     .faq p.mail link vs the paragraph around it                                 = 2.70:1
   Technique G183 needs BOTH >=3:1 against the surrounding text AND a non-colour cue; none
   of these had either. An underline at REST (not only on hover) settles it outright, and
   these two footer links are the site's only published contact channels — the ones the
   accessibility statement points people at.
   Nav links, .btn, .arrow and card links are deliberately excluded: they are discrete
   visual components, not text inside a sentence, so 1.4.1 does not bite on them and
   underlining them would be noise. */
.foot-bottom a,.foot-bottom .linklike,.crumbs a,
main p a[href],main li a[href]{
  text-decoration:underline;
  text-underline-offset:2px;
  text-decoration-thickness:from-font;
}
/* a component that merely happens to sit in a <p>/<li> is still a component */
main p a.btn,main p a.arrow,main li a.btn,main li a.arrow,
main p a.svc-card,main li a.svc-card{text-decoration:none}
/* A-03 / SC 1.4.12 — `flex-wrap:wrap` is load-bearing, not cosmetic. This pill's
   `overflow:hidden` (which is what rounds off the child buttons' square corners) was
   CLIPPING the third segment under the WCAG text-spacing override: at 320px on every FR
   and ES page the footer language toggle rendered "EN FR E…" with "ES" cut off and
   unreachable — the control that switches language, lost. It is the same failure mode
   responsive.css §6 documents for the mobile-menu copy of this pill.
   Wrapping makes the segments drop to a second row instead, so nothing is ever clipped;
   at normal spacing the pill still fits on one line and is pixel-identical (verified at
   320/375/768/1100/1280/1920/2560 in all three languages). */
.seg{display:inline-flex;flex-wrap:wrap;border:1px solid var(--rule);border-radius:6px;overflow:hidden}
.seg button{background:transparent;border:0;border-right:1px solid var(--rule);padding:7px 12px;font:inherit;font-size:12px;font-weight:600;color:var(--dim);cursor:pointer}
.seg button:last-child{border-right:0}.seg button.on{background:var(--navy);color:var(--cream)}
.foot-ctl{display:flex;gap:10px;flex-wrap:wrap}   /* same reason as .seg above (SC 1.4.12) */
/* reveal — scroll-triggered by site.js adding .in.
   FAILSAFE (04 §1.7 / 02 §H2): the hidden state must never be able to outlive JS. A 0s
   animation with a 2.5s delay and `forwards` fill flips every .rv element back to visible
   without any script at all, so a blocked/failed/disabled site.js can no longer leave the
   page as "hero over blank space". Animations beat normal declarations in the cascade, so
   .rv.in must cancel it (`animation:none`) for the scroll reveal to still transition in.
   Once an inline `document.documentElement.classList.add('js')` exists (requested from the
   shell/JS owner in docs/stress/fix-requests.md — it must be set by site.js itself, not by
   a head script, so a blocked site.js still gets the failsafe) the `html.js` rule below
   turns the failsafe off and the per-section reveal is fully restored below the fold. */
.rv{opacity:0;transform:translateY(18px);transition:opacity .8s cubic-bezier(.2,.7,.2,1),transform .8s cubic-bezier(.2,.7,.2,1);animation:rv-failsafe 0s linear 2.5s forwards}
@keyframes rv-failsafe{to{opacity:1;transform:none}}
.rv.in,html.js .rv{animation:none}
.rv.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.rv{opacity:1;transform:none;transition:none;animation:none}}
.big .n{font-variant-numeric:tabular-nums}
@media (max-width:1180px){section.price .wrap{grid-template-columns:1fr;gap:36px}section.price .lead{max-width:60ch}.price-card{display:grid;grid-template-columns:auto minmax(0,1fr);gap:16px 56px;align-items:start}.price-card .ctas,.price-card .fine{grid-column:2}.price-card .big{grid-row:1/4}section.price ul{margin-top:8px}.cov .head{grid-template-columns:1fr;gap:16px}.cov .head .lead{justify-self:start}}
/* NOTE: the nav's own breakpoint is NOT here any more — the burger/desktop-nav switch moved
   to 1100px (responsive.css §6) because the French nav labels need ~1067px. The 900px
   breakpoint below is layout-only. */
@media (max-width:900px){.hero .wrap,.how .head,section.incl .wrap,.keyless .wrap,section.price .wrap,.cov .head,.faq .wrap,.cta .wrap{grid-template-columns:1fr}.how .head .lead,.cov .head .lead{justify-self:start}.steps{grid-template-columns:1fr}.step{border-right:0;padding:24px 0 8px!important;border-bottom:1px solid var(--rule-soft)}.step .num{margin-bottom:20px}.price-card{grid-template-columns:1fr}.price-card .ctas,.price-card .fine,.price-card .big{grid-column:1;grid-row:auto}.how-photo{grid-template-columns:1fr}.how-photo .slot-b{display:none}.regions{grid-template-columns:minmax(0,1fr);gap:0}.region{padding-block:24px;border-bottom:1px solid var(--rule)}.hero-art{aspect-ratio:16/10}.hero-art img{object-position:50% 60%}.cta .van{display:none}.big{font-size:clamp(72px,18vw,120px)}}
