/* ============================================================
   JC Home Services — homepage (/) only.
   Loaded AFTER tokens.css and base.css. Nothing in here edits either
   of those two files: another agent owns them.

   Namespacing rule: every homepage-only component is prefixed `h-`
   or carries its own unique class. The ONLY classes borrowed from
   base.css are the stable primitives — .container, .section, .btn,
   .eyebrow, .skip-link, .visually-hidden, .text-center, .site-footer.
   `.hero`, `.funnel-header` and `.formcard` are deliberately NOT reused:
   they are funnel-page components and would drag the opt-in page's
   one-screen gate onto a long scrolling page.

   MEASURED, NOT ESTIMATED (see the build report):
     ink        #161718 on --paper  = 15.78:1
     ink-dim    .72     on --paper  =  6.69:1
     ink-faint  .55     on --paper  =  3.85:1  ⛔ UNDER THE 4.5 FLOOR
     accent-deep#3B646A on --paper  =  5.74:1
     accent     #4A7C82 with #fff   =  4.67:1
     accent-bright on --deep        =  6.76:1
     accent-bright on --paper       =  2.35:1  ⛔ never on light
     on-deep-dim .72 on --deep      =  8.60:1
   Consequence: --ink-faint and --accent-bright are used on this page for
   HAIRLINES AND DECORATION ONLY, never for a word a customer reads.
   ============================================================ */

:root {
  /* Sticky chrome. Measured against the rendered header, not guessed —
     a guessed value lands anchor jumps underneath the bar. */
  --hdr-h:    76px;
  --bar-h:    48px;
  --chrome-h: 124px;   /* header + jumpbar, both sticky on desktop */
}
@media (max-width: 899px) {
  :root {
    --hdr-h:    64px;
    --bar-h:    46px;
    /* On a phone the header is NOT sticky (the bottom call bar carries the
       phone and the primary door), so only the jumpbar eats the top. */
    --chrome-h: 46px;
  }
}

/* Anchor landing. Pure CSS, so every jump lands correctly with JavaScript
   switched off. base.css already supplies scroll-behavior + the
   prefers-reduced-motion override. */
main [id], #main { scroll-margin-top: calc(var(--chrome-h) + 14px); }
/* `main` itself is the skip-link target and is NOT covered by `main [id]`.
   Without this the first keyboard user to press Skip To Content lands with
   the content tucked under the sticky bar. */
#main:focus { outline: none; }

/* The mobile call bar sits over the bottom of the page; this is what stops
   it covering the footer's last line. */
@media (max-width: 899px) { body { padding-bottom: 5.25rem; } }

/* ============================================================
   HEADER — light bar, dark logo. Solid from the first pixel:
   a transparent header over the dark hero would put the dark logo on a
   dark plate, which is the one thing the brand rule forbids.
   ============================================================ */
.site-header {
  background: var(--paper);
  border-bottom: 1px solid var(--hairline-2);
  z-index: 60;
}
@media (min-width: 900px) { .site-header { position: sticky; top: 0; } }

.h-headinner {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-md); min-height: var(--hdr-h);
  padding-block: .55rem; flex-wrap: wrap;
}
.h-brand { display: inline-flex; align-items: center; flex: none; }
.h-brand img { height: 50px; width: auto; }
@media (min-width: 900px) { .h-brand img { height: 58px; } }

.h-headcta { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }
.h-headcta .btn { padding: .85rem 1.4rem; font-size: .88rem; min-height: 48px; }

.h-tel {
  display: inline-flex; align-items: center; gap: .5rem;
  font-weight: 600; font-size: 1rem; color: var(--ink);
  text-decoration: none; padding: .5rem .25rem;
  min-height: 44px;                /* measured at 42px; the phone number is
                                      the single most tapped thing on a
                                      plumber page and must not be 2px short */
}
.h-tel:hover { color: var(--accent-deep); }
.h-tel svg { width: 17px; height: 17px; fill: var(--accent); flex: none; }

/* Below 900px the header is the logo alone. The phone and the urgent door
   live in the fixed bottom bar, where a thumb already is. */
@media (max-width: 899px) { .h-headcta { display: none; } }

/* ============================================================
   JUMP BAR — the site nav IS the section nav on a one-page site,
   so there is exactly one navigation mechanism, never two.
   Modelled on hvac-report's sticky .toc: a row of links on a wide
   screen, a labelled dropdown with aria-expanded/aria-controls below it.
   ============================================================ */
.jumpbar {
  position: sticky; top: 0; z-index: 55;
  background: color-mix(in srgb, var(--paper) 94%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 900px) { .jumpbar { top: var(--hdr-h); } }

.jumpbar__inner {
  display: flex; align-items: center; gap: var(--space-sm);
  min-height: var(--bar-h); padding-block: .35rem;
}

.jumpbar__toggle {
  display: inline-flex; align-items: center; gap: .55rem;
  font-family: var(--sans); font-weight: 600; font-size: .92rem;
  color: var(--ink); background: transparent;
  border: 1px solid var(--hairline); border-radius: 10px;
  padding: .55rem .95rem; min-height: 44px; cursor: pointer;
}
.jumpbar__toggle:hover { border-color: var(--accent); }
.jumpbar__toggle svg { width: 13px; height: 13px; transition: transform .25s var(--ease); }
.jumpbar__toggle[aria-expanded="true"] svg { transform: rotate(180deg); }

/* The list. Narrow screens: an absolutely-positioned panel under the bar.
   `hidden` is toggled by JS, so a collapsed menu is out of the tab order
   and out of the accessibility tree, not merely invisible. */
.sectionnav {
  position: absolute; left: 0; right: 0; top: 100%;
  display: flex; flex-direction: column; gap: .1rem;
  background: color-mix(in srgb, var(--paper) 98%, transparent);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--hairline);
  box-shadow: var(--shadow-card);
  max-height: 72vh; overflow-y: auto;
  padding: .5rem var(--gutter) .9rem;
}
.sectionnav[hidden] { display: none; }
.sectionnav a {
  display: block; padding: .8rem .6rem; border-radius: 8px;
  color: var(--ink-dim); font-size: 1rem; font-weight: 500;
  text-decoration: none; border-left: 2px solid transparent;
}
.sectionnav a:hover { background: var(--accent-tint); color: var(--ink); }
.sectionnav a.is-active { background: var(--accent-tint); border-left-color: var(--accent); color: var(--accent-deep); font-weight: 600; }

/* Wide: the row. 1040px is where all eight labels fit the container without
   crowding; below it the dropdown takes over. Because a media query sees the
   ZOOMED viewport, 200% zoom on a laptop also lands here and gets the
   dropdown instead of a row that runs off the screen. */
@media (min-width: 1040px) {
  .jumpbar__toggle { display: none; }
  .sectionnav {
    position: static; display: flex !important; flex-direction: row;
    align-items: center; gap: clamp(.4rem, .1rem + 1vw, 1.4rem);
    background: none; backdrop-filter: none; -webkit-backdrop-filter: none;
    border: 0; box-shadow: none; max-height: none; overflow: visible;
    padding: 0; width: 100%;
  }
  .sectionnav[hidden] { display: flex !important; }
  .sectionnav a {
    padding: .5rem .2rem; font-size: .92rem; border-left: 0;
    border-bottom: 2px solid transparent; border-radius: 0;
    white-space: nowrap;
  }
  .sectionnav a:hover { background: none; color: var(--ink); border-bottom-color: var(--accent); }
  .sectionnav a.is-active { background: none; border-bottom-color: var(--accent); color: var(--accent-deep); }
}

/* ============================================================
   BANDS — the section rhythm: paper → paper-2 → deep.
   A deep band may carry a faded photograph; a light band never does
   (the AI placeholders wash out to grey on a light ground and start
   reading as a stock image rather than atmosphere).
   ============================================================ */
.h-band { position: relative; overflow: hidden; }
.h-band--alt  { background: var(--paper-2); }
.h-band--deep { background: var(--deep); color: var(--on-deep); }
.h-band--deep h2, .h-band--deep h3 { color: var(--on-deep); }
.h-band--deep p { color: var(--on-deep-dim); }
.h-band--deep .eyebrow { color: var(--accent-bright); }
.h-band--deep > * { position: relative; z-index: 2; }

/* The photograph. A background layer, never an <img>: it carries no
   information, and swapping a real photo of Jeremy in later is one URL.
   ⚠ The breakpoint below MATCHES the <link rel=preload> media queries in
   index.html exactly. If you move one, move the other, or the browser
   fetches a file it then throws away. */
/* ⚠ THE FADE IS A BRAND RULE, NOT A TASTE DECISION. Do not lighten it.
   At the token defaults (`--hero-photo-opacity:1`, veil bottoming out at
   0.55) this photograph rendered with the man's FACE clearly readable and
   the van's painted service list legible down the left edge. The man is
   NOT Jeremy, Pagosa is a town where he is known personally, and his van
   is white and unbranded. Both of those are claims the Honest Plumber
   angle cannot survive being wrong about.
   The values below were set by looking at the render until neither the
   face nor the lettering resolved. A real photograph of Jeremy can drop
   the opacity back to 1 and use the token veil. */
.h-photo {
  position: absolute; inset: 0; z-index: 0;
  background-size: cover; background-position: 50% 38%;
  opacity: .52;
  filter: saturate(0.55) contrast(1.02);
}
.h-veil {
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(100deg,
      rgba(18, 23, 26, 0.95) 0%,
      rgba(18, 23, 26, 0.90) 40%,
      rgba(18, 23, 26, 0.80) 66%,
      rgba(18, 23, 26, 0.88) 100%);
}
@media (max-width: 899px) {
  .h-veil {
    background: linear-gradient(to bottom,
      rgba(18,23,26,0.95) 0%, rgba(18,23,26,0.90) 45%, rgba(18,23,26,0.95) 100%);
  }
}

/* The three non-hero bands are TEXTURE, not a picture. At the hero's .52
   the kitchen and doorstep frames still resolved a face in profile (cap,
   ear, beard) at full resolution on a retina screen. These sections do not
   need a legible photograph to work, so they are taken down until they are
   grain. Checked by cropping the render at 1:1, not by eye at thumbnail
   size, which is where the first pass got it wrong. */
.h-band--deep .h-photo { opacity: .30; }

.h-photo--hero      { background-image: url('../assets/ai-van-portrait-dusk@900.webp');       background-position: 62% 40%; }
.h-photo--method    { background-image: url('../assets/ai-kitchen-consult@900.webp'); }
.h-photo--next      { background-image: url('../assets/ai-doorstep-consult@900.webp'); }
.h-photo--close     { background-image: url('../assets/ai-van-walking-sunset@900.webp'); }
@media (min-width: 900px) {
  .h-photo--hero   { background-image: url('../assets/ai-van-portrait-dusk.webp'); }
  .h-photo--method { background-image: url('../assets/ai-kitchen-consult.webp'); }
  .h-photo--next   { background-image: url('../assets/ai-doorstep-consult.webp'); }
  .h-photo--close  { background-image: url('../assets/ai-van-walking-sunset.webp'); }
}

/* ============================================================
   HERO
   ============================================================ */
.home-hero { position: relative; overflow: hidden; background: var(--deep); color: var(--on-deep); }
.home-hero__inner {
  position: relative; z-index: 2;
  padding-block: clamp(2.75rem, 1.6rem + 5vw, 6rem) clamp(3rem, 2rem + 5vw, 6.5rem);
}
.home-hero::after {
  content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(120% 90% at 62% 38%, transparent 34%, rgba(10,12,13,0.55) 100%);
}
.home-hero h1 {
  color: var(--on-deep); max-width: 17ch; text-wrap: balance;
  line-height: 1.04; letter-spacing: -0.018em; margin-bottom: var(--space-md);
}
.home-hero h1 em { font-style: italic; color: var(--accent-bright); }
.home-hero__lead {
  font-size: var(--fs-lead); line-height: 1.5; color: var(--on-deep-dim);
  max-width: 46ch; margin-bottom: var(--space-sm);
}
/* The four short denial lines. Set tight so they read as one block of
   plain speech rather than four stranded paragraphs. */
.h-linestack { margin: 0 0 var(--space-lg); max-width: 46ch; }
.h-linestack p {
  margin: 0 0 .2rem; color: var(--on-deep-dim);
  font-size: 1.05rem; line-height: 1.5;
}
.h-linestack p:last-child { color: var(--on-deep); font-weight: 600; margin-top: .5rem; }

.h-actions { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-bottom: var(--space-lg); }
/* 200% ZOOM GUARD. base.css .btn--lg uses max-width:100%; at 200% zoom on a
   375px phone the two hero buttons must be free to go full width and stack
   rather than one of them clipping off the edge of its row. */
.h-actions .btn { flex: 1 1 15rem; max-width: 100%; }
@media (min-width: 620px) { .h-actions .btn { flex: 0 1 auto; } }

/* Credential chips — principle 6: licence number and tenure as plain,
   readable text in the top third, not inside an image and not in the footer. */
.h-chips { display: flex; flex-wrap: wrap; gap: .45rem; margin: 0; padding: 0; list-style: none; }
.h-chips li {
  font-size: .72rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase;
  color: var(--on-deep-dim);                     /* 8.60:1 — measured */
  border: 1px solid var(--deep-hairline); border-radius: 100px;
  padding: .42rem .8rem;
}
.h-band--deep .h-chips li { color: var(--on-deep-dim); }

/* ============================================================
   SECTION FURNITURE
   ============================================================ */
.h-head { max-width: 38ch; margin-bottom: var(--space-lg); }
.h-head--center { margin-inline: auto; text-align: center; max-width: 44ch; }
.h-head h2 { margin-bottom: var(--space-sm); }
.h-lead { font-size: var(--fs-lead); line-height: 1.55; color: var(--ink-dim); max-width: 56ch; }
.h-band--deep .h-lead { color: var(--on-deep-dim); }
.h-head--center .h-lead { margin-inline: auto; }
.h-body { max-width: 60ch; }
.h-body p { color: var(--ink-dim); }
.h-band--deep .h-body p { color: var(--on-deep-dim); }
.h-body--center { margin-inline: auto; text-align: center; }

/* A run of one-sentence paragraphs, set as a tight block. The copy is
   written in single lines on purpose; four <p> at full paragraph spacing
   pulls them apart until they stop reading as one thought. */
.h-stack p { margin: 0 0 .35rem; }
.h-stack p:last-child { margin-bottom: 0; }

.h-rule { width: 56px; height: 2px; background: var(--accent); border: 0; margin: 0 0 var(--space-md); }
.h-band--deep .h-rule { background: var(--accent-bright); }
.h-head--center .h-rule { margin-inline: auto; }

.h-usp {
  display: block; font-family: var(--serif); font-size: clamp(1.25rem, 1.05rem + .9vw, 1.7rem);
  line-height: 1.25; color: var(--ink); margin-top: var(--space-md);
  padding-left: var(--space-md); border-left: 3px solid var(--accent);
}
.h-band--deep .h-usp { color: var(--on-deep); border-left-color: var(--accent-bright); }

.h-note {
  background: var(--surface); border: 1px solid var(--hairline);
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  padding: var(--space-sm) var(--space-md); margin-block: var(--space-md);
}
.h-note p { margin-bottom: 0; color: var(--ink-dim); }
.h-note p + p { margin-top: .4rem; }

/* ============================================================
   CARDS
   ============================================================ */
.h-grid { display: grid; gap: var(--space-md); }
@media (min-width: 700px)  { .h-grid--2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 700px)  { .h-grid--3 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .h-grid--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 640px)  { .h-grid--6 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .h-grid--6 { grid-template-columns: repeat(3, 1fr); } }

.h-card {
  display: flex; flex-direction: column;
  background: var(--surface);
  /* A visible border AND a visible shadow. The opt-in card shipped a white
     border on a white card and a black shadow on a near-black ground, and
     rendered nothing at all. Both values here are measured against the
     surface they actually sit on. */
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  padding: clamp(1.35rem, 1rem + 1.2vw, 1.9rem);
  box-shadow: var(--shadow-soft);
  transition: transform .4s var(--ease), border-color .4s var(--ease), box-shadow .4s var(--ease);
}
.h-card:hover { transform: translateY(-4px); border-color: var(--accent); box-shadow: var(--shadow-card); }
.h-card h3 { margin-bottom: var(--space-2xs); }
.h-card p  { color: var(--ink-dim); margin-bottom: var(--space-2xs); }
.h-card p:last-child { margin-bottom: 0; }
.h-card__tag {
  font-size: var(--fs-label); font-weight: 600; letter-spacing: .18em;
  text-transform: uppercase; color: var(--accent-deep);   /* 6.53:1 on white */
  margin-bottom: var(--space-2xs);
}
/* The one card in a row that carries the position. */
.h-card--feature { border-color: var(--accent); box-shadow: var(--shadow-card); }
.h-card--feature .h-card__tag { color: var(--accent-deep); }

/* Numbered steps */
.h-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-lg); }
@media (min-width: 760px)  { .h-steps--3 { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 760px)  { .h-steps--4 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .h-steps--4 { grid-template-columns: repeat(4, 1fr); } }
.h-step__n {
  display: grid; place-items: center;
  width: 46px; height: 46px; border-radius: 12px;
  font-family: var(--serif); font-size: 1.3rem; line-height: 1;
  color: var(--accent-deep); background: var(--accent-tint);
  border: 1px solid var(--accent); margin-bottom: var(--space-sm);
}
.h-band--deep .h-step__n {
  color: var(--deep); background: var(--accent-bright);
  border-color: var(--accent-bright);
}
.h-step h3 { margin-bottom: var(--space-2xs); }
.h-step p  { color: var(--ink-dim); margin-bottom: .3rem; }
.h-band--deep .h-step p { color: var(--on-deep-dim); }
.h-step p:last-child { margin-bottom: 0; }

/* Plain lists of things a homeowner can check in their own house */
.h-checks { list-style: none; margin: var(--space-md) 0 0; padding: 0; display: grid; gap: .6rem; }
.h-checks li { display: flex; gap: .7rem; align-items: flex-start; color: var(--ink-dim); }
.h-checks li::before {
  content: ""; flex: none; width: 7px; height: 7px; margin-top: .62rem;
  border-radius: 50%; background: var(--accent);
}
.h-band--deep .h-checks li { color: var(--on-deep-dim); }
.h-band--deep .h-checks li::before { background: var(--accent-bright); }
@media (min-width: 720px) { .h-checks--2 { grid-template-columns: repeat(2, 1fr); gap: .6rem var(--space-lg); } }

/* Before / after, the transformation block */
.h-ba { display: grid; gap: var(--space-md); margin-top: var(--space-lg); }
@media (min-width: 760px) { .h-ba { grid-template-columns: repeat(2, 1fr); gap: var(--space-lg); } }
.h-ba h3 {
  font-family: var(--sans); font-size: var(--fs-label); font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink-dim); margin-bottom: var(--space-sm);
}
.h-ba__after h3 { color: var(--accent-deep); }

/* ============================================================
   SERVICE JUMP ROW — the offer page's .o-nav card row, at JC's scale.
   A row of cards, not a text menu.
   ============================================================ */
.svcnav {
  display: grid; gap: var(--space-sm);
  grid-template-columns: repeat(2, 1fr);
  margin-top: var(--space-xl);
}
@media (min-width: 760px)  { .svcnav { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1040px) { .svcnav { grid-template-columns: repeat(6, 1fr); } }
.svcnode {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: .6rem; padding: var(--space-md) .6rem;
  background: var(--surface); border: 1px solid var(--hairline);
  border-radius: var(--radius); text-decoration: none;
  transition: transform .3s var(--ease), border-color .3s var(--ease), box-shadow .3s var(--ease);
}
.svcnode:hover { transform: translateY(-3px); border-color: var(--accent); box-shadow: var(--shadow-soft); }
.svcnode__ico {
  display: grid; place-items: center; flex: none;
  width: 52px; height: 52px; border-radius: 50%;
  border: 1px solid var(--hairline); background: var(--paper);
}
.svcnode__ico svg {
  width: 26px; height: 26px;
  stroke: var(--accent-deep); fill: none; stroke-width: 1.5;
  stroke-linecap: round; stroke-linejoin: round;
}
.svcnode__t {
  font-family: var(--serif); font-size: 1.02rem; line-height: 1.2;
  color: var(--ink);
}
.svcnode:hover .svcnode__t { color: var(--accent-deep); }

/* ============================================================
   SERVICE SECTIONS
   ============================================================ */
.h-svc__grid { display: grid; gap: var(--space-lg); align-items: start; }
@media (min-width: 900px) {
  .h-svc__grid { grid-template-columns: 1fr 1fr; gap: clamp(2rem, 1rem + 4vw, 4.5rem); }
}
.h-svc__mech {
  font-family: var(--sans); font-size: var(--fs-label); font-weight: 600;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--accent-deep); margin-bottom: var(--space-2xs);
}
.h-band--deep .h-svc__mech { color: var(--accent-bright); }
.h-svc__cta { margin-top: var(--space-lg); }

/* ============================================================
   FAQ — single-open accordion.
   `hidden` on the closed panel keeps it out of the tab order and out of
   the accessibility tree; max-height alone only makes it invisible.
   ============================================================ */
.faq { max-width: 860px; margin-inline: auto; }
.faq__item { border-bottom: 1px solid var(--hairline); }
.faq__h { margin: 0; font: inherit; }
.faq__q {
  width: 100%; background: transparent; border: 0; cursor: pointer; text-align: left;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-md);
  padding: 1.4rem 0; color: var(--ink); min-height: 56px;
  font-family: var(--serif); font-size: clamp(1.12rem, 1rem + .6vw, 1.45rem); line-height: 1.25;
}
.faq__q:hover { color: var(--accent-deep); }
.faq__ic {
  flex: none; width: 32px; height: 32px; border-radius: 50%;
  border: 1px solid var(--hairline); display: grid; place-items: center;
  position: relative; transition: background .3s var(--ease), border-color .3s var(--ease);
}
.faq__ic::before, .faq__ic::after {
  content: ""; position: absolute; background: var(--accent); border-radius: 2px;
  transition: opacity .25s var(--ease), transform .25s var(--ease);
}
.faq__ic::before { width: 12px; height: 2px; }
.faq__ic::after  { width: 2px; height: 12px; }
.faq__item.is-open .faq__ic { background: var(--accent-tint); border-color: var(--accent); }
.faq__item.is-open .faq__ic::after { opacity: 0; transform: rotate(90deg); }
.faq__a { overflow: hidden; }
.faq__a[hidden] { display: none; }
.faq__a-in { padding: 0 0 1.5rem; color: var(--ink-dim); max-width: 68ch; }
.faq__a-in p { margin: 0 0 .35rem; color: var(--ink-dim); }
.faq__a-in p:last-child { margin-bottom: 0; }

/* ============================================================
   CLOSING BLOCK
   ============================================================ */
.h-close h2 { max-width: 20ch; margin-inline: auto; }
.h-close h2 + h2 { margin-top: .2rem; }
.h-close .h-actions { justify-content: center; margin-top: var(--space-lg); }
.h-close__fine {
  margin-top: var(--space-lg); font-size: .82rem; letter-spacing: .04em;
  color: var(--on-deep-dim);
}

/* Founder quote */
.h-quote {
  margin: var(--space-lg) 0 0; padding: 0 0 0 var(--space-md);
  border-left: 3px solid var(--accent);
  font-family: var(--serif); font-style: italic;
  font-size: clamp(1.15rem, 1rem + .8vw, 1.6rem); line-height: 1.4;
  color: var(--ink); max-width: 34ch;
}

/* ============================================================
   STICKY CALL BAR — mobile only.
   Principle 4: a plumbing site's conversion on a phone is a phone call.
   Two controls, nothing else, and body padding so it covers nothing.
   ============================================================ */
.callbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  display: none; align-items: center; gap: .5rem;
  padding: .55rem var(--gutter) calc(.55rem + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--paper) 96%, transparent);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  border-top: 1px solid var(--hairline);
}
.callbar__tel {
  flex: 1 1 auto; display: inline-flex; align-items: center; justify-content: center;
  gap: .45rem; min-height: 50px; padding: .7rem .8rem;
  border: 1px solid var(--accent); border-radius: var(--radius);
  color: var(--ink); font-weight: 600; font-size: .95rem; text-decoration: none;
  background: var(--surface);
}
.callbar__tel svg { width: 17px; height: 17px; fill: var(--accent); flex: none; }
.callbar .btn { flex: 1 1 auto; padding: .7rem .9rem; font-size: .82rem; min-height: 50px; }
@media (max-width: 899px) { .callbar { display: flex; } }

/* ============================================================
   SECONDARY BUTTON — base.css ships .btn--primary only.
   accent-deep on paper measures 5.74:1; the fill on hover is the same
   accent the primary button uses, with white at 4.67:1.
   ============================================================ */
.btn--ghost {
  background: transparent; color: var(--accent-deep);
  border: 1px solid var(--accent);
}
.btn--ghost:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
/* On a deep band the same button inverts, or it disappears into the plate. */
.h-band--deep .btn--ghost, .home-hero .btn--ghost {
  color: var(--on-deep); border-color: var(--accent-bright);
  background: rgba(242, 240, 236, 0.06);
}
.h-band--deep .btn--ghost:hover, .home-hero .btn--ghost:hover {
  background: var(--accent-bright); color: var(--deep); border-color: var(--accent-bright);
}

/* ============================================================
   MOTION — opt-in, and it can never leave content stuck hidden.
   home.js adds .js-anim only once it is about to run the observer, so no
   JS, a 404 on the script or a crash before setup all give a fully
   visible page. Never a blank one.
   ============================================================ */
@media (prefers-reduced-motion: no-preference) {
  .js-anim .reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s var(--ease), transform .6s var(--ease); }
  .js-anim .reveal.is-in { opacity: 1; transform: none; }
  .js-anim .reveal[data-delay="1"] { transition-delay: .09s; }
  .js-anim .reveal[data-delay="2"] { transition-delay: .18s; }
  .js-anim .reveal[data-delay="3"] { transition-delay: .27s; }
  /* Big type travels less than small type. */
  .js-anim h1.reveal, .js-anim h2.reveal { transform: translateY(10px); }
  @media (max-width: 640px) { .js-anim .reveal { transform: translateY(12px); transition-duration: .45s; } }
}

/* ============================================================
   PRINT — base.css already ships a print block. These are the additions
   for components base.css has never seen. Chrome that means nothing on
   paper goes; every panel opens; every band flattens to white.
   ============================================================ */
@media print {
  .site-header, .jumpbar, .callbar, .h-photo, .h-veil, .h-actions, .svcnav { display: none !important; }
  .js-anim .reveal { opacity: 1 !important; transform: none !important; }

  .home-hero, .h-band, .h-band--deep, .h-band--alt { background: #fff !important; color: #000 !important; }
  .home-hero::after { display: none !important; }
  .home-hero h1, .h-band--deep h2, .h-band--deep h3,
  .home-hero__lead, .h-band--deep p, .h-band--deep .h-lead,
  .h-band--deep .h-body p, .h-band--deep .h-step p, .h-band--deep .h-checks li,
  .h-close__fine { color: #000 !important; }
  .home-hero h1 em, .h-band--deep .eyebrow, .h-band--deep .h-svc__mech { color: #000 !important; }
  .h-chips li { color: #000 !important; border-color: #666 !important; }
  .h-band--deep .h-step__n { color: #000 !important; background: #fff !important; border-color: #666 !important; }
  .h-rule, .h-band--deep .h-rule { background: #000 !important; }

  .h-card, .h-note, .h-usp, .h-quote, .faq__item, .h-step { break-inside: avoid; box-shadow: none !important; }
  .h-card { border-color: #999 !important; }
  h2, h3 { break-after: avoid; }
  .home-hero__inner { padding-block: 0 1.2rem; }
  .section { padding-block: 1.1rem; }

  /* Every answer open on paper; a printed FAQ with closed panels is blank. */
  .faq__a[hidden] { display: block !important; }
  .faq__ic { display: none !important; }
}


/* ============================================================
   LATE ADDITIONS, all from looking at the render.
   ============================================================ */

/* The closing block is a deep band with a photograph and the footer is a
   flat deep band. Butted together with no line they read as one slab. */
.site-footer { border-top: 1px solid var(--deep-hairline); }

/* The footer's link list is ONE list under ONE heading, because the copy
   file's footer has exactly one heading. Two columns is a CSS decision,
   not a second heading a customer reads. */
.footer__links { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 var(--space-md); }
.footer__links a {
  display: flex; align-items: center;
  color: var(--on-deep-dim); font-size: .9rem;
  min-height: 44px;                 /* measured at 33px first; eleven stacked
                                       links on a phone is exactly where a
                                       small target costs a tap */
  padding-block: .35rem; text-decoration: none;
  transition: color .3s var(--ease);
}
.footer__links a:hover { color: var(--accent-bright); }
@media (max-width: 480px) { .footer__links { grid-template-columns: 1fr; } }

/* #promise and #truth borrow the service frame so the text is not stranded
   in the left half of an 1180px container. */
#promise .h-ba { margin-top: var(--space-xl); }


/* On a 375x667 phone the hero's primary button landed half under the fixed
   call bar. Measured, then trimmed: ~34px comes out of the hero's top pad and
   the gap under the denial lines, which puts the whole button clear of the bar
   on the shortest phone still in wide use. Nothing else moves. */
@media (max-width: 899px) {
  .home-hero__inner { padding-block: 1.75rem 2.25rem; }
  .home-hero h1 { margin-bottom: var(--space-sm); }
  .home-hero__lead { margin-bottom: var(--space-xs); }
  .h-linestack { margin-bottom: var(--space-md); }
  .h-actions { margin-bottom: var(--space-md); }
}


/* ============================================================
   200% TEXT ZOOM — measured, not assumed.
   At 200% text zoom on a 375px phone the six service cards sit in a
   2-column grid whose tracks are ~157px, and "Whole-Home Repipe",
   "24-Hour Plumbing Repair" and "Water Safety Inspection" ran ~57px past
   their own card. The page scroll width did NOT grow, so the words were
   simply clipped: content lost, with no way for the reader to recover it.
   That is the same class of defect the opt-in review caught.

   Media queries cannot see text zoom, so the fix is not a breakpoint: every
   run of text that sits in a fixed track is allowed to break rather than
   overflow. Nothing changes at 100%; at 200% a word wraps instead of
   vanishing. `hyphens: auto` makes the break land somewhere sensible.
   ============================================================ */
/* A per-component list was tried first and was the wrong shape: it fixed the
   six cards and left the body copy, the leads and the eyebrows overflowing by
   the same mechanism. A grid or flex child defaults to `min-width: auto`, so
   ANY string too long for its track widens the track instead of wrapping.
   The net therefore goes over the whole page, and every grid and flex child
   on it is told it may be narrower than its own content. */
.site-header, .jumpbar, main, .site-footer, .callbar {
  overflow-wrap: break-word;
  /* `hyphens: auto` was here and fired at EVERY width, not just at zoom.
     Design review found nine hyphenated words on screen at 1440px
     ("be-cause", "sys-tems", "some-body", "to-morrow's"). `overflow-wrap`
     plus the `min-width: 0` net below already prevent the content LOSS this
     rule was written for; hyphenation only made the break prettier. It is
     now limited to phone widths, where a long word in a narrow track is a
     real risk. Do not restore it globally. */
  hyphens: manual;
}
@media (max-width: 420px) {
  .site-header, .jumpbar, main, .site-footer, .callbar { hyphens: auto; }
}
.h-svc__grid > *, .h-grid > *, .h-steps > *, .h-ba > *, .svcnav > *,
.h-checks > *, .h-actions > *, .h-headinner > *, .jumpbar__inner > *,
.footer__grid > *, .callbar > * { min-width: 0; }
/* The chips are pills with `white-space: nowrap` inherited from the funnel
   proofline pattern; at 200% they must be allowed to wrap too. */
.h-chips li { white-space: normal; }
/* Card and node padding shrinks before the text does, so the words keep
   their room at large sizes. */
.svcnode { padding-inline: .45rem; }


/* base.css sizes button padding in rem, so at very large text zoom the
   padding alone is wider than the phone. WCAG 1.4.4 only asks for 200% and
   the page is clean there, but the buttons are the one control a reader
   cannot afford to lose, so their side padding is switched to a viewport
   clamp (which text zoom does not scale) and they are allowed to be no
   wider than their column. */
.btn {
  max-width: 100%;
  padding-inline: clamp(0.9rem, 0.4rem + 3vw, 2rem);
}


/* Print, second pass — found by actually printing the page to PDF and
   reading it, not by reading the CSS. The hero's four denial lines
   ("No cheap shortcuts." and the rest) are `--on-deep-dim`, which is a light
   ink meant for a dark plate. The earlier print block flattened
   `.h-band--deep p` but the hero is `.home-hero`, not a `.h-band--deep`, so
   those four lines printed as pale grey on white and were close to
   invisible on paper. Everything inside the hero is now forced to ink. */
@media print {
  .home-hero p, .home-hero li, .home-hero .h-linestack p,
  .home-hero .h-linestack p:last-child, .home-hero__lead,
  .h-close__fine, .h-band--deep .h-lead p, .h-band--deep .h-stack p {
    color: #000 !important;
  }
  .h-linestack p:last-child { font-weight: 700; }
}

/* Tap targets: the section-nav links measured 42px, under the 44px floor. */
.sectionnav a, .jumpbar a { min-height: 44px; display: inline-flex; align-items: center; }

/* ============================================================
   CRAFT PASS — the design review's ten, applied.
   Everything below is typography, rhythm and proportion. No copy
   moves, no colour token changes, no photo rule relaxed.
   ============================================================ */

/* 1. MEASURE. The two-column bands landed prose in a ~310px track at
   1440px: about 35-45 characters, roughly half the comfortable 60-75.
   A short measure is what forced the hyphenation defect. The frame is
   now weighted toward the prose side instead of a flat 1fr 1fr. */
@media (min-width: 900px) {
  .h-svc__grid { grid-template-columns: minmax(260px, 0.82fr) minmax(440px, 1.18fr); }
}
.h-body, .h-linestack { max-width: 62ch; }

/* 2. PARAGRAPH RHYTHM. Chris writes in single-sentence lines. At an even
   paragraph gap, twelve of them in a row read as a transcript: no shape,
   no hierarchy, nothing for the eye to hold. Tightened into a run, with
   the closing line carrying weight so each stack has an ending.
   ⛔ This is spacing only. Not one word is touched. */
.h-stack p, .h-linestack p { margin: 0 0 .28rem; line-height: 1.55; }
/* ⚠ The closing line gets WEIGHT and SIZE only — never a colour.
   Setting `color: var(--ink)` here painted "Just honest work at an
   honest price." in near-black on the near-black hero: invisible.
   The bands each already set their own text colour correctly, so the
   emphasis must inherit it rather than name one. A rule that hard-codes
   ink cannot be right on both a paper band and a deep band. */
.h-stack p:last-child, .h-linestack p:last-child {
  margin-top: .75rem; margin-bottom: 0;
  font-size: 1.08em; font-weight: 600;
  color: inherit; opacity: 1;
}

/* 3. THE STEP NUMERALS. A pale mint pill holding dark text is the
   universal signature of a DISABLED control, and on the dark band it was
   the brightest object on screen, out-shouting the headings. The numeral
   becomes the type it always wanted to be: large, serif, accent, over a
   hairline. */
.h-step__n {
  width: auto; height: auto; border: none; background: none;
  border-radius: 0; place-items: start;
  font-size: 2.6rem; line-height: 1; color: var(--accent-deep);
  padding-bottom: .5rem; margin-bottom: .7rem;
  border-bottom: 1px solid var(--hairline);
}
.h-band--deep .h-step__n {
  color: var(--accent-bright); background: none; border-color: rgba(255,255,255,.16);
}

/* 4. RAGGED BOTTOMS. Columns aligned at the top and nowhere else, so a
   3-line column sat beside a 9-line one with a void under it. Cards now
   stretch to a common floor. */
.h-steps, .h-grid, .svcnav { align-items: stretch; }
.h-step, .h-usp, .h-rock { display: flex; flex-direction: column; }
.h-step > :last-child, .h-usp > :last-child { margin-bottom: 0; }

/* 5. ONE AXIS PER BAND. A centred H2 over a left-aligned prose block
   offset left of centre gave three different left edges in one section.
   When the heading is centred, the prose block centres with it. */
.h-head--center + .h-body, .h-body--center { margin-inline: auto; }

/* 6. THE MOBILE HERO. The review is right that the first paint is a
   headline over a large dark field, with the buttons below the fold.
   ⛔ The fix is NOT to lighten the photograph. See the brand rule above:
   the man is not Jeremy and the van carries another company's lettering.
   The fix is to stop the hero reserving a full screen it does not fill,
   which lifts the buttons and the credentials into view instead. */
@media (max-width: 640px) {
  .home-hero { min-height: auto; padding-block: 2.6rem 3rem; }
}
