/* Houston Sprinkler Fix — base stylesheet
   Single static stylesheet, no build step, no external font or JS dependency.

   Contrast, computed rather than eyeballed (WCAG AA needs 4.5:1 for body and
   small bold text, 3:1 for large text):
     --type on --canvas-c ......................... 14.30:1
     --hushed on --canvas-c ........................ 6.58:1
     --hushed on --plain ........................... 6.95:1
     white on --spray (#2e7023) .................... 6.07:1
     white on the --spray hover (#235618) .......... 8.69:1
     white on --turf .............................. 10.43:1
     --spray on --canvas-c (links, band labels) .... 5.75:1
     --spray on --plain ............................ 6.07:1
     --spray on the #e6efe3 step tint .............. 5.15:1
     --turf on --canvas-c (h2) ..................... 9.89:1
     --turf on --plain (h3, area pills) ........... 10.43:1
     brand mark (#a9dcaa) on --turf ................ 6.71:1
     nav link (#d5dfd3) on --turf .................. 7.61:1
     hero lead (#e3e9e1) on --turf ................. 8.45:1
     hero subnote (#c8d3c6) on --turf .............. 6.75:1
     footer text (#a9bda6) on the footer #1e3a1c ... 6.27:1
     success text (#1f5d34) on its #e4f0e6 tint .... 6.70:1
     error text (#b3261e) on its #fdecea tint ...... 5.72:1
     --type on --dew (#8ee0cf) ..................... 9.85:1
   --zone (#53814b) is the light end of the hero gradient and nothing else. It
   sits at 4.32:1 on --canvas-c, under the 4.5:1 floor, and must never carry text.

   The rationale behind these choices, and the files this palette was checked
   against, are recorded outside the web root — this stylesheet is served
   publicly, so it does not carry them.
*/

:root {
  /* Chrome: the deep green the header, footer, headings and CTA band sit on. */
  --turf: #274724;
  /* RGB channels of --turf, for the hero photo scrim. Recompute both together. */
  --shade-l: 39, 71, 36;
  /* Mid tone: hero gradient only. Never text. */
  --zone: #53814b;
  /* Accent + every call-to-action, and the body link color. */
  --spray: #2e7023;
  /* Highlight: small-area only. */
  --dew: #8ee0cf;
  --canvas-c: #f6faf4;
  --plain: #ffffff;
  --type: #1b2a19;
  --hushed: #4f5d53;
  --rule: #dde7db;
  --curve: 8px;
  --round-sm: 4px;
  --bound-c: 1152px;
  /* The fixed CTA bar's real height: 10+11 padding plus a 0.92rem line (23px),
     +2px slack. One height at every width, so no media override. body's
     padding-bottom matches it. */
  --anchor-h: 67px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: var(--type);
  background: var(--canvas-c);
  line-height: 1.55;
  padding-bottom: var(--anchor-h);
}
img { max-width: 100%; display: block; }
a { color: var(--spray); text-decoration: none; }
a:hover { text-decoration: underline; }
.measure-x { max-width: var(--bound-c); margin: 0 auto; padding: 0 20px; }

/* Header */
header.headband {
  background: var(--turf);
  color: var(--plain);
  position: sticky;
  top: 0;
  z-index: 50;
}
header.headband .runner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  max-width: var(--bound-c);
  margin: 0 auto;
  flex-wrap: wrap;
  gap: 10px;
}
header.headband .insignia {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--plain);
}
/* The brand mark sits on --turf. --spray against --turf computes to 1.72:1,
   far below the 3:1 large-text floor, so the second word takes a light tint of
   the same hue instead of the accent variable. */
header.headband .insignia span { color: #a9dcaa; }
.medallion { width: 30px; height: 30px; border-radius: 50%; display: block; flex-shrink: 0; }
header.headband nav { display: flex; gap: 16px; flex-wrap: wrap; }
header.headband nav a { color: #d5dfd3; font-size: 0.95rem; }
header.headband nav a:hover { color: var(--plain); }
header.headband .reach-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  background: var(--spray);
  color: var(--plain);
  padding: 9px 16px;
  border-radius: var(--curve);
  font-weight: 700;
}
header.headband .reach-btn:hover { background: #235618; text-decoration: none; }

/* Hero */
.splash {
  background: linear-gradient(135deg, var(--turf), var(--zone));
  color: var(--plain);
  padding: 56px 20px 48px;
}
.splash .measure-x { display: flex; flex-direction: column; gap: 18px; }
.splash .overline {
  display: inline-block;
  background: rgba(255,255,255,0.12);
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 0.8rem;
  letter-spacing: 0.03em;
  width: fit-content;
}
.splash h1 { font-size: 2.2rem; margin: 0; max-width: 780px; }
.splash p.standfirst { font-size: 1.1rem; color: #e3e9e1; max-width: 620px; margin: 0; }
.splash .prompt-row { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 6px; }
.splash .postscript { font-size: 0.9rem; color: #c8d3c6; max-width: 660px; }

/* The referral disclosure is a legal requirement, not decoration, so it does
   not rely on the hero photo happening to be dark behind it. Its own scrim
   keeps it conspicuous at every width and over any part of the image. */
.splash .standing-note {
  font-size: 0.9rem;
  color: #ffffff;
  max-width: 700px;
  background: rgba(var(--shade-l), 0.84);
  border-left: 3px solid var(--dew);
  padding: 12px 16px;
  border-radius: 6px;
  margin: 6px 0 0;
}
.splash .standing-note strong { color: #ffffff; }

.pushbtn {
  display: inline-block;
  padding: 13px 22px;
  border-radius: var(--curve);
  font-weight: 700;
  font-size: 1rem;
}
.pushbtn.dominant { background: var(--spray); color: var(--plain); }
.pushbtn.dominant:hover { background: #235618; text-decoration: none; }
.pushbtn.hairline-btn { background: rgba(255,255,255,0.08); color: var(--plain); border: 1px solid rgba(255,255,255,0.35); }
.pushbtn.hairline-btn:hover { background: rgba(255,255,255,0.16); text-decoration: none; }

/* Hero with a full-bleed background photo (homepage only) — a left-to-right
   dark gradient layered over the image so the H1 and lead stay readable. */
.splash.photo-led {
  background-image:
    linear-gradient(90deg, rgba(var(--shade-l), 0.92) 0%, rgba(var(--shade-l), 0.74) 40%, rgba(var(--shade-l), 0.30) 70%, rgba(var(--shade-l), 0.06) 100%),
    url('/images/hero-sprinkler-photo.jpg');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  min-height: 560px;
  display: flex;
  align-items: center;
  padding: 56px 20px;
}
@media (max-width: 820px) {
  .splash.photo-led {
    background-image:
      linear-gradient(180deg, rgba(var(--shade-l), 0.90) 0%, rgba(var(--shade-l), 0.82) 55%, rgba(var(--shade-l), 0.66) 100%),
      url('/images/hero-sprinkler-photo.jpg');
    min-height: 470px;
  }
}

/* Sections */
section { padding: 48px 20px; }
section.contrast-band { background: var(--plain); border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); }
.division-label {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  color: var(--spray);
  font-weight: 700;
  margin-bottom: 6px;
}
h2 { font-size: 1.65rem; margin: 0 0 20px; color: var(--turf); }
h3 { font-size: 1.15rem; margin: 0 0 8px; color: var(--turf); }

/* Grid cards. This site runs 2-up and 4-up rather than a 3-up default: the
   symptom cards carry a sentence of diagnosis each and read badly at a third
   of the measure, and the four-across row is for short link tiles. */
.lattice { display: grid; gap: 18px; }
.lattice.couplet { grid-template-columns: repeat(2, 1fr); }
.lattice.cols-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 980px) { .lattice.cols-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 820px) {
  .lattice.couplet { grid-template-columns: 1fr; }
  .splash h1 { font-size: 1.7rem; }
  header.headband .runner { justify-content: center; text-align: center; }
}
@media (max-width: 560px) { .lattice.cols-4 { grid-template-columns: 1fr; } }

/* 821-1060px: brand, a full nav and the phone number no longer fit on one line
   now that the call button shows real digits. Rather than shrink the number,
   the nav takes its own centered row — brand left, phone right, nav beneath. */
@media (min-width: 821px) and (max-width: 1060px) {
  header.headband nav { order: 3; flex: 1 0 100%; justify-content: center; margin-top: 2px; }
}
.frame-box {
  background: var(--plain);
  border: 1px solid var(--rule);
  border-radius: var(--curve);
  padding: 20px;
}
.frame-box p { color: var(--hushed); margin: 6px 0 0; font-size: 0.95rem; }
.frame-box p:last-child { margin-bottom: 0; }

/* Trust strip */
.credibility {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  justify-content: center;
  padding: 18px 20px;
  background: var(--plain);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  font-size: 0.92rem;
  color: var(--hushed);
}
.credibility strong { color: var(--turf); }

/* FAQ — native <details>/<summary>, no JS */
.ask { border-bottom: 1px solid var(--rule); padding: 14px 0; }
.ask:first-of-type { padding-top: 0; }
.ask summary {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--turf);
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.ask summary::-webkit-details-marker { display: none; }
.ask summary::after {
  content: "+";
  font-size: 1.4rem;
  font-weight: 400;
  color: var(--spray);
  flex-shrink: 0;
}
.ask[open] summary::after { content: "\2212"; }
.ask p { margin: 10px 0 0; color: var(--hushed); }

/* How it works — an ordered list rather than numbered cards, because the order
   is the content and a list says so without a decorative digit. */
ol.progression {
  list-style: none;
  counter-reset: stage;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
ol.progression .rung {
  counter-increment: stage;
  background: var(--plain);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--spray);
  border-radius: var(--curve);
  padding: 20px;
}
ol.progression .rung h3::before {
  content: counter(stage) ". ";
  color: var(--spray);
  font-weight: 700;
}
ol.progression .rung h3 { font-size: 1.02rem; }
ol.progression .rung p { color: var(--hushed); font-size: 0.92rem; margin: 0; }
@media (max-width: 820px) { ol.progression { grid-template-columns: 1fr; } }

/* Price table. The wrapper is required, not optional: a table's own
   overflow:hidden (used to clip the border radius) does not create a scroll
   context, so without it the whole document slides sideways on a phone. */
.table-pan { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.charges-table {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  background: var(--plain);
  border: 1px solid var(--rule);
  border-radius: var(--curve);
  font-size: 0.95rem;
}
.charges-table caption {
  caption-side: bottom;
  text-align: left;
  color: var(--hushed);
  font-size: 0.85rem;
  padding-top: 10px;
}
.charges-table th, .charges-table td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--rule); vertical-align: top; }
.charges-table thead th { background: #e6efe3; color: var(--turf); font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.05em; }
.charges-table tbody tr:last-child td { border-bottom: none; }
.charges-table td.figure { white-space: nowrap; font-weight: 700; color: var(--turf); }

/* Coverage tiers — a plain nested list, not pills, because the grouping is the
   point and pills flatten it. */
.tier-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 22px; }
.tier-list > li > h3 { margin-bottom: 4px; }
.tier-list .tier-note { color: var(--hushed); font-size: 0.92rem; margin: 0 0 10px; }
.territories { display: flex; flex-wrap: wrap; gap: 10px; }
.territories a {
  background: var(--plain);
  border: 1px solid var(--rule);
  padding: 9px 14px;
  border-radius: 999px;
  color: var(--turf);
  font-size: 0.92rem;
}
.territories a:hover { border-color: var(--spray); text-decoration: none; }
.territories span {
  padding: 9px 14px;
  border-radius: 999px;
  border: 1px dashed var(--rule);
  color: var(--hushed);
  font-size: 0.92rem;
}

/* CTA band */
.endcap {
  background: var(--turf);
  color: var(--plain);
  text-align: center;
  padding: 44px 20px;
}
.endcap h2 { color: var(--plain); }
.endcap p { color: #d5dfd3; margin-bottom: 18px; }

/* Contact form */
form.approach { display: grid; gap: 12px; max-width: 480px; }
form.approach label { font-size: 0.88rem; font-weight: 600; color: var(--turf); display: block; margin-bottom: 4px; }
form.approach input, form.approach select, form.approach textarea {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--rule);
  border-radius: var(--round-sm);
  font-size: 0.95rem;
  font-family: inherit;
}
form.approach .terms-note { font-size: 0.78rem; color: var(--hushed); }
form.approach .alt-contact { position: absolute; left: -9999px; top: -9999px; }
form.approach button[disabled] { opacity: 0.6; cursor: not-allowed; }
.outcome-line { margin-top: 12px; padding: 11px 14px; border-radius: var(--round-sm); font-size: 0.9rem; display: none; }
.outcome-line.visible { display: block; }
.outcome-line.success { background: #e4f0e6; color: #1f5d34; }
.outcome-line.error { background: #fdecea; color: #b3261e; }

/* Breadcrumb */
.trailmarks { font-size: 0.85rem; color: var(--hushed); padding: 14px 20px 0; max-width: var(--bound-c); margin: 0 auto; }
.trailmarks a { color: var(--hushed); }

/* Footer */
footer.headband {
  background: #1e3a1c;
  color: #a9bda6;
  padding: 40px 20px 24px;
  font-size: 0.9rem;
}
footer.headband .measure-x { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 24px; }
footer.headband h4 { color: var(--plain); font-size: 0.95rem; margin: 0 0 10px; }
footer.headband ul { list-style: none; padding: 0; margin: 0; }
footer.headband li { margin-bottom: 6px; }
footer.headband a { color: #a9bda6; }
footer.headband .last-row {
  max-width: var(--bound-c);
  margin: 24px auto 0;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.08);
  font-size: 0.8rem;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
}
@media (max-width: 720px) { footer.headband .measure-x { grid-template-columns: 1fr 1fr; } }

.unfilled {
  background: #eafaf5;
  color: #14483c;
  border: 1px dashed var(--dew);
  padding: 2px 6px;
  border-radius: 3px;
  font-size: 0.82em;
}

/* Sticky CTA bar — visible at EVERY width (calls are the priority conversion) */
.anchorbar {
  display: flex;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  background: var(--turf);
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  box-shadow: 0 -2px 10px rgba(0,0,0,0.15);
  gap: 10px;
  justify-content: center;
}
.anchorbar-inner {
  display: flex;
  gap: 10px;
  width: 100%;
  max-width: var(--bound-c);
  margin: 0 auto;
}
.anchorbar a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  text-align: center;
  padding: 11px 10px;
  border-radius: var(--round-sm);
  font-weight: 700;
  font-size: 0.92rem;
}
.anchorbar .voice-glyph { flex: none; }
.perch-call { flex: 3; background: var(--spray); color: var(--plain); }
.standing-ask { flex: 2; background: rgba(255,255,255,0.1); color: var(--plain); border: 1px solid rgba(255,255,255,0.35); }
.perch-call:hover { background: #235618; text-decoration: none; }
.standing-ask:hover { background: rgba(255,255,255,0.18); text-decoration: none; }
/* Narrow phones: the digits must survive, the qualifier is what gives way. */
.anchorbar .dock-note { display: none; }
@media (min-width: 600px) { .anchorbar .dock-note { display: inline; } }
@media (min-width: 721px) {
  .anchorbar-inner { justify-content: center; }
  .anchorbar a { flex: 0 0 auto; padding: 11px 22px; font-size: 0.92rem; }
}

/* --- Work photos ------------------------------------------------------ */
/* One inline documentary shot dropped between two content sections partway
   down a service page. Deliberately not a gallery grid and not a CSS
   background: one photo per page, off-rhythm, no captions.

   The base rule caps the width so an unclassed figure can never render
   full-bleed across the page — that failure looks completely correct in the
   markup, so the block ships before any page references the class. There are
   deliberately no orientation modifier classes here: every master is landscape
   1200x800, and an unused modifier turns "add the class" into the easy fix for
   an image that should have been regenerated instead. */
.onsite {
  max-width: var(--bound-c);
  margin: 0 auto;
  padding: 34px 20px;
}
.onsite img {
  display: block;
  width: 100%;
  max-width: 800px;
  height: auto;
  margin: 0 auto;
  border-radius: var(--curve);
  border: 1px solid var(--rule);
}

/* --- Homepage work strip ---------------------------------------------- */
/* Twelve small thumbnails, one per service page. Deliberately not links and
   not lightboxed — they are scroll-depth reassurance, not a gallery. The
   full-size versions live on the matching service pages.

   Column counts are worked out for twelve so the rows come out even at every
   breakpoint: 4+4+4 on desktop and 2x6 at both narrower widths. A ragged
   trailing row is the visible tell that nobody redid the arithmetic. */
.frieze .contacts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
}
.frieze img {
  display: block;
  width: 100%;
  /* height:auto is required — the img height="320" attribute is a
     presentational hint that would otherwise force a 320px box and make
     aspect-ratio be ignored entirely. */
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--round-sm);
  border: 1px solid var(--rule);
  background: var(--plain);
}
@media (max-width: 900px) { .frieze .contacts { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .frieze .contacts { grid-template-columns: repeat(2, 1fr); gap: 10px; } }

/* --- Reviews ---------------------------------------------------------- */
/* The reviews partial is gated off server-side and emits zero bytes until a
   real vendor with real reviews exists, so none of this renders today. It
   ships anyway: the alternative is a section that appears unstyled on the day
   somebody flips the flag, which is the same class of silent failure as markup
   shipped ahead of its CSS. */
.lattice.trisect { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 820px) { .lattice.trisect { grid-template-columns: 1fr; } }
.commendation .marks { color: var(--spray); letter-spacing: 0.12em; margin: 0 0 8px; }
.commendation p { color: var(--hushed); margin: 0 0 10px; }
.commendation .byline { color: var(--turf); font-weight: 600; font-size: 0.9rem; margin: 0; }
.voices h2 { margin-bottom: 18px; }
