/* ==========================================================================
   ENTERLACE CORP — 2026
   Art direction: AS-BUILT / drawing set.  See DESIGN-SPEC.md.

   The page is DRAWN, not lit. Ink fields, warm paper, hairline rules instead
   of boxes, monospaced designators hanging in a reserved gutter, tabular
   schedules, sheet keys counting down the page, a title-block footer.

   Nothing floats, nothing glows, nothing shimmers.
   One CSS file, no framework, no third-party request.

   0  FONTS
   1  TOKENS
   2  BASE + RESET
   3  SHEET: wrap, rail, bands, section openers
   4  BUTTONS
   5  HEADER / NAV / SKIP / CALL BAR
   6  BREADCRUMBS
   7  INK PLATES: hero, p-hero, drawing index
   8  STAMP STRIP + BRAND ROW
   9  SCHEDULES: cards, cities, steps, stats, included, guides, reviews
   10 PROSE, PLATES, FOLDS, FAQ, TABLES
   11 SPLIT + ASIDE
   12 FORMS + PLANNER
   13 PARTNER BAND + CTA BAND
   14 TITLE BLOCK (footer)
   15 MOTION
   16 RESPONSE: min-width steps, then narrow-screen corrections
   ========================================================================== */

/* --------------------------------------------------------------------------
   0  FONTS — self-hosted, latin subset, woff2 only. Metric-matched fallback
   faces make the swap cost ~0 CLS (values measured, see fonts/fonts.css).
   Preloaded in <head>: Archivo + Inter Tight ONLY. Never mono, never serif.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Archivo";
  src: url("/assets/fonts/archivo-variable.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-stretch: 100%; font-display: swap;
  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: "Inter Tight";
  src: url("/assets/fonts/inter-tight-variable.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
  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: "Inter Tight";
  src: url("/assets/fonts/inter-tight-italic-variable.woff2") format("woff2");
  font-weight: 100 900; font-style: italic; font-display: swap;
  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";
  src: url("/assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  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";
  src: url("/assets/fonts/ibm-plex-mono-600.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
  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;
}
/* Accent — ITALIC ONLY, one emphasised word in an H1/H2. Nothing else. */
@font-face {
  font-family: "Instrument Serif";
  src: url("/assets/fonts/instrument-serif-400.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  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: "Instrument Serif";
  src: url("/assets/fonts/instrument-serif-italic-400.woff2") format("woff2");
  font-weight: 400; font-style: italic; font-display: swap;
  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;
}

/* metric-matched fallbacks (zero-CLS swap) */
@font-face {
  font-family: "Archivo Fallback";
  src: local("Segoe UI"), local("Helvetica Neue"), local("Helvetica"), local("Arial");
  size-adjust: 101.59%; ascent-override: 86.43%; descent-override: 20.67%; line-gap-override: 0.00%;
}
@font-face {
  font-family: "Inter Tight Fallback";
  src: local("Segoe UI"), local("Helvetica Neue"), local("Helvetica"), local("Arial");
  size-adjust: 96.54%; ascent-override: 100.34%; descent-override: 24.98%; line-gap-override: 0.00%;
}
@font-face {
  font-family: "IBM Plex Mono Fallback";
  src: local("Consolas"), local("SF Mono"), local("Menlo"), local("DejaVu Sans Mono");
  size-adjust: 109.13%; ascent-override: 93.92%; descent-override: 25.20%; line-gap-override: 0.00%;
}

/* --------------------------------------------------------------------------
   1  TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* --- type stacks --- */
  --font-display: "Archivo", "Archivo Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body:    "Inter Tight", "Inter Tight Fallback", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono:    "IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, Consolas, monospace;
  --font-accent:  "Instrument Serif", Georgia, "Times New Roman", serif;

  /* --- scale (root is 17px; 18px >=1560) --- */
  --step--2: 0.72rem;   /* mono labels, captions        */
  --step--1: 0.82rem;   /* small print, meta            */
  --step-0:  1rem;      /* body                         */
  --step-1:  1.125rem;  /* deck / .sec-sub              */
  --step-2:  1.4rem;    /* h3                           */
  --step-3:  clamp(1.65rem, 2.5vw, 2.3rem);  /* h2 / .sec-h      */
  --step-4:  clamp(2.1rem, 3.6vw, 3.1rem);   /* interior h1      */
  --step-5:  clamp(2.6rem, 5vw, 4.4rem);     /* home h1          */

  /* --- colour: four hues, four non-overlapping jobs --- */
  --ink:       #00171F;  /* headlines, ink fields, 2px keylines */
  --ink-body:  #152A33;  /* body text on paper                  */
  --prussian:  #003459;  /* structure only, never a fill        */
  --sea:       #005B7C;  /* interactive text on paper  6.6:1    */
  --cerulean:  #007EA7;  /* icon strokes, 2px accent rules      */
  --picton:    #00A8E8;  /* SIGNAL: button fill, marker, on ink */

  --paper:   #F6F3EE;    /* warm bone — default ground          */
  --paper-2: #EFEBE3;    /* secondary band                      */
  --white:   #FFFFFF;    /* mounted objects only                */
  --txt-inv:      #F2EFE9;
  --txt-inv-soft: #A9C4D2;  /* 8.3:1 on ink */

  /* three rule weights replace every box on the site */
  --hair: rgba(0, 52, 89, 0.16);   /* hairlines inside a block  */
  --rule: rgba(0, 23, 31, 0.34);   /* block boundaries          */
  --key:  #00171F;                 /* section openers, 2px      */
  --hair-inv: rgba(242, 239, 233, 0.16);
  --rule-inv: rgba(242, 239, 233, 0.30);
  --input-line: rgba(0, 52, 89, 0.6);  /* 3.9:1 on white — visible field edges */

  /* signal colours, schedule status only */
  --sig-ok: #4ade80;
  --sig-alert: #fb7185;
  --sig-warn: #f5b301;

  /* --- layout --- */
  --wrap: 1180px;
  --gut: clamp(20px, 4.4vw, 72px);
  --rail: 0px;                       /* the gutter; grows >=1180 */
  --gap: clamp(20px, 2.4vw, 40px);   /* grid column gap          */
  --band: clamp(56px, 7vw, 120px);
  --band-xl: clamp(80px, 10vw, 176px);
  --hdr-h: 60px;

  /* --- motion (see §15). Two curves, no more. -----------------------------
     --ease-plot  a plotter head decelerating onto its stop: fast out of the
                  gate, long settle, no overshoot. Rules, type, sheets.
     --ease-mark  a hand drawing a marker across a word: a beat of pressure,
                  then a glide. Used only for wipes and the highlighter. */
  --ease-plot: cubic-bezier(0.16, 0.84, 0.44, 1);
  --ease-mark: cubic-bezier(0.33, 0, 0.15, 1);

  /* 4px base spacing */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 20px; --s5: 28px;
  --s6: 40px; --s7: 56px; --s8: 80px; --s9: 120px; --s10: 190px;

  --field: var(--paper);   /* current band colour, for notched legends */
}

/* --------------------------------------------------------------------------
   2  BASE
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  font-size: 17px;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--hdr-h) + 18px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink-body);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.62;
  counter-reset: sheet;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { max-width: 100%; height: auto; }
a { color: inherit; }
p { margin: 0 0 1em; }
ul, ol { margin: 0 0 1em; padding-left: 1.25em; }
strong, b { color: var(--ink); font-weight: 650; }
address { font-style: normal; }
[hidden] { display: none !important; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--ink);
  margin: 0 0 0.5em;
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
h1 { font-size: var(--step-4); font-weight: 800; letter-spacing: -0.028em; }
h2 { font-size: var(--step-3); letter-spacing: -0.022em; }
h3 { font-size: var(--step-2); letter-spacing: -0.012em; font-weight: 650; }
h4 { font-size: var(--step-1); letter-spacing: -0.008em; }

/* The ONE accent: an italic serif word inside a headline. */
h1 em, h2 em, .sec-h em {
  font-family: var(--font-accent);
  font-style: italic;
  font-weight: 400;
  letter-spacing: 0;
  font-size: 1.06em;
}

/* every price, spec, stat and designator is tabular */
[class*="mono"], .kicker, .sec-h::before, code, kbd, samp {
  font-variant-numeric: tabular-nums;
}

/* -- utilities ------------------------------------------------------------ */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: max(var(--gut), env(safe-area-inset-left)) max(var(--gut), env(safe-area-inset-right));
}
/* narrow keeps the same spine — it shortens the measure, it does not re-centre */
.wrap.narrow > * { max-width: 74ch; }
/* .prose used AS the container (about, assessment) must not shrink the sheet
   itself, or the whole page re-centres and the gutter stops lining up */
.wrap.prose { max-width: var(--wrap); }
.wrap.prose > * { max-width: 66ch; }

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

.ico { width: 20px; height: 20px; flex: none; stroke-width: 1.5; }

/* focus: one global rule, visible on every ground (defect 10) */
:focus-visible {
  outline: 3px solid var(--sea);
  outline-offset: 2px;
}
.hdr :focus-visible, .m-nav :focus-visible, .hero :focus-visible, .p-hero :focus-visible,
.cta-band :focus-visible, .pband :focus-visible, .ftr :focus-visible, .callbar :focus-visible,
.callout :focus-visible, .aside-cta :focus-visible {
  outline-color: var(--picton);
}
.card:focus-visible, .g-card:focus-visible, .city-grid a:focus-visible,
.dash-row a:focus-visible, .b-card:focus-visible { outline-offset: -3px; }
/* MOUNTED OBJECTS TAKE THE RING THAT SUITS THEIR OWN GROUND, not the ground
   they are mounted on — the -3px offset above draws the ring INSIDE the object,
   so it never reaches the ink field behind it and the field's colour is
   irrelevant. Measured on each:
     .pband-card  is white.        picton 2.70:1 (fails 1.4.11) — sea, 7.5:1.
     .hero-panel  is the machined plate of §7.1, face #052E40. sea is 1.11:1 there
                  and effectively invisible; picton measures 5.3:1. The -3px ring
                  lands on bare plate on all four sides — the backlit lens starts
                  5px in, so the ring never crosses it and 5.3 is the real number.
   This pair used to be one rule sharing sea, from when both objects were white.
   If the plate is ever lightened past ~#0B4C68, re-measure picton before
   touching anything else. */
.pband .pband-card :focus-visible { outline-color: var(--sea); }
.hero .hero-panel :focus-visible { outline-color: var(--picton); }
/* the skip link's ring lands on the ink header, where sea is 2.50:1 */
.skip:focus-visible { outline-color: var(--txt-inv); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--picton); color: var(--ink);
  font-family: var(--font-display); font-weight: 700;
  padding: 12px 20px; border-radius: 0;
}
.skip:focus { left: 0; }

/* --------------------------------------------------------------------------
   3  THE SHEET — bands, the rail, section openers
   -------------------------------------------------------------------------- */
.sec        { padding: var(--band) 0; background: var(--paper); --field: var(--paper); }
.sec-light  { background: var(--paper-2); --field: var(--paper-2); }
.sec-ink    { background: var(--ink); color: var(--txt-inv-soft); --field: var(--ink); }
.sec-white  { background: var(--white); --field: var(--white); }
.sec-xl     { padding: var(--band-xl) 0; }
.sec-tight  { padding: calc(var(--band) * 0.62) 0; }

.sec-ink h1, .sec-ink h2, .sec-ink h3, .sec-ink strong, .sec-ink b { color: var(--txt-inv); }
.sec-ink .sec-h::after { border-color: var(--rule-inv); }
.sec-ink .sec-h::before { color: var(--picton); }

/* SECTION OPENER = dimension rule + sheet key in the gutter.
   ::after draws a hairline with 8px ticks turned down at both ends.
   ::before is the designator: "A-3 / SERVICE AREAS" (CSS counter + data-key). */
.sec-h {
  position: relative;
  counter-increment: sheet;
  font-size: var(--step-3);
  margin: 0 0 0.55em;
  padding-top: 24px;
}
.sec-h::after {
  content: "";
  position: absolute; top: 0; left: calc(-1 * var(--rail)); right: 0;
  height: 9px;
  border: 1px solid var(--rule);
  border-bottom: 0;
  pointer-events: none;
}
.sec-h::before {
  content: "A-" counter(sheet);
  display: block;
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: var(--step--2);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--sea);
}
.sec-h[data-key]::before { content: "A-" counter(sheet) "  /  " attr(data-key); }

.sec-sub {
  max-width: 58ch;
  margin: 0 0 2em;
  font-size: var(--step-1);
  color: var(--ink-body);
}
.sec-ink .sec-sub, .sec-ink p { color: var(--txt-inv-soft); }

/* --------------------------------------------------------------------------
   4  BUTTONS — rectangles. No pill, no glow, no sheen, no lift.
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 48px;
  padding: 13px 24px;
  border: 1.5px solid var(--picton);
  border-radius: 2px;
  background: var(--picton);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.95rem; font-weight: 700; letter-spacing: 0.005em;
  text-align: center; text-decoration: none; cursor: pointer;
  transition: background 0.12s linear, border-color 0.12s linear, color 0.12s linear;
}
.btn:hover { background: var(--ink); border-color: var(--ink); color: var(--picton); }
.btn .ico { width: 18px; height: 18px; }

.btn-lg { min-height: 56px; padding: 16px 30px; font-size: 1.02rem; }
.btn-sm { min-height: 44px; padding: 10px 18px; font-size: 0.86rem; }
.btn-block { display: flex; width: 100%; }

/* secondary — 1.5px keyline, transparent. -ghost on ink, -dark/-line on paper */
.btn-ghost {
  background: transparent; color: var(--txt-inv); border-color: var(--txt-inv);
}
.btn-ghost:hover { background: var(--txt-inv); border-color: var(--txt-inv); color: var(--ink); }
.btn-ghost-dark, .btn-line {
  background: transparent; color: var(--ink); border-color: var(--ink);
}
.btn-line { color: var(--prussian); border-color: var(--prussian); }
.btn-ghost-dark:hover { background: var(--ink); border-color: var(--ink); color: var(--paper); }
.btn-line:hover { background: var(--prussian); border-color: var(--prussian); color: var(--paper); }

/* every phone link carries the number in mono tabular, everywhere */
.btn[href^="tel:"], .hdr-tel, .aside-tel, .cb-call, .ftr-nap a[href^="tel:"], .c-row a[href^="tel:"] {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
}

/* --------------------------------------------------------------------------
   5  HEADER
   -------------------------------------------------------------------------- */
.hdr {
  position: sticky; top: 0; z-index: 50;
  background: var(--ink);
  border-bottom: 1px solid var(--hair-inv);
  transition: transform 0.28s ease;
}
.hdr.is-hidden { transform: translateY(-100%); }
.hdr-in { display: flex; align-items: center; gap: 26px; height: var(--hdr-h); }

.brand { display: flex; align-items: center; min-height: 44px; gap: 11px; text-decoration: none; color: var(--txt-inv); }
.brand-mark { width: 32px; height: 32px; color: var(--picton); flex: none; }
.brand-txt { display: flex; flex-direction: column; line-height: 1.05; }
.brand-txt b {
  font-family: var(--font-display);
  font-size: 1.12rem; font-weight: 800; letter-spacing: 0.15em; color: var(--txt-inv);
}
.brand-txt i {
  font-family: var(--font-mono); font-style: normal;
  font-size: 0.66rem; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--txt-inv-soft); margin-top: 4px;
}

.nav { margin-left: auto; }
.nav ul { display: flex; gap: 4px; list-style: none; margin: 0; padding: 0; }
.nav a {
  display: flex; align-items: center;
  height: 44px; padding: 0 12px;
  color: var(--txt-inv); text-decoration: none; white-space: nowrap;
  font-family: var(--font-display); font-size: 0.9rem; font-weight: 600;
  border-bottom: 2px solid transparent;
}
.nav a:hover { color: var(--picton); }
.nav a[aria-current="page"] { color: var(--picton); border-bottom-color: var(--picton); }

.hdr-cta { display: flex; align-items: center; gap: 14px; flex: none; }
.hdr-tel {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 44px; min-width: 44px;
  color: var(--txt-inv); text-decoration: none; white-space: nowrap;
  font-size: 0.92rem; font-weight: 500;
}
.hdr-tel .ico { width: 17px; height: 17px; color: var(--picton); }
.hdr-tel:hover { color: var(--picton); }
.hdr-mail {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; color: var(--txt-inv-soft);
}
.hdr-mail:hover { color: var(--picton); }

.burger {
  display: none; margin-left: auto;
  width: 46px; height: 46px; padding: 11px;
  background: none; border: 0; cursor: pointer;
}
.burger span { display: block; width: 24px; height: 2px; background: var(--txt-inv); margin: 5px 0; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* MOBILE NAV — ships OPEN in markup so the site is navigable with no JS at
   all (defect 2). CSS closes it when the burger reports collapsed; if :has()
   is unsupported the menu simply stays open. Height-capped + scrollable so the
   last link is always reachable inside the sticky header (defect 3). */
.m-nav {
  display: block;
  background: var(--ink);
  border-top: 1px solid var(--hair-inv);
  padding: 8px var(--gut) 22px;
  max-height: calc(100dvh - var(--hdr-h));
  overflow-y: auto;
  overscroll-behavior: contain;
}
.m-nav[hidden] { display: none; }
.hdr:has(.burger[aria-expanded="false"]) .m-nav { display: none; }
.m-nav ul { list-style: none; margin: 0 0 14px; padding: 0; }
.m-nav li a {
  display: flex; align-items: center; min-height: 48px;
  color: var(--txt-inv); text-decoration: none;
  font-family: var(--font-display); font-weight: 600;
  border-bottom: 1px solid var(--hair-inv);
}
.m-nav li a[aria-current="page"] { color: var(--picton); }
.m-nav .btn { margin-top: 10px; }
.m-mail {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 44px; margin-top: 14px;
  color: var(--txt-inv-soft); text-decoration: none;
  font-family: var(--font-mono); font-size: var(--step--1);
}
.m-mail .ico { width: 17px; height: 17px; color: var(--picton); }

/* mobile call bar — shown to 1100px, because .hdr-cta .btn is hidden there
   and an iPad otherwise has no visible Free Quote anywhere (defect 12) */
.callbar { display: none; }

/* --------------------------------------------------------------------------
   6  BREADCRUMBS
   -------------------------------------------------------------------------- */
.crumbs { background: var(--paper); border-bottom: 1px solid var(--hair); }
.crumbs ol {
  display: flex; flex-wrap: wrap; align-items: center;
  list-style: none; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--sea);
}
.crumbs li { display: flex; align-items: center; }
.crumbs li + li::before { content: "/"; margin: 0 8px; color: var(--hair); }
.crumbs a { display: flex; align-items: center; min-height: 44px; color: var(--sea); text-decoration: none; }
.crumbs a:hover { text-decoration: underline; }
.crumbs [aria-current] { display: flex; align-items: center; min-height: 44px; color: var(--ink); }

/* --------------------------------------------------------------------------
   7  INK PLATES — hero, interior hero, drawing index
   -------------------------------------------------------------------------- */
.hero, .p-hero {
  position: relative;
  background: var(--ink);
  color: var(--txt-inv-soft);
  --field: var(--ink);
}
.hero-in {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: clamp(40px, 5.5vw, 92px) max(var(--gut), env(safe-area-inset-left)) clamp(36px, 5vw, 84px);
}
.hero-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--gap); align-items: start; }
.hero-grid > :first-child { grid-column: 1 / span 7; }
.hero-grid > .hero-panel { grid-column: 8 / span 5; }

.kicker {
  display: block;
  margin: 0 0 18px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--sea);
}
.hero .kicker, .p-hero .kicker, .pband .kicker, .cta-band .kicker, .sec-ink .kicker { color: var(--picton); }

/* THE DRAWING HEADER. On an ink plate the kicker is the sheet's title line, so
   it carries a rule the way a title line does. The rule is a pseudo-element,
   absolutely positioned: it costs no layout, and §15 extends it left-to-right
   on load. */
.hero .kicker, .p-hero .kicker {
  position: relative;
  margin-bottom: 16px;
  padding-bottom: 13px;
}
.hero .kicker::after, .p-hero .kicker::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: var(--rule-inv);
  transform-origin: left center;
}

.hero h1 { color: var(--txt-inv); font-size: var(--step-5); letter-spacing: -0.03em; margin-bottom: 0.4em; }
.p-hero { padding: clamp(34px, 4vw, 68px) 0 clamp(30px, 3.6vw, 60px); }
.p-hero h1 { color: var(--txt-inv); font-size: var(--step-4); max-width: 22ch; }

/* THE MARKER. The emphasised word pair in a hero headline is struck with a
   picton highlighter, stroked across the words left-to-right by §15's plotMark
   — an estimator running a marker over the scope of work.

   GEOMETRY — FULL COVERAGE. The band spans the em's entire content box
   (`background-size: 100% 100%`), so it covers every letter including caps,
   ascenders and descenders. It used to be a 0.52em nib struck through the
   x-height, which left the H and A of "Home Automation" standing clear above
   it; the client wanted the whole word covered. Sizing to 100% rather than a
   fixed em value means it tracks the font's own metrics and needs no media
   query from the 36px mobile H1 to the 70px desktop one.
   THREE PLACES carry this height and must move together: here, the plotMark
   keyframe (§15.1) and the reduced-motion pin (§15.4).

   ALPHA IS LOAD-BEARING — 0.28, and it is a measured compromise, not a taste
   call. Once the band covers the WHOLE glyph there is no longer any part of the
   letter sitting on high-contrast ink, so the type/band ratio alone has to carry
   legibility. Measured, picton type on a picton band over ink:
       0.38  3.37:1  (the old half-height value — too murky at full coverage)
       0.28  4.15:1  <- here. comfortably over the 3.0 large-text floor
       0.24  4.52:1  but the band starts to disappear into the page
   Raising alpha makes the mark louder and the word harder to read; lowering it
   does the reverse. Below ~1.4:1 band-vs-page the highlight stops reading as a
   highlight at all. If a heavier band is ever wanted, the type must stop being
   picton at the same time (bone on a 45% band measures 6.85:1).

   `background-size` is the animated property; the width here is the resting
   state, so the animation only ever supplies the `from`.
   box-decoration-break: clone re-paints the block on every line when it wraps. */
.hero h1 em, .p-hero h1 em {
  color: var(--picton);
  background-image: linear-gradient(rgba(0, 168, 232, 0.28), rgba(0, 168, 232, 0.28));
  background-repeat: no-repeat;
  background-position: 0 0;
  background-size: 100% 100%;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.hero-sub {
  max-width: 54ch; margin: 0 0 30px;
  font-size: var(--step-1); color: var(--txt-inv-soft);
}
.hero-ctas { display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 32px; }
.p-hero .hero-ctas { margin-bottom: 0; }

.hero-points {
  display: flex; flex-wrap: wrap; gap: 10px 32px;
  list-style: none; margin: 0; padding: 0;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--txt-inv-soft);
}
.hero-points li { display: flex; align-items: center; gap: 9px; }
.hero-points .ico { width: 15px; height: 15px; color: var(--picton); }

/* ==========================================================================
   7.1  THE ENCLOSURE — the "What we install" index
   --------------------------------------------------------------------------
   THE IDEA. This company's product is the part of the house you do not see:
   the enclosure in the garage where every system in the property terminates.
   Six systems, one can, one contractor — which is what the footer of this very
   panel says. So the panel is not a document about the work. It IS the work:
   a dark machined plate, flush-recessed into the ink field, six engraved
   channels, and the home-run bundle running down a service gutter on the left.

   WHY IT IS NOT A GLASS CARD. Everything here is opaque and machined. There is
   no blur, no transparency, no drop shadow, nothing floating: the plate sits
   BELOW the surface of the field, not above it, and it is held there by an
   inset top shadow and a single light-catch on the bottom lip — the way a real
   recess is lit from above. The corner radius is not a style choice either: it
   is the fillet a router bit leaves, which is why the milled edge outside it
   carries the same curve one pixel larger.

   WHERE THE LIGHT COMES FROM. Every lit thing on this panel has a source and a
   conductor, and the conductor is the riser: supply LED at the top of the
   gutter, one hairline home-run down it, an open terminal ring where each of
   the six channels taps off, a terminal bar at the bottom. It is the schedule
   of the job drawn as a schematic — one run in, six drops off it — which is
   also the sentence in the panel's own footer.

   (An earlier pass drew the riser as a twisted pair, on the reasoning that a
   twisted pair is both the literal shape of structured cabling and the literal
   meaning of the word Enterlace. Zoomed up it read as a DNA helix, so it is
   gone. A single riser with six taps is the same idea told in the site's own
   as-built drawing language, and it survives being looked at closely.)

   On load the light runs DOWN the riser once and each terminal fills and each
   designator comes up as it passes (§15.1a, `energize`): the install-day moment
   when the rack is powered and the ports come up one by one. On hover the light
   runs INTO the channel from the riser side and backlights the engraving, the
   way a Lutron keypad's engraving lights (§15.3a). Contained light with a
   cause — not a halo round a rectangle.

   COLOUR. Nothing new. Every value below is ink (#00171F) pushed toward
   prussian (#003459), or bone / txt-inv-soft at an alpha, or picton as the one
   signal. Measured, not estimated — worst case is the lightest point of the
   plate face, #052E40, and for the lit states the composited surface under the
   text once a channel is backlit:
                            on the plate     on a lit channel
     titles     #F2EFE9        12.4:1            8.8:1
     specs      #A9C4D2         8.6:1            6.0:1
     designator #86A0AF         5.2:1              —
     lit type   #7FD8F7         8.9:1            6.0:1
     picton     #00A8E8         5.3:1            3.4:1   (hardware only)
   AA needs 4.5:1 for all of that text and 1.4.11 needs 3:1 for the hardware, so
   every line clears its own floor. The focus ring is picton here, not sea — §2.
   ========================================================================== */
.hero-panel {
  /* the material, defined once */
  --plate-top: #052E40;                      /* face, lightest, under the head */
  --plate-mid: #02202D;
  --plate-bot: #011A24;                      /* face falls away to the bottom lip */
  --score-in:  rgba(0, 0, 0, 0.5);           /* an engraved line: the dark cut… */
  --score-up:  rgba(169, 196, 210, 0.085);   /* …then the light it holds        */
  --key-dim:   #86A0AF;                      /* designator at rest, 5.2:1       */
  /* TWO PICTONS, and the split is a measured requirement, not a preference.
     --lamp is picton itself and is only ever used for hardware: the terminal
     fill, the channel lamp, the lens tint, the focus ring. Every one of those is
     non-text and answers to the 3:1 floor of WCAG 1.4.11, which picton clears at
     5.3:1 on the plate and 3.4:1 on the brightest part of a backlit channel.
     --lamp-hi is picton lightened toward white and is what lit TEXT uses, because
     text answers to 4.5:1 and flat picton does NOT get there once a channel is
     backlit — measured under the designator, where the lens is strongest, picton
     is 3.55:1 and fails. --lamp-hi is 5.96:1 in the same place and 8.9:1 on the
     unlit plate. It is also the truer read: a clear engraving over a cyan lamp
     goes white-hot at the source, it does not simply change colour. Do not
     collapse these two back into one. */
  --lamp:      #00A8E8;
  --lamp-hi:   #7FD8F7;
  --term:      rgba(169, 196, 210, 0.42);    /* a terminal, not yet live        */
  /* GEOMETRY, in two numbers. --gutter is where the riser runs and everything
     that sits on it (LED, terminals, terminal bar, row dividers) is placed off
     it; --indent is where the mono column starts. §16 narrows the pair together
     on phones, which is the only place the panel's spine ever moves. */
  --gutter: 19px;
  --indent: 36px;

  position: relative;
  background: linear-gradient(180deg, var(--plate-top), var(--plate-mid) 46%, var(--plate-bot));
  color: var(--txt-inv-soft);
  border-radius: 14px;
  overflow: hidden;                          /* the fillet clips head and lip   */
  /* THE RECESS, and the whole reason this does not read as a card. A recess lit
     from above is dark along its top inner face and bright along its bottom
     one; a card is the other way round. So: 1px of black at the top, prussian
     down the two sides where the cut is edge-on to the light, and a bone
     hairline along the bottom lip. Invert those two and the plate immediately
     starts floating instead of sitting in the wall. */
  border-width: 1px;
  border-style: solid;
  border-color: rgba(0, 0, 0, 0.72) rgba(0, 52, 89, 0.95) rgba(169, 196, 210, 0.2);
  box-shadow:
    inset 0 8px 18px -10px rgba(0, 0, 0, 0.95),   /* shadow falling in from the top */
    inset 0 -1px 0 rgba(169, 196, 210, 0.1),
    0 1px 0 rgba(169, 196, 210, 0.045);           /* chamfer below the aperture     */
  --field: #02202D;
}
.dash { padding: 0; }

/* THE HEAD — an engraved label strip with the supply LED seated at the head of
   the riser. Its gradient is dark at the very top and brightens downward: that
   is the same falling shadow as the plate's, continued across the child that
   covers it. The strip is aria-hidden in the markup, so the LED costs a screen
   reader nothing. */
.dash-head {
  position: relative;
  display: flex; align-items: center; gap: 10px;
  padding: 13px 18px 13px var(--indent);
  background: linear-gradient(180deg,
    rgba(0, 0, 0, 0.34), rgba(0, 52, 89, 0.62) 46%, rgba(0, 52, 89, 0.14));
  border-bottom: 1px solid var(--score-in);
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--txt-inv);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.55);   /* the engraved cut under the type */
}
.dash-head b { font-weight: 600; color: inherit; }
.dash-head::before {
  content: "";
  position: absolute; z-index: 2;             /* seats OVER the riser below it  */
  left: calc(var(--gutter) - 4px); top: 50%; margin-top: -4px;
  width: 9px; height: 9px; border-radius: 50%;
  background: radial-gradient(circle at 50% 32%, #86DCFF, var(--lamp) 58%, #00648C);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.62), 0 0 9px 1px rgba(0, 168, 232, 0.5);
}
.dash-dot, .dash-live { display: none; }   /* fabricated telemetry — deleted */

/* THE CHANNEL FIELD — a shallow well milled into the face. `position: relative`
   is load-bearing: the riser and the commissioning sweep are its pseudos. */
.dash-rows {
  position: relative;
  list-style: none; margin: 0; padding: 0;
  box-shadow: inset 0 1px 0 var(--score-up), inset 0 8px 14px -12px rgba(0, 0, 0, 0.8);
}

/* THE RISER. One hairline down the gutter, twice: ::before is the engraved run
   at rest, ::after is the same line in picton, revealed downward once on load.
   Both overshoot the row list by 24px top and bottom so the run starts under
   the supply LED and finishes under the terminal bar rather than floating
   between them; the LED and the bar carry z-index 2 so they cap it at any root
   font size, which is why the overshoot can be a single constant.

   z-index 1 is what makes the bottom overshoot visible at all. The panel's only
   stacking context is the panel itself, so the riser sorts against the head, the
   channels and the lip directly — and the lip comes AFTER the row list in tree
   order, so at z-index 0 the lip's shaded background painted straight over the
   last 24px of the run and the riser appeared to stop short of the terminal bar
   it is supposed to land on. At 1 it clears the lip. It still sits UNDER every
   channel, which are also 1 but later in tree order, so a terminal is always
   drawn on top of the line it taps. */
.dash-rows::before,
.dash-rows::after {
  content: "";
  position: absolute; z-index: 1;
  left: var(--gutter); top: -24px; bottom: -24px; width: 1px;
  pointer-events: none;
}
.dash-rows::before { background: rgba(169, 196, 210, 0.24); }
.dash-rows::after {
  background: var(--lamp);
  filter: drop-shadow(0 0 3px rgba(0, 168, 232, 0.85));
  /* resting state = spent. The keyframe's 100% matches these exactly, so the
     animation is fully interpolable and reduced-motion lands on "off". */
  clip-path: inset(0 0 0 0);
  opacity: 0;
}

/* A CHANNEL, and its tap off the riser. The divider is an engraved score — the
   dark cut, then the light it holds — and it clears the gutter by 6px rather
   than running the full width, so the riser stays one unbroken run instead of a
   ladder with six rungs across it. It is a pseudo on the li and NOT a border, so
   that clearance is possible at all, and it is on the li rather than the anchor
   for the reason §15.1 gives: the anchor is what fades in, and a divider that
   fades with it takes the ruled form away and the sheet lands blank. */
.dash-row { position: relative; z-index: 1; }
.dash-row + .dash-row::before {
  content: "";
  position: absolute; right: 0; top: -1px; height: 1px;
  left: calc(var(--gutter) + 11px);
  background: var(--score-in);
  box-shadow: 0 1px 0 var(--score-up);
}
/* THE TERMINAL — an open ring on the riser, centred on its channel whatever the
   channel's height. Open, not filled: the run passes through it until the drop
   is live, and then it fills (§15.1a on load, §15.3a on hover). */
.dash-row::after {
  content: "";
  position: absolute; left: calc(var(--gutter) - 4px); top: 50%; margin-top: -4.5px;
  width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid var(--term);
  background: transparent;
  pointer-events: none;
}
.dash-row a {
  position: relative;
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: center; gap: 4px 12px;
  padding: 13px 18px 13px var(--indent);
  color: var(--txt-inv); text-decoration: none;
}
.dash-row a > * { position: relative; z-index: 1; }

/* THE BACKLIGHT — a lens behind the engraving, inset from the channel edges so
   the light always has a housing and never bleeds to the plate's edge. It is
   wiped in from the riser side (§15.3a), not faded: the light arrives. */
.dash-row a::before {
  content: "";
  position: absolute; z-index: 0;
  inset: 5px 12px 5px 6px;
  border-radius: 10px;
  background: linear-gradient(90deg,
    rgba(0, 168, 232, 0.26), rgba(0, 168, 232, 0.1) 44%, rgba(0, 168, 232, 0.028));
  box-shadow:
    inset 0 0 0 1px rgba(0, 168, 232, 0.26),
    inset 0 1px 0 rgba(134, 220, 255, 0.16);
  clip-path: inset(0 100% 0 0 round 10px);
  pointer-events: none;
}
/* THE CHANNEL LAMP — the edge indicator that says which drop is live. */
.dash-row a::after {
  content: "";
  position: absolute; z-index: 0;
  left: 0; top: 9px; bottom: 9px; width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--lamp);
  box-shadow: 0 0 7px 0 rgba(0, 168, 232, 0.55);
  transform: scaleY(0); transform-origin: 50% 50%;
  pointer-events: none;
}

.dash-key {
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  color: var(--key-dim); letter-spacing: 0.04em;
}
/* no icon ships in this row any more; the rule is the guard for one coming back */
.dash-row .ico { width: 18px; height: 18px; color: var(--picton); }
.dash-row b {
  display: block;
  font-family: var(--font-display); font-size: 0.94rem; font-weight: 650;
  line-height: 1.25; color: var(--txt-inv);
}
.dash-row i {
  display: block; font-style: normal; line-height: 1.5;
  font-family: var(--font-mono); font-size: var(--step--2); color: var(--txt-inv-soft);
  letter-spacing: 0.02em;
}
.dash-st, .st-ok, .st-rec, .st-auto {
  font-style: normal;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(169, 196, 210, 0.55);
}

/* THE LIP — the enclosure's ID strip, in shadow, with the riser landing on a
   terminal bar at the bottom of the gutter. */
.dash-foot {
  position: relative;
  display: flex; align-items: center; gap: 12px;
  padding: 13px 18px 13px var(--indent);
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.2), rgba(0, 0, 0, 0.34));
  border-top: 1px solid var(--score-in);
  box-shadow: inset 0 1px 0 var(--score-up);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--txt-inv-soft);
}
.dash-foot::before {
  content: "";
  position: absolute; z-index: 2;             /* caps the riser, as the LED does */
  left: calc(var(--gutter) - 6px); top: 50%; margin-top: -1px;
  width: 13px; height: 2px; border-radius: 1px;
  background: rgba(169, 196, 210, 0.4);
}
.eq { display: none; }   /* equaliser — deleted with the rest of the telemetry */

/* --------------------------------------------------------------------------
   8  STAMP STRIP + BRAND ROW
   -------------------------------------------------------------------------- */
.trust { background: var(--paper-2); border-bottom: 1px solid var(--hair); --field: var(--paper-2); }
.trust-list {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  list-style: none; margin: 0; padding: 0;
}
.trust-list li {
  padding: 20px 20px 22px 0;
  border-left: 1px solid var(--hair);
  padding-left: 22px;
}
.trust-list li:first-child { border-left: 0; padding-left: 0; }
.trust-k {
  display: block; margin-bottom: 8px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sea);
}
.trust-list b {
  display: block; font-family: var(--font-display); font-weight: 650;
  font-size: 0.98rem; line-height: 1.25; color: var(--ink);
}
.trust-list i { font-style: normal; font-size: var(--step--1); color: var(--ink-body); }
.trust-list .ico { display: none; }

/* static ruled logo row — the 26s marquee is deleted (WCAG 2.2.2) */
.brands { background: var(--paper-2); padding: 30px 0 34px; --field: var(--paper-2); }
.brands-lbl {
  margin: 0 0 20px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sea);
}
.marq { display: block; }   /* was the marquee viewport — now an inert wrapper */
/* Column counts track site.brands.length (5). Each breakpoint below is chosen so
   5 cells always fill their rows — with `li:last-child { grid-column: span 2 }`
   closing the short row. Change the brand list and these must be re-checked. */
.brands-list {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  list-style: none; margin: 0; padding: 0;
  border-top: 1px solid var(--hair);
}
.b-card {
  display: flex; align-items: center; justify-content: center;
  min-height: 62px; padding: 12px 8px;
  border-bottom: 1px solid var(--hair);
  border-left: 1px solid var(--hair);
  background: none;
}
.b-card:first-child { border-left: 0; }
.bm {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  line-height: 1.05; color: var(--ink); text-align: center;
  font-family: var(--font-display);
}
.bm i { font-style: normal; font-weight: 600; }
.bm svg { width: 18px; height: 18px; }
.bm-lutron { flex-direction: row; gap: 6px; font-weight: 800; letter-spacing: 0.18em; font-size: 0.9rem; }
.bm-omada { font-weight: 700; font-size: 1.05rem; letter-spacing: 0.01em; text-transform: lowercase; }
.bm-omada svg { width: 20px; height: 11px; }
.bm-omada i { font-size: 0.52em; letter-spacing: 0.08em; color: var(--sea); margin-top: 2px; }
.bm-sonos { font-weight: 700; letter-spacing: 0.3em; font-size: 0.92rem; }
.bm-sonos i { font-size: 0.5em; letter-spacing: 0.1em; margin-top: 3px; color: var(--sea); }
.bm-urc { font-weight: 900; font-style: italic; font-size: 1.15rem; letter-spacing: 0.03em; }
.bm-urc i { font-style: italic; font-size: 0.4em; margin-top: 2px; color: var(--sea); }
.bm-ubnt { font-weight: 800; font-size: 1.02rem; }

/* --------------------------------------------------------------------------
   9  SCHEDULES
   -------------------------------------------------------------------------- */

/* --- service schedule: 12-col, span 4 -> 3-up. No box, no fill, no radius. */
.cards {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 0;
}
.cards > * { grid-column: span 4; }
.card {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  column-gap: 12px; row-gap: 4px;
  align-content: start;
  padding: 16px 0 22px;
  border-top: 1px solid var(--rule);
  color: inherit; text-decoration: none;
  transition: border-color 0.12s linear;
}
.card-key {
  grid-column: 1; grid-row: 1;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.06em; color: var(--sea); padding-top: 3px;
}
.card-ico {
  grid-column: 1; grid-row: 2;
  display: block; color: var(--cerulean); padding-top: 2px;
}
.card-ico .ico { width: 20px; height: 20px; }
.card > h3 {
  grid-column: 2; grid-row: 1;
  margin: 0; font-size: 1.06rem; font-weight: 650; letter-spacing: -0.01em;
  transition: color 0.12s linear;
}
.card > p {
  grid-column: 2; grid-row: 2;
  margin: 0; font-size: var(--step--1); color: var(--ink-body); max-width: 42ch;
}
.card-go {
  grid-column: 3; grid-row: 1;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--sea);
  white-space: nowrap; padding-top: 3px;
}
.card-go em { font-style: normal; font-family: var(--font-mono); margin-left: 6px; }
/* on a schedule row the affordance is the arrow alone — the label stays in the
   accessibility tree but stops eating the title column at narrow desktop widths */
.card > .card-go { font-size: 0; letter-spacing: 0; }
.card > .card-go em { font-size: var(--step--2); margin-left: 0; }
a.card:hover { border-top-color: var(--key); }
a.card:hover > h3 { color: var(--sea); }
/* non-link variant (partners page) must not look broken */
div.card { cursor: default; }

/* --- city index: ruled, 5-up, mono ZIP hanging right --- */
.city-grid {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 0;
  list-style: none; margin: 0; padding: 0;
  border-top: 1px solid var(--rule);
}
.city-grid li { border-bottom: 1px solid var(--hair); }
.city-grid a {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  min-height: 48px; padding: 13px 0;
  color: var(--ink); text-decoration: none;
  font-family: var(--font-display); font-size: 0.98rem; font-weight: 650;
}
.city-grid a:hover { color: var(--sea); }
.city-grid a em, .city-grid a i {
  font-style: normal;
  font-family: var(--font-mono); font-size: var(--step--2);
  color: var(--sea); letter-spacing: 0.04em;
}
.city-grid .ico { display: none; }
/* current city gets the marker highlight — the only non-button use of picton */
.city-grid .is-active a span:first-child {
  box-shadow: inset 0 -0.42em 0 rgba(0, 168, 232, 0.38);
}

/* --- steps: 12-col span 3 -> 4-up, numerals hang in the channel --- */
.steps {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 0;
  counter-reset: step;
  margin-top: 2em;
}
.step {
  counter-increment: step;
  padding: 14px 0 26px;
  border-top: 2px solid var(--key);
}
.step::before {
  content: counter(step, decimal-leading-zero);
  display: block; margin-bottom: 14px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.14em; color: var(--sea);
}
.step h3 { font-size: 1.06rem; font-weight: 650; margin-bottom: 8px; }
.step p { margin: 0; font-size: var(--step--1); color: var(--ink-body); }

/* --- stats: cells on a flat plate, split by vertical hairlines --- */
.stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  list-style: none; margin: 0; padding: 0;
}
.stats li { padding: 4px 20px 4px 26px; border-left: 1px solid var(--rule-inv); }
.stats li:first-child { border-left: 0; padding-left: 0; }
.stats b {
  display: block;
  font-family: var(--font-display); font-weight: 300; font-size: clamp(2.4rem, 4vw, 3.4rem);
  line-height: 1.05; letter-spacing: -0.03em; color: var(--txt-inv);
  font-variant-numeric: tabular-nums;
}
.stats span {
  display: block; margin-top: 10px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--txt-inv-soft);
}
/* if a stats block is ever placed on paper it must still be legible */
.sec .stats li { border-left-color: var(--hair); }
.sec .stats b { color: var(--ink); }
.sec .stats span { color: var(--sea); }

/* --- "what's included": 12-col span 4 -> 3-up (2-up inside prose) --- */
.inc-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 0;
  margin: 1.6em 0 0.6em;
}
.prose .inc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.inc { padding: 14px 0 20px; border-top: 1px solid var(--hair); background: none; }
.inc h3 { font-size: 0.98rem; font-weight: 650; margin: 0 0 6px; }
.inc p { margin: 0; font-size: var(--step--1); color: var(--ink-body); }

/* --- guides index: 12-col span 3 -> 4-up --- */
.g-cards {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: 0;
}
.g-cards > * { grid-column: span 3; }
.g-card {
  display: flex; flex-direction: column; gap: 8px;
  padding: 16px 0 24px;
  border-top: 1px solid var(--rule);
  color: inherit; text-decoration: none;
  transition: border-color 0.12s linear;
}
.g-card:hover { border-top-color: var(--key); }
.g-card:hover h3 { color: var(--sea); }
.g-meta {
  display: flex; gap: 14px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--sea);
}
.g-card h3 { margin: 0; font-size: 1.06rem; font-weight: 650; transition: color 0.12s linear; }
.g-card p { margin: 0; font-size: var(--step--1); color: var(--ink-body); flex: 1; }
.g-card .card-go { padding-top: 2px; }

/* --- reviews --- */
.t-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--gap);
  margin-top: 10px;
}
.t-card {
  display: flex; flex-direction: column; gap: 14px;
  margin: 0; padding: 24px;
  background: var(--white); border: 1px solid var(--rule);
  --field: var(--white);
}
.t-stars { color: var(--ink); font-size: 0.95rem; letter-spacing: 0.16em; }
.t-card blockquote { margin: 0; font-size: 0.98rem; color: var(--ink-body); }
.t-card figcaption { margin-top: auto; display: flex; flex-direction: column; gap: 3px; }
.t-card figcaption b { font-family: var(--font-display); font-weight: 650; }
.t-card figcaption span {
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--sea);
}
.t-more { margin-top: 28px; }

/* --------------------------------------------------------------------------
   10  PROSE, PLATES, FOLDS, FAQ, TABLES
   -------------------------------------------------------------------------- */
.prose { max-width: 66ch; counter-reset: ph; }
/* lifts the 66ch measure for a block that is a schedule, not reading matter
   (a fee table, a spec grid). Add alongside .prose: class="prose prose-wide" */
.prose-wide { max-width: 92ch; }
.prose > h2 {
  position: relative;
  counter-increment: ph;
  font-size: var(--step-3);
  margin: 1.9em 0 0.5em;
  padding-top: 18px;
  border-top: 1px solid var(--hair);
}
.prose > h2:first-child { margin-top: 0; border-top: 0; padding-top: 0; }
.prose > h2::before {
  content: counter(ph, decimal-leading-zero);
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.12em; color: var(--sea);
  display: block; margin-bottom: 10px;
}
.prose h3 { font-size: 1.12rem; margin-top: 1.6em; }
.prose ul { display: grid; gap: 10px; padding-left: 0; list-style: none; }
.prose ul li { position: relative; padding-left: 26px; }
.prose ul li::before {
  content: ""; position: absolute; left: 0; top: 0.72em;
  width: 14px; height: 1px; background: var(--cerulean);
}
.prose ol { padding-left: 1.3em; }
/* :not(.btn) — a button dropped into prose must stay a button, not become a link */
.prose a:not(.btn) { color: var(--sea); text-decoration: underline; text-underline-offset: 2px; }
.prose a:not(.btn):hover { color: var(--ink); }

/* tables — a schedule, not a card */
.prose table {
  width: 100%; border-collapse: collapse; margin: 1.6em 0;
  font-size: var(--step--1); font-variant-numeric: tabular-nums;
  background: var(--white);
}
.prose th {
  background: var(--ink); color: var(--txt-inv); text-align: left; vertical-align: bottom;
  padding: 12px 14px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.14em; text-transform: uppercase;
}
.prose td { padding: 12px 14px; border-top: 1px solid var(--hair); vertical-align: top; }
.prose tr:last-child td { border-bottom: 1px solid var(--hair); }
.table-scroll { overflow-x: auto; }
.table-scroll:focus-visible { outline-offset: -3px; }

/* PLATE — hairline frame, white mount, mono caption. Never a rounded photo. */
.g-img {
  margin: 2em 0;
  padding: 10px;
  background: var(--white);
  border: 1px solid var(--rule);
}
.g-img img { display: block; width: 100%; height: auto; }
.g-img figcaption {
  margin-top: 10px; padding-top: 9px;
  border-top: 1px solid var(--hair);
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--sea);
}

/* QUICK ANSWER — notched mono legend straddling a hairline. No fill. */
.qa-box {
  position: relative;
  margin: 8px 0 1.8em;
  padding: 24px 24px 6px;
  border: 1px solid var(--rule);
}
.qa-lbl {
  position: absolute; top: 0; left: 20px;
  transform: translateY(-50%);
  margin: 0; padding: 0 10px;
  background: var(--field, var(--paper));
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sea);
}
.qa-box p:last-child { margin-bottom: 1em; }
.qa-box p:not(.qa-lbl) { font-size: 1.02rem; color: var(--ink); }

/* CALLOUT — an ink plate dropped into the prose. Conversion, so it is loud. */
.callout {
  margin: 2.2em 0;
  padding: clamp(24px, 3vw, 34px);
  background: var(--ink);
  color: var(--txt-inv-soft);
  border-left: 3px solid var(--picton);
  --field: var(--ink);
}
.callout h3 { color: var(--txt-inv); margin-top: 0; }
.callout p { margin-bottom: 1.2em; }
.callout a:not(.btn) { color: var(--picton); }
.callout .btn { color: var(--ink); }
.callout .btn:hover { background: var(--txt-inv); border-color: var(--txt-inv); color: var(--ink); }

.cta-inline { display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 2em; }

/* FOLDS + FAQ — hairline rows, +/- in mono at the right, details-driven */
.fold, .faq { background: none; border: 0; border-bottom: 1px solid var(--hair); }
.faqs { border-top: 1px solid var(--rule); }
.fold:first-of-type { border-top: 1px solid var(--rule); }
.fold summary, .faq summary {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  min-height: 56px; padding: 15px 0;
  cursor: pointer; list-style: none;
  font-family: var(--font-display); font-weight: 650; color: var(--ink);
}
.fold summary::-webkit-details-marker, .faq summary::-webkit-details-marker { display: none; }
.fold summary:hover, .faq summary:hover { color: var(--sea); }
.fold-h { font-size: 1.02rem; font-weight: 650; }
.fold-x, .faq-ico {
  flex: none; position: relative;
  width: 1.2em; height: 1.2em; color: transparent;
  font-family: var(--font-mono); font-size: 1.05rem; overflow: hidden;
}
.fold-x::before, .faq-ico::before {
  content: "+"; position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--sea); font-weight: 600;
}
.fold[open] .fold-x::before, .faq[open] .faq-ico::before { content: "\2212"; }
svg.faq-ico { display: none; }
.fold-b, .faq-a { padding: 0 0 20px; max-width: 68ch; color: var(--ink-body); }
.fold-b > :last-child, .faq-a > :last-child { margin-bottom: 0; }
.faq-a { font-size: 0.98rem; }

/* --------------------------------------------------------------------------
   11  SPLIT + ASIDE — prose 7 / gap / aside 4
   -------------------------------------------------------------------------- */
.split {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: var(--s7);
  align-items: start;
}
.split > :first-child { grid-column: 1 / span 7; }
.split > :last-child { grid-column: 9 / span 4; }

.aside {
  position: sticky; top: calc(var(--hdr-h) + 20px);
  display: grid; gap: 0;
  align-self: start;
}
.aside-card { padding: 16px 0 22px; border-top: 2px solid var(--key); background: none; }
.aside-card h2, .aside-card h3 {
  margin: 0 0 12px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--sea);
}
.aside-card ul { list-style: none; margin: 0; padding: 0; }
/* the tablet rule below columnises these lists; without this a row can be
   fragmented across the column break and lose its 46px target height */
.aside-card li { border-top: 1px solid var(--hair); break-inside: avoid; }
.aside-card li:first-child { border-top: 0; }
.aside-card li a {
  display: flex; align-items: center; gap: 10px;
  min-height: 46px; padding: 6px 0;
  font-size: var(--step--1); color: var(--ink); text-decoration: none;
}
.aside-card li a:hover { color: var(--sea); }
.aside-card .ico { width: 15px; height: 15px; color: var(--cerulean); }

.aside-cta {
  padding: 24px;
  background: var(--ink); color: var(--txt-inv-soft);
  border: 0; margin-bottom: 24px;
  --field: var(--ink);
}
.aside-cta h2, .aside-cta h3 { color: var(--picton); }
.aside-cta p { font-size: var(--step--1); }
.aside-cta .btn { width: 100%; }
.aside-tel {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  min-height: 48px; margin: 14px 0 10px;
  color: var(--picton); text-decoration: none;
  font-size: 1.14rem; font-weight: 600;
}
.aside-tel .ico { color: var(--picton); }
.aside-tel:hover { color: var(--txt-inv); }

/* --------------------------------------------------------------------------
   12  FORMS + PROJECT PLANNER
   -------------------------------------------------------------------------- */
.c-grid {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: var(--s7);
  align-items: start;
}
.c-grid > :first-child { grid-column: 1 / span 5; }
.c-grid > :last-child { grid-column: 6 / span 7; }
.c-info { border-top: 1px solid var(--rule); }
.c-row {
  display: grid; grid-template-columns: 22px minmax(0, 1fr);
  gap: 14px; align-items: start;
  padding: 16px 0;
  border-bottom: 1px solid var(--hair);
}
.c-row .ico { width: 18px; height: 18px; color: var(--cerulean); margin-top: 3px; }
.c-row b {
  display: block; margin-bottom: 2px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--sea);
}
/* tel:/mailto: here are conversion elements — hold the 44px target */
.c-row a {
  display: inline-flex; align-items: center; min-height: 44px;
  color: var(--ink); text-decoration: none; font-weight: 600;
}
.c-row a:hover { color: var(--sea); text-decoration: underline; }

/* the form is a mounted cut sheet — white, keylined, square */
.form {
  padding: clamp(20px, 2.6vw, 32px);
  background: var(--white);
  border: 1px solid var(--rule);
  --field: var(--white);
}
.form h2 { font-size: var(--step-2); margin-bottom: 0.4em; }
.f-row { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
.f-field { display: grid; gap: 6px; margin-bottom: 16px; min-width: 0; }
.f-field label {
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--sea);
}
.f-field input, .f-field select, .f-field textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--input-line);
  border-radius: 0;
  background: var(--white);
  color: var(--ink-body);
  font-family: var(--font-body); font-size: max(16px, 1rem);
  transition: border-color 0.12s linear;
}
.f-field textarea { resize: vertical; }
.f-field input:hover, .f-field select:hover, .f-field textarea:hover { border-color: var(--prussian); }
.f-field input:focus-visible, .f-field select:focus-visible, .f-field textarea:focus-visible {
  border-color: var(--ink); outline: 3px solid var(--sea); outline-offset: 0;
}
.f-note { margin: 14px 0 0; font-size: var(--step--1); color: var(--ink-body); }
.f-legend {
  margin: 1.6em 0 0.9em; padding-bottom: 8px;
  border-bottom: 1px solid var(--hair);
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--sea);
}
.form .f-legend:first-child { margin-top: 0; }
.form .btn { width: 100%; margin-top: 8px; }
.form-ok {
  margin-top: 14px; padding: 14px 16px;
  border: 1px solid var(--hair); border-left: 3px solid var(--cerulean);
  background: var(--paper);
  font-size: var(--step--1); color: var(--ink);
}

.wiz-sub { margin: -4px 0 20px; font-size: var(--step--1); color: var(--ink-body); }
/* revision strip. min-width:0 is the whole fix for the <=414px overflow. */
.wiz-progress {
  display: flex; gap: 6px;
  list-style: none; margin: 0 0 24px; padding: 0;
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--sea);
}
.wiz-progress li {
  flex: 1 1 0; min-width: 0;
  display: flex; align-items: center; gap: 7px;
  padding: 8px 0 0;
  border-top: 2px solid var(--hair);
  white-space: nowrap; overflow: hidden;
}
.wiz-progress li b {
  flex: none;
  display: grid; place-items: center;
  width: 18px; height: 18px;
  background: var(--paper-2); color: var(--sea);
  font-size: 11px; font-weight: 600;
}
.wiz-progress li.on { border-top-color: var(--ink); color: var(--ink); }
.wiz-progress li.on b { background: var(--picton); color: var(--ink); }

.wstep { border: 0; margin: 0; padding: 0; min-width: 0; }
.wstep legend {
  padding: 0; margin-bottom: 16px;
  font-family: var(--font-display); font-size: 1.08rem; font-weight: 650; color: var(--ink);
}
.wstep legend i { font-style: normal; font-weight: 400; font-size: 0.84em; color: var(--sea); }
.wiz-on .wstep { display: none; }
.wiz-on .wstep.on { display: block; }
.wiz-nav { display: none; }
.wiz-on .wiz-nav { display: flex; gap: 12px; margin-top: 24px; }
.wiz-nav .btn { width: auto; margin-top: 0; flex: 1 1 auto; }

.chips { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
.chip { min-width: 0; }
.chip input { position: absolute; opacity: 0; pointer-events: none; }
.chip span {
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 48px; padding: 12px 10px;
  border: 1.5px solid var(--input-line);
  background: var(--white); color: var(--ink-body);
  font-family: var(--font-display); font-size: 0.92rem; font-weight: 600;
  cursor: pointer;
  transition: border-color 0.12s linear, background 0.12s linear, color 0.12s linear;
}
.chip:hover span { border-color: var(--ink); }
.chip input:checked + span {
  border-color: var(--ink); background: var(--ink); color: var(--txt-inv);
}
.chip input:focus-visible + span { outline: 3px solid var(--sea); outline-offset: 2px; }

/* --------------------------------------------------------------------------
   13  PARTNER BAND (prussian plate) + CTA BAND (ink plate)
   -------------------------------------------------------------------------- */
.pband {
  background: var(--prussian);
  color: var(--txt-inv-soft);
  border-top: 2px solid var(--cerulean);
  padding: var(--band) 0;
  --field: var(--prussian);
}
.pband-in {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gap); row-gap: var(--s6);
  align-items: start;
}
.pband-in > :first-child { grid-column: 1 / span 7; }
.pband-in > :last-child { grid-column: 9 / span 4; }
/* The home page runs this band with no side card. A lone child is BOTH
   :first-child and :last-child, so without this it inherits the rule above and
   gets squeezed into columns 9-12. Must stay after both. */
.pband-in > :only-child { grid-column: 1 / span 8; }
.pband h2 { color: var(--txt-inv); font-size: var(--step-3); margin-bottom: 0.5em; }
.pband h2 em { color: var(--picton); }
.pband p { max-width: 54ch; }
.pband .hero-ctas { margin: 26px 0 0; }

/* payout ladder as a white cut sheet on the prussian field */
.pband-card {
  padding: 22px 24px 24px;
  background: var(--white); color: var(--ink-body);
  border: 0;
  --field: var(--white);
}
.pband-lbl {
  margin: 0 0 14px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--sea);
}
.pband-card ul { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hair); }
.pband-card li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 12px 0;
  border-bottom: 1px solid var(--hair);
  font-size: var(--step--1);
}
.pband-card li b {
  font-family: var(--font-mono); font-size: 1.15rem; font-weight: 600;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.pband-ex {
  margin: 14px 0 0;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--sea);
}
.pband-ex b { color: var(--ink); }

.cta-band {
  background: var(--ink);
  color: var(--txt-inv-soft);
  border-top: 2px solid var(--cerulean);
  padding: var(--band) 0;
  --field: var(--ink);
}
.cta-in {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s6); flex-wrap: wrap;
}
.cta-band h2 { color: var(--txt-inv); font-size: var(--step-3); margin-bottom: 0.35em; max-width: 20ch; }
.cta-band h2 em { color: var(--picton); }
.cta-band p { margin: 0; max-width: 52ch; }
.cta-actions { display: flex; gap: 12px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   14  TITLE BLOCK — the footer is the stamp on the drawing
   -------------------------------------------------------------------------- */
.ftr {
  background: var(--ink);
  color: var(--txt-inv-soft);
  border-top: 2px solid var(--cerulean);
  font-size: var(--step--1);
  --field: var(--ink);
}
.ftr-title {
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  border-bottom: 1px solid var(--rule-inv);
}
.ftr-cell {
  padding: 18px 18px 12px 0;   /* bottom trimmed 8px: the 44px links below add it back */
  border-left: 1px solid var(--hair-inv);
  padding-left: 18px;
  min-width: 0;
}
.ftr-cell:first-child { border-left: 0; padding-left: 0; }
.ftr-cell dt, .ftr-k {
  display: block; margin-bottom: 7px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--txt-inv-soft);
}
.ftr-cell dd, .ftr-v {
  margin: 0;
  font-family: var(--font-mono); font-size: var(--step--2); line-height: 1.55;
  letter-spacing: 0.02em; color: var(--txt-inv);
  font-variant-numeric: tabular-nums;
}
/* two of the three are tel: links — conversion elements at a 19px tap target
   before this. 44px floor, same as every other link on the site (§8 d25). */
.ftr-cell a {
  display: flex; align-items: center; min-height: 44px;
  color: var(--txt-inv); text-decoration: none;
}
.ftr-cell a:hover { color: var(--picton); }

.ftr-grid {
  display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr;
  gap: var(--gap);
  padding-top: var(--s7); padding-bottom: var(--s6);
}
.brand-ftr { color: var(--txt-inv); margin-bottom: 16px; }
.ftr-pitch { color: var(--txt-inv-soft); max-width: 34ch; }
.ftr-nap { display: grid; gap: 3px; margin: 16px 0 8px; font-family: var(--font-mono); font-size: var(--step--2); }
.ftr-nap a {
  display: flex; align-items: center; min-height: 44px;
  color: var(--txt-inv); text-decoration: none;
}
.ftr-nap a:hover { color: var(--picton); }
.ftr-hours, .ftr-lic {
  font-family: var(--font-mono); font-size: var(--step--2); line-height: 1.6;
  color: var(--txt-inv-soft);   /* 8.3:1 — was #6f7c9c at 4.41 */
}
.ftr-lic { margin-bottom: 0; }
.ftr-col h2 {
  margin-bottom: 14px;
  font-family: var(--font-mono); font-size: var(--step--2); font-weight: 600;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--txt-inv-soft);
}
.ftr-col ul { list-style: none; margin: 0; padding: 0; }
.ftr-col li { border-top: 1px solid var(--hair-inv); }
.ftr-col li:first-child { border-top: 0; }
.ftr-col a {
  display: flex; align-items: center; min-height: 44px;
  color: var(--txt-inv-soft); text-decoration: none; font-size: var(--step--1);
}
.ftr-col a:hover { color: var(--picton); }
.ftr-btm {
  display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  border-top: 1px solid var(--rule-inv);
  padding-top: 22px; padding-bottom: 26px;
  font-family: var(--font-mono); font-size: var(--step--2);
  letter-spacing: 0.04em; color: var(--txt-inv-soft);
}
.ftr-btm p { margin: 0; }

/* ==========================================================================
   15  MOTION — the page plots itself in.

   ONE metaphor: a plotter drawing a sheet. Rules extend, keylines draw, type
   sets into place, a marker strokes across a word. Nothing floats, glows,
   bounces, shimmers or follows the cursor, and nothing loops.

   THREE HARD RULES, in priority order:

   1. The entrance is CSS-ONLY. Every declaration below runs off a selector the
      stylesheet already owns — no class is waiting on site.js. CSS animations
      start at style-resolution time, so the page is already moving before the
      deferred script has been fetched. (The previous pass gated the whole
      effect on `html.js-anim`, which is why a refresh looked dead.)
   2. The LCP element never starts transparent. On every page the H1 is the
      largest text block, and Chrome does not count an `opacity: 0` element as
      painted. `.hero h1` / `.p-hero h1` therefore animate TRANSFORM ONLY. The
      deck is the next-largest block and is a plausible LCP candidate on a
      phone, so it fades from a *visible* floor (0.38), never from zero.
      Everything else here is small enough to fade from 0 safely.
   3. Nothing shifts. Only transform, opacity, clip-path and background-size
      are animated — none of them affect layout, so CLS stays at 0.

   `animation-fill-mode: backwards` throughout, and every @keyframes below
   declares `from` only: the implicit `to` is the element's real resting style,
   so an animation can never strand an element in a decorated state, and
   deleting a rule here can never change how the page looks at rest.
   ========================================================================== */

/* --- 15.1  the load choreography -----------------------------------------
   The sheet plots from the top down and finishes with the marker, 1.22s.

     0.02s  the drawing header wipes in, left to right
     0.09s  H1 rises 14px into place            (transform only — see rule 2)
     0.20s  the cut sheet is uncovered downward — frame, keylines, head
     0.21s  deck sets                            (fades from 0.38, rises 10px)
     0.26s  the header's hairline extends out under it
     0.29s  calls to action set
     0.32s  the cut sheet's six rows resolve in order, then its footer
     0.35s  the point list sets
     0.46s  stamp-strip cells are wiped in, left to right, done at 0.98s
     0.62s  the marker strokes across the emphasised words, landing at 1.22s

   ORDERING NOTE. The header rule starts at 0.26s, AFTER the wipe above it has
   finished, and not alongside it. Both gestures run left-to-right from the
   same origin, and the rule is a child of the wiped box: when they started
   together the rule's leading edge was always ahead of the wipe's clip edge,
   so the whole extension was masked and the animation was invisible. Sequenced,
   you see the label set and then the rule drawn out under it — which is the
   order a plotter would do it in anyway.
   -------------------------------------------------------------------------- */
@keyframes plotWipe  { from { clip-path: inset(0 100% 0 0); } }
@keyframes plotRule  { from { transform: scaleX(0); } }
@keyframes plotRise  { from { transform: translateY(14px); } }
@keyframes plotSet   { from { opacity: 0; transform: translateY(10px); } }
@keyframes plotDeck  { from { opacity: 0.38; transform: translateY(10px); } }
/* `round 14px` matches §7.1's fillet, and the resting clip below matches this
   keyframe's shape exactly. Without both halves the two values are not
   interpolable, clip-path falls back to a discrete 50% swap, and the plate
   stops being uncovered and simply blinks on. */
@keyframes plotSheet { from { clip-path: inset(0 0 100% 0 round 14px); } }
/* the band height here MUST match `.hero h1 em`'s resting background-size (§5),
   or the marker changes thickness while it strokes. Only the width animates. */
@keyframes plotMark  { from { background-size: 0% 100%; } }
@keyframes inkFade   { from { opacity: 0; } }

.hero .kicker,
.p-hero .kicker          { animation: plotWipe 0.34s var(--ease-mark) 0.02s backwards; }
.hero .kicker::after,
.p-hero .kicker::after   { animation: plotRule 0.5s var(--ease-plot) 0.26s backwards; }

/* LCP: transform only. Opacity is never touched, at any point in the timeline. */
.hero h1,
.p-hero h1               { animation: plotRise 0.5s var(--ease-plot) 0.09s backwards; }

.hero .hero-sub,
.p-hero .hero-sub        { animation: plotDeck 0.42s var(--ease-plot) 0.21s backwards; }
.hero .hero-ctas,
.p-hero .hero-ctas       { animation: plotSet 0.38s var(--ease-plot) 0.29s backwards; }
.hero .hero-points       { animation: plotSet 0.36s var(--ease-plot) 0.35s backwards; }

/* THE CUT SHEET, in two stages — the blank form, then the schedule on it.
   First the sheet is uncovered downward: its edge, its head and every row rule
   arrive together as one drawn object. Then the entries resolve into it in
   order, and the footer last.

   The fade is on `.dash-row a`, NOT on the `<li>`. The row's score line and its
   terminal both live on the li (`.dash-row + .dash-row::before`, `.dash-row
   ::after`), and fading the li took them with it — the plate then landed empty
   and the whole "form first, entries onto it" idea was lost. Fading the anchor
   leaves the scored, terminated form standing and writes the six entries into
   it, which is the point, and it is also what lets §15.1a light the terminals
   before their text has finished arriving.

   Each delay is timed to land after the uncovering clip has already passed
   over that row, so nothing ever appears ahead of the plotter head. */
.hero .hero-panel        { clip-path: inset(0 0 0 0 round 14px);
                           animation: plotSheet 0.4s var(--ease-plot) 0.2s backwards; }

.hero .dash-row a        { animation: inkFade 0.26s linear backwards; }
.hero .dash-row:nth-child(1) a { animation-delay: 0.32s; }
.hero .dash-row:nth-child(2) a { animation-delay: 0.37s; }
.hero .dash-row:nth-child(3) a { animation-delay: 0.42s; }
.hero .dash-row:nth-child(4) a { animation-delay: 0.47s; }
.hero .dash-row:nth-child(5) a { animation-delay: 0.52s; }
.hero .dash-row:nth-child(6) a { animation-delay: 0.57s; }
.hero .dash-foot > *,
.hero .dash-foot::before { animation: inkFade 0.26s linear 0.62s backwards; }

/* --- 15.1a  COMMISSIONING — the enclosure comes up ------------------------
   The one moment on this page that belongs to Enterlace and nobody else, and
   the answer to "it's too static". Once the plate has been uncovered and the
   six channels have been written onto it, the supply LED seats at 0.58s and the
   light runs DOWN the riser in the gutter, taking 0.78s to reach the terminal
   bar. Each terminal fills and each designator comes up as the light passes that
   tap, and both go back down behind it — six ports coming up in order on a rack
   that has just been energised. Then the riser goes back to being an engraving.
   Nothing is left lit, and it happens exactly once.

   It is deliberately the LAST thing in the timeline: the marker strokes the
   headline at 0.62–1.22s and leads, the panel answers underneath it and lands
   at 1.42s. Two gestures, one after the other, never competing for the eye.

   `energize` carries an explicit 100% that is identical to the resting state in
   §7.1 (clip fully open, opacity 0). That is what makes reduced-motion safe:
   collapsing the duration jumps to 100%, which is "spent", not "mid-sweep".
   Each key's peak sits at 34% of its own 0.46s, so the delays below are the
   moment the light reaches that tap minus 0.156s.
   -------------------------------------------------------------------------- */
@keyframes energize {
  0%   { clip-path: inset(0 0 100% 0); opacity: 0; }
  9%   { opacity: 1; }
  74%  { opacity: 1; }
  100% { clip-path: inset(0 0 0 0);    opacity: 0; }
}
@keyframes keyLit {
  0%, 100% { color: var(--key-dim); text-shadow: none; }
  34%      { color: var(--lamp-hi); text-shadow: 0 0 10px rgba(0, 168, 232, 0.75); }
}
@keyframes termLit {
  0%, 100% { border-color: var(--term); background: transparent; box-shadow: none; }
  34%      { border-color: var(--lamp); background: var(--lamp);
             box-shadow: 0 0 9px 0 rgba(0, 168, 232, 0.65); }
}
@keyframes ledOn { from { opacity: 0; } }

.hero .dash-head::before { animation: ledOn 0.3s linear 0.58s backwards; }
.hero .dash-rows::after  { animation: energize 0.78s linear 0.64s backwards; }

/* the designator and its terminal come up together — one delay per channel,
   shared by both so a tap can never light out of step with its number */
.hero .dash-key   { animation: keyLit 0.46s var(--ease-plot) backwards; }
.hero .dash-row::after { animation: termLit 0.46s var(--ease-plot) backwards; }
.hero .dash-row:nth-child(1) .dash-key, .hero .dash-row:nth-child(1)::after { animation-delay: 0.57s; }
.hero .dash-row:nth-child(2) .dash-key, .hero .dash-row:nth-child(2)::after { animation-delay: 0.70s; }
.hero .dash-row:nth-child(3) .dash-key, .hero .dash-row:nth-child(3)::after { animation-delay: 0.83s; }
.hero .dash-row:nth-child(4) .dash-key, .hero .dash-row:nth-child(4)::after { animation-delay: 0.96s; }
.hero .dash-row:nth-child(5) .dash-key, .hero .dash-row:nth-child(5)::after { animation-delay: 1.09s; }
.hero .dash-row:nth-child(6) .dash-key, .hero .dash-row:nth-child(6)::after { animation-delay: 1.22s; }

.crumbs ol               { animation: inkFade 0.3s linear 0.06s backwards; }

/* THE STAMP STRIP is wiped, not faded: each cell is drawn across from its own
   divider, in sequence, so the bottom of the document header reads as four
   stamps being applied left to right rather than four things switching on.
   A clip costs no layout, so the verticals that separate the cells never move
   relative to one another.

   --ease-plot, not --ease-mark: the marker curve holds a beat before it moves,
   which on four short cells 60ms apart made the strip look like it stalled and
   then rushed. The plotter curve puts each cell across fast and lets it settle,
   and the whole strip is done at 0.98s — before the marker lands. */
.trust-list > li                 { animation: plotWipe 0.34s var(--ease-plot) backwards; }
.trust-list > li:nth-child(1)    { animation-delay: 0.46s; }
.trust-list > li:nth-child(2)    { animation-delay: 0.52s; }
.trust-list > li:nth-child(3)    { animation-delay: 0.58s; }
.trust-list > li:nth-child(4)    { animation-delay: 0.64s; }

/* THE MARKER — the signature moment, and the one the client asked for by name.
   An estimator running a highlighter across the scope of work: it starts at
   0.62s, once the page has finished setting itself, and takes 600ms to cross
   the words on --ease-mark, which loads a beat of pressure at the start and
   lets the nib run out at the end.

   background-size is the cheapest honest way to draw it. box-shadow cannot be
   animated across a line break, and width/clip on an inline box collapses the
   moment the pair wraps — whereas background-size + box-decoration-break:clone
   gives each line fragment its own band and its own stroke, and animates a
   paint-only property, so a wrapped headline neither reflows nor shifts. */
.hero h1 em,
.p-hero h1 em            { animation: plotMark 0.6s var(--ease-mark) 0.62s backwards; }

/* --- 15.2  scroll reveal --------------------------------------------------
   A rise plus a fade, 420ms on the same plotter curve. Gated on `js-anim` so
   that a page whose script never runs is simply a page with no reveal — the
   backstop in site.js drops the whole effect rather than leave content hidden.
   -------------------------------------------------------------------------- */
.js-anim .rv {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.42s var(--ease-plot), transform 0.42s var(--ease-plot);
  transition-delay: var(--rv-d, 0ms);
}
.js-anim .rv.in { opacity: 1; transform: none; }

/* a section's dimension rule draws out of the gutter as the section arrives.
   `left` is already -(--rail), so a left origin starts the line on the spine. */
.js-anim .sec-h.rv::after {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.55s var(--ease-plot);
  transition-delay: var(--rv-d, 0ms);
}
.js-anim .sec-h.rv.in::after { transform: scaleX(1); }

/* hard guarantee: nothing in the load choreography ever waits on a script to
   become visible. site.js also skips these when collecting reveal targets —
   this is the belt to that pair of braces. */
.js-anim .hero .rv, .js-anim .p-hero .rv, .js-anim .hero-panel.rv,
.js-anim .crumbs .rv, .js-anim .trust .rv {
  opacity: 1;
  transform: none;
}

/* --- 15.3  interaction ----------------------------------------------------
   The same language at the pointer: rules darken, keylines draw, designators
   advance. No lift, no scale, no shadow, no glow — buttons keep their invert.
   -------------------------------------------------------------------------- */

/* a schedule row's keyline draws itself across on hover. Absolutely positioned
   so it is neither a grid item (.card) nor a flex item (.g-card). */
.card, .g-card { position: relative; }
.card::after, .g-card::after {
  content: "";
  position: absolute; left: 0; right: 0; top: -1px;
  height: 2px; background: var(--key);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 0.34s var(--ease-plot);
  pointer-events: none;
}
a.card:hover::after, a.card:focus-visible::after,
.g-card:hover::after, .g-card:focus-visible::after { transform: scaleX(1); }

/* the city index rules the row it is on */
.city-grid a { position: relative; }
.city-grid a::after {
  content: "";
  position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--key);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 0.3s var(--ease-plot);
  pointer-events: none;
}
.city-grid a:hover::after, .city-grid a:focus-visible::after { transform: scaleX(1); }

/* the designator advances. `.card-go em` is inline, so it needs a box first. */
.card-go em { display: inline-block; }
.card-go em, .dash-st { transition: transform 0.18s var(--ease-plot); }
a.card:hover .card-go em,
.g-card:hover .card-go em { transform: translateX(4px); }

/* --- 15.3a  A CHANNEL GOING LIVE -----------------------------------------
   The enclosure's hover, and the "add something on hover" the client asked for.
   It is one causal chain, not a set of simultaneous state changes, and it is
   ordered so the light appears to arrive from the riser:

     0ms    the terminal on the riser fills, and the channel lamp opens on the
            plate's left edge — the drop goes live at its tap
     40ms   the backlight wipes right, INTO the channel, on --ease-mark
     0ms    the designator and the arrow come up to --lamp-hi with it
     +5px   the arrow advances

   Everything is paint or transform. Nothing here reflows, nothing lifts off the
   plate, nothing blurs, and the light never leaves the lens — the whole effect
   is contained inside a rounded rect 12px in from the channel edge, which is
   what separates a backlit engraving from a glowing card.

   TOUCH. The lamp/lens/colour changes are declared for :hover inside
   `@media (hover: hover)` so a phone never latches a lit channel after a tap,
   and repeated for :focus-visible OUTSIDE it so a keyboard gets the identical
   affordance on every device. The transitions themselves live on the resting
   rules (above, §7.1's neighbours) so they apply to both. */
.dash-row a::before { transition: clip-path 0.26s var(--ease-mark) 0.04s; }
.dash-row a::after  { transition: transform 0.24s var(--ease-plot); }
.dash-key, .dash-row b { transition: color 0.16s linear, text-shadow 0.16s linear; }
.dash-row::after {
  transition: border-color 0.18s linear, background-color 0.18s linear, box-shadow 0.18s linear;
}

@media (hover: hover) {
  .dash-row a:hover::before { clip-path: inset(0 0 0 0 round 10px); }
  .dash-row a:hover::after  { transform: scaleY(1); }
  .dash-row:has(a:hover)::after {
    border-color: var(--lamp); background: var(--lamp);
    box-shadow: 0 0 9px 0 rgba(0, 168, 232, 0.65);
  }
  .dash-row a:hover .dash-key { color: var(--lamp-hi); text-shadow: 0 0 9px rgba(0, 168, 232, 0.6); }
  .dash-row a:hover b { text-shadow: 0 0 14px rgba(0, 168, 232, 0.45); }
  .dash-row a:hover .dash-st { color: var(--lamp-hi); transform: translateX(5px); }
}
/* keyboard gets the identical channel, on every device — the terminal lives on
   the li and the focus lives on the a, so `:has()` is the only way to reach it
   from the link. Unsupported `:has()` degrades to "terminal stays open", which
   is a resting style, not a broken one: the lamp, lens, designator and arrow
   all still respond. */
.dash-row a:focus-visible::before { clip-path: inset(0 0 0 0 round 10px); }
.dash-row a:focus-visible::after  { transform: scaleY(1); }
.dash-row:has(a:focus-visible)::after {
  border-color: var(--lamp); background: var(--lamp);
  box-shadow: 0 0 9px 0 rgba(0, 168, 232, 0.65);
}
.dash-row a:focus-visible .dash-key { color: var(--lamp-hi); text-shadow: 0 0 9px rgba(0, 168, 232, 0.6); }
.dash-row a:focus-visible .dash-st  { color: var(--lamp-hi); transform: translateX(5px); }

/* nav items rule under themselves before they become current */
.nav a { transition: color 0.12s linear, border-color 0.16s linear; }
.nav a:hover { border-bottom-color: rgba(0, 168, 232, 0.5); }

/* the fold marker fades between + and − instead of swapping hard */
.fold-x::before, .faq-ico::before { transition: color 0.14s linear; }
.fold summary:hover .fold-x::before, .faq summary:hover .faq-ico::before { color: var(--ink); }

/* --- 15.4  reduced motion -------------------------------------------------
   This is the ONLY reduced-motion block in the file, and it has to be complete,
   because a `*` selector does NOT match ::before / ::after — that exact defect
   shipped once, leaving a pseudo-element pulsing forever for the users least
   able to tolerate it. Every rule in §15 leans on pseudo-elements, so they are
   named here explicitly.

   Two layers:
   (a) collapse every duration and delay, which is enough on its own for the
       from-only keyframes — with nothing but a `from`, the implicit `to` is
       the resting design, so a zero-length animation lands exactly there;
   (b) then pin, with !important, every property §15 animates that is NOT its
       own resting value in the cascade, so no future edit can strand one.

   Nothing loops anywhere in this file (`iteration-count: 1` is belt to that
   brace), and the marker ends fully struck rather than not drawn at all — the
   highlight is part of the design, only the stroking of it is motion.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }
  .rv, .js-anim .rv { opacity: 1 !important; transform: none !important; }
  /* every clip in the load choreography, uncovered */
  .hero .kicker, .p-hero .kicker,
  .hero .hero-panel,
  .trust-list > li { clip-path: none !important; }
  /* everything that fades in, opaque */
  .crumbs ol, .hero .dash-row a, .hero .dash-foot > *,
  .hero .dash-foot::before, .hero .dash-head::before { opacity: 1 !important; }
  /* THE COMMISSIONING SWEEP (§15.1a), spent. Named element by element because
     the `*` above does not reach a pseudo, and this sweep is nothing BUT
     pseudo-elements: without this a reduced-motion user would be left with a
     picton riser frozen mid-run down the gutter. */
  .hero .dash-rows::after { opacity: 0 !important; clip-path: inset(0 0 0 0) !important; }
  /* The designator and its terminal are pinned back to unlit — but only on
     channels that are NOT under the pointer or holding focus. A bare pin would
     have used !important to overwrite §15.3a's hover and focus states too, and
     taken the affordance away from exactly the users this block is for. Where
     `:has()` is unavailable the whole selector drops out and `termLit`/`keyLit`
     still land unlit on their own: both carry an explicit 100% identical to the
     resting style, which is the belt these braces are backing up. */
  .hero .dash-row a:not(:hover):not(:focus-visible) .dash-key {
    color: var(--key-dim) !important;
    text-shadow: none !important;
  }
  .hero .dash-row:not(:has(a:hover)):not(:has(a:focus-visible))::after {
    border-color: var(--term) !important;
    background: transparent !important;
    box-shadow: none !important;
  }
  /* the marker, fully struck. Keep this height in step with §5 and plotMark. */
  .hero h1 em, .p-hero h1 em { background-size: 100% 100% !important; }
  /* rules that are part of the resting design, snapped to drawn */
  .hero .kicker::after, .p-hero .kicker::after,
  .js-anim .sec-h.rv::after, .js-anim .sec-h.rv.in::after { transform: none !important; }
  /* The hover keylines on schedule rows and the city index are NOT removed
     here. Their transform is a resting style, not an animation, so with the
     transition collapsed above they simply appear and disappear with the
     pointer — a state change, not motion — and reduced-motion users keep the
     same affordance everyone else gets. */
}

/* ==========================================================================
   16  RESPONSE
   Wide screens are solved by BLEED and a stepped sheet, never by stretching.
   ========================================================================== */

/* Above the burger breakpoint the mobile panel is never shown — even if it was
   left expanded on the way up through 1100px, where there is no burger left to
   close it (defect 19). Placed after the base rule so it wins on order.
   1101 is the strict complement of the .burger breakpoint below; site.js and the
   noscript override in layout.mjs carry the same number. Change all four or none. */
@media (min-width: 1101px) {
  .m-nav { display: none; }
}

/* -- the gutter appears at 1180: designators hang, a spine is drawn --------- */
@media (min-width: 1180px) {
  :root { --rail: 112px; --hdr-h: 72px; }

  .sec > .wrap { position: relative; padding-left: calc(var(--gut) + var(--rail)); }
  .sec > .wrap::before {
    content: "";
    position: absolute; top: 0; bottom: 0;
    left: calc(var(--gut) + var(--rail) - 1px);
    width: 1px; background: var(--hair);
  }
  .sec-ink > .wrap::before { background: var(--hair-inv); }

  /* designators move out into the channel */
  .sec-h { padding-top: 26px; }
  /* pre-WRAP, not pre: the channel is 92px and "SERVICE AREAS" measures 118px
     (125px once the root goes to 18px), so `pre` pushed the designator across
     the spine and into the heading column. pre-wrap still honours the \A break
     below; the longest single word ("SCHEDULE") is 72px, well inside 92. */
  .sec-h::before {
    position: absolute; left: calc(-1 * var(--rail)); top: 26px;
    margin: 0; width: calc(var(--rail) - 20px);
    white-space: pre-wrap; overflow-wrap: break-word; line-height: 1.5;
  }
  .sec-h[data-key]::before { content: "A-" counter(sheet) "\A" attr(data-key); }
  .prose > h2::before {
    position: absolute; left: calc(-1 * var(--rail)); top: 18px; margin: 0;
  }
}

@media (min-width: 1440px) { :root { --wrap: 1360px; } }
@media (min-width: 1560px) { html { font-size: 18px; } }
@media (min-width: 1920px) { :root { --wrap: 1560px; --rail: 152px; } }
@media (min-width: 2400px) { :root { --wrap: 1720px; } }

/* -- 1021–1180: no rail yet, but full desktop chrome ----------------------- */
@media (max-width: 1360px) {
  .brand-txt i { display: none; }
}
@media (max-width: 1180px) {
  .hdr-mail { display: none; }
  .nav a { padding: 0 9px; font-size: 0.86rem; }
}

/* -- THE HEADER BREAKPOINT ------------------------------------------------
   The desktop header needs 1007px (brand 191 + nav 475 + hdr-cta 289 + 2x26
   gaps) and does not fit until ~1070. Switching it on at 1021 scrolled the
   document sideways by up to 45px and truncated the primary CTA to "Free Qu"
   on a 1024x768 iPad in landscape. Burger territory therefore runs to 1100,
   with the callbar carrying the Free Quote — see the callbar block below.
   THREE OTHER PLACES CARRY THIS NUMBER: the `min-width: 1101px` .m-nav guard
   above, the noscript override in layout.mjs, and the matchMedia query in
   site.js (which must stay the strict complement, i.e. min-width: 1101px). */
@media (max-width: 1100px) {
  .nav { display: none; }
  .hdr-cta .btn { display: none; }
  .burger { display: block; }

  /* the callbar is the only Free Quote from here down — show it with the
     burger, not at 1020, or 1021–1100 has no visible CTA at all */
  .callbar {
    display: flex; gap: 10px;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
    background: var(--ink);
    border-top: 2px solid var(--cerulean);
    padding: 9px max(14px, env(safe-area-inset-left)) calc(9px + env(safe-area-inset-bottom));
  }
  .callbar a {
    flex: 1; display: flex; align-items: center; justify-content: center;
    min-height: 46px; padding: 10px;
    text-decoration: none; text-align: center;
    font-family: var(--font-display); font-size: 0.95rem; font-weight: 700;
  }
  .callbar .cb-call { background: var(--picton); color: var(--ink); }
  .callbar .cb-quote { background: transparent; color: var(--txt-inv); border: 1.5px solid var(--txt-inv); }
  /* clears the bar on every page — the old 66px did not (defect 5).
     The padding is CONSTANT whether the bar is shown or hidden. Reserving the
     space either way is what keeps the reveal below from shifting the page. */
  body { padding-bottom: calc(78px + env(safe-area-inset-bottom)); }

  /* ---- THE BAR STAYS OUT OF THE WAY UNTIL THE HERO CTAs ARE GONE ----
     Opening a page used to put "Call" and "Free Quote" on screen twice at once:
     once in the hero, and again pinned to the bottom. The client's read on that
     was that it takes more real estate than it earns, and he is right — while
     the hero buttons are visible the bar is pure duplication.

     So site.js watches the hero's own CTA pair and only slides the bar up once
     they have scrolled off. Scroll back to the top and it slides away again.

     PROGRESSIVE ENHANCEMENT, and the reason this is keyed off a class on <html>
     rather than being hidden by default: with JavaScript off, `callbar-auto` is
     never added and the bar simply stays visible, exactly as it does today. A
     phone with no JS keeps its permanent call button rather than losing it. */
  .callbar-auto .callbar {
    transform: translateY(110%);
    transition: transform 0.3s cubic-bezier(0.16, 0.84, 0.44, 1);
    will-change: transform;
  }
  .callbar-auto .callbar.is-in { transform: none; }
  /* Never trap focus off-screen: if a keyboard reaches the hidden bar, show it. */
  .callbar-auto .callbar:focus-within { transform: none; }
}

/* Reduced motion keeps the behaviour and drops the slide. */
@media (prefers-reduced-motion: reduce) {
  .callbar-auto .callbar { transition: none; }
}

/* -- the 640–1020 band: tablets. Previously unstyled territory (defect 12). - */
@media (max-width: 1020px) {
  .hero-grid > :first-child,
  .hero-grid > .hero-panel { grid-column: 1 / -1; }
  .hero-grid { row-gap: var(--s6); }

  .split > :first-child, .split > :last-child,
  .c-grid > :first-child, .c-grid > :last-child,
  .pband-in > :first-child, .pband-in > :last-child { grid-column: 1 / -1; }
  .aside { position: static; }
  .aside-card ul { columns: 2; column-gap: var(--gap); }
  .aside-cta { grid-column: 1 / -1; }
  .aside-cta ul { columns: 1; }

  .cards > * { grid-column: span 6; }
  .g-cards > * { grid-column: span 6; }
  .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .inc-grid, .prose .inc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .t-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* ten cities: the ladder only ever uses counts that divide 10, so no ruled
     row is ever short. 3-up gave 3+3+3+1 here and 4-up gave 4+4+2 at 1180. */
  .city-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* 5 marks at 3-up = 3 + 2, and the last cell spans the leftover column, so
     both rows fill. No dead cell, no orphan. */
  .brands-list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .brands-list li:last-child { grid-column: span 2; }
  .b-card:first-child { border-left: 1px solid var(--hair); }
  .brands-list li:nth-child(3n + 1) { border-left: 0; }
  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stats li { padding: 18px 20px; border-top: 1px solid var(--rule-inv); }
  .stats li:nth-child(odd) { padding-left: 0; border-left: 0; }
  .ftr-title { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .ftr-cell:nth-child(3n + 1) { border-left: 0; padding-left: 0; }
  .ftr-grid { grid-template-columns: 1fr 1fr; }
}

/* -- phones ---------------------------------------------------------------- */
@media (max-width: 780px) {
  .cta-in { align-items: flex-start; }
  .cta-actions { width: 100%; }
  .cta-actions .btn { flex: 1 1 auto; }
}

@media (max-width: 640px) {
  .hdr-in { gap: 12px; }
  /* icon-only phone link keeps its accessible name (defect 4) */
  .hdr-tel .hdr-num {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip-path: inset(50%); overflow: hidden; white-space: nowrap;
  }

  .hero h1 { font-size: clamp(2rem, 8.6vw, 2.6rem); }
  .hero-sub, .sec-sub { font-size: 1.02rem; }
  .hero-points { gap: 8px 20px; }
  .sec-h { font-size: 1.62rem; }

  /* THE ENCLOSURE narrows its spine (§7.1). The measure to beat at 390 is the
     longest spec string, "4K · hard-wired · recorded on site" — 34 characters of
     tabular mono, 250px with the tracking dropped. Everything below is spent
     buying that: 26px indent, 20px designator column, 9px gaps, 14px right pad
     and no letter-spacing on the mono, which leaves ~264px of free column. Miss
     it and the first channel wraps to a second line and stands 20px taller than
     the other five, which is what an enclosure with one crooked channel looks
     like. At 360 it wraps regardless — it did before this treatment too, there
     is simply not 250px there. The gutter narrows with the indent and every
     seated part follows it, because all of them are centred off --gutter. */
  .hero-panel { --gutter: 12px; --indent: 26px; }
  .dash-head, .dash-foot { padding-right: 14px; }
  .dash-row a {
    grid-template-columns: 20px minmax(0, 1fr) auto;
    gap: 4px 9px;
    padding-right: 14px;
  }
  .dash-row i { letter-spacing: 0; }
  .dash-st { letter-spacing: 0.06em; }
  .dash-row a::before { inset: 5px 9px 5px 3px; }
  .dash-foot::before { width: 11px; }

  .cards > *, .g-cards > * { grid-column: span 12; }
  .cards a.card > p { display: none; }       /* scoped: partner cards keep theirs */
  .card { padding: 14px 0 16px; }
  .card-ico { grid-row: 1; align-self: center; padding-top: 0; }
  .card > h3 { grid-column: 2; grid-row: 1; font-size: 1rem; }
  .card > p { grid-column: 1 / -1; grid-row: 2; }
  .card-key { display: none; }
  .card > .card-go { padding-top: 0; }

  .steps, .inc-grid, .prose .inc-grid, .t-grid { grid-template-columns: 1fr; }
  .steps { row-gap: 0; }
  .brands-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .brands-list li:last-child { grid-column: span 2; }
  .brands-list li:nth-child(4n + 1) { border-left: 1px solid var(--hair); }
  .brands-list li:nth-child(odd) { border-left: 0; }
  .trust-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .trust-list li { padding: 16px 12px 18px; border-top: 1px solid var(--hair); }
  .trust-list li:nth-child(odd) { border-left: 0; padding-left: 0; }
  .trust-list i { display: none; }

  .split, .c-grid { row-gap: var(--s6); }
  .aside-card ul { columns: 1; }
  .f-row { grid-template-columns: 1fr; }
  .wiz-progress { gap: 4px; }
  .wiz-progress li { font-size: 0; padding-top: 7px; }   /* labels drop, numbers stay */
  .wiz-progress li b { font-size: 12px; width: 20px; height: 20px; }
  .chips { gap: 8px; }
  .chip span { font-size: 0.88rem; padding: 11px 8px; }

  .prose table { font-size: var(--step--2); }
  .prose th, .prose td { padding: 10px 9px; overflow-wrap: anywhere; }

  .qa-box { padding: 22px 16px 4px; }
  .qa-lbl { left: 12px; }
  .callout { padding: 22px 20px; }
  .g-img { padding: 8px; }

  .ftr-title { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ftr-cell { padding: 14px 12px 8px; border-top: 1px solid var(--hair-inv); }
  .ftr-cell:nth-child(odd) { border-left: 0; padding-left: 0; }
  .ftr-grid { grid-template-columns: 1fr; gap: var(--s5); }
  .ftr-btm { font-size: 11px; }
}

@media (max-width: 420px) {
  .hero-points { flex-direction: column; gap: 7px; }
  .hero-ctas .btn { width: 100%; }
  .stats { grid-template-columns: 1fr; }
  .stats li { padding: 16px 0; border-left: 0; }
  .callbar { gap: 8px; padding-inline: 10px; }
  .callbar a { font-size: 0.86rem; padding: 8px 4px; }
}

/* -- 320 REFLOW (WCAG 1.4.10) ---------------------------------------------
   The header set the minimum content width at 325px: brand 191 (wordmark alone
   is 148 at 1.12rem/.15em) + 12 + tel 44 + 12 + burger 46 = 305 inside a 280px
   content box at 320. Tightening the two gaps and the wordmark's tracking
   recovers ~43px. .hdr-tel and .burger are NOT touched — both are already at
   the 44px tap-target floor. */
@media (max-width: 380px) {
  .hdr-in { gap: 8px; }
  .brand { gap: 8px; }
  .brand-txt b { font-size: 0.95rem; letter-spacing: 0.06em; }
}

/* -- PRINT ----------------------------------------------------------------
   `.js-anim .rv { opacity: 0 }` is cleared only by the IntersectionObserver, so
   Ctrl+P without scrolling printed 49 of 53 reveal targets on the home page
   invisible. Nothing here is a design decision — it is the screen chrome coming
   off the paper. */
@media print {
  /* `animation: none` drops every §15 rule back to its resting style, which is
     the whole point of the from-only keyframes: a sheet that has finished
     plotting is exactly what should come out of the printer. */
  *, *::before, *::after { animation: none !important; transition: none !important; }
  .rv, .js-anim .rv { opacity: 1 !important; transform: none !important; }
  .card::after, .g-card::after, .city-grid a::after { display: none !important; }
  .callbar, .burger, .m-nav, .skip { display: none !important; }
  .hdr { position: static; }
  body { padding-bottom: 0 !important; }
}
