/* ============================================================
   ONDEMAND PRIME — "THE ROUTE" REBUILD
   Fixed canvas background scrubbed by scroll position.
   PREVIEW MODE: procedural placeholder scenes (swap for real
   Higgsfield-generated WebP frames — see JS config at bottom).
   ============================================================ */

:root{
  --asphalt:#0C0F15;
  --asphalt-2:#12161F;
  --signal:#FF5500;        /* brand orange, sampled from the ODP mark — primary accent */
  --signal-deep:#E04A00;   /* pressed/hover state for orange fills */
  --pacific:#B4551C;       /* secondary accent — dimmed orange, deliberately subordinate to --signal */
  --bone:#EFEBE2;
  --slate:#8B93A3;
  --line:rgba(239,235,226,.14);
  /* ACCESSIBILITY NOTE — deliberate, client decision 2026-09-14.
     These panel values are lighter and more transparent than AA allows for
     the orange .eyebrow labels sitting on them. Measured: orange #FF5500
     gives 4.38:1 over dark frames and 3.09:1 over the bright dock frames,
     against a 4.5:1 floor for normal text. Cream body copy is unaffected
     (11.8:1 / 8.3:1) — only the orange labels fail.
     The client was shown the measurements and three options (keep orange and
     accept darker panels; recolour the labels to cream and go lighter; or
     ship lighter and accept the failure) and chose the third.
     Do not silently "fix" this back. The accessible route is recolouring the
     818 .eyebrow labels, not darkening the panels. */
  --panel:rgba(44,52,66,.62);
  --panel-heavy:rgba(40,48,61,.78);
  --panel-card:rgba(44,52,66,.70);   /* the .svc/.mode/.comp/.sv-* boxes */
  --panel-soft:rgba(44,52,66,.64);   /* the lighter .step/.comp variant */
  --display:'Archivo',sans-serif;
  --mono:'IBM Plex Mono',monospace;
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{
  font-family:var(--display);
  font-variation-settings:'wdth' 100;
  background:var(--asphalt);
  color:var(--bone);
  line-height:1.55;
  overflow-x:hidden;
}
::selection{background:var(--signal);color:var(--asphalt)}

/* ---------- LOADER ---------- */
#loader{
  position:fixed;inset:0;z-index:200;background:#07090D;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:22px;
  transition:opacity .6s ease;
}
.loader-mark img{width:230px;height:auto;display:block}
.loader-track{width:190px;height:2px;background:rgba(239,235,226,.14);position:relative;overflow:hidden}
.loader-track i{position:absolute;left:0;top:0;bottom:0;width:0%;background:var(--signal);transition:width .25s ease}
.loader-note{font-family:var(--mono);font-size:10.5px;letter-spacing:.24em;color:var(--slate)}
/* Fades in only once body carries .ready — keyed on the class alone, not on
   how it got there. route.js adds it once frames finish loading. Any page
   that does NOT load route.js (freight/courier/specialized/dedicated —
   pages with no canvas animation) MUST ship <body class="ready"> in its
   markup, or main/nav/footer stay opacity:0 forever: a silently blank
   page with no console error and no failing DOM check. */
main,nav,footer{opacity:0;transition:opacity .7s ease .1s}
body.ready main,body.ready nav,body.ready footer{opacity:1}

body.no-frames{background:linear-gradient(165deg,#0C0F15 0%,#152030 45%,#0A0D12 100%)}

/* ---------- FIXED JOURNEY CANVAS ---------- */
#journey{
  position:fixed;inset:0;width:100vw;height:100vh;
  z-index:0;display:block;
}
#grain{
  position:fixed;inset:0;z-index:1;pointer-events:none;
  opacity:.5;mix-blend-mode:overlay;
}
/* ---------- SCRIM ----------
   A light top/bottom pass only. This used to be a raked left-to-right
   wedge — 84% black down the left edge — because copy was always set
   left. Copy now alternates sides per scene, so a fixed wedge would
   darken the wrong half as often as the right one, and it was the
   single biggest thing hiding the footage. Directional protection now
   lives in each .panel's own wash, which follows the copy.
   What is left protects the nav on the way in and the footer on the
   way out, and nothing else. */
.scrim{
  position:fixed;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to bottom,
      rgba(8,10,15,.52) 0%,
      rgba(8,10,15,.08) 16%,
      rgba(8,10,15,0)   34%,
      rgba(8,10,15,0)   70%,
      rgba(8,10,15,.12) 86%,
      rgba(8,10,15,.42) 100%);
}
@media(max-width:900px){
  .scrim{
    background:
      linear-gradient(to bottom,
        rgba(8,10,15,.60) 0%,
        rgba(8,10,15,.30) 30%,
        rgba(8,10,15,.30) 62%,
        rgba(8,10,15,.58) 100%);
  }
}

.vignette{
  position:fixed;inset:0;z-index:1;pointer-events:none;
  background:radial-gradient(ellipse at center,transparent 62%,rgba(5,7,11,.40) 100%);
}

/* ---------- INTERIOR-PAGE BACKGROUND ----------
   The homepage owns the scrub: 965 frames, ~136MB, paid for by ~14 viewports
   of scroll. The interior pages run 2-7.4 viewports, so the same journey
   would compress to roughly 3.5x speed and most frames would never finish
   loading before the reader scrolled past them. They get one still from the
   same shoot instead — a single frame already sitting in /frames, so it costs
   ~117KB and nothing new ships.

   The frame is chosen per page and passed in as --bg / --bg-sm on the element
   rather than hard-coded here, so the picture is visible in the markup of the
   page it belongs to and this rule stays the same for all seven.

   The wash is heavier at top and bottom (fixed nav, footer) and lifts through
   the middle so the photo still reads in the gutters either side of .panel and
   across the full width in the spacers between sections. It is a flat wash,
   not the homepage's raked wedge: interior copy is centred in a panel, not set
   hard left, so there is no one side that needs the darkening. */
.page-bg{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  background-image:var(--bg);
  background-size:cover;
  background-position:center;
}
@media(max-width:900px){
  .page-bg{background-image:var(--bg-sm)}
}
.page-bg::after{
  content:'';position:absolute;inset:0;
  background:linear-gradient(to bottom,
    rgba(8,10,15,.80) 0%,
    rgba(8,10,15,.44) 18%,
    rgba(8,10,15,.38) 60%,
    rgba(8,10,15,.82) 100%);
}

@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}

/* ---------- NAV ---------- */
nav{
  position:fixed;top:0;left:0;right:0;z-index:50;
  display:flex;align-items:center;justify-content:space-between;
  padding:18px 32px;
  transition:transform .32s ease;
}
/* The bar has no background at all, so page content passing underneath it
   is visibly on top of the links rather than hidden by a grey strip. The
   fix is not to darken it again: the bar leaves on the way down and comes
   back on the way up, so there is nothing to collide with while reading,
   and the footage is unobstructed for most of the scroll. */
nav.nav-hidden{transform:translateY(-100%)}
/* 2026-09-25 — WCAG 2.4.7/2.4.11. Tabbing into the nav while it is hidden
   put the focus ring entirely above the viewport (measured: rect top
   -40.4px) — a focusable control with no visible focus indicator. Keyboard
   focus inside the bar always brings it back. Must stay AFTER
   nav.nav-hidden: both selectors are (0,1,1), so this wins on source order
   alone and moving it up would silently disable it. */
nav:focus-within{transform:none}
/* No bar means the type carries itself. Two stops: the wide one kills a
   bright sky, the tight one holds against a hard specular edge. */
nav .logo,
.nav-links > li > a,
.nav-toggle,
.nav-phone{
  text-shadow:0 1px 10px rgba(5,7,11,.92), 0 0 3px rgba(5,7,11,.8);
}
/* While the menu is open the bar matches the panel below it, so the two
   read as one surface rather than a translucent strip over a solid one. */
nav.open{background:#161B25;border-bottom:1px solid var(--line)}
.logo{display:inline-flex;align-items:center;gap:11px;font-weight:800;font-size:19px;letter-spacing:-.01em;text-decoration:none;color:var(--bone);font-variation-settings:'wdth' 118}
/* Dark-background variant of the ODP mark: the black of the supplied logo is
   recoloured to --bone, the orange is untouched. It is decorative — the
   wordmark beside it carries the name — so it ships alt="". */
.logo-mark{height:30px;width:auto;display:block;flex:none}
.logo b{color:var(--signal)}
.nav-links{display:flex;gap:28px;align-items:center;list-style:none}
.nav-links > li{position:relative}
/* opacity:.85 removed 2026-09-24 — Task 8 found it was doing nothing the
   design needs (links already go to full opacity on hover/focus/current,
   so full opacity is an already-approved look for them) while quietly
   costing real contrast: corrected measurement (accounting for element
   opacity properly — see scripts/contrast-probe.py) put these at ~4:1
   against the daylight-arrival frames, below AA. Removing the rule
   (rather than adding a text-shadow bump) was the smaller change and
   cleared it outright — see docs/verification/2026-09-24-lighter-site.md. */
.nav-links a{color:var(--bone);text-decoration:none;font-size:13.5px;font-weight:500;letter-spacing:.02em;transition:opacity .2s,color .2s}
.nav-links > li > a{position:relative}
.nav-links a:hover,.nav-links a:focus-visible{opacity:1;color:var(--signal)}
.nav-cta{
  background:var(--signal);color:#fff!important;font-weight:700;
  padding:9px 18px;border-radius:3px;opacity:1!important;
}
.nav-cta:hover{background:var(--signal-deep)}
.nav-phone{font-family:var(--mono);font-size:12.5px}

/* Current-page marker. This replaces a bar that was hardcoded in the markup
   (class="nav-freight") and therefore sat under Freight on all ~100 pages no
   matter where you actually were. The state is now stamped per page by
   _src/build.py: aria-current="page" on an exact URL match, data-active when
   the page merely lives under that section (a lane page lights Freight). */
.nav-links > li > a[aria-current="page"],
.nav-links > li > a[data-active]{opacity:1}
.nav-links > li > a[aria-current="page"]::after,
.nav-links > li > a[data-active]::after{
  content:'';position:absolute;left:0;right:0;bottom:-6px;height:2px;
  background:var(--signal);
}

/* ---------- NAV DROPDOWNS ----------
   Hover plus :focus-within, deliberately no JS: every parent is a real link
   to its own hub page, so keyboard users tab in and the panel opens, and a
   touch tap just navigates to the hub instead. Below 1200px these stop being
   dropdowns entirely and list inline inside the menu panel. */
.nav-caret{
  display:inline-block;width:5px;height:5px;margin-left:7px;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg) translateY(-2px);
  opacity:.55;transition:opacity .2s;
}
.has-menu:hover .nav-caret,.has-menu:focus-within .nav-caret{opacity:1}
.nav-panel{
  position:absolute;top:calc(100% + 15px);left:-20px;z-index:60;
  display:flex;gap:30px;
  padding:18px 22px;min-width:212px;
  /* Near-opaque on purpose, NOT var(--panel-heavy) + backdrop-filter. An
     element that has backdrop-filter becomes a backdrop root for everything
     inside it, so a nested backdrop-filter has nothing left to sample: the
     moment nav picks up .open its own blur silently kills the blur on this
     panel and page text reads straight through the menu. The panel floats
     over arbitrary content, so it has to be legible on its own. */
  background:#161B25;
  border:1px solid var(--line);border-radius:4px;
  box-shadow:0 18px 44px rgba(6,8,12,.55);
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .18s ease,transform .18s ease,visibility .18s;
}
/* keeps the pointer inside the menu while it crosses the gap below the label */
.nav-panel::before{content:'';position:absolute;left:0;right:0;top:-15px;height:15px}
.nav-panel-wide{min-width:428px}
.has-menu:hover > .nav-panel,
.has-menu:focus-within > .nav-panel{opacity:1;visibility:visible;transform:none}
.nav-col h5{
  font-family:var(--mono);font-size:9.5px;font-weight:500;letter-spacing:.2em;
  text-transform:uppercase;color:var(--slate);margin:0 0 10px 8px;
}
.nav-col ul{list-style:none;display:flex;flex-direction:column;gap:1px}
.nav-col a{
  display:block;padding:6px 9px;margin:0 -9px;border-radius:3px;
  font-size:13px;white-space:nowrap;opacity:.78;transition:background .15s,opacity .15s,color .2s;
}
.nav-col a:hover,.nav-col a:focus-visible{background:rgba(239,235,226,.07);opacity:1}
.nav-col a[aria-current="page"],.nav-col a[data-active]{color:var(--signal);opacity:1}

/* ---------- NAV MENU BUTTON (below 1200px) ---------- */
.nav-toggle{
  display:none;align-items:center;gap:10px;
  background:none;border:1px solid var(--line);border-radius:3px;
  padding:9px 14px;cursor:pointer;color:var(--bone);
  font-family:var(--mono);font-size:10.5px;letter-spacing:.18em;text-transform:uppercase;
}
.nav-toggle:hover{color:var(--signal);border-color:rgba(255,85,0,.45)}
.nav-burger{display:block;position:relative;width:16px;height:12px;flex:none}
.nav-burger i{position:absolute;left:0;right:0;height:1.5px;background:currentColor;transition:transform .22s ease,opacity .18s ease}
.nav-burger i:nth-child(1){top:0}
.nav-burger i:nth-child(2){top:5.25px}
.nav-burger i:nth-child(3){top:10.5px}
nav.open .nav-burger i:nth-child(1){transform:translateY(5.25px) rotate(45deg)}
nav.open .nav-burger i:nth-child(2){opacity:0}
nav.open .nav-burger i:nth-child(3){transform:translateY(-5.25px) rotate(-45deg)}

/* ---------- CONTENT LAYER ---------- */
main{position:relative;z-index:10}
section{position:relative;padding:0 6vw}
.spacer{height:55vh}          /* breathing room where footage shows through */
.spacer-lg{height:85vh}

/* Fix 6: vertical rhythm for interior pages. The homepage paces its
   sections with .spacer/.spacer-lg divs against the canvas animation;
   interior pages deliberately carry none, since there's no scroll-frame
   animation to pace against — but nothing replaced them, so consecutive
   .panel blocks sat flush (0px gap, doubled hairlines). This rule only
   ever matches two <section> elements that are direct adjacent siblings,
   which never happens on the homepage (a .spacer/.spacer-lg div always
   sits between its sections) — so it reaches interior pages only, with
   no class or page-scoping needed, and the homepage is untouched. */
section + section{margin-top:64px}
@media (max-width:560px){
  section + section{margin-top:40px}
}

/* ---------- HERO ---------- */
#hero{
  min-height:100vh;display:flex;flex-direction:column;justify-content:center;
  /* Clear the fixed nav, whose height changes with how far it wraps: one
     row above 1200px, two below it, three once .nav-links itself wraps
     (~500-580px). --nav-h is measured and set by site.js on load/resize;
     the 66px fallback is the single-row height, so with JS off this
     resolves to the 100px floor exactly as it did before. max() keeps the
     roomier value, so the desktop look is unchanged (66+20 < 100) and the
     narrow breakpoints below can still raise it further. */
  padding-top:max(100px, calc(var(--nav-h, 66px) + 20px));
}
.eyebrow{
  font-family:var(--mono);font-size:12px;letter-spacing:.22em;color:var(--signal);
  text-transform:uppercase;margin-bottom:20px;display:flex;align-items:center;gap:10px;
}
.eyebrow::before{content:'';width:34px;height:1px;background:var(--signal)}
/* Fix 5: the hero eyebrow sits directly on the scrubbed video canvas with
   no panel and no text-shadow behind it — unlike #hero h1/.hero-sub (both
   carry text-shadow) and .caps (its own translucent panel). Sampled
   against a lit-window backdrop it dropped to 1.02:1. Give it the same
   translucent-chip treatment .caps already uses so contrast holds no
   matter what's playing behind it. Scoped to #hero only — every other
   .eyebrow sits on a solid .panel already and has nothing to fix. */
#hero .eyebrow{
  background:var(--panel-card);
  backdrop-filter:blur(3px);
  border:1px solid var(--line);
  border-radius:2px;
  padding:7px 14px 7px 11px;
  width:fit-content;
}
#hero h1{
  font-size:clamp(30px,4.2vw,60px);
  font-weight:850;line-height:.98;letter-spacing:-.025em;
  font-variation-settings:'wdth' 112;
  max-width:12ch;
  text-shadow:0 2px 40px rgba(5,7,11,.8);
}
#hero h1 em{font-style:normal;color:var(--signal)}

/* ---------- CONTENT-PAGE HERO ----------
   Compact hero for interior pages (courier, specialized, dedicated, …)
   that don't carry the homepage's canvas animation. Real top padding
   clears the fixed nav instead of forcing a full-viewport stage. The
   #hero rules above are untouched — the homepage's full-bleed hero
   still works exactly as before. Apply as class="page-hero" (no id,
   so it never competes with #hero's higher-specificity rules). */
.page-hero{
  padding-top:150px;
  padding-bottom:40px;
}
/* Interior heroes set their copy straight onto the .page-bg photograph —
   they are the one section on these pages with no .panel between type and
   picture, so nothing but a text-shadow was holding the contrast. Rather
   than darken .page-bg globally (which would flatten the photo everywhere,
   including the panels' gutters where it is doing its job), this scrim is
   scoped to the hero and scrolls away with it.

   Full-bleed via the negative inline offsets — section carries padding:0 6vw
   and inset:0 would stop at the padding box, leaving two lit strips at the
   edges. z-index:-1 keeps it under the hero's own type while staying inside
   main's stacking context, so it still sits above the fixed backdrop.

   Raked left, like the homepage: interior hero copy is set hard left with an
   empty right half, so the darkening follows the type and the photograph
   keeps its lit side. Under 900px the copy runs full width and the wedge
   stops making sense, so it flattens. */
.page-hero::before{
  content:'';position:absolute;z-index:-1;pointer-events:none;
  top:0;bottom:0;left:-6vw;right:-6vw;
  background:linear-gradient(100deg,
    rgba(8,10,15,.88) 0%,
    rgba(8,10,15,.70) 34%,
    rgba(8,10,15,.28) 62%,
    rgba(8,10,15,0)   84%);
}
@media(max-width:900px){
  .page-hero::before{
    background:linear-gradient(to bottom,
      rgba(8,10,15,.86) 0%,
      rgba(8,10,15,.66) 45%,
      rgba(8,10,15,.58) 100%);
  }
}
/* .f-hero shares this h1 treatment (Fix 2): /freight/'s hero shipped
   before .page-hero existed and was never wired up to it. Extending the
   selector — rather than adding the page-hero class to .f-hero's section —
   avoids stacking .page-hero's own padding-top/bottom on top of
   .f-hero .panel{padding-top:56px} below. */
.page-hero h1,.f-hero h1{
  font-size:clamp(38px,6vw,84px);
  font-weight:850;line-height:1.03;letter-spacing:-.025em;
  font-variation-settings:'wdth' 112;
  max-width:14ch;
  text-shadow:0 2px 40px rgba(5,7,11,.8);
}
.page-hero h1 em,.f-hero h1 em{font-style:normal;color:var(--signal)}

.hero-sub{
  margin-top:26px;font-size:clamp(16px,1.4vw,19px);color:var(--bone);
  max-width:52ch;opacity:.92;text-shadow:0 1px 20px rgba(5,7,11,.9);
}
/* Second hero-sub line (homepage only — client asked for the coverage/lane
   copy to read as a distinct, secondary line under the main promise, not
   folded into one paragraph). Shares .hero-sub's color/opacity/text-shadow
   so it isn't a new, unverified contrast regime on the dock footage — it
   reads as secondary purely through scale and a tighter lead-in than the
   26px gap .hero-sub itself uses after the h1. */
.hero-sub-2{
  margin-top:8px;
  font-size:clamp(13px,1.05vw,15px);
  letter-spacing:.01em;
}
.hero-ctas{margin-top:38px;display:flex;gap:14px;flex-wrap:wrap}
/* ---------- HERO: bottom-pinned CTAs (client: "too wordy and too clumped
   up") ----------
   .hero-lead (eyebrow/h1/sub×2/chips) and .hero-ctas are the only two
   direct children left in #hero's flex column ahead of .scroll-cue. Auto
   margins win over justify-content's free-space split: giving both blocks
   margin-top:auto divides #hero's leftover vertical space into two equal
   gaps — one above .hero-lead, one between .hero-lead and .hero-ctas —
   which keeps .hero-lead upper-middle and pins the buttons (and the
   scroll cue right under them, via its own fixed margin-top:9vh) to the
   hero's bottom-left. Scoped to #hero: .hero-ctas is reused as-is on every
   interior .page-hero, which is not a flex column and must keep its plain
   in-flow margin-top:38px. */
#hero .hero-lead{margin-top:auto}
#hero .hero-ctas{margin-top:auto}
/* Below ~490px (the width #hero's own padding-top rule already treats as
   "phone" — see the max(170px, …) clearance fix above) the eyebrow, wrapped
   h1, two hero-sub lines and wrapped chips routinely add up to more than
   100vh once the fixed top clearance is included. min-height:100vh is a
   floor, not a cap, so the box simply grows past the viewport in that case
   — but the auto margins above have zero free space left to split, so
   .hero-ctas would land flush against the chips with ~0px gap: the exact
   "clumped up" look this task exists to fix, just moved lower on the page.
   Below that width, drop back to plain stacked flow with a fixed gap. */
@media (max-width:490px){
  #hero .hero-lead{margin-top:0}
  #hero .hero-ctas{margin-top:34px}
}
.btn{
  display:inline-block;text-decoration:none;font-weight:700;font-size:15px;
  padding:15px 30px;border-radius:3px;letter-spacing:.01em;transition:all .2s;
}
.btn-primary{background:var(--signal);color:#fff}
.btn-primary:hover{background:var(--signal-deep);transform:translateY(-1px)}
.btn-ghost{border:1px solid rgba(239,235,226,.4);color:var(--bone);font-family:var(--mono);font-size:13.5px}
.btn-ghost:hover{border-color:var(--signal);color:var(--signal)}
.scroll-cue{
  margin-top:9vh;font-family:var(--mono);font-size:11px;letter-spacing:.2em;
  color:var(--slate);text-transform:uppercase;display:flex;align-items:center;gap:12px;
}
.scroll-cue i{display:block;width:1px;height:44px;background:linear-gradient(var(--signal),transparent);animation:drop 2s infinite}
@keyframes drop{0%{transform:scaleY(0);transform-origin:top}50%{transform:scaleY(1)}100%{transform:scaleY(0);transform-origin:bottom}}

/* Capability chips — the dual-capability proof, above the fold. */
.caps{
  list-style:none; display:flex; flex-wrap:wrap; gap:10px;
  margin:22px 0 0; padding:0;
}
.caps li{
  font-family:var(--mono); font-size:.72rem; letter-spacing:.09em;
  text-transform:uppercase; color:var(--bone);
  padding:7px 13px; border:1px solid var(--line);
  border-radius:2px; background:var(--panel);
  backdrop-filter:blur(3px);
  white-space:nowrap;
}
/* The accent chip carries a denser panel than its two cream siblings
   (.86 vs .72). Orange sits at 0.278 relative luminance against cream's
   0.833, so the alpha that holds cream far clear of AA leaves orange at
   4.83:1 over the lit-dock frames — passing, but a thin margin on the
   tightest element on the page. .86 restores it to 5.22:1. Measured off
   rendered pixels, not tokens: .scrim and .vignette are fixed siblings
   at z-index 1, so reading the canvas or walking ancestors misses them
   and understates the real backdrop. */
.caps li:nth-child(2){ border-color:rgba(255,85,0,.5); color:var(--signal);
  background:rgba(26,31,42,.88) }
@media (max-width:560px){
  .caps{ gap:8px }
  .caps li{ font-size:.66rem; padding:6px 10px }
}

/* Vertical jump-nav — same chip layout as .caps, but for a set of
   equally-weighted anchors (e.g. /specialized/'s five verticals). No
   per-item accent: unlike .caps, nothing here should read as emphasized
   over its siblings. Own class so it never inherits .caps's nth-child
   rule, and links are styled here directly instead of with inline styles. */
.vert-nav{
  list-style:none; display:flex; flex-wrap:wrap; gap:10px;
  margin:22px 0 0; padding:0;
}
.vert-nav li{
  font-family:var(--mono); font-size:.72rem; letter-spacing:.09em;
  text-transform:uppercase;
  padding:7px 13px; border:1px solid var(--line);
  border-radius:2px; background:var(--panel);
  backdrop-filter:blur(3px);
  white-space:nowrap;
}
.vert-nav a{ color:var(--bone); text-decoration:none; transition:color .2s }
.vert-nav a:hover,.vert-nav a:focus-visible{ color:var(--signal) }
@media (max-width:560px){
  .vert-nav{ gap:8px }
  .vert-nav li{ font-size:.66rem; padding:6px 10px }
}

/* ---------- CRED TICKER ---------- */
.ticker-wrap{
  position:relative;z-index:10;overflow:hidden;
  border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  background:var(--panel);backdrop-filter:blur(6px);
  padding:13px 0;
}
.ticker{display:flex;gap:0;white-space:nowrap;animation:tick 42s linear infinite;width:max-content}
.ticker span{
  font-family:var(--mono);font-size:12px;letter-spacing:.14em;color:var(--slate);
  text-transform:uppercase;padding:0 26px;
}
.ticker span b{color:var(--signal);font-weight:500;padding-right:26px}
@keyframes tick{to{transform:translateX(-50%)}}

/* ---------- PANELS ----------
   Not boxes. .panel is a layout container and nothing else: the fill,
   the blur, the border and the radius are all gone, because a box drawn
   over the footage is the thing the whole redesign is removing.

   Contrast comes from ::before — a gradient raked from whichever side the
   copy sits on, fading to zero before it reaches any edge, with a vertical
   mask so it has no horizontal edge either. There is no border, no corner
   and no boundary to perceive; it reads as type on a picture, which is
   what the hero has always done.

   z-index:-1 puts the wash under the panel's own type while staying inside
   main's stacking context (main is z-index:10), so it still paints above
   the fixed canvas at z-index 0. Same construction as .page-hero::before. */
.panel{
  padding:clamp(18px,2.2vw,30px) 0;
  max-width:1180px;margin:0 auto;
  position:relative;
}
.panel::before{
  content:'';position:absolute;z-index:-1;pointer-events:none;
  top:-6vh;bottom:-6vh;left:-9vw;right:-9vw;
  background:linear-gradient(100deg,
    rgba(8,10,15,.88) 0%,
    rgba(8,10,15,.74) 30%,
    rgba(8,10,15,.34) 62%,
    rgba(8,10,15,0)   86%);
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 14%,#000 86%,transparent 100%);
          mask-image:linear-gradient(to bottom,transparent 0,#000 14%,#000 86%,transparent 100%);
}
/* .panel-heavy no longer means "a darker box" — there are no boxes. It
   means a slightly stronger wash, for the sections carrying the densest
   type over the brightest frames.

   2026-09-24 — Task 8 investigated raising/extending these stops after
   #intro's .lede (to-left, not panel-heavy at the time) measured failing
   at 1.56-1.67:1. That first reading turned out to be mostly a measurement
   artifact (see the contrast-probe.py header for the opacity/reference-
   colour bug it was built on — .lede carries opacity:.86, which the first
   version of the probe didn't account for). Once the probe was corrected,
   #intro measured 2.46:1 with NO panel-heavy, 2.05:1 with panel-heavy at
   these original stops, and a best case of 2.82:1 with the stops pushed
   much further (0%/35%/68%/92%/100% at .94/.88/.64/.18/0) — still short of
   4.5:1 in every configuration tried. Since no amount of wash strength
   tested here clears it, and this project's stated bias is toward a
   LIGHTER page, panel-heavy was NOT added to #intro and these stops were
   left at their original values rather than kept darker for no measured
   benefit. See docs/verification/2026-09-24-lighter-site.md — #intro's
   .lede is recorded there as a genuine, not-yet-resolved shortfall. */
/* 2026-09-25 — `.panel.panel-heavy`, not the bare `.panel-heavy` this used
   to be. The old selector was (0,1,0) against `.panel::before`'s (0,1,0)
   and resolved on source order alone. It worked, but that is the identical
   fragility that left `.to-right`/`.to-wide`'s panel-heavy variants inert
   (see the two notes below): one reorder and it goes silently dead. Every
   element carrying panel-heavy also carries panel — checked across all 99
   pages, not assumed — so this is a specificity change with no match
   change. It still loses to `.panel.to-right::before`/`.panel.to-wide::before`
   (both (0,2,1), both later in source), which is the existing, intended
   behaviour: those two have their own panel-heavy rules at (0,3,1). */
.panel.panel-heavy::before{
  background:linear-gradient(100deg,
    rgba(8,10,15,.92) 0%,
    rgba(8,10,15,.82) 30%,
    rgba(8,10,15,.44) 62%,
    rgba(8,10,15,0)   88%);
}

/* ---------- SIDE PLACEMENT (homepage) ----------
   ~45vw with a readable ceiling, so the clear half of the frame stays
   clear. The wash rakes from the copy's side. Assignment per section is
   derived from the frame playing at that section's scroll position — see
   docs/superpowers/plans/2026-09-24-lighter-site.md Task 6. */
.panel.to-left,
.panel.to-right{
  max-width:min(45vw,620px);
}
.panel.to-left { margin-left:0;  margin-right:auto }
.panel.to-right{ margin-right:0; margin-left:auto  }
.panel.to-right::before{
  background:linear-gradient(260deg,
    rgba(8,10,15,.88) 0%,
    rgba(8,10,15,.74) 30%,
    rgba(8,10,15,.34) 62%,
    rgba(8,10,15,0)   86%);
}
/* 2026-09-24 — this used to be the SAME declaration as .to-right::before
   above (one rule, two selectors), which meant panel-heavy had no effect
   at all on #freight-band, the only .to-right section: its .lede
   measured 2.99:1 despite carrying the panel-heavy class. That IS a real
   CSS defect (fixed here — panel-heavy is now its own, working rule) —
   but the 2.99:1 reading itself was also inflated by the same probe bug
   noted above (.lede's own opacity:.86). With a corrected measurement
   AND this specificity fix alone — no extra alpha, no extended reach,
   same stops panel-heavy always had — #freight-band's .lede measures
   5.70:1, a clean pass. Tried pushing these stops further during
   investigation; it wasn't needed, so it isn't shipped — no reason to
   darken the page past what the corrected numbers ask for. */
.panel.to-right.panel-heavy::before{
  background:linear-gradient(260deg,
    rgba(8,10,15,.92) 0%,
    rgba(8,10,15,.82) 30%,
    rgba(8,10,15,.44) 62%,
    rgba(8,10,15,0)   88%);
}
/* 2026-09-25 — side placement is a DESKTOP-ONLY device. It shipped with no
   responsive reset at all, and min(45vw,620px) keeps resolving all the way
   down: measured sided-panel widths were 168.8px at a 375px viewport,
   186.3 at 414, 252 at 560, 345.6 at 768. At 375px that is a ~169px ribbon
   of copy inside a 337px content box — #intro's 431-character paragraph
   set ~21 characters to the line — and it does not even buy what it was
   for: at phone aspect ratio the 16:9 frame is cover-cropped to roughly
   its central 26%, which is almost entirely van, so there is no clear half
   to aim at. Below 900px the copy goes back to full width.

   900px is the line the rest of the design already draws: route.js
   switches to the frames-sm tier there, and .scrim (top of this file)
   flattens from a graded pass to an even wash at exactly this breakpoint —
   both are the same concession, that the cropped frame has no usable side.

   .to-right also swaps its 260deg rake for the .to-wide top/bottom wash:
   a rake that darkens the right edge is aimed at a half that no longer
   exists once the copy spans the full width, and it would leave the start
   of every line as the least-protected pixel on screen.

   #intro/#compliance's hand-fitted clamp() caps are released here too.
   They were derived from the van's on-screen x-position at 1100-1920px
   and are floor-bound (300px) everywhere below ~1171px, which inside a
   full-width phone or tablet column is just a second, narrower ribbon —
   300px of copy in a 691px box at 768. They fall back to .lede's own
   62ch measure, the same body-copy width every interior page uses. */
@media (max-width:900px){
  .panel.to-left,
  .panel.to-right{ max-width:100%; margin:0 }
  .panel.to-right::before,
  .panel.to-right.panel-heavy::before{
    background:linear-gradient(to bottom,
      rgba(8,10,15,0)   0%,
      rgba(8,10,15,.72) 16%,
      rgba(8,10,15,.80) 84%,
      rgba(8,10,15,0)   100%);
    -webkit-mask-image:none;mask-image:none;
  }
}
/* The four sections that cannot compress to a 620px column — the services
   grid, the coverage city grid, the FAQ list and the quote form. They keep
   full width and take a top/bottom wash instead of a raked one. */
.panel.to-wide{
  max-width:1180px;margin:0 auto;
}
.panel.to-wide::before{
  background:linear-gradient(to bottom,
    rgba(8,10,15,0)   0%,
    rgba(8,10,15,.72) 16%,
    rgba(8,10,15,.80) 84%,
    rgba(8,10,15,0)   100%);
  -webkit-mask-image:none;mask-image:none;
}
/* 2026-09-24 — like .to-right above, .to-wide had no distinct panel-heavy
   rule at all: `.panel.to-wide::before` (two classes) beats
   `.panel-heavy::before` (one class) on specificity regardless of source
   order, so #services and #quote's panel-heavy class was inert. #quote's
   .qform label (11px, the smallest type on the page) measured borderline
   4.26-4.65:1 against the daylight-arrival backdrop (frame 714, the
   brightest on the page) — this is a top/bottom wash, not a side one, so
   the fix here is just raising the peak alpha, not extending reach. */
.panel.to-wide.panel-heavy::before{
  background:linear-gradient(to bottom,
    rgba(8,10,15,0)   0%,
    rgba(8,10,15,.84) 16%,
    rgba(8,10,15,.90) 84%,
    rgba(8,10,15,0)   100%);
  -webkit-mask-image:none;mask-image:none;
}
h2{
  font-size:clamp(30px,3.6vw,52px);font-weight:800;line-height:1.06;
  letter-spacing:-.02em;font-variation-settings:'wdth' 110;
  max-width:22ch;
}
h2 em{font-style:normal;color:var(--signal)}
.lede{margin-top:20px;font-size:clamp(15px,1.25vw,17.5px);color:var(--bone);opacity:.86;max-width:62ch}
/* #compliance-only narrowing. Measured, not guessed: across the dawn/I-10
   frames this section's panel is on screen (~414 entry, ~429 mid, ~445
   exit), the van's left edge sits at roughly viewport-x 565-575px for the
   panel's second and third lines of body copy at a 1440px viewport. The
   section's normal .to-left column (620px, unmodified — every other
   to-left/to-right section measured clear at that width) let the last
   two lines' ragged right edge run onto the van's own cargo box and its
   ODP wordmark. Only .lede narrows here, not .panel: the heading/eyebrow
   were measured too (right edge stays under ~610px at the narrowest width
   tested) and clear the van with large margin at every width in this
   band without their own override.
   A flat 450px cap fixed the 1440px case but does NOT scale: the cap's
   own right edge moves at ~6vw (it inherits the section's 6vw padding as
   its left origin) while the van's on-screen position — a `cover`-fit
   crop sized to the full viewport — moves at a much steeper rate as the
   viewport narrows. Verified live at frame 429: a flat 450px cap
   overlaps the van again at 1366px and 1280px viewports, confirmed by
   screenshot, not assumed. Replaced with a value that itself scales with
   viewport width so the gap it holds open stays roughly constant:
   below ~1171px the column holds at a tested-safe 300px (checked clear
   up to 300px at 1100px wide); it then grows linearly to 450px by
   ~1439px, matching (with margin) the safe ceilings measured live at
   1100/1280/1366/1440/1680/1920px; above that the original 450px ceiling
   (extensively verified) still applies untouched. */
#compliance .lede{max-width:clamp(300px, calc(56vw - 356px), 450px)}
/* #intro-only narrowing, same approach as #compliance above, own
   coefficients — the geometry here is different (the bright feature is
   the van itself, filling roughly frame-x 0.35-0.86 across #intro's
   whole 19/36/54 entry/mid/exit span, not a single edge like
   #compliance's cargo box) and #compliance's own numbers do not apply.

   #intro has no eyebrow and no h2 — checked the source, not assumed:
   the section is a single <p class="lede">, nothing else to narrow or
   measure.

   Client decision 2026-09-24: narrow rather than out-darken. Wash-side
   fixes (panel-heavy, extended gradient reach) were tried first and
   measured — see the .panel-heavy::before comment above — and dropped
   because they did not clear AA and this project favours a lighter page.
   The unnarrowed 620px column measured 2.46-3.39:1 depending on wash
   configuration, at every width tested.

   Measured (self-consistent: scroll position recomputed after each
   candidate width, since narrowing reflows #intro's own height and
   therefore the whole page's scroll-to-frame mapping) at
   1100/1280/1366/1440/1680/1920px, entry/mid/exit frames checked in
   full at the narrowest and widest of those:

     1100  mid  (frame ~38)             300px → 4.44:1  (short, floor)
     1100  enter(frame ~23)             300px → 6.24:1
     1100  exit (frame ~53)             300px → 4.73:1
     1280  mid  (frame ~39)             300px → 4.76:1
     1366  mid  (frame ~40)             300px → 4.66:1
     1440  mid  (frame ~39)             300px → 5.29:1
     1680  mid  (frame ~39)          304.5px → 5.22:1
     1920  mid  (frame ~38)          319.9px → 4.84:1
     1920  enter(frame ~23)          319.9px → 6.50:1
     1920  exit (frame ~53)          319.9px → 4.53:1

   9 of 10 checkpoints clear 4.5:1. The one that doesn't — 1100 at the
   section's mid frame — is bound by the 300px floor (the narrowest width
   judged typographically reasonable, same floor #compliance uses) and
   misses by 0.06, not by a margin narrowing further would meaningfully
   close without going narrower than that floor. Reported as a residual,
   honestly-measured shortfall rather than pushed further — see
   docs/verification/2026-09-24-lighter-site.md. */
#intro .lede{max-width:clamp(300px, calc(6.4vw + 197px), 320px)}
/* Both caps above are van-clearance geometry, derived only at 1100-1920px
   and both pinned to their 300px floor below ~1171px. Below 900px there is
   no side placement left for them to protect (see the .to-left/.to-right
   reset above) and a 300px cap inside a full-width column is just a second
   ribbon. Released back to .lede's own 62ch measure — measured 337px at a
   375px viewport (the column itself is narrower than 62ch, so the cap is
   inert there) and ~440px at 768px, a normal line length rather than a
   300px one. Must stay after both rules above: same (1,1,0) specificity. */
@media (max-width:900px){
  #compliance .lede,
  #intro .lede{max-width:62ch}
}
/* Fix 1: prose links inside copy blocks. Before this rule, an anchor
   dropped into .lede (or any panel paragraph) fell through to the UA
   default — #0000EE, 1.98:1 against the panel. Palette-locked teal,
   underlined so it still reads as a link at a glance. */
.lede a,.panel p a{color:var(--signal);text-decoration:underline;text-underline-offset:2px}
.lede a:hover,.panel p a:hover,.lede a:focus-visible,.panel p a:focus-visible{color:var(--signal-deep)}
.checks{margin-top:26px;list-style:none;display:grid;gap:11px}
.checks li{display:flex;gap:12px;font-size:15px;align-items:flex-start}
.checks li::before{content:'—';color:var(--signal);font-weight:700;flex-shrink:0}

/* ---------- SERVICES ---------- */
/* minmax(min(N,100%),1fr) — NOT minmax(N,1fr). The bare form forces a
   track wider than the container on narrow screens; body{overflow-x:
   hidden} then clips the viewport rather than the element, so a
   document-level overflow check reports a clean 0 while content is
   genuinely cut off. Measured: this grid clipped 52px at a 371px
   viewport before the min() wrapper (same mistake, different grid, as
   .cov-grid below and assets/freight.css's .spec-table/.engage-grid). */
.svc-grid{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr));
  gap:30px 44px;margin-top:38px;
}
.svc{
  background:none;border:0;border-top:1px solid var(--line);border-radius:0;
  padding:22px 0 0;text-decoration:none;color:var(--bone);
  transition:border-color .2s,transform .2s;position:relative;overflow:hidden;
}
.svc:hover{border-top-color:var(--signal);transform:none}
.svc h3{font-size:20px;font-weight:750;letter-spacing:-.01em;font-variation-settings:'wdth' 108}
.svc p{margin-top:10px;font-size:14px;color:var(--slate);line-height:1.6}
.svc .tag{
  display:inline-block;margin-top:16px;font-family:var(--mono);font-size:10.5px;
  letter-spacing:.14em;color:var(--signal);border:1px solid rgba(255,85,0,.35);
  padding:4px 9px;border-radius:2px;text-transform:uppercase;
}
.svc .go{
  position:absolute;top:22px;right:22px;font-family:var(--mono);font-size:13px;
  color:var(--slate);transition:color .2s,transform .2s;
}
.svc:hover .go{color:var(--signal);transform:translateX(3px)}
.svc-freight{ border-top-color:rgba(255,85,0,.34) }
.svc-freight .tag{ color:var(--signal); border-color:rgba(255,85,0,.4) }
/* Fix 4: moved from assets/freight.css, which /courier/ and /dedicated/
   don't load — .svc-static was unreachable on those two pages, leaving
   their non-clickable <div class="svc svc-static"> cards with the hover
   lift and pointer affordance meant only for the real <a class="svc">
   links. Belongs in site.css since .svc itself lives here. */
.svc-static{ cursor:default }
.svc-static:hover{ transform:none }

/* Spec strip — mono numerics, the instrumentation language freight uses.

   2026-09-25 — this was the last opaque fill left inside <main> on the
   homepage: `.spec-strip > div{background:var(--asphalt-2)}` is #12161F at
   full alpha, a solid block sitting on the footage inside #freight-band,
   and the most conspicuous remaining box precisely because everything
   around it lost its fill in this redesign.

   It cannot simply drop the fill: the old construction painted var(--line)
   on the CONTAINER and used gap:1px to let it show through as separators,
   so transparent cells would have let that line colour wash the whole
   strip instead. Rebuilt on the same hairline-and-gap pattern .svc/.comp
   use — no container fill, a 1px rule above each cell, spacing from the
   grid gap. The data (truck dimensions, pallet counts) keeps its mono
   type and its label/value stack; only the box is gone.

   minmax(min(190px,100%),1fr), not the bare form it shipped with: the bare
   track clipped this grid by 23px at a 375px viewport on the homepage
   (recorded in docs/verification/2026-09-24-lighter-site.md §9 and left
   unfixed there), invisible to a document-level check because
   body{overflow-x:hidden}. Same rule as .svc-grid above. */
.spec-strip{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(190px,100%),1fr));
  gap:22px 44px; background:none; border:0;
  margin:30px 0 32px;
}
.spec-strip > div{ background:none; border-top:1px solid var(--line); padding:15px 0 0 }
.spec-strip dt{
  font-family:var(--mono); font-size:.66rem; letter-spacing:.12em;
  text-transform:uppercase; color:var(--slate); margin-bottom:7px;
}
.spec-strip dd{ font-family:var(--mono); font-size:1rem; color:var(--bone) }

/* ---------- PROCESS ---------- */
.steps{grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:30px 44px;margin-top:38px;display:grid}
.step{border-top:2px solid var(--signal);background:none;padding:22px 0 0;border-radius:0}
.step .n{font-family:var(--mono);font-size:12px;color:var(--signal);letter-spacing:.2em}
.step h3{margin-top:12px;font-size:19px;font-weight:750}
.step p{margin-top:10px;font-size:14px;color:var(--slate);line-height:1.6}
.modes-note{
  margin-top:26px;font-family:var(--mono);font-size:12.5px;color:var(--slate);
  letter-spacing:.05em;text-align:center;
}
.modes-note b{color:var(--signal);font-weight:500}

/* ---------- COMPLIANCE ---------- */
.comp-grid{grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));gap:30px 44px;margin-top:34px;display:grid}
.comp{background:none;border:0;border-top:1px solid var(--line);border-radius:0;padding:22px 0 0}
.comp h3{font-size:15.5px;font-weight:700;display:flex;gap:10px;align-items:center}
.comp h3::before{content:'';width:8px;height:8px;background:var(--signal);border-radius:1px;flex-shrink:0}
.comp p{margin-top:10px;font-size:13.5px;color:var(--slate);line-height:1.6}

/* ---------- MODES ---------- */
.modes{grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));gap:30px 44px;margin-top:38px;display:grid}
.mode{background:none;border:0;border-top:1px solid var(--line);border-radius:0;padding:22px 0 0;transition:border-color .2s}
.mode:hover{border-top-color:var(--pacific)}
/* Bare .m-tag, not .mode .m-tag — the freight page's engagement cards
   (.engage .m-tag, in assets/freight.css) use the same tag markup outside
   a .mode ancestor, and were rendering as unstyled plain text under the
   scoped selector. One rule serves both usages. */
.m-tag{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;color:var(--pacific);text-transform:uppercase}
.mode h3{margin-top:10px;font-size:21px;font-weight:750}
.mode p{margin-top:10px;font-size:14px;color:var(--slate);line-height:1.6}

/* ---------- QUOTE ---------- */
.quote-wrap{display:grid;grid-template-columns:1fr 1fr;gap:48px;align-items:start}
.q-contact{font-family:var(--mono);font-size:14px;display:grid;gap:14px;margin-top:28px}
.q-contact a{color:var(--signal);text-decoration:none}
.q-contact a:hover{text-decoration:underline}
.qform{display:grid;gap:12px}
.qform label{font-family:var(--mono);font-size:11px;letter-spacing:.14em;color:var(--slate);text-transform:uppercase}
.qform select,.qform input,.qform textarea{
  width:100%;background:rgba(8,10,15,.8);border:1px solid var(--line);border-radius:3px;
  color:var(--bone);font-family:var(--display);font-size:14.5px;padding:13px 14px;
  transition:border-color .2s;
}
.qform select:focus,.qform input:focus,.qform textarea:focus{outline:none;border-color:var(--signal)}
.qform button{
  background:var(--signal);color:#fff;border:none;border-radius:3px;
  font-family:var(--display);font-weight:800;font-size:15px;letter-spacing:.02em;
  padding:16px;cursor:pointer;transition:background .2s;margin-top:6px;
}
.qform button:hover{background:var(--signal-deep)}
.q-status{ font-family:var(--mono); font-size:.76rem; line-height:1.5; margin-top:6px; min-height:1em }
.q-status-ok{ color:var(--signal) }
.q-status-warn{ color:#FFB020 }
.q-status-err{ color:#FF7A6B }
.q-alt{font-family:var(--mono);font-size:12px;color:var(--slate);text-align:center;margin-top:4px}
.q-alt a{color:var(--signal);text-decoration:none}

/* ---------- CLIENT PORTAL (OnTime 360 embed, restyled) ---------- */
.qform input[type="submit"]{
  background:var(--signal);color:#fff;border:none;border-radius:3px;
  font-family:var(--display);font-weight:800;font-size:15px;letter-spacing:.02em;
  padding:16px;cursor:pointer;transition:background .2s;margin-top:6px;
}
.qform input[type="submit"]:hover{background:var(--signal-deep)}
.portal-form{max-width:420px;margin-top:28px}
.portal-powered{font-family:var(--mono);font-size:11px;color:var(--slate);margin-top:14px}
.portal-powered a{color:var(--slate);text-decoration:underline;text-underline-offset:2px}
.portal-powered a:hover{color:var(--signal)}

/* ---------- COVERAGE ---------- */
.cov-grid{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));
  gap:34px; margin-top:30px;
}
.cov h3{ font-size:1.05rem; margin-bottom:16px }
.lane-list > div{
  display:flex; justify-content:space-between; align-items:baseline;
  gap:16px; padding:11px 0; border-bottom:1px solid var(--line);
}
.lane-list dt{ font-size:.95rem }
.lane-list dd{
  font-family:var(--mono); font-size:.8rem; color:var(--signal); white-space:nowrap;
}

/* ---------- FOOTER ---------- */
footer{
  position:relative;z-index:10;background:#07090D;border-top:1px solid var(--line);
  padding:56px 6vw 32px;margin-top:0;
}
/* Full lockup over the footer columns. At 210px it still fits a 320px
   viewport, so it stays put at every width. */
.f-brand{display:block;max-width:1180px;margin:0 auto 40px}
.f-brand img{width:210px;height:auto;display:block}
/* minmax() takes min(190px,100%) — a bare 190px floor cannot shrink and
   silently overflows the grid under ~230px, which body{overflow-x:hidden}
   then hides from a document-level check. */
.f-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(190px,100%),1fr));gap:36px;max-width:1180px;margin:0 auto}
.f-grid h4{font-family:var(--mono);font-size:11px;letter-spacing:.18em;color:var(--slate);text-transform:uppercase;margin-bottom:16px}
.f-grid ul{list-style:none;display:grid;gap:9px}
.f-grid a{color:var(--bone);opacity:.75;text-decoration:none;font-size:13.5px}
.f-grid a:hover{opacity:1;color:var(--signal)}
.f-bottom{
  max-width:1180px;margin:44px auto 0;padding-top:22px;border-top:1px solid var(--line);
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px;
  font-family:var(--mono);font-size:11px;color:var(--slate);letter-spacing:.05em;
}
.f-bottom a{color:inherit;text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
.f-bottom a:hover{color:var(--signal);text-decoration-color:currentColor}

/* ---------- RESPONSIVE / A11Y ---------- */
/* Global link colour. Until now no bare a{} rule existed, so any link inside
   body copy fell through to the browser default blue — invisible while the
   site was nav + footer, glaring once pages carried in-content links. */
main a{color:var(--signal);text-decoration:none;border-bottom:1px solid rgba(255,85,0,.35);transition:border-color .2s,color .2s}
main a:hover{color:var(--signal-deep);border-bottom-color:var(--signal)}
/* components that style their own links opt out of the underline */
main .sv-cross a,main .checks a,main .city-grid a,main .crumbs a,main .quote-wrap a,
main .sv-card h3 a,main .nav-cta,main .lane-table a{border-bottom:none}
main .sv-card h3 a{color:inherit}
main .crumbs a{color:var(--slate)}

a:focus-visible,button:focus-visible{outline:2px solid var(--signal);outline-offset:3px}
/* Fix 5: the nav's own breakpoint, deliberately NOT the 920px one below.
   A single row needs logo (304px) + links (814px) + padding (64px) = 1182px,
   rounded to 1200px. The 2026-09-28 logo swap widened the logo to 328px;
   re-measured in a 1201px iframe it still fits one row with no overflow. Below that the links now collapse behind a menu button
   rather than wrapping onto extra rows: the old wrapped layout ran three rows
   and 136-138px tall on phones, which is what forced the #hero clearance
   workarounds further down. Re-measure this number if the nav's top-level
   items change. section/.quote-wrap stay on 920px — they are unrelated
   to the nav's width budget and look wrong if dragged up with it. */
@media (max-width:1200px){
  nav{padding:14px 18px}
  .nav-toggle{display:inline-flex}
  /* The link list becomes a panel under the bar. It is absolutely positioned
     so the fixed bar itself stays one row tall at every width, which is what
     keeps --nav-h (and the #hero clearance that reads it) stable. */
  .nav-links{
    display:none;
    position:absolute;top:100%;left:0;right:0;
    flex-direction:column;align-items:stretch;gap:0;
    padding:4px 18px 20px;
    /* opaque for the same reason as .nav-panel above — nav.open's own
       backdrop-filter makes any blur requested here a no-op */
    background:#161B25;
    border-top:1px solid var(--line);border-bottom:1px solid var(--line);
    max-height:calc(100vh - var(--nav-h, 62px));overflow-y:auto;
  }
  nav.open .nav-links{display:flex}
  .nav-links > li{border-bottom:1px solid var(--line)}
  .nav-links > li:last-child,.nav-links > li:nth-last-child(2){border-bottom:none}
  .nav-links > li > a{display:block;padding:13px 0;font-size:14px}
  .nav-caret{display:none}
  /* dropdowns stop being dropdowns — every child link is simply listed */
  .nav-panel{
    position:static;display:block;min-width:0;
    opacity:1;visibility:visible;transform:none;
    padding:0 0 14px;
    background:none;backdrop-filter:none;border:none;border-radius:0;box-shadow:none;
  }
  .nav-panel::before{display:none}
  .nav-col + .nav-col{margin-top:13px}
  .nav-col h5{margin-left:0}
  .nav-col a{white-space:normal;font-size:13px;opacity:.72;margin:0;padding:7px 0 7px 14px}
  .nav-col a:hover,.nav-col a:focus-visible{background:none}
  /* the marker turns into a left rule, since there is no baseline to sit under */
  .nav-links > li > a[aria-current="page"]::after,
  .nav-links > li > a[data-active]::after{
    left:-18px;right:auto;top:0;bottom:0;width:2px;height:auto;
  }
  .nav-phone{display:block;padding:14px 0;font-size:12.5px}
  .nav-cta{display:block;margin-top:16px;padding:12px 18px;font-size:13.5px;text-align:center}
}
@media (max-width:920px){
  .quote-wrap{grid-template-columns:1fr}
  section{padding:0 5vw}
}
/* Fix 4: below ~490px the wrapped nav (see Fix 3 above) runs 136-138px
   tall — taller than #hero's fixed padding-top:100px — so the fixed nav
   overlapped the homepage eyebrow line. #hero is flex-centered with
   min-height:100vh, so at these narrow widths the tall wrapped h1 already
   forces the box past 100vh and centering stops applying: padding-top
   maps ~1:1 onto the eyebrow's actual position. This value is coupled to
   the wrapped nav's height — if the nav's wrapped height changes, re-check
   clearance here (see verification method in nav-overlap-fix-report.md). */
@media (max-width:490px){
  /* Historic Fix 4 floor. The max() above already clears the measured nav,
     but this keeps the extra breathing room the narrow layout was tuned
     with, and holds if JS never runs. */
  #hero{padding-top:max(170px, calc(var(--nav-h, 139px) + 20px))}
}
@media (max-width:400px){
  nav{padding:12px 14px}
  .nav-links{padding:4px 14px 18px}
  .nav-toggle{padding:8px 11px;font-size:10px;gap:8px}
  .nav-links > li > a[aria-current="page"]::after,
  .nav-links > li > a[data-active]::after{left:-14px}
}
@media (prefers-reduced-motion:reduce){
  .ticker{animation:none}
  .scroll-cue i{animation:none}
  html{scroll-behavior:auto}
}
