/* ===========================================================================
   Trust Solar New Zealand - Riverhead, Auckland
   ---------------------------------------------------------------------------
   DARK-DOMINANT, one gold accent. That is not a style preference: the client's
   own logo artwork sets "TRUST" in WHITE with a gold sun-and-panel mark, so the
   lockup cannot be placed on a light surface at all, and the only art direction
   they supplied was a vehicle-wrap mockup - near-black truck, gold wordmark,
   thin gold pinstripe (Capsule note 2026-08-30).

   Sampled from that artwork: gold #D9A441, body near-black #0B0C0F.

   Every ratio below is MEASURED (WCAG relative-luminance formula), and the
   numbers decide which token carries text. A dark ground makes this simpler
   than the light template it was cloned from - ONE gold clears AA everywhere,
   where the teal needed four separate steps:

       #D9A441 gold on #0B0C0F page      =  8.70:1   text AND graphics
       #D9A441 gold on #16171C card      =  7.95:1   text on a raised surface
       #0B0C0F ink  on #D9A441 gold      =  8.70:1   the BUTTON - dark on gold
       #E7E9ED type on #0B0C0F page      = 16.10:1
       #A2A7B3 muted on #0B0C0F page     =  8.13:1
       #A2A7B3 muted on #16171C card     =  7.43:1
       #FF8F84 error on #16171C card     =  8.11:1

   🔴 The button is DARK TYPE ON GOLD, never white on gold: white on #D9A441 is
   2.25:1 and unreadable. The same rule drives the floating contact bar, whose
   fleet default is white icons on the accent - see --fb-icon below.

   The token NAMES are inherited from the fleet template (--brand / --red /
   --ink) because ~250 rules reference them. --ink now means TYPE and never a
   surface; --panel is the dark surface it used to double as.
   =========================================================================== */

:root {
  --brand:        #D9A441;   /* the logo gold. Graphics, and TEXT on any dark surface here */
  --brand-bg:     #D9A441;   /* gold surface carrying DARK ink - 8.70:1 */
  --brand-dk:     #EBC275;   /* hover on a gold surface: goes LIGHTER, dark ink stays readable */
  --brand-lt:     #EBC275;   /* lighter gold for small graphics and icons on dark */
  --brand-dkr:    #D9A441;   /* alias - this site has no light surface needing a darker step */
  --brand-soft:   #241F14;   /* gold-tinted dark wash - tints, icon discs, hover fills */

  /* The template's second family. This site has ONE accent, so these alias the gold. */
  --red:          #D9A441;
  --red-bg:       #D9A441;
  --red-dk:       #EBC275;
  --red-soft:     #241F14;

  /* 🔴 --ink is TYPE ONLY. Where the light template used it as a dark background, those rules
     now use --panel. Mixing the two is what turns a dark section white-on-white. */
  --ink:          #E7E9ED;   /* body type - 16.1:1 on the page ground */
  --ink-2:        #101116;   /* deep panel: hero, enquiry band, footer */
  --ink-0:        #08090B;   /* deepest strip: utility bar, footer bottom bar */
  --panel:        #101116;   /* what --ink meant when it was a BACKGROUND */
  --muted:        #A2A7B3;   /* secondary copy - 8.13:1 on page, 7.43:1 on a card */
  --line:         #2C2F38;
  --band:         #101116;   /* the alternating band */
  --surface:      #16171C;   /* raised card surface - what was #fff */
  --surface-2:    #1D1F26;   /* input fields, hover fills */
  --page:         #0B0C0F;   /* the body ground */
  --white:        #ffffff;
  --err:          #FF8F84;   /* 8.11:1 on a card. The gold is the ACTION colour and must never
                                double as the warning colour. */

  /* Shadows do almost nothing on a dark ground - depth here comes from the border and a
     slightly lighter surface. Kept (deeper and blacker) only so the tokens stay valid. */
  --shadow:       0 6px 24px rgba(0,0,0,.5), 0 2px 6px rgba(0,0,0,.4);
  --shadow-md:    0 14px 40px rgba(0,0,0,.55), 0 3px 10px rgba(0,0,0,.4);
  --shadow-lg:    0 26px 70px rgba(0,0,0,.7);

  --wrap:         1180px;
  --pad:          clamp(20px, 4vw, 34px);
  --sec-y:        clamp(60px, 7.4vw, 100px);
  --radius:       8px;
  --radius-sm:    5px;

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

  /* Float bar (fleet component) - overridable from /dash via /api/config.
     🔴 Re-themed, not pasted. The component's default is --fb-icon:#fff, which on this gold is
     2.25:1 - under the 3:1 WCAG 1.4.11 wants for a UI component, and the exact mistake the fleet
     notes call out. Dark ink on the gold is 8.70:1 and matches the primary button, which is the
     same action. */
  --fb-bg:        var(--brand-bg);
  --fb-icon:      #0B0C0F;
  --fb-hover-bg:  #EBC275;
  --fb-hover-icon:#0B0C0F;
}

/* --------------------------------------------------------------- fonts
   Self-hosted, latin subset only: 43 kB for the pair against a Google Fonts
   round trip plus a render-blocking stylesheet. The reference pairs Mulish 800
   for headings with Red Hat Text for body, and that pairing is most of why it
   reads the way it does. */
@font-face {
  font-family: 'Mulish';
  src: url('/assets/fonts/mulish-800-latin.woff2') format('woff2');
  font-weight: 800; 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(--page);
  /* 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; }
/* <picture> defaults to display:inline, so it does not establish a block box for the <img>
   inside it. Every photograph on this site is wrapped in one (WebP source + JPEG fallback),
   so leaving it inline puts an inline wrapper around a block image in a grid cell - which
   creates baseline gaps under the image and makes width/aspect-ratio resolve against the
   wrong box. Set it once here rather than per component. */
picture { display: block; }
a { color: var(--brand-dkr); }
h1, h2, h3, h4 {
  font-family: 'Mulish', 'Red Hat Text', system-ui, sans-serif;
  font-weight: 800;
  line-height: 1.14;
  letter-spacing: -.012em;
  margin: 0 0 .5em;
  text-wrap: balance;
}
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(--brand-bg); color: #0B0C0F; padding: 12px 18px;
}
.skip:focus { left: 0; }

/* --------------------------------------------------------------- buttons
   🔴 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-bg); color: #0B0C0F;
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 15px;
  letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none; border: 2px solid var(--brand-bg); 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);
  -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;
}
/* PRIMARY = GOLD WITH DARK TYPE. 🔴 Not white on gold - that is 2.25:1 and unreadable. The
   logo's gold is a fill meant to sit behind dark ink, exactly as it does on the vehicle wrap,
   and #0B0C0F on it measures 8.70:1. Hover goes LIGHTER rather than darker, because darkening a
   mid gold walks it towards the page ground and the button dissolves. */
.btn { background: var(--brand-bg); color: #0B0C0F; border-color: var(--brand-bg); }
.btn::before { background: #0B0C0F; }
.btn:hover {
  background: var(--brand-dk); border-color: var(--brand-dk);
  transform: translateY(-2px); box-shadow: var(--shadow-md);
}
.btn:hover::before { background: #0B0C0F; }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn--ghost::before { background: var(--brand); }
.btn--ghost:hover { background: var(--brand-bg); border-color: var(--brand-bg); color: #0B0C0F; }
.btn--ghost:hover::before { background: #0B0C0F; }
/* Ghost button on a DARK surface (hero, enquiry band): white type and a translucent rule. */
.hero .btn--ghost, .enq .btn--ghost, .sec--dark .btn--ghost { color: #fff; border-color: rgba(255,255,255,.42); }
.hero .btn--ghost::before, .enq .btn--ghost::before, .sec--dark .btn--ghost::before { background: var(--brand-lt); }
.hero .btn--ghost:hover, .enq .btn--ghost:hover, .sec--dark .btn--ghost:hover { background: #fff; border-color: #fff; color: #0B0C0F; }
.hero .btn--ghost:hover::before, .enq .btn--ghost:hover::before, .sec--dark .btn--ghost:hover::before { background: #0B0C0F; }
/* .btn--light is the inverse CTA: white fill, dark type. On a dark site it is the loudest thing
   available, so it is reserved for a gold band where a gold button would vanish. */
.btn--light { background: #fff; color: #0B0C0F; border-color: #fff; }
.btn--light::before { background: #0B0C0F; }
.btn--light:hover { background: var(--brand-bg); border-color: var(--brand-bg); color: #0B0C0F; }
.btn--light:hover::before { background: #0B0C0F; }
.btn--full { width: 100%; justify-content: center; }
.btn--sm { padding: 11px 18px; font-size: 13.5px; }

/* Inline text link. */
.tlink {
  color: var(--brand-dkr); font-weight: 700; text-decoration: none;
  border-bottom: 2px solid rgba(0,152,160,.45);
}
.tlink:hover { border-bottom-color: var(--brand); }

.eyebrow {
  display: inline-block;
  font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 12.5px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--brand-dkr); margin-bottom: 13px;
}
/* A short cyan rule under the eyebrow. Cheap, and it is the one place the raw logo cyan can be
   used at full strength on white without a contrast problem, because it is a graphic and not
   text. */
.eyebrow::after {
  content: ''; display: block; width: 34px; height: 3px; border-radius: 2px;
  background: var(--brand); margin-top: 9px;
}
.sec__head--c .eyebrow::after, .center .eyebrow::after { margin-left: auto; margin-right: auto; }

/* --------------------------------------------------------------- utility bar
   Dark, not brand-coloured. The brief is a white-dominant design, and a full-width cyan strip
   sitting directly above a cyan-and-red logo makes the header read as two competing bands. */
.util { background: var(--ink-0); color: rgba(255,255,255,.8); border-bottom: 1px solid rgba(255,255,255,.06); }
.util__in {
  min-height: var(--util-h);
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  font-size: 13px;
}
.util__tag { display: inline-flex; align-items: center; gap: 8px; }
.util__tag svg { color: var(--brand-lt); flex: 0 0 auto; }
.util__right { display: inline-flex; align-items: center; gap: 20px; }
.util__hrs { color: rgba(255,255,255,.6); }
.util__phone {
  display: inline-flex; align-items: center; gap: 8px;
  color: #fff; text-decoration: none; white-space: nowrap;
  font-family: 'Mulish', sans-serif; font-weight: 800; letter-spacing: .02em;
}
.util__phone svg { color: var(--brand-lt); }
.util__phone:hover { color: var(--brand-lt); }
.util__phone:hover svg { color: #fff; }
@media (max-width: 900px) { .util__hrs { display: none; } }
@media (max-width: 700px) {
  .util__tag { display: none; }
  .util__in { justify-content: center; }
}

/* --------------------------------------------------------------- header */
/* DARK header. The logo lockup sets "TRUST" in white, so a light header would erase half the
   wordmark - this is decided by the artwork, not by taste. */
.hdr {
  position: sticky; top: 0; z-index: 90;
  background: var(--page); border-bottom: 1px solid var(--line);
  transition: box-shadow .2s;
}
.hdr[data-stuck] { box-shadow: 0 4px 22px rgba(0,0,0,.6); }
.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); }

/* The REAL logo artwork, rendered from the client's vector PDF by build/brand.py, not a redrawn
   SVG lockup. "TRUST" is white in the artwork, so it only works on the dark header. */
.brand { display: inline-flex; align-items: center; text-decoration: none; flex: 0 0 auto; }
/* The header lockup is wide (1077x200, about 5.4:1), so the height is what sets its footprint:
   54px tall is ~290px wide, which is what the nav has room for down to the 1120px burger
   breakpoint. */
.brand__logo {
  width: auto; height: 54px; transition: height .2s;
}
.hdr[data-stuck] .brand__logo { height: 46px; }
/* Both selectors on purpose. `.hdr[data-stuck] .brand__logo` is (0,2,1) and beats a bare
   `.brand__logo` inside the media query, so on a phone the logo GREW from 42px to 46px the moment
   the header stuck - 226px to 248px wide - and the header row overflowed the 375px viewport by
   14px on every page long enough to scroll. qa.mjs caught it (it scrolls before it measures); a
   screenshot at the top of the page never would. */
@media (max-width: 560px) {
  .brand__logo, .hdr[data-stuck] .brand__logo { height: 42px; }
}

/* 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: 20px; flex-wrap: nowrap; margin-left: auto; }
.nav > a, .nav__dropbtn {
  font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 13px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--ink); 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-dkr); }
.nav__home { color: var(--ink); }
.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: 268px; background: var(--surface); 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(--surface-2); color: var(--brand); }

.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-bg); color: #0B0C0F; text-decoration: none;
  padding: 12px 20px; border-radius: var(--radius);
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 13.5px;
  letter-spacing: .045em; text-transform: uppercase;
  transition: background .16s;
}
.hdr__quote svg { color: var(--brand); }
.hdr__quote:hover { background: var(--brand-bg); }
.hdr__quote:hover svg { color: #0B0C0F; }

.burger { display: none; width: 44px; height: 44px; background: none; border: 0; padding: 10px; cursor: pointer; }
.burger span { display: block; height: 2.5px; background: var(--ink); 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. Collapse is scoped to .cnc-js so a no-JS visitor and every
   crawler get the full list rather than an empty bar. */
/* Dark, to match the header it drops out of. */
.nav-m { display: none; border-top: 1px solid var(--line); padding: 10px var(--pad) 22px; background: var(--page); }
.nav-m a {
  display: block; padding: 12px 2px; text-decoration: none; color: var(--ink);
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 15px;
  border-bottom: 1px solid var(--line);
}
.nav-m__label {
  margin: 16px 0 2px; font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--brand-dkr);
}
.nav-m__cta {
  /* Dark ink on the gold, like every other gold surface here - white is 2.25:1. This one hid
     from the contrast sweep because the mobile menu is CLOSED until someone taps the burger,
     so build/qa.mjs now opens it before sampling. */
  margin-top: 14px; text-align: center; background: var(--brand-bg); color: #0B0C0F !important;
  border-radius: var(--radius); border-bottom: 0 !important; text-transform: uppercase;
  letter-spacing: .045em; font-size: 14px;
}
.nav-m__cta--alt { background: var(--surface-2); color: var(--ink) !important; border: 1px solid var(--line); }

@media (max-width: 1240px) {
  .nav { display: none; }
  .burger { display: block; }
  .cnc-js .nav-m { display: none; }
  .cnc-js .nav-m[data-open] { display: block; }
  .nav-m { display: block; }
}
@media (max-width: 560px) {
  .hdr__quote span { display: none; }
  .hdr__quote { padding: 12px 14px; }
  .brand__name { font-size: 17px; }
}

/* --------------------------------------------------------------- hero
   SPLIT hero: type on white at the left, one photograph at the right.
   Deliberately not the template's full-bleed dark banner. Two reasons, and the second is the
   one that actually decided it:
     1. The brief is "the clean white aesthetic" of the Webflow reference the client named. A
        black-gradient banner is the opposite of that.
     2. The client's strongest photographs are PORTRAIT interiors (1440x1800 bathrooms). A
        full-bleed 16:5 banner crops those to a strip of wall. A portrait media panel shows them
        at their best, and it means the design does not depend on owning one perfect landscape
        photograph - which this client does not have. */
/* DARK hero. Continues the header's surface so the top of every page is one dark field with
   the gold logo sitting in it, which is how the logo artwork was designed to be seen. */
.hero { position: relative; background: var(--ink-2); color: #fff; overflow: hidden; }
.hero::before {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(58% 70% at 8% 18%, rgba(0,152,160,.18), transparent 70%),
    radial-gradient(46% 60% at 96% 96%, rgba(0,152,160,.10), transparent 72%);
  pointer-events: none;
}
.hero .eyebrow { color: var(--brand-lt); }
.hero .eyebrow::after { background: var(--brand-lt); }
.hero__grid {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1.02fr .98fr;
  gap: clamp(30px, 5vw, 68px); align-items: center;
  padding-top: clamp(42px, 6vw, 78px); padding-bottom: clamp(42px, 6vw, 78px);
}
.hero__grid--sm { padding-top: clamp(34px, 4.4vw, 58px); padding-bottom: clamp(34px, 4.4vw, 58px); }
.hero__copy { max-width: 620px; }
.hero__copy--wide { max-width: 820px; }
.hero h1 { color: #fff; margin-bottom: .42em; }
/* Display type scales to the CONTENT, not to one clamp(). build.mjs measures each H1 and stamps
   the bucket - these run from 12 to 48 characters, and a single size either shrinks the short
   ones or takes the long ones to four lines and pushes the CTA below the fold on a phone. */
h1[data-len="short"] { font-size: clamp(33px, 5.2vw, 56px); }
h1[data-len="long"]  { font-size: clamp(29px, 4.4vw, 48px); }
h1[data-len="xlong"] { font-size: clamp(26px, 3.7vw, 41px); }
.hero__lede { font-size: clamp(16.5px, 1.5vw, 18.5px); color: rgba(255,255,255,.82); max-width: 620px; }
.hero__cta { display: flex; flex-wrap: wrap; gap: 13px; margin-top: 28px; }
.hero__cta--c { justify-content: center; }

/* Three short proofs under the CTAs. Ticks rather than bullets, and set small - they are
   reassurance, not content. */
.hero__pts {
  list-style: none; padding: 0; margin: 30px 0 0;
  display: flex; flex-wrap: wrap; gap: 10px 26px;
  font-size: 14.5px; color: rgba(255,255,255,.86);
}
.hero__pts li { position: relative; padding-left: 25px; margin: 0; }
.hero__pts li::before {
  content: ''; position: absolute; left: 0; top: 50%; margin-top: -8px;
  width: 17px; height: 17px; border-radius: 50%; background: var(--brand);
}
.hero__pts li::after {
  content: ''; position: absolute; left: 4.5px; top: 50%; margin-top: -3.5px;
  width: 8px; height: 4.5px; border-left: 2px solid #fff;
  border-bottom: 2px solid #fff; transform: rotate(-45deg);
}

/* The media panel. A slight lift and a cyan corner accent so the photograph reads as placed
   rather than pasted. */
.hero__media { position: relative; }
.hero__media picture, .hero__media img {
  display: block; width: 100%; border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.hero__media img { object-fit: cover; aspect-ratio: 4 / 5; }
.hero__media--sm img { aspect-ratio: 4 / 3; }
.hero__media::after {
  content: ''; position: absolute; right: -14px; bottom: -14px; z-index: -1;
  width: 58%; height: 46%; border-radius: var(--radius);
  background: var(--brand); opacity: .55;
}
/* A hero with no media panel (Contact, Areas, Our Work, 404) - copy only, centred band. */
.hero--plain { padding: clamp(44px, 6vw, 80px) 0 clamp(38px, 5vw, 66px); }
.hero--plain .hero__copy { max-width: 820px; }

@media (max-width: 880px) {
  .hero__grid { grid-template-columns: 1fr; gap: 34px; }
  /* Media BELOW the copy on a phone: the headline and the phone number are what the visitor came
     for, and a 4:5 portrait photograph above them pushes both off the first screen. */
  .hero__media { order: 2; max-width: 520px; }
  .hero__media img { aspect-ratio: 4 / 3; }
  .hero__media::after { display: none; }
}

/* --------------------------------------------------------------- trust strip
   Kept dark. On a white-dominant page this one band is what stops the hero and the services
   section running into each other as one long stretch of white, and it is where the logo cyan can
   carry text at full strength (7.2:1 on --ink). */
/* GOLD band, not dark: the hero above it is already dark, so a dark strip would merge into it.
   Ink text on the logo gold measures 7.41:1. */
/* 🔴 GOLD BAND: dark ink, never white. White on #D9A441 is 2.25:1 and fails at any size.
   build/qa.mjs measures this in the browser and fails the run - it is what caught it here. */
.trust { background: var(--brand-bg); color: #0B0C0F; }
.trust__in {
  display: flex; flex-wrap: wrap; gap: 12px clamp(18px, 2.4vw, 34px);
  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: 'Mulish', sans-serif; font-weight: 800;
  font-size: clamp(11.5px, 1.05vw, 12.5px); letter-spacing: .03em; text-transform: uppercase;
  color: #0B0C0F; white-space: nowrap;   /* dark ink on the gold band - white here is 2.25:1 */
}
@media (max-width: 720px) { .trust__item { white-space: normal; } }
.trust__item svg { color: #0B0C0F; flex: 0 0 auto; }

/* --------------------------------------------------------------- sections */
.sec { padding: var(--sec-y) 0; }
.sec--white { background: var(--page); }
.sec--band { background: var(--band); }
.sec--dark { background: var(--panel); color: #fff; }
.sec--dark h2, .sec--dark h3 { color: #fff; }
.sec--dark .eyebrow { color: var(--brand-lt); }
.sec--dark .eyebrow::after { background: var(--brand-lt); }
.sec--dark a:not(.btn):not(.tlink) { color: var(--brand-lt); }
/* The brand band. 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. */
/* A GOLD band carries INK text - white on the gold is 2.42:1. */
.sec--brand { background: var(--brand-bg); color: #0B0C0F; }
.sec--brand h2, .sec--brand h3 { color: #0B0C0F; }
.sec--brand .eyebrow { color: #0B0C0F; }
.sec--brand .eyebrow::after { background: #0B0C0F; }
.sec--brand .sec__head p { color: #14150F; }

.sec__head { max-width: 780px; margin-bottom: clamp(30px, 4vw, 46px); }
.sec__head--c { margin-left: auto; margin-right: auto; text-align: center; }
/* 52px section headings, larger than the H1, exactly 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; }
/* :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-dkr); text-decoration: underline; text-underline-offset: 3px; }
.prose a:not(.btn):not(.tlink):hover { color: var(--brand); }
.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 #fff; border-bottom: 2.4px solid #fff;
  transform: rotate(-45deg);
}
.prose ol { padding-left: 1.3em; }
.prose ol li::marker { font-family: 'Mulish', sans-serif; font-weight: 800; color: var(--brand-dkr); }

/* 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 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(285px, 1fr)); gap: clamp(22px, 2.6vw, 32px); }
/* FOUR-UP. auto-fill with a 285px minimum yields THREE tracks at 1180px, so a four-card grid
   lands as three across and one orphan underneath - which reads as an afterthought, and the
   fourth card here is the client's headline selling point (gas out, all-electric, done with the
   solar). An explicit track count puts it beside the other three at desktop and pairs them 2x2
   on tablet. The gap tightens because four 259px cards need the width more than they need air. */
.cards--4 { grid-template-columns: repeat(4, 1fr); gap: clamp(16px, 1.8vw, 24px); }
@media (max-width: 1080px) { .cards--4 { grid-template-columns: repeat(2, 1fr); gap: clamp(20px, 2.4vw, 28px); } }
@media (max-width: 620px)  { .cards--4 { grid-template-columns: 1fr; } }
/* At four across the card body has ~210px of usable width, so the padding and the promise line
   come in a step. Below 1080px the cards are back to full size and inherit the defaults. */
@media (min-width: 1081px) {
  .cards--4 .card__body { padding: 18px 19px 22px; }
  .cards--4 .card h3 { font-size: 18.5px; }
  .cards--4 .card__p { font-size: 14.8px; }
}
/* Grid items already stretch to a common height, but the card BODY does not, so four blurbs of
   different lengths leave four "Learn more" links at four different heights and the row reads as
   ragged. Pushing it down with margin-top:auto lines them up. Scoped to .cards--4 deliberately -
   the three-up grids elsewhere have been signed off looking as they do. */
.cards--4 .card { display: flex; flex-direction: column; }
.cards--4 .card__img { flex: 0 0 auto; }
.cards--4 .card__body { flex: 1 1 auto; display: flex; flex-direction: column; align-items: flex-start; }
.cards--4 .card__more { margin-top: auto; padding-top: 13px; }
/* A real surface rather than a bare image and some text. On a white-dominant design the cards
   are the only thing giving the services section structure, so they get a white panel, a hairline
   and a lift on hover. */
.card {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; transition: transform .22s, box-shadow .22s, border-color .22s;
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: transparent; }
.card__img { display: block; overflow: hidden; background: var(--surface-2); }
.card__img picture { display: block; }
.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: 22px 24px 26px; }
.card h3 { font-size: 20px; margin-bottom: .42em; color: var(--ink); }
.card__p { display: block; font-size: 15.5px; line-height: 1.62; color: var(--muted); }
.card__more { color: var(--brand-dkr); }
.card__more {
  display: inline-flex; align-items: center; gap: 8px; margin-top: 13px;
  font-family: 'Mulish', 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: var(--ink); }
.sec--brand .card h3 { color: var(--ink); }
.sec--brand .card__p { color: var(--muted); }
.sec--brand .card__more { color: var(--brand-dkr); }

/* --------------------------------------------------------------- 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; }

/* Tick list - 30px brand discs with the same white tick in each, as the
   reference does, 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: 'Mulish', 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 #fff; border-bottom: 2.6px solid #fff;
  transform: rotate(-45deg);
}
.sec--dark .ticks li { color: rgba(255,255,255,.94); }

/* --------------------------------------------------------------- numbered steps */
.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: 'Mulish', sans-serif; font-weight: 800; font-size: 30px;
  color: var(--brand-dkr); line-height: 1;
}
.steps h3 { font-size: 19px; margin-bottom: .28em; }
.steps p { font-size: 15.5px; margin-bottom: 0; }

/* --------------------------------------------------------------- areas */
.areas { display: grid; grid-template-columns: repeat(auto-fit, minmax(285px, 1fr)); gap: clamp(20px, 2.4vw, 30px); }
.area {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 26px 26px 28px; position: relative; overflow: hidden;
  transition: box-shadow .22s, border-color .22s;
}
/* A cyan bar down the left edge rather than across the top - it reads as a list of places
   rather than as another row of cards, which is what the top border made it look like next to
   the service grid. */
.area::before {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 4px;
  background: var(--brand);
}
.area:hover { box-shadow: var(--shadow-md); border-color: transparent; }
.area h3 { font-size: 18.5px; }
.area p { font-size: 15.5px; margin-bottom: 0; color: var(--muted); }
.sec--band .area { border-color: transparent; box-shadow: var(--shadow); }

/* --------------------------------------------------------------- brands strip */
.brands { background: var(--surface); border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 30px 0; }
.brands__label {
  text-align: center; font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 12px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 16px;
}
/* Product/supplier names as type, not as logo files - the client displays these
   marks on their own site but we hold no artwork licence, and set as type they
   cannot be mistaken for accreditation badges. */
.brands__list {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; justify-content: center; gap: 12px 34px;
}
.brands__list li {
  margin: 0; font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: clamp(15px, 1.7vw, 20px); letter-spacing: .02em; color: var(--ink);
}

/* --------------------------------------------------------------- FAQ
   Bright photo behind a near-white panel with brand accordion bars, as the
   reference has it - not a darkened photo with white text on hairlines. */
.faq-sec { position: relative; background: var(--panel); }
.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(--brand-bg); color: var(--ink);
  padding: 15px 52px 15px 20px; position: relative;
  font-family: 'Mulish', 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(--surface);
  -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-bg); border-radius: var(--radius) var(--radius) 0 0; color: #0B0C0F; }
.faq details[open] summary::after { transform: rotate(45deg); }
.faq__a { padding: 18px 20px 20px; background: var(--surface); 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; }

/* --------------------------------------------------------------- reviews
   REMOVED. The roofing template this was cloned from carried a Trustindex review slider - a
   .reviews block, a .reviews__slot, and a .ti-stage parked off-canvas at left:-1400px because the
   widget had to keep a real width while it measured itself.
   GD Plumbing has no reviews feed, so the markup, the JS and these rules were all taken out
   rather than left as dead weight. If reviews are ever added, restore the whole set from
   _R/roofingcompanytauranga.co.nz - including the off-canvas staging trick, which is not
   guessable and which exists because `left: -100vw` put 805px of horizontal overflow on every
   page at 375px wide. */

/* --------------------------------------------------------------- gallery */
.gal { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.gal__btn { padding: 0; border: 0; background: var(--band); 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-bg); color: #fff; }
.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); }
.callout h2, .callout h3 { color: #fff; margin-top: 0; }
.callout p { color: rgba(255,255,255,.86); }
.callout .eyebrow { color: var(--brand-lt); }

/* --------------------------------------------------------------- enquiry */
/* DARK enquiry band. With a dark header and footer, a dark enquiry section makes the page read
   as one composition rather than a light page with dark ends. The form itself stays a WHITE card
   so it is unmistakably the thing to fill in. Every colour is stated, nothing inherits. */
.enq { background: var(--ink-2); color: #fff; padding: var(--sec-y) 0; border-top: 1px solid rgba(255,255,255,.08); }
.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); color: #fff; }
.enq .eyebrow { color: var(--brand-lt); }
.enq .eyebrow::after { background: var(--brand-lt); }
.enq__copy > p { color: rgba(255,255,255,.82); }
.enq__big {
  display: inline-flex; align-items: center; gap: 13px; margin: 8px 0 22px;
  font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: clamp(23px, 2.6vw, 31px); color: var(--brand-lt); text-decoration: none;
}
.enq__big svg { color: var(--brand-lt); }
.enq__big:hover { color: #fff; }
.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: rgba(255,255,255,.9); }
.enq__facts svg { color: var(--brand-lt); flex: 0 0 auto; margin-top: 4px; }
.enq__facts a { color: #fff; }
.enq__note { font-size: 15px; color: rgba(255,255,255,.72); margin: 0; }
.enq__note strong { color: #fff; }

/* 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. */
/* LIGHT form panel, not the template's dark one - the brief is a white-dominant design and a
   near-black block is the heaviest object on the page.
   🔴 Every colour below was changed in ONE pass. The template's version assumed a dark panel:
   white labels, #ffc4c4 errors, white message text. Converting the background without converting
   all of those leaves white-on-white labels - the exact "widget vanishes on its own card" failure
   the fleet notes describe, and it looks fine right up until someone tries to read it. Each rule
   states its colour outright rather than inheriting. */
.form {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(24px, 3.4vw, 38px); box-shadow: var(--shadow-md);
}
.form__h {
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 20px;
  color: var(--ink); margin: 0 0 20px;
}
.form .form__row { margin-bottom: 15px; }
.form .form__row label {
  display: block; margin-bottom: 6px;
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 12.5px;
  letter-spacing: .05em; text-transform: uppercase; color: var(--ink);
}
.form .form__row input,
.form .form__row select,
.form .form__row textarea {
  width: 100%; padding: 12px 14px; font: inherit; font-size: 16px;
  color: #F2F3F6; -webkit-text-fill-color: #F2F3F6;   /* WebKit honours this over color */
  background: var(--surface-2); border: 1.5px solid var(--line); border-radius: var(--radius-sm);
  transition: border-color .15s, background .15s;
}
.form .form__row input:hover, .form .form__row select:hover, .form .form__row textarea:hover {
  border-color: #454A57;
}
.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='%23D9A441'/></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: #868D9B; -webkit-text-fill-color: #868D9B; }
.form .form__row input:focus, .form .form__row select:focus, .form .form__row textarea:focus {
  outline: 3px solid var(--brand); outline-offset: 1px; background: #0F1015; border-color: var(--brand);
}
.form .btn { margin-top: 10px; }
/* Error text on a light panel. #ED1C24 is only 4.38:1 on white, so the darker step is used -
   an error message is small text and has to clear AA. */
/* Error text is a real red - the gold is the ACTION colour and must not double as the warning.
   #B3261E on white is 5.9:1. */
.form .err { display: block; color: var(--err); font-size: 13.5px; margin-top: 5px; font-weight: 700; }
.form .form__msg { margin: 14px 0 0; font-size: 15px; color: var(--ink); }
.form .form__msg.err { color: var(--err); }
.form .form__legal { margin: 14px 0 0; font-size: 13px; color: var(--muted); }
/* 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: 'Mulish', 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-lt); 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__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-lt); }
.ftr__btm-wrap { background: var(--ink-0); }
.ftr__btm { padding: 17px 0; text-align: center; font-size: 14px; color: rgba(255,255,255,.72); }
/* 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(15,17,19,.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: var(--surface); 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: 'Mulish', sans-serif; font-weight: 800; font-size: 29px; color: var(--brand-dkr); 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); }

/* ===========================================================================
   Site-specific components (inherited from the gdplumbing build)
   Added for this build - the split hero's supporting pieces, the contact
   cards, the footer's real logo, and the wide FAQ used on pages with no
   media column. Kept at the end so they cannot be missed when re-theming.
   =========================================================================== */

/* --------------------------------------------------------------- split media caption */
.split__cap {
  margin: 14px 0 0; font-size: 14px; color: var(--muted); line-height: 1.5;
}
.split__media picture { display: block; }
.split__media img { border-radius: var(--radius); box-shadow: var(--shadow-md); }

/* --------------------------------------------------------------- wide FAQ
   The FAQ on these pages sits in a normal section rather than inside the
   template's dark photo panel, so it needs its own width and centring. */
.faq--wide { max-width: 860px; margin: 0 auto; }

/* 🔴 STATE EVERY COLOUR. The base .faq summary rule above was written for the dark template and
   sets `color: #fff` to sit on a brand-blue bar. Overriding only the BACKGROUND to white left
   white text on a white bar - six unreadable questions that render as blank grey slabs, and the
   page otherwise looks completely finished. That is the same class of bug as the embedded-widget
   rule in the fleet notes, and it was caught here by looking at a screenshot rather than by
   reading the CSS. The plus/minus glyph is a mask painted with `background`, so it needs its
   colour restated too or it stays white and disappears with the text. */
.faq summary {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line);
  transition: border-color .16s, background .16s;
}
.faq summary::after { background: var(--brand-dkr); }
.faq summary:hover { border-color: var(--brand); background: var(--brand-soft); color: var(--brand); }
.faq details[open] summary {
  background: var(--brand-bg); color: #0B0C0F; border-color: var(--brand-bg);
}
.faq details[open] summary::after { background: var(--brand-lt); }
.faq__a { border-color: var(--line); color: var(--ink); }
.faq__a p { color: var(--muted); }

/* --------------------------------------------------------------- contact cards */
.ccards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: clamp(18px, 2.2vw, 26px);
}
.ccard {
  display: block; text-decoration: none; color: inherit;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 28px 26px 30px;
  transition: transform .22s, box-shadow .22s, border-color .22s;
}
/* Only the ones that actually go somewhere get the affordance. A hover lift on
   a static address panel promises a link that is not there. */
a.ccard:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); border-color: transparent; }
.ccard__ic {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; border-radius: 50%;
  background: var(--brand-soft); color: var(--brand); margin-bottom: 16px;
}
.ccard__l {
  display: block; font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--brand-dkr); margin-bottom: 7px;
}
.ccard__v {
  display: block; font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 18px; color: var(--ink); line-height: 1.3;
  /* An email address has no spaces to break at and will otherwise push the
     card wider than its column on a phone. */
  overflow-wrap: anywhere;
}
.ccard__n { display: block; margin-top: 6px; font-size: 14.5px; color: var(--muted); }

/* --------------------------------------------------------------- footer additions */
/* The stacked lockup is near-square (595x536), so width is what sizes it here, not height -
   at 64px tall the wordmark inside it would be 6px. */
.ftr__logo {
  width: min(100%, 230px); height: auto; margin-bottom: 16px;
}
.ftr__tag {
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 15px;
  color: var(--brand-lt); margin-top: 14px;
}
.ftr__social { display: flex; gap: 10px; margin-top: 18px; }
.ftr__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  background: rgba(255,255,255,.09); color: #fff;
  transition: background .18s, color .18s;
}
.ftr__social a:hover { background: var(--brand-bg); color: #fff; }

/* --------------------------------------------------------------- header quote button
   Gold with ink type, to match the primary CTA - it is the same action. */
.hdr__quote {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--brand-bg); color: #0B0C0F; text-decoration: none;
  padding: 12px 18px; border-radius: var(--radius-sm);
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 13.5px;
  letter-spacing: .03em; white-space: nowrap;
  transition: background .16s, transform .16s;
}
.hdr__quote svg { color: #0B0C0F; }
.hdr__quote:hover { background: var(--brand-dk); transform: translateY(-1px); }
.hdr__quote:hover svg { color: #0B0C0F; }
@media (max-width: 620px) { .hdr__quote span { display: none; } .hdr__quote { padding: 11px 13px; } }

/* --------------------------------------------------------------- utilities */
.pt0 { padding-top: 0; }

/* ===========================================================================
   RCL-specific components
   =========================================================================== */

/* --------------------------------------------------------------- full-bleed home hero
   The home page uses the client's best landscape photograph (the pool surround) under a dark
   overlay, with the copy on top. Service pages keep the split hero above. The image is a real
   <img> inside .hero__bg rather than a CSS background so it goes through pic() - WebP source,
   alt text, width/height - like every other photograph on the site. */
.hero--bleed { min-height: clamp(520px, 66vh, 720px); display: flex; align-items: center; }
.hero--bleed::before { display: none; }
.hero__bg { position: absolute; inset: 0; z-index: 0; }
.hero__bg picture, .hero__bg img { width: 100%; height: 100%; }
.hero__bg img { object-fit: cover; object-position: 50% 55%; }
/* The overlay. Dark enough at the left for white type to clear AA against the brightest part
   of any photograph, fading out to the right so the picture still reads as a picture. */
.hero__bg::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(90deg, rgba(0,0,0,.92) 0%, rgba(0,0,0,.8) 42%, rgba(0,0,0,.4) 100%),
    linear-gradient(0deg, rgba(0,0,0,.55) 0%, rgba(0,0,0,0) 40%);
}
.hero--bleed .wrap { position: relative; z-index: 2; padding-top: clamp(54px, 7vw, 96px); padding-bottom: clamp(54px, 7vw, 96px); }
.hero--bleed .hero__copy { max-width: 720px; }
.hero--bleed .hero__lede { color: rgba(255,255,255,.88); }
@media (max-width: 880px) {
  .hero--bleed { min-height: 0; }
  .hero__bg::after {
    background: linear-gradient(180deg, rgba(0,0,0,.84) 0%, rgba(0,0,0,.88) 100%);
  }
}

/* --------------------------------------------------------------- split hero photo card on dark */
.hero__media picture, .hero__media img { box-shadow: 0 20px 50px rgba(0,0,0,.45); }

/* --------------------------------------------------------------- cards on the warm band */
.sec--band .card { border-color: transparent; box-shadow: var(--shadow); }

/* --------------------------------------------------------------- dropdown on the dark header */
.nav__panel { border-top-color: var(--brand); }

/* ===========================================================================
   Valmar-specific components
   =========================================================================== */

/* The hero's second paragraph - the brief's longer positioning line, set smaller than the lede. */
.hero__sub { font-size: 15.5px; color: rgba(255,255,255,.76); max-width: 640px; margin-top: -2px; }

/* Two-up technology features on the band: white cards with the product shot on top. */
.feats--2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.feat--card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
  box-shadow: var(--shadow);
}
.feat--card .feat__img { margin: 0; border-radius: 0; }
.feat--card .feat__img img { transition: none; }
.feat--card h3, .feat--card p { padding: 0 24px; }
.feat--card h3 { margin-top: 20px; }
.feat--card p { margin-bottom: .8em; }
.feat--card p:last-child { padding-bottom: 24px; }

/* The six-step process on a dark section: a grid of numbered steps rather than a single column. */
.steps--grid { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 30px 34px; }
.steps--grid li::before { color: var(--brand-lt); }
.steps--grid h3 { color: #fff; }
.steps--grid p { color: rgba(255,255,255,.82); }

/* Standards teaser: the dark callout at full width. */
.callout--wide { max-width: none; }
.callout--wide h2 { font-size: clamp(25px, 2.9vw, 36px); }
.callout--wide .eyebrow::after { background: var(--brand-lt); }
.callout .btn--light { margin-top: 6px; }
.prose .callout { margin: 1.6em 0; }
.prose .callout .eyebrow { margin-bottom: 8px; }
.prose .callout p { color: rgba(255,255,255,.88); }

/* The scope note - the brief's own disclaimer, on every service page. Quiet, but not hidden. */
.note {
  margin: 1.8em 0; padding: 18px 22px; border-left: 4px solid var(--brand);
  background: var(--surface-2); border-radius: 0 var(--radius) var(--radius) 0;
  font-size: 15px; color: var(--muted);
}
.note p { margin: 0; }
.note strong { color: var(--ink); }

/* Specification tables on the technology page. */
.spec { width: 100%; border-collapse: collapse; margin: 0 0 1.4em; font-size: 15.5px; }
.spec th, .spec td { text-align: left; vertical-align: top; padding: 10px 12px; border-bottom: 1px solid var(--line); }
.spec th { width: 34%; font-family: 'Mulish', sans-serif; font-weight: 800; color: var(--ink); font-size: 13.5px; letter-spacing: .02em; }
.spec td { color: var(--muted); }
.spec tr:first-child th, .spec tr:first-child td { border-top: 2px solid var(--brand); }
@media (max-width: 560px) {
  .spec th, .spec td { display: block; width: auto; padding: 8px 0; border: 0; }
  .spec th { padding-top: 12px; }
  .spec td { border-bottom: 1px solid var(--line); padding-bottom: 12px; }
}

/* Footer: a second heading inside the contact column, for the resource links. */
.ftr__h--sm { font-size: 15px; margin-top: 26px; margin-bottom: 8px; }


/* ===========================================================================
   DARK THEME - additions, not overrides of anything above.
   These cover the places the light template simply had no rule for, because on
   a white page the browser default was already right.
   =========================================================================== */

/* The template scopes body-link colour with :not(.btn):not(.tlink) so a prose
   link rule can never beat a button - keep that, and give it the gold. */
/* 🔴 BODY LINKS ARE SCOPED TO UNCLASSED ANCHORS, and that matters more than it looks.
   The template's own note says components must beat prose - `.prose a` is (0,1,1) and `.btn` is
   (0,1,0), so a body-link rule silently wins over a button's own colour. `a:not(.btn):not(.tlink)`
   is (0,3,0) and beats EVERY component: it painted .hdr__quote's label gold on the gold button,
   1.0:1, completely invisible, and the header CTA rendered as a bare icon. An exclusion list has
   to be extended every time a component is added, and will be forgotten. `:not([class])` cannot
   go stale - a component always carries a class, a body-copy link never does. */
a:not([class]) { color: var(--brand); }
a:not([class]):hover { color: var(--brand-lt); }

/* The utility strip and the header sit on the same near-black, so without this
   the boundary between them disappears entirely. */
.util { border-bottom: 1px solid rgba(255,255,255,.07); }

/* Photographs carry a lot of light and sit on a near-black ground. A hairline
   keeps them from floating, and a slight desaturation stops a bright sky
   fighting the gold. */
.card__img img, .fig img, .media img { border-radius: 0; }
.card { transition: border-color .16s, transform .16s, box-shadow .16s; }
.card:hover { border-color: var(--brand); transform: translateY(-3px); }
.card h3 { color: var(--ink); }
.card:hover h3 { color: var(--brand); }
.card__promise {
  display: block; font-family: 'Mulish', sans-serif; font-weight: 800;
  font-size: 15px; color: var(--brand); margin-bottom: .5em; letter-spacing: -.01em;
}
.card__more { color: var(--brand); }

/* Section headings and eyebrows. On white the template relied on --ink being
   dark; here it is already light, so only the eyebrow needs the accent. */
.eyebrow { color: var(--brand); }
.sec--dark .eyebrow, .sec--band .eyebrow { color: var(--brand); }
h1, h2, h3, h4 { color: #FFFFFF; }
.sec--brand h2, .sec--brand h3, .sec--brand .card h3 { color: #0B0C0F; }

/* --band is a *darker* band on this site rather than a lighter one, so a card
   sitting on it needs to be the lighter surface to stay legible. */
.sec--band .card, .sec--band .area, .sec--band .form { background: var(--surface); }

/* The gold band. Used once or twice per site as the loudest possible break -
   dark type on gold, 8.70:1. */
.sec--brand { background: var(--brand-bg); color: #0B0C0F; }
.sec--brand p, .sec--brand li { color: #14150F; }
.sec--brand .eyebrow { color: #0B0C0F; }
.sec--brand .eyebrow::after { background: #0B0C0F; }

/* Definition-style spec rows used on the packages page. */
.spec { list-style: none; margin: 0 0 1.1em; padding: 0; }
.spec li {
  display: flex; justify-content: space-between; gap: 16px; margin: 0;
  padding: 10px 0; border-bottom: 1px solid var(--line); font-size: 15.5px;
}
.spec li:last-child { border-bottom: 0; }
.spec dt, .spec .spec__k { color: var(--muted); }
.spec .spec__v { color: var(--ink); font-weight: 700; text-align: right; }

/* The package cards. Deliberately NOT a price table - the client's own figures
   are internally contradictory and the dollar amounts are held back until they
   confirm them (see build/build.mjs). */
.pkg { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px; }
.pkg__card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 28px 26px 26px; display: flex; flex-direction: column;
}
.pkg__card--feature { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }
.pkg__tier {
  font-family: 'Mulish', sans-serif; font-weight: 800; font-size: 13px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--brand); margin: 0 0 6px;
}
.pkg__size {
  font-family: 'Mulish', sans-serif; font-weight: 800; line-height: 1;
  font-size: clamp(38px, 4.6vw, 52px); color: #fff; margin: 0 0 2px;
}
.pkg__for { color: var(--muted); margin: 0 0 18px; font-size: 15.5px; }
.pkg__card .btn { margin-top: auto; }
.pkg__flag {
  display: inline-block; align-self: flex-start; margin: 0 0 14px;
  background: var(--brand-soft); color: var(--brand); border: 1px solid var(--brand);
  border-radius: 100px; padding: 4px 12px; font-size: 12.5px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
@media (max-width: 900px) { .pkg { grid-template-columns: 1fr; } }

/* The scope / finance note. */
.note {
  background: var(--brand-soft); border: 1px solid var(--line);
  border-left: 3px solid var(--brand);
  border-radius: var(--radius); padding: 20px 24px; margin: 30px 0 0;
  font-size: 15.5px; color: var(--muted);
}
.note strong { color: var(--ink); }

/* Blog index cards and the post body. */
.post__meta { color: var(--muted); font-size: 14.5px; margin-bottom: 1.4em; }
.prose h2 { margin-top: 1.5em; }
.prose h3 { margin-top: 1.3em; font-size: 21px; }
.prose ul li::marker { color: var(--brand); }
