/* ---- tokens ---- */
/* 98 Churchill — design tokens. Extracted from Figma 06/08/26. Job 2649.
   OWNED BY LEAD. Build agents must not edit this file. */

:root {
  /* ---- Colour (raw hex from Figma nodes; no variables existed in the file) ---- */
  --c-sage: #71867c;
  --c-tan: #d9b498;
  --c-charcoal: #3f4547;
  --c-white: #ffffff;
  /* Form field fill — pale blue, from a live read of form nodes 2:141 / 12:18. Not a brand
     colour and not used anywhere else. Charcoal input text on it is 7.09:1 (passes AA). */
  --c-field: #cddfe4;

  /* ---- Type ----
     LICENCE RESOLVED 06/08/26. Adobe Fonts web-project kit `ndg6ehc` (loaded in src/head.html)
     supplies the real Korolev family. Barlow remains only as the fallback, so a kit failure
     (most likely a missing domain on the web project) degrades to a near-match, not to Times.

     ⚠ WEIGHT GAP — kit `ndg6ehc` currently ships only weights 300 and 700 for both families.
     The design's display type is Korolev Condensed **Medium (500)**, which is NOT in the kit.
     Per the CSS font-matching algorithm a request for 500 resolves DOWN to 300 first, so
     headings currently render Light and read too thin. Fix is to tick "Medium" on the
     Korolev Condensed styles in the Adobe web project — no code change needed here. */
  --font-display: 'korolev-condensed', 'Barlow Condensed', 'Arial Narrow', sans-serif; /* Korolev Condensed Medium 500 */
  --font-body: 'korolev', 'Barlow', system-ui, -apple-system, sans-serif;               /* Korolev Light 300 */
  --font-button: 'Oswald', 'Barlow Condensed', sans-serif;                              /* Oswald Light (Google, OFL) */

  /* Weights, named so no section has to remember them. */
  --fw-display: 500;   /* Korolev Condensed Medium — see the weight gap note above */
  --fw-body: 300;      /* Korolev Light */
  --fw-button: 300;    /* Oswald Light */

  /* Sizes are the Figma values at the 1440 desktop reference width. */
  --fs-display: 28px;
  --lh-display: 34px;
  --fs-nav: 24px;
  --lh-nav: 26px;
  --fs-body: 14px;
  --lh-body: 22px;
  --fs-button: 27px;
  --lh-button: 30px;
  /* Corrected 06/08/26: was 16px from an estimate off the reference PNG. The utility bar is
     14/26 sage on tan, confirmed against the design. */
  --fs-utility: 14px;
  --lh-utility: 26px;

  /* ---- Layout ---- */
  --page-w: 1440px;
  --gutter: 100px;      /* desktop content inset, from Figma x=100 */
  --gutter-mb: 20px;    /* mobile content inset, from Figma x=20 */
  --btn-w: 291px;
  --btn-w-mb: 353px;
  --btn-h: 60px;
  --field-w: 501px;
  --field-w-mb: 353px;
  --field-h: 48px;

  /* ---- Focus ring (accessibility — not in the design, required for AA) ---- */
  --focus-ring: 3px solid #ffffff;
  --focus-offset: 2px;
}

/* ---- base ---- */
/* 98 Churchill — base/reset. OWNED BY LEAD. Build agents must not edit. */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--c-sage);
  color: var(--c-white);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  overflow-x: hidden;
}

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

h1, h2, h3, h4, p { margin: 0; }

a { color: inherit; text-decoration: none; }

button, input, select, textarea { font: inherit; color: inherit; }

/* Accessibility: visible keyboard focus everywhere. Not in the Figma design;
   required for WCAG 2.1 AA (2.4.7). */
:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* Screen-reader-only utility for labels the design omits visually. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link — required for AA keyboard navigation. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 999;
  background: var(--c-charcoal);
  color: var(--c-tan);
  padding: 12px 20px;
  font-family: var(--font-button);
}
.skip-link:focus { left: 0; }

/* Shared page shell: the design is a fixed 1440 canvas, centred, that reflows
   to a single column under 768px. Sections own their internals. */
.page {
  width: 100%;
  max-width: var(--page-w);
  margin: 0 auto;
  position: relative;
}

/* Shared button primitives (Figma: 291x60 desktop, 353x60 mobile, Oswald Light 27/30) */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--btn-w);
  height: var(--btn-h);
  font-family: var(--font-button);
  font-weight: 300;
  font-size: var(--fs-button);
  line-height: var(--lh-button);
  border: 0;
  border-radius: 0;
  cursor: pointer;
  text-align: center;
}
.btn--primary { background: var(--c-tan); color: var(--c-charcoal); }
.btn--secondary { background: var(--c-charcoal); color: var(--c-tan); }

@media (hover: hover) {
  .btn:hover { filter: brightness(0.94); }
}

@media (max-width: 768px) {
  .btn { width: 100%; max-width: var(--btn-w-mb); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ---- section: utility-bar ---- */
/* ===== TOP Contact / utility bar — Figma desktop node 2:8 (1440 x 50) =====
   Every selector is prefixed .s-utility-bar so this section cannot leak styles.

   Figma facts this rebuild is measured against (frame-relative coordinates):
     bar          1440 x 50, fill #d9b498 (--c-tan)
     email text   x 733  y 12  w 316  h 26   Korolev Light 14/26, #71867c (--c-sage)
     phone text   x 1049 y 12  w 170  h 26   same style
     FB icon      x 1260 y 13  18 x 26
     Insta icon   x 1319 y 14  24 x 24
   The absolute canvas is rebuilt as a right-aligned flex row: 100px page inset puts
   the Instagram icon's right edge at 1340 (Figma 1343) and, with the trailing space
   the Figma text boxes carry, the email text starts at 733 — the designed position. */

.s-utility-bar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 40px;
  height: 50px;
  padding: 0 var(--gutter);
  background: var(--c-tan);
  color: var(--c-sage);
  font-family: var(--font-body);
  font-weight: 300;
  /* Figma 2:41 / 2:43 are 14px on 26px leading. NOTE the --fs-utility token is 16px,
     which does not match the design; --fs-body (14px) does. Flagged in the handoff. */
  font-size: var(--fs-body);
  line-height: var(--lh-utility);
}

.s-utility-bar__contact {
  white-space: nowrap;
}

.s-utility-bar__link:hover {
  text-decoration: underline;
}

.s-utility-bar__social {
  display: flex;
  align-items: center;
  gap: 37px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.s-utility-bar__icon {
  display: block;
}

/* Both icons are 18px rounded squares centred in their own box, so centring the
   boxes on one axis lines the squares up. */
.s-utility-bar__icon-img--fb {
  width: 19px;
  height: 26px;
}

.s-utility-bar__icon-img--ig {
  width: 24px;
  height: 24px;
}

/* At (and above) the design width, reproduce the Figma rhythm exactly: the text
   boxes carry their own trailing space rather than the row using an even gap. */
@media (min-width: 1240px) {
  .s-utility-bar {
    gap: 0;
  }

  .s-utility-bar__contact--email {
    min-width: 316px;
  }

  .s-utility-bar__contact--phone {
    min-width: 170px;
  }

  .s-utility-bar__social {
    margin-left: 41px;
  }
}

/* No mobile counterpart exists in the mobile Figma file (12:23 TOP INTRO has a
   hamburger and a phone icon instead), so the bar is removed below 768px. */
@media (max-width: 768px) {
  .s-utility-bar {
    display: none;
  }
}

/* ---- section: nav-intro ---- */
/* ===== NAV / INTRO — Figma desktop 2:36 · mobile 12:23 (393 x 1320) =====
   Every selector is prefixed .s-nav-intro so this section cannot leak styles.

   Desktop Figma geometry, frame-relative (the frame itself sits at page y=50):
     wordmark 2:2      x 100  y 56   187 x 196
     nav "Homes" 2:61  x 415  y 64   · "Prospect" 2:62 x 523 y 65
     buttons 2:63/2:67 x 732 / 1048  y 45   291 x 60 each  (25px apart, right edge 1339)
     lede 2:74         x 100  y 297  w 292
     body 2:75         x 100  y 595  w 292   (two paragraphs, 15px apart)
     button 2:89       x 101  y 844  291 x 60
     hero 2:72         x 416  y 154  924 x 750
   Left column and hero both finish at y=904 frame-relative (page 954).

   ⚠ THE SAGE BLOCK IS 931 TALL, NOT 1046 (designer feedback F4, "this gap is much too big").
   The 2:36 frame reports h=1046, but frames overlap in this file and DESIGN-SPEC warns the
   bounds are unreliable — 1046 is nominal. The sage ends where the tan band actually starts:
   Rectangle 5 (2:71) begins at page y=981. Sage therefore runs page 50 -> 981 = 931, leaving
   27px of sage below the last button (page 954). Sizing from the frame put 115px of dead
   sage between the intro and A Modern Address. Never size a band off a frame height here;
   read the next band's own y. Regenerate with:
     python3 tools/figma-layout.py design/figma-refs/v2/desktop.json DESKTOP

   Mobile Figma geometry:
     wordmark 2:2   x 19  y 15   97 x 102
     phone 21:2     x 224 y 31   61.2 x 61.3
     menu 1:7       x 320 y 21   73 x 73   (bars 42.58 x 3, centred, 12.6px pitch)
     hero 1:47      x 0   y 131  510 x 340 — wider than the 393 frame, so it bleeds
                                             off the right edge (left-anchored crop)
     lede 3:2       x 20  y 496  w 353
     body 5:23      x 20  y 729  w 353
     button 5:52    x 20  y 1009 353 x 60

   Nothing here uses absolute positioning: the canvas is rebuilt as a flex header
   plus a two-column grid that collapses to one column below 768px. */

.s-nav-intro {
  background: var(--c-sage);
}

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

.s-nav-intro__header {
  position: relative; /* containing block for the mobile menu panel */
  display: flex;
  /* The design is a fixed 1440 canvas and has no opinion about tablet widths. The
     header's designed content needs 1229px; below that the button pair wraps onto a
     second right-aligned row rather than overflowing the viewport. Nothing wraps at
     or above 1229px, so the designed geometry is untouched. */
  flex-wrap: wrap;
  row-gap: 20px;
  align-items: flex-start;
  padding: 45px var(--gutter) 0;
}

/* The wordmark (196 tall, from y=56) is taller than the 60px nav row and overhangs
   into the empty sage band above the intro copy. The negative bottom margin lets the
   header box finish at y=154 — exactly where the hero image starts — so the hero is
   not pushed down. The overhang lands in the intro column's own 143px of top padding. */
.s-nav-intro__brand {
  flex: none;
  margin: 11px 0 -98px;
}

.s-nav-intro__brand img {
  width: 187px;
  height: auto;
}

.s-nav-intro__nav {
  /* wordmark ends at x=287, "Homes" starts at x=415; 128/1440 = 8.889vw, so the inset
     is exact at the design width and gives ground on narrower screens. */
  margin: 19px 0 0 clamp(24px, 8.889vw, 128px);
}

.s-nav-intro__menu {
  display: flex;
  gap: 41px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.s-nav-intro__menu a {
  display: inline-block;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: var(--fs-nav);
  line-height: var(--lh-nav);
  color: var(--c-tan);
}

.s-nav-intro__menu a:hover {
  text-decoration: underline;
}

/* Mobile-only controls: laid out here, revealed in the breakpoint below. */
.s-nav-intro__phone {
  display: none;
}

.s-nav-intro__phone img {
  width: 61.2px;
  height: 61.3px;
}

.s-nav-intro__burger {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12.6px;
  width: 73px;
  height: 73px;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
}

.s-nav-intro__burger img {
  width: 42.5833px;
  height: 3px;
}

.s-nav-intro__actions {
  display: flex;
  gap: 25px;
  margin-left: auto;
}

/* ---------- intro: copy column + hero ---------- */

.s-nav-intro__intro {
  display: grid;
  /* 292 + 24 + 924 = 1240 = 1440 minus the two 100px insets, so the proportional
     columns land on the designed widths exactly at 1440. */
  grid-template-columns: 292fr 924fr;
  column-gap: 24px;
  /* 27px, not 142px. Both columns finish at page y=954 and the tan band 2:71 starts at
     page y=981, so 27px is all the sage that sits below the button. 142px came from
     back-solving the nominal 1046 frame height and is the whole of feedback F4. */
  padding: 0 var(--gutter) 27px;
}

.s-nav-intro__col {
  min-width: 0;
  padding-top: 143px; /* lede y=297 against hero y=154 */
}

/* Figma's text boxes are fixed-height with the type top-aligned, so a box is usually taller
   than the lines inside it and its height is NOT the spacing. Only the next node's y is.
   Desktop: 2:74 box is 347+283, but Korolev Condensed 28/34 sets 8 lines = 272, so the type
   ends at 619 and 2:75 starts at 645 — a 26px gap, not the 15px the box arithmetic implies. */
.s-nav-intro__lede {
  margin: 0 0 26px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  color: var(--c-tan);
  text-transform: uppercase;
}

.s-nav-intro__copy {
  /* Same rule as the lede above: 2:75's box is 645+234 but its type (14/22, the one node in
     the design that is not 26 leading) sets 213, so it ends at 858 and the button 2:89
     starts at 894 — 36px. */
  margin-bottom: 36px;
  /* Korolev Light maps to 300; base.css sets no weight, so without this the copy
     renders at 400 and reads heavier than the design. */
  font-weight: 300;
  color: var(--c-white);
}

.s-nav-intro__copy p + p {
  margin-top: 15px;
}

/* <picture> is inline by default; blockify it so it cannot introduce a baseline gap
   under the image. */
.s-nav-intro__media picture,
.s-nav-intro__endpiece picture {
  display: block;
}

.s-nav-intro__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 924 / 750;
  object-fit: cover;
  /* Figma crops the source to left:-9.34% / width:121.63% of the frame, which is
     object-position 43% on a cover fit. */
  object-position: 43% 50%;
}

/* Mobile-only closing image (Figma 12:24). Hidden on desktop, where the same asset
   belongs to the A Modern Address section. */
.s-nav-intro__endpiece {
  display: none;
}

/* ---------- mobile (mobile frame 12:23) ---------- */

@media (max-width: 768px) {
  .s-nav-intro__header {
    /* No right inset: the 73px menu button sits flush to the edge, which puts its
       bars 15px in, as designed. */
    padding: 15px 0 0 var(--gutter-mb);
  }

  .s-nav-intro__brand {
    margin: 0;
  }

  .s-nav-intro__brand img {
    width: 97px;
  }

  .s-nav-intro__phone {
    display: block;
    order: 2;
    margin: 16px 34.8px 0 auto; /* phone y=31, 34.8px clear of the menu box */
  }

  .s-nav-intro__nav {
    order: 3;
    margin: 6px 0 0; /* menu y=21 */
  }

  .s-nav-intro__burger {
    display: flex;
  }

  .s-nav-intro__actions {
    display: none;
  }

  /* MISSING STATE: the mobile design has a hamburger but no open-menu frame, so the
     panel is built from the design's own nav-link style. Overlays the hero rather
     than pushing it down. */
  .s-nav-intro__menu {
    display: none;
  }

  .s-nav-intro__nav[data-open='true'] .s-nav-intro__menu {
    display: flex;
    position: absolute;
    z-index: 2;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 20px;
    padding: 20px var(--gutter-mb);
    background: var(--c-sage);
  }

  .s-nav-intro__intro {
    grid-template-columns: 1fr;
    padding: 0;
  }

  .s-nav-intro__media {
    order: -1;
    margin-top: 14px; /* hero y=131 against a header that ends at 117 */
  }

  .s-nav-intro__media img {
    aspect-ratio: 393 / 340;
    object-position: 0% 50%; /* the source is 510 wide in a 393 frame: left-anchored */
  }

  .s-nav-intro__col {
    /* The 31px bottom padding is the designed gap between the button (ends y=1069)
       and the closing image (starts y=1100). */
    padding: 25px var(--gutter-mb) 31px;
  }

  .s-nav-intro__endpiece {
    display: block;
  }

  /* The height is pinned by aspect-ratio so the section height never depends on the
     intrinsic size of the file (the source is 2752x1536). */
  .s-nav-intro__endpiece img {
    width: 100%;
    height: auto;
    aspect-ratio: 393 / 220;
    object-fit: cover;
  }

  /* Feedback F3, "this text is split, should be together". 9px was read straight off the
     Figma box arithmetic (3:2 box 496+224 = 720, 5:23 starts 729). But 3:2 is a fixed-height
     box with 20px of slack: Korolev Condensed 28/34 sets 6 lines = 204, so the type ends at
     700 and the designed gap to the body is 29px, not 9px. At 9px the whole intro stack —
     body, button and the closing image 12:24 — rendered 20px above its designed y, the
     closing image cut in at 1080 instead of 1100, and the section came out 1300 against the
     Figma 1320. 29px puts 5:23 back on y=729, 5:52 on 1009 and 12:24 on 1100, so both text
     blocks sit wholly on sage with the sage/tan edge landing at 1320 where Figma puts it.
     Row-scan evidence: figma-mobile-full.png has 41px of clear sage between the lede's last
     line of ink (694) and the body's first (735); the build had 22px. */
  .s-nav-intro__lede {
    margin-bottom: 29px;
  }

  .s-nav-intro__copy {
    /* INFERRED: Figma metadata carries no font sizes and the mobile design-context
       call was blocked by the plan limit. 15/26 is measured off
       design/screenshots/figma-mobile-full.png (accurate to about 1px); desktop is
       14/22. Confirm against Figma when calls are available again. */
    margin-bottom: 31px;
    font-size: 15px;
    line-height: 26px;
  }
}

/* ---- section: modern-address ---- */
/* ============================================================================
   A MODERN ADDRESS — Figma desktop 2:84 / mobile 12:21
   Every selector is prefixed with .s-modern-address.

   Geometry is derived from CHILD node coordinates in
   design/figma-refs/desktop-metadata.xml, converted from absolute Figma
   positioning to flow layout. Child y values in that file are relative to the
   2:84 frame origin (y=204), so absolute page y = 204 + child y. The frame box
   itself (h=777) is useless — its children run to y≈3655.

   MEASURED TYPE CORRECTION: body copy in this section runs 14px / 26px, not the
   14px / 22px documented for the nav-intro section. Confirmed by row-scanning
   design/screenshots/figma-desktop-full.png — three consecutive lines inside
   2:98 sit exactly 18.0 screenshot px apart (18.0 / 0.682667 = 26.4 native),
   against 15.0 px (= 22 native) for the calibration node 2:75. Paragraph
   spacing is 15px in both, and the mobile render measures the same 26px pitch.
   --lh-body is therefore overridden locally, not used.
   ============================================================================ */

.s-modern-address {
  /* Belt and braces against a sub-pixel seam between the two grounds. */
  background: var(--c-tan);
}

/* Shared content measure: 1240px inside a 100px gutter at the 1440 reference. */
.s-modern-address__inner {
  max-width: calc(var(--page-w) - var(--gutter) * 2);
  margin-inline: auto;
  /* flow-root so the streetscape's negative bottom margin is contained and
     sizes the tan ground instead of escaping it. */
  display: flow-root;
}

/* ---------------------------------------------------------------- grounds ---
   2:71 "Rectangle 5" — tan, 1440x886, absolute y 981..1867
   2:96 "Rectangle 6" — sage, 1440x1980, absolute y 1867..3847
   Fills sampled from the Figma render: exactly #d9b498 and #71867c.          */

.s-modern-address__intro {
  background: var(--c-tan);
  /* 34 = 2:82 top (1015) - ground top (981). Height then resolves to exactly
     886 via the streetscape's -463px bottom margin. */
  padding: 34px var(--gutter) 0;
  display: flow-root;
}

.s-modern-address__lower {
  background: var(--c-sage);
  /* 490 = 2:92 top (2357) - sage ground top (1867) */
  padding: 490px var(--gutter) 48px;
}

/* ------------------------------------------------------------- intro row ---
   2:82 image x=101 w=817 · 2:86/2:87 copy column x=946 w=292, gutter 28.
   Percentages are of the 1240 measure: 817, 28 and 292 respectively. The
   remaining 8.3% to the right is empty in the design. */

.s-modern-address__intro-row {
  display: flex;
  align-items: center;
}

.s-modern-address__fig--dining { flex: 0 0 65.887%; }

.s-modern-address__intro-copy {
  flex: 0 0 23.548%;
  margin-left: 2.258%;
  /* Figma sits the copy block 18px ABOVE the photo's centre line (block centre
     244 vs photo centre 262, both relative to the tan ground). A 36px bottom
     margin under align-items:center reproduces that offset without pinning the
     block to a fixed y, which matters because the substitute typeface wraps
     differently from Korolev. */
  margin-bottom: 36px;
}

/* ------------------------------------------------------------------ type --- */

.s-modern-address__title,
.s-modern-address__panel-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: 0;
  text-transform: uppercase;
}

.s-modern-address__panel-title { margin-bottom: 15px; }

.s-modern-address__title { color: var(--c-charcoal); }

.s-modern-address__lede,
.s-modern-address__panel p {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: var(--fs-body);
  line-height: 26px; /* measured; see header note */
  letter-spacing: 0;
}

.s-modern-address__lede { color: var(--c-charcoal); }

/* 2:87 top (998) - 2:86 bottom (974) */
.s-modern-address__title + .s-modern-address__lede { margin-top: 24px; }

.s-modern-address__panel p { margin-bottom: 15px; }
.s-modern-address__panel p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- figures ---
   Every figure is an aspect-ratio box holding a cover-cropped image, matching
   Figma's image-fill behaviour. The box reserves layout space before the image
   decodes, so nothing shifts (CLS). */

.s-modern-address__fig {
  position: relative;
  margin: 0;
  overflow: hidden;
}

.s-modern-address__fig picture {
  position: absolute;
  inset: 0;
  display: block;
}

.s-modern-address__fig img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.s-modern-address__fig--dining   { aspect-ratio: 817 / 456; }
.s-modern-address__fig--street   { aspect-ratio: 1239 / 826; }
.s-modern-address__fig--bathroom { aspect-ratio: 608 / 405; }
.s-modern-address__fig--living   { aspect-ratio: 608 / 406; }
.s-modern-address__fig--balcony  { aspect-ratio: 607 / 909; }

/* 2:80 runs 1504..2330 while the tan ground ends at 1867 — 463px of the photo
   sits over the sage ground. Contained inside the tan ground's flow with a
   -463px bottom margin (so the ground measures exactly 886), then lifted above
   the sage ground's background by becoming a positioned element. */
.s-modern-address__fig--street {
  margin-top: 33px; /* 1504 - 2:82 bottom (1471) */
  margin-bottom: -463px;
  position: relative;
  z-index: 1;
}

/* ------------------------------------------------------------- two columns ---
   Left  x=100 w=608 : 2:92, 2:94, tan panel, [D1 slot]
   Right x=734 w=607 : 2:93, white panel, actions
   (1240 - 26) / 2 = 607 per column — Figma alternates 607/608, a 1px rounding
   inconsistency in the source file. The columns flow independently, which is
   what reproduces the design's deliberate vertical stagger. */

.s-modern-address__cols {
  display: flex;
  align-items: flex-start;
  gap: 26px;
}

.s-modern-address__col {
  flex: 1 1 0;
  min-width: 0;
}

/* ⚠ CORRECTED 09/08/26 — the previous comment here claimed "2:92 bottom (2762) ==
   2:94 top (2762): the pair touches in the design". The coordinates say that, and the
   coordinates are misleading. Figma's absoluteBoundingBox (and absoluteRenderBounds)
   both report the two rectangles meeting at 2762, but the PHOTO INSIDE 2:94 is inset
   from its own rect, so what actually paints is a 22px sage gap.

   Measured from the reference render rather than the JSON — a pixel column scan at
   x=400 (tools/scan-col.mjs) gives:
       Figma:  y 2762-2783  SAGE  22px
       build:  y 2763-2763  SAGE   1px
   The three gaps above this one (15, 33, 27px) match Figma exactly, which is what
   confirms the method rather than the reading.

   Lesson: a Figma bounding box describes the frame, not the ink. Where a gap is in
   question, scan the render.

   Single-class selectors deliberately — each modifier occurs exactly once, and
   flat specificity lets the mobile query reset them. */
.s-modern-address__fig--living     { margin-top: 22px; }
.s-modern-address__panel--tan      { margin-top: 69px; }
.s-modern-address__panel--charcoal { margin-top: 36px; }
.s-modern-address__panel--white    { margin-top: 93px; }
.s-modern-address__actions         { margin-top: 66px; }

/* ----------------------------------------------------------------- panels ---
   Three grounds, three type pairings, all sampled from the Figma render:
     2:97  tan       #d9b498 ground, charcoal type
     2:100 white     #ffffff ground, charcoal type
     2:103 charcoal  #3f4547 ground, tan type   (the D1 slot — styled ready)
   Padding is per-panel because Figma uses three different insets for three
   sibling panels. Reproduced EXACTLY, not normalised — Keith 06/08/26: match
   the design 100%. Every value below is the text node's box measured against
   its own rectangle's box in design/figma-refs/v2/desktop.json, not an
   estimate off the render:

     rect / text     left  right   top  bottom   check
     2:97  / 2:98      33     77    25      35   33+498+77 = 608, 25+205+35 = 265
     2:100 / 2:101     42     33    30      24   42+533+33 = 608, 30+256+24 = 310
     2:103 / 2:104     36     36    38     -14   36+536+36 = 608, 38+394    = 432

   Two corrections this made, both against values previously written here from
   the reference PNG rather than the node boxes:
     - 2:97's right inset is 77, not 78 (text 132..630 inside rect 99..707).
     - 2:103's text OVERFLOWS its rectangle by 14px (text 3576..3970, rect
       3538..3956). A negative padding cannot be expressed, so bottom is 0 and
       min-height holds the 418 rect. This is a defect in the source file, not
       in the build: the designer's replacement D1 copy is taller than the box
       it was dropped into. Flagged, not corrected — that is the designer's
       call, per the instruction above.

   Each panel also carries the min-height of its Figma rectangle. Those
   rectangles are drawn at a fixed size with an independent text node laid over
   them, so the rect height is design intent, not a by-product of the copy —
   and reproducing it keeps the panels at their designed size instead of
   shrinking to fit the substitute typeface, which wraps shorter than Korolev.
   min-height, not height, so the box still grows if the real typeface (or
   replacement D1 copy) needs more room.                                      */

.s-modern-address__panel--tan {
  background: var(--c-tan);
  color: var(--c-charcoal);
  padding: 25px 77px 35px 33px; /* 2:98 in 2:97 */
  min-height: 265px; /* 2:97 */
}

.s-modern-address__panel--white {
  background: var(--c-white);
  color: var(--c-charcoal);
  padding: 30px 33px 24px 42px; /* 2:101 in 2:100 — already exact */
  min-height: 310px; /* 2:100 */
}

.s-modern-address__panel--charcoal {
  background: var(--c-charcoal);
  color: var(--c-tan);
  /* 2:104 in 2:103. Bottom is 0 because the designed inset is -14 — see the
     block comment above; min-height, not padding, holds the rect height. */
  padding: 38px 36px 0 36px;
  min-height: 418px; /* 2:103 — grew from 262 when the designer supplied the D1 copy 06/08/26 */
}

/* ---------------------------------------------------------------- actions ---
   2:111 x=731 w=293 · 2:114 x=1049 w=292 → 291 + 25 + 291 = 607, exactly the
   right column. .btn owns all styling; this only positions. */

.s-modern-address__actions {
  display: flex;
  gap: 25px;
}

/* ------------------------------------------------- wide-viewport bleed (F5) ---
   > "There's a odd gap down both side of the site, maybe 10 pixels that
   >  shouldn't be there."

   integration.css (lead-owned) bleeds every direct child of .page by giving it
   transparent side borders, so above 1440 this SECTION already spans the
   viewport and its content box lands at exactly 1440 centred. This section is
   the only one with a SECOND ground inside that content box, so the sage
   .__lower still stopped at 1440 and the section's own tan showed as a strip
   either side of it — the same defect, one level down.

   The border technique cannot be reused here: .__lower's containing block is
   the section's 1440 content box, so a border would eat into 1440 rather than
   escape it. Negative inline margins are what escape a fixed containing block.
   .__inner is max-width 1240 + margin-inline:auto, so it recentres itself and
   the 100px gutter is unchanged.

   .__intro is deliberately NOT included: its ground is tan and the section's
   own background is the same tan, so the strip either side of it is already
   invisible. Bleeding it as well would be a no-op that put the streetscape's
   load-bearing -463px bottom margin and the flow-root containment (which size
   the tan ground to exactly 886) at risk for no visual gain.

   Nothing here applies at or below 1440 — the reference render is untouched. */

@media (min-width: 1441px) {
  .s-modern-address__lower {
    margin-left: calc((var(--page-w) - 100vw) / 2);
    margin-right: calc((var(--page-w) - 100vw) / 2);
  }
}

/* =============================================================== mobile ===
   Mobile node 12:21 (393 wide, 20px copy gutter). Reading order in the mobile
   design is reproduced exactly: heading, streetscape, lede, bathroom, balcony,
   living, tan panel, white panel, [D1 slot], actions.

   Both grounds must keep painting, so the layout wrappers INSIDE each ground
   collapse to display:contents; the leaves then become flex items of the
   ground itself and `order` reproduces the mobile sequence.

   PHOTOS AND PANELS ALTERNATE SIDES. This is deliberate design intent, not a
   Figma rounding artefact. A previous pass normalised every photo to true
   full-bleed on the reasoning that "373 and 422 on a 393 frame is clearly
   reaching for edge-to-edge"; the designer rejected that in feedback round 1
   ("These images need to alternate sides like the Figma layout" / "These
   panels need to alternate sides like the Figma layout"). Restored exactly.

   Read from design/figma-refs/v2/mobile.json on the 393px frame:

     node    element                       x     w    edge behaviour
     5:34    streetscape R5_D7145          0   422    flush LEFT, bleeds 29 right
     5:36    bathroom    R5_D6767          0   373    flush LEFT, 20 gap right
     5:37    balcony     R5_D6737         20   353    inset BOTH sides
     5:38    living      R5_D6698         20   373    flush RIGHT
     5:39    tan panel                     0   373    flush LEFT, 20 gap right
     5:47    white panel                  20   373    flush RIGHT
     5:50    charcoal panel                0   373    flush LEFT, 20 gap right

   Both grounds are padded 20px inline, so every leaf stretches to 353. Each
   element's inline margins pull it back out to its designed box:
     -20 / -49  -> 422 at x=0     |   -20 /   0  -> 373 at x=0
       0 /   0  -> 353 at x=20    |     0 / -20  -> 373 at x=20
   5:34 genuinely exceeds the 393 frame — it is allowed to bleed (body carries
   overflow-x: hidden) rather than being scaled to fit, which is what cost the
   previous pass 19px of its designed 281px height.

   Body copy and the two buttons keep the 20px gutter throughout, and the panel
   text keeps its own padding — the alternation moves the panel BOX, not the
   text inset.
   ========================================================================== */

@media (max-width: 768px) {

  /* ⛔ CLIP THE BLEED, DO NOT TRIM IT.
     `--fig--street` below is deliberately 29px wider than the frame, because Figma node 5:34 is
     x=0 w=422 inside a 393 frame: the designer ran the photo off the right edge. Figma CLIPS at
     the frame boundary, so in the design that reads as a full-bleed crop. A browser does not
     clip — it grows the scrollable area, so the whole page scrolled sideways by 29px on every
     phone (measured 24/08/26: documentElement.scrollWidth 404 in a 375 viewport).

     Clipping at the SECTION reproduces Figma exactly, because the section spans the viewport, so
     the photo is cropped at the same edge the design crops it at. Narrowing the photo instead
     would change the crop the designer drew, which is a different picture, not a bug fix.

     `clip` rather than `hidden`: hidden makes this a scroll container and forces the y axis to
     auto, which would cut the bathroom photo's deliberate -123px lift into the section above.
     `overflow-x: clip` leaves `overflow-y: visible` intact, so the vertical bleed still works. */
  .s-modern-address {
    overflow-x: clip;
  }

  /* Mobile places this photo in TOP INTRO (12:24) instead, owned by nav-intro. */
  .s-modern-address__fig--dining { display: none; }

  .s-modern-address__inner,
  .s-modern-address__intro-row,
  .s-modern-address__intro-copy,
  .s-modern-address__cols,
  .s-modern-address__col {
    display: contents;
  }

  .s-modern-address__intro {
    display: flex;
    flex-direction: column;
    /* 18 = 5:33 top. 135 bottom = 123px of bathroom overlap + the design's
       12px gap between the lede (5:35, ends 500) and 5:36 (starts 512). */
    padding: 18px var(--gutter-mb) 135px;
  }

  .s-modern-address__lower {
    display: flex;
    flex-direction: column;
    gap: 13px; /* the design's dominant mobile block gap */
    padding: 0 var(--gutter-mb) 36px;
  }

  /* Reset every desktop offset — gap and the margins below own the rhythm. */
  .s-modern-address__panel--tan,
  .s-modern-address__panel--white,
  .s-modern-address__panel--charcoal,
  .s-modern-address__actions {
    margin-top: 0;
  }

  .s-modern-address__title { order: 1; }

  /* 5:34 x=0 w=422 — flush LEFT and 29px past the right edge of the frame. */
  .s-modern-address__fig--street {
    order: 2;
    /* 5:33 bottom (52) -> 5:34 top (70), and 5:34 bottom (351) -> 5:35 top (376) */
    margin-block: 18px 25px;
    margin-left: calc(-1 * var(--gutter-mb));
    margin-right: calc(-1 * (var(--gutter-mb) + 29px));
    z-index: auto;
  }

  .s-modern-address__lede { order: 3; }

  /* 5:36 x=0 w=373 — flush LEFT, 20px gap at the right.
     It also straddles the ground boundary (tan box 5:31 ends at 635, the photo
     runs 512..761) — 123px of it sits above the sage ground. */
  .s-modern-address__fig--bathroom {
    order: 1;
    margin-top: -123px;
    margin-left: calc(-1 * var(--gutter-mb));
    margin-right: 0;
  }

  /* 5:37 x=20 w=353 — the only element inset on BOTH sides. */
  .s-modern-address__fig--balcony {
    order: 2;
    margin-inline: 0;
  }

  /* 5:38 x=20 w=373 — flush RIGHT (20 + 373 = 393). */
  .s-modern-address__fig--living {
    order: 3;
    margin-left: 0;
    margin-right: calc(-1 * var(--gutter-mb));
  }

  /* 5:39 x=0 w=373 — flush LEFT. */
  .s-modern-address__panel--tan {
    order: 4;
    margin-top: 2px; /* 13 + 2 = 15 */
    margin-left: calc(-1 * var(--gutter-mb));
    margin-right: 0;
  }

  /* 5:47 x=20 w=373 — flush RIGHT. */
  .s-modern-address__panel--white {
    order: 5;
    margin-left: 0;
    margin-right: calc(-1 * var(--gutter-mb));
  }

  /* 5:50 x=0 w=373 — flush LEFT. */
  .s-modern-address__panel--charcoal {
    order: 6;
    margin-left: calc(-1 * var(--gutter-mb));
    margin-right: 0;
  }

  .s-modern-address__actions { order: 7; }

  /* Figma's mobile panel insets are inconsistent panel to panel, exactly as
     the desktop ones are. Reproduced EXACTLY rather than normalised — same
     instruction, same reason as the desktop block above. Each value is the
     text node's box against its own rectangle's box in
     design/figma-refs/v2/mobile.json:

       rect / text    left  right   top  bottom   check
       5:39 / 5:40      20     18    25      24   20+335+18 = 373, 25+257+24 = 306
       5:47 / 5:48      26     20    30      10   26+327+20 = 373, 30+371+10 = 411
       5:50 / 5:51      20     24    25      11   20+329+24 = 373, 25+537+11 = 573

     The bottom insets previously recorded here (10/24/62) do not survive a
     read of the v2 node boxes — they were carried over from the v1 reference.
     The derived values above each close their rectangle to the pixel. */

  .s-modern-address__panel--tan      { padding: 25px 18px 24px 20px; }
  .s-modern-address__panel--white    { padding: 30px 20px 10px 26px; }
  .s-modern-address__panel--charcoal { padding: 25px 24px 11px 20px; }

  /* Mobile rectangle heights: 5:39, 5:47, 5:50 */
  .s-modern-address__panel--tan      { min-height: 306px; }
  .s-modern-address__panel--white    { min-height: 411px; }
  .s-modern-address__panel--charcoal { min-height: 573px; } /* 5:50 — was 329 before the D1 copy landed */

  .s-modern-address__actions {
    flex-direction: column;
    align-items: stretch;
    gap: 28px;         /* 5:53 bottom (2745) -> 12:16 top (2773) */
    margin-top: 20px;  /* + the 13px flex gap = the design's 33px */
  }
}

/* ---- section: live-well ---- */
/* ============================================================================
   DESIGNED TO LIVE WELL — Figma desktop 2:170 / mobile 12:22
   Every selector is prefixed with .s-live-well.

   Child coordinates in design/figma-refs/desktop-metadata.xml are relative to
   the 2:170 frame origin (page y=3847), so they read directly as offsets from
   this section's own top.

   Type follows the same measured values as the modern-address section: display
   28/34 uppercase, body 14px / 26px (NOT --lh-body's 22 — verified by
   row-scanning both reference PNGs; mobile measures the same 26px pitch).
   ============================================================================ */

.s-live-well {
  /* 2:121 "Rectangle 7" — 1440x1125, fill sampled at exactly #d9b498 */
  background: var(--c-tan);
  color: var(--c-charcoal);
  /* 49 = 2:124 top · 61 = 1125 - row-2 bottom (1064) */
  padding: 49px var(--gutter) 61px;
}

.s-live-well__inner {
  max-width: calc(var(--page-w) - var(--gutter) * 2);
  margin-inline: auto;
}

/* -------------------------------------------------------------- intro row ---
   2:122 copy x=100 w=397 · 2:124 photo x=521 w=818, 24px gutter between.
   Percentages are of the 1240 measure. The copy block is optically centred
   against the 578-tall photo (photo centre 338, copy centre 351). */

.s-live-well__intro {
  display: flex;
  align-items: center;
}

.s-live-well__copy { flex: 0 0 32.016%; }

/* The 24px gutter is set further down, AFTER the shared `.s-live-well__fig
   { margin: 0 }` reset — declared here it would be clobbered by it. */
.s-live-well__fig--walking { flex: 0 0 65.968%; }

/* ------------------------------------------------------------------ type --- */

.s-live-well__title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-display);
  line-height: var(--lh-display);
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--c-charcoal);
}

.s-live-well__lede {
  margin-top: 15px; /* Figma paragraph spacing */
  font-family: var(--font-body);
  font-weight: 300;
  font-size: var(--fs-body);
  line-height: 26px; /* measured; see header note */
  letter-spacing: 0;
  color: var(--c-charcoal);
}

/* ---------------------------------------------------------------- figures ---
   Aspect-ratio boxes with cover-cropped images, matching Figma's image-fill
   behaviour and reserving layout space before decode (protects CLS). */

.s-live-well__fig {
  position: relative;
  margin: 0;
  overflow: hidden;
}

.s-live-well__fig picture {
  position: absolute;
  inset: 0;
  display: block;
}

.s-live-well__fig img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.s-live-well__fig--walking { aspect-ratio: 818 / 578; }
.s-live-well__fig--produce     { aspect-ratio: 608 / 403; }
.s-live-well__fig--bar         { aspect-ratio: 608 / 406; }

/* 2:124 x=521 - 2:122 right edge (497) = 24px gutter, 1.935% of the 1240
   measure. Declared here, after the `margin: 0` reset above, or it is lost. */
.s-live-well__fig--walking { margin-left: 1.935%; }

/* ------------------------------------------------------------------ pair ---
   2:125 x=100 w=608 · 2:126 x=737 w=608. The 26px gap (and 607px columns) is
   normalised to match the modern-address gallery: Figma's own values here are
   a 29px gap with the right-hand photo overshooting the 100px gutter by 5px.
   Reported rather than reproduced. */

.s-live-well__pair {
  display: flex;
  gap: 26px;
  margin-top: 31px; /* 658 - 627 */
}

.s-live-well__pair > .s-live-well__fig {
  flex: 1 1 0;
  min-width: 0;
}

/* =============================================================== mobile ===
   Mobile node 12:22 (393 wide). Reading order is already the DOM order — copy,
   wide photo, then the pair — so no reordering is needed.

   PHOTOGRAPHY GOES FULL-BLEED, matching the mobile modern-address treatment.
   Figma draws all three mobile photos 373px wide against a 393px frame, flush
   to alternating edges (5:62 x=20, 5:65 x=0, 5:66 x=20) — edge-to-edge intent
   rather than a gutter. Copy keeps the 20px gutter.
   ========================================================================== */

@media (max-width: 768px) {

  .s-live-well {
    /* 41 = 5:61 top · 42 = 1042 - photo-3 bottom (1000) */
    padding: 41px var(--gutter-mb) 42px;
  }

  .s-live-well__intro { display: block; }

  .s-live-well__copy { flex: none; }

  /* flex-basis:0 on a column axis would collapse these boxes to zero height —
     the aspect-ratio box must own the height here, so the flex shorthand from
     the desktop rules is cleared, not inherited. */
  .s-live-well__fig--walking,
  .s-live-well__pair > .s-live-well__fig {
    flex: none;
  }

  .s-live-well__fig {
    margin-inline: calc(-1 * var(--gutter-mb));
  }

  .s-live-well__fig--walking {
    margin-top: 27px; /* 5:62 top (217) - 5:61 bottom (190) */
  }

  .s-live-well__pair {
    flex-direction: column;
    gap: 12px;        /* 5:66 top (751) - 5:65 bottom (739) */
    margin-top: 12px; /* 5:65 top (492) - 5:62 bottom (480) */
  }
}

/* ---- section: contact ---- */
/* 98 Churchill — CONTACT section. Job 2649. Figma mobile 12:20 (393x750).

   MOBILE ONLY. The desktop design has no CONTACT section — the same logo / agents / Ray White
   block lives inside the desktop FOOTER (2:172), owned by another agent. Displaying both would
   duplicate the agent contacts, so this is display:none above 768px.

   Geometry from the Figma child coordinates (frame-relative):
     band 5:67        393 x 750, charcoal
     wordmark 5:68    228 x 240 at y=48
     agents 5:73      228 wide at y=344, block height 225 (three name + number pairs)
     white panel 5:74 353 x 79 at y=612
     RW logo 5:75     240 x 57 at y=623 */

.s-contact {
  display: none;
}

@media (max-width: 768px) {
  .s-contact {
    display: block;
    background: var(--c-charcoal);
    padding: 48px var(--gutter-mb) 59px;
    text-align: center;
  }

  .s-contact__wordmark {
    width: 228px;
    height: 240px;
    max-width: 100%;
    margin: 0 auto;
  }

  .s-contact__agents {
    width: 228px;
    max-width: 100%;
    margin: 56px auto 0; /* wordmark ends y=288, agents start y=344 */
    padding: 0;
    list-style: none;
  }

  .s-contact__agent + .s-contact__agent {
    /* 3 pairs x 60px of line box + 2 x 22px = 224px against the designed 225 (Figma 5:73).
       The remaining 1px is NOT chased: 5:73 is a single 6-line text node and its type spec
       is not in design/figma-refs/v2/mobile.json (that export stops after A MODERN ADDRESS),
       and figma-mobile-full.png has no pixels below the fold to measure against. Guessing a
       line-height to close 1px would be inventing a source. */
    margin-top: 22px;
  }

  /* White on charcoal is 9.75:1. */
  .s-contact__agent-name {
    display: block;
    font-family: var(--font-display);
    font-weight: 500;
    font-size: 20px;
    line-height: 30px;
    text-transform: uppercase;
    letter-spacing: 0;
    color: var(--c-white);
  }

  .s-contact__agent-phone {
    display: block;
    font-family: var(--font-body);
    font-weight: 300;
    font-size: 20px;
    line-height: 30px;
    color: var(--c-white);
  }

  .s-contact__agency {
    display: flex;
    align-items: center;      /* logo 623-680 inside a 612-691 plate: 11px clear top and bottom */
    justify-content: flex-start;
    width: 353px;
    max-width: 100%;
    height: 79px;
    /* Plate 5:74 x=20, so 61px of padding puts the logo's left edge on the designed x=81,
       the same column as the wordmark and the agent list. Centring it was wrong. */
    padding-left: 61px;
    margin: 43px auto 0; /* agents block ends y=569, panel starts y=612 */
    background: var(--c-white);
  }

  /* Ray White Prospect logo — Figma 5:75, 240 x 57. The source PNG is 512 x 121 (aspect
     4.2314 against the slot's 4.2105), so object-fit keeps it undistorted inside the
     designed box rather than stretching it by a third of a pixel. */
  .s-contact__agency-logo {
    width: 240px;
    height: 57px;
    max-width: 100%;
    object-fit: contain;
    object-position: left center;
  }
}

/* ---- section: form ---- */
/* 98 Churchill — FORM section. Job 2649.
   Figma desktop 2:141 (frame x=627 w=770 h=825) · mobile 12:18 (393x825).

   Geometry read from the Figma child coordinates:
     white panel 2:142   607 x 746 at y=12
     label               x=49, line-height 30, 20px, uppercase, tan
     input               501 x 48 desktop / 353 x 48 mobile, fill #cddfe4, radius 10, text inset 15
     field group pitch   115px (label top 31 -> 146 -> 261 -> 376 -> 491)
     submit 2:160        353 x 60, fill tan, square corners, label 27/30 charcoal
     reassurance 2:158   y=692, 20/30

   Values NOT in src/tokens.css, so declared locally here rather than editing the lead's file:
     --form-field-bg  #cddfe4  (input fill, verbatim from nodes 2:144/2:147/2:150/2:153/2:156)
     --form-label-*   20/30    (form labels are 20px, not the 28px section-display size)
     --form-radius    10px     (inputs ARE rounded in Figma; the submit button is square) */

/* ⛔ THE FORM TOKENS ARE SHARED, NOT SECTION-SCOPED (fixed 24/08/26).
   These were declared on `.s-form` alone. The register MODAL's panel is NOT inside that section,
   so every one of them resolved to nothing inside it: the modal's inputs rendered with
   `background: rgba(0,0,0,0)` — no fill at all — `border-radius: 0` instead of 10px, and 14px
   text instead of 20px. It looked like a different, unfinished form because it WAS one.
   Declaring them on both surfaces from ONE place is what stops the two drifting again. */
.s-form,
.s-modal__panel {
  --form-field-bg: #cddfe4;
  --form-label-size: 20px;
  --form-label-lh: 30px;
  --form-text-size: 20px;
  --form-text-lh: 30px;
  --form-radius: 10px;
  --form-pitch: 31px;

  /* ⛔ WCAG 2.2 AA. The Figma spec puts tan labels on the white panel — measured at 1.92:1
     against #ffffff, where AA needs 4.5:1 for 20px medium text (not "large" by the spec: large
     is 24px, or 18.66px BOLD). It is a brand-canon choice that fails an accessibility floor, and
     the floor is the hard rule. `--form-label-ink` keeps the tan available as an accent while
     giving the label an AA-compliant ink; charcoal on white measures 9.4:1. */
  --form-label-ink: var(--c-charcoal);
}

.s-form {
  /* The composed design floats this white panel over the charcoal footer ground. Sections are
     stacked in document order here, so the band carries the same charcoal. */
  background: var(--c-charcoal);
  padding: 60px 0 70px;
}

/* The white panel is 607 wide and sits at x=627 on the 1440 canvas. min() keeps it on-canvas
   at narrower desktop widths instead of overflowing. */
.s-form__panel {
  width: 607px;
  max-width: 100%;
  margin-left: min(627px, calc(100% - 607px));
  background: var(--c-white);
  padding: 31px 57px 31px 49px; /* 607 - 49 - 57 = 501 = the designed field width */
}

/* AA 2.4.7: base.css uses a white focus ring, which is invisible on this white panel.
   Charcoal instead — 9.75:1 on white, 7.09:1 on the field fill, 5.08:1 on the tan button. */
.s-form :focus-visible {
  outline: 3px solid var(--c-charcoal);
  outline-offset: 2px;
}

/* ---- fields ---- */

.s-form__field {
  margin-bottom: var(--form-pitch);
}

.s-form__label {
  display: block;
  margin-bottom: 6px; /* label top 31 -> input top 67, with a 30px label line box */
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--form-label-size);
  line-height: var(--form-label-lh);
  text-transform: uppercase;
  letter-spacing: 0;
  /* See the --form-label-ink note above: tan on white measures 1.92:1 and fails AA. */
  color: var(--form-label-ink, var(--c-tan));
}

.s-form__input {
  display: block;
  width: 100%;
  height: var(--field-h);
  padding: 0 15px;
  border: 0;
  border-radius: var(--form-radius);
  background: var(--form-field-bg);
  font-family: var(--font-body);
  font-weight: 300;
  font-size: var(--form-text-size);
  line-height: normal;
  color: var(--c-charcoal);
}

/* Design draws the placeholder in full charcoal, which reads as a filled value. Held back to
   85% so it reads as a hint and still clears AA (4.97:1 on the field fill). */
.s-form__input::placeholder {
  color: var(--c-charcoal);
  opacity: 0.85;
}

/* Error state is carried by the message text below the field. This border is an extra signal,
   never the only one. */
.s-form__input[aria-invalid='true'] {
  box-shadow: inset 0 0 0 2px var(--c-charcoal);
}

/* ---- select ---- */

.s-form__select-wrap {
  position: relative;
}

.s-form__select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 56px; /* clear of the arrow */
  cursor: pointer;
}

/* Figma 2:162 / 5:101 — the exported tan polygon, rotated 180 as in the design. */
.s-form__select-arrow {
  position: absolute;
  top: 50%;
  right: 28px;
  width: 20px;
  height: 17px;
  transform: translateY(-50%) rotate(180deg);
  pointer-events: none;
}

/* ---- errors, warnings, status (none of these states were designed) ---- */

.s-form__error,
.s-form__note {
  margin-top: 6px;
  padding-left: 10px;
  border-left: 3px solid var(--c-charcoal);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 20px;
  color: var(--c-charcoal);
}

.s-form__error {
  font-weight: 600;
}

.s-form__error[hidden],
.s-form__note[hidden] {
  display: none;
}

.s-form__status {
  font-family: var(--font-body);
  font-size: var(--form-text-size);
  line-height: var(--form-text-lh);
  color: var(--c-charcoal);
}

/* Kept in the DOM from first paint so the live region is registered, but takes no space until
   there is something to announce. */
.s-form__status:empty {
  display: none;
}

.s-form__status--ok,
.s-form__status--error,
.s-form__status--busy {
  margin-bottom: 24px;
  padding: 14px 18px;
  border-left: 4px solid var(--c-charcoal);
}

.s-form__status--error {
  font-weight: 600;
}

/* ---- consent (added; not in the design) ---- */

.s-form__consent {
  display: grid;
  grid-template-columns: 22px 1fr;
  column-gap: 12px;
  row-gap: 6px;
  align-items: start;
  margin-bottom: var(--form-pitch);
}

.s-form__checkbox {
  width: 22px;
  height: 22px;
  margin: 4px 0 0;
  accent-color: var(--c-charcoal);
  flex: none;
}

.s-form__consent-label {
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 24px;
  color: var(--c-charcoal);
}

.s-form__error--consent {
  grid-column: 1 / -1;
}

/* ---- honeypot (added; not in the design) ---- */

.s-form__gotcha {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---- submit + reassurance ---- */

/* Reuses .btn .btn--primary for the fill and the box. The design's submit differs from the
   page buttons in two ways, overridden here: 353 wide (not 291) and Korolev Condensed Medium
   (not Oswald Light) per Figma node 2:161. */
.s-form__submit {
  width: var(--btn-w-mb);
  max-width: 100%;
  font-family: var(--font-display);
  font-weight: 500;
}

.s-form__submit[disabled] {
  cursor: progress;
  opacity: 0.85;
}

/* Figma node 2:158 is 539 wide — 38px past the 501 field, still inside the 607 panel — so it
   is not capped at the field width. With the stand-in typeface it may still wrap; that is the
   documented consequence of the Korolev licence blocker, not a layout error. */
.s-form__reassurance {
  margin-top: 26px;
  margin-right: -38px;
  font-family: var(--font-body);
  font-weight: 300;
  font-size: var(--form-text-size);
  line-height: var(--form-text-lh);
  color: var(--c-charcoal);
}

/* Tan on white is 1.92:1 — reported as a WCAG AA failure rather than silently recoloured.
   The underline means the link is not signalled by colour alone. */
.s-form__link {
  color: var(--c-tan);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---- mobile: Figma 12:18, full-bleed white, 20px insets ---- */

@media (max-width: 768px) {
  .s-form {
    background: var(--c-white);
    padding: 0;
  }

  .s-form__panel {
    width: 100%;
    margin-left: 0;
    padding: 31px var(--gutter-mb) 26px;
  }

  .s-form__submit {
    width: 100%;
    margin-top: 29px; /* mobile gap to the button is 60px, not 31px */
  }

  .s-form__select-arrow {
    right: 15px;
  }

  .s-form__reassurance {
    margin-top: 31px;
    margin-right: 0; /* mobile node 5:106 is 351 wide, inside the 353 field */
  }
}

/* ---- section: footer ---- */
/* ===== FOOTER — Figma desktop 2:172 (1440 x 1028) · mobile 12:19 (393 x 308) =====
   Every selector is prefixed .s-footer so this section cannot leak styles.

   Ground is #3f4547 (--c-charcoal) — sampled from design/screenshots/figma-desktop-full.png
   at the 2:128 backing rectangle, since the Figma metadata carries no fills.

   Desktop Figma geometry, frame-relative:
     wordmark 2:129     x 207 y 71   289 x 303   (sage artwork)
     agents 2:135       x 207 y 459  289 x 201   (centred, white)
     Ray White 2:140    x 207 y 745  292 x 65.35 (white plate; logo 199x47 inside)
     address 2:165      x 207 y 895  · RLA 2:166 x 627 y 899
     Terms 2:167        x 838 y 899  · Privacy 2:168 x 1049 y 903
   The identity column is 292 wide at a 207px inset — note that is NOT the 100px page
   gutter used everywhere else; the legal row runs 207..1236, i.e. inset 207 both sides.
   The four blocks are a consistent 85px apart and the frame ends 95px after the row.

   Mobile Figma geometry: four centred lines at y 50 / 116 / 178 / 238, boxes 351 wide
   at x=22, in a 308-tall frame. */

.s-footer {
  background: var(--c-charcoal);
  /* 207/1440 = 14.375vw, so the inset is exactly the designed 207px at 1440 and gives
     ground below it — a flat 207px each side overflows the legal row under ~950px. */
  padding: 71px clamp(var(--gutter-mb), 14.375vw, 207px) 95px;
}

/* ---------- identity column (desktop only) ---------- */

.s-footer__identity {
  width: 292px;
}

.s-footer__wordmark {
  width: 289px;
  height: auto;
}

.s-footer__agents {
  width: 289px;
  margin: 85px 0 0;
  padding: 0;
  list-style: none;
  text-align: center;
  color: var(--c-white);
}

.s-footer__agent + .s-footer__agent {
  margin-top: 12px;
}

/* INFERRED: 2:135 is a single Figma text node with mixed per-character styling, which
   get_metadata cannot report and the design-context call for this node was blocked by
   the plan limit. Sizes (24 / 20) and the condensed face are measured off
   design/screenshots/figma-desktop-full.png; the two weights are read from the render. */
.s-footer__agent-name {
  display: block;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: var(--fs-nav);
  line-height: 30px;
  text-transform: uppercase;
}

.s-footer__agent-phone {
  display: block;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: 20px;
  line-height: 26px;
}

.s-footer__agent-phone:hover {
  text-decoration: underline;
}

/* White plate 2:137 (292 x 65.35) holding the Ray White Prospect logo 2:138 at
   199 x 47. Figma insets the logo 50.46px from the plate's left edge and 42.21px from
   the right, so it is left-aligned with a 50px pad rather than centred. */
.s-footer__agency {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  width: 292px;
  height: 65.35px;
  padding-left: 50px;
  margin-top: 85px;
  background: var(--c-white);
}

.s-footer__agency-logo {
  width: 199px;
  height: auto;
}

/* ---------- legal row ---------- */

.s-footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px 24px;
  margin-top: 85px;
}

/* Figma sets these four boxes at y 895 / 899 / 899 / 903 and mixes left, centre and
   right alignment across the row. Rebuilt on one baseline with space-between, which
   reproduces every item's designed x position to within about 5px. */
.s-footer__legal-item {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: 20px;
  line-height: 26px;
  /* ⛔ WAS var(--c-sage) — #71867c on the charcoal footer measures 2.51:1.
     AA needs 4.5:1 for 20px regular text, and at 2.51 the thin strokes genuinely stop rendering:
     "RLA 321928" appeared on screen as two glyphs and "Terms & Conditions" / "Privacy Policy"
     did not appear at all. Keith reported the footer as MISSING them. They were present in the
     DOM, correctly positioned and clickable the whole time — just painted at a contrast where a
     person cannot see them, which for practical purposes IS missing.
     ⚠ The RLA is legally required to be legible on public sales collateral, so this is not a
     preference. --c-tan on charcoal measures 7.6:1 and is already the footer's accent colour,
     so it stays on brand rather than resorting to plain white. */
  color: var(--c-tan);
  white-space: nowrap;
}

.s-footer__legal-link:hover {
  text-decoration: underline;
}

/* ---------- mobile (mobile frame 12:19) ---------- */

@media (max-width: 768px) {
  /* 50 + (4 x 26) + (3 x 36) + 46 = 308, the designed frame height. */
  .s-footer {
    padding: 50px var(--gutter-mb) 46px;
  }

  /* Mobile carries the wordmark, agents and Ray White plate in its own CONTACT
     section (12:20), so they are not repeated here. */
  .s-footer__identity {
    display: none;
  }

  .s-footer__legal {
    flex-direction: column;
    align-items: center;
    /* Figma spaces these lines 66 / 62 / 60 apart — an inconsistency, evened out. */
    gap: 36px;
    margin-top: 0;
    text-align: center;
  }
}

/* ---- register modal ---- */
/* ---- register modal ----
   REBUILT 24/08/26 (senior-ui-ux-designer). The first pass was off brand and unusable on a small
   phone. Both causes were concrete, measured on the live site, and are recorded here so the same
   mistakes are not available to make twice:

   1. ⛔ IT USED TOKENS THAT DO NOT EXIST. `--c-ink`, `--c-sand`, `--f-display`, `--f-body` are not
      in tokens.css — the real names are `--c-charcoal`, `--c-tan`, `--font-display`, `--font-body`.
      All four silently fell through to hardcoded fallbacks, so the panel rendered #f4efe8, a colour
      that appears nowhere in this brand, and the heading rendered in the BODY face rather than the
      condensed display face. A CSS variable that does not exist does not warn; it just quietly
      uses whatever you guessed.

   2. ⛔ THE FORM TOKENS WERE SECTION-SCOPED. `--form-field-bg` and friends were declared on
      `.s-form`, and this panel is not inside it, so the modal's inputs computed to
      `background: rgba(0,0,0,0)` — literally no fill — with `border-radius: 0` and 14px text
      against the canon's #cddfe4 / 10px / 20px. Now declared once for both surfaces in form.css.

   3. ⛔ THE SUBMIT BUTTON SAT BELOW THE FOLD AT 320px, measured at 711px in a 568px viewport. The
      panel scrolled, so it was reachable, but the primary action was invisible on open with no
      affordance suggesting it existed. On the smallest common phone that reads as a broken form.
      Fixed structurally below: the panel is a flex column, only the FIELDS scroll, and the submit
      is pinned where it can always be seen.

   The dials for this surface are deliberately low — VARIANCE 4 / MOTION 3 / DENSITY 4, trimmed
   from the place-brand preset. The approved form section is brand canon (lessons L5); a modal
   that announces itself as new art direction is the wrong answer for a lead form. This inherits
   `.s-form__*` for every field so the two surfaces cannot diverge visually. */

/* ---- STRUCTURE: matched to the Southend house pattern (Keith, 24/08/26: "look at the modals
   for salt and southend....those are much better").
   Southend uses a FIXED, FLEX-CENTRED overlay with an explicitly-sized card that scrolls — NOT a
   <dialog> sized by max-width. That is precisely why it does not break: a fixed full-viewport
   container resolves its children's widths against the viewport, whereas a <dialog> carries
   `width: fit-content` from the UA sheet and, when a percentage width fails to resolve, silently
   collapses to its content. Mine collapsed to 280px in an 1800px viewport with 216px fields.
   We keep the <dialog> ELEMENT — it gives the focus trap, Escape and inert background for free,
   which the div-based version has to hand-roll — but we drive the layout Southend's way. */

.s-modal {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100dvh;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 24px;                        /* Southend: 24px gutter around the card */
  border: 0;
  background: transparent;              /* the dim is on ::backdrop */
  color: inherit;
  overflow: visible;
  box-sizing: border-box;
}

/* dialog is display:none until open; the open state must restore FLEX, not block. */
.s-modal[open] {
  display: flex;
  align-items: center;
  justify-content: center;
}

.s-modal::backdrop {
  background: rgba(63, 69, 71, 0.62);   /* --c-charcoal at Southend's ~0.55-0.62 weight */
}

/* THE CARD. Explicit width, scrolls as one piece — Southend's shape. */
.s-modal__panel {
  --modal-pad-b: 32px;                  /* referenced by the sticky foot's full-bleed maths */
  position: relative;
  width: 560px;
  max-width: 100%;
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--c-white);           /* .s-form__panel canon */
  border-radius: 3px;                   /* Southend uses 3px, not square */
  padding: 32px 28px;
  box-sizing: border-box;
}

.s-modal__head { padding: 0 0 20px; }

.s-modal__title {
  margin: 0 0 8px;
  padding-right: 44px;                  /* clear of the close target */
  font-family: var(--font-display);
  font-weight: var(--fw-display);
  font-size: 28px;
  line-height: 32px;
  text-transform: uppercase;
  color: var(--c-charcoal);             /* 9.75:1 on white */
}

.s-modal__intro {
  margin: 0;
  font-family: var(--font-body);
  font-weight: var(--fw-body);
  font-size: 16px;
  line-height: 24px;
  color: var(--c-charcoal);
}

/* The card scrolls as one piece, so body is just flow. */
.s-modal__body { padding: 0; }

/* The submit STICKS to the bottom of the scrolling card. Southend lets it scroll away; sticking
   it costs nothing and keeps the primary action in view on a short phone, which is the defect
   that started this (submit measured 711px down a 568px viewport). */
/* ⛔ A STICKY FOOTER MUST OUT-PAINT AND OUT-STACK WHAT SCROLLS UNDER IT.
   Without a z-index the scrolling select rendered THROUGH the submit button — "Please choose a
   time" was visible straight over the CTA on a phone. And because the card has horizontal
   padding, a sticky child only spans the content box, so content slid past it at the edges:
   the negative side margins plus matching padding give it a full-bleed opaque band. */
.s-modal__foot {
  position: sticky;
  bottom: calc(-1 * var(--modal-pad-b, 0px));
  z-index: 3;
  margin: 4px -28px calc(-1 * var(--modal-pad-b, 0px));
  padding: 14px 28px calc(14px + var(--modal-pad-b, 0px));
  background: var(--c-white);
  /* A hairline so the pinned band reads as a surface rather than as text that stopped. */
  box-shadow: 0 -1px 0 rgba(63, 69, 71, 0.12);
}

.s-modal__foot .s-form__submit { width: 100%; max-width: none; }

/* 44px minimum touch target. */
.s-modal__close {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  background: transparent;
  font-family: var(--font-body);
  font-size: 28px;
  line-height: 1;
  color: var(--c-charcoal);
  cursor: pointer;
}

.s-modal__close:hover { color: var(--c-sage); }
.s-modal__close:focus-visible { outline: 3px solid var(--c-charcoal); outline-offset: -3px; }

/* ⛔ THE FIELDS MUST FILL THE CARD. The canon sets a fixed --field-w (501px) for the page form's
   fixed-width panel; inside a fluid card that leaves them narrower than their container and
   looking wrong. Override to fluid here, and ONLY here. */
.s-modal__panel .s-form__input,
.s-modal__panel .s-form__select,
.s-modal__panel select.s-form__input {
  width: 100%;
  max-width: none;
}

.s-modal__panel .s-form__form { margin: 0; padding: 0; }

/* ⛔ DENSITY IS A GAP PROBLEM, NOT A FIELD PROBLEM.
   The canon keeps 20px labels and 48px fields on mobile, and that is the approved design — the
   modal must not restyle them or it goes off brand again, which is what started this. What a
   modal CAN do is close the gaps: the page form has a whole screen to breathe in, an overlay does
   not. At the canon's 31px pitch only four of six fields fit a 667px phone. Reducing the PITCH
   alone shows the whole form without altering how a single field looks. */
/* ---------------------------------------------------------------------------
   DESKTOP: THE WHOLE FORM ON ONE SCREEN, NO INNER SCROLL.

   Keith, 25/08/26: "fix the modal pop up so the content on desktop loads and you dont need to
   scroll in the form to see all form field/data".

   Measured on the live modal before changing anything. Content 1005px, against the panel's
   `calc(100dvh - 48px)`:

       viewport      available   result
       1920 x 1080     1032      fits
       1512 x  982      934      scrolls 71px
       1440 x  900      852      scrolls 153px
       1280 x  800      752      scrolls 253px
       1366 x  768      720      scrolls 285px

   And 720px is the generous reading: a real 1366x768 laptop loses another ~90px to browser
   chrome, so the true budget there is closer to 630. Six stacked fields cannot fit that, which
   is why the answer is fewer ROWS rather than smaller parts.

   ⛔ THE FIELDS THEMSELVES ARE NOT TOUCHED. Round 1 shipped a modal that restyled the canon's
   20px labels and 48px fields, and Keith's word for it was "off brand". The canon holds here:
   same label size, same field height, same colours. Only the PITCH tightens, 31px to 16px,
   which is the same lever round 2 used on mobile and Keith accepted.

   PAIRING: the modal body becomes a two-column grid, so the six fields fall into three rows in
   their existing DOM order — first/last, mobile/postcode, email/best time. No wrapper divs, so
   the page form and the build's generated markup are untouched, and tab order is still DOM order.
   Every label fits its column with room to spare, measured in the live font at 20px: the longest
   is "Best time to contact" at 158px in a 243px column.

   The status region and the consent row span both columns. The honeypot is `position: absolute`
   and the hidden inputs are `display: none`, so neither claims a grid cell and the pairing does
   not silently shift by one.

   `overflow-y: auto` and the sticky foot STAY. They are the safety net for a short window, a
   landscape phone or a browser at 200% zoom, where scrolling is the correct behaviour rather
   than a clipped form. The goal is that a normal desktop never reaches it.
   --------------------------------------------------------------------------- */
@media screen and (min-width: 601px) {
  .s-modal__panel {
    /* 31px of pitch between six stacked fields was 186px of the overflow on its own. */
    --form-pitch: 16px;
    --modal-pad-b: 20px;
    padding: 24px 28px 20px;
  }

  .s-modal__body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 18px;
    align-items: start;
  }

  /* Full-width rows. Without this the consent row would take one cell and drag the layout
     out of step, putting a checkbox beside a text field. */
  .s-modal__body > .s-form__status,
  .s-modal__body > .s-form__consent {
    grid-column: 1 / -1;
  }

  /* The select's 56px right padding clears the arrow at 504px, where there is room to spare.
     In a 243px column it left 172px for text and clipped three of the five options mid-word.
     36px still clears the 20px arrow with a 16px gap, and the trimmed option text now has 26px
     of slack rather than 2 — which matters because this page renders in a SUBSTITUTE typeface
     until Korolev loads, so a 2px margin is not a margin. */
  .s-modal__panel .s-form__select {
    padding-right: 36px;
  }
}

@media screen and (max-width: 600px) {
  .s-modal__panel { --form-pitch: 16px; }
  .s-modal__panel .s-form__submit { margin-top: 0; }
  .s-modal__head { padding-bottom: 14px; }
}
.s-modal__panel .s-form__status { margin-bottom: 16px; }

/* --- small screens --------------------------------------------------------------------------- */
@media screen and (max-width: 600px) {
  /* Full-bleed sheet. align-items must become stretch — centring a 100dvh panel inside a 100dvh
     flex box left a sliver of the page showing above it. */
  .s-modal { padding: 0; top: 0; left: 0; }
  .s-modal[open] { align-items: stretch; justify-content: stretch; }
  .s-modal__panel {
    --modal-pad-b: calc(18px + env(safe-area-inset-bottom, 0px));
    width: 100%;
    height: 100dvh;
    max-height: 100dvh;
    border-radius: 0;
    padding: 26px 20px var(--modal-pad-b);
  }
  .s-modal__foot { margin-left: -20px; margin-right: -20px; padding-left: 20px; padding-right: 20px; }
  .s-modal__title { font-size: 24px; line-height: 28px; }
  .s-modal__intro { font-size: 15px; line-height: 22px; }
}

@media screen and (max-width: 360px) {
  .s-modal__intro { display: none; }
  .s-modal__panel {
    --modal-pad-b: calc(14px + env(safe-area-inset-bottom, 0px));
    padding: 22px 16px var(--modal-pad-b);
  }
  .s-modal__foot { margin-left: -16px; margin-right: -16px; padding-left: 16px; padding-right: 16px; }
}

/* Page behind must not scroll. <html> as well as body — iOS ignores overflow:hidden on body. */
.has-modal-open, .has-modal-open body { overflow: hidden; }

/* MOTION 3: one short rise, nothing at all under a reduced-motion preference. */
@media (prefers-reduced-motion: no-preference) {
  .s-modal[open] .s-modal__panel { animation: s-modal-in 180ms ease-out; }
  @keyframes s-modal-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ---- integration (lead-owned, cross-section) ---- */
/* 98 Churchill — cross-section composition. OWNED BY LEAD. Build agents must not edit.
   Loaded last, so it wins specificity ties against section stylesheets without !important.
   Its only job is composition that no single section can express, because the sections live
   in separate agent-owned files. */

/* ---------------------------------------------------------------------------
   Desktop: the form panel belongs INSIDE the footer band, not above it.

   Figma:  form   2:141  x 627-1397, y 5027-5852  (770 x 825)
           footer 2:172  x 0-1440,   y 4972-6000  (1440 x 1028)

   The form starts 55px below the footer band's top (5027 - 4972) and its left edge is at
   x=627. The footer's identity column runs x 207-499, so the two never collide horizontally.
   Stacking them in document flow adds roughly 940px of page height that does not exist in the
   design — this was the single largest source of desktop height error.

   Mobile is left alone: there, Figma genuinely stacks them (FORM y5981 h825, FOOTER y6806 h308).
   --------------------------------------------------------------------------- */

.band-form-footer {
  position: relative;
}

/* ⛔ THE BAND STARTS AT 1200px, NOT 769px. Measured 24/08/26, live.
   The overlay only works if the form and the footer's identity column do not collide, which
   the comment above asserts from the 1440 canvas: footer column ends x=499, form starts x=627.
   That is true AT 1440. It is not true as the viewport narrows, because the two columns do not
   scale together — the form is anchored to the right edge and the footer column to the left:

       viewport   form left   agent name right   result
         769         315            400          OVERLAP 84px
         800         328            404          OVERLAP 76px
         900         369            418          OVERLAP 49px
        1000         410            433          OVERLAP 23px
        1100         451            447          clears by 4px
        1200         492            462          clears by 30px

   So between 769 and ~1050 the three agent names sat UNDER the opaque white form panel. Same
   failure as the legal row, one breakpoint over: present in the DOM, correctly coloured, and
   invisible — and these are the selling agents' names and mobile numbers.
   1100 clears by 4px, which is a coincidence rather than a gutter, so the band starts at 1200.
   Below it the page stacks, which is what it already did at 768 and what Figma draws for mobile. */
@media (min-width: 1200px) {
  .band-form-footer > .s-form {
    position: absolute;
    top: 55px;                    /* 5027 - 4972 */
    /* Figma form frame x=627, measured from the 1440 CONTENT BOX — not the viewport.
       REGRESSION FIXED 07/08: the full-bleed change below makes .band-form-footer span the
       whole viewport, so a bare `left: 627px` started measuring from the screen edge. At
       1920 that put the form at 627 instead of 867 — 240px too far left, sitting left of the
       footer wordmark with dead space to its right. Offset by half the overflow so it tracks
       the content box at any width. Below 1441 the overflow is 0 and this reduces to 627. */
    left: calc(627px + max(0px, (100vw - var(--page-w)) / 2));
    width: 770px;                 /* Figma form frame width */
    margin: 0;
    z-index: 2;

    /* ⛔ NO BACKGROUND ON THE OVERLAY, AND NO VERTICAL PADDING.
       In flow the section paints its own charcoal ground. Lifted out of flow and laid over the
       footer, that ground is redundant — the band behind it is already the same charcoal — but it
       is NOT harmless: it makes the section an opaque rectangle that hides whatever it covers.
       That is how the legal row disappeared. Transparent, the geometry can drift again and the
       worst case is a link overlapped for clicks rather than a legally-required RLA rendered
       invisible. Belt and braces with the overhang above, because one of them being right is not
       a reason for the other to be wrong. */
    background: transparent;
    padding-top: 0;
    padding-bottom: 0;
  }

  /* The band must reserve the footer's designed height, because the form no longer
     contributes to flow. 1028px is the Figma footer frame height.

     ⚠ But our form is TALLER than Figma's. The design's form is 825px; ours is 962px because
     a consent checkbox and an aria-live status region were added (the design has neither, and
     a lead form feeding a CRM needs both). Sitting at top:55px it therefore ends 1017px into
     the band, past the legal row's designed y of 895 — which hid RLA XXXXXX, Terms and
     Privacy Policy behind the form panel. Caught by eye in the side-by-side, not by any
     automated check: the links were present in the DOM, correctly styled and clickable by
     coordinate, just painted underneath an opaque panel.

     The band grows by exactly the form's overhang so the legal row clears it. Expressed as a
     variable so it stays correct if the form's height changes again. */
  .band-form-footer {
    /* Form bottom sits 1017px into the band (55 top + 962 height). The legal row's own
       designed offset puts its top at 886px. 151px is the shortfall plus 20px clearance.
       NOTE: footer.css already gives .s-footer__legal margin-top:85px, so this must be
       ADDED to that, not substituted for it — overwriting it moved the row only 60px and
       left the links still hidden. */
    /* ⛔ MEASURE THE SECTION, NOT THE PANEL. This was 151px, derived from the PANEL's height.
       The overlay is the SECTION `.s-form`, which is taller: 60px top padding + panel + 70px
       bottom padding. Adding the last-name field on 24/08/26 grew the panel and the section's
       bottom edge landed 39px INTO the legal row. Because the section carries an opaque charcoal
       background, RLA 321928, Terms and Privacy Policy were buried under a charcoal panel on a
       charcoal ground: present in the DOM, correctly coloured, and invisible.
       ⚠ The earlier automated check measured `.s-form__panel` and reported 31px of CLEARANCE
       while the section was overlapping by 39. It was measuring the wrong box. */
    --form-overhang: 200px;
  }

  .band-form-footer > .s-footer {
    min-height: calc(1028px + var(--form-overhang));
    position: relative;
    z-index: 1;
  }

  /* Push the legal row clear of the form rather than letting it sit under the panel.
     85px is the section's own designed gap; the overhang is added on top of it. */
  .band-form-footer > .s-footer .s-footer__legal {
    margin-top: calc(85px + var(--form-overhang));
  }
}

/* ---------------------------------------------------------------------------
   STACKED RANGE 769-1199: centre the panel.

   Raising the band to 1200px handed these widths back to normal flow, and that exposed a second
   bug the overlap had been hiding. `.s-form__panel` carries

       margin-left: min(627px, calc(100% - 607px));

   which is correct INSIDE the 770px overlay — 770-607=163, so it insets 163px — and wrong in a
   full-width section, where `100% - 607px` is the whole remaining viewport. At 1024 that put the
   panel at x=417 with its right edge flush on the viewport edge: no gutter, reading as clipped.
   The mobile block already resets it to `margin-left: 0` below 769; this is the same reset for
   the range that only started stacking today. Centred, not zeroed, because at these widths a
   607px panel in a 1024px section looks deliberate centred and lopsided flush-left.
   --------------------------------------------------------------------------- */
@media (min-width: 769px) and (max-width: 1199px) {
  .band-form-footer > .s-form .s-form__panel {
    margin-left: auto;
    margin-right: auto;
  }
}

/* Below the fold of the widest layout the canvas is a fixed 1440 design, so the absolute
   left offset must not survive into the tablet range where the page has started to fluid-scale.
   Between the band's start and 1440px, anchor the form to the right instead of a fixed x,
   keeping the same proportional relationship to the footer column. */
@media (min-width: 1200px) and (max-width: 1439px) {
  .band-form-footer > .s-form {
    left: auto;
    right: 3vw;
    width: min(770px, 56vw);
  }
}

/* ---------------------------------------------------------------------------
   FULL-BLEED COLOUR BANDS  (designer feedback F5)

   > "There's a odd gap down both side of the site, maybe 10 or pixels that
   >  shouldn't be there."

   Cause: `.page` is max-width 1440 centred, so on any viewport wider than 1440 the
   section backgrounds stop at 1440 and the BODY background shows as a strip down each
   side. Measured: 1500px viewport = 30px each side, 1680px = 120px, 1920px = 240px.
   Where a section happens to be sage the strip is invisible; against the tan and
   charcoal bands it reads as an odd gap. That is what the designer saw.

   Figma is a fixed 1440 canvas with no wider artwork, so the correct reading is that
   the bands run edge to edge while the content stays 1440 and centred.

   TECHNIQUE — transparent side borders rather than padding or a wrapper.
   Only 2 of the 7 sections have an inner content wrapper, and several already use
   horizontal padding for their own insets, so adding padding here would double it.
   A border is a separate box-model channel: with the global `box-sizing: border-box`
   the section still spans the viewport, its CONTENT BOX lands at exactly 1440 centred,
   and the background paints under the transparent border (background-clip defaults to
   border-box) so the colour reaches the viewport edge.

   Absolutely-positioned children resolve against the padding box, which sits inside the
   border, so the form's `left: 627px` in the band above stays correct.
   --------------------------------------------------------------------------- */
@media (min-width: 1441px) {
  .page {
    max-width: none;
  }

  .page > * {
    border-left: calc((100vw - var(--page-w)) / 2) solid transparent;
    border-right: calc((100vw - var(--page-w)) / 2) solid transparent;
    background-clip: border-box;
  }

  /* The band wrapper is a plain positioning context with no background of its own —
     bleeding it would do nothing, and its border would double up with the footer's.
     Let the footer inside it do the bleeding instead. */
  .page > .band-form-footer {
    border-left: 0;
    border-right: 0;
  }
  .band-form-footer > .s-footer {
    border-left: calc((100vw - var(--page-w)) / 2) solid transparent;
    border-right: calc((100vw - var(--page-w)) / 2) solid transparent;
    background-clip: border-box;
  }
}

/* ---------------------------------------------------------------------------
   The utility bar is a separate agent-owned section that renders above <header>.
   Semantically it is part of the banner, so expose it as one landmark region rather
   than a stray block before the header.
   --------------------------------------------------------------------------- */
.s-utility-bar {
  position: relative;
  z-index: 3;
}

/* ---------------------------------------------------------------------------
   Duplicate-image guard.
   Figma parents shutterstock_2723216705 differently per breakpoint: on mobile it is 12:24
   inside TOP INTRO, on desktop it is 2:82 inside A Modern Address. Two different agents
   therefore legitimately render the same photograph. Show exactly one per breakpoint.
   --------------------------------------------------------------------------- */
@media (max-width: 768px) {
  /* mobile: TOP INTRO owns it (12:24) */
  .s-modern-address [data-fig="2:82"] { display: none; }
}
@media (min-width: 769px) {
  /* desktop: A Modern Address owns it (2:82) */
  .s-nav-intro [data-fig="12:24"] { display: none; }
}

/* ---- legal pages ---- */
/* Legal pages (privacy, terms). Same tokens as the site; charcoal ground because
   white-on-charcoal is 9.75:1 and passes AA comfortably, unlike white-on-sage (3.89:1). */
.s-legal { background: var(--c-charcoal); color: var(--c-white); min-height: 100vh; padding: 64px 0; }
.s-legal__inner { max-width: 760px; margin: 0 auto; padding: 0 var(--gutter-mb); }
.s-legal__banner { background: var(--c-tan); color: var(--c-charcoal); padding: 14px 18px; margin-bottom: 32px; font-family: var(--font-body); }
.s-legal__title { font-family: var(--font-display); font-size: 40px; line-height: 1.1; text-transform: uppercase; color: var(--c-tan); margin-bottom: 16px; }
.s-legal__meta { font-family: var(--font-body); font-size: 14px; line-height: var(--lh-body); opacity: 0.85; }
.s-legal h2 { font-family: var(--font-display); font-size: 22px; line-height: 1.2; text-transform: uppercase; color: var(--c-tan); margin: 32px 0 10px; }
.s-legal p { font-family: var(--font-body); font-size: 16px; line-height: 1.6; margin-bottom: 12px; }
.s-legal code { background: rgba(255,255,255,0.12); padding: 1px 5px; }
.s-legal__back { margin-top: 40px; }
.s-legal__back a { color: var(--c-tan); text-decoration: underline; }
@media (min-width: 769px) { .s-legal__inner { padding: 0 40px; } }

