/* ===========================================================================
   JMC Builders - Paraparaumu, Kapiti Coast
   ---------------------------------------------------------------------------
   Cloned from haydeconstruction.co.nz (2026-09-30) and re-themed to the
   client's logo: the JMC BLUE of the wordmark (#22a9e1, sampled from the
   logo PNG), the LIGHT GREY of "BUILDERS" (#d2d3d5) and a CHARCOAL ground
   (#14171c) - the logo was drawn to sit on a dark background. Montserrat 800
   for headings, Montserrat 500 tracked out for the small uppercase labels
   (the wordmark is a heavy geometric sans), Red Hat Text for body. Every
   colour is a custom property here, so re-theming is one block.
   =========================================================================== */

:root {
  /* 🔴 JMC BLUE IS A FILL, NEVER TEXT ON A LIGHT SURFACE. Measured (WCAG relative luminance,
     2026-09-30):
       #22a9e1 on white   2.9:1   - unreadable as text, and under 3:1 even as a graphic
       #14171c on #22a9e1 6.3:1   - charcoal ink on blue is the button, the tick disc, the util bar
       #22a9e1 on #14171c 6.3:1   - blue on charcoal is the eyebrow, the icon, the nav hover
     So the three roles are split between the blue and a deep blue:
       --brand      the JMC blue. Fills under charcoal ink, and accents on charcoal surfaces.
       --brand-ink  the ink that sits ON the blue (buttons, discs). The charcoal.
       --brand-text brand-coloured TEXT on white: a deep blue, 6.65:1 on white and 6.1:1 on
                    the band, so eyebrows, text links and step numbers read as blue-family
                    without failing AA. */
  --brand:        #22a9e1;
  --brand-dk:     #1a94c6;   /* hover/pressed blue */
  --brand-ink:    #14171c;
  --brand-text:   #0a6389;
  --ink:          #14171c;   /* charcoal: body copy, the header, dark sections */
  --ink-2:        #1c2128;   /* charcoal panels, a step lighter than the header */
  --muted:        #4b5259;   /* secondary copy on white - 7.9:1 */
  --line:         #e2e4e7;
  --band:         #f2f5f7;   /* light cool grey band */
  --white:        #ffffff;
  --shadow:       0 10px 34px rgba(20,23,28,.10);
  --shadow-lg:    0 22px 60px rgba(20,23,28,.22);

  --wrap:         1180px;
  --pad:          clamp(20px, 4vw, 34px);
  --sec-y:        clamp(56px, 7.2vw, 92px);
  --radius:       4px;

  --hdr-h:        88px;
  --hdr-h-stuck:  68px;
  --util-h:       40px;

  /* Float bar (fleet component) - overridable from /dash via /api/config. Charcoal under blue
     icons (6.3:1), hovering to blue under charcoal icons. White icons on the blue would be 2.9:1
     and fail the 3:1 a UI component needs, so blue is never the resting fill under white. */
  --fb-bg:        var(--ink);
  --fb-icon:      #22a9e1;
  --fb-hover-bg:  var(--brand);
  --fb-hover-icon:#14171c;
}

/* --------------------------------------------------------------- fonts
   Self-hosted, latin subset only: 94 kB for the four files against a Google
   Fonts round trip plus a render-blocking stylesheet. Montserrat 800 for
   headings; Montserrat 500, tracked out, for the small uppercase labels that
   echo the logo's wordmark; Red Hat Text for body. */
@font-face {
  font-family: 'Montserrat';
  src: url('/assets/fonts/montserrat-800-latin.woff2') format('woff2');
  font-weight: 800; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/assets/fonts/montserrat-500-latin.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Red Hat Text';
  src: url('/assets/fonts/redhattext-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Red Hat Text';
  src: url('/assets/fonts/redhattext-700-latin.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}

/* --------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }
/* scroll-padding-top clears the sticky header on an in-page jump. Without it #enquire lands
   with the form's first label hidden behind the header, which reads as a broken anchor. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--hdr-h) + 16px); }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}
body {
  margin: 0;
  font-family: 'Red Hat Text', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  font-size: 17px;
  line-height: 1.68;
  color: var(--ink);
  background: var(--white);
  /* NOT overflow-x: hidden. That hides a real horizontal overflow rather than
     fixing it - on the last site in this fleet it concealed a 156px blowout on
     a 375px viewport and the page looked perfect. Measure
     documentElement.scrollWidth against clientWidth instead. */
}
img, svg, video { max-width: 100%; height: auto; display: block; }
a { color: var(--brand-text); }
h1, h2, h3, h4 {
  font-family: 'Montserrat', 'Red Hat Text', system-ui, sans-serif;
  font-weight: 800;
  line-height: 1.14;
  letter-spacing: -.012em;
  margin: 0 0 .5em;
  text-wrap: balance;
}
/* Headings are sentence case. The logo's capitals are carried by the small tracked labels
   (eyebrows, nav, trust strip) instead, so the display type stays readable at length. */
h1 { letter-spacing: -.016em; }
p { margin: 0 0 1.05em; }
p:last-child, ul:last-child, ol:last-child { margin-bottom: 0; }
ul, ol { margin: 0 0 1.05em; padding-left: 1.25em; }
li { margin-bottom: .4em; }
:focus-visible { outline: 3px solid var(--brand); outline-offset: 3px; }

.wrap { width: 100%; max-width: var(--wrap); margin: 0 auto; padding: 0 var(--pad); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--ink); color: #fff; padding: 12px 18px;
}
.skip:focus { left: 0; }

/* --------------------------------------------------------------- buttons
   The primary button is BLUE with charcoal ink, and hovers to charcoal with blue. The
   ghost button is a charcoal outline.
   🔴 Components must beat prose. `.prose a` is (0,1,1) and `.btn` is (0,1,0),
   so a body-link colour rule silently wins over a button's own colour - which
   on prestigepainters rendered every in-prose CTA at 1.00:1, invisible, and
   only looked right on hover. Body link rules below are scoped with
   :not(.btn):not(.tlink) for exactly that reason. */
.btn {
  display: inline-flex; align-items: center; gap: 11px;
  padding: 15px 26px;
  background: var(--brand); color: var(--brand-ink);
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 15px;
  letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none; border: 2px solid var(--brand); border-radius: var(--radius);
  cursor: pointer; transition: background .16s, color .16s, border-color .16s, transform .16s;
}
/* The ring-and-arrow glyph, drawn in CSS rather than shipped as an <svg> in
   every button, so a colour change is one rule. */
/* 🔴 A CSS mask uses the ALPHA channel only - colour is irrelevant. Drawing a white arrow on
   top of a black circle therefore masks NOTHING out and renders as a solid disc, which is exactly
   what shipped on the first deploy. The arrow has to be a hole: one path, fill-rule="evenodd", so
   the inner subpath subtracts from the outer one. */
.btn::before {
  content: ''; flex: 0 0 auto; width: 19px; height: 19px; border-radius: 50%;
  background: var(--brand-ink);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill-rule='evenodd' d='M12 1a11 11 0 1 0 0 22 11 11 0 0 0 0-22zM10 7l5 5-5 5z'/></svg>") center/contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path fill-rule='evenodd' d='M12 1a11 11 0 1 0 0 22 11 11 0 0 0 0-22zM10 7l5 5-5 5z'/></svg>") center/contain no-repeat;
}
.btn:hover { background: var(--ink); border-color: var(--ink); color: var(--brand); transform: translateY(-2px); }
.btn:hover::before { background: var(--brand); }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--ghost::before { background: var(--ink); }
.btn--ghost:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn--ghost:hover::before { background: var(--brand); }
.btn--light { background: #fff; color: var(--ink); border-color: #fff; }
.btn--light:hover { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.btn--full { width: 100%; justify-content: center; }
.btn--sm { padding: 11px 18px; font-size: 13.5px; }

/* Inline text link with the underline the reference uses. */
.tlink {
  color: var(--brand-text); font-weight: 700; text-decoration: none;
  border-bottom: 2px solid rgba(141,198,63,.8);
}
.tlink:hover { border-bottom-color: var(--ink); color: var(--ink); }

.eyebrow {
  display: inline-block;
  font-family: 'Montserrat', sans-serif; font-weight: 500;
  font-size: 13px; letter-spacing: .2em; text-transform: uppercase;
  color: var(--brand-text); margin-bottom: 12px;
}

/* --------------------------------------------------------------- utility bar
   Blue with charcoal ink (6.3:1), sitting above the charcoal header - the logo's two
   colours in the order the ute is signwritten. */
.util { background: var(--brand); color: var(--brand-ink); }
.util__in {
  min-height: var(--util-h);
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  font-family: 'Montserrat', sans-serif; font-weight: 500;
  font-size: 12.5px; letter-spacing: .12em; text-transform: uppercase;
}
.util__tag { color: var(--brand-ink); }
.util__phone { color: var(--brand-ink); font-weight: 800; text-decoration: none; white-space: nowrap; }
.util__phone:hover { text-decoration: underline; }
@media (max-width: 700px) {
  .util__tag { display: none; }
  .util__in { justify-content: center; }
}

/* --------------------------------------------------------------- header */
.hdr {
  position: sticky; top: 0; z-index: 90;
  background: var(--ink); border-bottom: 1px solid rgba(255,255,255,.08);
  transition: box-shadow .2s;
}
.hdr[data-stuck] { box-shadow: 0 4px 22px rgba(20,23,28,.35); }
.hdr__in {
  min-height: var(--hdr-h);
  display: flex; align-items: center; justify-content: space-between; gap: 22px;
  transition: min-height .2s;
}
.hdr[data-stuck] .hdr__in { min-height: var(--hdr-h-stuck); }

.brand { display: inline-flex; align-items: center; text-decoration: none; color: #fff; flex: 0 0 auto; }
/* The horizontal lockup (874x200), height-driven so it scales with the header. */
.brand__logo { height: 62px; width: auto; transition: height .2s; }
.hdr[data-stuck] .brand__logo { height: 50px; }
@media (max-width: 560px) { .brand__logo { height: 48px; } }

/* nowrap on purpose. With wrap, "Contact" silently drops to a second row and
   the header grows 60px at 1280px wide. The burger takes over at 1120px. */
.nav { display: flex; align-items: center; gap: 22px; flex-wrap: nowrap; margin-left: auto; }
.nav > a, .nav__dropbtn {
  font-family: 'Montserrat', sans-serif; font-weight: 500;
  font-size: 13.5px; letter-spacing: .12em; text-transform: uppercase;
  color: #fff; text-decoration: none; white-space: nowrap;
  background: none; border: 0; padding: 0; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
}
.nav > a:hover, .nav__dropbtn:hover,
.nav > a[aria-current="page"], .nav__drop[data-current] .nav__dropbtn { color: var(--brand); }
.nav__home { color: #fff; }
.nav__home svg { display: block; }

.nav__drop { position: relative; }
.nav__panel {
  position: absolute; top: calc(100% + 14px); left: 50%; transform: translateX(-50%) translateY(-6px);
  min-width: 300px; background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--brand);
  box-shadow: var(--shadow); padding: 8px; border-radius: var(--radius);
  display: flex; flex-direction: column;
  opacity: 0; visibility: hidden; transition: opacity .16s, transform .16s, visibility .16s;
}
.nav__drop:hover .nav__panel,
.nav__drop:focus-within .nav__panel,
.nav__drop[data-open] .nav__panel { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
/* A gap between the button and the panel breaks a hover journey; this bridges it. */
.nav__drop::after { content: ''; position: absolute; left: 0; right: 0; top: 100%; height: 16px; }
.nav__panel a {
  font-family: 'Red Hat Text', sans-serif; font-weight: 700; font-size: 15px;
  text-transform: none; letter-spacing: 0;
  color: var(--ink); text-decoration: none; padding: 9px 13px; border-radius: 3px;
}
.nav__panel a:hover, .nav__panel a[aria-current="page"] { background: var(--band); color: var(--brand-text); }

.hdr__cta { display: flex; align-items: center; gap: 12px; flex: 0 0 auto; }
.hdr__quote {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--brand); color: var(--brand-ink); text-decoration: none;
  padding: 12px 20px; border-radius: var(--radius);
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 13.5px;
  letter-spacing: .045em; text-transform: uppercase;
  transition: background .16s, color .16s;
}
.hdr__quote svg { color: var(--brand-ink); }
.hdr__quote:hover { background: #fff; color: var(--ink); }
.hdr__quote:hover svg { color: var(--ink); }

.burger { display: none; width: 44px; height: 44px; background: none; border: 0; padding: 10px; cursor: pointer; }
.burger span { display: block; height: 2.5px; background: #fff; margin: 4px 0; border-radius: 2px; transition: transform .2s, opacity .2s; }
.burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Mobile menu. Collapsed in plain CSS and opened by [data-open]; see the note in the
   max-width block below for why the collapse is not scoped to .cnc-js. */
.nav-m { display: none; border-top: 3px solid var(--brand); padding: 10px var(--pad) 22px; background: #fff; }
.nav-m a {
  display: block; padding: 12px 2px; text-decoration: none; color: var(--ink);
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 15px;
  border-bottom: 1px solid var(--line);
}
.nav-m__label {
  margin: 16px 0 2px; font-family: 'Montserrat', sans-serif; font-weight: 800;
  font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.nav-m__cta {
  margin-top: 14px; text-align: center; background: var(--brand); color: var(--brand-ink) !important;
  border-radius: var(--radius); border-bottom: 0 !important; text-transform: uppercase;
  letter-spacing: .045em; font-size: 14px;
}
.nav-m__cta--alt { background: var(--ink); color: #fff !important; }

@media (max-width: 1120px) {
  .nav { display: none; }
  .burger { display: block; }
  /* Collapsed from the FIRST paint, never by a class the deferred site.js adds: a phone used
     to paint this menu open and then close it, moving the whole page (a large layout shift
     in PageSpeed). No-JS visitors get the full list from the noscript style in the layout's
     head, which must use this same breakpoint. Fleet rollout 2026-10-06. */
  .nav-m[data-open] { display: block; }
}
@media (max-width: 560px) {
  .hdr__quote span { display: none; }
  .hdr__quote { padding: 12px 14px; }
}

/* --------------------------------------------------------------- hero
   Photo, dark gradient in the lower half only, copy bottom-left. The gradient
   does NOT cover the whole photograph, which is what keeps the roof visible
   and stops it reading as a stock banner. */
.hero { position: relative; background: var(--ink); overflow: hidden; }
.hero__bg { position: absolute; inset: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; }
.hero::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(0deg, rgba(20,23,28,.94) 12%, rgba(20,23,28,.72) 42%, rgba(20,23,28,.18) 78%, rgba(20,23,28,.05) 100%);
}
.hero__in {
  position: relative; z-index: 2;
  min-height: clamp(460px, 70vh, 720px);
  display: flex; flex-direction: column; justify-content: flex-end;
  padding-top: clamp(60px, 12vh, 130px); padding-bottom: clamp(38px, 6vh, 66px);
  color: #fff;
}
.hero--sm .hero__in { min-height: clamp(320px, 44vh, 460px); }
.hero__copy { max-width: 760px; }
.hero .eyebrow { color: var(--brand); }
.hero h1 { color: #fff; margin-bottom: .38em; }
/* Display type scales to the CONTENT, not to one clamp(). build.mjs measures
   each H1 and stamps the bucket - these run from 16 to 48 characters, and a
   single size either shrinks the short ones or takes the long ones to five
   lines and pushes the CTA off screen. Uppercase runs wider, so each bucket is
   a step under the reference's. */
h1[data-len="short"] { font-size: clamp(32px, 5.2vw, 56px); }
h1[data-len="long"]  { font-size: clamp(27px, 4.2vw, 46px); }
h1[data-len="xlong"] { font-size: clamp(24px, 3.5vw, 39px); }
.hero__lede { font-size: clamp(16.5px, 1.5vw, 18.5px); color: rgba(255,255,255,.93); max-width: 700px; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 13px; margin-top: 26px; }
.hero__cta .btn--ghost { color: #fff; border-color: rgba(255,255,255,.55); }
.hero__cta .btn--ghost::before { background: #fff; }
.hero__cta .btn--ghost:hover { background: #fff; border-color: #fff; color: var(--ink); }
.hero__cta .btn--ghost:hover::before { background: var(--ink); }

/* --------------------------------------------------------------- trust strip */
.trust { background: var(--ink-2); color: #fff; }
.trust__in {
  display: flex; flex-wrap: wrap; gap: 12px clamp(16px, 2.2vw, 30px);
  justify-content: center; padding: 20px 0;
}
/* Sized so all four items sit on ONE row from about 1180px up. At 13px with a 38px gap the
   fourth wrapped onto a line by itself, which reads as a layout fault rather than a design. */
.trust__item {
  display: inline-flex; align-items: center; gap: 9px;
  font-family: 'Montserrat', sans-serif; font-weight: 500;
  font-size: clamp(11px, 1vw, 12px); letter-spacing: .07em; text-transform: uppercase;
  color: #fff; white-space: nowrap;
}
@media (max-width: 720px) { .trust__item { white-space: normal; } }
.trust__item svg { color: var(--brand); flex: 0 0 auto; }

/* --------------------------------------------------------------- sections */
.sec { padding: var(--sec-y) 0; }
.sec--white { background: #fff; }
.sec--band { background: var(--band); }
.sec--dark { background: var(--ink); color: #fff; }
.sec--dark h2, .sec--dark h3 { color: #fff; }
.sec--dark .eyebrow { color: var(--brand); }
.sec--dark a:not(.btn):not(.tlink) { color: var(--brand); }
/* The brand band. Blue cannot carry white text (2.9:1), so the services band is the second charcoal
   surface with blue accents - the same charcoal-and-blue the logo is. Its own text colour is white, so every child that must stay readable states its
   colour explicitly - a row with a colour set is exactly what makes an embedded panel render
   white on white. */
.sec--brand { background: var(--ink-2); color: #fff; }
.sec--brand h2, .sec--brand h3 { color: #fff; }
.sec--brand .eyebrow { color: var(--brand); }
.sec--brand .sec__head p { color: rgba(255,255,255,.88); }

.sec__head { max-width: 780px; margin-bottom: clamp(30px, 4vw, 46px); }
.sec__head--c { margin-left: auto; margin-right: auto; text-align: center; }
/* 46px section headings, larger than the H1 on a phone, as the reference has it. */
.sec h2 { font-size: clamp(29px, 3.6vw, 46px); }
.sec__head p { font-size: 17.5px; color: var(--muted); margin-bottom: 0; }
.sec--dark .sec__head p { color: rgba(255,255,255,.86); }
.sec__after { margin-top: 26px; }

/* --------------------------------------------------------------- prose */
.prose { max-width: 780px; }
.prose h2 { font-size: clamp(25px, 2.7vw, 34px); margin-top: 1.7em; }
.prose h2:first-child { margin-top: 0; }
.prose h3 { font-size: clamp(19px, 1.8vw, 23px); margin-top: 1.5em; }
.prose > p:first-child { font-size: 18.5px; }
.prose .eyebrow + h2 { margin-top: 0; }
/* :not(.btn):not(.tlink) - see the note on .btn above. A bare `.prose a` rule
   outranks .btn and silently repaints every in-prose button. */
.prose a:not(.btn):not(.tlink) { color: var(--brand-text); text-decoration: underline; text-underline-offset: 3px; }
.prose a:not(.btn):not(.tlink):hover { color: var(--ink); }
.prose ul { list-style: none; padding-left: 0; }
.prose ul li { position: relative; padding-left: 32px; margin-bottom: .6em; }
.prose ul li::before {
  content: ''; position: absolute; left: 0; top: .42em;
  width: 20px; height: 20px; border-radius: 50%; background: var(--brand);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='12' fill='black'/></svg>") center/contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><circle cx='12' cy='12' r='12' fill='black'/></svg>") center/contain no-repeat;
}
.prose ul li::after {
  content: ''; position: absolute; left: 5px; top: .68em;
  width: 10px; height: 6px; border-left: 2.4px solid var(--brand-ink); border-bottom: 2.4px solid var(--brand-ink);
  transform: rotate(-45deg);
}
.prose ol { padding-left: 1.3em; }
.prose ol li::marker { font-family: 'Montserrat', sans-serif; font-weight: 800; color: var(--brand-text); }

/* Two-column: prose left, media right. */
.split { display: grid; grid-template-columns: 1.05fr .95fr; gap: clamp(30px, 5vw, 64px); align-items: start; }
.split--flip .split__media { order: -1; }
.split__media img { width: 100%; border-radius: var(--radius); box-shadow: var(--shadow); }
/* The SiteWise Gold badge (about page) is artwork on a white ground, not a photograph: no
   shadow, no full-width stretch, sat under the photograph on the white section it needs. */
.split__media img.badge { display: block; max-width: 380px; height: auto; margin: 22px auto 0; box-shadow: none; }
/* The LBP roundel and the NZCB shield under Jamie's photograph on the home page (Richard,
   2026-10-07). Flat artwork on a transparent ground: no radius, no shadow, and never stretched to
   the column. Both sit at ONE height so they read as a pair, which makes the shield (half the
   roundel's aspect) the narrower of the two. The width/height on the img tags are the file sizes
   (about 3x the rendered width); the height here wins. */
.creds { display: flex; justify-content: center; align-items: center; gap: clamp(26px, 4vw, 42px); margin-top: 28px; }
.split__media .creds img { width: auto; height: 168px; border-radius: 0; box-shadow: none; }
@media (max-width: 600px) { .split__media .creds img { height: 136px; } }
/* The copy column on a service page runs to several thousand pixels and the media column is one
   photograph, so without this the right-hand side is mostly empty space. Sticky keeps the photo
   in view as the copy scrolls past it. Desktop only - on a stacked layout it would pin the image
   over the text. */
@media (min-width: 901px) {
  .split__media { position: sticky; top: calc(var(--hdr-h) + 22px); }
}
@media (max-width: 900px) {
  .split { grid-template-columns: 1fr; }
  .split--flip .split__media { order: 0; }
}

/* --------------------------------------------------------------- service cards
   Photo, bold heading, copy - no bordered card and no hover lift, matching the
   reference. The whole tile is the link, so the markup uses <a> with <span>
   children (a <div> or <p> inside an <a> is invalid). */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: clamp(24px, 3vw, 38px); }
/* Three cards (every page but home hides its own service) sit as three across at a comfortable
   width; four on the home page. */
.cards--3 { max-width: 1180px; }
.cards--3 .card { max-width: 520px; }
.cards--4 { grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
.card { display: block; text-decoration: none; color: inherit; }
.card__img { display: block; overflow: hidden; border-radius: var(--radius); background: var(--ink); }
.card__img img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .5s ease; }
.card:hover .card__img img { transform: scale(1.045); }
.card__body { display: block; padding-top: 17px; }
.card h3 { font-size: 20px; margin-bottom: .42em; }
.card__p { display: block; font-size: 15.5px; line-height: 1.62; }
.card__more {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 13px;
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 13px;
  letter-spacing: .07em; text-transform: uppercase;
}
.card__more::after {
  content: ''; width: 15px; height: 9px; background: currentColor;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 12'><path d='M0 5h15L11 1l1.4-1.4L19 6l-6.6 6.4L11 11l4-4H0z' fill='black'/></svg>") center/contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 12'><path d='M0 5h15L11 1l1.4-1.4L19 6l-6.6 6.4L11 11l4-4H0z' fill='black'/></svg>") center/contain no-repeat;
  transition: transform .2s;
}
.card:hover .card__more::after { transform: translateX(4px); }
/* On the brand band every card element states its colour outright. Inheriting
   from the row is what renders a panel white on white. */
.sec--brand .card { color: #fff; }
.sec--brand .card h3 { color: #fff; }
.sec--brand .card__p { color: rgba(255,255,255,.88); }
.sec--brand .card__more { color: var(--brand); }

/* --------------------------------------------------------------- features */
.feats { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: clamp(24px, 3vw, 40px); }
.feat__img { border-radius: var(--radius); overflow: hidden; margin-bottom: 18px; }
.feat__img img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.feat h3 { font-size: 20px; }
.feat p { font-size: 15.5px; margin-bottom: 0; }

/* --------------------------------------------------------------- before and after
   Two labelled figures side by side. The labels are on the picture, black on
   blue for BEFORE and blue on charcoal for AFTER, so they read at a glance. */
.ba { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2.6vw, 30px); max-width: 1000px; margin: 0 auto; }
.ba__item { margin: 0; }
.ba__item img { width: 100%; border-radius: var(--radius); box-shadow: var(--shadow); aspect-ratio: 4 / 3; object-fit: cover; }
.ba__item figcaption { margin-top: 12px; font-size: 15px; color: var(--muted); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ba__tag {
  display: inline-block; padding: 4px 10px; border-radius: 3px;
  background: var(--brand); color: var(--brand-ink);
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 12px;
  letter-spacing: .1em; text-transform: uppercase;
}
.ba__tag--after { background: var(--ink); color: var(--brand); }
@media (max-width: 640px) { .ba { grid-template-columns: 1fr; } }

/* Tick list - 28px blue discs with a charcoal tick in each, rather than a
   different pictogram per row. */
.ticks { list-style: none; padding: 0; margin: 0; display: grid; gap: 15px; }
.ticks li { position: relative; padding-left: 44px; margin: 0; font-size: 16.5px; }
.ticks li strong { font-family: 'Montserrat', sans-serif; font-weight: 800; }
.ticks li::before {
  content: ''; position: absolute; left: 0; top: .16em;
  width: 28px; height: 28px; border-radius: 50%; background: var(--brand);
}
.ticks li::after {
  content: ''; position: absolute; left: 8px; top: .58em;
  width: 12px; height: 7px; border-left: 2.6px solid var(--brand-ink); border-bottom: 2.6px solid var(--brand-ink);
  transform: rotate(-45deg);
}
.sec--dark .ticks li { color: rgba(255,255,255,.94); }

/* --------------------------------------------------------------- numbered steps
   The step numbers are text, so on white they are the bronze (5.9:1) and on a
   dark surface the blue (6.3:1); blue on white would be 2.9:1. */
.steps { list-style: none; padding: 0; margin: 0; counter-reset: s; display: grid; gap: 26px; }
.steps li { counter-increment: s; position: relative; padding-left: 66px; margin: 0; }
.steps li::before {
  content: counter(s, decimal-leading-zero);
  position: absolute; left: 0; top: -2px;
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 30px;
  color: var(--brand-text); line-height: 1;
}
.sec--dark .steps li::before { color: var(--brand); }
.steps h3 { font-size: 19px; margin-bottom: .28em; }
.steps p { font-size: 15.5px; margin-bottom: 0; }
/* Two photographs under a step (new builds: Jamie's truck and digger photographs at step 3, the
   wrapped houses at step 4 - 2026-11-04). Two up beside the copy, one up on a phone, where two
   would be 140px wide each inside the step's number gutter. */
.steps__media { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 14px; }
.steps__media figure { margin: 0; }
.steps__media img { display: block; width: 100%; height: auto; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius); box-shadow: var(--shadow); }
@media (max-width: 560px) { .steps__media { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------- areas */
.areas { display: grid; grid-template-columns: repeat(auto-fit, minmax(285px, 1fr)); gap: clamp(22px, 2.6vw, 34px); }
/* Headings only since Rob's Capsule note 492073056 (2026-10-21), so the card is a short tile. */
.area { background: #fff; border-radius: var(--radius); padding: 20px 24px 22px; border-top: 3px solid var(--brand); box-shadow: var(--shadow); }
.area h3 { font-size: 19px; margin-bottom: 0; }

/* --------------------------------------------------------------- FAQ
   Bright photo behind a near-white panel with charcoal accordion bars that open
   to blue - not a darkened photo with white text on hairlines. */
.faq-sec { position: relative; background: var(--ink); }
.faq-sec__bg { position: absolute; inset: 0; }
.faq-sec__bg img { width: 100%; height: 100%; object-fit: cover; }
.faq-sec > .wrap { position: relative; z-index: 2; }
.faq-panel {
  background: rgba(255,255,255,.96); border-radius: var(--radius);
  padding: clamp(26px, 4vw, 52px); max-width: 900px; margin: 0 auto;
  box-shadow: var(--shadow-lg);
}
.faq-panel h2 { text-align: center; color: var(--ink); }
.faq-panel > p { text-align: center; color: var(--muted); max-width: 640px; margin: 0 auto 28px; }
.faq details { border-radius: var(--radius); margin-bottom: 10px; overflow: hidden; }
.faq summary {
  list-style: none; cursor: pointer;
  background: var(--ink); color: #fff;
  padding: 15px 52px 15px 20px; position: relative;
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 16px;
  border-radius: var(--radius);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; position: absolute; right: 19px; top: 50%; margin-top: -8px;
  width: 16px; height: 16px; background: var(--brand);
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 3h2v18h-2z M3 11h18v2H3z' fill='black'/></svg>") center/contain no-repeat;
          mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M11 3h2v18h-2z M3 11h18v2H3z' fill='black'/></svg>") center/contain no-repeat;
  transition: transform .2s;
}
.faq details[open] summary { background: var(--brand); color: var(--brand-ink); border-radius: var(--radius) var(--radius) 0 0; }
.faq details[open] summary::after { transform: rotate(45deg); background: var(--brand-ink); }
.faq__a { padding: 18px 20px 20px; background: #fff; border: 1px solid var(--line); border-top: 0; border-radius: 0 0 var(--radius) var(--radius); }
.faq__a p:last-child { margin-bottom: 0; }
.faq__a { font-size: 16px; }

/* --------------------------------------------------------------- gallery */
.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.gal__btn { padding: 0; border: 0; background: var(--ink); cursor: zoom-in; border-radius: var(--radius); overflow: hidden; display: block; }
.gal__btn img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; transition: transform .45s, opacity .2s; }
.gal__btn:hover img { transform: scale(1.05); opacity: .88; }

.lb { position: fixed; inset: 0; z-index: 200; background: rgba(9,10,11,.94); display: none; align-items: center; justify-content: center; padding: 5vh 6vw; }
.lb[data-open] { display: flex; }
.lb__img { max-width: 100%; max-height: 82vh; object-fit: contain; border-radius: var(--radius); }
.lb__cap { position: absolute; left: 0; right: 0; bottom: 3.4vh; text-align: center; color: rgba(255,255,255,.9); font-size: 14.5px; padding: 0 8vw; margin: 0; }
.lb__btn { position: absolute; background: rgba(255,255,255,.12); color: #fff; border: 0; cursor: pointer; width: 52px; height: 52px; border-radius: 50%; font-size: 30px; line-height: 1; }
.lb__btn:hover { background: var(--brand); color: var(--brand-ink); }
.lb__close { top: 3vh; right: 3vw; font-size: 34px; }
.lb__prev { left: 2vw; top: 50%; margin-top: -26px; }
.lb__next { right: 2vw; top: 50%; margin-top: -26px; }
body[data-lb] { overflow: hidden; }
body[data-lb] .hdr, body[data-lb] .util, body[data-lb] .floatbar { visibility: hidden; }

/* --------------------------------------------------------------- callout */
.callout { background: var(--ink-2); color: #fff; border-radius: var(--radius); padding: clamp(26px, 3.6vw, 42px); border-left: 6px solid var(--brand); }
.callout h2, .callout h3 { color: #fff; margin-top: 0; }
.callout p { color: rgba(255,255,255,.9); }
.callout .btn { background: var(--brand); color: var(--brand-ink); border-color: var(--brand); }
.callout .btn::before { background: var(--brand-ink); }
.callout .btn:hover { background: #fff; border-color: #fff; color: var(--ink); }
.callout .btn:hover::before { background: var(--ink); }

/* A full-width CTA band: blue under charcoal ink, the one place the brand colour carries a
   heading. Every child states its own colour, so nothing inherits white from a dark parent. */
.cta { background: var(--brand); color: var(--brand-ink); }
/* The side padding is restated: .cta__in sits on the same element as .wrap, and a shorthand with
   0 at the sides wiped the wrap's gutter, so the band's copy ran to the edge of a phone screen. */
.cta__in { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 22px 40px; padding: clamp(34px, 4.6vw, 56px) var(--pad); }
.cta h2 { color: var(--brand-ink); font-size: clamp(25px, 2.9vw, 36px); margin: 0 0 .25em; }
.cta p { color: var(--brand-ink); margin: 0; max-width: 640px; font-size: 17px; }
.cta .btn { background: var(--ink); border-color: var(--ink); color: #fff; }
.cta .btn::before { background: #fff; }
.cta .btn:hover { background: #fff; border-color: #fff; color: var(--ink); }
.cta .btn:hover::before { background: var(--ink); }
.cta .btn--ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.cta .btn--ghost::before { background: var(--ink); }
.cta .btn--ghost:hover { background: var(--ink); color: #fff; }
.cta .btn--ghost:hover::before { background: var(--brand); }
.cta__btns { display: flex; flex-wrap: wrap; gap: 12px; }

/* --------------------------------------------------------------- enquiry */
.enq { background: #fff; padding: var(--sec-y) 0; border-top: 1px solid var(--line); }
.enq__grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(32px, 5vw, 68px); align-items: start; }
.enq h2 { font-size: clamp(27px, 3.2vw, 40px); }
.enq__copy > p { color: var(--muted); }
.enq__big {
  display: inline-flex; align-items: center; gap: 13px; margin: 8px 0 22px;
  font-family: 'Montserrat', sans-serif; font-weight: 800;
  font-size: clamp(23px, 2.6vw, 31px); color: var(--ink); text-decoration: none;
}
.enq__big svg { color: var(--brand-text); }
.enq__big:hover { color: var(--brand-text); }
.enq__facts { list-style: none; padding: 0; margin: 0 0 18px; display: grid; gap: 12px; }
.enq__facts li { display: flex; gap: 12px; align-items: flex-start; margin: 0; font-size: 15.5px; color: var(--ink); }
.enq__facts svg { color: var(--brand-text); flex: 0 0 auto; margin-top: 4px; }
.enq__facts a { color: var(--brand-text); }
.enq__note { font-size: 15px; color: var(--muted); margin: 0; }

/* Dark form panel on a white section, as the reference has it.
   🔴 Every text element below states its own colour at two or more classes.
   A widget styled with single-class selectors, or one relying on
   `color: inherit`, renders white on its own white card the moment a parent
   row sets a colour - which is exactly the bug that reads as "nearly working"
   because the panel around it still looks perfect. */
.form { background: var(--ink-2); border-radius: var(--radius); padding: clamp(24px, 3.4vw, 38px); }
.form .form__row { margin-bottom: 15px; }
.form .form__row label {
  display: block; margin-bottom: 6px;
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 13px;
  letter-spacing: .05em; text-transform: uppercase; color: #ffffff;
}
.form .form__row input,
.form .form__row select,
.form .form__row textarea {
  width: 100%; padding: 12px 14px; font: inherit; font-size: 16px;
  color: #14171c; -webkit-text-fill-color: #14171c;   /* WebKit honours this over color */
  background: #ffffff; border: 1px solid #ffffff; border-radius: 3px;
}
.form .form__row select { appearance: none; background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'><path d='M6 8 0 0h12z' fill='%23000014'/></svg>"); background-repeat: no-repeat; background-position: right 14px center; background-size: 11px; padding-right: 38px; }
.form .form__row textarea { resize: vertical; min-height: 118px; }
.form .form__row input::placeholder,
.form .form__row textarea::placeholder { color: #6b7178; -webkit-text-fill-color: #6b7178; }
.form .form__row input:focus, .form .form__row select:focus, .form .form__row textarea:focus { outline: 3px solid var(--brand); outline-offset: 1px; }
.form .btn { background: var(--brand); border-color: var(--brand); color: #14171c; margin-top: 8px; }
.form .btn::before { background: #14171c; }
.form .btn:hover { background: #ffffff; border-color: #ffffff; color: #14171c; }
.form .btn:hover::before { background: #14171c; }
.form .err { display: block; color: #ffc4c4; font-size: 13.5px; margin-top: 5px; }
.form .form__msg { margin: 14px 0 0; font-size: 15px; color: #ffffff; }
.form .form__msg.err { color: #ffc4c4; }
.form .form__legal { margin: 14px 0 0; font-size: 13px; color: rgba(255,255,255,.72); }
/* Honeypot: off-canvas, not display:none or type=hidden - capable bots skip both. */
.hp { position: absolute; left: -9999px; top: 0; width: 1px; height: 1px; overflow: hidden; }

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

/* --------------------------------------------------------------- footer */
.ftr { background: var(--ink-2); color: rgba(255,255,255,.86); font-size: 15.5px; }
.ftr__grid { display: grid; grid-template-columns: 1fr 1fr 1.15fr; gap: clamp(28px, 4vw, 54px); padding-top: clamp(42px, 5vw, 66px); padding-bottom: 30px; }
.ftr__h {
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 20px;
  color: #fff; margin: 0 0 16px;
}
.ftr a { color: rgba(255,255,255,.86); text-decoration: none; }
.ftr a:hover { color: #fff; text-decoration: underline; }
.ftr__contact { list-style: none; padding: 0; margin: 0; display: grid; gap: 13px; }
.ftr__contact li { display: flex; gap: 12px; align-items: flex-start; margin: 0; }
.ftr__contact svg { color: var(--brand); flex: 0 0 auto; margin-top: 4px; }
.ftr__links { display: flex; flex-direction: column; }
.ftr__links a { padding: 8px 0; border-bottom: 1px solid rgba(255,255,255,.12); }
.ftr__logo { height: 64px; width: auto; margin-bottom: 16px; }
.ftr__badge { display: block; height: 52px; width: auto; margin-top: 16px; }
.ftr__grid p { color: rgba(255,255,255,.8); }
.ftr__areas-row { padding-bottom: 34px; border-top: 1px solid rgba(255,255,255,.12); padding-top: 28px; }
.ftr__areas-row .ftr__h { font-size: 17px; margin-bottom: 8px; }
.ftr__areas { margin: 0; color: rgba(255,255,255,.8); font-size: 15px; }
.ftr__areas .tlink { color: #fff; border-bottom-color: var(--brand); }
.ftr__areas .tlink:hover { color: var(--brand); }
.ftr__btm-wrap { background: var(--ink); }
.ftr__btm { padding: 17px 0; text-align: center; font-size: 14px; color: rgba(255,255,255,.72); display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 22px; }
/* The whole phrase is the link, not just the brand name - one credit unit and
   a bigger tap target. Underline on hover only, so it reads as a credit rather
   than competing with the footer nav. */
.ftr__credit { color: rgba(255,255,255,.72) !important; text-decoration: none; }
.ftr__credit:hover { color: #fff !important; text-decoration: underline; }
@media (max-width: 800px) { .ftr__grid { grid-template-columns: 1fr; } }

/* --------------------------------------------------------------- float bar
   Fleet component. Lower right per the fleet standard rather than vertically
   centred as the reference has it - that is a cross-site convention, not a
   per-site design choice. */
.floatbar { position: fixed; right: 18px; bottom: 18px; z-index: 95; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.floatbar__list { display: flex; flex-direction: column; gap: 10px; }
.floatbar__btn {
  width: 50px; height: 50px; border-radius: 50%;
  background: var(--fb-bg); color: var(--fb-icon);
  display: grid; place-items: center; border: 0; cursor: pointer;
  box-shadow: 0 6px 20px rgba(20,23,28,.28);
  transition: transform .18s, background .18s, color .18s, opacity .18s;
}
.floatbar__btn:hover { background: var(--fb-hover-bg); color: var(--fb-hover-icon); }
.cnc-js .floatbar:not([data-open]) .floatbar__list { opacity: 0; visibility: hidden; transform: translateY(10px); pointer-events: none; }
.cnc-js .floatbar .floatbar__list { transition: opacity .2s, transform .2s, visibility .2s; }
/* 🔴 Restate the hover transform AFTER the collapse rule. An equal-specificity
   `transform: none` later in the file wins, which is why the hover scale never
   fired in the jedibuilders reference implementation. */
.floatbar__btn:hover { transform: scale(1.08); }
.floatbar__toggle:hover { transform: scale(1.08); }

.fb-pop { position: fixed; inset: 0; z-index: 190; background: rgba(9,10,11,.6); display: none; align-items: center; justify-content: center; padding: 24px; }
.fb-pop[data-open] { display: flex; }
.fb-pop__card { background: #fff; border-radius: var(--radius); padding: 34px 40px; text-align: center; position: relative; max-width: 380px; }
.fb-pop__card p { color: var(--muted); font-size: 15px; }
.fb-pop__num { display: block; font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 29px; color: var(--ink); text-decoration: none; margin: 6px 0 10px; }
.fb-pop__close { position: absolute; top: 8px; right: 12px; background: none; border: 0; font-size: 28px; line-height: 1; cursor: pointer; color: var(--muted); }

/* --------------------------------------------------------------- reveal
   🔴 threshold: 0 with rootMargin only. A ratio threshold never fires on a copy
   column taller than about 16 viewports, which is most service pages, and the
   whole body then sits at opacity 0 until the visitor happens to scroll.
   All of it is scoped to .cnc-js so no-JS visitors and crawlers see everything. */
.cnc-js [data-reveal] { opacity: 0; transform: translateY(16px); transition: opacity .55s ease, transform .55s ease; }
.cnc-js [data-reveal].is-in { opacity: 1; transform: none; }
.cnc-js [data-reveal][data-delay="1"] { transition-delay: .09s; }
.cnc-js [data-reveal][data-delay="2"] { transition-delay: .18s; }
@media (prefers-reduced-motion: reduce) {
  .cnc-js [data-reveal] { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------- misc */
.lead { font-size: 19px; }
.center { text-align: center; }
.mt0 { margin-top: 0; }
.stack > * + * { margin-top: clamp(28px, 3.4vw, 46px); }

/* --------------------------------------------------------------- home hero
   The deck-and-ramp photograph is the point of the home page, so the gradient
   on the home hero is lighter and lower than on the inner pages: it darkens
   only the band the copy sits in and leaves the work visible. */
.hero--home::after {
  background: linear-gradient(0deg, rgba(20,23,28,.93) 10%, rgba(20,23,28,.72) 38%, rgba(20,23,28,.30) 68%, rgba(20,23,28,.06) 100%);
}
.hero--home .hero__bg img { object-position: 50% 40%; }
/* The copy can sit over pale decking or sky as well as over the darkened band, so every hero
   text element carries a soft shadow. */
.hero .eyebrow, .hero h1, .hero__lede { text-shadow: 0 1px 2px rgba(20,23,28,.55), 0 2px 18px rgba(20,23,28,.45); }
/* On a phone the whole photograph is behind the copy, so the band has to start higher. */
@media (max-width: 700px) {
  .hero--home::after {
    background: linear-gradient(0deg, rgba(20,23,28,.94) 12%, rgba(20,23,28,.72) 48%, rgba(20,23,28,.30) 80%, rgba(20,23,28,.08) 100%);
  }
}


/* --------------------------------------------------------------- about hero
   A PORTRAIT, not a house. The short hero strip is about 3:1 on a desktop, and a centred cover
   crop of a photograph of a person cuts him off at the eyes (it did - Rob, 2026-09-30). Anchoring
   the same full-width image to the top kept his head but filled the strip with a face a third of
   a metre tall. So on a desktop the photograph is a PANEL on the right 58% of the hero, anchored
   to the top, fading into the charcoal the copy sits on: head, shoulders and shirt at a sensible
   size, and no text over his face. The image keeps the full height of the original and is trimmed
   on the right (HERO_ABOUT in build/images.mjs), which sits him in the middle of that panel. The
   22vw floor stops an ultrawide screen making the strip shallower than his head and shoulders.
   Checked at 390, 768, 1440, 1920 and 2560 wide with build/shots-local.mjs - look at all five
   again after touching any number here. */
.hero--about .hero__bg img { object-position: 68% 0; }
.hero--about .hero__in { min-height: max(clamp(320px, 44vh, 460px), 22vw); }
.hero--about .hero__copy { max-width: 560px; }
@media (min-width: 901px) {
  .hero--about .hero__bg { left: auto; width: 58%; }
  .hero--about .hero__bg img { object-position: 50% 0; }
  .hero--about::after {
    background:
      linear-gradient(90deg, rgba(20,23,28,1) 42%, rgba(20,23,28,.55) 54%, rgba(20,23,28,0) 70%),
      linear-gradient(0deg, rgba(20,23,28,.62) 0%, rgba(20,23,28,0) 34%);
  }
}
/* Tablet: the photograph is full width again and he sits on the right, so the copy keeps to the
   left half rather than running across his beard. */
@media (min-width: 701px) and (max-width: 900px) {
  .hero--about .hero__copy { max-width: 52%; }
}
/* On a phone the copy is as wide as the screen, so it has to sit BELOW his face rather than
   beside it: the extra room at the top of the hero is the room his head and shoulders occupy. */
@media (max-width: 700px) {
  .hero--about .hero__in { padding-top: 56vw; }
}

/* The projects hero: the house is in the upper half of the frame. */
.hero--projects .hero__bg img { object-position: 50% 30%; }

/* --------------------------------------------------------------- projects
   One section per job: the heading, a facts list across the full width, then the photographs in
   the order they were taken, each with a visible caption. There is no running copy beside the
   facts since Rob's Capsule note 492073056 (2026-10-21), so the facts sit under the heading in
   columns rather than in a side panel. The facts are a <dl>, so a screen reader hears
   "Where: Raumati Beach" rather than a run of loose phrases. Every element states its own colour:
   the sections alternate white and band, and the captions sit on the charcoal of the button. */
.prj__head { margin-bottom: clamp(22px, 3vw, 34px); }
.prj__copy h2 { margin-bottom: .6em; }
.prj__facts {
  margin: 0; background: #fff; border: 1px solid var(--line); border-top: 4px solid var(--brand);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 6px 24px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); column-gap: 32px;
}
.prj__facts div { padding: 12px 0; }
.prj__facts dt {
  font-family: 'Montserrat', sans-serif; font-weight: 500; font-size: 12px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--muted); margin-bottom: 3px;
}
.prj__facts dd { margin: 0; font-size: 15.5px; line-height: 1.5; color: var(--ink); }

/* Two across on a phone. One across made the page 35,000px tall - 54 photographs in a single
   column - and the lightbox is where a photograph gets looked at properly anyway. */
@media (max-width: 600px) {
  .gal--prj { grid-template-columns: 1fr 1fr; gap: 10px; }
}
/* The caption bar under each project photograph went on 2026-11-10 (Rob's Capsule note
   494006814), and with it the rule that stopped the hover zoom painting over the caption. */
.gal--prj .gal__btn { text-align: left; font: inherit; }
.gal--prj .gal__btn img { display: block; }

/* The jump list at the top of the projects page. Kept OUTSIDE .prose, whose link rule would
   repaint it. */
.prj-index { list-style: none; padding: 0; margin: 30px 0 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 10px; }
.prj-index li { margin: 0; }
.prj-index a {
  display: block; height: 100%; padding: 12px 16px; background: var(--band); color: var(--ink);
  border-left: 4px solid var(--brand); border-radius: var(--radius); text-decoration: none;
  font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 15px; line-height: 1.3;
  transition: background .16s, color .16s;
}
.prj-index a span {
  display: block; margin-bottom: 3px; font-weight: 500; font-size: 11.5px;
  letter-spacing: .14em; text-transform: uppercase; color: var(--brand-text);
}
.prj-index a:hover { background: var(--ink); color: #ffffff; }
.prj-index a:hover span { color: var(--brand); }

/* --------------------------------------------------------------- testimonials
   Plain quotes, no stars and no Review markup: a business's own testimonials are not
   eligible for review rich results. Two or three across on desktop, one column on a phone. */
.quotes { display: grid; gap: clamp(18px, 2.6vw, 30px); margin: 0 auto; }
.quotes--2 { grid-template-columns: repeat(2, 1fr); max-width: 1000px; }
.quotes--3 { grid-template-columns: repeat(3, 1fr); }
.quotes--5 { grid-template-columns: repeat(2, 1fr); }
.quote { margin: 0; background: var(--white); border: 1px solid var(--line); border-top: 4px solid var(--brand); border-radius: var(--radius); padding: clamp(20px, 2.6vw, 30px); box-shadow: var(--shadow); display: flex; flex-direction: column; }
.sec--band .quote, .sec--white .quote { background: var(--white); }
.sec--dark .quote { background: var(--ink-2); border-color: rgba(255,255,255,.08); }
.quote blockquote { margin: 0 0 16px; padding: 0; border: 0; flex: 1 1 auto; }
.quote blockquote p { font-size: 15.5px; line-height: 1.65; margin: 0; color: var(--ink); }
.sec--dark .quote blockquote p { color: rgba(255,255,255,.92); }
.quote blockquote p::before { content: 'C'; font-family: 'Montserrat', sans-serif; font-weight: 800; font-size: 2.2em; line-height: 0; color: var(--brand); vertical-align: -0.35em; margin-right: 4px; }
.quote figcaption { font-family: 'Montserrat', sans-serif; font-weight: 500; font-size: 13px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.quote figcaption strong { font-weight: 800; color: var(--brand-text); display: block; letter-spacing: .02em; text-transform: none; font-size: 15px; }
.sec--dark .quote figcaption { color: rgba(255,255,255,.7); }
.sec--dark .quote figcaption strong { color: var(--brand); }
@media (max-width: 900px) { .quotes--3 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px) { .quotes--2, .quotes--3, .quotes--5 { grid-template-columns: 1fr; } }
