/* ==========================================================================
   UZ PRO CONSTRUCTION — Design System
   Style:  Trust & Authority + Minimalism
   Type:   Playfair Display (display) + Inter (body/UI)
   Colour: Green-neutral ramp + brand green sampled from the UZ Pro logo
           (#026E31 deep → #419F19 mid → #82CF00 lime)

   Contrast policy:
     - Deep green #026E31 carries text        → 6.5:1 on white   (AA)
     - Lime #82CF00 NEVER carries text on light (1.9:1 — fails)
       It is used on dark surfaces only, where it reaches 8.8:1
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Neutrals — green-cast ramp so greys sit under the brand, not against it */
  --ink:        #0F1712;
  --stone-900:  #0E2015;   /* dark section ground */
  --stone-800:  #1A3123;
  --stone-700:  #33473A;
  --stone-600:  #4E5A52;   /* muted text on light — 6.5:1 AA */
  --stone-500:  #74827A;   /* decorative only, NOT body text */
  --stone-400:  #98A595;
  --stone-300:  #C6D0C3;
  --stone-200:  #E1E8DE;   /* borders */
  --stone-100:  #EDF1EA;
  --stone-50:   #F7F9F6;   /* page background */
  --white:      #FFFFFF;

  /* Brand green — sampled from the supplied logo gradient */
  --brand:      #026E31;   /* PRIMARY. 6.5:1 on --stone-50 — AA text + CTAs */
  --brand-700:  #01541F;   /* hover / pressed */
  --brand-500:  #2E8B1F;   /* mid gradient stop, decorative */
  --brand-400:  #7CC61A;   /* 8.1:1 on --stone-900 — dark sections only */
  --brand-300:  #A8DE5C;   /* selection, subtle fills */
  --brand-50:   #EDF7E7;   /* tint background — 5.9:1 with --brand */
  --brand-grad: linear-gradient(135deg, #026E31 0%, #419F19 55%, #82CF00 100%);

  /* Semantic */
  --bg:            var(--stone-50);
  --bg-elevated:   var(--white);
  --fg:            var(--ink);
  --fg-muted:      var(--stone-600);
  --border:        var(--stone-200);
  --accent:        var(--brand);
  --on-accent:     var(--white);
  --ring:          var(--brand);
  --destructive:   #B91C1C;
  --success:       #15803D;

  /* Typography */
  --font-display: 'Playfair Display', ui-serif, Georgia, serif;
  --font-body:    'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;

  --fs-display: clamp(2.75rem, 1.30rem + 5.6vw, 5.25rem);
  --fs-h1:      clamp(2.25rem, 1.45rem + 3.2vw, 4rem);
  --fs-h2:      clamp(1.875rem, 1.35rem + 2.1vw, 3rem);
  --fs-h3:      clamp(1.375rem, 1.15rem + 0.9vw, 1.875rem);
  --fs-h4:      clamp(1.125rem, 1.03rem + 0.38vw, 1.3125rem);
  --fs-body:    1.0625rem;
  --fs-sm:      0.9375rem;
  --fs-xs:      0.8125rem;
  --fs-label:   0.75rem;

  /* Spacing — density 4/10 (standard) */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;     --sp-7: 3rem;     --sp-8: 4rem;
  --sp-9: 5rem;     --sp-10: 6rem;    --sp-11: 8rem;

  --section-y: clamp(4rem, 2.5rem + 6vw, 8rem);
  --gutter:    clamp(1.25rem, 0.8rem + 2.2vw, 3rem);
  --maxw:      1240px;
  --maxw-prose: 68ch;

  /* Radii + elevation */
  --r-sm: 4px;  --r-md: 8px;  --r-lg: 14px;  --r-xl: 22px;  --r-full: 999px;

  --shadow-sm: 0 1px 2px rgba(11,26,16,.05), 0 1px 3px rgba(11,26,16,.04);
  --shadow-md: 0 4px 12px rgba(11,26,16,.06), 0 2px 4px rgba(11,26,16,.04);
  --shadow-lg: 0 18px 40px -12px rgba(11,26,16,.14), 0 6px 14px rgba(11,26,16,.05);
  --shadow-xl: 0 34px 70px -20px rgba(11,26,16,.20), 0 10px 24px rgba(11,26,16,.07);

  /* Motion */
  --e-out:  cubic-bezier(0.22, 1, 0.36, 1);
  --e-io:   cubic-bezier(0.65, 0, 0.35, 1);
  --t-fast: 160ms;
  --t-base: 240ms;
  --t-slow: 420ms;

  --header-h: 76px;
}

/* --------------------------------------------------------------------------
   2. RESET
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
  /* `clip` not `hidden`: pre-reveal elements are translated ±28px horizontally
     and would otherwise widen the page. `hidden` would create a scroll container
     and break the `position: sticky` estimator column; `clip` does not. */
  overflow-x: clip;
}

body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'kern' 1, 'liga' 1, 'cv11' 1;
  overflow-x: clip;
}

img, picture, svg, video { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; }
ul, ol { list-style: none; padding: 0; }
a { color: inherit; text-decoration: none; }

/* Focus — never removed, always visible (a11y priority 1) */
:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}
.on-dark :focus-visible { outline-color: var(--brand-400); }

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

/* --------------------------------------------------------------------------
   3. TYPOGRAPHY
   -------------------------------------------------------------------------- */
h1, h2, h3, h4, .h4 {
  font-family: var(--font-display);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-wrap: balance;
  color: var(--fg);
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); line-height: 1.2; }
h4, .h4 { font-size: var(--fs-h4); line-height: 1.3; font-family: var(--font-body); font-weight: 600; letter-spacing: -0.01em; }

p { text-wrap: pretty; }

.display {
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.03em;
}

.lead {
  font-size: clamp(1.0625rem, 1rem + 0.4vw, 1.25rem);
  line-height: 1.65;
  color: var(--fg-muted);
  max-width: 56ch;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  font-family: var(--font-body);
}
.eyebrow::before {
  content: '';
  width: 28px; height: 1px;
  background: currentColor;
  opacity: .55;
}
.on-dark .eyebrow { color: var(--brand-400); }

/* Contact details are links inside headings — give them a 44px tap height */
h4 > a, .h4 > a { display: inline-flex; align-items: center; min-height: 44px; }
h4 > a:hover, .h4 > a:hover { color: var(--accent); }

.muted { color: var(--fg-muted); }
.serif-italic { font-family: var(--font-display); font-style: italic; font-weight: 400; }

/* --------------------------------------------------------------------------
   4. LAYOUT
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container-wide { max-width: 1440px; }
.container-narrow { max-width: 860px; }

.section { padding-block: var(--section-y); position: relative; }
.section-tight { padding-block: clamp(3rem, 2rem + 4vw, 5rem); }

.section-head { max-width: 60ch; margin-bottom: clamp(2.5rem, 2rem + 2vw, 4rem); }
.section-head > .eyebrow { margin-bottom: var(--sp-4); }
.section-head > h2 + p { margin-top: var(--sp-4); }
.section-head.center { margin-inline: auto; text-align: center; }
.section-head.center .lead { margin-inline: auto; }
.section-head.center .eyebrow::before { display: none; }

.on-dark { background: var(--stone-900); color: var(--stone-100); }
.on-dark h1, .on-dark h2, .on-dark h3, .on-dark h4, .on-dark .h4 { color: var(--white); }
.on-dark .lead, .on-dark .muted { color: var(--stone-300); }

.grid { display: grid; gap: var(--sp-5); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); }

.split {
  display: grid;
  gap: clamp(2rem, 1rem + 5vw, 5rem);
  align-items: center;
}
@media (min-width: 900px) { .split { grid-template-columns: 1fr 1fr; } }

.stack > * + * { margin-top: var(--sp-4); }
.divider { height: 1px; background: var(--border); border: 0; }
.on-dark .divider { background: rgba(255,255,255,.12); }

/* --------------------------------------------------------------------------
   5. BUTTONS
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--white);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 52px;              /* > 44px touch target */
  padding: 0 var(--sp-6);
  border-radius: var(--r-full);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: .01em;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: transform var(--t-base) var(--e-out),
              box-shadow var(--t-base) var(--e-out),
              background-color var(--t-base) var(--e-out),
              color var(--t-base) var(--e-out),
              border-color var(--t-base) var(--e-out);
  will-change: transform;
}
.btn svg { width: 18px; height: 18px; flex: none; transition: transform var(--t-base) var(--e-out); }

/* Brass sheen sweep on hover */
.btn::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(110deg, transparent 25%, rgba(255,255,255,.22) 50%, transparent 75%);
  transform: translateX(-120%);
  transition: transform 620ms var(--e-out);
  z-index: -1;
}
.btn:hover::after { transform: translateX(120%); }
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.btn:active { transform: translateY(0); transition-duration: 80ms; }
.btn:hover svg.arrow { transform: translateX(3px); }

.btn-accent { --btn-bg: var(--brand); --btn-fg: var(--white); }
.btn-accent:hover { --btn-bg: var(--brand-700); }

.btn-ghost {
  --btn-bg: transparent;
  --btn-fg: var(--ink);
  border: 1px solid var(--stone-300);
}
.btn-ghost:hover { --btn-bg: var(--white); border-color: var(--ink); }
/* The hero sits on a dark image, so its ghost buttons follow the dark rules too */
.on-dark .btn-ghost, .hero .btn-ghost { --btn-fg: var(--white); border-color: rgba(255,255,255,.28); }
.on-dark .btn-ghost:hover, .hero .btn-ghost:hover { --btn-bg: rgba(255,255,255,.08); border-color: rgba(255,255,255,.6); }

.btn-light { --btn-bg: var(--white); --btn-fg: var(--ink); }
.btn-sm { min-height: 44px; padding: 0 var(--sp-5); font-size: var(--fs-xs); }
.btn-block { width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .45; pointer-events: none; }

/* Text link with animated underline */
.link-u {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px;
  font-weight: 600; font-size: var(--fs-sm);
  color: var(--accent);
  cursor: pointer;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1.5px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  padding-bottom: 2px;
  transition: background-size var(--t-base) var(--e-out);
}
.link-u:hover { background-size: 100% 1.5px; }
.link-u svg { width: 16px; height: 16px; transition: transform var(--t-base) var(--e-out); }
.link-u:hover svg { transform: translateX(3px); }
.on-dark .link-u { color: var(--brand-400); }

/* --------------------------------------------------------------------------
   6. HEADER / NAV
   -------------------------------------------------------------------------- */
.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  height: var(--header-h);
  display: flex;
  align-items: center;
  transition: background-color var(--t-slow) var(--e-out),
              box-shadow var(--t-slow) var(--e-out),
              height var(--t-slow) var(--e-out);
}
.header::before {
  content: '';
  position: absolute; inset: 0;
  background: rgba(247,249,246,.88);
  backdrop-filter: blur(14px) saturate(180%);
  -webkit-backdrop-filter: blur(14px) saturate(180%);
  border-bottom: 1px solid var(--border);
  opacity: 0;
  transition: opacity var(--t-slow) var(--e-out);
}
.header.is-stuck::before { opacity: 1; }
.header.is-stuck { --header-h: 66px; }

.header .container {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-5); position: relative; z-index: 1; width: 100%;
}

/* Logo */
.logo { display: inline-flex; align-items: center; gap: 10px; flex: none; min-height: 44px; }
/* The mark is green dots on a WHITE field. On the light header that white sits
   almost flush with the page, so the dots read as floating — intended. A drop
   shadow here would turn it into a raised card, so there isn't one; a hairline
   ring gives it just enough edge on white surfaces without doing that. */
.logo-mark {
  width: 38px; height: 38px; flex: none;
  border-radius: 9px;
  object-fit: cover;
  box-shadow: inset 0 0 0 1px rgba(11,26,16,.06);
}
.logo-text { display: flex; flex-direction: column; line-height: 1; }
.logo-name {
  font-family: var(--font-display);
  font-size: 1.16rem; font-weight: 600; letter-spacing: -0.01em;
  color: var(--ink);
}
.logo-sub {
  font-size: 9.5px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--stone-600); font-weight: 600; margin-top: 3px;
}
/* Hero is dark → header text starts light, flips on scroll */
.header:not(.is-stuck) .logo-name,
.header:not(.is-stuck) .nav-link { color: var(--white); }
.header:not(.is-stuck) .logo-sub { color: rgba(255,255,255,.72); }
.header:not(.is-stuck) .btn-ghost { color: var(--white); border-color: rgba(255,255,255,.35); }
.header:not(.is-stuck) .btn-ghost:hover { background: rgba(255,255,255,.1); }
.header:not(.is-stuck) .burger span { background: var(--white); }
.header.no-hero:not(.is-stuck)::before { opacity: 1; }
.header.no-hero:not(.is-stuck) .logo-name { color: var(--ink); }
.header.no-hero:not(.is-stuck) .nav-link { color: var(--stone-700); }
.header.no-hero:not(.is-stuck) .logo-sub { color: var(--stone-600); }
.header.no-hero:not(.is-stuck) .btn-ghost { color: var(--ink); border-color: var(--stone-300); }
.header.no-hero:not(.is-stuck) .burger span { background: var(--ink); }

.nav { display: none; align-items: center; gap: var(--sp-6); }
@media (min-width: 1040px) { .nav { display: flex; } }

.nav-link {
  position: relative;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--stone-700);
  padding: var(--sp-2) 0;
  transition: color var(--t-base) var(--e-out);
}
.nav-link::after {
  content: '';
  position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1.5px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: right;
  transition: transform var(--t-base) var(--e-out);
}
.nav-link:hover::after, .nav-link[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }
.nav-link:hover { color: var(--accent); }

.header-actions { display: flex; align-items: center; gap: var(--sp-3); }
.header-phone { display: none; }
@media (min-width: 640px) { .header-phone { display: inline-flex; } }

/* Burger */
.burger {
  display: inline-flex; flex-direction: column; justify-content: center;
  gap: 5px; width: 46px; height: 46px; align-items: center;
  cursor: pointer; border-radius: var(--r-full); flex: none;
}
@media (min-width: 1040px) { .burger { display: none; } }
.burger span {
  display: block; width: 22px; height: 1.5px; background: var(--ink);
  border-radius: 2px;
  transition: transform var(--t-base) var(--e-out), opacity var(--t-fast) linear, background-color var(--t-base) var(--e-out);
}
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; transform: scaleX(.2); }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Mobile drawer */
.drawer {
  position: fixed; inset: 0; z-index: 99;
  background: var(--stone-50);
  padding: calc(var(--header-h) + var(--sp-6)) var(--gutter) var(--sp-8);
  display: flex; flex-direction: column;
  overflow-y: auto;
  clip-path: circle(0% at calc(100% - 46px) 38px);
  transition: clip-path 620ms var(--e-out);
  visibility: hidden;
}
.drawer.is-open { clip-path: circle(150% at calc(100% - 46px) 38px); visibility: visible; }
.drawer-nav { display: flex; flex-direction: column; }
.drawer-link {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 1.4rem + 1.8vw, 2.5rem);
  font-weight: 500; letter-spacing: -.02em;
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between;
  opacity: 0; transform: translateY(14px);
  transition: opacity 420ms var(--e-out), transform 420ms var(--e-out), color var(--t-base) var(--e-out);
}
.drawer.is-open .drawer-link { opacity: 1; transform: none; }
.drawer-link:hover { color: var(--accent); }
.drawer-link span { font-family: var(--font-body); font-size: var(--fs-xs); color: var(--stone-400); font-weight: 500; }
.drawer-foot { margin-top: auto; padding-top: var(--sp-7); display: grid; gap: var(--sp-3); }
body.is-locked { overflow: hidden; }

/* Sticky mobile call bar */
.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: var(--border);
  border-top: 1px solid var(--border);
  transform: translateY(105%);
  transition: transform var(--t-slow) var(--e-out);
  padding-bottom: env(safe-area-inset-bottom);
}
.callbar.is-visible { transform: none; }
@media (min-width: 1040px) { .callbar { display: none; } }
.callbar a {
  display: flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: 56px; background: var(--white);
  font-size: var(--fs-sm); font-weight: 600;
}
.callbar a.primary { background: var(--brand); color: var(--white); }
.callbar svg { width: 17px; height: 17px; }

/* --------------------------------------------------------------------------
   7. HERO
   -------------------------------------------------------------------------- */
.hero {
  position: relative;
  min-height: min(94svh, 900px);
  display: flex;
  align-items: flex-end;
  padding-top: calc(var(--header-h) + var(--sp-8));
  padding-bottom: var(--sp-8);
  overflow: hidden;
  background: var(--stone-900);
  color: var(--white);
}
.hero-media {
  position: absolute; inset: -8% 0 -8% 0;   /* overscan for parallax */
  z-index: 0;
  will-change: transform;
  /* Poster painted here rather than relying solely on the <video poster> so it
     still shows when no video is ever attached. Sized identically to the video
     (cover/center) so swapping between them is imperceptible. */
  background-color: var(--stone-900);
  background-image: url('../img/hero-poster.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
.hero-media img, .hero-media .ph { width: 100%; height: 100%; object-fit: cover; }

.hero-video {
  width: 100%; height: 100%;
  object-fit: cover;          /* fills the box without ever stretching */
  object-position: center;
  display: block;
  opacity: 0;                 /* poster shows through until the first frame paints */
  transition: opacity 700ms var(--e-out);
  pointer-events: none;
}
.hero-video.is-ready { opacity: 1; }
/* Tuned against the actual video, sampled across the whole loop rather than a
   single frame: the shot brightens noticeably around t≈4s, which dropped the
   worst-case text contrast to 3.7:1. These stops hold it above 4.5:1 (AA) at
   every point of the loop. Measured, not eyeballed — see README §11.
   If the video is ever replaced, re-check the darkest stop (72%). */
.hero-scrim {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to top, rgba(11,26,16,.94) 0%, rgba(11,26,16,.70) 40%, rgba(11,26,16,.52) 72%, rgba(11,26,16,.68) 100%),
    linear-gradient(to right, rgba(11,26,16,.62) 0%, transparent 68%);
}
.hero .container { position: relative; z-index: 2; width: 100%; }
.hero-inner { max-width: 780px; }
.hero h1 { color: var(--white); margin-block: var(--sp-5) var(--sp-5); }
.hero .lead { color: rgba(255,255,255,.82); }
.hero-cta { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-7); }

/* Word-by-word reveal (custom splitter — no paid GSAP plugin) */
.split-line { display: block; overflow: hidden; }
.split-word { display: inline-block; will-change: transform; }

/* Two-up grid rather than a single inline row: each badge now carries a heading
   and a line of supporting copy, which will not read as a list of chips. */
.hero-badges {
  display: grid;
  gap: var(--sp-4) var(--sp-6);
  grid-template-columns: 1fr;
  margin-top: var(--sp-7); padding-top: var(--sp-5);
  border-top: 1px solid rgba(255,255,255,.16);
}
@media (min-width: 620px) { .hero-badges { grid-template-columns: 1fr 1fr; } }

.hero-badge {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-3);
  align-items: start;
}
.hero-badge svg {
  width: 18px; height: 18px;
  color: var(--brand-400);
  flex: none;
  margin-top: 3px;
}
.hero-badge b {
  display: block;
  color: var(--white);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -.01em;
  line-height: 1.35;
}
.hero-badge span {
  display: block;
  color: rgba(255,255,255,.74);
  font-size: var(--fs-xs);
  line-height: 1.5;
  margin-top: 3px;
}

/* Anchored right, not centred — the hero copy is left-aligned and a centred
   cue collides with the badge row on short viewports */
.scroll-cue {
  position: absolute; right: var(--gutter); bottom: var(--sp-6); z-index: 3;
  display: none; flex-direction: column; align-items: center; gap: var(--sp-2);
  writing-mode: horizontal-tb;
  font-size: 10px; letter-spacing: .2em; text-transform: uppercase;
  color: rgba(255,255,255,.6);
}
@media (min-width: 1040px) { .scroll-cue { display: flex; } }
.scroll-cue i {
  display: block; width: 1px; height: 44px;
  background: linear-gradient(to bottom, rgba(255,255,255,.5), transparent);
  position: relative; overflow: hidden;
}
.scroll-cue i::after {
  content: ''; position: absolute; top: 0; left: 0; width: 1px; height: 14px;
  background: var(--brand-400);
  animation: cue 2.2s var(--e-io) infinite;
}
@keyframes cue { 0% { transform: translateY(-16px); opacity: 0 } 40% { opacity: 1 } 100% { transform: translateY(46px); opacity: 0 } }

/* --------------------------------------------------------------------------
   8. TRUST BAR / STATS
   -------------------------------------------------------------------------- */
.trustbar { background: var(--white); border-bottom: 1px solid var(--border); }
.trustbar-inner {
  display: grid; gap: var(--sp-5);
  grid-template-columns: repeat(2, 1fr);
  padding-block: var(--sp-6);
}
@media (min-width: 780px) { .trustbar-inner { grid-template-columns: repeat(4, 1fr); } }

.stat { text-align: center; position: relative; }
@media (min-width: 780px) { .stat + .stat::before {
  content: ''; position: absolute; left: 0; top: 12%; bottom: 12%; width: 1px; background: var(--border);
} }
.stat-num {
  font-family: var(--font-display);
  font-size: clamp(2rem, 1.5rem + 1.8vw, 3rem);
  font-weight: 500; line-height: 1; letter-spacing: -.03em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat-num .suffix { color: var(--accent); }
.stat-label {
  font-size: var(--fs-xs); color: var(--fg-muted); margin-top: var(--sp-2);
  letter-spacing: .04em;
}

/* Credential cells — verified facts only, no invented metrics */
/* Explicit 1 -> 3 columns rather than auto-fit.
   With exactly three items, auto-fit produces a two-column band (roughly
   600–815px, which includes iPad portrait at 768) that strands the third badge
   alone on its own row. Going straight from one column to three removes that
   state; three stacked rows read fine in between. */
.creds {
  display: grid; gap: var(--sp-5);
  grid-template-columns: 1fr;
  padding-block: var(--sp-6);
}
@media (min-width: 760px) {
  .creds { grid-template-columns: repeat(3, 1fr); }
}
.cred {
  display: flex; gap: var(--sp-4); align-items: flex-start;
  position: relative;
}
.cred + .cred::before {
  content: ''; position: absolute; left: calc(var(--sp-5) / -2); top: 6%; bottom: 6%;
  width: 1px; background: var(--border);
}
/* The divider sits in the column gap, so it must appear at exactly the width
   the grid becomes three columns — otherwise it either floats above a stacked
   item or goes missing from a row that has gaps. Keep in step with .creds. */
@media (max-width: 759px) { .cred + .cred::before { display: none; } }
.cred-icon {
  width: 42px; height: 42px; border-radius: var(--r-md); flex: none;
  display: grid; place-items: center;
  background: var(--brand-50); color: var(--brand);
}
.cred-icon svg { width: 21px; height: 21px; }
.cred b {
  display: block; font-size: var(--fs-sm); font-weight: 600;
  letter-spacing: -.01em; line-height: 1.35;
}
.cred span {
  display: block; font-size: var(--fs-xs); color: var(--fg-muted);
  margin-top: 3px; line-height: 1.5;
}

/* Brand gradient hairline — the one place the full logo gradient appears */
.grad-rule { height: 3px; background: var(--brand-grad); border: 0; }

/* Accreditation strip */
.accreds {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--sp-5) var(--sp-7);
  padding-block: var(--sp-5);
  border-top: 1px solid var(--border);
}
.accred {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  color: var(--stone-600); font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .06em; text-transform: uppercase;
  filter: grayscale(1); opacity: .72;
  transition: filter var(--t-base) var(--e-out), opacity var(--t-base) var(--e-out);
}
.accred:hover { filter: none; opacity: 1; }
.accred svg { width: 26px; height: 26px; color: var(--accent); flex: none; }

/* --------------------------------------------------------------------------
   9. CARDS
   -------------------------------------------------------------------------- */
.card {
  background: var(--bg-elevated);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  position: relative;
  overflow: hidden;
  transition: transform var(--t-slow) var(--e-out),
              box-shadow var(--t-slow) var(--e-out),
              border-color var(--t-slow) var(--e-out);
}
.card::before {
  content: ''; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--t-slow) var(--e-out);
}
.card:hover { transform: translateY(-5px); box-shadow: var(--shadow-lg); border-color: var(--stone-300); }
.card:hover::before { transform: scaleX(1); }

.card-icon {
  width: 52px; height: 52px; border-radius: var(--r-md);
  display: grid; place-items: center;
  background: var(--brand-50);
  color: var(--accent);
  margin-bottom: var(--sp-5);
  transition: background-color var(--t-base) var(--e-out), transform var(--t-slow) var(--e-out);
}
.card:hover .card-icon { background: var(--brand); color: var(--white); transform: scale(1.06) rotate(-3deg); }
.card-icon svg { width: 25px; height: 25px; }
.card h3 { margin-bottom: var(--sp-3); }
.card p { color: var(--fg-muted); font-size: var(--fs-sm); }
.card-list { margin-top: var(--sp-5); display: grid; gap: var(--sp-2); }
.card-list li {
  display: flex; gap: var(--sp-2); align-items: flex-start;
  font-size: var(--fs-sm); color: var(--fg-muted);
}
.card-list svg { width: 17px; height: 17px; color: var(--accent); flex: none; margin-top: 4px; }
.card-price {
  margin-top: var(--sp-5); padding-top: var(--sp-4);
  border-top: 1px dashed var(--border);
  font-size: var(--fs-xs); color: var(--fg-muted);
}
.card-price b { display: block; font-family: var(--font-display); font-size: 1.4rem; color: var(--ink); font-weight: 500; }

/* --------------------------------------------------------------------------
   10. IMAGE PLACEHOLDERS (swap for real <img> — see README)
   -------------------------------------------------------------------------- */
.ph {
  position: relative;
  background:
    linear-gradient(135deg, var(--stone-200) 0%, var(--stone-100) 45%, var(--stone-300) 100%);
  overflow: hidden;
  display: grid; place-items: center;
  isolation: isolate;
}
.ph::before {
  content: '';
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(11,26,16,.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(11,26,16,.05) 1px, transparent 1px);
  background-size: 44px 44px;
  mask-image: radial-gradient(ellipse at 30% 20%, #000, transparent 78%);
  -webkit-mask-image: radial-gradient(ellipse at 30% 20%, #000, transparent 78%);
}
.ph::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 70% 15%, rgba(124,198,26,.30), transparent 60%);
}
.ph-mark { position: relative; z-index: 2; width: 64px; height: 64px; color: var(--stone-500); opacity: .5; }
.ph-dark { background: linear-gradient(135deg, #1B3524 0%, #0E2015 52%, #234A2B 100%); }
/* The hero placeholder sits behind the headline — keep its motif near-invisible
   so it never competes with the copy. Irrelevant once a real photo is dropped in. */
.hero .ph-mark { opacity: .1; }
.ph-dark .ph-mark { color: var(--brand-400); opacity: .38; }

.media {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  aspect-ratio: 4 / 3;          /* reserves space → CLS < 0.1 */
  background: var(--stone-100);
}
/* .ph must be listed alongside img — without it the placeholder collapses to
   its icon height instead of filling the reserved aspect-ratio box */
.media img, .media .ph { width: 100%; height: 100%; object-fit: cover; }
.media-tall { aspect-ratio: 3 / 4; }
.media-wide { aspect-ratio: 16 / 9; }
.media-square { aspect-ratio: 1; }

/* Framed image with brand offset rule */
.media-framed { position: relative; }
.media-framed::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px rgba(11,26,16,.08);
  pointer-events: none;
}
.media-offset { position: relative; }
.media-offset::before {
  content: '';
  position: absolute;
  inset: 22px -22px -22px 22px;
  border: 1px solid var(--brand);
  border-radius: var(--r-lg);
  opacity: .4;
  z-index: -1;
}
@media (max-width: 640px) { .media-offset::before { inset: 14px -14px -14px 14px; } }

/* --------------------------------------------------------------------------
   11. PROCESS TIMELINE
   -------------------------------------------------------------------------- */
.process { position: relative; }
.process-track { position: relative; display: grid; gap: var(--sp-6); }
@media (min-width: 900px) { .process-track { grid-template-columns: repeat(3, 1fr); gap: var(--sp-7) var(--sp-6); } }

/* Progress rail — desktop horizontal, mobile vertical */
.process-rail {
  position: absolute; z-index: 0;
  background: rgba(255,255,255,.14);
}
@media (max-width: 899px) {
  .process-rail { left: 21px; top: 12px; bottom: 12px; width: 1px; }
  .process-track { padding-left: 58px; }
}
@media (min-width: 900px) { .process-rail { display: none; } }
.process-rail i {
  position: absolute; inset: 0 auto 0 0; width: 100%; height: 0;
  background: var(--brand-400);
  transform-origin: top;
}

.step { position: relative; z-index: 1; }
.step-num {
  width: 44px; height: 44px; border-radius: var(--r-full);
  display: grid; place-items: center;
  background: var(--stone-900);
  border: 1px solid rgba(255,255,255,.2);
  font-family: var(--font-display); font-size: 1rem; font-weight: 600;
  color: var(--brand-400);
  margin-bottom: var(--sp-4);
  transition: background-color var(--t-slow) var(--e-out), color var(--t-slow) var(--e-out), border-color var(--t-slow) var(--e-out);
}
@media (max-width: 899px) { .step-num { position: absolute; left: -58px; top: 0; margin: 0; } }
.step.is-active .step-num { background: var(--brand); color: var(--white); border-color: var(--brand); }
.step h3 { font-size: var(--fs-h4); font-family: var(--font-body); font-weight: 600; margin-bottom: var(--sp-2); }
.step p { font-size: var(--fs-sm); color: var(--stone-300); }
.step-meta {
  display: inline-block; margin-top: var(--sp-3);
  font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--brand-400); font-weight: 600;
}

/* --------------------------------------------------------------------------
   12. PORTFOLIO
   -------------------------------------------------------------------------- */
.filters {
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  margin-bottom: var(--sp-6);
}
.filter {
  min-height: 44px; padding: 0 var(--sp-5);
  border-radius: var(--r-full);
  border: 1px solid var(--border);
  background: var(--white);
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .03em;
  color: var(--fg-muted);
  cursor: pointer;
  transition: all var(--t-base) var(--e-out);
}
.filter:hover { border-color: var(--stone-400); color: var(--ink); }
.filter[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--white); }

.work-grid { display: grid; gap: var(--sp-5); grid-template-columns: repeat(auto-fill, minmax(min(100%, 330px), 1fr)); }
.work {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--stone-900);
  display: block;
  transition: transform var(--t-slow) var(--e-out), box-shadow var(--t-slow) var(--e-out);
}
.work.is-hidden { display: none; }
.work:hover { transform: translateY(-6px); box-shadow: var(--shadow-xl); }
.work-media { aspect-ratio: 4 / 5; overflow: hidden; }
.work-media img, .work-media .ph { width: 100%; height: 100%; object-fit: cover; transition: transform 900ms var(--e-out); }
.work:hover .work-media img, .work:hover .work-media .ph { transform: scale(1.06); }
.work-body {
  position: absolute; inset: auto 0 0 0;
  padding: var(--sp-7) var(--sp-5) var(--sp-5);
  /* Bathroom photography is usually bright, so this scrim has to carry the text
     on its own — do not weaken it to "let the image through". */
  background: linear-gradient(to top,
    rgba(11,26,16,.96) 0%,
    rgba(11,26,16,.88) 38%,
    rgba(11,26,16,.55) 72%,
    rgba(11,26,16,0) 100%);
  color: var(--white);
}
.work-tag {
  font-size: 10px; letter-spacing: .18em; text-transform: uppercase;
  color: var(--brand-400); font-weight: 700;
}
.work h3 { color: var(--white); font-size: var(--fs-h4); font-family: var(--font-display); font-weight: 500; margin-top: var(--sp-2); }
.work-meta {
  display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4);
  margin-top: var(--sp-3);
  font-size: var(--fs-xs); color: rgba(255,255,255,.75);
}
.work-meta span { display: inline-flex; align-items: center; gap: 6px; }
.work-meta svg { width: 14px; height: 14px; color: var(--brand-400); }
.work-cta {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: var(--sp-4);
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--white);
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height var(--t-slow) var(--e-out), opacity var(--t-slow) var(--e-out), margin-top var(--t-slow) var(--e-out);
}
.work:hover .work-cta, .work:focus-visible .work-cta { max-height: 30px; opacity: 1; }
.work-cta svg { width: 14px; height: 14px; }

/* --------------------------------------------------------------------------
   13. BEFORE / AFTER SLIDER
   -------------------------------------------------------------------------- */
.ba {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  /* 4/5 not 16/10: the real before/after photos are portrait 3:4 (bathrooms are
     tall, narrow rooms and get shot upright). A landscape box would crop them to
     a thin horizontal band. 4/5 keeps nearly the whole frame while staying
     shorter than a full 3/4 panel.
     max-width is essential: in the home-page split column this sits at ~480px,
     but on a case-study page the container is full width, and 4/5 of 1158px is
     a 1448px-tall slab taller than the viewport. */
  aspect-ratio: 4 / 5;
  max-width: 720px;
  margin-inline: auto;
}

/* Mixed-orientation pair (Woolwich: landscape before, portrait after).
   In the 4/5 box the landscape shot loses ~40% of its width to the cover crop.
   A square box splits the difference — each image gives up about 25% on its
   long axis instead of one being butchered. Apply to .ba on that page only. */
.ba.ba-square {
  aspect-ratio: 1 / 1;
  max-width: 640px;
  user-select: none;
  touch-action: pan-y;
  cursor: ew-resize;
  background: var(--stone-200);
}
.ba-layer { position: absolute; inset: 0; }
.ba-layer img, .ba-layer .ph { width: 100%; height: 100%; object-fit: cover; }
.ba-after { clip-path: inset(0 0 0 var(--pos, 50%)); }
.ba-tag {
  position: absolute; top: var(--sp-4);
  padding: 7px 14px; border-radius: var(--r-full);
  background: rgba(11,26,16,.72);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  color: var(--white);
  font-size: 10px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  pointer-events: none;
}
.ba-tag.before { left: var(--sp-4); }
.ba-tag.after { right: var(--sp-4); background: rgba(2,110,49,.9); }
.ba-handle {
  position: absolute; top: 0; bottom: 0;
  left: var(--pos, 50%);
  width: 2px; background: var(--white);
  transform: translateX(-1px);
  box-shadow: 0 0 0 1px rgba(11,26,16,.18);
  pointer-events: none;
}
.ba-knob {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%);
  width: 52px; height: 52px; border-radius: var(--r-full);
  background: var(--white);
  box-shadow: var(--shadow-lg);
  display: grid; place-items: center; grid-auto-flow: column; gap: 3px;
  color: var(--ink);
  transition: transform var(--t-base) var(--e-out);
}
.ba:hover .ba-knob { transform: translate(-50%, -50%) scale(1.08); }
.ba-knob svg { width: 15px; height: 15px; }
.ba-range {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0; cursor: ew-resize; margin: 0;
}
.ba-range:focus-visible + .ba-handle .ba-knob { outline: 3px solid var(--brand); outline-offset: 3px; }

/* --------------------------------------------------------------------------
   14. QUOTE ESTIMATOR
   -------------------------------------------------------------------------- */
.est {
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
}
/* The estimator's left-hand intro column.
   Sticky ONLY once .split is actually two columns (>=900px). Below that the two
   panels stack vertically, and a pinned first child collides with the estimator
   card scrolling past it — they render on top of each other.
   This must stay a class, not an inline style: inline styles beat media queries,
   which is exactly how that bug got in. */
.est-intro { position: static; }
@media (min-width: 900px) {
  .est-intro {
    position: sticky;
    top: calc(var(--header-h) + 2rem);
    align-self: start;   /* required — a stretched grid item cannot stick */
  }
}

.est-head { padding: var(--sp-6) var(--sp-6) 0; }
.est-progress { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-5); }
.est-bar { flex: 1; height: 4px; background: var(--stone-200); border-radius: var(--r-full); overflow: hidden; }
.est-bar i {
  display: block; height: 100%; width: 25%;
  background: var(--brand); border-radius: var(--r-full);
  transition: width var(--t-slow) var(--e-out);
}
.est-count { font-size: var(--fs-xs); font-weight: 600; color: var(--fg-muted); white-space: nowrap; font-variant-numeric: tabular-nums; }

.est-body { padding: var(--sp-6); min-height: 430px; position: relative; }
.est-step { display: none; }
.est-step.is-active { display: block; }
.est-step h3 { margin-bottom: var(--sp-2); }
.est-step > p.muted { font-size: var(--fs-sm); margin-bottom: var(--sp-5); }

.opts { display: grid; gap: var(--sp-3); }
.opts-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 190px), 1fr)); }

.opt { position: relative; }
.opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.opt label {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  min-height: 60px; padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  cursor: pointer;
  transition: all var(--t-base) var(--e-out);
  height: 100%;
}
.opt label:hover { border-color: var(--stone-400); background: var(--stone-50); }
.opt input:checked + label { border-color: var(--brand); background: var(--brand-50); box-shadow: 0 0 0 1px var(--brand); }
.opt input:focus-visible + label { outline: 2px solid var(--ring); outline-offset: 2px; }
.opt-check {
  width: 20px; height: 20px; border-radius: var(--r-full);
  border: 1.5px solid var(--stone-300);
  display: grid; place-items: center; flex: none; margin-top: 2px;
  transition: all var(--t-base) var(--e-out);
}
.opt input[type="checkbox"] + label .opt-check { border-radius: var(--r-sm); }
.opt input:checked + label .opt-check { background: var(--brand); border-color: var(--brand); }
.opt-check svg { width: 12px; height: 12px; color: var(--white); opacity: 0; transform: scale(.5); transition: all var(--t-base) var(--e-out); }
.opt input:checked + label .opt-check svg { opacity: 1; transform: scale(1); }
.opt-text b { display: block; font-size: var(--fs-sm); font-weight: 600; line-height: 1.35; }
.opt-text span { display: block; font-size: var(--fs-xs); color: var(--fg-muted); margin-top: 3px; line-height: 1.45; }

.field { display: grid; gap: var(--sp-2); }
.field label { font-size: var(--fs-xs); font-weight: 600; letter-spacing: .03em; }
.field label .req { color: var(--destructive); }
.field input, .field textarea, .field select {
  min-height: 52px; padding: var(--sp-3) var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--white); font-size: var(--fs-sm);
  transition: border-color var(--t-base) var(--e-out), box-shadow var(--t-base) var(--e-out);
  width: 100%;
}
.field textarea { min-height: 110px; resize: vertical; padding-top: var(--sp-3); line-height: 1.6; }
.field input:hover, .field textarea:hover { border-color: var(--stone-400); }
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--brand); box-shadow: 0 0 0 3px rgba(2,110,49,.14);
}
.field .hint { font-size: var(--fs-xs); color: var(--fg-muted); }

/* Error text. Scoped to .err itself, NOT to `.field .err` — the estimator's
   submit-failure message and the radio-group errors sit outside any .field, and
   when this was descendant-scoped they inherited nothing: body colour instead of
   red, and an unconstrained SVG that stretched to the full width of the flex
   line (222px tall). `flex: none` on the icon is what prevents that. */
/* The doubled class is deliberate, not a typo. It raises specificity to (0,2,0)
   so this beats `.card p { color: var(--fg-muted) }` (0,1,1) — the contact form
   is a .card, and without this its field errors render muted grey instead of
   red. Doubling rather than relying on source order keeps it robust if these
   blocks are ever reordered. */
.err.err {
  font-size: var(--fs-xs); color: var(--destructive); font-weight: 500;
  align-items: center; gap: 5px;
}
.err svg { width: 13px; height: 13px; flex: none; }

/* Field-level errors stay hidden until the field is marked invalid. Errors
   outside a .field are toggled by the `hidden` attribute in JS instead. */
.field .err { display: none; }
.field.is-invalid input, .field.is-invalid textarea { border-color: var(--destructive); }
.field.is-invalid .err { display: flex; }

.est-foot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-5) var(--sp-6);
  border-top: 1px solid var(--border);
  background: var(--stone-50);
}
.est-back { font-size: var(--fs-sm); font-weight: 600; color: var(--fg-muted); cursor: pointer; display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding-inline: 4px; }
.est-back:hover { color: var(--ink); }
.est-back svg { width: 15px; height: 15px; }
.est-back[hidden] { visibility: hidden; display: inline-flex; }

/* Result panel */
.est-result { text-align: center; padding-block: var(--sp-4); }
.est-figure {
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 1.6rem + 2.6vw, 3.5rem);
  font-weight: 500; letter-spacing: -.03em; line-height: 1.05;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin-block: var(--sp-4) var(--sp-2);
}
.est-figure em { font-style: normal; color: var(--stone-400); font-size: .55em; }
.est-breakdown {
  margin-top: var(--sp-5); text-align: left;
  border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden;
}
.est-breakdown li {
  display: flex; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-3) var(--sp-4);
  font-size: var(--fs-sm);
  border-bottom: 1px solid var(--border);
}
.est-breakdown li:last-child { border-bottom: 0; background: var(--stone-50); font-weight: 600; }
.est-breakdown span:first-child { color: var(--fg-muted); }
.est-breakdown b { font-weight: 600; font-variant-numeric: tabular-nums; }

.est-note {
  display: flex; gap: var(--sp-3); align-items: flex-start;
  margin-top: var(--sp-5); padding: var(--sp-4);
  background: var(--brand-50); border-radius: var(--r-md);
  font-size: var(--fs-xs); color: var(--stone-700); text-align: left; line-height: 1.6;
}
.est-note svg { width: 18px; height: 18px; color: var(--accent); flex: none; margin-top: 1px; }

.est-success { text-align: center; padding-block: var(--sp-7); }
.est-success .tick {
  width: 72px; height: 72px; border-radius: var(--r-full);
  background: var(--brand-50); color: var(--accent);
  display: grid; place-items: center; margin: 0 auto var(--sp-5);
}
.est-success .tick svg { width: 34px; height: 34px; }

/* Spinner */
.spinner {
  width: 17px; height: 17px; border-radius: var(--r-full);
  border: 2px solid rgba(255,255,255,.35); border-top-color: var(--white);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
   15. TESTIMONIALS
   -------------------------------------------------------------------------- */
.marquee { overflow: hidden; position: relative; padding-block: var(--sp-2); }
.marquee::before, .marquee::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: clamp(40px, 8vw, 140px); z-index: 2; pointer-events: none;
}
.marquee::before { left: 0; background: linear-gradient(to right, var(--stone-900), transparent); }
.marquee::after { right: 0; background: linear-gradient(to left, var(--stone-900), transparent); }
.marquee-track { display: flex; gap: var(--sp-5); width: max-content; will-change: transform; }

.quote {
  width: min(84vw, 400px); flex: none;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  display: flex; flex-direction: column;
}
.quote-stars { display: flex; gap: 3px; margin-bottom: var(--sp-4); }
.quote-stars svg { width: 16px; height: 16px; color: var(--brand-400); }
.quote blockquote {
  font-family: var(--font-display); font-size: 1.125rem; line-height: 1.55;
  color: var(--white); font-weight: 400; flex: 1;
}
.quote-author { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: 1px solid rgba(255,255,255,.12); }
.quote-avatar {
  width: 42px; height: 42px; border-radius: var(--r-full); flex: none;
  background: var(--brand); color: var(--white);
  display: grid; place-items: center;
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .04em;
}
.quote-author b { display: block; font-size: var(--fs-sm); color: var(--white); font-weight: 600; }
.quote-author span { display: block; font-size: var(--fs-xs); color: var(--stone-400); }

/* --------------------------------------------------------------------------
   16. FAQ
   -------------------------------------------------------------------------- */
.faq { border-top: 1px solid var(--border); }
.faq-item { border-bottom: 1px solid var(--border); }
.faq-q {
  width: 100%; text-align: left; cursor: pointer;
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-5);
  padding: var(--sp-5) 0; min-height: 64px;
  font-size: clamp(1rem, .95rem + .3vw, 1.1875rem);
  font-weight: 600; letter-spacing: -.01em;
  transition: color var(--t-base) var(--e-out);
}
.faq-q:hover { color: var(--accent); }
.faq-icon {
  width: 34px; height: 34px; border-radius: var(--r-full); flex: none;
  border: 1px solid var(--border);
  display: grid; place-items: center;
  transition: all var(--t-base) var(--e-out);
  position: relative;
}
.faq-icon::before, .faq-icon::after {
  content: ''; position: absolute; background: currentColor; border-radius: 2px;
  transition: transform var(--t-base) var(--e-out), opacity var(--t-base) var(--e-out);
}
.faq-icon::before { width: 12px; height: 1.5px; }
.faq-icon::after  { width: 1.5px; height: 12px; }
.faq-q[aria-expanded="true"] .faq-icon { background: var(--brand); border-color: var(--brand); color: var(--white); transform: rotate(180deg); }
.faq-q[aria-expanded="true"] .faq-icon::after { transform: scaleY(0); opacity: 0; }
.faq-a { overflow: hidden; height: 0; }
.faq-a-inner { padding-bottom: var(--sp-5); max-width: var(--maxw-prose); color: var(--fg-muted); font-size: var(--fs-sm); }
.faq-a-inner p + p { margin-top: var(--sp-3); }

/* --------------------------------------------------------------------------
   17. AREAS
   -------------------------------------------------------------------------- */
.areas { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.area {
  padding: 9px var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-full);
  font-size: var(--fs-xs); color: var(--fg-muted); font-weight: 500;
  background: var(--white);
  transition: all var(--t-base) var(--e-out);
}
.area:hover { border-color: var(--brand); color: var(--accent); background: var(--brand-50); }

/* --------------------------------------------------------------------------
   18. CTA BAND
   -------------------------------------------------------------------------- */
.cta-band { position: relative; overflow: hidden; background: var(--stone-900); }
.cta-band .ph, .cta-band img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .26; }
.cta-band .container { position: relative; z-index: 2; }
.cta-band-inner { text-align: center; max-width: 760px; margin-inline: auto; }
.cta-band-actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); justify-content: center; margin-top: var(--sp-7); }

/* --------------------------------------------------------------------------
   19. FOOTER
   -------------------------------------------------------------------------- */
.footer { background: var(--ink); color: var(--stone-300); padding-block: var(--sp-9) var(--sp-6); }
.footer-grid { display: grid; gap: var(--sp-7); }
@media (min-width: 780px) { .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: var(--sp-6); } }
.footer h4, .footer .h4 {
  font-family: var(--font-body); font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--white);
  margin-bottom: var(--sp-4);
}
/* Touch targets: links get vertical padding to clear 44px, and the grid gap is
   reduced to compensate so the footer doesn't grow taller than intended. */
.footer-links { display: grid; gap: var(--sp-1); }
.footer-links a {
  font-size: var(--fs-sm); color: var(--stone-400);
  display: flex; align-items: center; min-height: 44px;
  transition: color var(--t-base) var(--e-out);
}
.footer-links a:hover { color: var(--brand-400); }
.footer .logo-name { color: var(--white); }
.footer .logo-sub { color: var(--stone-500); }
.footer-blurb { font-size: var(--fs-sm); color: var(--stone-400); margin-top: var(--sp-4); max-width: 38ch; }
.footer-contact { display: grid; gap: var(--sp-2); }
.footer-contact a, .footer-contact p { display: flex; gap: var(--sp-3); font-size: var(--fs-sm); color: var(--stone-400); align-items: flex-start; }
.footer-contact a { min-height: 44px; align-items: center; }
.footer-contact a svg { margin-top: 0; }
.footer-contact a:hover { color: var(--brand-400); }
.footer-contact svg { width: 17px; height: 17px; color: var(--brand); flex: none; margin-top: 3px; }
/* Accreditation plaque.
   The official Constructionline and SSIP marks are dark artwork on transparency,
   so they cannot sit directly on the dark footer — the text would disappear.
   A white plaque is also what the schemes require: the logo reproduced
   unaltered, never recoloured or inverted. */
.footer-accreds {
  display: grid;
  gap: var(--sp-5);
  align-items: center;
  margin-top: var(--sp-8);
  padding-top: var(--sp-7);
  border-top: 1px solid rgba(255,255,255,.1);
}
@media (min-width: 760px) {
  .footer-accreds { grid-template-columns: auto 1fr; gap: var(--sp-7); }
}
/* Sits straight on the footer — no plaque. This only works because the artwork
   is the REVERSED variant: white field keyed out, neutral ink flipped to white,
   gold retained. The supplied original is a white rectangle with dark ink and
   would be unreadable here. See README §12 before swapping the file. */
.accred-plaque {
  display: grid;
  place-items: center;
  justify-self: start;
}
.accred-plaque img {
  width: 190px;
  height: auto;
  display: block;
}
@media (max-width: 420px) { .accred-plaque img { width: 160px; } }

.footer-accreds-copy b {
  display: block;
  color: var(--white);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: -.01em;
  margin-bottom: var(--sp-2);
}
.footer-accreds-copy p {
  color: var(--stone-400);
  font-size: var(--fs-sm);
  max-width: 52ch;
  margin: 0;
}

.footer-bottom {
  margin-top: var(--sp-8); padding-top: var(--sp-5);
  border-top: 1px solid rgba(255,255,255,.1);
  display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5);
  align-items: center; justify-content: space-between;
  font-size: var(--fs-xs); color: var(--stone-500);
}
.footer-bottom nav { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.footer-bottom nav a { display: inline-flex; align-items: center; min-height: 44px; padding-inline: 4px; }
.footer-bottom a:hover { color: var(--brand-400); }
.socials { display: flex; gap: var(--sp-2); }
.socials a {
  width: 44px; height: 44px; border-radius: var(--r-full);
  border: 1px solid rgba(255,255,255,.14);
  display: grid; place-items: center; color: var(--stone-400);
  transition: all var(--t-base) var(--e-out);
}
.socials a:hover { background: var(--brand); border-color: var(--brand); color: var(--white); transform: translateY(-2px); }
.socials svg { width: 17px; height: 17px; }

/* --------------------------------------------------------------------------
   20. CASE STUDY PAGE
   -------------------------------------------------------------------------- */
.cs-hero { padding-top: calc(var(--header-h) + var(--sp-8)); padding-bottom: var(--sp-7); }
.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); font-size: var(--fs-xs); color: var(--fg-muted); margin-bottom: var(--sp-5); }
.crumbs a { display: inline-flex; align-items: center; min-height: 44px; }
.crumbs a:hover { color: var(--accent); }
.crumbs svg { width: 13px; height: 13px; opacity: .5; }

.spec { border-top: 1px solid var(--border); }
.spec-row {
  display: grid; gap: var(--sp-1);
  padding: var(--sp-4) 0;
  border-bottom: 1px solid var(--border);
}
@media (min-width: 560px) { .spec-row { grid-template-columns: 150px 1fr; gap: var(--sp-5); align-items: baseline; } }
.spec-row dt { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--fg-muted); }
.spec-row dd { font-size: var(--fs-sm); margin: 0; }

/* Case-study lead image. Project photos are shot portrait (3:4) because
   bathrooms are tall, narrow rooms. A 16/9 hero would crop away most of the
   frame — on the Shepherd's Bush shot it cut off the basin entirely. Portrait
   ratio plus a max-width keeps the whole photo without a full-bleed slab. */
.cs-lead-media {
  aspect-ratio: 4 / 5;
  max-width: 760px;
  margin-inline: auto;
}

.gallery-grid { display: grid; gap: var(--sp-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.gallery-grid .media { aspect-ratio: 3/4; }
.gallery-grid .media.span-2 { grid-column: span 2; aspect-ratio: 16/10; }
/* Full-width panorama row. A 2.29:1 shot dropped into a 3/4 portrait cell keeps
   about a fifth of its width — it has to span the grid and carry its own ratio. */
.gallery-grid .media.media-pano {
  grid-column: 1 / -1;
  aspect-ratio: 2048 / 894;
}
@media (max-width: 700px) { .gallery-grid .media.span-2 { grid-column: span 1; aspect-ratio: 4/3; } }

.pull {
  border-left: 2px solid var(--brand);
  padding-left: var(--sp-5);
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 1.1rem + 1vw, 1.75rem);
  line-height: 1.4; font-style: italic; font-weight: 400;
  color: var(--ink);
}
.pull footer { font-family: var(--font-body); font-size: var(--fs-xs); font-style: normal; color: var(--fg-muted); margin-top: var(--sp-4); font-weight: 600; letter-spacing: .04em; }

/* --------------------------------------------------------------------------
   20b. LEGAL PAGES (privacy, terms, cookies)
   Long-form statutory text. Slightly wider measure than editorial prose and
   real list markers — the global reset strips them, which is fine for nav
   lists but wrong for a legal document where the bullets carry meaning.
   -------------------------------------------------------------------------- */
.legal { max-width: 74ch; }
.legal h2 {
  font-size: var(--fs-h3);
  margin-top: var(--sp-8);
  margin-bottom: var(--sp-4);
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
}
.legal h2:first-of-type { margin-top: 0; }
.legal h3 {
  font-family: var(--font-body);
  font-size: var(--fs-h4);
  font-weight: 600;
  letter-spacing: -0.01em;
  margin-top: var(--sp-6);
  margin-bottom: var(--sp-3);
}
.legal p { color: var(--fg-muted); margin-bottom: var(--sp-4); }
.legal ul {
  list-style: disc;
  padding-left: 1.3em;
  margin: 0 0 var(--sp-5);
  display: grid;
  gap: var(--sp-2);
}
.legal li { color: var(--fg-muted); }
.legal li::marker { color: var(--accent); }
.legal a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.legal a:hover { text-decoration-thickness: 2px; }
.legal strong { color: var(--fg); font-weight: 600; }

.legal-meta {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-xs); font-weight: 600;
  letter-spacing: .04em;
  color: var(--fg-muted);
  background: var(--brand-50);
  border: 1px solid var(--border);
  border-radius: var(--r-full);
  padding: 7px var(--sp-4);
}

/* Contents list — 21 sections is a lot to scroll blindly */
.legal-toc {
  background: var(--stone-100);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-5) var(--sp-6);
  margin-bottom: var(--sp-8);
}
.legal-toc h2 {
  font-family: var(--font-body);
  font-size: var(--fs-xs); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--fg);
  margin: 0 0 var(--sp-4);
}
.legal-toc ol {
  list-style: none; padding: 0; margin: 0;
  display: grid; gap: var(--sp-2);
  counter-reset: toc;
}
@media (min-width: 700px) { .legal-toc ol { grid-template-columns: 1fr 1fr; gap: var(--sp-2) var(--sp-5); } }
.legal-toc li { counter-increment: toc; }
.legal-toc a {
  display: flex; gap: var(--sp-3); align-items: baseline;
  font-size: var(--fs-sm); color: var(--fg-muted);
  text-decoration: none;
  padding: 5px 0;
}
.legal-toc a::before {
  content: counter(toc);
  font-variant-numeric: tabular-nums;
  color: var(--accent); font-weight: 600;
  min-width: 1.6em;
}
.legal-toc a:hover { color: var(--accent); }

.prose { max-width: var(--maxw-prose); }
.prose p + p { margin-top: var(--sp-4); }
.prose h3 { margin-top: var(--sp-6); margin-bottom: var(--sp-3); }
.prose p { color: var(--fg-muted); }

/* --------------------------------------------------------------------------
   21. ANIMATION HOOKS
   Elements are visible by default; JS hides them only if it runs.
   Guarantees no-JS users and crawlers see all content.
   -------------------------------------------------------------------------- */
html.js-anim [data-reveal] { opacity: 0; }
/* Once revealed we must cancel the offset at source. GSAP's clearProps removes
   only its own inline transform, which would fall back to the rules below and
   leave the element permanently displaced (and, being transformed, would also
   break position:sticky in any descendant). */
html.js-anim [data-reveal].is-revealed { opacity: 1; transform: none; }
html.js-anim [data-reveal="up"]    { transform: translateY(26px); }
html.js-anim [data-reveal="left"]  { transform: translateX(-28px); }
html.js-anim [data-reveal="right"] { transform: translateX(28px); }
html.js-anim [data-reveal="scale"] { transform: scale(.95); }
html.js-anim .split-word { opacity: 0; transform: translateY(105%); }

/* --------------------------------------------------------------------------
   22. UTILITIES
   -------------------------------------------------------------------------- */
.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 {
  position: absolute; left: var(--sp-4); top: -100px; z-index: 200;
  background: var(--ink); color: var(--white);
  padding: var(--sp-3) var(--sp-5); border-radius: var(--r-md);
  font-size: var(--fs-sm); font-weight: 600;
  transition: top var(--t-base) var(--e-out);
}
.skip:focus { top: var(--sp-4); }
.text-center { text-align: center; }
.mt-6 { margin-top: var(--sp-6); }
.mt-7 { margin-top: var(--sp-7); }
[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   23. REDUCED MOTION — full bypass
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  html.js-anim [data-reveal],
  html.js-anim .split-word { opacity: 1 !important; transform: none !important; }
  .marquee-track { transform: none !important; }
  .scroll-cue i::after { display: none; }
  .btn::after { display: none; }
  /* main.js already declines to attach a source; this is the belt-and-braces
     guarantee that the still poster is what gets seen. */
  .hero-video { display: none !important; }
}

/* --------------------------------------------------------------------------
   24. PRINT
   -------------------------------------------------------------------------- */
@media print {
  .header, .drawer, .callbar, .scroll-cue, .cta-band, .est { display: none !important; }
  body { background: #fff; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
}
