@charset "utf-8";
/* ==========================================================================
   LFG Freight Solutions — v2, photographic direction.

   Palette sampled directly from the client's flyer PNG, not eyeballed:
     navy  #001F4C   orange #FD5A01   paper #F6F6F6   white #FFFFFF

   Display face is Bebas Neue at weight 400 only. There is no bold cut; a
   heavier weight triggers faux-bold synthesis and breaks the mark. Every rule
   that sets the display face also sets font-weight: 400 — including headings
   and th, which default to bold.

   Contrast pairs in use, all measured, all AA:
     white  on navy   #001F4C   16.2 : 1
     orange on navy             5.11 : 1
     navy   on orange           5.11 : 1
     navy   on paper  #F6F6F6   14.9 : 1
     navy   on white            16.7 : 1
   White on orange is only 3.16 : 1 and is therefore NOT used for text
   anywhere — the orange band and the orange button both take navy type.
   ========================================================================== */

/* --------------------------------------------------------------- fonts -- */
@font-face {
  font-family: 'Bebas Neue';
  src: url('../fonts/bebas-neue-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* -------------------------------------------------------------- tokens -- */
:root {
  --navy: #001F4C;
  --navy-deep: #00132F;
  --orange: #FD5A01;
  --orange-soft: #FF7A33;
  --paper: #F6F6F6;
  --white: #FFFFFF;
  --ink: #10192B;
  --muted: #4A5568;
  --go: #24D07A;
  --footer-bg: #E9EBEF;   /* off-white, cool enough to sit under the navy bar */

  --wrap: 1180px;
  /* The hero is a composition over a photograph, not a column of reading text.
     1180px centred works down the page but on an ultrawide frame it drags the
     headline into the middle of the trailer, when the artwork's clean area is
     an L: the top third full width plus the left third full height. Letting the
     hero container track the frame keeps the headline inside that left third at
     3440 while staying symmetric — the padding is equal on both sides, the
     container is simply wider. */
  --wrap-hero: clamp(1180px, 88vw, 1680px);
  --pad: clamp(20px, 5vw, 48px);
  --rule: 3px;

  /* Height of the sticky tap-to-call bar. Zero above the phone breakpoint so
     every dependent calculation collapses to nothing on desktop. */
  --callbar-h: 0px;

  --display: 'Bebas Neue', 'Haettenschweiler', 'Arial Narrow', Impact, sans-serif;
  --text: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
          Arial, 'Noto Sans', sans-serif;
}

@media (max-width: 767px) {
  :root { --callbar-h: 58px; }
}

/* ---------------------------------------------------------------- base -- */
*, *::before, *::after { 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(--white);
  color: var(--ink);
  font-family: var(--text);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* Keep the sticky call bar off the last of the footer. The bar grows by the
     safe-area inset on a notched phone, so the reservation has to grow with it
     or the last footer line ends up underneath. */
  padding-bottom: calc(var(--callbar-h) + env(safe-area-inset-bottom, 0px));
}

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

h1, h2, h3, h4, h5, h6 {
  font-family: var(--display);
  font-weight: 400;              /* Bebas Neue has no bold cut. Never raise. */
  margin: 0;
  line-height: 1.02;
  letter-spacing: 0.012em;
  /* The client's flyer is set in uniform caps. The markup stays sentence case
     so the copy reads and copies correctly; the caps are presentational. */
  text-transform: uppercase;
}

p { margin: 0 0 1em; }
ul, ol { margin: 0; padding: 0; list-style: none; }

:focus-visible {
  outline: 3px solid var(--orange);
  outline-offset: 3px;
  border-radius: 2px;
}
.hero :focus-visible,
.band--navy :focus-visible,
.band--deep :focus-visible,
.site-footer__bar :focus-visible { outline-color: var(--white); }
.band--orange :focus-visible { outline-color: var(--navy); }

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--navy);
  color: var(--white);
  border-bottom: 4px solid var(--orange);
  padding: 14px 20px;
  font: 400 20px/1 var(--display);
  letter-spacing: 0.08em;
}
.skip:focus { left: 12px; top: 12px; }

.vh {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* --------------------------------------------------------- scaffolding -- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);   /* symmetric left / right, always */
}

.band { padding-block: clamp(66px, 9vw, 120px); }
.band--navy   { background: var(--navy); color: var(--white); }
.band--deep   { background: var(--navy-deep); color: var(--white); }
.band--paper  { background: var(--paper); color: var(--ink); }
.band--white  { background: var(--white); color: var(--ink); }
.band--orange { background: var(--orange); color: var(--navy); }

.h2 {
  font-size: clamp(40px, 6.4vw, 72px);
  max-width: 20ch;
}
.rule {
  width: 104px;
  height: var(--rule);
  background: var(--orange);
  border: 0;
  margin: 24px 0 0;
}
.band--navy .rule, .band--deep .rule { background: var(--orange); }

/* ------------------------------------------------------------ masthead -- */
.masthead {
  position: absolute;
  inset: 0 0 auto 0;
  z-index: 30;
  padding-block: clamp(18px, 2.6vw, 30px);
  pointer-events: none;
}
.masthead .wrap { display: flex; align-items: center; max-width: var(--wrap-hero); }
.masthead img {
  width: clamp(150px, 17vw, 236px);
  height: auto;
  filter: drop-shadow(0 2px 16px rgba(0, 0, 0, .7));
}

/* ==========================================================================
   1 — HERO
   ========================================================================== */
.hero {
  position: relative;
  height: 100vh;
  min-height: 600px;
  isolation: isolate;
  background: var(--navy-deep);
  color: var(--white);
  overflow: hidden;
}
@supports (height: 100svh) { .hero { height: 100svh; } }

/* 112% tall so the parallax has somewhere to travel without ever exposing an
   edge. With the script blocked the offset is zero, which is exactly the
   intended first view — the parallax only ever moves the art *up*. */
.hero__art {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 112%;
  z-index: 0;
  will-change: transform;
}
.hero__art picture { display: block; width: 100%; height: 100%; }
.hero__art img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center center;
  /* The portrait frame is measurably darker than the landscape one through the
     zone the copy sits in: mean luminance of the top third is 51.9 against
     58.8 on the desktop frame (8-bit grey, measured off the sources). A small
     lift keeps it from going muddy on a phone in daylight. Removed again at
     the desktop-art breakpoint below, where it is not needed. */
  filter: brightness(1.08) saturate(1.04);
}

/* Two scrims. Both are load-bearing, and both are pinned to measurements taken
   off the source artwork rather than guessed:

   VERTICAL. The foreground road carries a bright orange reflection across the
   bottom quarter of both frames — specular highlights clipping to 255 in rows
   70–90% of the landscape frame and rows 60–80% of the portrait one. That is
   exactly where the sticky call bar, the equipment strip and the actions sit,
   so it is darkened here rather than by regenerating the art.

   HORIZONTAL. The headline sits upper-left, in the artwork's clean L. The left
   third of the landscape frame peaks at luminance 165 where the sunset meets
   the horizon; white type over that alone is 2.5:1. The left scrim takes the
   worst case to 8.2:1 and leaves the truck, which is right of centre, clean. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
/* Portrait frame. Its top third is already dark (mean luminance 42–49), so the
   headline only needs a light touch up there — .34 takes the worst pixel in
   that zone to 11.7 : 1 for white and 4.5 : 1 for the orange accent, and keeps
   the sky reading as sky. The weight goes where it is actually needed: the road
   reflection across the bottom quarter, under the strip and the call bar. */
.hero__scrim--v {
  background: linear-gradient(to bottom,
    rgba(0, 19, 47, .34) 0%,
    rgba(0, 19, 47, .12) 26%,
    rgba(0, 19, 47, .00) 46%,
    rgba(0, 19, 47, .16) 62%,
    rgba(0, 19, 47, .58) 78%,
    rgba(0, 19, 47, .90) 100%);
}
.hero__scrim--h { display: none; }

/* Must stay identical to the media attribute on the hero <source> elements and
   to the desktopArt matchMedia string in site.js. All three swap together. */
@media (min-width: 1024px) and (min-aspect-ratio: 1/1) {
  .hero__art img { filter: none; }
  .hero__scrim--v {
    background: linear-gradient(to bottom,
      rgba(0, 19, 47, .40) 0%,
      rgba(0, 19, 47, .08) 22%,
      rgba(0, 19, 47, .06) 52%,
      rgba(0, 19, 47, .34) 68%,
      rgba(0, 19, 47, .74) 84%,
      rgba(0, 19, 47, .92) 100%);
  }
  .hero__scrim--h {
    display: block;
    background: linear-gradient(to right,
      rgba(0, 19, 47, .62) 0%,
      rgba(0, 19, 47, .40) 30%,
      rgba(0, 19, 47, .00) 58%);
  }
}

.hero__inner {
  position: relative;
  z-index: 3;
  height: 100%;
  display: flex;
  flex-direction: column;
  /* Clears the masthead lockup with air to spare — the headline must never
     crowd the logo it sits under. Deliberately tighter on phones, where every
     pixel the copy gives back is a pixel of truck. */
  padding-top: clamp(112px, 14vh, 140px);
  padding-bottom: calc(var(--callbar-h) + env(safe-area-inset-bottom, 0px) + 12px);
}

.hero__copy, .hero__actions, .equip__row { max-width: var(--wrap-hero); }

.hero h1 {
  font-size: clamp(42px, 8.4vw, 92px);
  line-height: .96;
  max-width: 18ch;
  text-wrap: balance;
}
.hero h1 .accent { color: var(--orange-soft); }

.hero__sub {
  margin: 20px 0 0;
  font-size: clamp(17px, 1.6vw, 21px);
  line-height: 1.55;
  max-width: 40ch;
  color: #E4EDF9;
  font-weight: 600;
}

/* Two actions, equal weight. The form and the phone. Drivers call — the number
   is never buried behind a link. */
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: auto;             /* phones: sit low, over the scrimmed road */
}
@media (min-width: 1024px) and (min-aspect-ratio: 1/1) {
  .hero__inner { padding-top: clamp(140px, 20vh, 216px); }
  .hero__actions { margin-top: clamp(30px, 4vh, 48px); gap: 16px; }
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex: 1 1 auto;
  min-width: 230px;
  min-height: 54px;
  padding: 13px 28px;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(24px, 2.6vw, 31px);
  letter-spacing: .05em;
  text-transform: uppercase;
  text-decoration: none;
  border: var(--rule) solid transparent;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
@media (min-width: 620px) { .btn { flex: 0 0 auto; min-height: 60px; padding: 15px 30px; } }

.btn--go   { background: var(--orange); color: var(--navy); border-color: var(--orange); }
.btn--call { background: var(--white);  color: var(--navy); border-color: var(--white); }
.btn--go:hover, .btn--go:focus-visible {
  background: transparent; color: var(--orange); border-color: var(--orange);
}
.btn--call:hover, .btn--call:focus-visible {
  background: transparent; color: var(--white); border-color: var(--white);
}
.btn__ico { width: 24px; height: 24px; fill: currentColor; flex: 0 0 auto; }

/* Equipment strip — thin, along the bottom edge of the frame. */
.equip {
  border-top: 1px solid rgba(255, 255, 255, .22);
  padding-top: 12px;
  margin-top: clamp(16px, 2.4vh, 30px);
}
.equip__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 20px;
}
.equip__label {
  font-family: var(--display);
  font-weight: 400;
  font-size: 13px;             /* a label, not reading text — floor is 11px */
  letter-spacing: .24em;
  text-transform: uppercase;
  color: #9FB6D4;
}
.equip__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 18px;
}
.equip__list li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(14px, 1.5vw, 19px);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--white);
}
/* The studio's emblems are 8:5 (viewBox 0 0 256 160), not square. A square box
   letterboxes them: 21x21 delivered 21x13 of actual artwork. The box matches
   the artwork's ratio so nothing is thrown away.

   Size is a judgement, made against the studio's own specimen renders rather
   than a rule. At 21px dry van and reefer collapse into the same smudge and the
   hotshot is a smear; the set starts resolving at 26px; it is clean at 62px,
   the studio's designed minimum. 44px sits well clear of the point where all
   five separate while keeping this a strip along the hero's edge rather than a
   band competing with the headline. Below 40px the hotshot is the first to go. */
.equip__emb {
  /* Height-driven, width auto. The client's flyer draws these at differing
     widths on a shared height (power only is short, flatbed is long) and each
     wrapper carries its own viewBox, so letting width follow height keeps that
     relationship exactly as he drew it. */
  height: 22px;
  width: auto;
  flex: 0 0 auto;

  /* The studio's emblems are themed through five custom properties. Nothing was
     setting them, so every part fell back to navy and the whole set vanished
     into the navy strip. This is the dark-ground pairing from the studio's own
     specimen: body, ground, hub and tyre in paper, the single accent in orange.
     Note the naming trap the studio flagged: --emblem-ground is the GROUND BAR
     under the vehicle, and it follows the body colour. It is not a background. */
  --emblem-body:   var(--paper);
  --emblem-ground: var(--paper);
  --emblem-hub:    var(--paper);
  --emblem-tyre:   var(--paper);
  --emblem-accent: var(--orange);
}

/* Desktop pins the strip to the bottom edge of the frame. This block has to sit
   *after* the base .equip rule — same specificity, so source order decides.
   The interpuncts are added only here, where the strip is a single row. On a
   phone the five names wrap, and a separator stranded at the start of a new
   row reads as a bullet nobody asked for; spacing carries it instead. */
@media (min-width: 1024px) and (min-aspect-ratio: 1/1) {
  .equip { margin-top: auto; padding-top: 14px; }
  .equip__emb { height: 28px; width: auto; }
}
/* Wide enough that the five names are certain to hold a single row. */
@media (min-width: 860px) {
  .equip__list li + li::before {
    content: '·';
    margin-right: 16px;
    color: rgba(255, 255, 255, .45);
  }
}

/* Placeholder frames only. The real emblems arrive as a studio sprite and are
   inlined by tools/build-assets.py, at which point this rule stops matching. */
.emb-ph {
  fill: none;
  stroke: currentColor;
  stroke-width: 3;
  stroke-dasharray: 5 5;
  opacity: .6;
}

/* ==========================================================================
   2 — PROMISE BAND
   ========================================================================== */
.promise__grid {
  display: grid;
  gap: clamp(30px, 4vw, 60px);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 900px) {
  .promise__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
}
.promise .h2 { font-size: clamp(46px, 7.4vw, 84px); }

.wins { display: grid; }
.wins li {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 15px 0;
  border-bottom: 1px solid rgba(255, 255, 255, .16);
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(29px, 4vw, 46px);
  line-height: 1.06;
  letter-spacing: .02em;
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .55s ease, transform .55s cubic-bezier(.2, .7, .3, 1);
  transition-delay: calc(var(--i) * 85ms);
}
.wins li:first-child { border-top: 1px solid rgba(255, 255, 255, .16); }
.is-in .wins li { opacity: 1; transform: none; }
.wins__bar {
  flex: 0 0 auto;
  width: 26px;
  height: var(--rule);
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .5s cubic-bezier(.2, .7, .3, 1);
  transition-delay: calc(var(--i) * 85ms + 140ms);
}
.is-in .wins__bar { transform: scaleX(1); }

/* ==========================================================================
   3 — WHAT WE HANDLE. The green line lives here and nowhere else.
   ========================================================================== */
.run {
  position: relative;
  margin-top: clamp(30px, 4vw, 52px);
}

/* Two coincident lines: the grey track, and the green fill drawn on top with
   stroke-dashoffset — the same mechanic v1 used, driven from scroll progress.

   The viewBox is 2 x 1000 in a box that is exactly 2px wide, so the x scale is
   exactly 1 and stroke-width: 2 lands as 2 real pixels with no help. The y
   scale stretches 1000 user units over the full height, which is precisely
   what makes stroke-dasharray: 1000 equal "the whole line".

   Do NOT add vector-effect: non-scaling-stroke here. It was tried, and under a
   non-uniform viewBox it takes the dash pattern out of user space, so offset
   1000 renders as a fully drawn line and the fill never appears to move. */
.run__line {
  position: absolute;
  left: 8px;          /* 8px box centred on the 24px marker column */
  top: 0;
  width: 8px;
  height: 100%;
  overflow: visible;
}
.run__base { stroke: rgba(16, 25, 43, .16); stroke-width: 6; stroke-linecap: round; }
.run__go {
  stroke: var(--go);
  stroke-width: 6;
  stroke-linecap: round;
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
}

.run__list { display: grid; }
.run__list li {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr);
  align-items: center;
  gap: clamp(18px, 2.6vw, 30px);
  padding: clamp(15px, 2.2vw, 22px) 0;
}
.run__list li + li { border-top: 1px solid rgba(16, 25, 43, .10); }
.run__list h3 {
  font-size: clamp(23px, 3vw, 36px);
  letter-spacing: .02em;
  color: var(--navy);
}

.run__dot {
  display: block;
  width: 24px; height: 24px;
  background: var(--paper);
  border-radius: 50%;
  /* The line is absolutely positioned, so without this it paints OVER every
     marker and runs straight through them. */
  position: relative;
  z-index: 1;
}
.run__dot svg { width: 24px; height: 24px; }
/* A status light, not a tick. A lamp sitting on the line reads as a dispatch
   board; a checkmark always fights the line it sits on. */
.run__ring {
  fill: var(--paper);
  stroke: rgba(16, 25, 43, .22);
  stroke-width: 2;
  transition: stroke .3s ease;
}
.run__lamp {
  fill: rgba(16, 25, 43, .13);
  transition: fill .35s ease, filter .35s ease;
}
.run__list li.is-done .run__ring { stroke: var(--go); }
.run__list li.is-done .run__lamp {
  fill: var(--go);
  filter: drop-shadow(0 0 5px rgba(36, 208, 122, .85));
}

/* ==========================================================================
   4 — WHY WORK WITH US
   ========================================================================== */
.why__grid {
  display: grid;
  gap: clamp(28px, 3.6vw, 44px);
  grid-template-columns: 1fr;
  margin-top: clamp(34px, 4vw, 56px);
}
@media (min-width: 620px)  { .why__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .why__grid { grid-template-columns: repeat(4, 1fr); } }

/* These are cards, so they are built as cards rather than dressed as section
   heads. No rule: a rule under each one produced a second horizontal directly
   below the section rule and read as two stray lines.

   The base is cut at the same oblique as the LFG letterforms and the swoosh in
   the client's own logo, so the form is derived from his mark rather than
   invented, and it reads as motion without a speed line.

   --cut is the depth of that slant at the left edge, where it bites deepest.
   The bottom padding clears it explicitly, or the last line of copy sits in the
   wedge. Cards stretch to a common height so the cut is consistent across all
   four despite the copy wrapping to different depths. */
.why__item {
  --card-pad: clamp(26px, 2.4vw, 32px);
  --cut: 26px;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--navy);
  color: var(--white);
  border: 0;
  padding: var(--card-pad);
  padding-bottom: calc(var(--card-pad) + var(--cut) + 12px);
  clip-path: polygon(0 0, 100% 0, 100% 100%, 0 calc(100% - var(--cut)));
}
.why__item p { margin-bottom: 0; }
.why__grid { align-items: stretch; }
.why__item h3 {
  font-size: clamp(26px, 2.6vw, 33px);
  color: var(--white);
  letter-spacing: .025em;
  max-width: 12ch;
  margin-bottom: auto;      /* copy sits to the base, headings top-align */
}
.why__item p {
  margin: 12px 0 0;
  font-size: 17px;
  line-height: 1.6;
  color: #BDCCE4;
  max-width: 26ch;
}

/* ==========================================================================
   5 — NO CATCH. Fear removal. Loud, and carries no heading of ours.
   ========================================================================== */
.nocatch__list {
  display: grid;
  gap: 0;
}
.nocatch__list li {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(34px, 6.2vw, 74px);
  line-height: 1.04;
  letter-spacing: .015em;
  text-transform: uppercase;
  /* Was navy on an orange band. Orange is an accent, never a surface: white on
     navy is 16.2:1 against navy on orange at 5.11:1, and it stops a full orange
     band competing with the orange CTA. The rules keep the orange. */
  color: var(--white);
  padding: clamp(14px, 2vw, 22px) 0;

  /* A hairline, not a rule. Orange at 3px on this band fought the type and the
     CTA; lane markings were worse. At 74px the Bebas caps already separate
     themselves, so the divider only has to organise, not decorate. */
  border: 0;
  border-bottom: 1px solid rgba(246, 246, 246, .18);
}
/* No divider above the first item: the orange section rule already sits there. */

/* ==========================================================================
   6 — THE ASK
   ========================================================================== */
.ask__grid {
  display: grid;
  gap: clamp(38px, 5vw, 64px);
  grid-template-columns: 1fr;
  align-items: start;
  margin-top: clamp(34px, 4vw, 52px);
}
@media (min-width: 980px) {
  .ask__grid { grid-template-columns: minmax(0, .82fr) minmax(0, 1.18fr); }
}

.ask__sub {
  font-size: clamp(26px, 3vw, 34px);
  letter-spacing: .05em;
  color: var(--orange-soft);
}
.ask__lines { margin: 18px 0 30px; display: grid; gap: 14px; }
.ask__tel {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(38px, 5.4vw, 58px);
  letter-spacing: .02em;
  color: var(--white);
  text-decoration: none;
  display: inline-block;
}
.ask__tel:hover { color: var(--orange-soft); }
/* The address stays in the text face and in lower case on purpose: the local
   part of an email address is case-sensitive and must never be shown in caps. */
.ask__mail {
  font-size: clamp(18px, 2vw, 22px);
  font-weight: 700;
  color: #DCE6F4;
  text-decoration: none;
  border-bottom: 2px solid var(--orange);
  padding-bottom: 3px;
  word-break: break-word;
}
.ask__mail:hover { color: var(--white); }

/* One per row. Flex-wrap packed these by width, and because the four labels are
   very different lengths it produced a ragged 2 / 1 / 1. A single column is also
   what .ask__lines above it does, so the whole side column now reads as one
   stack instead of two competing rhythms. */
.assurances {
  display: grid;
  gap: 11px;
}
.assurances li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 16px;
  line-height: 1.5;
  color: #C3D3E8;
  font-weight: 600;
}
.assurances .dot { width: 9px; height: 9px; background: var(--go); flex: 0 0 auto; }

.apply__frame {
  margin-top: 18px;
  border: 1px solid rgba(255, 255, 255, .18);
  background: var(--white);
}
/* Jotform's jsform embed builds and SIZES its own iframe. Deliberately no
   height or min-height here: a fixed height fought Jotform's own sizing and
   left the form clipped and mis-laid-out. Width and border only. */
.apply__frame iframe {
  display: block;
  width: 100%;
  border: 0;
}
.apply__fallback {
  margin: 16px 0 0;
  font-size: 16px;
  color: #C3D3E8;
}
.apply__fallback a { color: var(--white); font-weight: 700; }

/* ==========================================================================
   7 — FOOTER
   ========================================================================== */
/* The footer runs light so the full-colour lockup can be used instead of the
   white knockout. The tagline bar stays dark: it closes the navy run of the page
   and gives the light block an edge to sit against rather than a raw seam.
   Measured contrast on #E9EBEF: navy 13.3:1, --muted #4A5568 7.0:1. */
.site-footer { background: var(--footer-bg); color: var(--navy); }
.site-footer__bar {
  background: var(--navy-deep);
  /* The footer runs light now, so the bar has to restate its own colour or it
     inherits navy onto navy and disappears. */
  color: var(--white);
  padding: 22px var(--pad);
  text-align: center;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(19px, 2.4vw, 30px);
  letter-spacing: .06em;
  text-transform: uppercase;
  line-height: 1.3;
}
.site-footer__bar em { font-style: normal; color: var(--orange); }

.site-footer__main { padding-block: clamp(40px, 5vw, 64px); }
.site-footer__stack {
  display: grid;
  gap: 24px;
  justify-items: center;
  text-align: center;
}
.site-footer__stack img { width: clamp(180px, 22vw, 230px); }
.motto {
  margin: 0;
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(22px, 2.8vw, 32px);
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--navy);
}
.legal {
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  justify-content: center;
  font-size: 15px;
  color: var(--muted);
  line-height: 1.6;
}
.legal a { color: var(--muted); }

/* ==========================================================================
   STICKY TAP-TO-CALL — phones only, present throughout.
   ========================================================================== */
.callbar { display: none; }
@media (max-width: 767px) {
  .callbar {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 120;
    height: var(--callbar-h);
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    background: var(--orange);
    color: var(--navy);          /* 5.11 : 1 — white would be 3.16 : 1 */
    text-decoration: none;
    font-family: var(--display);
    font-weight: 400;
    font-size: 26px;
    letter-spacing: .06em;
    border-top: var(--rule) solid var(--navy);
    padding-bottom: env(safe-area-inset-bottom);
    box-sizing: content-box;
  }
  .callbar svg { width: 21px; height: 21px; fill: currentColor; }
}

/* ------------------------------------------------------- reveal states -- */
.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .7s ease, transform .7s cubic-bezier(.2, .7, .3, 1);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.reveal.is-in, .is-in .reveal { opacity: 1; transform: none; }

/* ------------------------------------------------------- no javascript -- */
/* The page must be complete and legible with the script blocked. Everything
   that would otherwise wait for an observer resolves to its finished state. */
.no-js .reveal { opacity: 1; transform: none; }
.no-js .wins li { opacity: 1; transform: none; }
.no-js .wins__bar { transform: scaleX(1); }
.no-js .run__go { stroke-dashoffset: 0; }
.no-js .run__ring { stroke: var(--go); }
.no-js .run__lamp { fill: var(--go); }

/* ---------------------------------------------------- reduced motion -- */
/* Everything resolves to its finished state. All copy legible, both calls to
   action reachable, nothing depends on an animation having run. The parallax
   is not merely slowed here — site.js never binds it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }
  .reveal, .wins li { opacity: 1 !important; transform: none !important; }
  .wins__bar { transform: scaleX(1) !important; }
  .run__go { stroke-dashoffset: 0 !important; }
  .run__ring { stroke: var(--go) !important; }
  .run__lamp { fill: var(--go) !important; }
}
