/* ==========================================================================
   LiftPulse — one-page lead-gen site
   Hybrid of the ControlFreq design system on a dark-first urgency layout:
   CF green (#7DC342) accents/CTAs · CF navy scale · CF amber (#F5A623) for
   deadline urgency · Sora display + Public Sans body and labels.
   Token values mirror the ControlFreq --cf-* palette.
   ========================================================================== */

:root {
  --navy-950: #0e1520;   /* cf-grey-900 */
  --navy-900: #1a2333;   /* cf-navy */
  --navy-800: #2c3e56;   /* cf-navy-mid */
  --navy-700: #3d5270;   /* cf-navy-light */
  --ink: #1a2333;        /* cf-navy as ink on light */
  --slate: #5e718a;      /* cf-grey-500 */
  --slate-light: #8a9bb0; /* cf-grey-400 */
  --paper: #ffffff;
  --paper-dim: #f4f5f7;  /* cf-grey-50 */
  --accent: #7dc342;     /* cf-green */
  --accent-dark: #5fa029; /* cf-green-dark — 3.2:1 on white: fine for icons, short of the 4.5:1 text needs */
  --accent-ink: #4d8321;  /* the same green taken far enough down to clear 4.5:1 as text on white */
  --accent-deep: #477a1e; /* one step further down: 4.68:1 on the pricing table's green tint, where --accent-ink is only 4.15:1 */
  --accent-light: #a8d96e; /* cf-green-light */
  --accent-soft: rgba(125, 195, 66, 0.14);
  --accent-tint: #ebf6db; /* cf-green-xlight */
  --amber: #f5a623;      /* cf-warning — deadline urgency */
  --amber-ink: #9a6a10;  /* the same warning taken down to 4.73:1 as text on white — --amber is 2.03:1 there */
  --error: #e84040;      /* cf-error */
  --line-dark: rgba(138, 155, 176, 0.18);
  --line-light: #e2e6ea; /* cf-border */
  --radius: 16px;        /* cf radius-xl */
  --radius-sm: 8px;      /* cf radius-md */
  --radius-pill: 999px;  /* every button; matches the CTA pills in the PDFs */
  --shadow-card: 0 20px 45px rgba(14, 21, 32, 0.35);
  --shadow-card-light: 0 14px 40px rgba(26, 35, 51, 0.1);
  --font-display: 'Sora', system-ui, -apple-system, sans-serif;
  --font-body: 'Public Sans', system-ui, -apple-system, sans-serif;
  /* The brand's third face. Guidelines reserve it for eyebrows, standards and
     device IDs — technical values, not prose. */
  --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
  /* The order page's bar height: 10px of padding either side of a 44px touch
     target. Anchor jumps reserve it, so it has to track the real bar. */
  --header-h: 64px;
  /* The page gutter. The carousels bleed out of .container to the viewport
     edge with a negative margin, and that only cancels the container's
     padding if the two are the same number — one token so they cannot drift. */
  --gutter: 24px;
}

/* ---------- Reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; font-family: var(--font-body); }
/* Form controls take the UA font rather than inheriting, so the dialog close
   buttons and checkboxes were rendering in Arial. Covers every control at once
   rather than per-component. */
button, input, select, textarea, optgroup { font-family: inherit; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink);
  background: var(--navy-900);
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; display: block; }
h1, h2, h3 { font-family: var(--font-display); line-height: 1.15; margin: 0 0 0.66em; letter-spacing: -0.02em; }
/* Matches the order page's headline exactly, so the two sites open at the
   same scale. Line-height and tracking are set here rather than inherited
   from the rule above, which is tuned for the smaller h2 and h3. */
h1 { font-size: clamp(31px, 9.9vw, 77px); font-weight: 700; line-height: 1.04; letter-spacing: -0.036em; }
/* The headline's second sentence, a weight lighter than the first. Sora is a
   variable face here — the 400-800 axis is in the one file, so this costs no
   extra download. The tracking opens back up a little with it: -0.036em is
   tuned to stop 700 at this size from closing on itself, and at 400 the same
   value pulls the letters into each other instead. */
/* A point smaller than the line above it as well as lighter. calc on 1em, not
   a second clamp: `em` in a font-size resolves against the parent, so this is
   exactly 1pt down from whatever the h1's clamp has landed on at that
   viewport — 1.33px at every width rather than a fixed drop that would read
   as a lot at 31px and as nothing at 77px. */
.h1-soft { font-weight: 400; letter-spacing: -0.026em; font-size: calc(1em - 1pt); }
/* Between these widths the hero is still two columns, so the headline gets
   about 510px while the viewport is wide enough to pin the size at its 77px
   cap — which ran the headline to six lines. Below 1021px the hero stacks
   and the column is back to 640px, so the rule above is right again. */
@media (min-width: 1021px) and (max-width: 1239px) {
  h1 { font-size: clamp(31px, 6vw, 77px); }
}
h2 { font-size: clamp(1.7rem, 3.2vw, 2.5rem); font-weight: 700; }
h3 { font-size: 1.18rem; font-weight: 700; }
p { margin: 0 0 1em; }
a { color: inherit; }
ul, ol, dl, figure { margin: 0; padding: 0; }
li { list-style: none; }

/* The order page's track: a 1120px box with a fixed 24px gutter, giving a
   1072px column. This page used min(1180px, 92vw), so its content sat wider
   and its gutter grew with the viewport — the two pages lined up at no width.
   A fixed gutter also holds the column still on a phone instead of letting it
   creep in as the screen narrows. */
.container { width: min(1120px, 100%); margin-inline: auto; padding-inline: var(--gutter); }
.container-narrow { width: min(820px, 100%); }

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--accent); color: var(--navy-950); padding: 10px 18px;
  border-radius: 0 0 10px 0; font-weight: 600; text-decoration: none;
}
.skip-link:focus { left: 0; }

.accent { color: var(--accent); }
.deadline .accent { color: var(--amber); }

/* ---------- Scroll progress ---------- */
.scroll-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0;
  background: linear-gradient(90deg, var(--accent-dark), var(--accent-light));
  z-index: 120;
}

/* ---------- Buttons & links ---------- */
.btn {
  display: inline-block;
  background: var(--accent);
  /* cf-navy, the same ink the order page's button carries, so the two CTAs
     are the same button and not two near-blacks on the same green. */
  color: var(--navy-900);
  /* Weight, size, leading, padding and border all taken from the order page's
     button, so the CTA a visitor clicks here is the same object as the one
     waiting for them there. Line-height is stated because this page's body
     runs at 1.65, which alone made the button 7px taller. */
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 16px;
  line-height: 1.2;
  padding: 14px 30px;
  border: 1px solid var(--accent);
  border-radius: var(--radius-pill);
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease;
}
.btn:hover { transform: translateY(-2px); background: #8fd150; border-color: #8fd150; }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline: 3px solid var(--accent-tint); outline-offset: 2px; }
/* Guide downloads: a document icon in the button's own ink, in front of the label. */
a.guide-dl { display: inline-flex; align-items: center; justify-content: center; gap: 8px; }
.plan a.guide-dl { display: flex; }
.guide-dl svg {
  width: 1.125em; height: 1.125em; flex: none;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.guide-dl span { min-width: 0; }
/* The second action in a CTA pair is a text link, not a second button — one
   button carries the click, and a bordered twin next to it splits the eye. No
   fill, no rule, no button padding; the underline is what says "link". */
.link-cta {
  display: inline-block;
  color: #fff;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1rem;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
  cursor: pointer;
  transition: color 0.2s ease;
}
.link-cta:hover { color: var(--accent); }
.link-cta:focus-visible { outline: 3px solid var(--accent-tint); outline-offset: 3px; border-radius: 3px; }
/* A follow-on link set on its own line under a section intro. Green as text,
   so --accent-ink on light (4.58:1) and --accent on dark. */
/* Two sentences, one per line, each balanced on its own so a phone's extra
   wraps stay even instead of stranding a last word. */
.included-sub > span, .sub-lines > span { display: block; text-wrap: balance; }
/* An inline link to the trial terms: underlined in the sentence's own colour,
   so it reads as small print rather than a second call to action. */
.terms-link { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.terms-link:hover { color: #fff; }
.sub-more { display: inline-block; margin-top: 10px; color: var(--accent-ink); font-weight: 600; text-underline-offset: 3px; }
.sub-more:hover { text-decoration-thickness: 2px; }
.section-dark .sub-more { color: var(--accent); }
/* No larger variant: one button size across both sites, so a CTA does not
   change shape between the page that promises the trial and the page that
   takes the order. */
.btn-block { display: block; width: 100%; text-align: center; }

.link-ghost {
  color: var(--slate-light);
  font-weight: 600;
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.link-ghost:hover { color: #fff; border-color: var(--accent); }

/* Mono capitals, the brand guidelines' use for the third face and the same
   treatment as the partners site's hero eyebrow: it reads as a label above
   the heading rather than a second heading, and speaks the dashboard's
   readout language. JetBrains Mono is self-hosted at 400-500 only, so the
   size carries it rather than weight. line-height and letter-spacing are
   stated, not inherited, so it matches the partners site to the pixel. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: 1.6rem;
}
/* accent-ink, not accent-dark: at this size the kicker is text, so it needs
   4.5:1 on white — accent-dark only manages 3.2:1. */
.eyebrow-accent { color: var(--accent-ink); }
.section-dark .eyebrow-accent, .deadline .eyebrow-accent { color: var(--accent); }

/* ---------- Header ----------
   The trial order page's bar, carried over so the two sites read as one. It is
   sticky rather than fixed, and solid from the first pixel rather than fading
   in on scroll: the bar is part of the page there, and a header that changes
   its mind at 24px is the sort of difference that gives the hand-off away. */
.site-header {
  position: sticky; top: 0; z-index: 100;
  /* Solid, not 95%: at 0.95 the bar took a tint from whatever was behind it,
     so it read #0e1520 over the landing's navy and #1a212b over the order
     page's white. The same bar on all three sites, so the same colour. The
     blur stays: on the order page it is what makes the bar the containing
     block for the menu sheet. */
  background: #0e1520;
  backdrop-filter: blur(10px);
  border-bottom: 1px solid #263248;
}
/* Back on .container now that it is the order page's track — one definition
   of the column, so the bar and the page below it cannot drift apart. */
.header-inner {
  padding-block: 10px;
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
}
.brand { display: flex; align-items: center; text-decoration: none; }
/* flex:none so the lockup can never be squeezed below its minimum legible
   width — below 390px the markup swaps it for the mark instead. */
.site-header .brand, .site-header .brand picture { display: flex; flex: none; }
.site-header .brand img { height: 33px; width: auto; flex: none; }
.header-right { display: flex; align-items: center; gap: 6px; }

.site-header .tel {
  display: inline-flex; align-items: center; gap: 9px; flex: none; white-space: nowrap;
  font-family: var(--font-mono); font-size: 15px; line-height: 1.55; letter-spacing: -0.005em;
  color: #fff; text-decoration: none;
  /* Line-height and tracking are stated rather than inherited: this page's body
     sets neither the way the order page's does, and inheriting left the bar a
     pixel taller and the number a pixel wider than the one it is matching. */
  padding: 10px 2px; min-height: 44px; transition: color 0.15s ease;
}
.site-header .tel:hover, .site-header .tel:active { color: var(--accent); }
.tel-ico { flex: none; width: 16px; height: 16px; fill: var(--accent); }
/* The lockup is the ControlFreq mark with a LIFTPULSE wordmark drawn to the same
   letterform metrics, so the two brands read as one family. Both halves are <use>
   references to a single copy of the artwork at the top of the document. */
.brand-logo { height: 40px; width: auto; display: block; }
/* The mark is stroked, not filled, and carries its own brand green from the
   <defs> group — the guidelines forbid recolouring it. Only the wordmark
   changes: white on dark, soft black on light. */
.brand-word { fill: #fff; }

/* An anchor jump lands the section's top edge under the sticky header. The
   sections carry enough padding that the heading still clears it on desktop,
   but only by 6px at mobile padding — so every jump target reserves the header
   height plus a little air. */
section[id] { scroll-margin-top: calc(var(--header-h) + 12px); }

/* ---------- Navigation ----------
   One disclosure at every width now, the way the order page does it, rather
   than a bar that collapses into a panel at 960px. The button is the trigger
   for the nav it discloses, so it precedes the nav in the DOM and tab order.
   Three bars that become a cross when the panel is open, so the control says
   what it will do next. 44px square for touch. */
.nav-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none;
  padding: 0; background: none; border: 0; cursor: pointer; color: #fff; line-height: 0;
  transition: color 0.15s ease;
}
.nav-toggle:hover { color: var(--accent); }
.nav-toggle:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
.nav-bars { position: relative; display: block; width: 22px; height: 16px; }
.nav-bars i {
  position: absolute; left: 0; width: 100%; height: 2px; border-radius: 2px; background: currentColor;
  transition: transform 0.22s ease, opacity 0.15s ease;
}
.nav-bars i:nth-child(1) { top: 0; }
.nav-bars i:nth-child(2) { top: 7px; }
.nav-bars i:nth-child(3) { top: 14px; }
.nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-bars i:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
/* Open, the cross is drawn larger than the burger it replaces: on a phone
   the menu fills the screen, and the way out has to be as obvious as the
   way in. Scaled rather than re-drawn, so the bars still morph. */
.nav-bars { transition: transform 0.22s ease; }
.nav-toggle[aria-expanded="true"] { width: 52px; height: 52px; margin: -4px; }
.nav-toggle[aria-expanded="true"] .nav-bars { transform: scale(1.45); }

/* A vertical card hanging off the burger, so it travels with the sticky bar.
   The right offset puts its edge on the header track's own gutter at every
   width, which lines it up under the burger. Solid rather than tinted: over
   the hero's photograph a translucent panel left the headline legible through
   the menu. */
.site-nav {
  position: absolute; top: calc(100% + 8px);
  right: max(24px, calc(50% - 536px));
  width: min(288px, calc(100% - 48px));
  background: var(--paper-dim); border: 1px solid var(--line-light); border-radius: 12px;
  box-shadow: 0 18px 40px rgba(14, 21, 32, 0.45);
}
.site-nav-in { display: flex; flex-direction: column; padding: 8px; }
.site-nav a {
  display: flex; align-items: center; min-height: 48px; padding: 8px 12px; border-radius: 8px;
  color: var(--ink); text-decoration: none;
  font-family: var(--font-display); font-weight: 600; font-size: 16px;
  transition: background 0.15s ease;
}
/* The hover tint carries the brand, not the text colour: green-dark on any
   light ground is 3.2:1, short of the 4.5:1 this 16px text needs. */
.site-nav a:hover { background: var(--accent-tint); }

/* The trial hand-off, in the panel and below the destinations rather than
   among them: it leaves the page, and the four above it do not. */
.site-nav-cta {
  margin-top: 6px; padding-top: 14px !important;
  border-top: 1px solid var(--line-light);
  color: var(--accent-ink) !important;
}

/* The header button. Out of the bar below the desktop breakpoint, where the
   lockup, the number and the burger already fill the row — the panel carries
   the same destination there, and the hero's own CTA is a scroll away. */
.header-cta { display: none; margin-left: 14px; padding: 10px 20px; font-size: 15px; flex: none; }

/* ---------- The bar above 1120px ----------
   The menu is the footer's full list now — eight destinations — and a row of
   eight does not fit beside the lockup, the number and the button on a 1072px
   track (a row of four only just did). So the burger stays at every width and
   the list opens as the card below it; up here the header button is in the
   bar, so the panel's own trial link, its duplicate, drops out. With no
   script the burger does nothing, as on a phone, and the footer carries the
   same list. */
@media (min-width: 1120px) {
  .header-cta { display: inline-block; }
  .site-nav-cta { display: none !important; }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  min-height: max(640px, 92vh);
  display: flex;
  align-items: center;
  overflow: hidden;
  /* The header is in flow now rather than fixed over the hero, so the hero no
     longer reserves its height — that space is the bar itself. */
  padding: 60px 0 84px;
  color: #fff;
}
.hero-bg, .hero-bg img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 70% 40%;
}
.hero-overlay {
  position: absolute; inset: 0;
  /* The 0.82 stop holds to 52% rather than 42%: the headline's accent phrase
     now ends around the halfway mark, where a highlight in the photograph took
     the green down to 3.55:1. Holding the scrim that far right puts it back to
     5.09:1 and leaves the 75% and 100% stops — where the photo is meant to show
     through behind the card — untouched. */
  background:
    linear-gradient(90deg, rgba(14, 21, 32, 0.96) 0%, rgba(14, 21, 32, 0.82) 52%, rgba(14, 21, 32, 0.35) 75%, rgba(14, 21, 32, 0.55) 100%),
    linear-gradient(0deg, rgba(14, 21, 32, 0.9) 0%, rgba(14, 21, 32, 0) 30%);
}
/* One column since the status card left for its own section: the headline and
   its button are all the hero carries now. */
.hero-inner {
  position: relative; z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
}
.hero-copy { max-width: 640px; }
/* The headline is two sentences, one per line. Each needs about 13.7px of
   width per px of font-size, and the hero's left grid cell stops growing at
   640px, so the h1 clamp tops out at 2.85rem rather than 3.2rem — at 3.2rem the
   second sentence overflows by 60px and strands "down." on a line of its own.
   Below ~530px neither sentence fits at the 2.2rem floor and it wraps to four
   lines; balance keeps those breaks even rather than orphaning a word. */
/* Hero rhythm: proximity carries the meaning. Headline and lede are one
   statement so they sit close; the ask gets the largest gap above it, which
   is what makes the button read as the next step rather than another
   paragraph; the fine print qualifies the button so it sits tight beneath. */
.hero-copy h1 { text-wrap: balance; margin-bottom: clamp(16px, 2.4vw, 22px); }
.hero-copy .lede { margin: 0 0 clamp(34px, 4.8vw, 46px); }
/* Keep the phrase whole so the headline breaks between beats rather than
   orphaning a word at the end of a line. It is .nb, not .accent: once the
   whole of "Compliance in under 1 hour." went green the accent class covered
   the entire sentence, and nowrap on that made one unbreakable 1022px line
   inside a 640px column — it spilled across the hero and put 6px of
   horizontal overflow on the page at 760. The no-break is a property of the
   phrase, not of its colour. */
.hero-copy h1 .nb { white-space: nowrap; }
/* A point down from 1.18rem. The order page's lede carries the identical
   declaration — same size, line-height, tracking, colour and measure — and
   neither repo has a token for it, so the two files keep it in step by hand.
   Change one and change the other. */
.lede { font-size: calc(1.18rem - 1pt); color: #cbd8ea; max-width: 56ch; }
/* The pair sits on one row with the link beside the button, not beneath it.
   flex-wrap is what makes that safe: between 1021 and about 1090px the hero's
   left grid cell is narrower than the two together, and there the link drops to
   its own line rather than crushing the button. */
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 20px 32px; margin: 0; }

/* The live status section.
   It is light, and that is the point: the header, the hero and the deadline
   strip are three dark bands in a row, each a different dark — navy-950 behind
   the bar, a near-black photograph in the hero, and a warm-edged one here —
   and a fourth flat navy-900 band under them read as banding rather than as
   four sections. Breaking to paper here ends the run, gives the deadline a
   defined bottom edge instead of a navy-on-navy seam, and lets the white card
   sit on a ground quiet enough to look placed rather than pasted.

   The layout is the page's own centred-head pattern rather than the deadline
   strip's two columns: three short lines of copy beside a five-row card left a
   void down the whole left half of the track. Centred, the card is the section
   and the copy introduces it. */
.status {
  position: relative;
  background: var(--paper-dim); color: var(--ink);
  /* --accent-ink is measured on white; the dim ground costs it about 0.4 of a
     point. Same step-down .section-dim makes, for the same reason. */
  --accent-ink: #46761c;
  border-bottom: 1px solid var(--line-light);
}
/* padding-block, never the `padding` shorthand: these carry .container, whose
   padding-inline is the page's 24px gutter, and `padding: 72px 0` silently
   reset it to zero. Below 1120px the container is full width, so both
   sections ran their text hard into the viewport edge on every phone. */
.status-inner { padding-block: 76px; text-align: center; }
.status-copy { max-width: 620px; margin: 0 auto 38px; }
.status h2 { font-size: clamp(1.5rem, 2.8vw, 2.1rem); }
.status p { color: var(--slate); margin-bottom: 0; }
.status .hero-card { margin-inline: auto; max-width: 440px; text-align: left; }
/* The trace is height-constrained: a 260×48 viewBox scaled to `meet` takes its
   width from its height, so widening the card only added gutters either side
   of it. Taller is what makes it wider. */
.status .heartbeat { height: 58px; }

/* The dashboard card.
   White, and the brightest thing in the section: the readout is the one thing
   here a visitor is meant to study rather than skim, and dark-on-white gives
   it far more separation than a tinted panel did. Every value in it is
   taken down to the darker greens, which the accent cannot reach on white —
   #7dc342 is 2.2:1 there, where accent-ink clears 4.5:1 as text and
   accent-dark clears the 3:1 a graphic needs.
   The shadow is the light-ground one. --shadow-card is a 0.35-alpha navy drop
   built to read against a dark section, and on #f4f5f7 it silts up under the
   card instead of lifting it. */
.hero-card {
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
  padding: 22px 24px;
  box-shadow: var(--shadow-card-light);
  max-width: 380px;
}
.hero-card-head {
  display: flex; align-items: center; gap: 9px;
  font-size: 0.84rem; font-weight: 600; color: var(--slate);
  margin-bottom: 14px;
}
.status-dot {
  width: 9px; height: 9px; border-radius: 50%; background: var(--accent-dark); flex: none;
}
.heartbeat { width: 100%; height: 48px; margin-bottom: 14px; }
/* The untraced part of the line is a guide, not a signal, so it drops to grey
   rather than a faded green — on white a 26% green read as a second, weaker
   trace instead of the track the live one runs along. */
.heartbeat-base { stroke: rgba(26, 35, 51, 0.14); }
.heartbeat-line {
  stroke: var(--accent-dark);
  stroke-dasharray: 640;
  stroke-dashoffset: 640;
  animation: heartbeat-draw 3.2s linear infinite;
}
.hero-card-rows div {
  display: flex; justify-content: space-between; gap: 16px;
  padding: 8px 0; border-top: 1px solid var(--line-light);
  font-size: 0.9rem;
}
.hero-card-rows dt { color: var(--slate); }
/* The card is a live status readout, which is the mono face's defined role.
   Labels stay in the body face so the row still reads label-then-value. */
.hero-card-rows dd { margin: 0; font-family: var(--font-mono); font-weight: 400;
                     font-size: 0.92em; letter-spacing: 0.01em; color: var(--ink); }
.hero-card-rows dd.ok { color: var(--accent-ink); }
.hero-card-rows dd { display: inline-flex; align-items: center; gap: 8px; }
.hero-card-rows .sig i { background: #c8d1dd; }
.hero-card-rows .sig.s4 i { background: var(--accent-dark); }
.tick { width: 15px; height: 15px; flex: none; fill: none; stroke: var(--accent-ink); stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }
.vh { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* ---------- Deadline / countdown strip ---------- */
/* Amber hairline on the top edge only. It is there to separate two dark bands —
   the hero above is a near-black photograph and without it the two ran
   together. Below is the light status section now, which separates itself, and
   a second amber rule there just drew a line under nothing. */
.deadline { position: relative; overflow: hidden; color: #fff; border-top: 1px solid rgba(245, 166, 35, 0.35); }
.deadline-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; }
.deadline-overlay {
  position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(14, 21, 32, 0.96) 0%, rgba(16, 20, 30, 0.88) 55%, rgba(38, 28, 8, 0.82) 100%);
}
.deadline-inner {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
  gap: 48px; align-items: center;
  padding-block: 72px;
}
.deadline h2 { font-size: clamp(1.5rem, 2.8vw, 2.1rem); }
.deadline p { color: #c4d1e4; max-width: 58ch; margin-bottom: 0; }
.deadline .eyebrow-accent { color: var(--amber); }
/* .deadline p zeroes every paragraph margin, the eyebrow included; mono caps
   need clear air between them and the heading to read as a label. */
.deadline .eyebrow { margin-bottom: 14px; }

/* Same mono capitals as the eyebrows, with one line of its own height clear
   beneath it before the timer. Scoped under .deadline because .deadline p
   outranks a bare class and was zeroing the margin and repainting the colour.
   Amber, like the eyebrow above it: the strip's two labels speak together. */
.deadline .countdown-label {
  font-family: var(--font-mono);
  font-size: 0.875rem; font-weight: 500; line-height: 1.4; letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--amber); margin-bottom: 1.4em;
}
.countdown-grid { display: flex; gap: 10px; margin-bottom: 18px; }
.count-cell {
  flex: 1; min-width: 0;
  /* Light tiles on the dark band, so the countdown is the brightest thing in
     it. Navy digits on paper; the amber edge ties them to the band's labels. */
  background: var(--paper-dim);
  border: 1px solid rgba(245, 166, 35, 0.7);
  border-radius: var(--radius-sm);
  padding: 14px 6px 10px;
  box-shadow: 0 10px 24px rgba(14, 21, 32, 0.35);
  text-align: center;
}
.count-num {
  display: block;
  font-family: var(--font-display);
  font-variant-numeric: tabular-nums;
  font-size: clamp(1.6rem, 3vw, 2.3rem);
  font-weight: 700; color: var(--navy-900); line-height: 1;
}
/* .link-ghost was this whole line, so colour alone was enough to mark it.
   Only the last clause is a link now, and colour alone inside a sentence is
   not an affordance — it takes a faded underline, the same treatment the
   order page's hero call uses, and both go green together on hover.
   The paragraph itself needs no rule: .deadline p already gives it the band's
   ink, its measure and a zeroed bottom margin. */
.countdown-cta .link-ghost { color: #fff; border-bottom-color: rgba(255, 255, 255, 0.4);
  /* Whole, or it breaks as "Start a / trial now →" at the two widest
     breakpoints — a call to action split across a line. It needs 160px and
     the narrowest this column gets is 272px, so it always has somewhere to
     go even when it has to start a line of its own. */
  white-space: nowrap; }
.countdown-cta .link-ghost:hover { color: var(--accent); border-bottom-color: var(--accent); }
.count-unit {
  display: block; margin-top: 6px;
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--slate);
}

/* ---------- Generic sections ---------- */
.section { padding: 106px 0; }
.section-light { background: var(--paper); color: var(--ink); }
/* --accent-ink was measured against white; the dim ground costs about 0.4 of a
   contrast point and drops it to 4.2:1 as text. Stepped down again here, to
   4.98:1 on #f4f5f7. Inside a dim section only the eyebrow and the outline
   button's label use it, so nothing else moves. */
.section-dim {
  background: var(--paper-dim); color: var(--ink);
  --accent-ink: #46761c;
}
.section-dark { background: var(--navy-900); color: #fff; }

.section-head { text-align: center; max-width: 760px; margin: 0 auto 64px; }
.section-head-wide { max-width: 840px; }
.section-head-left { text-align: left; margin: 0 0 40px; }
.section-sub { font-size: 1.1rem; color: var(--slate); }
.section-dark .section-sub { color: #b7c6db; }

/* ---------- Section 2: the pilot timeline ----------
   The heading promises "1 Month", so the steps carry when as well as what:
   Day 0, Days 1-30, Day 30. A rail connects the three moments — across the top
   on desktop, down the left once the columns collapse. No cards: boxed columns
   with numbered tiles is the shape every template ships with. */
.pilot-track {
  position: relative;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px;
  padding-top: 34px;
  margin-bottom: 64px;
}
.pilot-track::before {
  content: ""; position: absolute; left: 8px; right: 8px; top: 8px; height: 2px;
  background: linear-gradient(90deg, var(--accent) 0%, var(--accent-light) 62%, rgba(168, 217, 110, 0) 92%);
}
.track-step { position: relative; }
/* the moment marker, sitting on the rail */
.track-step::before {
  content: ""; position: absolute; top: -34px; left: 0;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--paper); border: 3px solid var(--accent);
}
/* the decision point reads as an arrival, not another waypoint */
/* solid rather than haloed: rings and glows were stripped from the site. */
.track-step.track-end::before { background: var(--accent); border-color: var(--accent-dark); }
.track-when {
  font-family: var(--font-display);
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--accent-ink);
  margin: 0 0 6px;
}
.track-step h3 { margin-bottom: 8px; }
.track-step p:last-child { margin-bottom: 0; color: var(--slate); }

.pilot-banner {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 0; align-items: stretch;
  background: var(--navy-800);
  border-radius: var(--radius);
  overflow: hidden;
  color: #fff;
  box-shadow: var(--shadow-card);
}
.pilot-banner-media { position: relative; min-height: 280px; }
/* Direct child only: the chip logos overlaid on this figure are images too, and
   the unscoped selector was pinning every one of them to inset:0. */
.pilot-banner-media > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.pilot-banner-copy { padding: 44px 46px; align-self: center; }
/* Two points up on the base h3. Stated in rem rather than em: this heading's
   parent is body-sized, so `1em` here would be 17px and the sum would land
   somewhere the base rule never was. 1.18rem is the base, and rem is the
   root, so the arithmetic is against the size this heading actually had. */
.pilot-banner-copy h3 { font-size: calc(1.18rem + 2pt); }
.pilot-banner-copy p { color: #c4d1e4; }

/* ---------- Section 3: why ---------- */
/* A step up from navy-900. The section sat between two light bands and read as
   a hole in the page; --navy-800 lifts the ground and the panels do the rest. */
.why-section { background: var(--navy-800); }
.why-hub-head { text-align: left; margin: 0 0 54px; }
.why-hub-head h2 { max-width: 20ch; }
.why-hub-head .section-sub { max-width: 58ch; margin-inline: 0; }

/* A desktop monitor, drawn as one rather than as a diagram of one: an
   aluminium rim round a black glass bezel, a faint reflection across the
   glass, and a brushed-aluminium stand — neck and foot plate — casting its
   own shadow. Wider than the centre column so the estate map reads; the
   spoke still drops from the foot to the ring. The card styling every other
   .hub-node carries is taken off it. */
.imac { position: relative; }
.imac-face {
  position: relative; z-index: 1; padding: 0.55%; border-radius: 13px;
  background: linear-gradient(160deg, #eceff2 0%, #b9c0c7 38%, #dde1e5 62%, #9aa2ab 100%);
  box-shadow: 0 26px 40px -12px rgba(0, 0, 0, 0.55), 0 2px 4px rgba(0, 0, 0, 0.3);
}
.imac-bezel { padding: 2.6%; border-radius: 11px; background: #0b0c0e;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06); }
.imac-screen { position: relative; border-radius: 2px; overflow: hidden; background: #0e1520; }
.imac-screen::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(118deg, rgba(255, 255, 255, 0.13) 0%, rgba(255, 255, 255, 0.04) 34%, rgba(255, 255, 255, 0) 34.2%);
}
.imac-ui { display: block; width: 100%; height: auto; }
.imac-stand { position: relative; display: block; width: 100%; height: 0; padding-bottom: 10.5%; }
.imac-neck {
  position: absolute; left: 50%; top: 0; width: 12%; height: 90%; transform: translateX(-50%);
  background: linear-gradient(90deg, #7f878f 0%, #c9ced3 18%, #eef0f2 46%, #cfd4d9 70%, #8b939b 100%);
  box-shadow: inset 0 14px 12px -8px rgba(0, 0, 0, 0.55);
}
.imac-foot {
  position: absolute; left: 50%; bottom: 0; width: 31%; height: 10%; min-height: 4px; transform: translateX(-50%);
  border-radius: 3px 3px 7px 7px;
  background: linear-gradient(180deg, #f1f3f5 0%, #c3c9cf 55%, #8d959d 100%);
  box-shadow: 0 10px 14px -4px rgba(0, 0, 0, 0.55);
}
/* Inside the screen: 640x360 units, so these sizes scale with the picture. */
.imac-ui text { font-family: var(--font-body); fill: #1a2333; letter-spacing: 0; word-spacing: 1.5px; }
.im-bar { fill: #1a2333; }
.imac-ui .im-brand { font-family: var(--font-display); font-weight: 700; font-size: 11px; fill: #fff; letter-spacing: .04em; }
.imac-ui .im-tab { font-size: 10.5px; fill: #8a9bb0; }
.imac-ui .im-tab.on { fill: #fff; font-weight: 600; }
.im-tab-line { fill: #7dc342; }
.imac-ui .im-bar-note { font-size: 10px; fill: #cbd8ea; }
.im-side { fill: #f4f5f7; }
.imac-ui .im-side-h { font-family: var(--font-display); font-weight: 700; font-size: 12px; }
.imac-ui .im-side-n { font-size: 10px; fill: #5e718a; }
.im-sel rect { fill: #fdecec; }
.imac-ui .im-name { font-size: 10px; font-weight: 600; }
.imac-ui .im-car { font-size: 9px; fill: #5e718a; }
.imac-ui .im-st-ok { font-size: 9px; font-weight: 700; fill: #4d8321; }
.imac-ui .im-st-crit { font-size: 9px; font-weight: 700; fill: #b01f1f; }
.im-dot-ok { fill: #5fa029; }
.im-dot-crit { fill: #e84040; }
.im-btn { fill: #7dc342; }
.imac-ui .im-btn-t { font-family: var(--font-display); font-weight: 600; font-size: 10.5px; }
/* Site map: a light street-level plan, parkland and water in pale tints,
   roads as blue-grey bands, building footprints a step darker than the
   ground. Pins green with a dark ring; the fault red with a halo. */
.im-ground { fill: #f3f4f6; }
.im-park { fill: #d5f3df; }
.im-water { fill: #9fd9ee; }
.im-brook { fill: none; stroke: #9fd9ee; stroke-width: 2; stroke-linecap: round; }
.im-road { fill: none; stroke: #bccada; stroke-width: 7; stroke-linecap: round; stroke-linejoin: round; }
.im-road-in { fill: none; stroke: #dbe3ec; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.imac-ui .im-road-t { font-size: 8px; fill: #7d8da2; letter-spacing: .02em; }
.im-bldg rect { fill: #e2e6eb; }
.im-spin { fill: #3fbf4a; stroke: #1d6b25; stroke-width: 1.4; }
.im-spin-red { fill: #e03131; stroke: #8f1d1d; stroke-width: 1.4; }
.im-halo { fill: rgba(224, 49, 49, 0.22); }
.im-card-bg { fill: #fff; filter: drop-shadow(0 6px 14px rgba(26, 35, 51, 0.2)); }
.imac-ui .im-card-h { font-size: 9.5px; font-weight: 600; fill: #1a2333; letter-spacing: .02em; }
.im-card-x { stroke: #5e718a; stroke-width: 1.4; stroke-linecap: round; }
.imac-ui .im-card-k { font-size: 9px; fill: #1a2333; }
.imac-ui .im-card-v { font-size: 9px; fill: #3d5270; }
.imac-ui .im-card-v.crit { fill: #b01f1f; font-weight: 700; }
.im-card-ok { fill: #3fbf4a; stroke: #1d6b25; stroke-width: 1; }
.im-card-bad { fill: #e03131; stroke: #8f1d1d; stroke-width: 1; }
.im-card-btn { fill: #7dc342; }
.imac-ui .im-card-btn-t { font-family: var(--font-display); font-size: 8.5px; font-weight: 600; fill: #1a2333; }

/* A node. The spoke is a pseudo-element on the inner edge rather than a line
   drawn between two measured boxes — no script, and it cannot fall out of
   register when the copy rewraps. */
/* Light panels on the dark ground rather than a tint of it: six bright cards
   are what stops the band reading as a hole, and it is the same panel language
   as the status cards elsewhere on the site. The panel is 9.97:1 against the
   section, so its edge needs no border to be found. */
.hub-node {
  position: relative;
  background: var(--paper-dim);
  border-radius: var(--radius-sm);
  padding: 18px 20px;
  box-shadow: 0 14px 40px rgba(14, 21, 32, 0.3);
}
.hub-node h3 {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  font-size: 1.02rem; margin: 0 0 5px; color: var(--navy-900);
}
.hub-node p { margin: 0; font-size: 0.92rem; line-height: 1.5; color: var(--slate); }
.hub-ico { width: 20px; height: 20px; flex: none; color: var(--accent-ink); }
.hub-node .head-tag { font-size: 0.62rem; }

/* The six benefits are <details>, so on a phone — where the hub has become a
   stack of eight cards — they can close down to their headings and the list
   reads at a glance. On the diagram they are always open and not a control:
   the spokes need every card at full height, and a card that collapsed on a
   click would pull its spoke off its row. main.js keeps them open above 1020px
   and closes them on first load below it; with no script they simply stay
   open, which is the page as it was. */
.hub-acc > summary { list-style: none; cursor: default; }
.hub-acc > summary::-webkit-details-marker { display: none; }
.hub-acc > summary h3 { margin: 0 0 5px; }

/* ---------- Why: the flow ---------- */
/* What goes where, left to right: the lift phone they already have, the
   LiftPulse unit it plugs into, then out over the mobile network to the two
   places an alarm is received: a live operator (the emergency call) and the
   cloud dashboard (the unit's status). Each stage is one card, picture over
   caption. A dashed line is the wireless leg, carrying the four networks; a
   solid fork is where it lands. Mobile first: stacked top to bottom in the
   same order, with the fork running down a gutter on the left. */
.flow { --gutter: 34px; --line: var(--accent); --stage-w: clamp(200px, 17vw, 208px); --stage-h: 316px; }
.flow-track { display: grid; grid-template-columns: minmax(0, 1fr); justify-items: center; box-sizing: border-box; padding-inline: var(--gutter); }
.flow-panel {
  position: relative; box-sizing: border-box; width: min(100%, 320px); padding: 18px;
  display: flex; flex-direction: column; align-items: center; text-align: center;
  border-radius: 18px; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1);
}
.flow-cap { margin: 14px 0 0; font-size: 0.9rem; line-height: 1.5; color: #cbd8ea; text-wrap: balance; }
.flow-cap b { display: block; color: #fff; font-family: var(--font-display); font-size: 1.02rem; }

.flow-phone-art { display: block; width: 100%; max-width: 116px; height: auto; filter: drop-shadow(0 14px 24px rgba(14, 21, 32, 0.45)); }
/* The unit is the subject: its card carries the brand green. The phone card
   is always exactly as wide and as tall as the unit's. */
.flow-phone, .flow-unit { width: min(100%, 272px); height: var(--stage-h); justify-content: center; }
.flow-unit { border-color: rgba(125, 195, 66, 0.5); background: rgba(125, 195, 66, 0.07); }
/* The plain enclosure in a circle, with a small LiftPulse pill across its
   front. The lockup at 29.3px tall is 120px wide, the brand minimum, so the
   pill cannot go smaller. */
.flow-disc { position: relative; width: 100%; max-width: 190px; aspect-ratio: 1; }
.flow-disc-img { width: 100%; height: 100%; border-radius: 50%; overflow: hidden; background: var(--paper); box-shadow: 0 18px 50px rgba(14, 21, 32, 0.55); }
.flow-disc-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hub-cap {
  position: absolute; top: 58%; left: 50%; transform: translate(-50%, -50%); z-index: 2;
  display: flex; align-items: center; justify-content: center;
  background: var(--navy-950); border: 1px solid rgba(138, 155, 176, 0.3);
  border-radius: var(--radius-pill); padding: 4px 9px; box-shadow: 0 6px 16px rgba(14, 21, 32, 0.35);
}
.hub-cap-logo { display: block; height: 29.3px; width: auto; }
.hub-cap-logo .brand-word { fill: #fff; }

/* The two places an alarm lands. The gutter on the left carries the fork. */
.flow-dest { box-sizing: border-box; width: min(100%, 420px); display: grid; gap: 16px; margin-top: 22px; }
.flow-dest .flow-panel { width: 100%; }
.flow-op { flex-direction: row; text-align: left; gap: 12px; padding: 14px 16px; }
.flow-op .flow-cap { margin: 0; text-align: left; }
.flow-op-art { display: block; flex: none; width: 88px; height: 88px; filter: drop-shadow(0 10px 18px rgba(14, 21, 32, 0.45)); }
.flow-dash .imac { width: 100%; }

/* Links. Mobile: down the page. */
.flow-link { position: relative; display: grid; place-items: center; width: min(100%, 420px); height: 76px; }
.flow-air { height: 150px; }
.flow-link::before { content: ""; position: absolute; left: 50%; top: 0; bottom: 9px; border-left: 2px solid var(--line); transform: translateX(-1px); }
.flow-link::after {
  content: ""; position: absolute; left: 50%; bottom: 0; margin-left: -6px;
  border-top: 10px solid var(--line); border-left: 6px solid transparent; border-right: 6px solid transparent;
}
/* The wireless leg is dashed, and turns into the gutter where the fork starts. */
.flow-air::before { bottom: 0; border-left-style: dashed; }
.flow-air::after { left: -17px; right: 50%; bottom: 0; top: auto; width: auto; height: 0; margin: 0; border: 0; border-top: 2px dashed var(--line); }
.flow-socket, .flow-nets { position: relative; z-index: 1; }
.flow-socket {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  background: var(--navy-950); border: 1px solid rgba(125, 195, 66, 0.6); box-shadow: 0 6px 16px rgba(14, 21, 32, 0.45);
}
.flow-socket svg { width: 22px; height: 22px; fill: none; stroke: var(--accent); stroke-width: 1.7; stroke-linejoin: round; }
/* The four networks, sitting quietly on the wireless line: no pill, just the
   marks, small, greyscale and pale, by CSS filter only (the stored artwork is
   the operators' own, unaltered). A flat white knockout loses Vodafone's
   speechmark, and plain greyscale loses O2 and Three into the navy, so each
   mark gets the filter that suits how it is drawn. A patch of the section's own
   ground behind them breaks the dashed line where they sit. A row across the
   line on a phone; a column on the line on desktop. */
.flow-nets.network-chips--row {
  display: flex; align-items: center; justify-content: center; gap: 30px;
  margin: 0; padding: 8px 14px; list-style: none; background: var(--navy-800);
}
.flow-nets.network-chips--row li, .flow-nets.network-chips--row li:has(img) { background: none; border: 0; padding: 0; box-shadow: none; }
.flow-nets.network-chips--row img { height: 32px; width: auto; filter: grayscale(1) contrast(0.9) brightness(1.9); opacity: 0.55; }
.flow-nets.network-chips--row img[src$="ee.svg"] { height: 38px; width: 21.6px; }
.flow-nets.network-chips--row img[src$="o2.svg"] { height: 28px; width: 27.4px; }
.flow-nets.network-chips--row img[src$="three.svg"] { height: 36px; width: 28px; }
/* Safari sizes an SVG with no width/height of its own (O2, Vodafone, Three)
   as a 2:1 box, leaving each mark adrift in blank space. Every mark gets an
   explicit width from its viewBox, so the gaps are only the gap. */
.flow-nets.network-chips--row img[src$="vodafone.svg"] { width: 32px; }
.flow-nets.network-chips--row img { max-width: none; object-fit: contain; }
/* O2 and Three are dark line marks: invert them to the same soft light grey
   the filled marks (EE, Vodafone) reach through greyscale. */
.flow-nets.network-chips--row img[src$="o2.svg"],
.flow-nets.network-chips--row img[src$="three.svg"] { filter: grayscale(1) brightness(0) invert(0.82); }

/* The fork: a dashed bus down the gutter and a dashed stub with an arrowhead
   into each destination, carrying on the wireless leg's dash. The bus is drawn a card at a time, so it follows however tall
   the cards turn out. */
.flow-dest .flow-panel::before { content: ""; position: absolute; left: -16px; border-left: 2px dashed var(--line); transform: translateX(-1px); }
.flow-op::before { top: -22px; bottom: -16px; }
.flow-dash::before { top: -16px; height: calc(50% + 16px); }
.flow-branch { position: absolute; left: -16px; top: 50%; width: 16px; height: 0; border-top: 2px dashed var(--line); transform: translateY(-1px); }
.flow-branch::after {
  content: ""; position: absolute; right: -10px; top: -7px;
  border-left: 10px solid var(--line); border-top: 6px solid transparent; border-bottom: 6px solid transparent;
}

/* The benefits sit under the picture, in their own grid. */
.flow-benefits { margin-top: 56px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }

@media (min-width: 1021px) {
  .flow-track {
    grid-template-columns: var(--stage-w) 1fr var(--stage-w) 2.2fr clamp(270px, 27.5vw, 332px);
    align-items: center; justify-items: stretch; padding-inline: 0;
  }
  .flow-panel { width: 100%; }
  .flow-unit { width: 100%; }
  .flow { --stage-h: 332px; }
  .flow-link, .flow-air { width: 100%; height: auto; align-self: stretch; }
  .flow-wired { align-self: center; height: 40px; }
  .flow-dest { width: 100%; padding-left: var(--gutter); margin-top: 0; }
  .flow-link::before { left: 0; right: 9px; top: 50%; bottom: auto; border-left: 0; border-top: 2px solid var(--line); transform: translateY(-1px); }
  .flow-link::after { left: auto; right: 0; bottom: auto; top: 50%; margin: -6px 0 0; border-top: 6px solid transparent; border-bottom: 6px solid transparent; border-left: 10px solid var(--line); border-right: 0; }
  /* The wireless leg runs straight into the bus; no arrowhead, the stubs carry them. */
  .flow-air::before { left: 0; right: calc(0px - var(--gutter) + 16px); bottom: auto; border-left: 0; border-top: 2px dashed var(--line); }
  .flow-air::after { display: none; }
  .flow-nets.network-chips--row { flex-direction: column; gap: 16px; padding: 14px 10px; }
  .flow-op::before { top: 50%; bottom: -16px; }
}

/* Inline qualifier tag on a feature heading */
.head-tag {
  display: inline-block; vertical-align: middle; margin-left: 8px;
  font-family: var(--font-body); font-size: 0.66rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--accent); background: var(--accent-soft);
  padding: 3px 8px; border-radius: 6px;
  white-space: nowrap;
}

/* ---------- Section 4: ecosystem ---------- */
.eco-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 26px;
  /* Tallest panel content at this width, rounded up: the status rows need
     about 267px at the narrowest this row gets before it drops to two. */
  --eco-panel-h: 275px; }
/* The status chart is an SVG with its own aspect ratio, so left alone it
   grows with the card's width. Cap it to the panel and let it letterbox. */
.dash-mock > svg { max-height: 100%; width: 100%; height: auto; object-fit: contain; }
.eco-card {
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card-light);
  padding: 22px 22px 26px;
  display: flex; flex-direction: column; gap: 6px;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.eco-card:hover { transform: translateY(-6px); box-shadow: 0 22px 50px rgba(26, 35, 51, 0.14); }
/* Same container chrome as the two coded panels beside it */
/* Every card's top panel is one height, so the headings and the body copy
   below them start on the same line across the row. The three panels size
   themselves differently — a 4:3 photograph, a fixed stack of status rows,
   and an SVG that scales with its width — so none of them can derive a
   shared height on its own; it is set here and they fit inside it. */
.eco-card figure {
  background: #f4f6f8;
  border: 1px solid var(--line-light);
  border-radius: var(--radius-sm);
  padding: 16px;
  margin-bottom: 16px;
  height: var(--eco-panel-h);
  flex: none; min-width: 0;
}
.eco-card figure img {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: 10px; border: 1px solid var(--line-light);
}
.eco-card p { color: var(--slate); margin-bottom: 0; font-size: 0.97rem; }
.eco-card h3 { margin-bottom: 6px; }

.network-chips { display: flex; gap: 8px; margin-top: 14px; flex-wrap: wrap; }
.network-chips li {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.04em;
  color: var(--navy-700);
  background: var(--paper-dim);
  border: 1px solid var(--line-light);
  padding: 5px 12px; border-radius: 8px;
}
/* Logos are shown as supplied — no greyscale or recolouring, since most
   operator brand guidelines prohibit altering the mark. */
.network-chips img { display: block; height: 20px; width: auto; max-width: 88px; object-fit: contain; }
.network-chips li:has(img) { padding: 6px 12px; background: #fff; }
/* The brand name stays in the DOM as the accessible label (the img is alt="")
   and as the visible fallback if a logo file is missing — see main.js. */
.network-chips li:has(img) span {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* Two placements of the chips as a set rather than an inline row. Both ask for
   the marks in black and white, so the greyscale the base component refuses is
   applied here by filter only — no altered artwork is stored, and removing this
   one rule restores the operators' own colours. */
.network-chips--square,
.network-chips--row { display: grid; gap: 8px; }
/* All four supplied marks are symbols rather than wordmarks, with aspect ratios
   from 0.57 (EE) to 1.0 (Vodafone), so they are sized by height to read at a
   consistent optical weight rather than by the width a wordmark would need. */
.network-chips--square img,
.network-chips--row img { filter: grayscale(1) contrast(1.1); opacity: 0.82; }
.network-chips--square img { height: 36px; max-width: 96px; }
.network-chips--row img { height: 22px; max-width: 80px; }
/* Equal height is not equal weight across marks this different in shape, so each
   is nudged to sit at a comparable optical size beside the others. */
.network-chips--square img[src$="ee.svg"] { height: 42px; }
.network-chips--square img[src$="o2.svg"] { height: 32px; }
.network-chips--square img[src$="three.svg"] { height: 40px; }
.network-chips--row img[src$="ee.svg"] { height: 26px; }
.network-chips--row img[src$="o2.svg"] { height: 20px; }
.network-chips--row img[src$="three.svg"] { height: 25px; }
.network-chips--square li,
.network-chips--row li { margin: 0; }

/* One row of four under the section sub-heading. */
.network-chips--square {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  max-width: 536px; margin: 30px auto 0; padding: 0; list-style: none;
}
.network-chips--square li { padding: 14px 12px; }

/* one row, in the empty strip at the foot of the trial-kit shot */
.chip-strip {
  position: absolute; left: 5%; right: 5%; bottom: 5%;
  background: rgba(255, 255, 255, 0.82);
  backdrop-filter: blur(3px);
  border: 1px solid rgba(26, 35, 51, 0.07);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
}
.network-chips--row {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0; padding: 0; list-style: none;
}
.network-chips--row li { border: none; background: transparent; padding: 4px 2px; }
.network-chips--row li:has(img) { background: transparent; }

@media (max-width: 760px) {
  .chip-strip { left: 4%; right: 4%; bottom: 4%; padding: 7px 8px; }
  .network-chips--row li { font-size: 0.68rem; padding: 3px 1px; }
  .network-chips--row img { height: 17px; }
}

/* Coded dashboard mock (crisp text beats an AI render here) — light theme,
   the same product-UI language as the laptop screen in the pilot-kit photo */
.dash-mock {
  background: #f4f6f8;
  border-radius: var(--radius-sm);
  padding: 16px;
  margin-bottom: 16px;
  height: var(--eco-panel-h);
  display: flex; flex-direction: column; justify-content: center; gap: 9px;
  border: 1px solid var(--line-light);
  flex: none; min-width: 0; overflow: hidden;
}
.dash-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 4px; }
.dash-title { color: var(--navy-900); font-family: var(--font-display); font-weight: 700; font-size: 0.86rem; }
.dash-export {
  font-size: 0.72rem; font-weight: 700; color: var(--navy-950);
  background: var(--accent); border-radius: 7px; padding: 5px 10px;
}
.dash-row {
  display: flex; align-items: center; gap: 9px;
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 0.78rem; color: var(--navy-800);
}
.dash-row span:nth-child(2) { flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dash-row.on { border-color: #c4dd9f; }
.dash-val { font-family: var(--font-display); font-weight: 700; color: var(--navy-900); }
.dash-val.ok { color: var(--accent-ink); }
.dash-val.warn { color: var(--amber-ink); }

/* Roaming panel — same visual language as the estate mock beside it. */
.dash-tag {
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--slate);
}
.dash-val.dim { color: var(--slate); }
.sig { display: inline-flex; align-items: flex-end; gap: 2px; width: 18px; height: 14px; flex: none; }
.sig i { width: 3px; border-radius: 1px; background: #dde3e9; }
.sig i:nth-child(1) { height: 5px; }
.sig i:nth-child(2) { height: 8px; }
.sig i:nth-child(3) { height: 11px; }
.sig i:nth-child(4) { height: 14px; }
.sig.s4 i { background: var(--accent-dark); }
.sig.s3 i:nth-child(-n+3) { background: var(--slate); }
.sig.s2 i:nth-child(-n+2) { background: var(--slate); }

/* Estate map — the cloud platform card shows the fleet in the field */
.dash-brand { height: 15px; width: auto; flex: none; display: block; }
.estate-map {
  width: 100%; min-width: 0; display: block;
  aspect-ratio: 356 / 216;
  border-radius: 10px; border: 1px solid var(--line-light);
  background: #eef1f4;
}
.em-title { font-family: var(--font-display); font-weight: 700; font-size: 11.5px; fill: var(--navy-900); }
.em-row { font-family: var(--font-body); font-size: 10px; fill: var(--slate); }
.em-warn { font-family: var(--font-body); font-weight: 700; font-size: 10px; fill: #9a6a10; }

/* ---------- OEM / white label ---------- */
/* Lift-lobby photograph under a 50% wash of the section's own navy */
.section-oem {
  background:
    linear-gradient(90deg, rgba(26, 35, 51, 0.93) 0%, rgba(26, 35, 51, 0.86) 38%, rgba(26, 35, 51, 0.58) 66%, rgba(26, 35, 51, 0.5) 100%),
    url("../img/oem-van.webp") center / cover no-repeat var(--navy-900);
}
.oem-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr); gap: 56px; align-items: end; }
.oem-cta { display: inline-block; margin-top: 26px; text-decoration: none; }
.section-dark .btn-outline { color: var(--accent); border-color: var(--accent); }
.oem-media { margin: 0; }

/* The white-label portal mock: a browser window around the branded app */
.oem-ui {
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: 0 24px 60px rgba(10, 18, 30, 0.45);
}
.oem-chrome {
  display: flex; align-items: center;
  background: #e9edf1; border-bottom: 1px solid var(--line-light);
  padding: 8px 14px;
}
.oem-dots { display: inline-flex; gap: 5px; flex: 1; }
.oem-dots i { width: 9px; height: 9px; border-radius: 50%; background: #c7d0d9; }
.oem-chrome-pad { flex: 1; }
.oem-url {
  background: var(--paper); border-radius: 6px;
  font-size: 0.7rem; color: var(--slate); padding: 3px 14px;
  white-space: nowrap;
}
.oem-url b { color: var(--navy-800); }
.oem-appbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 16px;
}
.oem-user { display: inline-flex; align-items: center; gap: 8px; font-size: 0.72rem; color: var(--slate); }
.oem-user i { width: 18px; height: 18px; border-radius: 50%; background: #d7dee5; }
.oem-tabs { display: flex; gap: 16px; padding: 0 16px; border-bottom: 1px solid var(--line-light); overflow: hidden; }
.oem-tabs span {
  font-size: 0.66rem; font-weight: 600; color: var(--slate);
  padding: 8px 0 9px; border-bottom: 2.5px solid transparent; white-space: nowrap; flex: none;
}
.oem-tabs span.on { color: var(--navy-900); border-bottom-color: var(--accent); }
.oem-filters { display: flex; gap: 10px; padding: 12px 16px; }
.oem-select {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--line-light); border-radius: 7px;
  background: var(--paper);
  font-size: 0.72rem; font-weight: 600; color: var(--navy-800);
  padding: 6px 11px; white-space: nowrap;
}
.oem-select em { font-style: normal; font-weight: 700; font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--slate); }
.oem-select.dim { color: var(--slate); font-weight: 500; }
.oem-select svg { color: var(--slate-light); flex: none; }
.oem-map { display: block; width: 100%; }
.logo-slot {
  display: inline-flex; align-items: center;
  border: 1.5px dashed #a9b7c6; border-radius: 7px;
  padding: 5px 12px;
  font-size: 0.64rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--slate);
}
.oem-note { margin: 14px 0 0; font-size: 0.85rem; color: var(--slate-light); text-align: center; }

/* ---------- Section 5: pricing ---------- */
.estate-banner { position: relative; border-radius: var(--radius); overflow: hidden; margin-bottom: 40px; box-shadow: var(--shadow-card-light); }
.estate-banner img { display: block; width: 100%; height: 280px; object-fit: cover; }
.estate-banner figcaption {
  position: absolute; left: 20px; bottom: 16px;
  background: rgba(14, 21, 32, 0.78); color: #fff;
  font-size: 0.85rem; font-weight: 600;
  padding: 8px 16px; border-radius: 8px;
  backdrop-filter: blur(6px);
}

.table-wrap {
  overflow-x: auto;
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius);
  box-shadow: var(--shadow-card-light);
  margin-bottom: 30px;
  -webkit-overflow-scrolling: touch;
}
.price-table { width: 100%; min-width: 760px; border-collapse: collapse; font-size: 0.95rem; }
.price-table thead th {
  font-family: var(--font-display);
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: #fff; background: var(--navy-800);
  padding: 16px 20px; text-align: left; white-space: nowrap;
}
.price-table thead th span { display: block; font-family: var(--font-body); font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--slate-light); font-size: 0.75rem; }
.price-table tbody th, .price-table tbody td { padding: 18px 20px; border-top: 1px solid var(--line-light); text-align: left; }
.price-table tbody th { font-family: var(--font-display); font-weight: 700; white-space: nowrap; }
.price-table tbody tr { transition: background 0.2s ease; }
.price-table tbody tr:hover { background: #f6faee; }
.price-table .free { color: var(--accent-dark); font-weight: 700; white-space: nowrap; }
.price-table .strong { font-weight: 700; white-space: nowrap; }

/* Each rate cell carries the monthly figure with its annual equivalent beneath,
   so the two purchase routes sit side by side without a seventh column. */
.price-table .rate { white-space: nowrap; }
.price-table .rate-mo { display: block; font-weight: 700; }
.price-table .rate-yr { display: block; font-size: 0.85em; color: var(--slate); margin-top: 3px; }
.price-table .rate-capex { background: var(--accent-soft); }
/* Green on the tinted column, not green on white: --accent-soft composites to
   #edf7e5, where --accent-dark measures 2.91:1 and --accent-ink 4.15:1 — both
   short of the 4.5:1 this bold 15px figure needs. --accent-deep is 4.68:1 there.
   The trial order page carries the same table and the same colour. */
.price-table .rate-capex .rate-mo { color: var(--accent-deep); }
.price-table .rate-na span { color: var(--slate-light); font-style: italic; font-size: 0.88em; }
.price-table thead th:last-child { background: var(--navy-700); }
.tier-tag {
  display: inline-block; margin-left: 8px; vertical-align: middle;
  font-family: var(--font-body); font-size: 0.68rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--accent-dark); background: var(--accent-tint);
  padding: 3px 8px; border-radius: 6px;
}

/* Footnote marker tying a tier band to the multi-building callout */
.tier-star {
  color: var(--accent-dark); font-weight: 700; text-decoration: none;
  margin-left: 2px; vertical-align: super; font-size: 0.72em;
}
.tier-star:hover { text-decoration: underline; }

.table-note { margin: -18px 0 22px; font-size: 0.84rem; color: var(--slate); text-align: center; }

/* Multi-building portfolio callout beneath the pricing table */
.multi-building {
  display: flex; gap: 13px; align-items: flex-start;
  background: var(--accent-tint);
  border: 1px solid rgba(95, 160, 41, 0.35);
  border-radius: var(--radius-sm);
  padding: 16px 20px;
  margin: 0 0 26px;
  font-size: 0.95rem; color: var(--ink);
  scroll-margin-top: calc(var(--header-h) + 20px);
}
.multi-building strong { color: var(--accent-deep); }
.mb-star { color: var(--accent-deep); font-size: 1.1rem; line-height: 1.4; flex: none; }

.install-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 26px; margin-bottom: 26px; }
.install-card {
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius-sm);
  padding: 24px 26px;
  box-shadow: var(--shadow-card-light);
}
.install-card h3 { font-size: 1.02rem; }
.install-card p { margin: 0; color: var(--slate); font-size: 0.96rem; }

/* Price-sheet takeaway: the table stays visible, the PDF is the thing people
   forward on, so the ask is deliberately lighter than the pilot form. */
.sheet-cta { display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap; margin: 22px 0 0; }
.sheet-cta-note { font-size: 0.84rem; color: var(--slate); text-align: center; }
.field .opt { font-weight: 400; color: var(--slate); }
.sheet-next { margin: 22px 0 10px; font-weight: 600; color: var(--ink); }
.sheet-alt { margin: 14px 0 0; text-align: center; font-size: 0.9rem; color: var(--slate); }
.sheet-alt a { color: var(--accent-ink); font-weight: 600; }
#sheet-sent-to { color: var(--ink); overflow-wrap: anywhere; }
/* On white the label is text, so it takes --accent-ink (4.58:1); the ring is the
   control's only boundary, so it takes --accent-dark (3.21:1). Plain --accent
   measured 3.21:1 as a label and 2.15:1 as a ring — both short. */
.btn-outline {
  display: inline-block;
  background: transparent; color: var(--accent-ink);
  border: 2px solid var(--accent-dark);
  font-family: var(--font-display); font-weight: 700; font-size: 0.95rem;
  padding: 11px 22px; border-radius: var(--radius-pill); cursor: pointer; text-decoration: none;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}
.btn-outline:hover { background: var(--accent); border-color: var(--accent); color: var(--navy-900); transform: translateY(-2px); }
.btn-outline:focus-visible { outline: 3px solid var(--accent-tint); outline-offset: 2px; }

.sheet-dialog {
  width: min(440px, calc(100vw - 32px)); padding: 30px 30px 26px;
  border: none; border-radius: var(--radius); background: var(--paper); color: var(--ink);
  box-shadow: 0 30px 80px rgba(12, 25, 38, 0.35);
}
.sheet-dialog::backdrop { background: rgba(12, 25, 38, 0.6); backdrop-filter: blur(3px); }
.sheet-dialog h3 { font-size: 1.35rem; margin: 0 0 6px; }
.sheet-lede { margin: 0 0 20px; color: var(--slate); font-size: 0.92rem; }
.sheet-dismiss { position: absolute; top: 12px; right: 12px; margin: 0; }
.sheet-dismiss button {
  background: none; border: none; cursor: pointer; line-height: 1;
  font-size: 1.5rem; color: var(--slate); padding: 4px 9px; border-radius: var(--radius-pill);
}
.sheet-dismiss button:hover { background: var(--line-light); color: var(--ink); }
.sheet-dialog .hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.sheet-dialog .field { margin-bottom: 14px; }
.guide-dialog {
  max-height: calc(100dvh - 32px);
  overflow: auto;
}
.guide-dialog .btn {
  background: #7DC342;
  border-color: #7DC342;
  color: #16260A;
}
.guide-dialog .btn:hover { background: #5FA029; border-color: #5FA029; color: #16260A; }
.guide-dialog .form-status.error a { color: inherit; text-decoration: underline; }
.guide-dialog textarea.invalid { border-color: var(--error); background: #fdf4f4; }
@media (max-width: 375px) {
  .guide-dialog { padding: 22px 16px 18px; }
}

/* ---------- Pricing: plan cards ----------
   One question, then the cards for that answer. Every figure is the table's,
   which sits unchanged in the compare disclosure below. No "Recommended":
   there is no order data behind one, so the Standard card's badge states the
   6-lift threshold instead. With no script both lanes stack under their own
   headings (.lane-title), which .js-plans hides once the switch is working. */
.sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
#pricing .section-head { margin-bottom: 36px; }

/* The lane switch ships hidden; main.js reveals it. */
.plan-lanes { border: 0; margin: 0 auto 10px; padding: 0; max-width: 440px; text-align: center; }
.plan-lanes legend {
  display: block; width: 100%; padding: 0; margin: 0 0 10px;
  font-family: var(--font-display); font-weight: 600; font-size: 0.95rem; line-height: 1.3;
  letter-spacing: 0; color: var(--navy-900);
}
.lane-switch {
  display: grid; grid-template-columns: 1fr 1fr; gap: 4px; padding: 4px;
  background: var(--paper); border: 1px solid var(--line-light); border-radius: var(--radius-pill);
  box-shadow: 0 2px 8px rgba(26, 35, 51, 0.06);
}
.lane-switch button {
  min-height: 44px; padding: 10px 14px; border: 0; border-radius: var(--radius-pill);
  background: transparent; color: var(--slate); cursor: pointer;
  font-family: var(--font-display); font-weight: 600; font-size: 15px; line-height: 1.2; letter-spacing: 0;
  transition: background 0.15s ease, color 0.15s ease;
}
.lane-switch button:hover { color: var(--navy-900); }
.lane-switch button[aria-pressed="true"] { background: var(--accent); color: var(--navy-900); }
.lane-switch button:focus-visible { outline: 3px solid var(--navy-900); outline-offset: 2px; }
.lane-hint { margin: 10px 0 0; font-size: 0.88rem; line-height: 1.45; color: var(--slate); }

/* Lanes */
.plan-lane { margin-top: 30px; }
.lane-title {
  font-size: 1.15rem; line-height: 1.3; letter-spacing: -0.01em; margin: 0 0 14px; color: var(--navy-900);
}
.js-plans .lane-title { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.small-route {
  display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; justify-content: center;
  margin: 0 auto 26px; padding: 10px 16px; max-width: 920px;
  background: var(--paper); border: 1px dashed #c6ced8; border-radius: var(--radius-sm);
  font-size: 0.9rem; line-height: 1.45; color: var(--ink); text-align: center;
}
.small-route a, .close-six a.route-link { color: var(--accent-ink); font-weight: 700; }

/* Plan cards */
.plan-grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 22px; grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: stretch; }
.plan {
  position: relative; display: flex; flex-direction: column; height: 100%;
  background: var(--paper); border: 1px solid var(--line-light); border-radius: var(--radius);
  padding: 30px 26px 26px; box-shadow: var(--shadow-card-light);
}
.plan--marked { border: 2px solid var(--accent); padding: 29px 25px 25px; }
.plan-badge {
  position: absolute; top: 0; left: 50%; transform: translate(-50%, -50%);
  white-space: nowrap; padding: 5px 12px; border-radius: var(--radius-pill);
  background: var(--accent); color: var(--navy-900);
  font-family: var(--font-display); font-weight: 700; font-size: 0.72rem; line-height: 1.2;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.plan-band {
  margin: 0 0 6px; font-family: var(--font-display); font-weight: 700; font-size: 0.74rem; line-height: 1.3;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--slate);
}
.plan h4 { font-family: var(--font-display); font-size: 1.35rem; line-height: 1.2; letter-spacing: -0.015em; margin: 0 0 6px; color: var(--navy-900); }
@media (min-width: 901px) { .plan-grid .plan-promise { min-height: 2.9em; } }
.plan-promise { margin: 0 0 20px; font-size: 0.95rem; line-height: 1.45; color: var(--slate); }
.plan-price { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 8px; margin: 0; }
.plan-fig {
  font-family: var(--font-display); font-weight: 700; font-size: clamp(2.3rem, 3.4vw, 2.8rem); line-height: 1;
  letter-spacing: -0.03em; color: var(--navy-900);
}
.plan-unit { font-size: 0.9rem; line-height: 1.25; color: var(--ink); }
.plan-unit small { display: block; font-size: 0.8rem; color: var(--slate); }
.plan-sub { margin: 10px 0 0; font-size: 0.88rem; line-height: 1.45; color: var(--slate); }
.plan-sub strong { color: var(--ink); font-weight: 600; }
.plan-alt {
  margin: 18px 0 22px; padding-top: 14px; border-top: 1px solid var(--line-light);
  font-size: 0.88rem; line-height: 1.5; color: var(--ink);
}
.plan-alt .mono { font-family: var(--font-mono); font-weight: 500; }
.plan .btn, .plan .btn-outline { margin-top: auto; display: block; width: 100%; text-align: center; }

.plan-honest { margin: 22px auto 0; max-width: 720px; text-align: center; font-size: 0.9rem; line-height: 1.5; color: var(--slate); }

/* Small lane */
.small-grid { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 22px; align-items: stretch; }
.small-grid .plan-grid { grid-template-columns: minmax(0, 1fr); }
.close-six {
  display: flex; flex-direction: column; justify-content: center;
  background: var(--accent-tint); border: 1px solid rgba(95, 160, 41, 0.35); border-radius: var(--radius);
  padding: 26px;
}
.close-six h4 { font-family: var(--font-display); font-size: 1.1rem; line-height: 1.3; margin: 0 0 8px; color: var(--navy-900); }
.close-six p { margin: 0 0 16px; font-size: 0.95rem; line-height: 1.5; color: var(--ink); }
.close-six .route-link { font-family: var(--font-display); }
.close-six a.route-link { color: var(--accent-deep); }

/* Every plan includes. The one dark panel in a light section, so the list of
   what every plan carries is the thing the eye lands on after the plans.
   Literal colours, not tokens, so it renders identically on the order page,
   whose token names differ: navy #1a2333, green #7dc342 (fill, and green on
   dark), text #dbe4f0 at 12:1. line-height and letter-spacing stated so the
   two copies cannot drift through inheritance. */
.includes {
  margin-top: 40px; display: grid; grid-template-columns: minmax(0, 220px) minmax(0, 1fr); gap: 20px 36px; align-items: start;
  background: #1a2333; border: 0; border-top: 4px solid #7dc342; border-radius: 16px; padding: 32px 34px;
  box-shadow: 0 22px 44px -24px rgba(14, 21, 32, 0.55);
}
.includes h3 { font-size: 1.45rem; line-height: 1.25; letter-spacing: -0.01em; margin: 0; color: #fff; }
.includes ul { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px 30px; }
.includes li { position: relative; padding-left: 36px; font-size: 1rem; line-height: 1.5; letter-spacing: 0; color: #dbe4f0; }
.includes li svg {
  position: absolute; left: 0; top: 0; width: 24px; height: 24px; padding: 4px; box-sizing: border-box;
  border-radius: 50%; background: #7dc342; color: #1a2333;
}
#pricing .perks { margin-top: 20px; }
.price-foot { margin: 10px 0 0; text-align: center; font-size: 0.84rem; color: var(--slate); }

/* Compare disclosure */
.compare { margin-top: 34px; }
.compare > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 10px;
  min-height: 48px; padding: 12px 18px; border-radius: var(--radius-pill);
  font-family: var(--font-display); font-weight: 600; font-size: 0.98rem; line-height: 1.2; color: var(--navy-900);
  border: 1px solid var(--line-light); background: var(--paper); max-width: 600px; margin: 0 auto;
}
.compare > summary::-webkit-details-marker { display: none; }
.compare > summary span { font-family: var(--font-body); font-weight: 400; font-size: 0.84rem; color: var(--slate); }
.compare > summary::after {
  content: ""; width: 9px; height: 9px; flex: none; margin-top: -4px;
  border-right: 2px solid var(--navy-900); border-bottom: 2px solid var(--navy-900); transform: rotate(45deg);
  transition: transform 0.2s ease;
}
.compare[open] > summary::after { transform: rotate(-135deg); margin-top: 4px; }
.compare > summary:focus-visible { outline: 3px solid var(--navy-900); outline-offset: 2px; }
.compare-body { padding-top: 26px; }
.compare-body .table-note { margin: -14px 0 22px; }

@media (max-width: 900px) {
  .plan-grid { grid-template-columns: minmax(0, 1fr); gap: 26px; }
  .small-grid { grid-template-columns: minmax(0, 1fr); }
  .includes { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
  .plan-lanes { max-width: none; }
  .plan { padding: 26px 20px 20px; }
  .plan--marked { padding: 25px 19px 19px; }
  .includes { padding: 26px 22px; }
  .includes h3 { font-size: 1.3rem; }
  .includes ul { grid-template-columns: minmax(0, 1fr); }
  .small-route { justify-content: flex-start; text-align: left; }
  .compare > summary { flex-wrap: wrap; text-align: center; }
  .compare > summary span { flex-basis: 100%; }
}
/* A jump into the disclosure (the table's tier stars, or #multi-building
   from elsewhere) clears the sticky bar like a section jump does. */
.compare [id] { scroll-margin-top: calc(var(--header-h) + 12px); }

.perks {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  text-align: center; font-weight: 600; color: var(--slate);
  margin: 0; flex-wrap: wrap;
}
.perks svg { width: 18px; height: 18px; color: var(--accent-dark); flex: none; }

/* ---------- Section 8: FAQ ---------- */
.faq-item {
  background: var(--paper);
  border: 1px solid var(--line-light);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-card-light);
  margin-bottom: 14px;
  overflow: hidden;
}
.faq-item summary {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  list-style: none; cursor: pointer;
  font-family: var(--font-display); font-weight: 600; font-size: 1.02rem;
  padding: 20px 24px;
  transition: color 0.2s ease;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary:hover { color: var(--accent-dark); }
.faq-plus { width: 18px; height: 18px; flex: none; color: var(--accent-dark); transition: transform 0.3s ease; }
.faq-item[open] .faq-plus { transform: rotate(45deg); }
.faq-item p { padding: 0 24px 22px; margin: 0; color: var(--slate); max-width: 68ch; }
/* The two questions a prospect asks right before committing. Tinted so they
   read as the answers to "what do I risk" rather than more of the list. */
.faq-item.faq-key {
  background: var(--accent-tint);
  border-color: var(--accent-light);
}
.faq-item.faq-key summary { color: var(--navy-900); }
.faq-item.faq-key summary:hover { color: var(--accent-dark); }
.faq-item.faq-key p { color: #46586f; }
/* accent-dark only reaches 2.9:1 on the tint, under the 3:1 WCAG asks of a
   non-text control; this darker green clears it at 4.1:1. */
.faq-item.faq-key .faq-plus { color: #4d8321; }

/* ---------- Section 9: claim / form ---------- */
.claim { position: relative; }
.claim-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 64px; align-items: stretch;
}
/* Side by side, the left column runs the height of the card's working part:
   the photograph's top edge level with the Start button's, the last point's
   foot level with Send enquiry's. 38px is the card's top padding; 70px is its
   bottom padding plus the empty status line under the button. The heading
   takes the slack, so opening the estate step lengthens the gap above it
   rather than knocking the edges out of line. */
.claim-side { display: flex; flex-direction: column; padding: 38px 0 70px; }
.claim-side h2 { margin-top: auto; }
.claim-media { border-radius: var(--radius); overflow: hidden; margin-bottom: 30px; box-shadow: var(--shadow-card); border: 1px solid var(--line-dark); }
.claim-points { display: grid; gap: 10px; margin-top: 22px; }
.claim-points li {
  position: relative; padding-left: 30px;
  color: #d8e3f2; font-weight: 500;
}
.claim-points li::before {
  content: ""; position: absolute; left: 0; top: 4px;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(125, 195, 66, 0.16);
  border: 1.5px solid var(--accent);
}
.claim-points li::after {
  content: ""; position: absolute; left: 5px; top: 9px;
  width: 8px; height: 5px;
  border-left: 2px solid var(--accent); border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}

.form-card {
  background: var(--paper);
  color: var(--ink);
  border-radius: var(--radius);
  box-shadow: 0 30px 70px rgba(0, 0, 0, 0.45);
  padding: 38px 38px 34px;
}
.form-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; }
.field { margin-bottom: 18px; }
.field label {
  display: block; font-weight: 600; font-size: 0.88rem; margin-bottom: 7px;
}
.field .req { color: var(--accent-dark); }
.field input[type="text"], .field input[type="email"], .field input[type="tel"],
.field select, .field textarea {
  width: 100%;
  font: inherit; color: var(--ink);
  background: var(--paper-dim);
  border: 1.5px solid var(--line-light);
  border-radius: var(--radius-sm);
  padding: 13px 15px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
.field textarea { resize: vertical; min-height: 96px; }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-color: var(--accent); background: #fff;
  box-shadow: 0 0 0 4px rgba(125, 195, 66, 0.18);
}
.field input.invalid { border-color: var(--error); background: #fdf4f4; }

.field-hint { margin: 7px 0 0; font-size: 0.79rem; color: var(--slate); }

.hp-field { position: absolute; left: -9999px; top: -9999px; height: 0; overflow: hidden; }

.field-consent { margin: 4px 0 22px; }
.consent { display: flex; gap: 11px; align-items: flex-start; font-size: 0.86rem; color: var(--slate); font-weight: 500; }
.consent input { width: 17px; height: 17px; margin-top: 2px; accent-color: var(--accent-dark); flex: none; }
.consent a { color: var(--accent-dark); }

.form-note { text-align: center; font-size: 0.84rem; color: var(--slate); margin: 14px 0 0; }

/* Ordering leads the card and the enquiry form backs it up, so the order CTA
   sits above the fields: a solid button under a form someone had already
   filled in would throw that work away on the way to another site. The submit
   drops to the outline treatment so the two never compete. */
.order-lead { margin-bottom: 26px; }
.form-or {
  display: flex; align-items: center; gap: 14px;
  margin: 0 0 22px; color: var(--slate); font-size: 0.84rem;
}
.form-or::before, .form-or::after {
  content: ""; flex: 1; height: 1px; background: var(--line-light);
}
.form-intro { margin: 0 0 20px; text-align: center; color: var(--slate); font-size: 0.92rem; }

/* ---------- Stepped enquiry form ----------
   Two rows that open one at a time. Shut, each is a single 56px bar, which
   is what takes the card from taller than the viewport to about a third of it.
   The rule sits between the rows rather than around them, so the closed state
   reads as a list and not as two more cards inside a card. The rule below the
   last row separates the answers from consent and the send button, which now
   stand outside the accordion. */
.form-steps {
  list-style: none; margin: 0 0 20px; padding: 0 0 2px; counter-reset: none;
  border-bottom: 1px solid var(--line-light);
}
.form-step + .form-step { border-top: 1px solid var(--line-light); }
.form-step-head { margin: 0; font: inherit; }
.form-step-btn {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 16px 2px; background: none; border: 0; cursor: pointer;
  font-family: var(--font-display); font-size: 1rem; color: var(--ink); text-align: left;
}
.form-step-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
/* The number is the progress indicator: outlined while pending, filled once
   the step is answered, so the state is carried by more than colour alone. */
.form-step-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; flex: none; border-radius: 50%;
  border: 1.5px solid var(--slate-light); color: var(--slate);
  font-family: var(--font-mono); font-size: 0.78rem; line-height: 1;
}
.form-step.open .form-step-n { border-color: var(--accent-dark); color: var(--accent-ink); }
.form-step.done .form-step-n {
  background: var(--accent-dark); border-color: var(--accent-dark); color: #fff; font-size: 0;
}
.form-step.done .form-step-n::after { content: "\2713"; font-family: var(--font-body); font-size: 0.82rem; }
.form-step-title { font-weight: 600; flex: none; }
.form-step-summary {
  margin-left: auto; text-align: right; min-width: 0;
  color: var(--slate); font-family: var(--font-body); font-size: 0.85rem; font-weight: 400;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.form-step-panel { padding: 2px 2px 20px; }
.form-step-panel > .field:last-of-type { margin-bottom: 4px; }
@media (max-width: 460px) {
  /* The summary and the title compete for one line on a narrow card; the
     title is the one that has to survive. */
  .form-step-summary { display: none; }
}
/* .btn-outline sets inline-block after .btn-block in the cascade, so the
   full-width form submit needs the two together to win it back. */
.btn-outline.btn-block { display: block; width: 100%; padding: 14px 22px; }
/* The card is white but sits inside .section-dark, whose .btn-outline override
   was reaching in and painting the submit --accent: 2.15:1 on white as a label
   and as a ring. Put the light treatment back. */
.form-card .btn-outline { color: var(--accent-ink); border-color: var(--accent-dark); }
.form-card .btn-outline:hover { color: var(--navy-900); border-color: var(--accent); }
.form-status { text-align: center; font-weight: 600; margin: 12px 0 0; min-height: 1.4em; }
.form-status.error { color: var(--error); }

.form-success { text-align: center; padding: 34px 10px; color: var(--ink); }
.form-success svg { width: 62px; height: 62px; color: var(--accent-dark); margin: 0 auto 18px; }
.form-success p { color: var(--slate); max-width: 44ch; margin-inline: auto; }
/* The order form is the second path out of this card, for someone who has
   already decided. It stays subordinate to the submit button under the form,
   and becomes the obvious next step once the enquiry is in. */
.form-alt { text-align: center; font-size: 0.88rem; color: var(--slate); margin: 14px 0 0; }
.form-alt a { color: var(--accent-ink); font-weight: 600; }
.form-alt a:hover { color: var(--navy-900); }
.form-success .form-alt { margin-top: 26px; }
.form-success .btn { margin-top: 10px; }

/* ---------- Footer ---------- */
.site-footer { background: var(--navy-950); color: var(--slate-light); padding: 64px 0 0; font-size: 0.93rem; }
.footer-grid {
  display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px; padding-bottom: 52px;
}
.footer-brand p { margin: 16px 0 0; max-width: 40ch; }
.footer-nav { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 28px; align-content: start; grid-auto-flow: column;
  grid-template-rows: repeat(5, auto); }
/* White, not the footer's muted --slate-light: these are the page's navigation,
   and they sat at the same weight as the small print around them. Hover moves to
   the accent since white is no longer available as the lift. */
.footer-nav a { color: #fff; text-decoration: none; transition: color 0.2s ease; }
.footer-nav a:hover { color: var(--accent); }
.footer-contact h3 { color: #fff; font-size: 0.95rem; margin-bottom: 12px; }
.footer-contact a { color: var(--slate-light); text-decoration: none; }
.footer-contact a:hover { color: #fff; }
/* Small print, on its own light band running the full width. It belongs to
   the company rather than to the page, and the change of ground says so more
   plainly than one more rule across the same dark field. The notes flow in
   columns so the measure stays readable instead of running the whole
   container, and the colophon sits below a rule so company identity reads as
   a closing line, not another clause.
   12.2px gets no large-text allowance, so both tones clear 4.5:1 on
   --paper-dim: notes 9.97:1, colophon 4.58:1. */
.footer-legal {
  background: var(--paper-dim); color: var(--navy-800);
  padding-block: 34px 40px; font-size: 0.76rem; line-height: 1.72;
}
.legal-notes {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 20px 48px;
}
.legal-notes p { margin: 0; }
.legal-colophon {
  margin: 28px 0 0; padding-top: 20px;
  border-top: 1px solid var(--line-light);
  color: var(--slate);
}
.legal-colophon span { display: block; }
.legal-colophon span + span { margin-top: 4px; }
.footer-legal a {
  color: inherit; text-decoration: underline;
  /* --slate, not --slate-light: the underline is what distinguishes a link
     from the sentence around it, and at 2.60:1 it was too faint to do that
     job. 4.58:1, still plainly lighter than the 9.97:1 text. */
  text-decoration-color: var(--slate);
  text-underline-offset: 2px;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.footer-legal a:hover { color: var(--ink); text-decoration-color: currentColor; }

/* ---------- Sticky mobile CTA ---------- */
.mobile-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 110;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: rgba(14, 21, 32, 0.92);
  backdrop-filter: blur(10px);
  border-top: 1px solid var(--line-dark);
  transform: translateY(110%);
  transition: transform 0.35s ease;
  display: none;
}
.mobile-cta.visible { transform: translateY(0); }

/* ---------- Motion ----------
   Two animations only, both carrying information: the heartbeat trace (the
   product's own signal) and the countdown's ticking digits. Entrance reveals,
   ambient zooms and bobbing loops were removed deliberately — content renders
   immediately, with or without JavaScript. */
@keyframes heartbeat-draw {
  0% { stroke-dashoffset: 640; }
  55% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -640; }
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; }
  .heartbeat-line { stroke-dasharray: none; stroke-dashoffset: 0; }
}

/* ---------- Responsive ---------- */
/* The header has no breakpoints of its own: the same three parts at every
   width, which is what makes it the same bar as the order page's. */

/* 1021-1100px is where the two-column hero is tightest: the left cell is about
   510px and the button, gap and link come to 512. Trimming the gutter by 10px
   there keeps them on one row instead of wrapping for a 20px-wide band. */
@media (min-width: 1021px) and (max-width: 1100px) {
  .hero-actions { column-gap: 22px; }
}

@media (max-width: 1020px) {
  /* The 90deg scrim thins to 0.35 alpha at 75% so the photograph reads behind
     the status card. Once the hero stacks there is no card beside the copy, and
     the copy runs the full width straight into that thin band — the secondary
     CTA landed on a highlight at 4.11:1 with a 1.45:1 ring. Flat scrim here;
     the reveal returns above 1020px, where the card does. */
  .hero-overlay {
    background:
      linear-gradient(90deg, rgba(14, 21, 32, 0.94) 0%, rgba(14, 21, 32, 0.88) 100%),
      linear-gradient(0deg, rgba(14, 21, 32, 0.9) 0%, rgba(14, 21, 32, 0) 30%);
  }
  .legal-notes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 40px; }
  /* One column: the six benefits become a list of disclosures. */
  .flow-benefits { grid-template-columns: minmax(0, 1fr); gap: 14px; margin-top: 40px; }
  .hub-acc > summary { cursor: pointer; display: flex; align-items: center; gap: 12px; }
  .hub-acc > summary h3 { margin: 0; flex: 1; }
  .hub-acc > summary::after {
    content: '+'; flex: none; font-family: var(--font-mono); font-size: 1.2rem;
    line-height: 1; color: var(--accent-ink);
  }
  .hub-acc[open] > summary::after { content: '\2013'; }
  .hub-acc[open] > summary h3 { margin-bottom: 5px; }
  .hub-acc > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
  .claim-grid { grid-template-columns: minmax(0, 1fr); gap: 48px; }
  .claim-side { display: block; padding: 0; }
  .eco-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); --eco-panel-h: 290px; }
  .eco-card:last-child { grid-column: 1 / -1; }
  .oem-grid { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .oem-media { max-width: 520px; min-width: 0; }
  /* One column: copy spans the full width, so the left-heavy scrim no longer
     protects it — go flat and heavier instead. */
  .section-oem {
    background:
      linear-gradient(rgba(26, 35, 51, 0.91), rgba(26, 35, 51, 0.91)),
      url("../img/oem-van.webp") center / cover no-repeat var(--navy-900);
  }
}

@media (max-width: 760px) {
  .section { padding: 78px 0; }
  /* The button takes the full width on a phone; the link centres under it so
     the pair reads as one centred column rather than a button with something
     hanging off its left edge. */
  /* The card is a 380px panel on desktop. On a phone that left a dead gutter
     beside it, reading as a stray tile, so it takes the full column. Its
     heartbeat trace is already width: 100%. */
  .hero-card, .status .hero-card { max-width: none; }
  .hero-actions { flex-direction: column; gap: 18px; align-items: stretch; }
  .hero-actions > .btn { display: block; width: 100%; text-align: center; }
  /* Centred under the full-width button, which is what the pair is documented
     to do here and what the order page's hero does. `start` left it hanging
     off the button's left edge, reading as a stray second column. */
  .hero-actions > .link-cta { align-self: center; }
  .brand-logo { height: 32px; }
  .oem-tabs { gap: 14px; }
  .oem-tabs span { font-size: 0.62rem; }
  /* The hero takes the screen below the bar and the whole block sits in the
     middle of it. The call to action does not need anchoring to the bottom
     edge any more: once it scrolls away the sticky bar carries it, so the fold
     can be composed rather than stretched to reach the foot. The height is
     derived — viewport less the bar and the hero's own padding — so the fold
     ends exactly where the next section begins on any handset. svh, not vh,
     so it is measured with the browser chrome showing. */
  .hero { padding: 60px 0; min-height: 0; }
  /* Centred on a phone only: the column is narrow enough that centred lines
     still read, and it puts the headline, the lede and the button on one axis
     with the full-width button they sit above. Desktop stays left-aligned,
     where the measure is too wide for a centred rag. */
  .hero-copy {
    display: flex; flex-direction: column; justify-content: center;
    min-height: calc(100svh - var(--header-h) - 120px);
  }
  /* 48px, matching the column gap the same two blocks get side by side above
     this breakpoint. Stacked, they were inheriting 32px — a value chosen to
     sit between two columns, not to mark a break between a paragraph and the
     countdown under it, where it read as the copy running straight on. */
  .deadline-inner { grid-template-columns: minmax(0, 1fr); gap: 76px; padding-block: 56px; }
  /* The section is already a centred stack at every width, so the phone only
     needs it shorter and the copy left-aligned again — a centred rag under a
     left-aligned card looked like two different sections. */
  .status-inner { padding-block: 56px; text-align: left; }
  .status-copy { margin-bottom: 28px; }
  /* column sections become horizontal peek-through card rows: the next card
     stays partially in view as the swipe affordance.
     The bleed is --gutter, not 4vw. These sit inside .container, whose gutter
     is a flat 24px, and -4vw only cancels it at exactly 600px wide — above
     that the track hung past both edges of the screen and put up to 6px of
     horizontal scroll on the page, which is how it was found. */
  .pilot-track, .eco-grid {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    gap: 14px;
    margin-inline: calc(-1 * var(--gutter));
    padding: 10px var(--gutter) 24px;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .pilot-track::-webkit-scrollbar, .eco-grid::-webkit-scrollbar,
  .table-wrap::-webkit-scrollbar { display: none; }
  .pilot-track::before, .track-step::before { display: none; }
  .track-step {
    flex: 0 0 84%;
    scroll-snap-align: start;
    background: var(--paper);
    border: 1px solid var(--line-light);
    border-radius: var(--radius-sm);
    padding: 22px 22px 24px;
    box-shadow: var(--shadow-card-light);
  }
  /* Carousel cards are the narrowest they get, so the status heading wraps
     to three lines at 320px — this is the tallest the panel has to be. */
  .eco-grid { --eco-panel-h: 300px; }
  .eco-card { flex: 0 0 84%; scroll-snap-align: start; }
  .eco-card:last-child { grid-column: auto; }
  .eco-card:hover { transform: none; box-shadow: var(--shadow-card-light); }

  /* pricing: the five-column table becomes one upright card per tier */
  .table-wrap {
    background: transparent; border: none; border-radius: 0; box-shadow: none;
    margin-inline: calc(-1 * var(--gutter));
    padding: 10px var(--gutter) 24px;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
  }
  .price-table { min-width: 0; display: block; }
  .price-table thead { display: none; }
  .price-table tbody { display: flex; gap: 14px; }
  .price-table tbody tr {
    display: block;
    flex: 0 0 82%;
    scroll-snap-align: start;
    background: var(--paper);
    border: 1px solid var(--line-light);
    border-radius: var(--radius-sm);
    padding: 20px 20px 8px;
    box-shadow: var(--shadow-card-light);
  }
  .price-table tbody tr:hover { background: var(--paper); }
  .price-table tbody th, .price-table tbody td { display: block; padding: 10px 0; }
  .price-table tbody th {
    border-top: none; white-space: normal;
    font-size: 1.15rem; padding: 0 0 10px;
  }
  .price-table tbody td { border-top: 1px solid var(--line-light); }
  .price-table tbody td::before {
    display: block;
    font-family: var(--font-display);
    font-size: 0.66rem; font-weight: 700;
    letter-spacing: 0.08em; text-transform: uppercase;
    color: var(--slate);
    margin-bottom: 3px;
  }
  .price-table tbody td:nth-of-type(1)::before { content: "Total lifts"; }
  .price-table tbody td:nth-of-type(2)::before { content: "Contract term"; }
  .price-table tbody td:nth-of-type(3)::before { content: "Zero upfront cost, hardware included free"; }
  .price-table tbody td:nth-of-type(4)::before { content: "Hardware upfront · £295 per lift"; }
  .price-table .rate-capex { background: transparent; }
  .pilot-banner { grid-template-columns: minmax(0, 1fr); }
  .pilot-banner-media { min-height: 220px; }
  .pilot-banner-copy { padding: 32px 28px; }
  .form-row { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .form-card { padding: 28px 22px; }
  .footer-grid { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .footer-nav { grid-auto-flow: row; grid-template-rows: none; }
  .legal-notes { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .mobile-cta { display: block; }
  /* The menu becomes a sheet: full width, from the bar's bottom edge to the
     bottom of the screen. A 288px card hanging off the burger left most of
     the page showing behind it. The sticky CTA, where there is one, sits
     over the foot of the sheet, so the list keeps clear of it. Absolute off
     the bar rather than fixed, because the bar's backdrop-filter makes it the
     containing block for fixed children too. lvh, not svh: svh stops short
     of the screen's foot while Safari's toolbar is collapsed. */
  .site-nav {
    top: calc(100% + 1px); left: 0; right: 0; width: auto;
    height: calc(100lvh - var(--header-h) - 1px);
    border-radius: 0; border: 0; box-shadow: none;
    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  }
  .site-nav-in { padding: 12px var(--gutter) calc(96px + env(safe-area-inset-bottom)); }
  .site-nav a { min-height: 60px; padding: 10px 4px; font-size: 20px; border-radius: 0;
    border-bottom: 1px solid var(--line-light); }
  .site-nav-cta { border-top: 0; border-bottom: 0; margin-top: 10px; }
  body.form-in-view .mobile-cta { transform: translateY(110%); }
}

/* ==========================================================================
   /technology — the ecosystem page
   Its own sections, everything else borrowed: the same container, section
   bands, buttons, header and footer as the landing page, because it is the
   same site one level down. Only what this page alone needs lives here.
   ========================================================================== */

/* The copy and the readout side by side, the copy given the wider share: it
   is the argument, the card is the evidence. The card column is sized off the
   card's own 380px ceiling plus the gap, so the split does not have to be
   guessed and the copy keeps a single readable measure at every width. */
.tech-grid { display: grid; grid-template-columns: minmax(0, 1fr) 380px;
  gap: 30px 64px; align-items: center; }
/* Sized to the largest the headline can be while its longest line —
   "LiftPulse never sleeps." at 10.97 units per px of font-size — still holds
   one line. Below 1021 the column is the full container, so a plain vw tracks
   it: 7.7vw is what 320px allows once its 48px of gutter is taken off.
   Above 1021 the column stops following the viewport, because the card takes
   380 and the gap 64 out of it before the copy gets any. 100vw minus that
   fixed 496 is the column, so the size is measured off the column rather than
   off the window, and the 56px ceiling is what the 628px column allows at
   1120 and wider. The divisor carries margin for a desktop scrollbar, which
   100vw counts and the column does not.
   Changing either line's wording changes all of this — measure again rather
   than nudging. */
.tech-intro h1 { font-size: clamp(24px, 7.7vw, 56px); margin-bottom: 26px; }
@media (min-width: 1021px) {
  .tech-intro h1 { font-size: clamp(34px, calc((100vw - 496px) / 11.3), 56px); }
}
/* A single reading measure. Two columns made a wall of type at this length —
   the eye had to travel the full width twice before anything changed. */
.tech-lede { max-width: 58ch; }
.tech-lede p { color: #c4d1e4; margin-bottom: 1.1em; }
.tech-lede p:last-child { margin-bottom: 0; }

/* The lede as three disclosures. No rules and no panels: the heading's weight,
   size and colour already separate it from the prose under it, and four
   hairlines across a dark band added furniture the list did not need. Spacing
   does the separating instead. The marker is the FAQ's +/− so a disclosure
   behaves the same way wherever it appears, and it is the accent at 7.32:1. */
.tech-acc details + details { margin-top: 10px; }
.tech-acc summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 14px;
  padding: 10px 0;
  font-family: var(--font-display); font-weight: 600; font-size: 1.05rem;
  color: #fff; transition: color 0.15s ease;
}
.tech-acc summary::-webkit-details-marker { display: none; }
.tech-acc summary::after {
  content: '+'; margin-left: auto; flex: none;
  font-family: var(--font-mono); font-size: 1.25rem; line-height: 1;
  color: var(--accent);
}
.tech-acc details[open] summary::after { content: '\2013'; }
/* The open panel's heading takes the accent, so it is clear which heading
   the text below belongs to. 7.32:1 on this ground. */
.tech-acc details[open] summary { color: var(--accent); }
.tech-acc summary:hover { color: var(--accent); }
.tech-acc summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.tech-acc details > p { margin: 0 0 18px; }
/* The OEM section's audiences use the same disclosure. The h3 keeps the
   outline but takes the summary's face, size and colour. */
.oem-acc summary h3 { margin: 0; font: inherit; color: inherit; letter-spacing: inherit; }
.oem-acc details > p { color: #c4d1e4; }
.tech-open { font-family: var(--font-display); font-weight: 400;
  font-size: 1.28rem; line-height: 1.35; color: #fff; margin-bottom: 1.1em;
  max-width: 34ch; }
/* A hairline and a green flash: the statement is a pull quote, not a heading,
   so it takes a rule rather than a size it has not earned. */
.tech-open { border-left: 3px solid var(--accent); padding-left: 18px; }

/* The card is the landing page's, unchanged. Only the drop shadow swaps: the
   light-ground one disappears on navy, where --shadow-card was built to sit. */
.tech-panel .hero-card { max-width: none; box-shadow: var(--shadow-card); }
/* Centred against the copy, not hung from its top edge: the two cards are one
   block of evidence beside one block of argument, and starting them together
   left the shorter column trailing off into empty navy. */
.tech-panel { display: grid; gap: 18px; }

/* The two event cards, one either side of the same fault. Colour states the
   card, the heading states it in words, so the edge is reinforcement and not
   the only cue. Every colour here is measured on white: the amber edge is
   #be7d0a at 3.43:1 and the green --accent-dark at 3.21:1, both over the 3:1
   a graphic needs, while the headings take --amber-ink at 4.73:1 and
   --accent-ink at 4.58:1. The brand amber itself is 2.03:1 on white and is
   nowhere near either bar, which is why neither role uses it. */
.tech-event { border-left: 4px solid var(--line-light); }
.tech-event.warn { border-left-color: #be7d0a; }
.tech-event.ok { border-left-color: var(--accent-dark); }
.tech-event.warn .hero-card-head { color: var(--amber-ink); }
.tech-event.ok .hero-card-head { color: var(--accent-ink); }
.tech-event .hero-card-head { margin-bottom: 10px; }
.status-dot.warn { background: #be7d0a; }
.tech-event-line { margin: 0; font-size: 0.95rem; color: var(--ink); }
/* The one line that covers both cards, so it sits under the pair rather than
   inside either of them. */
.tech-panel-note { margin: 2px 0 0; font-size: 0.84rem; color: #9fb0c8;
  line-height: 1.5; }

/* Three figures across the foot of the band, on the rule that closes it. The
   number carries the weight and the label sits above it, so the row scans as
   three values rather than three sentences. */
.tech-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px 40px; margin: 64px 0 0; padding-top: 34px;
  border-top: 1px solid rgba(138, 155, 176, 0.22); }
.tech-stats dt { font-size: 0.84rem; color: #9fb0c8; margin-bottom: 8px; }
.tech-stats dd { margin: 0; font-family: var(--font-display); font-weight: 700;
  font-size: 1.12rem; color: #fff; letter-spacing: -0.02em; }
.tech-stats dd b { font-size: 2.6rem; line-height: 1; color: var(--accent);
  margin-right: 8px; letter-spacing: -0.04em; }

/* Three beats, one per line at every width, so no phrase is ever split, and
   set well above the page's h2: 10.4vw keeps "Every heartbeat." inside the
   column down to 360px, 3.6rem caps it on desktop. The
   last carries the point and takes the green — --accent-ink, 4.58:1 on white. */
.beats { font-size: clamp(2.2rem, 10.4vw, 3.6rem); line-height: 1.08; letter-spacing: -0.03em; }
.beats span { display: block; }
.beats .accent-ink { color: var(--accent-ink); }

/* ---------- The Venn ----------
   Three sets and the LiftPulse logo in the region all three share. The fills
   are the brand green at 0.2: overlapping translucent fills darken on their
   own, so the two-way regions come out of the arithmetic. The three-way region
   is filled white instead, so the logo sits on white as it is issued — its
   green mark disappeared into the green overlap. The edges are redrawn over
   the white so the lens keeps its outline.
   Labels run around the outside of each circle in the mono face, uppercase and
   tracked, in --accent-ink (4.58:1 on white) — a different voice from every
   heading on the page, which is the point of them. */
.venn-fig { margin: 0; }
.venn { display: block; width: 100%; max-width: 560px; margin: 0 auto; height: auto; }
.venn-set circle { fill: var(--accent); fill-opacity: 0.2;
  stroke: var(--accent-dark); stroke-width: 1.5; stroke-opacity: 0.55; }
.venn-shield { fill: #fff; stroke: var(--accent-dark); stroke-width: 3; stroke-linejoin: round;
  filter: drop-shadow(0 6px 14px rgba(26, 35, 51, 0.14)); }
.venn-edge circle { fill: none; stroke: var(--accent-dark); stroke-width: 1.5; stroke-opacity: 0.55; }
.venn-arc-label { font-family: var(--font-mono); font-weight: 500; font-size: 17px;
  letter-spacing: 0.2em; text-transform: uppercase; fill: var(--accent-ink); }
.venn-word { fill: #111114; }
.venn-fig figcaption { max-width: 58ch; margin: 30px auto 0; text-align: center;
  color: var(--slate); font-size: 0.97rem; }

/* ---------- What it reports ---------- */
/* Alert channels, under the app screens and above the line that explains
   them. White chips on the dim band; the icon is --accent-ink at 4.58:1. */
.channel-chips {
  list-style: none; margin: 30px 0 0; padding: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 12px;
}
.channel-chips li {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--paper); border: 1px solid var(--line-light);
  border-radius: var(--radius-pill); padding: 9px 16px 9px 12px;
  font-family: var(--font-display); font-weight: 600; font-size: 0.92rem; color: var(--navy-900);
  box-shadow: 0 6px 18px rgba(26, 35, 51, 0.06);
}
.channel-chips svg { width: 22px; height: 22px; flex: none; color: var(--accent-ink); }
.channel-chips + .section-sub { margin-top: 20px; }
/* On a phone the five pills wrap to three rows; as icons alone they sit on
   one. The names stay in the markup, hidden visually but still read out. */
@media (max-width: 600px) {
  .channel-chips { gap: 10px; flex-wrap: nowrap; }
  .channel-chips li { width: 48px; height: 48px; padding: 0; justify-content: center; }
  .channel-chips span { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
}
/* App screens: three phones between the heading and the sub-line. Drawn in
   HTML and SVG, so the text stays sharp and in the site's own faces. Red as
   text is #b01f1f (6.5:1 on white); --error is only ever a dot or a pin. */
.tech-reports .section-head:first-child { margin-bottom: 36px; }
.section-head-after { margin-bottom: 0; }
.app-shots {
  display: flex; justify-content: center; gap: 32px;
  margin: 0 0 40px;
}
.app-shot { margin: 0; flex: 0 0 250px; }
.phone {
  width: 250px; height: 520px; border-radius: 38px; padding: 9px;
  background: var(--navy-950); box-shadow: 0 24px 50px rgba(14, 21, 32, 0.22),
    inset 0 0 0 1.5px #3d5270;
}
.phone-screen {
  position: relative; height: 100%; border-radius: 30px; overflow: hidden;
  background: #fff; font-family: var(--font-body); color: var(--navy-900);
  display: flex; flex-direction: column; line-height: 1.35; letter-spacing: 0;
}
:where(.phone-screen) p { margin: 0; }
.phone-status {
  display: flex; justify-content: space-between; align-items: center;
  padding: 11px 20px 6px; font-size: 11px; font-weight: 700;
}
.phone-status::after { content: ''; position: absolute; top: 9px; left: 50%;
  width: 72px; height: 20px; margin-left: -36px; border-radius: 12px; background: var(--navy-950); }
.phone-sig { width: 34px; height: 9px; background:
  linear-gradient(currentColor, currentColor) 0 100% / 3px 4px no-repeat,
  linear-gradient(currentColor, currentColor) 4px 100% / 3px 6px no-repeat,
  linear-gradient(currentColor, currentColor) 8px 100% / 3px 9px no-repeat,
  linear-gradient(currentColor, currentColor) 16px 50% / 18px 9px no-repeat;
  border-radius: 1px; }
/* 1: lock screen */
.lock { background: radial-gradient(120% 70% at 50% 0%, #2c3e56 0%, #1a2333 55%, #0e1520 100%); color: #fff; }
.lock-time { font-family: var(--font-display); font-weight: 600; font-size: 52px;
  line-height: 1; text-align: center; margin-top: 30px; letter-spacing: -0.02em; }
.lock-date { text-align: center; font-size: 12.5px; color: #cbd8ea; margin: 6px 0 34px; }
.note { margin: 0 10px 8px; padding: 10px 12px 11px; border-radius: 16px;
  background: rgba(255, 255, 255, 0.96); color: var(--navy-900); font-size: 11.5px; }
.note-app { display: flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--slate); margin-bottom: 5px; }
.note-app svg { width: 18px; height: 18px; padding: 3px; border-radius: 5px; background: var(--navy-900); }
.note-app span { margin-left: auto; font-weight: 500; text-transform: none; letter-spacing: 0; }
.note-title { display: flex; align-items: center; gap: 6px; font-weight: 700; font-size: 12.5px; }
.note-crit .note-title, .note-crit .note-body { color: #b01f1f; }
.note-title i { width: 8px; height: 8px; border-radius: 50%; background: var(--error); flex: none;
  box-shadow: 0 0 0 3px rgba(232, 64, 64, 0.2); }
.note-body { color: #3d5270; margin-top: 2px; }
.note-crit { box-shadow: inset 3px 0 0 var(--error); }
.note-old { background: rgba(255, 255, 255, 0.78); }
/* 2 and 3: app screens */
.app-bar { padding: 12px 16px 12px; border-bottom: 1px solid var(--line-light); }
.app-bar b { display: block; font-family: var(--font-display); font-size: 17px; }
.app-bar span { font-size: 11px; color: var(--slate); }
.log { width: 100%; border-collapse: collapse; font-size: 11.5px; }
.log td { padding: 9.5px 0; border-bottom: 1px solid #eef0f3; }
.log td:first-child { padding: 9.5px 10px 9.5px 16px; width: 38px; font-family: var(--font-mono); font-size: 10.5px; color: var(--slate); }
.log td:nth-child(2) { font-weight: 600; }
.log td:last-child { padding-right: 16px; text-align: right; }
.log em { font-style: normal; font-size: 10px; font-weight: 700; padding: 2px 7px; border-radius: 999px;
  background: #eef0f3; color: #3d5270; white-space: nowrap; }
.log em.ok { background: var(--accent-tint); color: var(--accent-deep); }
.log em.crit { background: #fdecec; color: #b01f1f; }
.log tr.crit td:nth-child(2) { color: #b01f1f; }
.app-btn { margin: auto 16px 22px; padding: 10px; border-radius: 999px; text-align: center;
  background: var(--accent); color: var(--navy-900); font-family: var(--font-display); font-weight: 600; font-size: 12px; }
.map-count { display: flex; align-items: center; gap: 5px; }
.map-count i { width: 7px; height: 7px; border-radius: 50%; }
.map-count i.ok { background: var(--accent-dark); }
.map-count i.crit { background: var(--error); margin-left: 6px; }
.shot-map { flex: 1; min-height: 0; width: 100%; padding: 8px 0 4px; background: #f4f7fa; }
.map-ie { fill: #e6eaef; }
.map-gb { fill: #dfe5ec; stroke: #c3ccd8; stroke-width: .8; }
.pins circle { fill: var(--accent-dark); stroke: #fff; stroke-width: 1.4; }
.pin-alert circle { fill: var(--error); }
.pin-alert .pin-halo { fill: rgba(232, 64, 64, 0.22); stroke: none; }
.map-alert { display: flex; align-items: center; gap: 10px; margin: 10px 12px 18px;
  padding: 10px 12px; border-radius: 14px; background: #fff; box-shadow: 0 4px 16px rgba(26, 35, 51, 0.12);
  border: 1px solid #f3d4d4; font-size: 11px; color: var(--slate); }
.map-alert i { width: 10px; height: 10px; border-radius: 50%; background: var(--error); flex: none; }
.map-alert b { display: block; color: #b01f1f; font-size: 12px; }
.map-alert:not(.map-info) { color: #b01f1f; }
/* A logged event rather than a fault: the test call from the event log,
   in the page's navy rather than the alert red. The first card's bottom
   margin closes up so the two stack as one list. */
.map-alert:has(+ .map-info) { margin-bottom: 6px; }
.map-alert.map-info { margin-top: 0; border-color: var(--line-light); }
.map-alert.map-info i { background: var(--navy-700); }
.map-alert.map-info b { color: var(--navy-900); }
/* Captions run 8px past the 250px phone each side, inside the gap between
   shots, so a set two-line caption holds its break instead of wrapping. */
.app-shot figcaption { margin: 16px -8px 0; text-align: center; font-size: 0.92rem; color: var(--slate); line-height: 1.45; }
.app-shot figcaption b { display: block; font-family: var(--font-display); color: var(--navy-900); font-size: 1rem; margin-bottom: 2px; }
@media (max-width: 880px) {
  .app-shots {
    justify-content: flex-start; gap: 16px;
    overflow-x: auto; scroll-snap-type: x mandatory; scroll-padding-inline: var(--gutter);
    margin: 0 calc(-1 * var(--gutter)) 28px; padding: 6px var(--gutter) 20px;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
  }
  .app-shots::-webkit-scrollbar { display: none; }
  .app-shot { scroll-snap-align: start; }
}

/* On the white band the cards take the dim ground, so they still read as
   cards without a heavier border. */
.tech-signals .report-grid li { background: var(--paper-dim); border-color: transparent; }
.report-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 20px; }
.report-grid li { background: var(--paper); border: 1px solid var(--line-light);
  border-radius: var(--radius-sm); padding: 18px 18px 20px;
  font-size: 0.94rem; color: var(--slate); line-height: 1.5; }
.report-grid b { display: flex; align-items: center; gap: 9px; margin-bottom: 6px;
  font-family: var(--font-display); font-size: 1rem; color: var(--navy-900); }
.report-grid b::before { content: ''; flex: 0 0 10px; width: 10px; height: 10px;
  background: var(--accent); border-radius: 2px; }
/* Each item is a <details>, so on a phone the eight collapse to their headings
   like the Why cards on the landing page: closed on load, each opening on its
   own, the same +/− marker. On the grid they are held open and not a control —
   a four-across grid of cards at uneven heights is not an accordion. With no
   script they stay open. */
.report-grid p { margin: 0; }
.report-acc > summary { list-style: none; cursor: default; }
.report-acc > summary::-webkit-details-marker { display: none; }

.tech-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 20px 32px;
  justify-content: center; margin: 32px 0 0; }

@media (max-width: 1020px) {
  .report-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Below this the card column is narrower than the card, so the two stack. */
  /* Stacked, the live card comes up between the pull quote and the panels, so
     the reader sees the unit working before reading about it — the job it does
     beside the copy on a wide screen. The two event cards and their note stay
     after the panels. display: contents lets the children of both columns be
     ordered as one list; the gaps the two grids gave are margins here. */
  .tech-grid { display: flex; flex-direction: column; align-items: stretch; gap: 0; }
  .tech-copy, .tech-panel { display: contents; }
  .tech-panel .hero-card { max-width: 420px; }
  .tech-live { order: 1; margin: 4px 0 30px; }
  /* The panels are flattened too, so the Mains Power Fail card can sit between
     Digital Line + Live Monitoring and Global Visibility — the fault arrives
     just before the panel about being told first. Restored and its note stay
     after the panels. */
  .tech-lede { display: contents; }
  .tech-acc > details { max-width: 58ch; }
  .tech-acc > details:nth-of-type(-n+2) { order: 2; }
  .tech-event.warn { order: 3; margin: 18px 0 8px; }
  .tech-acc > details:nth-of-type(3) { order: 4; }
  .tech-event.ok, .tech-panel-note { order: 5; }
  .tech-event.ok { margin-top: 38px; }
  .tech-panel-note { margin-top: 18px; }
}
@media (max-width: 760px) {
  .tech-stats { grid-template-columns: minmax(0, 1fr); gap: 18px;
    margin-top: 44px; padding-top: 26px; }
  .tech-stats div { display: flex; align-items: baseline; gap: 14px;
    flex-direction: row-reverse; justify-content: flex-end; }
  .tech-stats dt { margin-bottom: 0; }
  .tech-stats dd b { font-size: 2.1rem; }
  .report-grid { grid-template-columns: minmax(0, 1fr); gap: 14px; }
  .report-acc > summary { cursor: pointer; display: flex; align-items: center; gap: 12px; }
  .report-acc > summary b { margin: 0; flex: 1; }
  .report-acc > summary::after {
    content: '+'; flex: none; font-family: var(--font-mono); font-size: 1.2rem;
    line-height: 1; color: var(--accent-ink);
  }
  .report-acc[open] > summary::after { content: '\2013'; }
  .report-acc[open] > summary b { margin-bottom: 6px; }
  .report-acc > summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
  /* Three short words scale down where six labels could not, so the phone
     gets the same diagram — only the type steps up to stay near 13px once the
     560-unit box is drawn at 342. */
  /* The 500-unit box is drawn at ~342px here, so the labels step up to stay
     near 14px on screen. */
  .venn-arc-label { font-size: 21px; letter-spacing: 0.16em; }
  .venn-fig figcaption { margin-top: 22px; }
}

/* 404 page. One light grey band under the site's own dark header, sized to
   fill the screen above the footer so the page does not read as half-built.
   On --paper-dim the text takes --ink and --slate, and green as text takes
   --accent-ink, as everywhere else on light. */
.nf { background: var(--paper-dim); min-height: calc(100vh - 260px); display: flex; align-items: center; }
.nf h1 { margin: 0 0 16px; color: var(--ink); }
.nf-lede { max-width: 56ch; margin: 0 0 28px; }
.nf-actions { display: flex; flex-wrap: wrap; gap: 14px; margin: 0 0 28px; }
.nf-note { max-width: 60ch; margin: 0; font-size: 0.95rem; color: var(--slate); }
.nf-note a { color: var(--accent-ink); font-weight: 600; }
