/* ==========================================================================
   Webfonts — self-hosted, latin subset, variable
   Served from this origin instead of fonts.googleapis.com: one fewer DNS
   lookup and TLS handshake, no render-blocking third-party stylesheet, and no
   visitor IP address handed to Google on every page view.

   Both families are SIL Open Font License 1.1; the license texts sit beside
   the files in assets/fonts/. The weight ranges below are each font's real
   variable axis, so every weight used on the site is a true master rather
   than a browser-synthesised approximation.
   ========================================================================== */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-var-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("../fonts/playfair-var-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Playfair Display";
  font-style: italic;
  font-weight: 400 900;
  font-display: swap;
  src: url("../fonts/playfair-var-italic-latin.woff2") format("woff2");
}

/* ==========================================================================
   Black Tie Concierge — design system
   Hand-authored. No framework, no CDN stylesheet. One file for the whole site.

   Color contract (WCAG 2.2 AA, measured against --ink #0A0A0B):
     --bone        15.6:1   headings, primary text
     --muted        7.2:1   secondary text
     --brand-text   5.4:1   red TEXT on dark
     --brand        7.3:1   as a FILL behind #fff
   The logo red on black is only 2.3:1, so --brand is a fill color exclusively
   and never carries text. Use --brand-text wherever red type is wanted.
   ========================================================================== */

/* ---------- tokens ---------- */
:root {
  --ink:           #0A0A0B;
  --ink-2:         #121214;
  --ink-3:         #1A1B1D;
  --ink-4:         #212226;  /* raised surface when standing on an alt band */
  --bone:          #E8E4DE;
  --bone-dim:      #CFCAC3;
  --muted:         #A09B94;

  --brand:         #9F2C2F;  /* fills only */
  --brand-deep:    #7E2225;
  --brand-lift:    #B3383B;  /* fill hover */
  --brand-text:    #D4635E;  /* red text on dark */
  --brand-text-hi: #E0736C;

  --line:          rgba(232, 228, 222, 0.12);
  --line-strong:   rgba(232, 228, 222, 0.24);
  --field-line:    rgba(232, 228, 222, 0.40);  /* 3.2:1 on --ink (WCAG 1.4.11) */
  --field-line-hi: rgba(232, 228, 222, 0.60);  /* hover lift, a visible step above */

  --font-display:  "Playfair Display", Georgia, "Times New Roman", serif;
  --font-ui:       Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* The uppercase micro-label. Two deliberate exceptions keep their own
     values: .eyebrow tracks wider because it opens a section, and .label
     is larger because it is read while typing rather than scanned. */
  --micro:         0.72rem;
  --micro-track:   0.17em;

  --gutter:        clamp(1.25rem, 5vw, 3rem);
  --measure:       68ch;
  --header-h:      76px;
  --radius:        2px;      /* near-square edges read more formal than pills */

  /* Makes browser-drawn UI — date pickers, select menus, scrollbars,
     form autofill — render dark instead of white on a near-black page. */
  color-scheme: dark;

  --ease:          cubic-bezier(0.22, 0.61, 0.36, 1);
  --dur:           0.45s;  /* decorative sweeps: nav underline, arrow rule, burger */
  --dur-ui:        0.18s;  /* pointer feedback: buttons, cards, fields */
}

@media (max-width: 900px) {
  :root { --header-h: 64px; }
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Keeps anchored sections clear of the fixed header instead of under it. */
  scroll-padding-top: calc(var(--header-h) + 1.5rem);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* Color changes are fine; movement is not. Kill the transforms that slide,
     grow or rotate, and shorten everything else to an instant swap. */
  *, *::before, *::after {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  .nav__link::after, .faq__item[open] .faq__q::after { transition: none !important; }
}

body {
  background: var(--ink);
  color: var(--bone);
  font-family: var(--font-ui);
  font-size: clamp(1rem, 0.3vw + 0.93rem, 1.0625rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
:where(ul, ol)[class] { list-style: none; padding: 0; }

/* One focus style everywhere, shown only for keyboard users. */
:focus-visible { outline: 2px solid var(--bone); outline-offset: 3px; border-radius: 1px; }
:focus:not(:focus-visible) { outline: none; }

::selection { background: var(--brand); color: #fff; }

/* A fine grain over the whole page. Large flat areas of near-black band badly
   on cheap panels and in dark rooms; a little noise breaks the gradient up and
   gives the black some surface. Non-interactive, and never printed. */
body::after {
  content: "";
  position: fixed; inset: 0;
  z-index: 400;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='g'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23g)' opacity='0.55'/%3E%3C/svg%3E");
  opacity: 0.05;
  mix-blend-mode: overlay;
}
@media print { body::after { display: none; } }

.hero { --hero-image: url("../img/hero.jpg"); }

/* ---------- typography ---------- */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.08;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
h1 { font-size: clamp(2.35rem, 5.4vw, 4.15rem); }
h2 { font-size: clamp(1.95rem, 4vw, 3rem); }
h3 { font-size: clamp(1.25rem, 2vw, 1.6rem); letter-spacing: -0.01em; }
h4, .h-label {
  font-size: 1.0625rem;
  font-family: var(--font-ui);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.35;
}
/* .h-label lets a subsection heading look like a small label while keeping
   its correct heading LEVEL, so screen-reader outlines do not skip a rank. */
.card h3.h-label { margin-bottom: 0.3rem; }

p { text-wrap: pretty; }
a { color: var(--brand-text); text-decoration-thickness: 1px; text-underline-offset: 0.22em; }
a:hover { color: var(--brand-text-hi); }
strong { font-weight: 600; color: var(--bone); }

.eyebrow {
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--brand-text);
  margin-bottom: 1.15rem;
}

/* The uppercase micro-label, declared once. Each rule below then carries only
   what is genuinely its own — colour, margin, the odd font-family. */
.hero__proof, .fact__label, .fleet-card__type, .spec dt,
.county__count, .rail__label, .footer__h {
  font-size: var(--micro);
  letter-spacing: var(--micro-track);
  text-transform: uppercase;
}

.lede { font-size: clamp(1.08rem, 0.6vw + 0.95rem, 1.3rem); color: var(--bone-dim); line-height: 1.6; }
.muted { color: var(--muted); }
.measure { max-width: var(--measure); }
.center { text-align: center; }
.center .measure, .measure.center { margin-inline: auto; }
.stack > * + * { margin-top: 1.15rem; }

/* ---------- layout ---------- */
.wrap { width: min(1220px, 100% - var(--gutter) * 2); margin-inline: auto; }
.wrap--narrow { width: min(760px, 100% - var(--gutter) * 2); }

.section { padding-block: clamp(4.5rem, 9vw, 8rem); }
.section--tight { padding-block: clamp(3rem, 6vw, 5rem); }
.section--alt { background: var(--ink-2); }

/* A section declares its ground; components read --raised from it, so a card
   is always one step lighter than whatever it stands on. Without this, cards
   on an --alt band painted the same color as the band and disappeared. */
body, .section, .footer { --raised: var(--ink-2); --raised-hi: var(--ink-3); }
.section--alt, .cta      { --raised: var(--ink-3); --raised-hi: var(--ink-4); }
.section--rule { border-top: 1px solid var(--line); }

.section-head { margin-bottom: clamp(2.5rem, 5vw, 4rem); }
.section-head.center { margin-inline: auto; max-width: 60ch; }

.grid { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
/* Pinned to three once there is room: auto-fit was fitting four across on a
   wide screen, so six cards broke 4 + 2 instead of an even 3 + 3. */
@media (min-width: 900px) { .grid--3 { grid-template-columns: repeat(3, 1fr); } }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); }

/* Six airports, one row on a desktop. auto-fit would strand the last two on a
   second line at most widths, which reads as an afterthought. */
.airports { display: grid; gap: clamp(0.75rem, 1.2vw, 1rem); grid-template-columns: repeat(6, 1fr); }
.airports .card { padding: clamp(1rem, 1.4vw, 1.35rem); text-align: center; }
.airports .card h3 { font-size: clamp(0.95rem, 1.1vw, 1.15rem); }
.airports .fleet-card__type { margin-bottom: 0.4rem; font-size: 0.8rem; letter-spacing: 0.18em; }
.airports .card p { font-size: 0.8125rem; }
@media (max-width: 1100px) { .airports { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px)  { .airports { grid-template-columns: repeat(2, 1fr); } }

/* Short hairline in the monogram red, used to open a major beat. */
.rule { width: 84px; height: 2px; border: 0; background: var(--brand); margin: 0 0 1.75rem; }
.center .rule, .rule.center { margin-inline: auto; }

/* ---------- utilities ----------
   These exist so no element needs a style attribute. That keeps the markup
   readable and lets the site ship a Content-Security-Policy without having to
   allow 'unsafe-inline' for styles. */
.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.25rem; }
.mt-4 { margin-top: 1.5rem; }
.mt-5 { margin-top: 2rem; }
.mt-6 { margin-top: 2.5rem; }
.mt-7 { margin-top: 3rem; }
.fs-sm { font-size: 0.9375rem; }
.mw-46 { max-width: 46rem; }
.mw-60ch { max-width: 60ch; }
.items-start { align-items: start; }

/* ---------- skip link ---------- */
.skip {
  position: absolute; left: 50%; top: 0;
  transform: translate(-50%, -120%);
  z-index: 200;
  background: var(--bone); color: var(--ink);
  padding: 0.75rem 1.4rem; font-weight: 600;
  border-radius: 0 0 var(--radius) var(--radius);
  transition: transform 0.2s var(--ease);
}
.skip:focus { transform: translate(-50%, 0); color: var(--ink); }

/* ---------- buttons ---------- */
.btn {
  --btn-bg: var(--brand);
  --btn-fg: #fff;
  --btn-bd: var(--brand);
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  min-height: 48px;                      /* WCAG 2.2 target size */
  padding: 0.85rem 1.9rem;
  background: var(--btn-bg); color: var(--btn-fg);
  border: 1px solid var(--btn-bd); border-radius: var(--radius);
  font-size: 0.875rem; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  text-decoration: none; cursor: pointer;
  transition: background-color var(--dur-ui) var(--ease),
              border-color var(--dur-ui) var(--ease),
              color var(--dur-ui) var(--ease);
}
.btn:hover { --btn-bg: var(--brand-lift); --btn-bd: var(--brand-lift); color: #fff; }

/* --field-line, not --line-strong: this outline is the whole affordance,
   and 0.24 alpha composites to 1.86:1 — under the 3:1 WCAG 1.4.11 wants
   for a control boundary. */
.btn--ghost { --btn-bg: transparent; --btn-fg: var(--bone); --btn-bd: var(--field-line); }
.btn--ghost:hover { --btn-bg: rgba(232, 228, 222, 0.08); --btn-bd: var(--bone); color: var(--bone); }


/* Pressed. Must stay after the :hover rules — equal specificity, so source
   order decides which one wins while the pointer is down. */
.btn:active        { --btn-bg: var(--brand-deep); --btn-bd: var(--brand-deep); }
.btn--ghost:active { --btn-bg: rgba(232, 228, 222, 0.14); --btn-bd: var(--bone); }

.btn--lg { min-height: 54px; padding: 1rem 2.4rem; font-size: 0.9375rem; }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.875rem; }
/* .cta centres via its own text-align, and text-align cannot position flex
   items — it has to be keyed in here too. */
.center .btn-row, .cta .btn-row { justify-content: center; }

/* On a phone, side-by-side buttons wrap to ragged widths. Stack them full
   width instead — tidier, and a bigger tap target for the call link. */
@media (max-width: 520px) {
  .btn-row { flex-direction: column; align-items: stretch; }
  .btn-row .btn { width: 100%; }
}

/* Quiet text link with a rule that extends on hover. */
.link-arrow {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: 0.8125rem; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--bone); text-decoration: none;
  padding-block: 0.35rem;
}
.link-arrow::after {
  content: ""; width: 1.3rem; height: 1px; background: var(--brand-text);
  transition: width var(--dur) var(--ease);
}
.link-arrow:hover { color: var(--brand-text-hi); }
.link-arrow:hover::after { width: 2.1rem; }

/* ==========================================================================
   Header
   ========================================================================== */
.header {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  height: var(--header-h);
  display: flex; align-items: center;
  background: rgba(10, 10, 11, 0.72);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.header.is-stuck { background: rgba(10, 10, 11, 0.94); border-bottom-color: var(--line); }

/* Once opaque the blur is invisible, so stop re-blurring the backdrop on every
   scroll frame. Deliberately NOT removed from .header itself: without JS
   .is-stuck never applies, and the 0.72 background needs the blur to stay
   legible over content scrolling beneath it. */
.header.is-stuck {
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

@supports not ((backdrop-filter: blur(4px)) or (-webkit-backdrop-filter: blur(4px))) {
  .header { background: rgba(10, 10, 11, 0.96); }
}

/* No width here: this element also carries .wrap, which sets the shared
   page width and gutter. Declaring width:100% overrode it and pushed the
   header out of alignment with every section below. */
.header__inner { display: flex; align-items: center; gap: 1.5rem; }

/* The monogram plus live text, rather than the flat lockup image. At header
   size the lockup's wordmark falls to about 4px per character; setting the
   name in the display face keeps it crisp and legible at every width. */
.brand {
  display: flex; align-items: center; gap: 0.7rem;
  margin-right: auto; text-decoration: none;
}
.brand img {
  /* Sized entirely in CSS — no inline height for a media query to lose to. */
  height: clamp(30px, 3.6vw, 38px);
  width: auto;
}
.brand__name {
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.5vw, 1.24rem);
  font-weight: 500;
  letter-spacing: 0.005em;
  line-height: 1;
  color: var(--bone);
  white-space: nowrap;
  transition: color 0.25s var(--ease);
}
.brand:hover .brand__name { color: var(--brand-text-hi); }

@media (max-width: 380px) {
  .brand__name { font-size: 0.95rem; }
}

.nav { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2.1rem); }
.nav__link {
  position: relative;
  color: var(--bone); text-decoration: none;
  font-size: 0.875rem; font-weight: 500; letter-spacing: 0.02em;
  padding-block: 0.5rem;
  transition: color 0.25s var(--ease);
}
.nav__link::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--brand-text);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--dur) var(--ease);
}
.nav__link:hover, .nav__link[aria-current="page"] { color: var(--brand-text-hi); }
.nav__link:hover::after, .nav__link[aria-current="page"]::after { transform: scaleX(1); }

.header .btn { padding: 0.7rem 1.35rem; min-height: 42px; font-size: 0.78rem; }

.header__tel {
  display: inline-flex; align-items: center; gap: 0.5rem;
  color: var(--bone); text-decoration: none;
  font-size: 0.9rem; font-weight: 600;
  white-space: nowrap;
}
.header__tel:hover { color: var(--brand-text-hi); }
.header__tel svg { width: 15px; height: 15px; flex: none; }

.burger {
  display: none;
  width: 46px; height: 46px;
  align-items: center; justify-content: center;
  background: none; border: 1px solid var(--line-strong); border-radius: var(--radius);
  cursor: pointer;
}
.burger span { display: block; position: relative; width: 19px; height: 1.5px; background: var(--bone); transition: background-color 0.2s var(--ease); }
.burger span::before,
.burger span::after {
  content: ""; position: absolute; left: 0;
  width: 19px; height: 1.5px; background: var(--bone);
  transition: transform var(--dur) var(--ease), top var(--dur) var(--ease);
}
.burger span::before { top: -6px; }
.burger span::after { top: 6px; }
.burger[aria-expanded="true"] span { background: transparent; }
.burger[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.burger[aria-expanded="true"] span::after { top: 0; transform: rotate(-45deg); }

@media (max-width: 900px) {
  .burger { display: flex; }
  .nav {
    /* NOT `inset: ... 0`: .header has a backdrop-filter, which makes it the
       containing block for its position:fixed children. Resolving `bottom:0`
       against a 64px-tall header collapsed this panel to a 60px strip with the
       links clipped inside it. Size it explicitly against the viewport. */
    position: fixed;
    top: var(--header-h); left: 0; right: 0; bottom: auto;
    height: calc(100vh - var(--header-h));
    height: calc(100dvh - var(--header-h));
    flex-direction: column; align-items: stretch; justify-content: flex-start;
    gap: 0;
    padding: 1.25rem var(--gutter) 2.5rem;
    background: var(--ink);
    overflow-y: auto;
    /* Hidden from assistive tech and the tab order until opened.
       visibility is stepped, not eased: it flips to visible instantly on open
       (otherwise focus() lands on a still-hidden element and is discarded) and
       is held back until the fade finishes on close. */
    visibility: hidden; opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.28s var(--ease), transform 0.28s var(--ease),
                visibility 0s linear 0.28s;
  }
  .nav.is-open {
    visibility: visible; opacity: 1; transform: none;
    transition: opacity 0.28s var(--ease), transform 0.28s var(--ease),
                visibility 0s linear 0s;
  }
  .nav__link {
    font-family: var(--font-display); font-size: 1.5rem; font-weight: 500;
    padding-block: 0.85rem; border-bottom: 1px solid var(--line);
  }
  .nav__link::after { display: none; }
  /* padding must be restated: this button is also matched by `.header .btn`,
     which sets the compact desktop pill padding at equal specificity. */
  .nav .btn {
    margin-top: 1.5rem; width: 100%; min-height: 52px;
    padding: 1rem 2.4rem; font-size: 0.875rem;
  }
  .nav .header__tel { margin-top: 1.1rem; justify-content: center; font-size: 1.05rem; }
}

@media (min-width: 901px) {
  .header__tel--mobile { display: none; }
}

/* Between the burger breakpoint and ~1000px the bar cannot hold five links,
   a phone number and a button without crowding. The button carries it there. */
@media (max-width: 1000px) {
  .header__tel--desktop { display: none; }
}

body.nav-open { overflow: hidden; }

/* ==========================================================================
   Hero
   ========================================================================== */
.hero {
  position: relative;
  display: flex; align-items: center;
  min-height: min(92svh, 900px);
  padding-top: calc(var(--header-h) + clamp(3rem, 8vh, 6rem));
  padding-bottom: clamp(3.5rem, 8vh, 6rem);
  overflow: hidden;
  isolation: isolate;
}
.hero--inner { min-height: auto; padding-bottom: clamp(2.5rem, 5vh, 4rem); }

/* Layered light rather than a stock photo: a warm key off to one side, a cool
   fill, and a fine grain so the dark gradient does not band on wide screens. */
.hero__bg { position: absolute; inset: 0; z-index: -2; background: var(--ink); }
.hero__bg::before {
  content: ""; position: absolute; inset: -20%;
  background:
    radial-gradient(60% 55% at 72% 18%, rgba(159, 44, 47, 0.30), transparent 68%),
    radial-gradient(48% 60% at 12% 88%, rgba(72, 78, 96, 0.26), transparent 70%),
    radial-gradient(90% 90% at 50% 0%, rgba(232, 228, 222, 0.06), transparent 62%);
}
.hero__bg::after {
  content: ""; position: absolute; inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: 0.045;
  mix-blend-mode: overlay;
}

/* Optional photograph. Set --hero-image on .hero to switch it on. */
.hero__photo {
  position: absolute; inset: 0; z-index: -1;
  background-image: var(--hero-image, none);
  background-size: cover;
  background-position: center 42%;
  opacity: var(--hero-photo-opacity, 0.45);
}
.hero__photo::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(10, 10, 11, 0.70) 0%, rgba(10, 10, 11, 0.60) 45%, rgba(10, 10, 11, 0.94) 100%);
}

.hero__content {
  max-width: 52rem;
  margin-inline: auto;
  text-align: center;
}
.hero h1 { margin-bottom: 1.5rem; }
.hero .btn-row { justify-content: center; }
.hero__proof { justify-content: center; }
.hero h1 em { font-style: italic; font-weight: 400; color: var(--brand-text); }
.hero .lede { max-width: 42rem; margin-inline: auto; margin-bottom: 2.4rem; }

.hero__proof {
  display: flex; flex-wrap: wrap; gap: 0.6rem 1.75rem;
  margin-top: 3rem; padding-top: 1.75rem;
  border-top: 1px solid var(--line);
  color: var(--muted);
  max-width: 44rem; margin-inline: auto;
}
.hero__proof li { display: flex; align-items: center; gap: 0.55rem; }
.hero__proof li::before { content: ""; width: 4px; height: 4px; border-radius: 50%; background: var(--brand-text); flex: none; }

/* ==========================================================================
   Facts band
   ========================================================================== */
/* Explicit counts rather than auto-fit: the intermediate 3-across case
   stranded the fourth fact on its own row with a dangling divider. */
.facts { display: grid; grid-template-columns: repeat(4, 1fr); }
.fact {
  padding: clamp(1.75rem, 3.5vw, 2.75rem) clamp(1rem, 2vw, 1.75rem);
  border-left: 1px solid var(--line);
  text-align: center;
}
.fact:first-child { border-left: 0; }
.fact__num {
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(2.1rem, 4vw, 3rem); line-height: 1;
  color: var(--bone); margin-bottom: 0.6rem;
}
.fact__label { color: var(--muted); }

@media (max-width: 820px) {
  .facts { grid-template-columns: repeat(2, 1fr); }
  .fact:nth-child(odd) { border-left: 0; }
  .fact:nth-child(n + 3) { border-top: 1px solid var(--line); }
}

/* ==========================================================================
   Cards
   ========================================================================== */
.card {
  display: flex; flex-direction: column;
  padding: clamp(1.6rem, 2.6vw, 2.25rem);
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color var(--dur-ui) var(--ease), background-color var(--dur-ui) var(--ease);
}
.card:hover { border-color: var(--line-strong); background: var(--raised-hi); }
.card__icon { color: var(--brand-text); margin-bottom: 1.4rem; }
.card__icon svg { width: 30px; height: 30px; }
.card h3 { margin-bottom: 0.75rem; }
.card p { color: var(--muted); }
.card .link-arrow { margin-top: auto; padding-top: 1.5rem; }

a.card { text-decoration: none; color: inherit; }
a.card:hover { color: inherit; }

/* The tile is the link, so hovering anywhere on it moves the arrow — not
   just the fourteen characters of the label itself. */
a.card:hover .link-arrow, a.card:focus-visible .link-arrow { color: var(--brand-text-hi); }
a.card:hover .link-arrow::after, a.card:focus-visible .link-arrow::after { width: 2.1rem; }

.card-list { margin-top: 1.25rem; display: grid; gap: 0.6rem; }
.card-list li { position: relative; padding-left: 1.4rem; font-size: 0.9375rem; color: var(--muted); }
.card-list li::before { content: ""; position: absolute; left: 0; top: 0.62em; width: 6px; height: 1px; background: var(--brand-text); }

/* ---------- fleet ---------- */
.fleet-card {
  overflow: hidden;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color var(--dur-ui) var(--ease);
}
.fleet-card:hover { border-color: var(--line-strong); }

/* A fixed ratio reserves the space, so dropping a photo in shifts nothing. */
.fleet-card__media {
  position: relative;
  aspect-ratio: 16 / 10;
  background: linear-gradient(150deg, var(--raised-hi), var(--raised) 60%);
  border-bottom: 1px solid var(--line);
  display: grid; place-items: center;
  overflow: hidden;
}
/* Stock photos arrive with wildly different colour temperatures — one shot at
   night, one in daylight, one under warm brick. Pulling the saturation down and
   the contrast up a touch makes three unrelated photographs read as one set,
   and the scrim below blends the bottom edge into the card body. */
.fleet-card__media img {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(0.72) contrast(1.06) brightness(0.9);
}
.fleet-card__media::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, transparent 55%, rgba(10, 10, 11, 0.55) 100%);
  pointer-events: none;
}
.fleet-card__media--empty::after {
  content: ""; position: absolute; inset: 0;
  background: url("../img/logo-mark.png") center / auto 46% no-repeat;
  opacity: 0.09;
}
.fleet-card__body { padding: clamp(1.4rem, 2.4vw, 1.9rem); }
.fleet-card__body h3 { margin-bottom: 0.35rem; }
.fleet-card__type { color: var(--brand-text); margin-bottom: 1.25rem; }

.spec { display: flex; gap: 1.75rem; padding-top: 1.15rem; border-top: 1px solid var(--line); }
.spec div { display: grid; gap: 0.2rem; }
.spec dt { color: var(--muted); }
.spec dd { font-family: var(--font-display); font-size: 1.35rem; color: var(--bone); }

/* ==========================================================================
   Editorial split
   ========================================================================== */
.split { display: grid; gap: clamp(2.5rem, 5vw, 5rem); align-items: center; }

@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; }
  .split--wide-left { grid-template-columns: 1.15fr 1fr; }
  .split--wide-right { grid-template-columns: 1fr 1.15fr; }
  .split__media--first { order: -1; }
}

.plaque {
  position: relative;
  aspect-ratio: 4 / 5;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background:
    radial-gradient(70% 60% at 30% 20%, rgba(159, 44, 47, 0.20), transparent 70%),
    linear-gradient(160deg, var(--ink-3), var(--ink-2));
  display: grid; place-items: center;
  overflow: hidden;
}
.plaque img { width: min(52%, 240px); opacity: 0.9; }

/* ==========================================================================
   Steps
   ========================================================================== */
.steps { counter-reset: step; display: grid; gap: clamp(1.5rem, 3vw, 2.25rem); }
.step { position: relative; padding-left: 4.25rem; }
.step::before {
  counter-increment: step; content: counter(step, decimal-leading-zero);
  position: absolute; left: 0; top: -0.15em;
  font-family: var(--font-display); font-size: 1.5rem;
  color: var(--brand-text);
}
/* bottom is negative by the grid gap so the line meets the next number
   instead of stopping in the space between steps. */
.step::after { content: ""; position: absolute; left: 2.9rem; top: 1.9em; bottom: calc(clamp(1.5rem, 3vw, 2.25rem) * -1); width: 1px; background: var(--line); }
.step:last-child::after { display: none; }
.step h3 { font-size: 1.15rem; margin-bottom: 0.4rem; }
.step p { color: var(--muted); }

/* ==========================================================================
   FAQ — native <details>, so it works with zero JavaScript
   ========================================================================== */
.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__q {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5rem;
  padding: 1.5rem 0;
  font-family: var(--font-display); font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  color: var(--bone); cursor: pointer;
  list-style: none;
  transition: color 0.25s var(--ease);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { color: var(--brand-text-hi); }
.faq__q::after {
  content: ""; flex: none; position: relative; top: 0.55em;
  width: 13px; height: 13px;
  background: var(--brand-text);
  /* A plus drawn with a mask, so it can rotate into a minus. */
  -webkit-mask: linear-gradient(#000 0 0) center / 13px 1.5px no-repeat,
                linear-gradient(#000 0 0) center / 1.5px 13px no-repeat;
          mask: linear-gradient(#000 0 0) center / 13px 1.5px no-repeat,
                linear-gradient(#000 0 0) center / 1.5px 13px no-repeat;
  transition: transform var(--dur) var(--ease);
}
.faq__item[open] .faq__q::after { transform: rotate(135deg); }
.faq__a { padding-bottom: 1.75rem; color: var(--muted); max-width: 62ch; }
.faq__a > * + * { margin-top: 0.85rem; }

/* ==========================================================================
   Service areas
   ========================================================================== */
.area-cols { columns: 3 13rem; column-gap: clamp(1.5rem, 3vw, 3rem); }
.area-cols li {
  break-inside: avoid;
  padding: 0.42rem 0;
  font-size: 0.9375rem; color: var(--muted);
  border-bottom: 1px solid var(--line);
}

/* ==========================================================================
   Service-area counties
   ========================================================================== */
.counties { border-top: 1px solid var(--line); }
.county { border-bottom: 1px solid var(--line); }
.county > .faq__q { padding: 1.15rem 0; font-size: clamp(1rem, 1.5vw, 1.2rem); }
.county__count {
  margin-left: auto; margin-right: 1rem;
  font-family: var(--font-ui);
  color: var(--muted); white-space: nowrap;
}
/* The summary is a flex row; on a narrow phone the county name and its count
   cannot share one line, so let the count drop beneath instead of pushing the
   row wider than the screen. */
.county > .faq__q { flex-wrap: wrap; }
@media (max-width: 560px) {
  .county > .faq__q { row-gap: 0.35rem; }
  .county__count {
    flex-basis: 100%; margin-left: 0; margin-right: 0;
    white-space: normal; order: 3;
  }
}
.county > .faq__a { padding-bottom: 1.5rem; max-width: none; }
.county .area-cols { columns: 4 11rem; }
@media (max-width: 560px) { .county .area-cols { columns: 2 8rem; } }

/* ==========================================================================
   Forms
   ========================================================================== */
.form { display: grid; gap: 1.35rem; }
.field { display: grid; gap: 0.5rem; }
.field--split { display: grid; gap: 1.35rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }

.label { font-size: 0.78rem; font-weight: 600; letter-spacing: 0.11em; text-transform: uppercase; color: var(--bone-dim); }
.label .req { color: var(--brand-text); margin-left: 0.15em; }
.hint { font-size: 0.8125rem; color: var(--muted); }

.input, .select, .textarea {
  width: 100%;
  min-height: 50px;
  padding: 0.8rem 1rem;
  background: var(--ink);
  color: var(--bone);
  border: 1px solid var(--field-line);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease);
  appearance: none;
}
.textarea { min-height: 8.5rem; resize: vertical; line-height: 1.6; }
.input::placeholder, .textarea::placeholder { color: #827D77; }  /* 4.85:1 */
.input:hover, .select:hover, .textarea:hover { border-color: var(--field-line-hi); }
.input:focus, .select:focus, .textarea:focus {
  outline: 2px solid var(--bone); outline-offset: 1px;
  border-color: transparent; background: var(--ink-2);
}
.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23A09B94' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  padding-right: 2.6rem;
}
.select option { background: var(--ink-2); color: var(--bone); }

/* Validation shown only after the field has been touched, so the form is not
   red before anyone has typed in it. */
.input:user-invalid, .textarea:user-invalid, .select:user-invalid { border-color: var(--brand-text); }
.field__error { display: none; font-size: 0.8125rem; color: var(--brand-text); }
.input:user-invalid ~ .field__error,
.textarea:user-invalid ~ .field__error,
.select:user-invalid ~ .field__error { display: block; }

.check { display: flex; gap: 0.75rem; align-items: flex-start; }
.check input { width: 24px; height: 24px; margin-top: 0.1rem; flex: none; accent-color: var(--brand); }
.check label { font-size: 0.875rem; color: var(--muted); }

.form__status { padding: 0.9rem 1.1rem; border: 1px solid var(--line-strong); border-radius: var(--radius); font-size: 0.9375rem; }
.form__status[data-state="ok"] { border-color: #3E6B4A; background: rgba(62, 107, 74, 0.16); color: #B6E0C0; }
.form__status[data-state="err"] { border-color: var(--brand); background: rgba(159, 44, 47, 0.16); color: #F0BDBA; }
.form__status[hidden] { display: none; }

/* Shown by JS when the pickup date is today or tomorrow, where the standing
   advice to call has become fine print. */
.form__urgent {
  display: grid; gap: 0.9rem;
  padding: 1.15rem 1.25rem;
  background: rgba(159, 44, 47, 0.14);
  border: 1px solid var(--brand);
  border-radius: var(--radius);
}
.form__urgent p { font-size: 0.9375rem; color: var(--bone-dim); }
.form__urgent[hidden] { display: none; }

/* Reassurance directly above the consent box. Static — nothing in it clicks. */
.assure {
  padding: 1.25rem 1.4rem;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.assure .rail__label { margin-bottom: 0.75rem; }
.assure .card-list { margin-top: 0; }

/* Busy reads as active work, not as a disabled control. Opacity alone dropped
   the label toward the 3:1 floor; this darkens the fill and keeps white text.
   pointer-events stays because the button is never actually disabled — see the
   `sending` guard in site.js, which avoids yanking focus mid-submit. */
.btn[aria-busy="true"] {
  --btn-bg: var(--brand-deep);
  --btn-bd: var(--brand-deep);
  --btn-fg: #fff;              /* keeps white text; inheriting a dark fg here is 1.9:1 */
  position: relative; overflow: hidden;
  cursor: progress;
  pointer-events: none;
}
.btn[aria-busy="true"]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.85), transparent);
  /* linear, not var(--ease) — an eased loop lurches at the seam. The global
     reduced-motion block already collapses this to a non-animation. */
  animation: btn-wipe 1.1s linear infinite;
}
@keyframes btn-wipe {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* Honeypot: off-screen rather than display:none, which bots detect. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ==========================================================================
   Contact rail
   ========================================================================== */
.rail { display: grid; gap: 1.75rem; align-content: start; }
.rail__item { padding-bottom: 1.6rem; border-bottom: 1px solid var(--line); }
.rail__item:last-child { border-bottom: 0; }
.rail__label { color: var(--muted); margin-bottom: 0.55rem; }
/* overflow-wrap:anywhere (not break-word) is what actually lowers the
   min-content width, so the address cannot set the grid track floor. */
.rail__value {
  font-family: var(--font-display); font-size: clamp(1.25rem, 2.2vw, 1.6rem);
  color: var(--bone); text-decoration: none; display: inline-block;
  overflow-wrap: anywhere;
}
a.rail__value:hover { color: var(--brand-text-hi); }

/* ==========================================================================
   CTA band
   ========================================================================== */
.cta {
  position: relative; overflow: hidden;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
  background: radial-gradient(58% 100% at 50% 0%, rgba(159, 44, 47, 0.24), transparent 70%), var(--ink-2);
  text-align: center;
}
.cta h2 { margin-bottom: 1rem; }
.cta p { color: var(--bone-dim); max-width: 46ch; margin: 0 auto 2.25rem; }

/* ==========================================================================
   Footer
   ========================================================================== */
.footer { padding-block: clamp(3.5rem, 6vw, 5rem) 2rem; background: var(--ink); }
.footer__grid {
  display: grid; gap: clamp(2rem, 4vw, 3.5rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  padding-bottom: 3rem; border-bottom: 1px solid var(--line);
}
.footer__brand .brand { margin: 0 0 1.35rem; }
.footer__brand .brand img { height: 46px; }
.footer__brand .brand__name { font-size: 1.35rem; }
.footer__brand p { color: var(--muted); font-size: 0.9375rem; max-width: 30ch; }
.footer__h { font-family: var(--font-ui); font-weight: 600; color: var(--bone); margin-bottom: 1.15rem; }
.footer__list { display: grid; gap: 0.7rem; }
.footer__list a, .footer__list span {
  display: inline-flex; align-items: center; min-height: 24px;
  color: var(--muted); text-decoration: none; font-size: 0.9375rem;
}
.footer__list a:hover { color: var(--brand-text-hi); }
.footer__bottom {
  display: flex; flex-wrap: wrap; gap: 0.75rem 1.5rem;
  justify-content: space-between; align-items: center;
  padding-top: 2rem;
  font-size: 0.8125rem; color: var(--muted);
}
.footer__bottom nav { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.footer__bottom a {
  display: inline-flex; align-items: center; min-height: 24px;
  color: var(--muted); text-decoration: none;
}
.footer__bottom a:hover { color: var(--brand-text-hi); }

/* ==========================================================================
   Long-form prose (legal pages)
   ========================================================================== */
.prose { max-width: 72ch; }
.prose > * + * { margin-top: 1.15rem; }
.prose h2 { font-size: clamp(1.4rem, 2.4vw, 1.85rem); margin-top: 3rem; }
.prose h3 { font-size: 1.15rem; margin-top: 2rem; }
.prose ul { display: grid; gap: 0.6rem; padding-left: 1.3rem; list-style: disc; }
.prose li::marker { color: var(--brand-text); }
.prose p, .prose li { color: var(--muted); }

/* ==========================================================================
   Reveal on scroll — opt-in, and off entirely for reduced motion
   ========================================================================== */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.5s var(--ease), transform 0.5s var(--ease); }
  .reveal.is-in { opacity: 1; transform: none; }
}

/* If scripting is unavailable, nothing may stay invisible. */
.no-js .reveal { opacity: 1 !important; transform: none !important; }

/* ==========================================================================
   Sticky action bar — phones only
   ========================================================================== */
.callbar { display: none; }

@media (max-width: 900px) {
  .callbar {
    position: fixed; inset: auto 0 0 0; z-index: 90;
    display: grid; grid-template-columns: 1fr 1fr;
    background: rgba(10, 10, 11, 0.94);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--line);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .callbar__btn {
    display: flex; align-items: center; justify-content: center; gap: 0.55rem;
    min-height: 56px;
    font-size: 0.8125rem; font-weight: 600;
    letter-spacing: 0.09em; text-transform: uppercase;
    text-decoration: none;
  }
  .callbar__btn svg { width: 16px; height: 16px; flex: none; }
  .callbar__btn--call  { background: var(--brand); color: #fff; }
  .callbar__btn--call:active { background: var(--brand-deep); color: #fff; }
  .callbar__btn--quote { background: transparent; color: var(--bone); }
  .callbar__btn--quote:active { background: rgba(232, 228, 222, 0.10); color: var(--bone); }

  /* Clear the bar so it never covers the last line of the footer. */
  .footer { padding-bottom: calc(2rem + 56px + env(safe-area-inset-bottom, 0)); }

  /* It must not float over the open navigation panel. */
  body.nav-open .callbar { display: none; }
}

/* ---------- print ---------- */
@media print {
  .header, .burger, .cta, .hero__bg, .hero__photo, .callbar { display: none !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
  /* Reset color on EVERYTHING. An element list silently missed strong,
     summary, label, span and the form controls, so the FAQ questions and every
     field label printed white on white. Backgrounds stay enumerated so the
     decorative rules and dividers survive. */
  *, *::before, *::after { color: #000 !important; }
  body, .card, .fleet-card, .faq__item,
  .input, .select, .textarea, .btn { background: #fff !important; }
  /* The hero reserves a screen-height box that would otherwise print blank. */
  .hero { min-height: 0 !important; padding-top: 0 !important; }
  .btn { border: 1px solid #000 !important; }
  .card, .fleet-card, .faq__item { border-color: #999 !important; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}
