/* ============================================================
   CYANOTYPE — the design system, extracted from the template.
   Every colour, radius and shadow is the template's own value.
   The type scale is the one exception: four steps (0.69, 0.75,
   0.88, 1.05rem) are midpoints of near-identical template sizes.
   Largest resulting shift is 0.48px.
   ============================================================ */

/* ---------- fonts, self-hosted ----------
   Hotlinking Google Fonts sends every visitor's IP to Google. Cost here: three
   latin files ~143 KB, plus 20.8 KB of latin-ext mono pulled by one ƒ glyph. */

@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 500 800;
  font-display: swap;
  src: url('/assets/fonts/bricolage-grotesque-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 500 800;
  font-display: swap;
  src: url('/assets/fonts/bricolage-grotesque-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/assets/fonts/instrument-sans-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/assets/fonts/instrument-sans-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Spline Sans Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('/assets/fonts/spline-sans-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Spline Sans Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url('/assets/fonts/spline-sans-mono-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ---------- colour, by role ----------
     Renamed from the template's appearance names (--paper, --mist, --deep,
     --sky, --blue, --ink-soft, --on-deep); the values are unchanged. */

  --surface: #f2f7fa;
  --surface-raised: #ffffff;
  --surface-tint: #e2eef6;
  --surface-inverse: #10384f;
  --surface-inverse-deep: #0b2a3d;

  --ink: #0e2433;
  --ink-muted: #43606f;
  --ink-inverse: #d9ebf6;
  --ink-inverse-muted: #8fb4c9;
  --ink-on-accent: #ffffff;

  --accent: #187fb5;
  --focus-ring: var(--accent);      /* overridden to --highlight by .on-inverse */
  --accent-strong: #0f6494;
  --highlight: #a9dcf2;             /* Jim's light blue — the brand colour */
  --highlight-soft: #cfe9f7;

  --line: #c6dcea;
  --line-inverse: #1d4a63;
  --line-inverse-strong: #24506a;

  /* --ink-muted, aliased under a name that says what it does here. No --line
     token beats 1.72:1 against any surface — a white input on --surface is
     1.08:1 — and WCAG 1.4.11 asks 3:1. This is 6.69:1. Form controls ONLY. */
  --line-strong: var(--ink-muted);

  /* The ONE value on this page that is not the template's: a brand built for
     print has no red. 7.45:1 on --surface-raised, 6.90:1 on --surface. Colour
     is never the only signal — the border and the message carry it too. */
  --danger: #a52019;

  /* Darkened from the template's #1fa855, which is 3.09:1 under white — enough
     for a bare glyph at 1.4.11's 3:1, an AA failure the moment a WhatsApp
     button carries a label. Same hue at 80% lightness clears 4.5:1. */
  --whatsapp: #198644;              /* white on it: 4.63:1 */
  --whatsapp-hover: #16793d;        /* white on it: 5.47:1 */

  --shadow-color: 14 36 51;         /* --ink as RGB channels, for shadow alphas */

  /* ---------- type ---------- */
  --font-display: 'Bricolage Grotesque', 'Trebuchet MS', 'Segoe UI', sans-serif;
  --font-body: 'Instrument Sans', 'Helvetica Neue', Arial, sans-serif;
  --font-mono: 'Spline Sans Mono', 'Courier New', monospace;

  --text-root: 16.5px;              /* the template's body size */
  --text-3xs: 0.62rem;
  --text-2xs: 0.69rem;
  --text-xs: 0.75rem;
  --text-sm: 0.82rem;
  --text-base-sm: 0.88rem;
  --text-base: 0.94rem;
  --text-md: 1rem;
  --text-lg: 1.05rem;
  --text-xl: 1.15rem;
  --text-2xl: 1.22rem;
  --text-3xl: 1.3rem;
  --text-numeral: 5.2rem;
  --text-h2: clamp(1.9rem, 3.6vw, 2.7rem);
  --text-h1: clamp(2.5rem, 5.4vw, 4.1rem);

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;

  --leading-body: 1.6;
  --leading-tight: 1.06;
  --leading-none: 1;

  --tracking-heading: -0.015em;
  --tracking-wide: 0.08em;
  --tracking-wider: 0.14em;
  --tracking-widest: 0.2em;

  /* ---------- spacing ----------
     A ladder for new work only. Components keep the template's own numbers,
     which are not all on it — snapping them is a redesign. */
  --space-3xs: 4px;
  --space-2xs: 8px;
  --space-xs: 12px;
  --space-sm: 18px;
  --space-md: 26px;
  --space-lg: 40px;
  --space-xl: 56px;
  --space-2xl: 92px;

  --gutter: 24px;
  --maxw: 1120px;

  /* ---------- radii ---------- */
  --radius-sm: 4px;
  --radius-md: 6px;
  --radius-lg: 8px;
  --radius-round: 50%;

  /* ---------- shadows ---------- */
  --shadow-sm: 0 10px 26px rgb(var(--shadow-color) / 0.07);
  --shadow-md: 0 10px 28px rgb(var(--shadow-color) / 0.22);
  --shadow-lg: 0 18px 44px rgb(var(--shadow-color) / 0.28);
  --shadow-xl: 0 24px 60px rgb(0 0 0 / 0.3);

  /* ---------- motion ---------- */
  --duration-fast: 0.12s;
  --duration: 0.15s;
  --duration-slow: 0.18s;
  --duration-breathe: 9s;
  --duration-reel: 36s;

  /* Declared so a browser in dark mode does not paint its own dark canvas
     under this text. There is no dark variant, by design. */
  color-scheme: light;
}

/* ============================================================
   Base layer — the template's own reset and element defaults.
   */

/* Deliberately does not match ::before / ::after: several decorations size
   their fill in content-box and shrink if box-sizing is forced on them —
   the hero's fact dots go from 8px to 5px. */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-root);
  line-height: var(--leading-body);
  background: var(--surface);
  color: var(--ink);
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-heading);
  text-wrap: balance;
}

/* --accent-strong, not --accent: the template's link blue is 4.10:1 on the
   page ground, which fails AA for normal text. --accent-strong is 5.95:1 and
   is already the template's own colour for mono labels. */
a {
  color: var(--accent-strong);
}

::selection {
  background: var(--highlight);
  color: var(--ink);
}

/* A variable, not a fixed colour, so a component on a dark ground corrects it
   by inheritance. --accent is 2.79:1 on --surface-inverse, below 1.4.11's 3:1;
   --highlight there is 8.35:1. */
:is(a, button, input, select, textarea, summary):focus-visible {
  outline: 2.5px solid var(--focus-ring);
  outline-offset: 2px;
}

/* Put this on any element whose background is --surface-inverse or
   --surface-inverse-deep. Everything focusable inside it inherits the ring. */
.on-inverse {
  --focus-ring: var(--highlight);
}

img,
svg {
  max-width: 100%;
}

.wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 var(--gutter);
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  /* `animation: none`, not a 0.01ms duration. A near-zero duration runs the
     animation to its END state — the film strip would jump to the far end of
     its travel. The template froze these at the start. */
  *,
  *::before,
  *::after {
    animation: none !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ========== QUOTE FORM ==========
   The four states are driven by `data-state` on the form. */

.quoteForm {
  background: var(--surface);
  color: var(--ink);
  padding: 34px;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-xl);

  /* Two columns, and a field spans both unless it is marked halfWidth. The
     pairing is grid auto-flow rather than a row wrapper in the markup, so
     reordering form.fields cannot strand a row with three things in it. */
  display: grid;
  grid-template-columns: 1fr 1fr;

  /* The 18px between fields is a margin, not a row gap. A half-width field
     spans four sub-rows and a row gap would fall between a label and its own
     control; a margin lands only between one field and the next. */
  column-gap: var(--space-sm);
  row-gap: 0;
}

.quoteForm > * {
  grid-column: 1 / -1;
  margin-bottom: var(--space-sm);
}

.quoteForm > *:last-child {
  margin-bottom: 0;
}

.field--half {
  grid-column: span 1;
}

/* Not the template's 960px, which collapses the page's sections but not the
   fields inside this form. At 960px the form has the full page width and
   two-up is right; on a phone it is not. */
@media (max-width: 640px) {
  .field--half {
    grid-column: 1 / -1;
  }

  .quoteForm {
    padding: var(--space-md);
  }
}

/* ---------- heading ---------- */

.quoteForm__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-xs);
  flex-wrap: wrap;
  border-bottom: 1px solid var(--line);
  padding-bottom: 14px;
}

.quoteForm__heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: var(--weight-bold);
}

.quoteForm__note {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: 0.16em; /* the template's own tracking; no token covers it */
  text-transform: uppercase;
  color: var(--accent-strong);
}

/* ---------- a field ---------- */

/* 7px is the template's label-to-control gap. Carried by margins rather than
   a grid `gap` because the help and error lines are absent most of the time,
   and an empty grid track still opens a gap on both sides of itself. */
.field {
  display: grid;
  align-content: start;
}

.field__label,
.field__help {
  margin-bottom: 7px;
}

.field__error {
  margin-top: 7px;
}

/* Two half fields put their label, help, control and error on the SAME four
   rows, so a help or error line on one cannot drag its neighbour's input out
   of line. Named rows, so a field with no help still lands its control in 3. */
@supports (grid-template-rows: subgrid) {
  .field--half {
    grid-row: span 4;
    grid-template-rows: subgrid;
  }

  .field--half .field__label {
    grid-row: 1;
  }

  .field--half .field__help {
    grid-row: 2;
  }

  .field--half .field__control {
    grid-row: 3;
  }

  .field--half .field__error {
    grid-row: 4;
  }
}

.field__label {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wider);
  text-transform: uppercase;
  color: var(--accent-strong);
}

.field__optional {
  color: var(--ink-muted);
  text-transform: none;
  letter-spacing: var(--tracking-wide);
}

.field__help {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  line-height: 1.45;
}

.field__control {
  width: 100%;
  padding: 12px 13px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  font-family: var(--font-body);
  font-size: var(--text-md);
  color: var(--ink);
}

.field__control::placeholder {
  color: var(--ink-muted);
}

.field__control--area {
  min-height: 104px;
  resize: vertical;
  line-height: var(--leading-body);
}

/* A file input cannot be padded like a text input without pushing its button
   off-centre, so the padding is trimmed and the button carries its own. */
.field__control--file {
  padding: 8px 9px;
  font-size: var(--text-base);
}

.field__control--file::file-selector-button {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--ink);
  background: var(--surface-tint);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: 8px 14px;
  margin-right: 12px;
  cursor: pointer;
}

.field__control--file::file-selector-button:hover {
  background: var(--highlight-soft);
}

/* ---------- the error state of a single field ---------- */

.field__control[aria-invalid="true"] {
  border-color: var(--danger);
  border-width: 2px;
  padding: 11px 12px; /* keeps the control the same size as its neighbours */
}

.field__error {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--danger);
}

/* ---------- the photo field's progress line ---------- */

/* Created in JavaScript by the downscaler, not in the markup: without
   JavaScript there is nothing for it to say. Neutral, not an error — the
   error colour is --danger, above. */
.field__status {
  margin-top: 7px;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--ink-muted);
  line-height: 1.45;
}

/* ---------- submit ---------- */

/* The template's own .btn / .btn-ink numbers under this form's own class;
   adopting the shared .btn is a class swap with no visual change. */
.quoteForm__submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-family: var(--font-body);
  font-weight: var(--weight-semibold);
  font-size: var(--text-md);
  padding: 14px 26px;
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--surface-inverse);
  background: var(--surface-inverse);
  color: var(--ink-on-accent);
  cursor: pointer;
  transition: background var(--duration), border-color var(--duration),
    transform var(--duration-fast);
}

.quoteForm__submit:hover {
  background: var(--surface-inverse-deep);
  border-color: var(--surface-inverse-deep);
}

.quoteForm__submit:active {
  transform: translateY(1px);
}

/* All four messages are in the markup and the CSS shows the one `data-state`
   names. `invalid` is NOT `error`: `error` means the submission failed on its
   way to Jim, `invalid` means the browser has not sent it yet. */

.quoteForm__submitBusy,
.quoteForm__submitSent,
.quoteForm__stateMsg {
  display: none;
}

.quoteForm[data-state="sending"] .quoteForm__submitIdle,
.quoteForm[data-state="success"]:not([data-landed]) .quoteForm__submitIdle {
  display: none;
}

.quoteForm[data-state="sending"] .quoteForm__submitBusy {
  display: inline;
}

/* `:not([data-landed])` because the two routes into `success` differ. The
   intercepted submit watched its POST leave and the button really is spent;
   the redirect landing is a fresh page load with a live form under it. */
.quoteForm[data-state="success"]:not([data-landed]) .quoteForm__submitSent {
  display: inline;
}

/* aria-disabled, not disabled: a disabled button drops out of the tab order
   and stops being announced. This rule enforces nothing — `pointer-events` is
   hit-testing, so only the guards in form.js stop a second POST. */
.quoteForm[data-state="sending"] .quoteForm__submit,
.quoteForm__submit[aria-disabled="true"] {
  pointer-events: none;
  opacity: 0.72;
}

/* Zero-sized and absolutely positioned rather than `display: none`, which
   some browsers have historically treated as a reason not to load a frame at
   all. At 0x0 with no offsets it adds no height and makes no scrollbar. */
.quoteForm__postTarget {
  position: absolute;
  width: 0;
  height: 0;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

.quoteForm[data-state="invalid"] .quoteForm__stateMsg[data-when="invalid"],
.quoteForm[data-state="sending"] .quoteForm__stateMsg[data-when="sending"],
.quoteForm[data-state="error"] .quoteForm__stateMsg[data-when="error"],
.quoteForm[data-state="success"] .quoteForm__stateMsg[data-when="success"] {
  display: block;
}

/* `data-landed` is set only when `success` was reached by arriving on
   Forminit's redirect, where the page cannot know who is reading. */
.quoteForm[data-state="success"][data-landed] .quoteForm__stateMsg[data-when="notYou"] {
  display: block;
}

/* The live region is in the page from the first paint, empty: a screen reader
   only announces changes inside a region it was already watching. */
.quoteForm[data-state="idle"] .quoteForm__status {
  margin-bottom: 0;
}

.quoteForm__status {
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  border-left: 3px solid transparent;
  padding-left: 0;
}

.quoteForm:not([data-state="idle"]) .quoteForm__status {
  padding-left: var(--space-xs);
}

.quoteForm[data-state="sending"] .quoteForm__status {
  color: var(--ink-muted);
  border-left-color: var(--ink-muted);
}

.quoteForm[data-state="invalid"] .quoteForm__status,
.quoteForm[data-state="error"] .quoteForm__status {
  color: var(--danger);
  border-left-color: var(--danger);
}

.quoteForm[data-state="success"] .quoteForm__status {
  color: var(--accent-strong);
  border-left-color: var(--accent-strong);
}

/* Focus is moved here by script through a negative `tabindex`, so this element
   is unreachable from the keyboard and its ring is not an indicator anybody
   navigates by. `main:focus` below is the only other one. */
.quoteForm__status:focus {
  outline: none;
}

.quoteForm__fine {
  font-size: var(--text-xs);
  color: var(--ink-muted);
}

/* ========== APP SHELL: skip link, header, nav, brand, footer, floats ==========
   Every selector here is a class — not one bare `header`, `nav` or `footer`
   rule. */

/* Read by `scroll-padding-top` below; a sticky header without it lands every
   anchor jump underneath itself. Measured in Chrome, not assumed: 96px at
   375px wide, 70px from 960px up. Re-measure if the header's contents change. */
:root {
  --header-h: 96px;

  /* The floating buttons and the footer's bottom padding read the same two
     numbers rather than repeating them, which is what drifts. */
  --float-size: 64px;
  --float-inset: 22px;
}

@media (min-width: 960px) {
  :root {
    --header-h: 70px;
  }
}

html {
  scroll-padding-top: calc(var(--header-h) + var(--space-2xs));
}

/* ---------- utilities ---------- */

/* In the accessibility tree, out of the picture. NOT `display: none`, which
   would take it out of the tree as well and leave the link named
   "07804 747681". */
.u-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- skip link ---------- */

/* Moved with `transform`, not a negative `top`: a negative `top` is a real
   position on the page and some engines will scroll to it. It cannot be
   `display: none` either — a hidden element is not focusable. */
.skipLink {
  position: absolute;
  left: var(--gutter);
  top: var(--space-2xs);
  z-index: 100;
  transform: translateY(-200%);
  background: var(--surface-raised);
  color: var(--accent-strong);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  padding: var(--space-2xs) var(--space-xs);
  font-weight: var(--weight-semibold);
  text-decoration: none;
  transition: transform var(--duration);
}

.skipLink:focus-visible {
  transform: translateY(0);
}

/* <main> and the five sections carry tabindex="-1" so an in-page link moves
   focus rather than only scrolling — without it focus stays on <body> in
   several browsers. Negative, so the ring was never a navigable indicator. */
main:focus,
.sec[tabindex="-1"]:focus {
  outline: none;
}

/* ---------- brand lockup ---------- */

.brand {
  grid-area: brand;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-xs);            /* 12px — the template's own .logo gap */
  text-decoration: none;
  color: var(--ink);
}

.brand__mark {
  width: 34px;
  height: 34px;
  flex: none;
}

.brand__ring {
  stroke: var(--surface-inverse);
}

.brand__blades {
  stroke: var(--accent);
}

.brand__name {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--text-lg);
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;         /* the template's own, not --tracking-heading's -0.015em */
}

.brand__tagline {
  display: block;
  font-family: var(--font-mono);
  font-weight: var(--weight-regular);
  font-size: var(--text-3xs);
  letter-spacing: 0.22em;          /* the template's own, not --tracking-widest's 0.2em */
  text-transform: uppercase;
  color: var(--accent-strong);
  line-height: var(--leading-body);
}

/* The tagline goes and the wordmark steps down so the name wraps inside its
   column instead of pushing the CTA off the row. Measured at 375px: the
   template's lockup is 193px and its header button is squeezed to 116px. */
@media (max-width: 559px) {
  .brand__tagline {
    display: none;
  }
}

.brand--inverse {
  color: var(--ink-on-accent);
}

.brand--inverse .brand__ring {
  stroke: var(--line-inverse-strong);
}

.brand--inverse .brand__blades {
  stroke: var(--highlight);
}

.brand--inverse .brand__tagline {
  color: var(--highlight);
}

/* ---------- header ---------- */

.siteHeader {
  position: sticky;
  top: 0;
  z-index: 90;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}

/* Two rows on a phone, one from 960px up, out of one set of markup. The whole
   mobile-nav answer is these two grid-template-areas: no toggle, no panel, no
   duplicated link list, no fourth script. */
.siteHeader__bar {
  display: grid;
  grid-template-areas:
    "brand cta"
    "util  util";
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  column-gap: var(--space-sm);     /* 18px — the template's own .nav gap */
}

/* The template's .btn + .btn-ink + .btn-sm numbers under this component's own
   name; adopting the shared .btn is a class swap with no visual change. */
.siteHeader__cta {
  grid-area: cta;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  white-space: nowrap;
  font-family: var(--font-body);
  font-weight: var(--weight-semibold);
  font-size: var(--text-base-sm);
  padding: 10px var(--space-sm);   /* the template's .btn-sm 10px 18px */
  border-radius: var(--radius-sm);
  border: 1.5px solid var(--surface-inverse);
  background: var(--surface-inverse);
  color: var(--ink-on-accent);
  text-decoration: none;
  transition: background var(--duration), border-color var(--duration),
    transform var(--duration-fast);
}

.siteHeader__cta:hover {
  background: var(--surface-inverse-deep);
  border-color: var(--surface-inverse-deep);
}

.siteHeader__cta:active {
  transform: translateY(1px);
}

/* Row two wraps rather than scrolling sideways: at 320px the four links are
   wider than the line, and a horizontal scroller would put "FAQ" off-screen
   with nothing to say it was there. */
.siteHeader__utility {
  grid-area: util;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0 var(--space-sm);
  border-top: 1px solid var(--line);
  margin-inline: calc(var(--gutter) * -1);   /* the rule runs edge to edge */
  padding-inline: var(--gutter);
}

.siteNav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  list-style: none;
  gap: var(--space-sm);
}

/* min-height is on the link and not on the row, so the tap target is the full
   height of the row even though the text is 13.5px. */
.siteNav__link,
.callLink {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  min-height: 44px;
  padding-inline: var(--space-3xs);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--ink-muted);
  text-decoration: none;
}

.siteNav__link:hover,
.callLink:hover {
  color: var(--ink);
}

/* The offer button top right and the phone number bottom left: the two
   mutually exclusive things a seller does, kept at opposite corners so they
   are not mis-tapped for one another. */
.callLink {
  color: var(--accent-strong);
  font-weight: var(--weight-semibold);
}

.callLink__icon {
  color: var(--accent);
  flex: none;
}

/* One of these two is display:none at any width, so the link's accessible name
   is always its visible text (2.5.3 Label in Name). display:none, not .u-vh:
   the hidden one must leave the tree or the number is announced twice. */
.callLink__full {
  display: none;
}

@media (min-width: 960px) {
  .siteHeader__bar {
    grid-template-areas: "brand util cta";
    grid-template-columns: auto minmax(0, 1fr) auto;
    height: 70px;                  /* the template's own header height */
  }

  .siteHeader__utility {
    justify-content: flex-end;
    gap: var(--space-md);          /* 26px — the template's own link gap */
    border-top: 0;
    margin-inline: 0;
    padding-inline: 0;
  }

  .siteNav__list {
    gap: var(--space-md);
  }

  .siteNav__link,
  .callLink {
    font-size: var(--text-base);   /* the template's .nav a.link size */
    min-height: 0;
    padding-inline: 0;
  }

  .callLink__short {
    display: none;
  }

  .callLink__full {
    display: inline;
  }

  .brand__mark {
    width: 38px;                   /* the template's own logo size */
    height: 38px;
  }

  .brand__name {
    font-size: var(--text-2xl);    /* back to the template's 1.22rem */
  }
}

/* ---------- footer ---------- */

.siteFooter {
  background: var(--surface-inverse-deep);
  color: var(--ink-inverse-muted);
  font-size: var(--text-base);
  padding-top: var(--space-xl);    /* 56px, the template's own */

  /* 44px is the template's own bottom padding; the rest keeps the last line of
     the footer out from under the floating buttons, reading the same two
     variables they are positioned by rather than repeating their numbers. */
  padding-bottom: calc(
    44px + var(--float-size) + var(--float-inset) + env(safe-area-inset-bottom, 0px)
  );
}

.siteFooter__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-lg);
}

@media (min-width: 960px) {
  .siteFooter__grid {
    grid-template-columns: 1.4fr 1fr 1fr;
    gap: 44px;                     /* the template's own .fgrid gap */
  }
}

.siteFooter__brandCol .brand {
  display: inline-flex;
  margin-bottom: var(--space-sm);  /* the template's inline 16px, on the ladder at 18px */
}

.siteFooter__blurb {
  max-width: 36ch;                 /* the template's own inline measure */
}

.siteFooter__heading {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.18em;          /* the template's own */
  text-transform: uppercase;
  color: var(--highlight);
  margin-bottom: var(--space-2xs);
}

.siteFooter__list {
  list-style: none;
  display: grid;
}

/* TARGET SIZE, an inherited defect: measured against the template these links
   are 18px tall and 9px apart, where WCAG 2.5.8 asks 24px and one of them
   dials a phone. display:block plus padding makes the target the whole row. */
.siteFooter__link,
.siteFooter__contactLink {
  display: block;
  padding-block: var(--space-xs);
  color: var(--ink-inverse);
  text-decoration: none;
}

.siteFooter__link:hover,
.siteFooter__contactLink:hover {
  color: var(--ink-on-accent);
  text-decoration: underline;
}

.siteFooter__smallprint {
  border-top: 1px solid var(--line-inverse);
  margin-top: var(--space-lg);
  padding-top: 20px;               /* the template's own */
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  /* NOT --ink-inverse-faint, the template's colour here: it is 4.04:1 on
     --surface-inverse-deep and this line is 11px ordinary text, so AA wants
     4.5:1. --ink-inverse-muted on the same ground is 6.75:1. */
  color: var(--ink-inverse-muted);
}

/* ---------- floating contact buttons ---------- */

/* A row and not a column: two stacked 64px circles are 140px of the right-hand
   edge on a 667px phone. env(safe-area-inset-bottom) because the bottom 34px
   belongs to the system gesture bar, which takes the tap. */
.contactFloat {
  position: fixed;
  right: var(--float-inset);
  bottom: calc(var(--float-inset) + env(safe-area-inset-bottom, 0px));
  z-index: 95;
  display: flex;
  gap: var(--space-xs);
}

.contactFloat__btn {
  width: var(--float-size);
  height: var(--float-size);
  border-radius: var(--radius-round);
  background: var(--surface);
  border: 1.5px solid var(--line);
  display: grid;
  place-items: center;
  box-shadow: var(--shadow-md);
  text-decoration: none;
  transition: transform var(--duration);
}

.contactFloat__btn:hover {
  transform: scale(1.05);
}

/* position: fixed, so the ring is drawn over whatever is behind it, and over
   the dark offer section --accent is 2.79:1. No ancestor can re-point
   --focus-ring here, so a --surface halo makes the ring ground-independent. */
.contactFloat__btn:focus-visible {
  box-shadow: var(--shadow-md), 0 0 0 7px var(--surface);
}

.contactFloat__inner {
  width: 46px;                     /* the template's own inner disc */
  height: 46px;
  border-radius: var(--radius-round);
  display: grid;
  place-items: center;
  color: var(--ink-on-accent);
}

.contactFloat__btn svg {
  width: 22px;                     /* the template's own glyph size */
  height: 22px;
}

.contactFloat__btn--wa .contactFloat__inner {
  background: var(--whatsapp);
}

.contactFloat__btn--wa:hover .contactFloat__inner {
  background: var(--whatsapp-hover);
}

.contactFloat__btn--call .contactFloat__inner {
  background: var(--surface-inverse);
}

.contactFloat__btn--call:hover .contactFloat__inner {
  background: var(--surface-inverse-deep);
}

/* ========== REPEATING COMPONENTS: one rule set per shape inside a section ==========
   Where the template already has a number, keep the number: 10/14/16/20/22/30px
   have no token, and snapping them to the ladder is a redesign. */

/* ---------- the shared button ----------
   .quoteForm__submit and .siteHeader__cta already carry these exact numbers;
   adopting this class in either is a class swap with no visual change. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;                       /* the template's own */
  font-family: var(--font-body);
  font-weight: var(--weight-semibold);
  font-size: var(--text-base);
  padding: 14px 26px;              /* the template's own */
  border-radius: var(--radius-sm);
  border: 1.5px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--duration), border-color var(--duration),
    transform var(--duration-fast);
}

.btn:active {
  transform: translateY(1px);
}

.btn--ink {
  background: var(--surface-inverse);
  color: var(--ink-on-accent);
  border-color: var(--surface-inverse);
}

.btn--ink:hover {
  background: var(--surface-inverse-deep);
}

.btn--line {
  background: transparent;
  color: var(--ink);
  border-color: var(--ink);
}

.btn--line:hover {
  background: var(--surface-tint);
}

/* The label is white on green and therefore TEXT, which is why --whatsapp is
   darkened where it is defined: the template's value is 3.09:1, this 4.63:1. */
.btn--wa {
  background: var(--whatsapp);
  color: var(--ink-on-accent);
  border-color: var(--whatsapp);
}

.btn--wa:hover {
  background: var(--whatsapp-hover);
  border-color: var(--whatsapp-hover);
}

.btn--sm {
  padding: 10px 18px;              /* the template's own */
  font-size: var(--text-sm);
}

/* A button on a dark ground gets .on-inverse from its container, so nothing
   is restated here. */

/* ---------- section head ---------- */
.sectionHead {
  max-width: 640px;                /* the template's own */
}

.sectionHead__kicker {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--accent-strong);
}

/* --text-h2, NOT --text-3xl. The scale's numbered steps top out at 1.3rem
   because the template hard-codes its display sizes. --text-3xl here rendered
   every section heading at half the size the template draws it. */
.sectionHead__title {
  font-size: var(--text-h2);
  font-weight: 700;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-heading);
  margin: 14px 0 16px;             /* the template's own */
}

.sectionHead__intro {
  font-size: var(--text-lg);
  color: var(--ink-muted);
  margin: 0;
}

.on-inverse .sectionHead__title {
  color: var(--ink-inverse);
}

.on-inverse .sectionHead__kicker {
  color: var(--highlight);
}

.on-inverse .sectionHead__intro {
  color: var(--ink-inverse-muted);
}

/* ---------- trust badge ----------
   TWO, not the template's four, and replacements are Jim's to choose. A flex
   row that does not stretch, so the row looks right with two. */
.badgeRow {
  display: flex;
  gap: 26px;                       /* the template's own */
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--ink-muted);
}

.badge::before {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--highlight);
  border: 1.5px solid var(--accent);
  margin-right: 9px;               /* the template's own */
  vertical-align: 1px;
}

.on-inverse .badgeRow {
  color: var(--ink-inverse-muted);
}

/* ---------- step ----------
   `tilt` arrives as an inline --step-tilt custom property, so a fourth step
   with a new angle needs no new CSS rule. It is layout, not motion. */
.stepList {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;                       /* the template's own */
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (max-width: 860px) {
  .stepList {
    grid-template-columns: 1fr;
  }
}

.step {
  background: var(--surface-raised);
  border: 1px solid var(--line);
  padding: 14px 14px 18px;         /* the template's own */
  box-shadow: 0 10px 26px rgb(var(--shadow-color) / 0.07);
  transform: rotate(var(--step-tilt, 0deg));
}

/* The print's photo window; 4 / 3.1 is the template's own ratio. */
.step__window {
  background: linear-gradient(170deg, var(--highlight-soft), var(--surface-tint));
  aspect-ratio: 4 / 3.1;
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}

/* The template's own gradient, kept as written — one of the two values 1.3
   recorded as having no token. */
.step__window::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 20% 0, rgba(255, 255, 255, .55), transparent 55%);
}

.step__number {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--text-numeral);
  color: var(--accent);
  opacity: .9;
  line-height: 1;
}

.step__frame {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: .16em;           /* the template's own, no token */
  text-transform: uppercase;
  color: var(--accent-strong);
  margin: 14px 2px 6px;            /* the template's own */
}

.step__title {
  font-size: var(--text-2xl);
  font-weight: 700;
  margin: 0 2px 7px;               /* the template's own */
}

.step__description {
  font-size: var(--text-base);
  color: var(--ink-muted);
  margin: 0 2px;                   /* the template's own */
}

/* ---------- category tile ---------- */
/* THE COLUMN COUNT FOLLOWS THE DATA: the hairline box closes only when the
   item count divides by the column count. There are TEN categories, so the
   breakpoints are 5, 2 and 1 — divisors of the count, not round numbers. */
.tileGrid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}

@media (max-width: 1000px) {
  .tileGrid {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 520px) {
  .tileGrid {
    grid-template-columns: 1fr;
  }
}

.tile {
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: 26px 24px;              /* the template's own */
  background: transparent;
  transition: background .15s;
}

.tile:hover {
  background: var(--surface-raised);
}

.tile .catIcon {
  width: 32px;
  height: 32px;
  color: var(--accent);
  margin-bottom: 14px;             /* the template's most-used spacing */
}

.tile__name {
  font-size: var(--text-md);       /* template 1.02rem, nearest step */
  font-weight: 700;
  margin: 0 0 4px;                 /* the template's own */
}

.tile__detail {
  font-size: var(--text-base-sm);  /* template 0.86rem, nearest step */
  color: var(--ink-muted);
  margin: 0;
}

/* ---------- benefit card ----------
   NOT cards, despite the name: the template draws two columns of rows
   separated by a hairline, on the section's ordinary light ground. */
.benefitGrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 56px;                     /* the template's own */
}

@media (max-width: 760px) {
  .benefitGrid {
    grid-template-columns: 1fr;
  }
}

.benefit {
  border-top: 1px solid var(--line);
  padding: 26px 0 30px;            /* the template's own */
}

.benefit__tag {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: .18em;           /* the template's own, no token */
  text-transform: uppercase;
  /* --accent-strong, not --accent: this is TEXT, at 11px, and --accent on
     --surface is 4.10:1 — the value every link was moved off. 5.95:1. */
  color: var(--accent-strong);
  margin-bottom: 10px;             /* the template's own */
}

.benefit__title {
  font-size: var(--text-xl);       /* template 1.18rem, nearest step */
  font-weight: 700;
  margin: 0 0 8px;
}

.benefit__description {
  font-size: var(--text-base);
  color: var(--ink-muted);
  margin: 0;
}

/* ---------- FAQ row ----------
   <details>/<summary>: keyboard and screen-reader accessible with no script,
   and find-in-page searches inside a closed one and opens it. */
.faq__row {
  border-top: 1px solid var(--line);
}

.faq__row:last-of-type {
  border-bottom: 1px solid var(--line);
}

.faq__question {
  list-style: none;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 20px;                       /* the template's own */
  padding: 22px 4px;               /* the template's own */
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--text-xl);       /* template 1.12rem, nearest step */
}

/* The question is an <h3> inside the <summary>, so heading navigation reaches
   the four questions. Inline and inheriting, so the summary's flex row and the
   "+" mark are untouched. */
.faq__questionText {
  display: inline;
  font: inherit;
  margin: 0;
  color: inherit;
}

.faq__question::-webkit-details-marker {
  display: none;
}

/* The template's own mark: a "+" that rotates 45 degrees into an x. */
.faq__question::after {
  content: "+";
  font-family: var(--font-mono);
  font-size: 1.3rem;               /* the template's own */
  color: var(--accent);
  flex: none;
  transition: transform .18s;
}

.faq__row[open] .faq__question::after {
  transform: rotate(45deg);
}

.faq__answer {
  padding: 0 4px 24px;             /* the template's own */
  color: var(--ink-muted);
  max-width: 60ch;
  margin: 0;
}

/* ---------- reassurance bullet ----------
   Deliberately not merged with the trust badge: they differ in ground, in
   type, in mark and in what they are for. */
.reassure {
  display: grid;
  gap: 14px;                       /* the template's most-used spacing */
  margin: 0;
  padding: 0;
  list-style: none;
}

.reassure__item {
  position: relative;
  padding-left: 26px;              /* the template's own */
  color: var(--ink-muted);
}

/* A generated mark, so it is in neither the markup nor the accessibility tree
   — the sentence carries the meaning and this is punctuation. */
.reassure__item::before {
  content: "";
  position: absolute;
  left: 0;
  top: .5em;                       /* the template's own */
  width: 10px;
  height: 10px;
  background: var(--accent);
  clip-path: polygon(0 0, 100% 0, 100% 100%);
}

.on-inverse .reassure__item {
  color: var(--ink-inverse);
}

.on-inverse .reassure__item::before {
  background: var(--highlight);
}

/* ---------- film strip ----------
   The holes are one repeating radial-gradient rather than markup, so there is
   no count to keep in step with the width. */
.filmStrip {
  background: var(--surface-inverse);
  overflow: hidden;
  border-block: 1px solid var(--line-inverse-strong);
}

.filmStrip__sprockets {
  height: 30px;                    /* the template's own */
  background-image: radial-gradient(circle at 22px 50%, var(--surface) 5.5px, transparent 6.5px);
  background-size: 46px 30px;      /* the template's own */
  background-repeat: repeat-x;
}

.filmStrip__viewport {
  overflow: hidden;
}

.filmStrip__track {
  display: flex;
  gap: 10px;                       /* the template's own */
  padding: 10px 0;
  width: max-content;
  animation: filmReel 36s linear infinite;
}

.filmStrip__item {
  display: flex;
  align-items: center;
  gap: 12px;                       /* the template's own */
  border: 1px solid var(--line-inverse-strong);
  background: var(--surface-inverse-deep);
  color: var(--ink-inverse);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  letter-spacing: .12em;           /* the template's own, no token */
  text-transform: uppercase;
  padding: 16px 26px;              /* the template's own */
  white-space: nowrap;
}

.filmStrip__index {
  color: var(--highlight);
  font-weight: 500;
}

@keyframes filmReel {
  to { transform: translateX(-50%); }
}

/* ========== THE PAGE: section rhythm, hero, offer ========== */

/* ---------- section rhythm ---------- */
.sec {
  padding: var(--space-2xl) 0;     /* 92px — the template's own rhythm */
}

/* The one tinted band on the page, edged top and bottom so the tile grid's
   own hairlines do not read as the section's edge. */
.sec--tinted {
  background: var(--surface-tint);
  border-block: 1px solid var(--line);
}

/* 52px is the template's own and is not a token step. */
.sec .sectionHead {
  margin-bottom: 52px;
}

/* ---------- hero ---------- */
.hero {
  padding: 78px 0 86px;            /* the template's own */
  position: relative;
  overflow: hidden;
}

.hero__grid {
  display: grid;
  grid-template-columns: 1.05fr .92fr;
  gap: 64px;                       /* the template's own */
  align-items: center;
}

/* The separator is a generated dot, not a character in the copy — Jim's data
   holds four readings, not three bullets. */
.hero__exif {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: .06em;           /* the template's own, no token */
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0;
}

.hero__exif span + span::before {
  content: "·";
  color: var(--accent);
  margin: 0 8px;
}

.hero__heading {
  font-size: var(--text-h1);
  font-weight: 800;
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-heading);
  margin: 18px 0 22px;             /* the template's own */
}

.hero__headingAccent {
  color: var(--accent);
}

.hero__sub {
  font-size: var(--text-xl);
  color: var(--ink-muted);
  max-width: 33em;                 /* the template's own measure */
  margin: 0 0 32px;
}

.hero__ctas {
  display: flex;
  gap: 14px;                       /* the template's most-used spacing */
  flex-wrap: wrap;
  margin-bottom: 30px;             /* the template's own */
}

.hero__right {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 30px;                       /* the template's own */
}

/* ---------- the aperture ----------
   The rotation is the template's own `breathe` keyframe, stopped by the
   blanket `animation: none` in the reduced-motion block above. */
.heroAperture {
  width: 300px;                    /* the template's own */
  max-width: 80%;
  height: auto;
  display: block;
}

.heroAperture__blades {
  transform-origin: 50% 50%;
  animation: breathe var(--duration-breathe) ease-in-out infinite;
}

@keyframes breathe {
  0%, 100% { transform: rotate(0deg); }
  50%      { transform: rotate(14deg); }
}

/* ---------- the quick-offer card ----------
   NOT A FORM: two controls and a link. `.on-inverse` in the markup re-points
   --focus-ring from --accent (2.79:1 here) to --highlight (8.35:1). */
.heroCard {
  background: var(--surface-inverse);
  color: var(--ink-inverse);
  border: 1px solid var(--surface-inverse-deep);
  border-radius: var(--radius-lg);
  padding: 22px 24px;              /* the template's own */
  width: 100%;
  max-width: 360px;                /* the template's own */
  box-shadow: 0 18px 44px rgb(var(--shadow-color) / 0.28);
}

.heroCard__head {
  display: flex;
  justify-content: space-between;
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  letter-spacing: var(--tracking-widest);
  text-transform: uppercase;
  color: var(--highlight);
  margin: 0 0 12px;                /* the template's own */
}

.heroCard__control {
  width: 100%;
  background: var(--surface-inverse-deep);
  /* --ink-inverse-muted, not --line-inverse: these two controls were measured
     at 1.30:1 border and 1.20:1 fill on this card — flat dark blocks. This is
     the dark-ground analogue of --line-strong, 5.61:1, and adds no new hex. */
  border: 1px solid var(--ink-inverse-muted);
  color: var(--ink-inverse);
  border-radius: var(--radius-sm);
  padding: 11px 12px;              /* the template's own */
  font-family: var(--font-body);
  font-size: var(--text-base);
  margin-bottom: 10px;             /* the template's own */
}

.heroCard__control::placeholder {
  color: var(--ink-inverse-muted);
}

/* The template's `.btn-sky`: --ink on --highlight is 11.5:1. */
.btn--sky {
  background: var(--highlight);
  color: var(--ink);
  border-color: var(--highlight);
}

.btn--sky:hover {
  background: var(--highlight-soft);
  border-color: var(--highlight-soft);
}

/* An anchor, not a button, so it needs the width a submit control would have
   had by default. */
.heroCard__go {
  width: 100%;
}

/* ---------- the offer section ----------
   The only dark section. `.on-inverse` is on the element, so every control of
   the quote form inside it inherits the readable focus ring. */
.offer {
  background: var(--surface-inverse);
  color: var(--ink-inverse);
}

.offer__grid {
  display: grid;
  grid-template-columns: .9fr 1.1fr;
  gap: 70px;                       /* the template's own */
  align-items: start;
}

.offer .reassure {
  margin-bottom: 38px;             /* the template's own */
}

.waPanel {
  border: 1px solid var(--line-inverse-strong);
  background: var(--surface-inverse-deep);
  padding: 24px 26px;              /* the template's own */
}

.waPanel__title {
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--ink-inverse);
  margin: 0 0 8px;
}

.waPanel__body {
  font-size: var(--text-base);
  color: var(--ink-inverse-muted);
  margin: 0 0 16px;                /* the template's own */
}

/* ---------- the one breakpoint the page needs ----------
   The template's own, at 960px. The component grids carry their own, because
   their column counts are divisors of counts that live in the data. */
@media (max-width: 960px) {
  .hero__grid,
  .offer__grid {
    grid-template-columns: 1fr;
  }

  .hero__right {
    margin-top: 26px;              /* the template's own */
  }

  .heroCard {
    max-width: 100%;
  }
}
