/* ===========================================================================
   GD Plumbing Services - Waipu, Bream Bay, Mangawhai
   ---------------------------------------------------------------------------
   Brief (Rob, Capsule 2026-08-11): clean, minimal text, "the clean white
   aesthetic" of the Webflow plumbing-x-construction template, with
   jarvisplumbing.co.nz named as the layout reference. So: white-dominant,
   generous space, one strong accent per job, and no heavy dark bands.

   The two brand colours are SAMPLED FROM THE CLIENT'S OWN LOGO, not guessed
   from a screenshot - the logo PNG off their live Wix site quantises to
   exactly two inks:
       #00AEEF   the cyan of "d." and "PLUMBING SERVICES"
       #ED1C24   the red of the "g"
   Guessing from a screenshot is what produced a wrong first build on an
   earlier site in this fleet.

   Colour strategy, so the two do not fight:
       BLUE  = brand and trust. Icons, eyebrows, links, rules, section accents.
       RED   = action. Primary CTA buttons, the float bar, phone emphasis.
   That mirrors the logo's own hierarchy rather than inventing one.

   Re-theming is one block: every colour is a custom property here.
   =========================================================================== */

:root {
  /* 🔴 FOUR blues and THREE reds, and which one you use depends on what sits
     on top of it. Every ratio below is MEASURED (see build/qa.mjs), not
     eyeballed - and the raw logo inks fail badly as text surfaces:

       white on #00AEEF  = 2.53:1  <- fails even the 3:1 for non-text graphics
       white on #ED1C24  = 4.38:1  <- fails AA for normal-size body text

     Shipping the logo colours as button fills would therefore have put an
     accessibility failure on every call to action on the site. The darker
     steps below hold the same hue and saturation and are visually
     near-identical, which is the whole point.

       --brand      #00AEEF  the logo cyan. Decorative ONLY on white: icons on
                             dark, large display type, rules, hairlines. It is
                             7.2:1 against --ink, so it CAN carry text on dark.
       --brand-bg   #007AA7  surfaces carrying white BODY text - 4.84:1
       --brand-dk   #00688F  hover/pressed on a brand surface - 6.22:1
       --brand-dkr  #006083  brand-coloured TEXT on white - 7.00:1 (AAA)
       --red        #ED1C24  the logo red. Decorative and large display only.
       --red-bg     #E2121A  red surfaces carrying white text - 4.84:1
       --red-dk     #C41016  hover/pressed - 6.12:1 */
  --brand:        #00AEEF;   /* logo cyan - accents, icons, large display type */
  --brand-bg:     #007AA7;   /* surfaces carrying white body text - 4.84:1 */
  --brand-dk:     #00688F;   /* hover/pressed - 6.22:1 */
  --brand-dkr:    #006083;   /* brand text on white - 7.00:1 */
  --brand-soft:   #E8F7FD;   /* pale cyan wash - tints, icon discs, hover fills */

  --red:          #ED1C24;   /* logo red - decorative and large display only */
  --red-bg:       #E2121A;   /* red surfaces carrying white text - 4.84:1 */
  --red-dk:       #C41016;   /* hover/pressed - 6.12:1 */
  --red-soft:     #FDECEC;

  --ink:          #0B1720;   /* near-black with a blue cast - 18.1:1 on white */
  --ink-2:        #142430;   /* dark panels and the footer */
  --muted:        #5A6672;   /* secondary copy on white - 6.5:1 */
  --line:         #E3E9EE;
  --band:         #F5F9FB;   /* the light cool band that carries most sections */
  --white:        #ffffff;
  /* Softer and wider than the roofing template's. On a white-dominant design a
     tight dark shadow reads as a hard edge; this reads as lift. */
  --shadow:       0 6px 24px rgba(11,23,32,.07), 0 2px 6px rgba(11,23,32,.04);
  --shadow-md:    0 14px 40px rgba(11,23,32,.10), 0 3px 10px rgba(11,23,32,.05);
  --shadow-lg:    0 26px 70px rgba(11,23,32,.16);

  --wrap:         1180px;
  --pad:          clamp(20px, 4vw, 34px);
  --sec-y:        clamp(60px, 7.4vw, 100px);
  /* Rounder than the roofing site's 4px. "Clean white" reads as soft-modern,
     not as square-industrial. */
  --radius:       14px;
  --radius-sm:    10px;

  /* 🔴 The header is TALL on purpose. The client's first note on 2026-09-03 was
     "our logo needs to be more prominent, at the moment it is just tiny in the
     left hand corner", with a screenshot of jarvisplumbing.co.nz's deep header
     as the reference, and "a bigger heading space for this page so the logo can
     be bigger". So 86px became 128px and the mark went 54px -> 94px.
     It still SHRINKS on scroll: a 128px bar pinned to the top of a phone screen
     eats a fifth of the viewport, so --hdr-h-stuck is what is on screen for
     nearly all of a visit, and --hdr-h is what greets you. The breakpoints below
     step both down again. */
  --hdr-h:        128px;
  --hdr-h-stuck:  84px;
  --util-h:       40px;

  /* Float bar (fleet component) - overridable from /dash via /api/config.
     🔴 Do NOT paste the template's defaults. Measured for THIS palette: white
     icons on the logo cyan score 2.53:1, under the 3:1 WCAG 1.4.11 wants for a
     UI component. White on --red-bg is 4.84:1 and matches the primary CTA, so
     the contact bar and the "get a quote" button read as the same action. */
  --fb-bg:        var(--red-bg);
  --fb-icon:      #ffffff;
  --fb-hover-bg:  var(--ink);
  --fb-hover-icon:#ffffff;
}

/* --------------------------------------------------------------- fonts
   🔴 POPPINS, at the client's explicit request (2026-09-03):

       "Font - don't like the current one. Try Questrial or Poppins - the dots
        on the i's need to be circular like our logo."

   That last clause is the reason it is Poppins and not a near-miss substitute.
   Poppins is a geometric sans built on circles, so its tittles (the dots on i
   and j) are true circles rather than the squarish ones Mulish and Red Hat Text
   draw - and the client's logo is itself geometric, with a perfectly round dot
   after the "d". It is also the face their own brand card already uses for the
   strapline (Poppins Semibold Italic), so the site and their print material now
   agree. Questrial was the alternative they offered; it ships one weight only,
   which is not enough for headings, nav and body on the same page.

   Self-hosted latin subset, three weights: 24 kB in total, which is actually
   LESS than the 43 kB Mulish + Red Hat Text pair it replaces.

   One consequence worth knowing before touching type sizes: Poppins is wider
   and has a smaller x-height than Red Hat Text at the same nominal size, so the
   body size came down from 17px to 16.5px and the tracking on uppercase labels
   came in. Setting it at the old sizes made every line noticeably longer. */
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-400-latin.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-600-latin.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-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: 'Poppins', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  /* 16.5, not 17. Poppins sets wider than Red Hat Text at the same size; at 17
     the measure ran long enough to hurt readability in .prose. */
  font-size: 16.5px;
  line-height: 1.7;
  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; }
/* <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: 'Poppins', system-ui, sans-serif;
  /* 700 is Poppins Bold and is the heaviest weight loaded. Poppins has no 800
     in this subset, and asking for one would synthesise a smeared fake bold. */
  font-weight: 700;
  line-height: 1.16;
  letter-spacing: -.018em;
  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(--ink); color: #fff; 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(--ink); color: #fff;
  font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 15px;
  letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none; border: 2px solid var(--ink); 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 = RED. The logo's red is the action colour on this site and the blue is the brand
   colour, which mirrors the logo's own hierarchy. --red-bg rather than the raw #ED1C24 because
   white on the logo red is 4.38:1 and fails AA for normal-size text; --red-bg is 4.84:1 and is
   visually indistinguishable. */
.btn { background: var(--red-bg); color: #fff; border-color: var(--red-bg); }
.btn::before { background: #fff; }
.btn:hover {
  background: var(--red-dk); border-color: var(--red-dk);
  transform: translateY(-2px); box-shadow: var(--shadow-md);
}
.btn:hover::before { background: #fff; }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--line); }
.btn--ghost::before { background: var(--brand-dkr); }
.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::before { background: var(--red-bg); }
.btn--light:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn--light:hover::before { background: var(--brand); }
.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,174,239,.45);
}
.tlink:hover { border-bottom-color: var(--brand); }

.eyebrow {
  display: inline-block;
  font-family: 'Poppins', sans-serif; font-weight: 700;
  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); color: rgba(255,255,255,.82); }
.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); 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: 'Poppins', sans-serif; font-weight: 700; letter-spacing: .02em;
}
.util__phone svg { color: var(--brand); }
.util__phone:hover { color: var(--brand); }
.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 */
.hdr {
  position: sticky; top: 0; z-index: 90;
  background: #fff; border-bottom: 1px solid var(--line);
  transition: box-shadow .2s;
}
.hdr[data-stuck] { box-shadow: 0 4px 22px rgba(15,17,19,.09); }
.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, not a redrawn SVG lockup. The client has a proper two-ink mark and
   substituting a generic house-and-pipe glyph for it would be a downgrade. It carries no black
   (checked in build/images.py, which prints the near-black pixel count), so the same file sits on
   the white header and on the dark footer without a knocked-out variant. */
.brand { display: inline-flex; align-items: center; text-decoration: none; flex: 0 0 auto; }
.brand__logo {
  width: auto; height: 94px; transition: height .2s;
}
.hdr[data-stuck] .brand__logo { height: 62px; }
/* Below the desktop nav breakpoint the header is just logo + burger, so the bar
   can come back down without the logo losing any of the prominence it gained. */
@media (max-width: 1120px) {
  :root { --hdr-h: 100px; --hdr-h-stuck: 76px; }
  .brand__logo { height: 74px; }
  .hdr[data-stuck] .brand__logo { height: 56px; }
}
@media (max-width: 560px) {
  :root { --hdr-h: 86px; --hdr-h-stuck: 70px; }
  .brand__logo { height: 62px; }
  .hdr[data-stuck] .brand__logo { height: 52px; }
}

/* 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: 'Poppins', sans-serif; font-weight: 700;
  font-size: 13.5px; letter-spacing: .045em; 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: #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: 'Poppins', sans-serif; font-weight: 600; 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-dkr); }

.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(--ink); color: #fff; text-decoration: none;
  padding: 12px 20px; border-radius: var(--radius);
  font-family: 'Poppins', sans-serif; font-weight: 700; 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: #fff; }

.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. */
.nav-m { display: none; border-top: 1px solid var(--line); padding: 10px var(--pad) 22px; background: #fff; }
.nav-m a {
  display: block; padding: 12px 2px; text-decoration: none; color: var(--ink);
  font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 15px;
  border-bottom: 1px solid var(--line);
}
.nav-m__label {
  margin: 16px 0 2px; font-family: 'Poppins', sans-serif; font-weight: 700;
  font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
}
.nav-m__cta {
  margin-top: 14px; text-align: center; background: var(--ink); color: #fff !important;
  border-radius: var(--radius); border-bottom: 0 !important; text-transform: uppercase;
  letter-spacing: .045em; font-size: 14px;
}
.nav-m__cta--alt { background: var(--brand); }

@media (max-width: 1120px) {
  .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. */
.hero { position: relative; background: #fff; overflow: hidden; }
/* A soft tinted field behind the copy column so the white hero still has some depth, and a
   hairline at the foot so it separates from the trust strip. */
.hero::before {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(58% 70% at 8% 18%, rgba(0,174,239,.09), transparent 70%),
    radial-gradient(46% 60% at 96% 96%, rgba(237,28,36,.055), transparent 72%);
  pointer-events: none;
}
.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: var(--ink); 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: var(--muted); 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: var(--muted);
}
.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-soft);
}
.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 var(--brand-dkr);
  border-bottom: 2px solid var(--brand-dkr); 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: .16;
}
/* 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). */
.trust { background: var(--ink); color: #fff; }
.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: 'Poppins', sans-serif; font-weight: 700;
  font-size: clamp(11.5px, 1.05vw, 12.5px); letter-spacing: .03em; 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: #7ecdf0; }
.sec--dark a:not(.btn):not(.tlink) { color: #7ecdf0; }
/* 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. */
.sec--brand { background: var(--brand-bg); color: #fff; }
.sec--brand h2, .sec--brand h3 { color: #fff; }
/* Fully opaque, not a white at 85-94% alpha. Compositing white down over a mid blue costs real
   contrast, and on a background already close to the AA threshold it is what tips it under. */
.sec--brand .eyebrow { color: #fff; }
.sec--brand .sec__head p { color: #fff; }

.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: 'Poppins', sans-serif; font-weight: 700; 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); }
/* 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: #fff; 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(--band); }
.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: 'Poppins', sans-serif; font-weight: 700; 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: #fff; }
.sec--brand .card__more { color: #fff; }

/* --------------------------------------------------------------- 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: 'Poppins', sans-serif; font-weight: 700; }
.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: 'Poppins', sans-serif; font-weight: 700; font-size: 30px;
  color: var(--brand); 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: #fff; 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: #fff; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); padding: 30px 0; }
.brands__label {
  text-align: center; font-family: 'Poppins', sans-serif; font-weight: 700;
  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: 'Poppins', sans-serif; font-weight: 700;
  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(--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(--brand-bg); color: #fff;
  padding: 15px 52px 15px 20px; position: relative;
  font-family: 'Poppins', sans-serif; font-weight: 700; 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: #fff;
  -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(--ink); border-radius: var(--radius) var(--radius) 0 0; color: #fff; }
.faq details[open] summary::after { transform: rotate(45deg); }
.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; }

/* --------------------------------------------------------------- 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); }
.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(--brand-bg); color: #fff; border-radius: var(--radius); padding: clamp(26px, 3.6vw, 42px); }
.callout h2, .callout h3 { color: #fff; margin-top: 0; }
.callout p { color: #fff; }
.callout .btn { background: #fff; color: var(--ink); border-color: #fff; }
.callout .btn::before { background: var(--brand); }
.callout .btn:hover { background: var(--ink); border-color: var(--ink); color: #fff; }
.callout .btn:hover::before { background: #fff; }

/* --------------------------------------------------------------- enquiry */
.enq { background: var(--band); 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: 'Poppins', sans-serif; font-weight: 700;
  font-size: clamp(23px, 2.6vw, 31px); color: var(--brand-dkr); text-decoration: none;
}
.enq__big svg { color: var(--red-bg); }
.enq__big:hover { color: var(--red-dk); }
.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-dkr); flex: 0 0 auto; margin-top: 4px; }
.enq__facts a { color: var(--brand-dkr); }
.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. */
/* 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: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(24px, 3.4vw, 38px); box-shadow: var(--shadow-md);
}
.form__h {
  font-family: 'Poppins', sans-serif; font-weight: 700; 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: 'Poppins', sans-serif; font-weight: 700; 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: #0B1720; -webkit-text-fill-color: #0B1720;   /* WebKit honours this over color */
  background: var(--band); 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: #c9d4dd;
}
.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='%230B1720'/></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: #7c8894; -webkit-text-fill-color: #7c8894; }
.form .form__row input:focus, .form .form__row select:focus, .form .form__row textarea:focus {
  outline: 3px solid var(--brand); outline-offset: 1px; background: #fff; border-color: #fff;
}
.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. */
.form .err { display: block; color: var(--red-dk); 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(--red-dk); }
.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: 'Poppins', sans-serif; font-weight: 700; 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__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__btm-wrap { background: var(--ink); }
.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: #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: 'Poppins', sans-serif; font-weight: 700; 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); }

/* ===========================================================================
   GD-specific components
   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: #fff; 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); }
.faq details[open] summary {
  background: var(--ink); color: #fff; border-color: var(--ink);
}
.faq details[open] summary::after { background: var(--brand); }
.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);
}
/* 🔴 TWO per row, not four. The client asked on 2026-09-03 for the email address and the opening
   hours to sit "on one line". Four cards across a 1180px wrap leaves ~206px of content in each,
   and gdyeplumbing@gmail.com does not fit in that at any size worth reading - the previous fix
   would have been to shrink the type until it did. Halving the columns gives ~490px instead, so
   both strings fit comfortably at full size and the fix is invisible. */
@media (min-width: 760px) { .ccards { grid-template-columns: repeat(2, 1fr); } }
.ccard {
  display: block; text-decoration: none; color: inherit;
  background: #fff; 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-dkr); margin-bottom: 16px;
}
.ccard__l {
  display: block; font-family: 'Poppins', sans-serif; font-weight: 700;
  font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--brand-dkr); margin-bottom: 7px;
}
.ccard__v {
  display: block; font-family: 'Poppins', sans-serif; font-weight: 700;
  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;
}
/* The two values the client asked to keep on one line. nowrap is safe HERE, unlike on a heading,
   because the clamp guarantees the string is narrower than the card at every viewport down to
   320px - measured, not assumed, and build/shots.mjs re-measures it on every run. */
.ccard__v--fit {
  white-space: nowrap; overflow-wrap: normal;
  font-size: clamp(15px, 1.35vw, 18px);
}
.ccard__n { display: block; margin-top: 6px; font-size: 14.5px; color: var(--muted); }

/* --------------------------------------------------------------- footer additions */
.ftr__logo {
  width: auto; height: 52px; margin-bottom: 16px;
}
/* The byline is now the client's own artwork rather than type we set - Lumios Marker Regular is
   an Adobe Font and we hold no licence for it. build/images.py writes the red and white
   colourways from one alpha channel. */
.ftr__tag { display: block; width: min(250px, 78%); height: auto; margin-top: 18px; }
.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); color: var(--ink); }

/* --------------------------------------------------------------- header quote button
   Red, to match the primary CTA - it is the same action. */
.hdr__quote {
  display: inline-flex; align-items: center; gap: 9px;
  background: var(--red-bg); color: #fff; text-decoration: none;
  padding: 12px 20px; border-radius: var(--radius-sm);
  font-family: 'Poppins', sans-serif; font-weight: 700; font-size: 14px;
  letter-spacing: .03em;
  transition: background .16s, transform .16s;
}
.hdr__quote svg { color: #fff; }
.hdr__quote:hover { background: var(--red-dk); transform: translateY(-1px); }
.hdr__quote:hover svg { color: #fff; }
@media (max-width: 620px) { .hdr__quote span { display: none; } .hdr__quote { padding: 11px 13px; } }

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


/* ===========================================================================
   2026-09-03 client feedback round
   Everything below was added or reworked in response to the client's written
   notes. Each block says which line of the brief it answers, because several of
   them look like arbitrary design choices otherwise.
   =========================================================================== */

/* --------------------------------------------------------------- banner hero
   "I don't want all the text being the first thing that they see when the
   website opens." So the home page opens on a photograph of their own fleet
   with the byline over it - their own mock-up - and the reading matter starts
   below the fold of the banner. Service pages keep the split hero.

   🔴 The scrim is not decoration. The banner photograph has a pale overcast sky
   across its top third and light gravel across its bottom, and the byline is
   WHITE (matching the client's mock-up). Composited over the bare photo the
   worst region measures about 1.9:1. The gradient below takes the same region
   to better than 7:1. build/qa.mjs measures contrast against the section's own
   background colour, which is opaque --ink here, so it will always pass - the
   number that matters is the composited one above, measured by hand off the
   generated image. Do not lighten the scrim without re-measuring. */
.hero--banner { position: relative; overflow: hidden; background: var(--ink); }
/* The soft cyan/red radial wash the white hero uses would sit ON TOP of the
   photograph and grey it out. */
.hero--banner::before { display: none; }
.hero__bg { position: absolute; inset: 0; z-index: 0; }
.hero__bg picture, .hero__bg img { width: 100%; height: 100%; object-fit: cover; }
/* 2026-09-21: photograph brightened at the client's request, scrim re-tuned to match - lighter
   over the byline band only (3:1 target, measured 3.58), unchanged from the H1 down (4.5:1
   target, measured 4.76). Stops mirrored in build/scrim-contrast.py; keep them in step. */
.hero--banner::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg,
    rgba(11,23,32,.56) 0%, rgba(11,23,32,.46) 40%, rgba(11,23,32,.52) 52%, rgba(11,23,32,.80) 100%);
}
.hero__banner-in {
  position: relative; z-index: 2;
  min-height: clamp(420px, 50vw, 600px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center;
  padding-top: clamp(44px, 6vw, 76px); padding-bottom: clamp(44px, 6vw, 76px);
}
/* The lockup is SVG since 2026-09-21 (traced from the client's one-bit PNG, which
   rendered as a staircase at 2x), so it is crisp at any size. The drop shadow is
   legibility over a brighter photograph, on top of the measured scrim, not in
   place of it. */
.hero__tag { width: min(620px, 88%); }
.hero__tag img { width: 100%; height: auto; display: block;
  filter: drop-shadow(0 1px 10px rgba(0,0,0,.35)); }
/* 🔴 This beats h1[data-len="..."] on source order, not on specificity - both
   are (0,1,1). It has to stay BELOW those rules in the file. The H1 is
   deliberately quieter than the byline: the byline is the brand and the H1 is
   there to say what the business does, to a reader and to a crawler. */
.hero--banner h1 {
  color: #fff; margin: 26px 0 0;
  font-size: clamp(21px, 2.55vw, 31px); font-weight: 600; letter-spacing: -.005em;
  text-shadow: 0 1px 14px rgba(0,0,0,.45);
  max-width: 20ch;
}
.hero--banner .hero__cta { margin-top: 26px; justify-content: center; }
@media (max-width: 560px) {
  .hero__banner-in { min-height: 380px; }
  .hero--banner .hero__cta { width: 100%; flex-direction: column; align-items: stretch; }
  .hero--banner .hero__cta .btn { justify-content: center; }
}

/* --------------------------------------------------------------- one-line headings
   "put on one line" appears three times in the client's notes, against three
   headings that were wrapping onto two.

   🔴 Implemented as a smaller size in a wider box, NOT as `white-space: nowrap`.
   nowrap cannot shrink: on any viewport where the heading does not fit it
   overflows the document horizontally, and a horizontal scrollbar on a phone is
   a far worse defect than a heading on two lines. Sized so the longest of the
   three ("Tank water is normal here, and so is treating it", 47 characters in a
   780px .prose column) fits with room to spare, and it simply wraps below about
   700px where nothing could fit it. build/shots.mjs asserts one line at 1440,
   1180 and 1024. */
/* 🔴 Two traps here, and both were found by MEASURING in a browser rather than by reasoning.
   Neither is visible in the CSS.

   1. `.prose .h--1line`, not `.h--1line`. `.prose h2` is (0,1,1) and a bare class is (0,1,0), so
      the plain class LOSES and the heading went on rendering at the full 34px prose size.
   2. The column these sit in is 712px wide, NOT 780. `<div class="wrap prose">` is ONE element
      carrying both classes, so `.wrap`'s `padding: 0 34px` is inside `.prose`'s 780px max-width
      and eats 68px of it. Sizing against 780 put the heading 4px over and it wrapped, at 1440
      only - which reads as a mystery, because the same rule is fine at 1180 where the vw term is
      still below the cap.

   29px is the largest cap that fits the longest of the three headings (716px of text at 31px)
   into 712px with a margin for a future copy edit. build/shots.mjs asserts it. */
.h--1line { font-size: clamp(19px, 2.2vw, 29px); letter-spacing: -.015em; }
.prose .h--1line { font-size: clamp(19px, 2.2vw, 29px); }
/* The areas heading lives in a .sec__head, which is capped at 780px for reading
   comfort. A single line of display type is not a paragraph, so it gets the
   full row and can therefore stay larger. */
.sec__head--wide { max-width: none; }
.sec .sec__head--wide .h--1line { font-size: clamp(20px, 2.8vw, 38px); }

/* --------------------------------------------------------------- brand mark panel
   "I don't like the bullet points content for this part of the page. Remove
   them. Maybe a spot for our logo?" - so the space the tick list left on the
   home page About block carries the mark and the byline instead. */
/* 2026-09-21: "no background box colour" - the band, border and padding came off, so the
   two marks sit directly on the white. The tag is now an <img> (SVG), not a <picture>. */
/* 2026-09-22 (Capsule 489331169): "make the byline bigger and have it aligned with the bottom
   of PLUMBING SERVICES". Bottom-aligned, and the tag fills the rest of the row. The words in
   logo.png sit flush on its bottom edge, but the byline art carries descenders (the p and g in
   "Expert Plumbing") below its baseline: the baseline is at 91.2% of the SVG's height (row 177
   of 194 in the viewBox, measured off image3.png). translateY(8.8%) - a percentage of the
   tag's OWN height - drops that baseline onto the logo's bottom edge at any width. */
.brandmark {
  display: flex; align-items: flex-end; gap: clamp(22px, 3vw, 40px);
  margin: 30px 0 30px; padding: 0;
}
.brandmark__logo { width: auto; height: 88px; flex: 0 0 auto; }
.brandmark__tag {
  display: block; flex: 1 1 auto; min-width: 0; width: auto; max-width: 440px; height: auto;
  transform: translateY(8.8%);
}
@media (max-width: 560px) {
  .brandmark { flex-direction: column; align-items: flex-start; gap: 18px; }
  .brandmark__logo { height: 74px; }
  .brandmark__tag { flex: none; width: min(360px, 100%); transform: none; }
}
