/* ============================================================
   Drone & Scanning Solutions LLC — Master Stylesheet
   Navy #1F3A5F · Gold #C0A062
   Author: DSS LLC · St. Thomas, USVI
   ============================================================ */

/* ---------- 1. TOKENS ---------- */
:root {
  /* brand */
  --navy:        #1F3A5F;
  --navy-900:    #142944;
  --navy-950:    #0E1E33;
  --navy-700:    #2C5183;
  --navy-100:    #E7ECF3;
  --gold:        #C0A062;
  --gold-600:    #856A34;
  --gold-300:    #DCC694;
  --gold-100:    #F5EFE1;

  /* neutrals */
  --paper:       #FBFAF8;
  --surface:     #FFFFFF;
  --surface-alt: #F4F5F7;
  --ink:         #131E2C;
  --body:        #4A5568;
  --muted:       #5E6A7C;
  --rule:        rgba(31, 58, 95, 0.14);
  --rule-strong: rgba(31, 58, 95, 0.26);
  --rule-dark:   rgba(255, 255, 255, 0.16);

  /* type */
  --serif: "Source Serif 4", ui-serif, Georgia, "Times New Roman", serif;
  --sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono:  "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* scale */
  --step--1: clamp(0.82rem, 0.80rem + 0.10vw, 0.88rem);
  --step-0:  clamp(1.00rem, 0.97rem + 0.15vw, 1.09rem);
  --step-1:  clamp(1.20rem, 1.13rem + 0.34vw, 1.42rem);
  --step-2:  clamp(1.45rem, 1.31rem + 0.68vw, 1.90rem);
  --step-3:  clamp(1.80rem, 1.53rem + 1.32vw, 2.65rem);
  --step-4:  clamp(2.20rem, 1.71rem + 2.42vw, 3.75rem);

  /* rhythm */
  --gutter:   clamp(20px, 4vw, 56px);
  --maxw:     1200px;
  --maxw-text: 68ch;
  --section-y: clamp(64px, 8vw, 120px);

  --radius:    10px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 2px rgba(19, 30, 44, .05), 0 2px 8px rgba(19, 30, 44, .05);
  --shadow-md: 0 4px 12px rgba(19, 30, 44, .07), 0 12px 32px rgba(19, 30, 44, .07);
  --shadow-lg: 0 8px 24px rgba(19, 30, 44, .09), 0 24px 64px rgba(19, 30, 44, .10);

  --ease: cubic-bezier(.22, .68, .28, 1);
  --t:    .28s var(--ease);
}

/* ---------- 2. RESET & BASE ---------- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; scroll-padding-top: 88px; -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--sans);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--body);
  background: var(--paper);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; transition: color var(--t), background-color var(--t), border-color var(--t); }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.14;
  letter-spacing: -0.012em;
  color: var(--navy);
  text-wrap: balance;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-1); }
p  { text-wrap: pretty; }

::selection { background: var(--gold); color: var(--navy-950); }

/* ---------- 3. ACCESSIBILITY ---------- */
.skip-nav {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; overflow: hidden; z-index: 10001;
}
.skip-nav:focus {
  position: fixed; top: 12px; left: 12px; width: auto; height: auto;
  padding: 12px 22px; background: var(--navy); color: #fff;
  border-radius: var(--radius); font-weight: 600; font-size: 14px;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

a:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible, [tabindex]:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
  border-radius: 3px;
}
.site-header a:focus-visible, .site-footer a:focus-visible { outline-color: var(--gold-300); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ---------- 4. LAYOUT ---------- */
.container { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.section { padding-block: var(--section-y); }
.section--tight { padding-block: clamp(48px, 5vw, 76px); }
.section--alt { background: var(--surface-alt); }
.section--navy { background: var(--navy-900); color: rgba(255,255,255,.82); }
.section--navy h2, .section--navy h3 { color: #fff; }

.section-head { max-width: 62ch; margin-bottom: clamp(36px, 4vw, 56px); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head p { margin-top: 16px; font-size: var(--step-1); color: var(--muted); line-height: 1.55; }
.section--navy .section-head p { color: rgba(255,255,255,.72); }

.eyebrow {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: var(--mono); font-size: 11.5px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--gold-600); margin-bottom: 18px;
}
.eyebrow::before {
  content: ""; width: 22px; height: 1px; background: var(--gold); flex: none;
}
.section--navy .eyebrow, .hero .eyebrow { color: var(--gold-300); }
/* a centered head centers its eyebrow rule and label */
.section-head--center .eyebrow { justify-content: center; }

.lede { font-size: var(--step-1); line-height: 1.55; color: var(--body); max-width: var(--maxw-text); }
/* lede on dark surfaces */
.section--navy .lede { color: rgba(255,255,255,.74); }

/* ---------- 5. BUTTONS ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  padding: 14px 26px; border-radius: var(--radius);
  font-size: 15px; font-weight: 600; letter-spacing: -0.005em;
  border: 1.5px solid transparent; text-align: center;
  transition: background-color var(--t), border-color var(--t), color var(--t), transform var(--t), box-shadow var(--t);
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--gold   { background: var(--gold); color: var(--navy-950); border-color: var(--gold); box-shadow: var(--shadow-sm); }
.btn--gold:hover { background: var(--gold-600); border-color: var(--gold-600); color: #fff; box-shadow: var(--shadow-md); }

.btn--navy   { background: var(--navy); color: #fff; border-color: var(--navy); box-shadow: var(--shadow-sm); }
.btn--navy:hover { background: var(--navy-900); border-color: var(--navy-900); box-shadow: var(--shadow-md); }

.btn--outline { border-color: var(--rule-strong); color: var(--navy); background: transparent; }
.btn--outline:hover { border-color: var(--navy); background: var(--navy); color: #fff; }

.btn--ghost  { border-color: rgba(255,255,255,.34); color: #fff; }
.btn--ghost:hover { background: rgba(255,255,255,.10); border-color: rgba(255,255,255,.6); }

.btn--full { width: 100%; }
.btn__arrow { transition: transform var(--t); }
.btn:hover .btn__arrow { transform: translateX(3px); }

.link-arrow {
  display: inline-flex; align-items: center; gap: 7px;
  font-weight: 600; font-size: 15px; color: var(--navy);
  border-bottom: 1.5px solid var(--gold); padding-bottom: 2px;
}
.link-arrow:hover { color: var(--gold-600); border-color: var(--gold-600); }
.section--navy .link-arrow { color: var(--gold-300); border-color: var(--gold); }
.section--navy .link-arrow:hover { color: #fff; border-color: #fff; }

/* ---------- 6. HEADER & NAV ---------- */
.site-header {
  position: sticky; top: 0; z-index: 1000;
  background: var(--navy-950);
  color: #fff;
  transition: background-color .3s ease, box-shadow .3s ease;
}
.site-header.is-scrolled {
  background: rgba(14, 30, 51, .93);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  box-shadow: 0 1px 0 rgba(255,255,255,.08), 0 6px 24px rgba(0,0,0,.20);
}
.site-header__inner {
  max-width: var(--maxw); margin-inline: auto;
  padding: 0 var(--gutter);
  display: flex; align-items: center; justify-content: space-between;
  min-height: 74px; gap: 24px;
}

.brand { display: inline-flex; align-items: center; gap: 12px; flex: none; }
/* Real logo lockup. Height-driven so the asset keeps its own aspect ratio; the width
   attribute in the markup reserves the right box before the SVG loads. The reversed
   variant is correct in both places, since header and footer are both navy-950. */
.brand__logo { display: block; width: auto; height: 32px; }
@media (max-width: 520px) { .brand__logo { height: 26px; } }

.nav { display: flex; align-items: center; gap: 4px; }
.nav > ul { display: flex; align-items: center; gap: 2px; }
/* :not(.btn) so a button in the nav keeps its own colours. .nav a would otherwise
   outrank .btn--gold and force white on gold at 2.11:1. */
.nav a:not(.btn) {
  display: block; padding: 9px 14px; border-radius: 7px;
  font-size: 14.5px; font-weight: 500; color: rgba(255,255,255,.80);
}
.nav a:not(.btn):hover { color: #fff; background: rgba(255,255,255,.09); }
/* Current section. A dropdown menu link carries aria-current, but the menu is closed by
   default, so the toggle needs the state too; both are set by js/script.js from the URL,
   which keeps the header markup byte-identical across pages. Gold text on a gold rule:
   the previous tinted rectangle was functionally correct and invisible on navy.
   --gold-300 measures 7.98:1 on the tinted header. */
.nav a:not(.btn)[aria-current="page"],
.nav__item.is-current .nav__toggle {
  color: var(--gold-300);
  background: rgba(192,160,98,.14);
  box-shadow: inset 0 -2px 0 var(--gold);
}
.nav .btn { margin-left: 12px; padding: 10px 20px; font-size: 14.5px; }

/* dropdown */
.nav__item { position: relative; }
.nav__toggle {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 14px; border-radius: 7px;
  font-size: 14.5px; font-weight: 500; color: rgba(255,255,255,.80);
  transition: color var(--t), background-color var(--t);
}
.nav__toggle:hover { color: #fff; background: rgba(255,255,255,.09); }
.nav__toggle svg { transition: transform var(--t); }
.nav__item.is-open .nav__toggle { color: #fff; background: rgba(255,255,255,.09); }
.nav__item.is-open .nav__toggle svg { transform: rotate(180deg); }

.nav__menu {
  position: absolute; top: calc(100% + 10px); left: 0;
  min-width: 264px; padding: 8px;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .2s var(--ease), transform .2s var(--ease), visibility .2s;
  display: flex; flex-direction: column; gap: 2px;
}
.nav__item.is-open .nav__menu { opacity: 1; visibility: visible; transform: translateY(0); }
.nav__menu a {
  padding: 10px 14px; border-radius: 8px;
  color: var(--navy); font-weight: 600; font-size: 14.5px;
}
.nav__menu a span {
  display: block; font-weight: 400; font-size: 12.5px;
  color: var(--muted); margin-top: 2px;
}
.nav__menu a:hover { background: var(--navy-100); color: var(--navy); }
.nav__menu a[aria-current="page"] { background: var(--navy-100); color: var(--navy); font-weight: 600; box-shadow: inset 2px 0 0 var(--gold); }

/* mobile toggle */
.nav-toggle {
  display: none; width: 44px; height: 44px; flex: none;
  align-items: center; justify-content: center; border-radius: 8px;
  color: #fff;
}
.nav-toggle:hover { background: rgba(255,255,255,.09); }
.nav-toggle span {
  display: block; width: 22px; height: 2px; background: currentColor;
  position: relative; transition: background-color .2s;
}
.nav-toggle span::before, .nav-toggle span::after {
  content: ""; position: absolute; left: 0; width: 22px; height: 2px;
  background: currentColor; transition: transform .28s var(--ease), top .28s var(--ease);
}
.nav-toggle span::before { top: -7px; }
.nav-toggle span::after  { top: 7px; }
.nav-toggle[aria-expanded="true"] span { background: transparent; }
.nav-toggle[aria-expanded="true"] span::before { top: 0; transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] span::after  { top: 0; transform: rotate(-45deg); }

@media (max-width: 960px) {
  .nav-toggle { display: flex; }
  .nav {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--navy-950); padding: 8px var(--gutter) 24px;
    border-top: 1px solid rgba(255,255,255,.10);
    max-height: calc(100vh - 74px); overflow-y: auto;
    display: none;
  }
  .nav.is-open { display: flex; }
  .nav > ul { flex-direction: column; align-items: stretch; gap: 0; width: 100%; }
  .nav a:not(.btn), .nav__toggle { padding: 13px 4px; font-size: 16px; width: 100%; }
  .nav .btn { margin: 14px 0 0; width: 100%; }
  .nav__item { position: static; }
  .nav__menu {
    position: static; opacity: 1; visibility: visible; transform: none;
    background: transparent; border: 0; box-shadow: none;
    padding: 0 0 8px 16px; display: none;
    border-left: 1px solid rgba(255,255,255,.14);
  }
  .nav__item.is-open .nav__menu { display: flex; }
  .nav__menu a { color: rgba(255,255,255,.78); padding: 10px 12px; font-size: 15px; }
  .nav__menu a span { color: rgba(255,255,255,.45); }
  .nav__menu a:hover { background: rgba(255,255,255,.08); color: #fff; }
  .nav__menu a[aria-current="page"] { background: rgba(192,160,98,.20); color: var(--gold-300); box-shadow: inset 2px 0 0 var(--gold); }
}

/* ---------- 7. HERO ---------- */
.hero {
  position: relative; isolation: isolate;
  background: var(--navy-950);
  color: rgba(255,255,255,.84);
  padding-block: clamp(72px, 10vw, 132px);
  overflow: hidden;
}
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(ellipse 80% 55% at 22% 0%, rgba(44, 81, 131, .55), transparent 70%),
    radial-gradient(ellipse 60% 50% at 92% 92%, rgba(192, 160, 98, .13), transparent 70%);
}
.hero__topo {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: -1; opacity: .5; pointer-events: none;
}
.hero__inner { position: relative; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.hero__title { color: #fff; max-width: 17ch; }
.hero__title em { font-style: normal; color: var(--gold); }
.hero__lede {
  margin-top: 22px; max-width: 58ch;
  font-size: var(--step-1); line-height: 1.58; color: rgba(255,255,255,.76);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 36px; }

.hero--page { padding-block: clamp(56px, 6vw, 88px); }
.hero--page .hero__title { max-width: 22ch; }
.hero--page .hero__lede { font-size: var(--step-1); }

/* Photographic hero. A modifier, not an edit to .hero: the other thirteen heroes keep
   the plain navy treatment and must not move.

   The photograph goes BEHIND the existing layers rather than instead of them. It rides
   in the hero's own background-image list with the scrim gradient stacked over it, and
   the hero's own background paints below every z-index:-1 child — so .hero__topo and
   the .hero::after washes still sit above the scrim, and the text still sits above
   those. Layer order, bottom to top: photograph, scrim, topo SVG, radial washes, text.

   The scrim is directional because the text is. It is near-opaque navy under the
   left-hand text column and thins toward the right, where the photograph is meant to
   read as a photograph.

   Contrast here was measured against COMPOSITED PIXELS, not against these declarations
   — dev/contrast.js reads CSS and cannot see a photograph, so it will report the hero
   as navy-on-navy and pass it for the wrong reason. Run dev/hero-contrast.js instead.

   The stop positions are set by the LEDE, not by the headline. The lede computes to
   21.5px at 1020px wide, which WCAG governs at 4.5:1, and at the original ramp it
   landed on blown-out concrete at 3.74:1. Deepening the middle of the ramp is what
   fixed it. The headline is display type at 36-60px and is governed at 3:1, where it
   sits at better than 1.6x with room to spare — so do not deepen these stops further
   on the headline's account. Past its own threshold, every extra point of opacity is
   photograph the reader loses for a number the standard does not ask for.

   The photograph itself is a custom property, not a literal, because two pages now use
   this modifier and the scrim geometry has to stay identical between them. A per-page
   class supplies only the URL. Do not fork the whole rule to change an image. */
.hero--photo {
  background-image:
    linear-gradient(90deg,
      rgba(14, 30, 51, .95) 0%,
      rgba(14, 30, 51, .93) 32%,
      rgba(14, 30, 51, .88) 74%,
      rgba(14, 30, 51, .62) 92%,
      rgba(14, 30, 51, .35) 100%),
    var(--hero-photo);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* The images. One line each; everything else is shared above. */
.hero--photo-runway { --hero-photo: url("../images/aerial-runway-construction-st-thomas.webp"); }
.hero--photo-roadway { --hero-photo: url("../images/roadway-drone-operation-st-croix.webp"); }

/* Below 700px the text column spans the full width, so a left-weighted scrim would
   leave the headline sitting on open photograph. It becomes near-uniform and heavy.
   Only background-image is overridden; size, position and repeat carry down. */
@media (max-width: 700px) {
  .hero--photo {
    background-image:
      linear-gradient(180deg,
        rgba(14, 30, 51, .95) 0%,
        rgba(14, 30, 51, .93) 55%,
        rgba(14, 30, 51, .90) 100%),
      url("../images/aerial-runway-construction-st-thomas.webp");
  }
}

/* stat strip */
.stats {
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: var(--surface);
}
.stats__grid {
  max-width: var(--maxw); margin-inline: auto;
  display: grid; grid-template-columns: repeat(4, 1fr);
}
.stats__item {
  padding: clamp(26px, 3.4vw, 40px) var(--gutter);
  text-align: center;
  border-left: 1px solid var(--rule);
}
.stats__item:first-child { border-left: 0; }
.stats__value {
  font-family: var(--serif); font-size: clamp(1.7rem, 1.2rem + 1.7vw, 2.5rem);
  font-weight: 600; color: var(--navy); line-height: 1.05;
}
.stats__label {
  margin-top: 8px; font-family: var(--mono); font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted);
}
@media (max-width: 760px) {
  .stats__grid { grid-template-columns: repeat(2, 1fr); }
  .stats__item:nth-child(odd) { border-left: 0; }
  .stats__item:nth-child(n+3) { border-top: 1px solid var(--rule); }
}

/* ---------- 8. CARDS & GRIDS ---------- */
.grid { display: grid; gap: clamp(18px, 2.2vw, 28px); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1020px) { .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 900px)  { .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .grid--2, .grid--3, .grid--4 { grid-template-columns: minmax(0, 1fr); } }

/* A grid child stretches to its row, but a card inside it sizes to its own
   content. Make the child a flex box and let the card fill it, so card bottoms
   align across a row however long the copy runs. A .card that is itself the
   grid child (see .grid--mini) already stretches and is unaffected. */
.grid > li, .grid > div { display: flex; }
.grid > li > .card, .grid > div > .card { width: 100%; }

/* compact audience cards inside a split column */
.grid--mini { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.grid--mini .card { --card-pad: 22px; padding: var(--card-pad); }
.grid--mini h3 { font-size: 16px; }
.grid--mini p { font-size: 14.5px; }
@media (max-width: 520px) { .grid--mini { grid-template-columns: minmax(0, 1fr); } }

.card {
  position: relative;
  /* Held as a property because .card--media bleeds an image out to the card edge with
     a negative margin of exactly this size. A literal in both places drifts apart and
     shows a sliver of card down the side of the image. */
  --card-pad: clamp(26px, 2.6vw, 34px);
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  padding: var(--card-pad);
  transition: transform var(--t), box-shadow var(--t), border-color var(--t);
  display: flex; flex-direction: column;
}
.card:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: var(--rule-strong); }
.card__icon {
  width: 44px; height: 44px; margin-bottom: 20px; color: var(--gold-600);
}
.card__num {
  font-family: var(--mono); font-size: 11px; letter-spacing: .14em;
  color: var(--gold-600); margin-bottom: 14px; display: block;
}
.card h3 { margin-bottom: 10px; }
.card p { color: var(--body); font-size: 15.5px; line-height: 1.62; }
.card__list { margin-top: 18px; display: flex; flex-direction: column; gap: 7px; }
.card__list li {
  position: relative; padding-left: 18px;
  font-size: 14.5px; color: var(--muted); line-height: 1.5;
}
.card__list li::before {
  content: ""; position: absolute; left: 0; top: 9px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--gold);
}
.card__foot { margin-top: auto; padding-top: 22px; }

/* Media card: a deliverable image full-bleed across the top of the card.

   The image escapes the card's padding with a negative margin of --card-pad on three
   sides and restores it below, so the body padding under the image is unchanged. Top
   corners follow the card radius, less the 1px border, so the image sits inside the
   frame rather than squaring off the corner; the bottom corners stay square where the
   image meets the copy.

   The ratio is fixed on the CONTAINER, not on the image. That is what keeps the row
   heights equal: every media box is the same height whatever its source measures, a
   card whose photograph has not arrived yet holds exactly the same box, and the grid
   child already stretches (see .grid > li above) so the card bottoms align across the
   row however long the copy runs. object-fit:cover then crops all six identically. */
.card--media .card__media {
  margin: calc(var(--card-pad) * -1) calc(var(--card-pad) * -1) var(--card-pad);
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--surface-alt);
  border-radius: calc(var(--radius-lg) - 1px) calc(var(--radius-lg) - 1px) 0 0;
}
/* height:100% and aspect-ratio:auto undo the global img defaults, so the container
   owns the ratio and the image fills it. Same reasoning as .figure--pair .figure__cell.

   An inline SVG diagram is a first-class occupant of this box, not a special case: the
   DSM/DTM card carries one. Its viewBox is authored at 16:10 to match, so it fills the
   container exactly and preserveAspectRatio never letterboxes it. object-fit is inert
   on an <svg> and is left in the shared declaration rather than split into two rules. */
.card--media .card__media img,
.card--media .card__media svg {
  width: 100%; height: 100%;
  aspect-ratio: auto; object-fit: cover;
}

/* linked card */
a.card { color: inherit; }
a.card h3 { transition: color var(--t); }
a.card:hover h3 { color: var(--gold-600); }

/* dark card */
.section--navy .card {
  background: rgba(255,255,255,.045);
  border-color: var(--rule-dark);
}
.section--navy .card p { color: rgba(255,255,255,.72); }
.section--navy .card__list li { color: rgba(255,255,255,.62); }
.section--navy .card__num { color: var(--gold-300); }
.section--navy .card:hover { border-color: rgba(192,160,98,.5); box-shadow: none; background: rgba(255,255,255,.07); }

/* ---------- 9. SPLIT / FEATURE ---------- */
/* Top-aligned by default. Centring only reads as deliberate when the two columns are
   close in height; it pushes the shorter one down by half the difference, and measured
   across all 17 splits on the site that displacement ran from 7px to 283px. At the top
   of that range it reads as a mistake rather than a choice, and two-column editorial
   layouts top-align. There is deliberately no .split--center modifier: every split was
   measured and none was better centred, so an unused modifier would be dead CSS. Add one
   the day a genuine case appears. */
.split {
  display: grid; gap: clamp(32px, 5vw, 72px);
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start;
}
.split--wide-left { grid-template-columns: 1.15fr 1fr; }
@media (max-width: 900px) { .split--wide-left { grid-template-columns: 1fr; } }

.checklist { display: flex; flex-direction: column; gap: 14px; margin-top: 28px; }
.checklist li {
  position: relative; padding-left: 32px;
  font-size: 15.5px; line-height: 1.55; color: var(--body);
}
.checklist li strong { color: var(--navy); font-weight: 600; }
.checklist li::before {
  content: ""; position: absolute; left: 0; top: 3px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--gold-100);
  border: 1.5px solid var(--gold);
}
.checklist li::after {
  content: ""; position: absolute; left: 6.5px; top: 9px;
  width: 7px; height: 3.5px;
  border-left: 1.8px solid var(--gold-600);
  border-bottom: 1.8px solid var(--gold-600);
  transform: rotate(-45deg);
}
.section--navy .checklist li { color: rgba(255,255,255,.76); }
.section--navy .checklist li strong { color: #fff; }
.section--navy .checklist li::before { background: rgba(192,160,98,.16); }
.section--navy .checklist li::after { border-color: var(--gold-300); }

/* ---------- 10. STEPS ---------- */
.steps { counter-reset: step; display: grid; gap: clamp(20px, 2.4vw, 28px); grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.steps li { position: relative; padding-top: 28px; border-top: 2px solid var(--rule); }
.steps li::before {
  counter-increment: step; content: "0" counter(step);
  position: absolute; top: -1px; left: 0;
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  color: var(--gold-600); background: var(--paper); padding-right: 12px;
  transform: translateY(-50%);
}
.section--alt .steps li::before { background: var(--surface-alt); }
.steps h3 { font-size: var(--step-1); margin-bottom: 8px; }
.steps p { font-size: 15px; color: var(--body); line-height: 1.6; }

/* ---------- 11. DELIVERABLES TABLE ---------- */
/* A table paints its own background, so it must own its text colours too. Without this it
   inherits whatever the surrounding section set — white on white inside .section--navy.
   Same reasoning as .card carrying dark-context overrides: the component is self-contained. */
.table-wrap {
  overflow-x: auto; border: 1px solid var(--rule); border-radius: var(--radius-lg);
  background: var(--surface); color: var(--body);
}
table { width: 100%; border-collapse: collapse; min-width: 560px; }
caption { text-align: left; padding: 20px 24px 0; font-size: 14px; color: var(--body); }
th, td { padding: 15px 24px; text-align: left; border-bottom: 1px solid var(--rule); font-size: 15px; vertical-align: top; color: var(--body); }
thead th {
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--navy); font-weight: 500;
  background: var(--surface-alt); border-bottom: 1px solid var(--rule-strong);
}
tbody th { font-weight: 600; color: var(--navy); font-family: var(--sans); font-size: 15px; letter-spacing: 0; text-transform: none; background: none; }
tbody tr:last-child th, tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: rgba(31,58,95,.025); }
/* Compact variant for a spec table inside a split column, where the 560px table minimum
   would otherwise force a horizontal scrollbar at desktop width. */
.table-wrap--compact table { min-width: 0; }
.table-wrap--compact th, .table-wrap--compact td { padding: 11px 14px; font-size: 14px; }
.table-wrap--compact caption { padding: 14px 14px 0; font-size: 13px; }

td code, .mono { font-family: var(--mono); font-size: 13px; color: var(--navy-700); }

/* ---------- 12. FAQ ---------- */
.faq { display: flex; flex-direction: column; gap: 0; border-top: 1px solid var(--rule); }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 24px;
  padding: 22px 0; cursor: pointer; list-style: none;
  font-family: var(--serif); font-size: var(--step-1); font-weight: 600;
  color: var(--navy); line-height: 1.3;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 13px; height: 13px; margin-top: 8px;
  border-right: 2px solid var(--gold-600); border-bottom: 2px solid var(--gold-600);
  transform: rotate(45deg); transition: transform var(--t);
}
.faq details[open] summary::after { transform: rotate(-135deg); }
.faq details > div { padding-bottom: 24px; max-width: var(--maxw-text); }
.faq details p + p { margin-top: 12px; }

/* ---------- 13. CTA BAND ---------- */
.cta-band {
  background: var(--navy);
  color: rgba(255,255,255,.80);
  position: relative; overflow: hidden; isolation: isolate;
}
.cta-band::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: radial-gradient(ellipse 70% 100% at 85% 50%, rgba(192,160,98,.20), transparent 65%);
}
.cta-band__inner {
  max-width: var(--maxw); margin-inline: auto; padding: clamp(52px, 6vw, 84px) var(--gutter);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 32px;
}
.cta-band h2 { color: #fff; max-width: 20ch; }
.cta-band p { margin-top: 12px; color: rgba(255,255,255,.72); max-width: 46ch; }
.cta-band__actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* ---------- 14. FORMS ---------- */
.form { display: grid; gap: 18px; grid-template-columns: repeat(2, 1fr); }
.field { display: flex; flex-direction: column; gap: 7px; }
.field--wide { grid-column: 1 / -1; }
.field label { font-size: 13.5px; font-weight: 600; color: var(--navy); }
.field label .req { color: var(--gold-600); }
.field input, .field select, .field textarea {
  padding: 12px 14px;
  background: var(--surface);
  border: 1.5px solid var(--rule-strong);
  border-radius: var(--radius);
  font-size: 15.5px; color: var(--ink);
  transition: border-color var(--t), box-shadow var(--t);
}
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--navy-700); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(192,160,98,.22);
}
.field textarea { resize: vertical; min-height: 128px; }
.field__hint { font-size: 12.5px; color: var(--muted); }
.form .btn { grid-column: 1 / -1; }
.form__note { grid-column: 1 / -1; font-size: 13px; color: var(--muted); text-align: center; }

/* Honeypot. Hidden from people and from assistive technology alike, so a screen reader
   user is never asked to fill in a trap. .sr-only is deliberately NOT used here: it keeps
   the field announced, which would turn a spam measure into an accessibility failure. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
@media (max-width: 620px) { .form { grid-template-columns: 1fr; } }

/* ---------- 15. BREADCRUMB ---------- */
.crumbs { padding-block: 16px; border-bottom: 1px solid var(--rule); background: var(--surface); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }
.crumbs li::after { content: "/"; margin-left: 8px; color: var(--rule-strong); }
.crumbs li:last-child::after { content: none; }
.crumbs a:hover { color: var(--navy); }
.crumbs [aria-current="page"] { color: var(--navy); font-weight: 500; }

/* ---------- 16. FIGURES / MEDIA ---------- */
.figure { border-radius: var(--radius-lg); overflow: hidden; border: 1px solid var(--rule); background: var(--surface-alt); }
.figure img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
/* inline SVG diagrams: fill the figure and hold their own aspect ratio from viewBox */
.figure svg { width: 100%; height: auto; }
.figure figcaption { padding: 14px 20px; font-size: 13.5px; color: var(--muted); border-top: 1px solid var(--rule); }
.figure--wide img { aspect-ratio: 16 / 9; }

/* Two images side by side under one caption.

   Built for the case where the two sources are not the same kind of picture: a wide
   photograph next to a centred product shot on a plain background. The cells are
   identical boxes — same ratio, same border, same radius — so the pair aligns top and
   bottom whatever the sources measure. The fit mode is then set per cell rather than
   per pair, which is the point of the component: cover crops a photograph to fill,
   contain sits a cut-out inside the box without cropping it. One mode for both would
   ruin one of the two, so the cell carries the mode.

   The outer <figure> drops its own frame here. Each cell is already a bordered box, so
   keeping it would draw a second frame around the pair.

   CURRENTLY UNUSED, AND DELIBERATELY KEPT. No page carries a .figure--pair today. It was
   built for the equipment slot on capabilities.html, which was then removed because the
   only images available were vendor marketing shots. It stays because the deliverable
   screenshot pairs planned for drone-survey-usvi.html and scan-to-BIM-usvi.html want
   exactly this component, and rebuilding it later would repeat the two-fit-mode reasoning
   above from scratch. Do not delete it as dead code. Nothing in dev/audit-page.js checks
   for unused classes, so nothing will warn you before it is gone. */
.figure--pair { border: 0; border-radius: 0; background: none; overflow: visible; }
.figure--pair .figure__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.figure--pair .figure__cell {
  aspect-ratio: 3 / 2; overflow: hidden;
  border: 1px solid var(--rule); border-radius: var(--radius-lg);
  background: var(--surface-alt);
}
/* height:100% and aspect-ratio:auto undo the .figure img defaults, so the cell sets the
   ratio and the image fills it rather than carrying a 4/3 of its own. */
.figure--pair .figure__cell img {
  display: block; width: 100%; height: 100%;
  aspect-ratio: auto; object-fit: cover;
}
/* A product shot on a plain white background. Cover would crop it to the cell and leave
   the cut-out floating on a white rectangle that does not match anything else on the
   page; contain on --surface-alt sits it on a neutral field instead. */
.figure--pair .figure__cell.is-product img { object-fit: contain; padding: 8%; }
/* The caption belongs to the pair, so it sits below both cells with no frame to sit in. */
.figure--pair figcaption { padding: 14px 2px 0; border-top: 0; }

@media (max-width: 700px) {
  .figure--pair .figure__pair { grid-template-columns: 1fr; }
}

/* A slot held for photography that has not arrived yet. This is NOT a .placeholder:
   the dimensions and the caption are already decided, so the photograph drops in
   without the layout moving, and the label states what it must show so nobody fills
   it with something else. Every one of these is listed in DEFERRED.md and must be
   filled or removed before launch.

   .card__media--reserved is the same instrument inside a .card--media: the 16/10 box
   is already held by .card--media .card__media, so it only needs the panel treatment. */
.figure--reserved .figure__slot,
.card__media--reserved {
  display: grid; place-content: center; gap: 6px;
  padding: 24px; text-align: center;
  background: var(--navy-100); color: var(--navy);
  font-family: var(--mono); font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
}
.figure--reserved .figure__slot span,
.card__media--reserved span { font-size: 10.5px; color: var(--body); letter-spacing: .08em; }

/* Aspect-ratio utilities. Needed because a reserved slot has no <img> to carry
   width and height attributes, and inline styles are not permitted. */
.ratio-2-1  { aspect-ratio: 2 / 1; }
.ratio-3-2  { aspect-ratio: 3 / 2; }
.ratio-4-3  { aspect-ratio: 4 / 3; }
.ratio-16-9 { aspect-ratio: 16 / 9; }

.placeholder {
  display: grid; place-items: center; gap: 10px;
  aspect-ratio: 4 / 3; background:
    repeating-linear-gradient(45deg, rgba(31,58,95,.035) 0 12px, transparent 12px 24px), var(--surface-alt);
  color: var(--muted); font-family: var(--mono); font-size: 11.5px;
  letter-spacing: .1em; text-transform: uppercase; text-align: center; padding: 24px;
}
.placeholder--wide { aspect-ratio: 16 / 9; }

/* ---------- 17. PILLS, TAGS & SPEC LISTS ---------- */
.pills { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; }
.pill {
  padding: 6px 13px; border-radius: 999px;
  border: 1px solid var(--rule-strong); background: var(--surface);
  font-size: 13px; color: var(--body);
}
/* Navy text, not gold: --gold-600 on --gold-100 measures 4.46:1 and fails AA. --gold-100
   is warmer than --surface-alt, so it is the one light ground --gold-600 does not clear.
   The fill and border stay gold, so the pill still reads as the emphasised one. 10.02:1. */
.pill--gold { background: var(--gold-100); border-color: var(--gold-300); color: var(--navy); font-weight: 600; }
.section--navy .pill { background: rgba(255,255,255,.06); border-color: var(--rule-dark); color: rgba(255,255,255,.76); }

/* Label/value pairs: contact details, equipment specs, capability summaries —
   any short definition list. Works as <ul><li> with .label/.value spans, or as
   <dl> with each dt/dd pair wrapped in a <div>. */
.spec-list { display: flex; flex-direction: column; gap: 22px; margin-top: 32px; }
.spec-list li, .spec-list > div { display: flex; flex-direction: column; gap: 3px; }
.spec-list dt, .spec-list .label {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--muted);
}
.spec-list a, .spec-list .value { font-size: 16.5px; color: var(--navy); font-weight: 500; }
.spec-list a:hover { color: var(--gold-600); }

/* Dark context. Without these the label is --muted (2.96:1) and the value is --navy
   (1.12:1) on a dark card, which is effectively invisible. */
.section--navy .spec-list dt, .section--navy .spec-list .label { color: rgba(255,255,255,.62); }
.section--navy .spec-list a, .section--navy .spec-list .value { color: #fff; }
.section--navy .spec-list a:hover { color: var(--gold-300); }

/* ---------- 18. FOOTER ---------- */
.site-footer {
  margin-top: auto;
  background: var(--navy-950); color: rgba(255,255,255,.62);
  padding-block: clamp(52px, 5vw, 72px) 0;
  font-size: 14.5px;
}
.site-footer__grid {
  max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter);
  display: grid; gap: 40px;
  grid-template-columns: 1.4fr repeat(3, 1fr);
}
@media (max-width: 900px) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 560px) { .site-footer__grid { grid-template-columns: 1fr; } }

.site-footer h2 {
  font-family: var(--mono); font-size: 10.5px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--gold-300); margin-bottom: 18px;
}
.site-footer ul { display: flex; flex-direction: column; gap: 10px; }
.site-footer a:hover { color: #fff; }
.site-footer address { font-style: normal; line-height: 1.75; }
.site-footer .brand { margin-bottom: 18px; }
.site-footer__blurb { max-width: 34ch; line-height: 1.7; }

.site-footer__bar {
  max-width: var(--maxw); margin: clamp(44px, 4vw, 60px) auto 0;
  padding: 22px var(--gutter);
  border-top: 1px solid rgba(255,255,255,.10);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 14px;
  font-size: 13px; color: rgba(255,255,255,.46);
}
.site-footer__bar ul { flex-direction: row; gap: 20px; }

/* ---------- 19. REVEAL ---------- */
[data-reveal] {
  opacity: 0; transform: translateY(16px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
}
[data-reveal].is-visible { opacity: 1; transform: none; }
[data-reveal-delay="1"] { transition-delay: .07s; }
[data-reveal-delay="2"] { transition-delay: .14s; }
[data-reveal-delay="3"] { transition-delay: .21s; }
[data-reveal-delay="4"] { transition-delay: .28s; }

/* ---------- 20. PROSE ---------- */
.prose { max-width: var(--maxw-text); }
/* Centres the measure rather than widening it. For a short section that would otherwise
   sit in a narrow column against a wide dead right margin: the block moves to the middle
   of the container and the line length stays at a readable 68ch. Pair it with
   .section-head--center so the head and the body share an axis. */
.prose--center { margin-inline: auto; }
.prose > * + * { margin-top: 20px; }
.prose h2 { margin-top: 48px; font-size: var(--step-2); }
.prose h3 { margin-top: 34px; }
.prose ul { display: flex; flex-direction: column; gap: 10px; }
.prose ul li { position: relative; padding-left: 20px; }
.prose ul li::before { content: ""; position: absolute; left: 0; top: 11px; width: 6px; height: 6px; border-radius: 50%; background: var(--gold); }
.prose a { color: var(--navy); border-bottom: 1.5px solid var(--gold); }
.prose a:hover { color: var(--gold-600); }
.prose strong { color: var(--navy); font-weight: 600; }

/* ---------- 21. UTILITIES ---------- */
.center { text-align: center; }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 12px; }
.mt-2 { margin-top: 24px; }
.mt-3 { margin-top: 36px; }
.mt-4 { margin-top: 48px; }
.text-muted { color: var(--muted); }
.nowrap { white-space: nowrap; }

@media print {
  .site-header, .nav-toggle, .cta-band, .hero__topo { display: none !important; }
  body { color: #000; background: #fff; }
  a::after { content: " (" attr(href) ")"; font-size: 11px; }
}
