/* Houston Duct Pros — 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). Figures are in the block at the end
   of this file, next to the palette they were computed against.

   The rationale behind these choices is recorded outside the web root — this
   stylesheet is served publicly, so it does not carry it.
*/

:root {
  /* Chrome: the jade the header, hero and CTA band sit on. Do not lighten —
     white on it is 4.63:1, which is the floor. */
  --plenum: #25836a;
  /* RGB channels of --plenum, for the hero photo scrim. Recompute both together. */
  --tint-over: 37, 131, 106;
  /* Mid tone: the light end of the hero gradient and the step-card tint. Never text. */
  --supply: #75c7b1;
  /* Accent: every call-to-action, and the body link color. */
  --draw: #176e62;
  /* Accent hover, and the footer ground — the chrome is too light for footer links. */
  --draw-deep: #11554c;
  /* Highlight: small-area only. Ink on it is 5.36:1. */
  --grille: #e8746a;
  --stock: #f4faf8;
  --clear: #ffffff;
  --script-c: #16261f;
  --dim: #4e6058;
  --keyline: #d6e6e0;
  --bevel: 6px;
  --column-w: 1176px;
  /* The fixed CTA bar's real height: 10+10 bar padding, 11+11 link padding,
     a 0.94rem line (24px) and 2px slack. One height at every width, so no
     media override. body's padding-bottom matches it. */
  --rail-h: 68px;
}

* { 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(--script-c);
  background: var(--stock);
  line-height: 1.6;
  padding-bottom: var(--rail-h);
}
img { max-width: 100%; display: block; }
a { color: var(--draw); text-decoration: none; }
a:hover { text-decoration: underline; }
.container { max-width: var(--column-w); margin: 0 auto; padding: 0 20px; }

/* Header */
header.bannerbar {
  background: var(--plenum);
  color: var(--clear);
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: 3px solid var(--grille);
}
header.bannerbar .shelf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 13px 20px;
  max-width: var(--column-w);
  margin: 0 auto;
  flex-wrap: wrap;
  gap: 10px;
}
header.bannerbar .masthead-name {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-weight: 700;
  font-size: 1.15rem;
  color: var(--clear);
  letter-spacing: 0.01em;
}
/* The second word of the wordmark takes a pale tint of the chrome hue: the
   accent against the chrome computes well under the 3:1 large-text floor. */
header.bannerbar .masthead-name span { color: #adebda; }
.cipher { width: 30px; height: 30px; border-radius: 50%; display: block; flex-shrink: 0; }
header.bannerbar nav { display: flex; gap: 18px; flex-wrap: wrap; }
header.bannerbar nav a { color: var(--clear); font-size: 0.95rem; }
header.bannerbar nav a:hover { color: #adebda; text-decoration: none; }
header.bannerbar .tel-action {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  background: var(--draw);
  color: var(--clear);
  padding: 9px 16px;
  border-radius: var(--bevel);
  font-weight: 700;
}
header.bannerbar .tel-action:hover { background: var(--draw-deep); text-decoration: none; }
/* 821-1060px: brand, nav and the phone number do not fit on one line. The
   nav takes its own centered row rather than the number shrinking. */
@media (min-width: 821px) and (max-width: 1060px) {
  header.bannerbar nav { order: 3; flex: 1 0 100%; justify-content: center; margin-top: 2px; }
}
@media (max-width: 820px) {
  header.bannerbar .shelf { justify-content: center; text-align: center; }
}

/* Hero. Inner pages sit on the chrome with the mid tone confined to a thin
   band along the bottom edge, so no copy ever lands on the light value. */
.frontispiece {
  background: var(--plenum);
  color: var(--clear);
  padding: 52px 20px 46px;
  border-bottom: 8px solid var(--supply);
}
.frontispiece .container { display: flex; flex-direction: column; gap: 16px; }
.frontispiece .supertitle {
  display: inline-block;
  border: 1px solid rgba(255,255,255,0.45);
  padding: 4px 12px;
  border-radius: 3px;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  width: fit-content;
}
.frontispiece h1 { font-size: 2.25rem; line-height: 1.18; margin: 0; max-width: 800px; }
.frontispiece p.chapeau { font-size: 1.1rem; color: var(--clear); max-width: 640px; margin: 0; }
.frontispiece .paths { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.frontispiece .undernote { font-size: 0.9rem; color: var(--clear); max-width: 680px; opacity: 0.92; }
/* The referral disclosure is a legal requirement, not decoration. Its own
   scrim keeps it conspicuous over any part of the hero photo. */
.frontispiece .plain-note {
  font-size: 0.9rem;
  color: var(--clear);
  max-width: 720px;
  background: rgba(var(--tint-over), 0.88);
  border-left: 4px solid var(--grille);
  padding: 12px 16px;
  border-radius: 4px;
  margin: 4px 0 0;
}
.frontispiece .plain-note strong { color: var(--clear); }

.tap {
  display: inline-block;
  padding: 13px 22px;
  border-radius: var(--bevel);
  font-weight: 700;
  font-size: 1rem;
}
.tap.anchor-btn { background: var(--draw); color: var(--clear); }
.tap.anchor-btn:hover { background: var(--draw-deep); text-decoration: none; }
.tap.muted-btn { background: transparent; color: var(--clear); border: 2px solid rgba(255,255,255,0.7); }
.tap.muted-btn:hover { background: rgba(255,255,255,0.14); text-decoration: none; }

/* Homepage hero: full-bleed photo with a left-to-right scrim so the H1 and
   lead sit on the quiet left side of the frame. */
.frontispiece.pictured {
  background-image:
    linear-gradient(90deg, rgba(var(--tint-over), 0.94) 0%, rgba(var(--tint-over), 0.80) 42%, rgba(var(--tint-over), 0.28) 72%, rgba(var(--tint-over), 0.05) 100%),
    url('/images/hero-ductpros-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) {
  .frontispiece.pictured {
    background-image:
      linear-gradient(180deg, rgba(var(--tint-over), 0.92) 0%, rgba(var(--tint-over), 0.84) 55%, rgba(var(--tint-over), 0.70) 100%),
      url('/images/hero-ductpros-photo-mobile.jpg');
    min-height: 470px;
  }
  .frontispiece h1 { font-size: 1.7rem; }
}

/* Sections */
section { padding: 46px 20px; }
section.inverse { background: var(--clear); border-top: 1px solid var(--keyline); border-bottom: 1px solid var(--keyline); }
.strapline-sm {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 0.78rem;
  color: var(--draw);
  font-weight: 700;
  margin-bottom: 6px;
}
h2 { font-size: 1.6rem; margin: 0 0 18px; color: var(--draw-deep); line-height: 1.25; }
h3 { font-size: 1.12rem; margin: 0 0 8px; color: var(--draw-deep); }
p.measure { max-width: 800px; }

/* The scope split — the block this site opens with, directly under the hero.
   Two columns: the cleaning this site covers, and the licensed system work it
   deliberately stops short of. It stands in for the usual trust strip. */
.scope-split { padding: 0 20px; margin-top: -30px; position: relative; z-index: 2; }
.scope-split .array { gap: 0; border-radius: var(--bevel); overflow: hidden; box-shadow: 0 6px 24px rgba(22,38,31,0.10); border: 1px solid var(--keyline); }
.scope-split .slab { border: 0; border-radius: 0; padding: 24px 26px; }
.scope-split .slab.covered { background: var(--clear); border-top: 6px solid var(--draw); }
.scope-split .slab.licensed { background: #fdf1ef; border-top: 6px solid var(--grille); }
.scope-split h2 { font-size: 1.2rem; margin-bottom: 8px; }
.scope-split ul { margin: 8px 0 0; padding-left: 18px; color: var(--dim); font-size: 0.95rem; }
.scope-split li { margin-bottom: 4px; }
.scope-split .scope-tag { display: inline-block; font-size: 0.74rem; letter-spacing: 0.06em; text-transform: uppercase; font-weight: 700; padding: 2px 8px; border-radius: 3px; margin-bottom: 8px; }
.scope-split .covered .scope-tag { background: #dff3ec; color: var(--draw-deep); }
.scope-split .licensed .scope-tag { background: var(--grille); color: var(--script-c); }

/* Grids and cards */
.array { display: grid; gap: 18px; }
.array.two-across { grid-template-columns: repeat(2, 1fr); }
.array.triplet { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .array.triplet { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) {
  .array.two-across, .array.triplet { grid-template-columns: 1fr; }
}
.slab {
  background: var(--clear);
  border: 1px solid var(--keyline);
  border-radius: var(--bevel);
  padding: 20px;
}
.slab p { color: var(--dim); margin: 6px 0 0; font-size: 0.95rem; }
.slab p:last-child { margin-bottom: 0; }
.slab.note { border-left: 4px solid var(--grille); }

/* How it works — four numbered stops on a rail, late on the page. */
.sequence {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  position: relative;
}
.milestone {
  background: #e4f4ee;
  border-radius: var(--bevel);
  padding: 20px 18px 18px;
  position: relative;
}
.milestone .leg-no {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background: var(--draw-deep);
  color: var(--clear);
  font-weight: 700;
  font-size: 0.95rem;
  margin-bottom: 10px;
}
.milestone h3 { font-size: 1rem; }
.milestone p { color: var(--dim); font-size: 0.92rem; margin: 0; }
@media (max-width: 900px) { .sequence { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .sequence { grid-template-columns: 1fr; } }

/* Coverage: the seven zones lead, the suburbs sit under each. */
.zone-list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px 28px; margin: 0; padding: 0; list-style: none; }
.zone-list > li { border-top: 2px solid var(--supply); padding-top: 12px; }
.zone-list h3 { margin-bottom: 4px; }
.zone-list h3 a { color: var(--draw-deep); }
.zone-list .zone-note { color: var(--dim); font-size: 0.9rem; margin: 0 0 10px; }
@media (max-width: 640px) { .zone-list { grid-template-columns: 1fr; } }
.reach { display: flex; flex-wrap: wrap; gap: 8px; }
.reach a {
  background: var(--clear);
  border: 1px solid var(--keyline);
  padding: 7px 12px;
  border-radius: 3px;
  color: var(--draw-deep);
  font-size: 0.9rem;
}
.reach a:hover { border-color: var(--draw); text-decoration: none; }
.reach span {
  padding: 7px 12px;
  border-radius: 3px;
  border: 1px dashed var(--keyline);
  color: var(--dim);
  font-size: 0.9rem;
}

/* FAQ — plain question/answer blocks in two columns on wide screens. */
.faq-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 36px; }
@media (max-width: 820px) { .faq-grid { grid-template-columns: 1fr; } }
.raised { border-top: 1px solid var(--keyline); padding: 16px 0 14px; }
.raised h3 { font-size: 1.04rem; margin-bottom: 6px; }
.raised p { margin: 0; color: var(--dim); }
.raised p + p { margin-top: 8px; }

/* Price table. The wrapper is required: a table's own overflow:hidden does
   not create a scroll context, so without it the document slides sideways
   on a phone. */
.sideways { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.cost-grid {
  width: 100%;
  min-width: 600px;
  border-collapse: collapse;
  background: var(--clear);
  border: 1px solid var(--keyline);
  font-size: 0.94rem;
}
.cost-grid caption { caption-side: bottom; text-align: left; color: var(--dim); font-size: 0.85rem; padding-top: 10px; }
.cost-grid th, .cost-grid td { padding: 11px 13px; text-align: left; border-bottom: 1px solid var(--keyline); vertical-align: top; }
.cost-grid thead th { background: #e4f4ee; color: var(--draw-deep); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
.cost-grid tbody tr:last-child td { border-bottom: none; }
.cost-grid td.amount { white-space: nowrap; font-weight: 700; color: var(--draw-deep); }

/* The estimator on the pricing page. */
.estimator { background: var(--clear); border: 1px solid var(--keyline); border-radius: var(--bevel); padding: 22px; }
.estimator .controls { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
@media (max-width: 720px) { .estimator .controls { grid-template-columns: 1fr; } }
.estimator label { display: block; font-size: 0.86rem; font-weight: 600; color: var(--draw-deep); margin-bottom: 4px; }
.estimator select, .estimator input { width: 100%; padding: 10px 11px; border: 1px solid var(--keyline); border-radius: 4px; font-size: 0.95rem; font-family: inherit; }
.estimator .readout { margin-top: 18px; padding: 16px 18px; background: #e4f4ee; border-radius: 4px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 560px) { .estimator .readout { grid-template-columns: 1fr; } }
.estimator .readout strong { display: block; font-size: 1.35rem; color: var(--draw-deep); }
.estimator .readout small { color: var(--dim); font-size: 0.82rem; }
.estimator .fine { color: var(--dim); font-size: 0.85rem; margin: 12px 0 0; }

/* CTA band */
.outro { background: var(--plenum); color: var(--clear); text-align: center; padding: 44px 20px; border-top: 8px solid var(--supply); }
.outro h2 { color: var(--clear); }
.outro p { color: var(--clear); margin-bottom: 18px; }

/* Contact form */
form.brief-form { display: grid; gap: 12px; max-width: 500px; }
form.brief-form label { font-size: 0.88rem; font-weight: 600; color: var(--draw-deep); display: block; margin-bottom: 4px; }
form.brief-form input, form.brief-form select, form.brief-form textarea {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--keyline);
  border-radius: 4px;
  font-size: 0.95rem;
  font-family: inherit;
  background: var(--clear);
}
form.brief-form .notice-line { font-size: 0.78rem; color: var(--dim); }
form.brief-form .extra-detail { position: absolute; left: -9999px; top: -9999px; }
form.brief-form button[disabled] { opacity: 0.6; cursor: not-allowed; }
.report-line { margin-top: 12px; padding: 11px 14px; border-radius: 4px; font-size: 0.9rem; display: none; }
.report-line.visible { display: block; }
.report-line.success { background: #dff3ec; color: #12564a; }
.report-line.error { background: #fdecea; color: #a8261e; }
.contact-split { display: grid; grid-template-columns: 1.15fr 0.85fr; gap: 36px; align-items: start; }
@media (max-width: 820px) { .contact-split { grid-template-columns: 1fr; } }

/* Breadcrumb */
.signpost { font-size: 0.85rem; color: var(--dim); padding: 14px 20px 0; max-width: var(--column-w); margin: 0 auto; }
.signpost a { color: var(--dim); }

/* Footer — on the deep accent, not the chrome: the chrome is too light for
   any tinted link to clear 4.5:1 on it. */
footer.bannerbar { background: var(--draw-deep); color: var(--clear); padding: 40px 20px 24px; font-size: 0.9rem; }
footer.bannerbar .container { display: grid; grid-template-columns: 2fr 1fr 1fr 1fr; gap: 24px; }
footer.bannerbar h2 { color: var(--clear); font-size: 0.95rem; margin: 0 0 10px; }
footer.bannerbar p { color: var(--clear); opacity: 0.92; margin: 0; }
footer.bannerbar ul { list-style: none; padding: 0; margin: 0; }
footer.bannerbar li { margin-bottom: 6px; }
footer.bannerbar a { color: #adebda; }
footer.bannerbar .undercarriage {
  max-width: var(--column-w);
  margin: 24px auto 0;
  padding-top: 18px;
  border-top: 1px solid rgba(255,255,255,0.14);
  font-size: 0.8rem;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
}
@media (max-width: 720px) { footer.bannerbar .container { grid-template-columns: 1fr 1fr; } }

.pending-value { background: #fdf1ef; color: #7a2a22; border: 1px dashed var(--grille); padding: 2px 6px; border-radius: 3px; font-size: 0.82em; }

/* Sticky CTA bar — visible at EVERY width (calls are the priority conversion) */
.undock {
  display: flex;
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 60;
  background: var(--draw-deep);
  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;
}
.standing-inner { display: flex; gap: 10px; width: 100%; max-width: var(--column-w); margin: 0 auto; }
.undock a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  white-space: nowrap;
  text-align: center;
  padding: 11px 10px;
  border-radius: 4px;
  font-weight: 700;
  font-size: 0.94rem;
}
.undock .receiver { flex: none; }
.fixedbar-call { flex: 3; background: var(--grille); color: var(--script-c); }
.fixedbar-ask { flex: 2; background: transparent; color: var(--clear); border: 1px solid rgba(255,255,255,0.5); }
.fixedbar-call:hover { background: #f08a80; text-decoration: none; }
.fixedbar-ask:hover { background: rgba(255,255,255,0.12); text-decoration: none; }
/* Narrow phones: the digits must survive, the qualifier is what gives way. */
.undock .rider { display: none; }
@media (min-width: 600px) { .undock .rider { display: inline; } }
@media (min-width: 721px) {
  .standing-inner { justify-content: center; }
  .undock a { flex: 0 0 auto; padding: 11px 22px; }
}

/* --- Work photos ------------------------------------------------------ */
/* One inline documentary shot dropped between two content sections partway
   down a service page. Not a gallery grid, not a CSS background, no captions.
   The base rule caps the width so an unclassed figure can never render
   full-bleed across the page — that failure looks correct in the markup, so
   the block ships before any page references the class. No orientation
   modifiers: every master is landscape 1200x800. */
.fieldshot { max-width: var(--column-w); margin: 0 auto; padding: 30px 20px; }
.fieldshot img {
  display: block;
  width: 100%;
  max-width: 800px;
  height: auto;
  margin: 0 auto;
  border-radius: var(--bevel);
  border: 1px solid var(--keyline);
}

/* --- Homepage work strip ---------------------------------------------- */
/* Thirteen thumbnails, one per service page, high on the page. Not links,
   not lightboxed. Thirteen does not tile evenly, so the first image is a
   double-width, double-height feature cell: 4 + 12 = 16 cells, four even
   rows of four on desktop; at two columns it spans one row, 14 cells, seven
   even rows. Re-do the arithmetic if the count ever changes. */
.runlet { padding-top: 40px; }
.runlet .previews { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; }
.runlet .previews img:first-child { grid-column: span 2; grid-row: span 2; }
.runlet 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: 3px;
  border: 1px solid var(--keyline);
  background: var(--clear);
}
@media (max-width: 900px) {
  .runlet .previews { grid-template-columns: repeat(2, 1fr); }
  .runlet .previews img:first-child { grid-column: span 2; grid-row: auto; }
}

/* --- Reviews ---------------------------------------------------------- */
/* Gated off server-side until real reviews exist. Styled anyway so the
   section does not appear unstyled on the day the flag is flipped. */
.remark .score-marks { color: var(--grille); letter-spacing: 0.12em; margin: 0 0 8px; }
.remark p { color: var(--dim); margin: 0 0 10px; }
.remark .attribution { color: var(--draw-deep); font-weight: 600; font-size: 0.9rem; margin: 0; }
.hearsay h2 { margin-bottom: 18px; }

/* Contrast figures, computed against the :root values above:
     --script-c on --stock ............................... 14.93:1
     --dim on --stock .............................. 6.33:1
     --dim on --clear ........................... 6.69:1
     white on --plenum (header, hero, cta band) ... 4.63:1
     white on --draw (buttons, call button) ....... 6.10:1
     white on --draw-deep (hover, footer, bar) .... 8.65:1
     --draw on --stock (links, section labels) ....... 5.77:1
     --draw on --clear ............................ 6.10:1
     --draw-deep on --stock (h2, h3) ................. 8.19:1
     --draw-deep on the #e4f4ee tint .............. 7.61:1
     brand span #adebda on --plenum ............... 3.46:1 (large text)
     footer links #adebda on --draw-deep .......... 6.46:1
     --script-c on --grille (sticky call button) ....... 5.36:1
     success text #12564a on #dff3ec .............. 7.40:1
     error text #a8261e on #fdecea ................ 6.20:1
   --supply is the light end of the hero border and the step tint's parent
   hue only. It sits under the 4.5:1 floor on every ground and never carries
   text. */
