/* Self-hosted webfonts. No third-party request, no CDN dependency, no data
   leaving the visitor to another origin. Regenerate with tools/fetch-fonts.ps1. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/Archivo-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 700;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/Archivo-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 800;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/Archivo-800-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 800;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/Archivo-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/IBMPlexMono-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/IBMPlexSans-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 400;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/IBMPlexSans-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/IBMPlexSans-500-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 500;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/IBMPlexSans-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/IBMPlexSans-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'IBM Plex Sans';
  font-style: normal;
  font-weight: 600;
  font-stretch: 100%;
  font-display: swap;
  src: url('../fonts/IBMPlexSans-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ==========================================================================
   Lake Victoria Logistics — design system

   Direction: "instrument panel". The company runs a 70,000 m³ tank farm,
   927 m³/hr fire pumps and a 2.0 MVA plant — so every engineering figure on
   this site is set as an instrument readout (IBM Plex Mono, tabular figures,
   on a dark panel), and sections are separated by a gauge-tick rule borrowed
   from tank calibration strips and vessel draft marks.

   Palette from the corporate mark: lake blue, leaf green, fuel-drop yellow.
   Data-visualisation hues are the validated reference categorical palette,
   used unchanged and mapped to product grades.
   ========================================================================== */

:root{
  /* --- brand --- */
  --abyss:#04161F;          /* deep water — heaviest ground */
  --navy:#082A45;
  --navy-2:#0E3A5C;
  --blue:#1B75BC;
  --blue-600:#15629F;
  --blue-100:#E7F1FA;
  --sky:#29ABE2;
  --green:#39B54A;
  --lime:#8DC63F;
  --yellow:#F7C223;

  /* --- neutrals, biased cool to sit with the blues --- */
  --ink:#0B1C28;
  --ink-2:#3B5361;
  /* was #6A808E, which is 4.12:1 on white and 3.86:1 on --bg-2 — both under AA.
     This is the text-secondary-light value brand.md already proposed: 5.51:1 on
     white, 5.16:1 on --bg-2. */
  --ink-3:#5B6B76;
  --line:#DDE6EB;
  --line-2:#C2D1DA;
  /* Form control borders. --line-2 is 1.56:1 on white, which is fine for a
     decorative rule but under the 3:1 a UI boundary needs. This is brand.md's
     border-input-light, measured at 3.11:1. */
  --border-input:#7F95A5;
  --bg:#FFFFFF;
  --bg-2:#F4F8FA;
  --bg-3:#EBF2F6;

  /* --- product-grade hues (data only, never decoration) --- */
  --grade-ago:#2a78d6;
  --grade-pms:#eb6834;
  --grade-jet:#1baf7a;
  --grade-ik:#eda100;
  --grade-eth:#e87ba4;

  --radius:3px;
  --shadow-sm:0 1px 2px rgba(4,22,31,.05), 0 4px 12px -6px rgba(4,22,31,.13);
  --shadow-md:0 2px 4px rgba(4,22,31,.06), 0 16px 34px -16px rgba(4,22,31,.22);
  --shadow-lg:0 30px 70px -30px rgba(4,22,31,.5);

  --wrap:1180px;
  --gutter:24px;
  --header-h:78px;

  --f-display:"Archivo","Helvetica Neue",Arial,sans-serif;
  --f-body:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --f-mono:"IBM Plex Mono",ui-monospace,"Cascadia Mono",Consolas,monospace;

  /* --- motion (section 7.10). One 80ms base unit, one step per band:
     1 hover and colour (50-100ms)        2 small UI changes (150-200ms)
     3 disclosures, dropdowns (200-300ms) 4 drawers, overlays (300-500ms).
     An exit steps down one step and uses --ease-in, so it is always faster than
     the entrance it reverses. Nothing here is linear except .progress, which is
     a continuous readout of scroll position rather than a transition. --- */
  --dur-1:80ms;
  --dur-2:160ms;
  --dur-3:240ms;
  --dur-4:320ms;
  --ease-out:cubic-bezier(.22,.61,.36,1);
  --ease-in:cubic-bezier(.55,.06,.68,.19);

  /* --- icon sizes (section 7.5): 16 / 20 / 24, then 32-48 for standalone marks --- */
  --icon-sm:16px;
  --icon-md:20px;
  --icon-lg:24px;
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--header-h) + 66px)}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important}
}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font-family:var(--f-body);font-size:16.5px;line-height:1.68;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
img{max-width:100%;height:auto;display:block}
/* Photographs are large and served from the CMS host. Space is already reserved by
   aspect-ratio; this tint means a still-loading area reads as an image rather than
   as a hole in the page — which matters on the connections these users are on. */
.card-img img,.split img,.gal img,.article img,.hero-shot img,.panel .panel-body img,
.team-card img,figure > img{background:var(--bg-3)}
a{color:var(--blue-600);text-decoration:none;text-underline-offset:3px}
a:hover{text-decoration:underline}
:focus-visible{outline:3px solid var(--sky);outline-offset:3px;border-radius:2px}

h1,h2,h3,h4{font-family:var(--f-display);margin:0;line-height:1.06;text-wrap:balance;font-weight:700;letter-spacing:-.02em}
h1{font-size:clamp(30px,5.6vw,62px);font-weight:800}
h2{font-size:clamp(24px,3.8vw,42px)}
h3{font-size:clamp(19px,2.2vw,25px)}
/* .h4 renders a heading at the h4 scale without making it an h4. Card and list
   titles that sit under an h2 are h3 elements for the document outline, and wear
   this class so the page looks exactly as it did. */
h4,.h4{font-size:18px;letter-spacing:-.01em}
h4 + p,.h4 + p{margin-top:7px}
p{margin:0 0 1em}
p:last-child{margin-bottom:0}
strong{font-weight:600}

.wrap{max-width:var(--wrap);margin:0 auto;padding:0 var(--gutter)}
.skip{position:absolute;left:-9999px;top:0;background:var(--navy);color:#fff;padding:14px 20px;z-index:400;font-weight:600}
.skip:focus{left:0}

/* ---------- the gauge-tick rule: the site's recurring motif ---------- */
.ticks-rule{
  height:10px;width:100%;
  background-image:repeating-linear-gradient(90deg,var(--line-2) 0 1px,transparent 1px 11px);
  opacity:.85;
}
.ticks-rule.on-dark{background-image:repeating-linear-gradient(90deg,rgba(255,255,255,.26) 0 1px,transparent 1px 11px)}
.ticks-rule.accent{background-image:repeating-linear-gradient(90deg,var(--yellow) 0 2px,transparent 2px 11px);height:6px;opacity:1}

/* ---------- scroll progress ---------- */
.progress{position:fixed;top:0;left:0;height:3px;width:0;z-index:200;
  background:linear-gradient(90deg,var(--lime),var(--yellow));transition:width var(--dur-1) linear}

/* ---------- top bar ---------- */
.topbar{background:var(--abyss);color:#9FB8C6;font-size:13.5px;letter-spacing:.01em}
.topbar .wrap{display:flex;flex-wrap:wrap;gap:6px 26px;align-items:center;justify-content:flex-end;min-height:38px}
.topbar a{color:#CFE0EA}
.topbar a:hover{color:#fff}
.topbar span{display:inline-flex;align-items:center;gap:8px}
.topbar svg{width:var(--icon-sm);height:var(--icon-sm);flex:none;fill:var(--lime)}

/* ---------- header ---------- */
/* No backdrop-filter here: a filtered element becomes the containing block for its
   position:fixed descendants, which clamped the mobile drawer to the header box.
   At 97% opacity the blur was imperceptible anyway. */
.site-header{position:sticky;top:0;z-index:100;background:rgba(255,255,255,.97);
  border-bottom:1px solid var(--line);transition:box-shadow var(--dur-2) var(--ease-out)}
.site-header.stuck{box-shadow:0 2px 18px -6px rgba(4,22,31,.22)}
.site-header .wrap{display:flex;align-items:center;gap:20px;min-height:var(--header-h)}
.brand{display:flex;align-items:center;gap:12px;flex:none}
.brand img{width:44px;height:auto;mix-blend-mode:multiply}
.brand-txt{font-family:var(--f-display);font-weight:800;line-height:1;color:var(--navy);letter-spacing:-.02em}
.brand-txt b{display:block;font-size:20px}
.brand-txt i{display:block;font-style:normal;font-size:10px;letter-spacing:.26em;color:var(--blue);
  font-family:var(--f-mono);font-weight:500;margin-top:4px}

.nav{margin-left:auto;display:flex;align-items:center;gap:1px}
.nav a{
  position:relative;font-weight:500;font-size:15px;color:var(--ink-2);
  padding:9px 12px;border-radius:var(--radius);white-space:nowrap;text-decoration:none;
  transition:color var(--dur-1) var(--ease-out);
}
.nav a::after{
  content:"";position:absolute;left:12px;right:12px;bottom:2px;height:2px;background:var(--yellow);
  transform:scaleX(0);transform-origin:left;transition:transform var(--dur-1) var(--ease-out);
}
.nav a:hover{color:var(--navy);text-decoration:none}
.nav a:hover::after{transform:scaleX(1)}
.nav a[aria-current="page"]{color:var(--navy);font-weight:600}
.nav a[aria-current="page"]::after{transform:scaleX(1)}
/* .nav a sets --ink-2 at specificity (0,1,1) and outranks .btn at (0,1,0), so the
   button in the nav lost its white text and rendered at 1.66:1 on --blue — on every
   page. The aria-current variant needs the attribute too, to outrank the rule above.
   White on --blue is 4.86:1. */
.nav a.btn,.nav a.btn[aria-current="page"]{color:#fff}
.nav .btn{margin-left:12px}
.nav .btn::after{display:none}

.btn{
  display:inline-flex;align-items:center;gap:10px;
  font-family:var(--f-body);font-weight:600;font-size:15px;letter-spacing:.005em;
  padding:13px 24px;border-radius:var(--radius);border:1.5px solid transparent;
  background:var(--blue);color:#fff;cursor:pointer;text-decoration:none;
  transition:background var(--dur-1) var(--ease-out),color var(--dur-1) var(--ease-out),border-color var(--dur-1) var(--ease-out),transform var(--dur-1) var(--ease-out);
}
.btn:hover{background:var(--blue-600);color:#fff;text-decoration:none}
.btn:active{transform:translateY(1px)}
.btn svg{width:var(--icon-sm);height:var(--icon-sm);fill:currentColor;transition:transform var(--dur-1) var(--ease-out)}
.btn:hover svg{transform:translateX(3px)}
.btn-ghost{background:transparent;color:#fff;border-color:rgba(255,255,255,.42)}
.btn-ghost:hover{background:#fff;color:var(--navy);border-color:#fff}
.btn-outline{background:transparent;color:var(--blue-600);border-color:var(--line-2)}
.btn-outline:hover{background:var(--blue-100);color:var(--blue-600);border-color:var(--blue)}

.nav-toggle{display:none;margin-left:auto;background:none;border:1px solid var(--line-2);
  border-radius:var(--radius);padding:10px 12px;cursor:pointer;min-height:44px;min-width:44px}
.nav-toggle svg{width:var(--icon-md);height:var(--icon-md);fill:var(--navy);display:block}

/* The inline nav fits from 981px up: brand 183px + 20px gap + nav 730px = 933px of
   header content, plus two 24px gutters. Collapsing at 1060px put a hamburger on
   1024px laptops and landscape tablets for no reason, against section 7.1. Measured
   30 October 2026. site.js mirrors this query to close the drawer. */
@media (max-width:1023px){
  .nav-toggle{display:block}
  .nav{
    position:fixed;inset:0 0 0 auto;width:min(340px,88vw);background:#fff;
    flex-direction:column;align-items:stretch;gap:0;padding:26px 20px 40px;
    box-shadow:-10px 0 40px rgba(4,22,31,.25);transform:translateX(100%);
    transition:transform var(--dur-3) var(--ease-in);overflow-y:auto;margin-left:0;
  }
  .nav.open{transform:translateX(0);transition:transform var(--dur-4) var(--ease-out)}
  .nav::before{content:"Menu";font-family:var(--f-mono);font-size:10px;letter-spacing:.24em;
    text-transform:uppercase;color:var(--ink-3);padding:8px 4px 18px;display:block}
  .nav a{padding:15px 6px;border-bottom:1px solid var(--line);border-radius:0;font-size:17px;font-weight:500}
  .nav a::after{display:none}
  .nav a[aria-current="page"]{color:var(--blue-600);border-left:3px solid var(--yellow);padding-left:14px}
  .nav .btn{margin:22px 0 0;justify-content:center;border-bottom:none}
  .nav-backdrop{position:fixed;inset:0;background:rgba(4,22,31,.5);z-index:99;opacity:0;
    pointer-events:none;transition:opacity var(--dur-3) var(--ease-in)}
  .nav-backdrop.show{opacity:1;pointer-events:auto;transition:opacity var(--dur-4) var(--ease-out)}
}

/* ---------- hero ---------- */
.hero{position:relative;background:var(--abyss);color:#fff;overflow:hidden;isolation:isolate}
.hero-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.3;z-index:-2}
.hero::after{
  content:"";position:absolute;inset:0;z-index:-1;
  background:
    radial-gradient(900px 460px at 78% 8%,rgba(41,171,226,.24),transparent 62%),
    linear-gradient(101deg,rgba(4,22,31,.96) 0%,rgba(4,22,31,.84) 44%,rgba(14,58,92,.58) 100%);
}
.hero .wrap{position:relative;padding-top:86px;padding-bottom:0}
.hero-grid{display:grid;grid-template-columns:1.12fr .88fr;gap:56px;align-items:center;padding-bottom:86px}
.hero h1{color:#fff;margin-bottom:22px;letter-spacing:-.028em}
.hero .eyebrow{color:var(--lime)}
.hero .lead{font-size:19px;color:#C6DAE6;max-width:56ch}
.hero-cta{display:flex;flex-wrap:wrap;gap:14px;margin-top:34px}
.hero-shot{position:relative;border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow-lg);
  border:1px solid rgba(255,255,255,.14)}
.hero-shot img{width:100%;aspect-ratio:4/3;object-fit:cover}
.hero-shot figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:26px 20px 14px;
  background:linear-gradient(transparent,rgba(4,22,31,.9));
  font-family:var(--f-mono);font-size:11.5px;letter-spacing:.13em;text-transform:uppercase;color:#BFD6E3;
}
@media (max-width:900px){
  .hero-grid{grid-template-columns:1fr;gap:34px;padding-bottom:56px}
  .hero .wrap{padding-top:52px}
}

.eyebrow{
  font-family:var(--f-mono);font-weight:500;font-size:11.5px;letter-spacing:.2em;
  text-transform:uppercase;color:var(--blue);margin:0 0 16px;display:block;
}

/* ---------- instrument readouts (the motif) ---------- */
.stats{background:var(--navy);color:#fff;position:relative}
.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:1px;background:rgba(255,255,255,.16)}
.stats-grid div{background:var(--navy);padding:28px 24px;position:relative}
.stats-grid b{
  display:block;font-family:var(--f-mono);font-size:clamp(28px,3vw,38px);line-height:1;
  font-weight:500;font-variant-numeric:tabular-nums;letter-spacing:-.03em;color:#fff;
  white-space:nowrap;
}
.stats-grid b .u{font-size:.44em;color:var(--lime);letter-spacing:.02em;margin-left:6px;
  vertical-align:.34em;text-transform:none}
/* direct child only — must not also style the unit span inside <b> */
.stats-grid div > span{display:block;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.18em;
  text-transform:uppercase;color:#8FB0C4;margin-top:12px}
.stats-grid div::before{content:"";position:absolute;left:24px;top:0;width:26px;height:3px;background:var(--yellow)}

/* inline readout chip, for figures inside prose */
.readout{
  display:inline-flex;align-items:baseline;gap:8px;background:var(--abyss);color:#fff;
  padding:7px 13px;border-radius:var(--radius);font-family:var(--f-mono);
  font-variant-numeric:tabular-nums;font-size:15px;font-weight:500;letter-spacing:-.01em;
}
.readout em{font-style:normal;font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--lime)}

/* spec list — engineering key/value pairs */
.spec{list-style:none;margin:22px 0 0;padding:0;border-top:1px solid var(--line)}
.spec li{display:flex;justify-content:space-between;align-items:baseline;gap:20px;
  padding:11px 0;border-bottom:1px solid var(--line)}
.spec dt,.spec .k{font-size:14.5px;color:var(--ink-2)}
.spec dd,.spec .v{margin:0;font-family:var(--f-mono);font-size:14.5px;font-weight:500;
  font-variant-numeric:tabular-nums;color:var(--ink);text-align:right}
.section-dark .spec{border-color:rgba(255,255,255,.16)}
.section-dark .spec li{border-color:rgba(255,255,255,.16)}
.section-dark .spec .k{color:#A9C4D3}
.section-dark .spec .v{color:#fff}

/* ---------- sections ---------- */
.section{padding:88px 0}
.section-tint{background:var(--bg-2)}
.section-dark{background:var(--navy);color:#fff}
.section-abyss{background:var(--abyss);color:#fff}
.section-dark h2,.section-dark h3,.section-dark h4,
.section-abyss h2,.section-abyss h3,.section-abyss h4{color:#fff}
.section-dark .lead,.section-dark p,.section-abyss .lead,.section-abyss p{color:#B6CEDC}
.section-dark .eyebrow,.section-abyss .eyebrow{color:var(--lime)}
.section-dark .muted,.section-abyss .muted{color:#8FB0C4}
@media (max-width:700px){.section{padding:58px 0}}

.section-head{max-width:70ch;margin-bottom:48px}
.section-head.center{margin-left:auto;margin-right:auto;text-align:center}
.section-head .lead{font-size:18.5px;color:var(--ink-2);margin-top:18px}
/* The rule above and .section-dark .lead have equal specificity (0,2,0), and this
   one is declared later, so a lead inside a dark section rendered --ink-2 on navy
   at 1.82:1 — dark text on a dark ground. One more class settles it: #B6CEDC is
   9.00:1 on --navy and 11.28:1 on --abyss. */
.section-dark .section-head .lead,.section-abyss .section-head .lead{color:#B6CEDC}

.grid{display:grid;gap:26px}
.g-1{grid-template-columns:1fr}
.g-2{grid-template-columns:repeat(2,1fr)}
.g-3{grid-template-columns:repeat(3,1fr)}
.g-4{grid-template-columns:repeat(4,1fr)}
@media (max-width:980px){.g-3,.g-4{grid-template-columns:repeat(2,1fr)}}
@media (max-width:640px){.g-2,.g-3,.g-4{grid-template-columns:1fr}}

/* ---------- in-page section navigation (long pages) ---------- */
.subnav{position:sticky;top:var(--header-h);z-index:90;background:rgba(255,255,255,.97);
  border-bottom:1px solid var(--line)}
.subnav .wrap{display:flex;gap:2px;overflow-x:auto;scrollbar-width:thin;min-height:56px;align-items:center}
.subnav a{font-family:var(--f-mono);font-size:12px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--ink-3);padding:8px 14px;white-space:nowrap;border-bottom:2px solid transparent;
  transition:color var(--dur-1) var(--ease-out),border-color var(--dur-1) var(--ease-out)}
.subnav a:hover{color:var(--navy);text-decoration:none}
.subnav a.active{color:var(--navy);border-bottom-color:var(--yellow)}
/* The section nav sticks below the header at every width. It used to be pinned to
   top:0 below 1060px, where the sticky header (79px, z-index 100) covered all 57px
   of it (z-index 90) the moment it stuck — so on every phone, tablet and 1024px
   laptop the section nav vanished as soon as you scrolled past it. Measured
   30 October 2026; scroll-padding-top already assumed the offset. */

/* ---------- cards ---------- */
.card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:32px 28px;
  display:flex;flex-direction:column}
.card-hover{transition:box-shadow var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out),border-color var(--dur-2) var(--ease-out)}
.card-hover:hover{box-shadow:var(--shadow-md);border-color:var(--line-2);transform:translateY(-4px)}
.card h3{margin-bottom:13px;color:var(--navy)}
.card p{color:var(--ink-2);font-size:15.5px}
.card .marker{width:38px;height:3px;background:var(--yellow);margin-bottom:22px}
/* A logo inside a column flexbox must opt out of align-items:stretch, or it is
   pulled to the full card width while max-height caps it — which flattens every
   mark to the same box and destroys its aspect ratio. object-fit is the backstop. */
.card-logo{height:50px;width:auto;max-width:82%;object-fit:contain;object-position:left center;
  align-self:flex-start;margin-bottom:22px;background:transparent}
.card-stat{margin-top:auto;padding-top:20px}
.card .num{font-family:var(--f-mono);font-size:11px;letter-spacing:.18em;color:var(--ink-3);
  display:block;margin-bottom:14px}

.ticks{list-style:none;margin:20px 0 0;padding:0;display:flex;flex-direction:column;gap:10px}
.ticks li{position:relative;padding-left:26px;font-size:15px;color:var(--ink-2)}
.ticks li::before{
  content:"";position:absolute;left:0;top:8px;width:13px;height:8px;
  border-left:2px solid var(--green);border-bottom:2px solid var(--green);transform:rotate(-45deg);
}
.section-dark .ticks li,.section-abyss .ticks li{color:#BCD3E1}
.section-dark .ticks li::before,.section-abyss .ticks li::before{border-color:var(--lime)}

.card-img{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:#fff;
  display:flex;flex-direction:column;transition:box-shadow var(--dur-2) var(--ease-out),transform var(--dur-2) var(--ease-out)}
.card-img:hover{box-shadow:var(--shadow-md);transform:translateY(-3px)}
.card-img img{width:100%;aspect-ratio:16/10;object-fit:cover}
.card-img .body{padding:28px}
.card-img h3{color:var(--navy);margin-bottom:11px}
.card-img p{color:var(--ink-2);font-size:15.5px}

/* ---------- split rows ---------- */
.split{display:grid;grid-template-columns:1fr 1fr;gap:58px;align-items:center}
.split + .split{margin-top:80px}
.split img{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:var(--radius);box-shadow:var(--shadow-md)}
.split.flip .split-media{order:2}
@media (max-width:860px){
  .split{grid-template-columns:1fr;gap:30px}
  .split + .split{margin-top:54px}
  .split.flip .split-media{order:0}
}
.split h2,.split h3{color:var(--navy);margin-bottom:18px}
.section-dark .split h2,.section-dark .split h3,
.section-abyss .split h2,.section-abyss .split h3{color:#fff}
.split p{color:var(--ink-2)}

/* ---------- page header ---------- */
.page-head{background:var(--abyss);color:#fff;position:relative;overflow:hidden}
.page-head::before{
  content:"";position:absolute;inset:0;
  background:radial-gradient(1000px 380px at 86% -14%,rgba(41,171,226,.3),transparent 62%);
}
/* must keep the horizontal gutter — zeroing it put the heading and lead flush
   against the screen edge on every inner page below 1180px */
.page-head .wrap{position:relative;padding:60px var(--gutter) 66px}
.page-head h1{color:#fff;max-width:19ch;letter-spacing:-.03em}
.page-head p{color:#B6CEDC;font-size:18.5px;max-width:66ch;margin-top:20px}
.crumb{font-family:var(--f-mono);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;
  color:#7C9CB0;margin-bottom:24px}
.crumb a{color:#B6CEDC}
/* The separator used to be #456A81, 3.19:1 on --abyss. It now inherits the crumb
   colour at 6.35:1; the links stay lighter, so the hierarchy still reads. */
.crumb span{margin:0 10px}

/* ---------- logo wall ---------- */
/* Collapsed borders rather than a 1px gap over a tinted backing: a ragged final
   row then simply ends, instead of showing empty tinted cells. */
.logos{display:grid;grid-template-columns:repeat(5,1fr);gap:0;background:transparent;border:0}
.logos.logos-4{grid-template-columns:repeat(4,1fr)}
@media (max-width:1000px){.logos,.logos.logos-4{grid-template-columns:repeat(3,1fr)}}
@media (max-width:620px){.logos,.logos.logos-4{grid-template-columns:repeat(2,1fr)}}
.logos div{background:#fff;display:flex;align-items:center;justify-content:center;
  padding:28px 22px;min-height:122px;border:1px solid var(--line);margin:0 -1px -1px 0}
.logos img{max-height:54px;width:auto;object-fit:contain;filter:grayscale(1);opacity:.62;
  transition:filter var(--dur-2) var(--ease-out),opacity var(--dur-2) var(--ease-out)}
.logos div:hover img{filter:none;opacity:1}

/* ---------- timeline ---------- */
.timeline{position:relative;padding-left:38px}
.timeline::before{content:"";position:absolute;left:9px;top:8px;bottom:8px;width:2px;
  background:repeating-linear-gradient(180deg,var(--line-2) 0 5px,transparent 5px 10px)}
.tl-item{position:relative;padding-bottom:40px}
.tl-item:last-child{padding-bottom:0}
.tl-item::before{content:"";position:absolute;left:-36px;top:7px;width:20px;height:20px;border-radius:50%;
  background:#fff;border:4px solid var(--blue)}
.tl-year{font-family:var(--f-mono);font-size:26px;font-weight:500;color:var(--blue);line-height:1;
  font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.tl-item h3{margin:9px 0 9px;color:var(--navy)}
.tl-item p{color:var(--ink-2);font-size:15.5px}

/* ---------- team ---------- */
.team-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;
  display:flex;flex-direction:column}
.team-card img{width:100%;aspect-ratio:1/1;object-fit:cover;object-position:center top;background:var(--bg-3)}
.team-card .body{padding:26px}
.team-card h3{font-size:21px;color:var(--navy);margin-bottom:5px}
.team-card .role{font-family:var(--f-mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--blue);margin-bottom:16px}
.team-card .bio{font-size:15px;color:var(--ink-2);white-space:pre-line}
details.bio-more{margin-top:12px}
details.bio-more summary{cursor:pointer;font-weight:600;font-size:14.5px;color:var(--blue-600);
  list-style:none;padding:8px 0;display:inline-flex;align-items:center;gap:8px}
details.bio-more summary::-webkit-details-marker{display:none}
details.bio-more summary::after{content:"▾";transition:transform var(--dur-2) var(--ease-out)}
details[open].bio-more summary::after{transform:rotate(180deg)}

/* ---------- accordion panels ---------- */
.panel{border:1px solid var(--line);border-radius:var(--radius);background:#fff;overflow:hidden}
.panel + .panel{margin-top:12px}
.panel summary{cursor:pointer;padding:24px 28px;font-family:var(--f-display);font-size:21px;font-weight:700;
  letter-spacing:-.015em;color:var(--navy);display:flex;align-items:center;gap:16px;list-style:none}
.panel summary::-webkit-details-marker{display:none}
.panel summary::after{content:"";margin-left:auto;flex:none;width:13px;height:13px;
  border-right:2px solid var(--blue);border-bottom:2px solid var(--blue);
  transform:rotate(45deg);transition:transform var(--dur-2) var(--ease-out);margin-top:-5px}
.panel[open] summary::after{transform:rotate(225deg);margin-top:3px}
.panel summary:hover{background:var(--bg-2)}
.panel .panel-body{padding:0 28px 28px;display:grid;grid-template-columns:1fr 1fr;gap:32px;align-items:start}
.panel .panel-body img{border-radius:var(--radius);width:100%;aspect-ratio:4/3;object-fit:cover}
.panel .panel-body p{color:var(--ink-2)}
@media (max-width:800px){.panel .panel-body{grid-template-columns:1fr}}

/* ---------- tables ---------- */
.table-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius);background:#fff}
/* Dark sections tint their descendants light, but a card, panel or table wrapper
   keeps its own white surface inside one — so those light colours have to be undone
   there, or the text lands light-on-light. Measured before this block: list text at
   #BCD3E1 on white = 1.55:1, a table caption at #8FB0C4 on white = 2.29:1, and any
   heading would have gone white on white. .chart is deliberately excluded, since it
   switches to a translucent dark surface of its own.

   Each selector is one level more specific than the dark-section rule it undoes. */
:is(.section-dark,.section-abyss) :is(.card,.card-img,.panel,.table-wrap){color:var(--ink)}
:is(.section-dark,.section-abyss) :is(.card,.card-img,.panel,.table-wrap) :is(h2,h3,h4){color:var(--navy)}
:is(.section-dark,.section-abyss) :is(.card,.card-img,.panel,.table-wrap) :is(p,.lead,.ticks li){color:var(--ink-2)}
:is(.section-dark,.section-abyss) :is(.card,.card-img,.panel,.table-wrap) .muted{color:var(--ink-3)}

/* .split has no surface of its own, so inside a dark section its text must stay
   light. .split p and .section-dark p have equal specificity and .split p is
   declared later, which rendered --ink-2 on navy at 1.82:1. */
:is(.section-dark,.section-abyss) .split p{color:#B6CEDC}
table{border-collapse:collapse;width:100%;min-width:640px;font-size:15px}
th,td{text-align:left;padding:15px 18px;border-bottom:1px solid var(--line)}
th{font-family:var(--f-mono);font-size:11px;font-weight:500;letter-spacing:.15em;text-transform:uppercase;
  color:var(--ink-3);background:var(--bg-2)}
td{color:var(--ink-2)}
td:first-child{color:var(--ink);font-weight:600}
tbody tr:hover{background:var(--bg-2)}
tr:last-child td{border-bottom:none}
td.num{font-variant-numeric:tabular-nums;text-align:right;font-family:var(--f-mono);font-size:14px;
  color:var(--ink);white-space:nowrap}
/* product-grade swatch in the first cell */
td .swatch{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:9px;vertical-align:baseline}

/* ---------- charts ---------- */
.chart{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:30px 30px 24px}
.section-dark .chart,.section-abyss .chart{background:rgba(255,255,255,.045);border-color:rgba(255,255,255,.16)}
.chart-title{font-family:var(--f-display);font-size:20px;font-weight:700;letter-spacing:-.015em;
  color:var(--navy);margin:0 0 4px}
.section-dark .chart-title,.section-abyss .chart-title{color:#fff}
.chart-sub{font-size:14px;color:var(--ink-3);margin:0 0 26px}
.section-dark .chart-sub,.section-abyss .chart-sub{color:#8FB0C4}
.bars{display:flex;flex-direction:column;gap:16px}
.bar-row{display:grid;grid-template-columns:170px 1fr;gap:18px;align-items:center}
.bar-label{font-size:14.5px;color:var(--ink-2);display:flex;align-items:center;gap:9px;line-height:1.3}
.section-dark .bar-label,.section-abyss .bar-label{color:#C3D8E4}
.bar-label .swatch{width:10px;height:10px;border-radius:2px;flex:none}
/* Fixed value column so the plot area is identical on every row — with flex the
   fill was shrunk by each row's own label width, which silently distorted scale. */
.bar-track{position:relative;display:grid;grid-template-columns:minmax(0,1fr) 196px;
  gap:14px;align-items:center}
.chart-narrow .bar-track{grid-template-columns:minmax(0,1fr) 132px}
.bar-fill{height:22px;border-radius:0 4px 4px 0;min-width:3px}
.bar-val{font-family:var(--f-mono);font-size:13.5px;font-variant-numeric:tabular-nums;color:var(--ink);
  white-space:nowrap;font-weight:500;text-align:left}
.section-dark .bar-val,.section-abyss .bar-val{color:#fff}
.bar-row:hover .bar-fill{filter:brightness(1.08)}

/* The chart tooltip. Its position and opacity are set from script, but its look
   belongs here rather than in a cssText assignment. */
.chart-tip{position:fixed;z-index:250;pointer-events:none;opacity:0;
  background:var(--abyss);color:#fff;padding:9px 13px;border-radius:var(--radius);
  font-size:13px;font-family:var(--f-mono);line-height:1.5;max-width:280px;
  transition:opacity var(--dur-1) var(--ease-out);box-shadow:0 10px 30px -10px rgba(0,0,0,.6)}

/* Product-grade fills for swatches and bars. Data-only hues: never use these for
   UI or decoration, and always keep the text label beside them. */
.g-ago{background:var(--grade-ago)}
.g-pms{background:var(--grade-pms)}
.g-jet{background:var(--grade-jet)}
.g-ik{background:var(--grade-ik)}
.g-eth{background:var(--grade-eth)}

/* Bar lengths. These are data rather than styling — each is a volume from
   data/*.json expressed as a percentage of its chart — and they live here only
   because a style attribute would be blocked by the CSP. A content refresh that
   changes a volume has to change the class on the bar AND the percentage here.
   The gate checks the printed figure against data/*.json but cannot check a bar
   length, so this is the one place a refresh can silently go stale — recorded
   against item 3.1 in UPGRADE-PLAN.md. */
.w-1-6{width:1.6%}
.w-7-4{width:7.4%}
.w-22-2{width:22.2%}
.w-29-6{width:29.6%}
.w-82-7{width:82.7%}
.w-100{width:100%}
.chart-foot{margin-top:24px;padding-top:18px;border-top:1px solid var(--line);
  font-family:var(--f-mono);font-size:11.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-3);
  display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap}
.section-dark .chart-foot,.section-abyss .chart-foot{border-color:rgba(255,255,255,.16);color:#8FB0C4}
@media (max-width:620px){
  /* Narrow screens: the value moves under the bar. Sharing the row with an "auto"
     value column left the plot area only ~38px wide, which turned a 2,000,000 L
     bar into a 4px stub — the chart has to keep the full width to stay readable. */
  .bar-row{grid-template-columns:1fr;gap:8px}
  .bar-track,.chart-narrow .bar-track{grid-template-columns:1fr;gap:7px}
  .bar-fill{min-width:4px}
  .bar-val{font-size:13px}
  .bar-label{font-weight:500}
  .chart{padding:24px 20px 20px}
}

/* ---------- process steps ---------- */
.steps{counter-reset:step;display:grid;gap:18px}
.step{position:relative;background:#fff;border:1px solid var(--line);border-radius:var(--radius);
  padding:26px 28px 26px 84px}
.step::before{counter-increment:step;content:counter(step,decimal-leading-zero);
  position:absolute;left:28px;top:25px;font-family:var(--f-mono);font-size:24px;font-weight:500;
  color:var(--blue);line-height:1;font-variant-numeric:tabular-nums}
.step::after{content:"";position:absolute;left:30px;top:56px;bottom:22px;width:1px;background:var(--line)}
.step:last-child::after{display:none}
.step h4{color:var(--navy);margin-bottom:8px;font-family:var(--f-display);font-size:19px}
.step p{color:var(--ink-2);font-size:15.5px}
.section-dark .step,.section-abyss .step{background:rgba(255,255,255,.045);border-color:rgba(255,255,255,.14)}
.section-dark .step h4,.section-abyss .step h4{color:#fff}
.section-dark .step p,.section-abyss .step p{color:#B6CEDC}
.section-dark .step::before,.section-abyss .step::before{color:var(--lime)}
.section-dark .step::after,.section-abyss .step::after{background:rgba(255,255,255,.16)}

/* ---------- pillars ---------- */
.pillar{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:28px;
  position:relative;transition:transform var(--dur-2) var(--ease-out),box-shadow var(--dur-2) var(--ease-out)}
.pillar::before{content:"";position:absolute;left:0;top:0;width:100%;height:3px;background:var(--green)}
.pillar:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}
.pillar h3{font-size:21px;color:var(--navy);margin-bottom:11px}
.pillar p{font-size:15px;color:var(--ink-2)}

/* ---------- gallery ---------- */
.gal{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:18px}
.gal figure{margin:0;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:#fff}
.gal button.gal-btn{display:block;width:100%;padding:0;border:0;background:none;cursor:zoom-in}
.gal img{width:100%;aspect-ratio:4/3;object-fit:cover;transition:transform var(--dur-2) var(--ease-out)}
.gal figure:hover img{transform:scale(1.05)}
.gal figcaption{padding:14px 16px;font-size:14.5px;color:var(--ink-2);border-top:1px solid var(--line)}
.lightbox{position:fixed;inset:0;background:rgba(4,14,20,.96);z-index:300;display:none;
  align-items:center;justify-content:center;padding:70px 24px}
.lightbox.open{display:flex}
.lightbox img{max-width:min(1180px,92vw);max-height:78vh;width:auto;border-radius:var(--radius);
  transition:opacity var(--dur-2) var(--ease-out)}
/* While the next photograph loads the one on screen dims instead of being replaced
   early, because the picture, its caption and the counter only ever change together.
   A dimmed frame is therefore always the last correct one. site.js adds .loading. */
.lightbox.loading img{opacity:.45}
.lb-btn{position:absolute;background:rgba(255,255,255,.1);border:1px solid rgba(255,255,255,.24);
  color:#fff;cursor:pointer;border-radius:var(--radius);width:48px;height:48px;display:flex;
  align-items:center;justify-content:center;transition:background var(--dur-1) var(--ease-out)}
.lb-btn:hover{background:rgba(255,255,255,.22)}
.lb-btn svg{width:var(--icon-md);height:var(--icon-md);fill:#fff}
.lb-close{top:22px;right:24px}
.lb-prev{left:24px;top:50%;transform:translateY(-50%)}
.lb-next{right:24px;top:50%;transform:translateY(-50%)}
.lb-cap{position:absolute;left:0;right:0;bottom:24px;text-align:center;color:#C6DAE6;font-size:15px;padding:0 24px}
.lb-count{font-family:var(--f-mono);font-size:11.5px;letter-spacing:.16em;color:#7C9CB0;display:block;margin-top:8px}
@media (max-width:640px){.lb-prev{left:10px}.lb-next{right:10px}.lightbox{padding:64px 12px}}

/* ---------- articles ---------- */
.article{display:grid;grid-template-columns:310px 1fr;gap:30px;background:#fff;border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden}
.article + .article{margin-top:20px}
.article img{width:100%;height:100%;min-height:210px;object-fit:cover}
.article .body{padding:30px 32px 30px 0}
.article .meta{font-family:var(--f-mono);font-size:11.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--blue);margin-bottom:12px}
.article h3{color:var(--navy);margin-bottom:12px}
.article p{color:var(--ink-2);font-size:15.5px}
@media (max-width:760px){
  .article{grid-template-columns:1fr}
  .article img{min-height:0;aspect-ratio:16/9}
  .article .body{padding:26px}
}

/* ---------- contact ---------- */
.contact-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:58px;align-items:start}
@media (max-width:900px){.contact-grid{grid-template-columns:1fr;gap:40px}}
.field{margin-bottom:21px}
.field label{display:block;font-weight:600;font-size:14.5px;color:var(--navy);margin-bottom:8px}
.field .req{color:#C0392B}
.field input,.field textarea{width:100%;padding:14px 15px;border:1px solid var(--border-input);
  border-radius:var(--radius);font-family:var(--f-body);font-size:16px;color:var(--ink);background:#fff;
  transition:border-color var(--dur-1) var(--ease-out),box-shadow var(--dur-1) var(--ease-out)}
.field input:focus,.field textarea:focus{border-color:var(--blue);outline:none;box-shadow:0 0 0 3px var(--blue-100)}
.field textarea{min-height:152px;resize:vertical}
.field .err{color:#C0392B;font-size:14px;margin-top:7px;display:none}
.field.invalid input,.field.invalid textarea{border-color:#C0392B}
.field.invalid .err{display:block}
/* --ink-3 now passes at 5.51:1, but this note carries the privacy disclosure at the
   point of collection, so it deliberately keeps the stronger --ink-2 at 8.08:1. */
.form-note{font-size:14px;color:var(--ink-2);margin-top:16px}

/* Error summary. Shown only after a failed submit, announced as an alert, and
   given focus so the whole list is read before the fields are revisited.
   #9C2C1E on #FDECEA is 6.58:1; the links are underlined, so the colour is not
   doing the work on its own. */
.form-errors{background:#FDECEA;border:1px solid #E4A19A;border-left:3px solid #C0392B;
  border-radius:var(--radius);padding:16px 18px;margin-bottom:22px;font-size:15px}
.form-errors[hidden]{display:none}
.form-errors strong{display:block;color:#9C2C1E;margin-bottom:8px}
.form-errors ul{margin:0;padding-left:20px}
.form-errors li{margin-top:4px}
.form-errors a{color:#9C2C1E;text-decoration:underline}

/* Dialling code beside the national number, so a pasted local number still
   stores as E.164. */
.phone-row{display:flex;gap:8px}
.phone-row select{flex:none;padding:14px 12px;border:1px solid var(--border-input);
  border-radius:var(--radius);background:#fff;color:var(--ink);
  font-family:var(--f-body);font-size:16px}
.phone-row select:focus{border-color:var(--blue);outline:none;box-shadow:0 0 0 3px var(--blue-100)}
.phone-row input{flex:1 1 auto;min-width:0}
.form-msg{padding:16px 18px;border-radius:var(--radius);margin-bottom:22px;display:none;font-size:15.5px}
.form-msg.ok{display:block;background:#E7F5EC;border:1px solid var(--green);color:#1C6B31}
.form-msg.bad{display:block;background:#FDECEA;border:1px solid #E4A19A;color:#9C2C1E}
.info-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:24px}
.info-list li{display:flex;gap:17px;align-items:flex-start}
.info-list .ico{flex:none;width:44px;height:44px;border-radius:var(--radius);background:var(--blue-100);
  display:flex;align-items:center;justify-content:center}
.info-list .ico svg{width:var(--icon-md);height:var(--icon-md);fill:var(--blue-600)}
.info-list h4,.info-list .h4{font-family:var(--f-mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:5px;font-weight:500}
.info-list p{color:var(--ink);font-size:16px}

/* ---------- CTA ---------- */
.cta{background:var(--abyss);color:#fff;position:relative;overflow:hidden}
.cta::before{content:"";position:absolute;inset:0;
  background:radial-gradient(700px 300px at 12% 120%,rgba(57,181,74,.22),transparent 60%)}
.cta .wrap{position:relative;padding:64px var(--gutter);display:flex;flex-wrap:wrap;gap:32px;
  align-items:center;justify-content:space-between}
.cta h2{color:#fff;margin-bottom:10px}
.cta p{color:#B6CEDC;max-width:54ch}

/* ---------- footer ---------- */
.site-footer{background:var(--abyss);color:#93AEBE;font-size:15px;padding:66px 0 0}
.foot-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1.2fr;gap:44px;padding-bottom:52px}
@media (max-width:900px){.foot-grid{grid-template-columns:1fr 1fr;gap:36px}}
@media (max-width:560px){.foot-grid{grid-template-columns:1fr}}
.site-footer h4{font-family:var(--f-mono);font-size:11px;letter-spacing:.2em;text-transform:uppercase;
  color:#fff;margin-bottom:20px;font-weight:500}
.site-footer ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:11px}
.site-footer a{color:#93AEBE}
.site-footer a:hover{color:#fff}
.foot-brand{display:flex;align-items:center;gap:13px;margin-bottom:20px}
.foot-brand img{width:50px;background:#fff;padding:5px;border-radius:var(--radius)}
.foot-brand .brand-txt b{color:#fff;font-size:19px}
.foot-brand .brand-txt i{color:var(--lime)}
.foot-bottom{border-top:1px solid rgba(255,255,255,.12);padding:24px 0;display:flex;flex-wrap:wrap;
  gap:12px;justify-content:space-between;font-size:13.5px}
/* A link on the legal line is the same colour as the text beside it, so it is
   underlined — colour is never the only signal — and padded to clear 24px. */
.foot-bottom a{display:inline-block;padding:4px 0;text-decoration:underline}

/* ---------- back to top ---------- */
/* Touch targets. WCAG 2.2 SC 2.5.8 exempts links inline in a sentence, but the
   footer and top-bar links are standalone navigation — on touch widths they get
   real padding so each one clears the minimum comfortably. */
@media (max-width:900px){
  .site-footer ul{gap:0}
  .site-footer ul li a{display:block;padding:13px 0}
  .topbar .wrap{justify-content:flex-start;min-height:44px}
  .topbar span{padding:4px 0}
  .topbar a{display:inline-block;padding:7px 0}
  .crumb a{display:inline-block;padding:8px 0}
  .info-list p a{display:inline-block;padding:6px 0}
}

.to-top{position:fixed;right:22px;bottom:22px;z-index:95;width:46px;height:46px;border-radius:50%;
  background:var(--navy);border:0;cursor:pointer;display:flex;align-items:center;justify-content:center;
  opacity:0;pointer-events:none;transform:translateY(10px);
  transition:opacity var(--dur-2) var(--ease-in),transform var(--dur-2) var(--ease-in);box-shadow:var(--shadow-md)}
.to-top.show{opacity:1;pointer-events:auto;transform:translateY(0);
  transition:opacity var(--dur-3) var(--ease-out),transform var(--dur-3) var(--ease-out)}
.to-top:hover{background:var(--blue)}
.to-top svg{width:var(--icon-md);height:var(--icon-md);fill:#fff}

/* ---------- reveal on scroll (starts visible; enhanced only when JS runs) ---------- */
.js-reveal{opacity:0;transform:translateY(14px);transition:opacity var(--dur-4) var(--ease-out),transform var(--dur-4) var(--ease-out)}
.js-reveal.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.js-reveal{opacity:1;transform:none}}

/* ==========================================================================
   Phone refinements. The desktop rhythm — generous padding, centred section
   heads, a four-across stat band — does not survive a 375px column: it turns
   into a very long scroll of half-empty blocks. These reset it.
   ========================================================================== */
@media (max-width:760px){
  /* utility bar: one compact line. The location also lives in the footer,
     so it is dropped here rather than wrapping onto a second row. */
  .topbar{font-size:12.5px}
  .topbar .wrap{min-height:38px;gap:0;flex-wrap:nowrap;justify-content:flex-start}
  .topbar span + span{display:none}
  .topbar span{padding:0}
  .topbar a{padding:9px 0}

  /* hero: tighter, and the two calls to action stop looking ragged */
  .hero .wrap{padding-top:38px}
  .hero-grid{gap:26px;padding-bottom:40px}
  .hero h1{margin-bottom:16px}
  .hero .lead{font-size:16.5px;line-height:1.6}
  .hero-cta{gap:10px;margin-top:26px}
  .hero-cta .btn{flex:1 1 100%;justify-content:center}
  .eyebrow{font-size:10.5px;letter-spacing:.15em;margin-bottom:12px}

  /* stat band: 2x2 beats a 430px-tall single column */
  .stats-grid{grid-template-columns:1fr 1fr}
  .stats-grid div{padding:20px 8px 20px 18px}
  .stats-grid b{font-size:25px}
  .stats-grid div::before{left:18px;width:20px}
  .stats-grid div > span{font-size:9.5px;letter-spacing:.13em;margin-top:8px}

  /* centred headings read poorly in a narrow column */
  .section-head{margin-bottom:32px}
  .section-head.center{text-align:left;margin-left:0;margin-right:0}
  .section-head .lead{font-size:16.5px}
  .section{padding:48px 0}

  /* reclaim padding that was sized for a 370px card, not a 327px screen */
  .card{padding:26px 22px}
  .card-img .body{padding:22px}
  .panel summary{padding:20px 20px;font-size:19px}
  .panel .panel-body{padding:0 20px 22px}
  .step{padding:22px 22px 22px 68px}
  .step::before{left:22px;top:22px;font-size:21px}
  .step::after{left:24px}
  .pillar{padding:24px}
  .page-head .wrap{padding:40px var(--gutter) 44px}
  .page-head p{font-size:16.5px;margin-top:14px}
  .cta .wrap{padding:44px var(--gutter)}
  .cta .btn{width:100%;justify-content:center}
  .grid{gap:18px}
  .split + .split{margin-top:42px}
  .rule{margin:40px 0}
  .mt-56{margin-top:36px}
  .mt-40{margin-top:28px}

  /* the section nav scrolls sideways; without this the last item just looks
     clipped rather than scrollable */
  .subnav{position:sticky}
  .subnav .wrap{position:relative}
  .subnav::after{content:"";position:absolute;right:0;top:0;bottom:1px;width:38px;pointer-events:none;
    background:linear-gradient(90deg,rgba(255,255,255,0),rgba(255,255,255,.97) 70%)}
  .subnav .wrap{padding-right:38px}

  /* a 122px cell x 5 rows made the client wall 605px tall on a phone */
  .logos div{min-height:86px;padding:18px 14px}
  .logos img{max-height:40px}

  /* the floating button was landing on card text */
  .to-top{right:14px;bottom:14px;width:42px;height:42px}
}

/* ---------- utilities ---------- */
.lead{font-size:18.5px}
.muted{color:var(--ink-3)}

/* ---------- legal and policy prose ---------- */
/* One readable column for text-only pages such as the privacy policy. 68ch keeps
   lines inside the 45-75 character range; the base h2 clamp tops out at 42px,
   which is too loud for a policy heading, so it steps down here. */
.prose{max-width:68ch}
.prose h2{margin-top:48px;font-size:clamp(21px,2.6vw,28px);line-height:1.2}
.prose h2:first-child{margin-top:0}
.prose ul{margin:0 0 1em;padding-left:24px}
.prose li{margin-bottom:8px}
.prose li:last-child{margin-bottom:0}
.prose code{font-family:var(--f-mono);font-size:.94em;word-break:break-all}
/* Body links are set in --blue-600, which is only 2.71:1 against --ink body text,
   under the 3:1 that colour-only differentiation needs. Underlining them here fixes
   it for the policy prose and the privacy note. The rest of the site still relies on
   colour alone: that is a markup-wide change, logged in VERIFICATION-LOG.md. */
.prose a,.form-note a{text-decoration:underline}
/* .muted now passes everywhere at 5.51:1, since --ink-3 was raised. Policy text
   keeps the stronger --ink-2 at 8.08:1 and still reads as secondary. */
.prose .muted{color:var(--ink-2)}
.center{text-align:center}
.mb-0{margin-bottom:0}
.mt-8{margin-top:8px}
.mt-40{margin-top:40px}
.mt-56{margin-top:56px}
.mb-32{margin-bottom:32px}
.m-0{margin:0}

/* The classes below replace inline style attributes, so that the Content-Security
   -Policy can forbid them outright rather than allowing style-src 'unsafe-inline'.
   Keep it that way: a style="" attribute anywhere in public/ would be blocked. */

/* A whole card is the link, so the base a:hover underline would run across it. */
a.card:hover{text-decoration:none}

/* Figure images pinned to a ratio. 4px rather than --radius (3px) is deliberate:
   it is what these already rendered at, and this change is not a restyle. */
.img-4x3,.img-21x8{width:100%;object-fit:cover;border-radius:4px}
.img-4x3{aspect-ratio:4/3}
.img-21x8{aspect-ratio:21/8;margin-bottom:34px}

/* Maps, charts and technical drawings carry information right to their edges, and the
   shared boxes (.split img, .card-img img, .panel img) all crop with object-fit:cover.
   Measured 30 October 2026: the incident-command chart lost 41% of its width — whole
   branches of it — and the network map lost 33% of its height, which is labelled towns.
   A photograph can be cropped to taste; a map cannot. These keep the whole frame and
   take their natural height. White ground, because the artwork is drawn on white and
   the --bg-3 loading tint would otherwise show as bars beside it. Never upscaled
   either: stretching an 800px drawing across a 1130px column makes it bigger and
   blurrier at once, so it stops at its natural width and centres. */
img.img-whole,.panel .panel-body img.img-whole{
  aspect-ratio:auto;object-fit:contain;width:auto;max-width:100%;height:auto;
  display:block;margin-inline:auto;background:#fff;
}

.fig-cap{font-size:14.5px;padding-top:10px}
.table-cap{caption-side:bottom;text-align:left;padding:14px 18px;font-size:14.5px}
.rule{height:1px;background:var(--line);border:0;margin:58px 0}
.pill{display:inline-block;background:var(--blue-100);color:var(--blue-600);border-radius:999px;
  padding:6px 15px;font-family:var(--f-mono);font-size:12px;font-weight:500;letter-spacing:.06em}
.note{border-left:3px solid var(--yellow);background:#FFFCF2;padding:18px 22px;
  border-radius:0 var(--radius) var(--radius) 0;font-size:15px;color:var(--ink-2)}
.section-dark .note,.section-abyss .note{background:rgba(247,194,35,.09);color:#C9DEEA}

/* ---------- 404 ---------- */
.err-page{min-height:64vh;display:flex;align-items:center;background:var(--abyss);color:#fff;
  text-align:center;position:relative;overflow:hidden}
.err-page::before{content:"";position:absolute;inset:0;
  background:radial-gradient(800px 340px at 50% 0,rgba(41,171,226,.25),transparent 62%)}
.err-page .wrap{position:relative;padding:88px var(--gutter)}
.err-code{font-family:var(--f-mono);font-size:clamp(58px,11vw,120px);line-height:1;color:var(--lime);
  font-variant-numeric:tabular-nums;letter-spacing:-.04em;margin-bottom:22px}
.err-page h1{color:#fff}
.err-page p{color:#B6CEDC;max-width:52ch;margin:20px auto 34px}
