/*
Theme Name: Goody's Plumbing
Theme URI: https://itsallgoody.com
Author: Goody Family Company LLC
Description: Custom theme for Goody's Plumbing, San Antonio. Commercial-led with a high-end residential door, brand colors sampled from the logo, full-bleed photography of the company's own work. Redesigned 09/02/2026 in the "Pillars" direction: dark-dominant field, oversized slab-serif headlines, Zilla Slab over IBM Plex Sans.
Version: 2.0.0
Requires at least: 6.5
Requires PHP: 8.1
License: Proprietary
Text Domain: goodys
*/

/* ============================================================
   Brand colors sampled from the logo: red #ED1C24, blue #2B3990.
   The ground is the logo's ink pushed dark - never pure black - and red is
   spent once per section. Single committed visual world: every color is
   painted explicitly, nothing is left to a browser or OS default.
   Redesign 09/02/2026 ("Ledger" type direction, Harley's pick, Katie's
   sign-off): the mockup is mockups/homepage-ledger.html.
   ============================================================ */
:root{
  --paper:     #F8F7F4;
  --white:     #FFFFFF;
  --ink:       #151A2E;
  --well:      #0E1220;
  --well-soft: #1A2038;
  --blue:      #2B3990;
  --blue-deep: #1E2765;
  --red:       #ED1C24;
  --red-cta:   #CE1720;
  --muted:     #5A6072;
  --faint:     #8A90A0;
  --line:      #E3E2DD;
  --line-soft: #EDECE8;

  --on-well:       rgba(255,255,255,.94);
  --on-well-muted: rgba(255,255,255,.64);
  --on-well-faint: rgba(255,255,255,.36);
  --hairline:      rgba(255,255,255,.13);

  --wrap: 1240px;
  --wrap-wide: 1400px;
  --gut: clamp(1.25rem, 4vw, 3.5rem);

  --font-display: "Zilla Slab", "Rockwell", "Roboto Slab", Georgia, serif;
  --font-body:    "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;

  --fs-hero:  clamp(2.4rem, 6.8vw, 5.7rem);
  --fs-h2:    clamp(1.8rem, 4vw, 3.2rem);
  --fs-h3:    clamp(1.1rem, 1.6vw, 1.35rem);
  --fs-lead:  clamp(1.02rem, 1.4vw, 1.2rem);
  --fs-body:  1.0625rem;
  --fs-tag:   0.7rem;

  --ease: cubic-bezier(.22,.61,.36,1);
}

/* ---------- fonts, self-hosted ----------
   Latin subsets pulled once by tools/fetch_fonts.py and served from this
   domain. Nothing loads from Google at runtime: the privacy policy does not
   have to disclose it and the first paint is not waiting on a second host.
   Every stack names a real local fallback, so a face that fails to load
   still reads. functions.php preloads the two files the first paint needs. */
@font-face{
  font-family:"Zilla Slab"; font-style:normal; font-weight:600; font-display:swap;
  src:url(fonts/zilla-slab-600-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"Zilla Slab"; font-style:normal; font-weight:700; font-display:swap;
  src:url(fonts/zilla-slab-700-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"IBM Plex Sans"; font-style:normal; font-weight:400; font-display:swap;
  src:url(fonts/ibm-plex-sans-400-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"IBM Plex Sans"; font-style:normal; font-weight:500; font-display:swap;
  src:url(fonts/ibm-plex-sans-500-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"IBM Plex Sans"; font-style:normal; font-weight:600; font-display:swap;
  src:url(fonts/ibm-plex-sans-600-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}

*, *::before, *::after{ box-sizing: border-box; }

body{
  margin:0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

img{ display:block; max-width:100%; height:auto; }

/* Everything that reads as a label, a heading or a control is set in the slab. */
h1,h2,h3,.tag,.nav a,.btn,.plate dt,.spec span,.mark,.tel,.big-tel,
.door li,.door-li,.cbox dt,.foot small,.roll dt,.roll dd em,.field label,.formnote,
.entry h1,.entry h2,.entry h3,.notice,.eyebrow,.marq span,.step-n,.sector p,
.footnav a,.regnote,.callbar a,.quote{
  font-family: var(--font-display);
}

h1,h2,h3{
  margin:0; font-weight:700; text-transform:uppercase;
  letter-spacing:-.005em; line-height:1.0; text-wrap:balance;
}
p{ margin:0; }
a{ color: var(--blue); }

.wrap{ width:100%; max-width: var(--wrap); margin-inline:auto; padding-inline: var(--gut); }

/* Accessibility: skip link and screen-reader text, WordPress conventions. */
.screen-reader-text{
  border:0; clip-path: inset(50%); height:1px; margin:-1px; overflow:hidden;
  padding:0; position:absolute; width:1px; word-wrap:normal!important;
}
.skip-link{
  position:absolute; left:-9999px; z-index:999; padding:1em 1.5em;
  background: var(--ink); color:#FFF; text-decoration:none;
}
.skip-link:focus{ left:0; top:0; }

/* ---------- label ---------- */
.tag{
  display:inline-block;
  font-size: var(--fs-tag); font-weight:700;
  letter-spacing:.16em; text-transform:uppercase;
  color: var(--blue);
}
.tag.on-dark, .dark .tag, .page-head .tag, .band .tag, .close .tag{ color: var(--on-well-muted); }

/* ---------- eyebrow bar ---------- */
.eyebrow{
  background: var(--well); color: var(--on-well-muted);
  font-size:.68rem; font-weight:600; letter-spacing:.12em; text-transform:uppercase;
  border-bottom:1px solid var(--hairline);
}
.eyebrow .wrap{
  max-width: var(--wrap-wide);
  display:flex; align-items:center; justify-content:space-between; gap:1rem; min-height:36px;
}
.eyebrow .dot{ display:inline-block; width:7px; height:7px; margin-right:.55rem; background: var(--red); border-radius:50%; }
.eyebrow .right{ color: var(--on-well-faint); }
.eyebrow a{ color:inherit; text-decoration:none; }

/* ---------- header ---------- */
.site-header{
  position:sticky; top:0; z-index:50;
  background: rgba(21,26,46,.96);
  backdrop-filter: blur(8px);
  border-bottom:1px solid var(--hairline);
}
/* padding-BLOCK, not the `padding: .85rem 0` shorthand. The shorthand also sets
   padding-inline to 0, which silently canceled .wrap's side gutter and ran the
   whole header edge-to-edge on phones. It passed a scrollWidth==clientWidth
   check, because losing a gutter does not cause overflow - it was only found by
   measuring where the elements actually sat.

   flex-wrap is load-bearing, not cosmetic. At exactly 1099px innerWidth,
   `@media (max-width:1099px)` evaluates FALSE - sub-pixel layout width plus the
   scrollbar puts the real value just over - so the rule that hides the button
   does not fire and the button overflowed the viewport by 35px. Nudging the
   breakpoint only moves that dead band somewhere else. Allowing the row to wrap
   means nothing in the header can push past the edge at ANY width, and the
   breakpoints below become refinements rather than the only thing holding it. */
.bar{ display:flex; flex-wrap:wrap; align-items:center; gap: clamp(1rem,3vw,2.5rem); padding-block:.85rem; }

.mark{ display:flex; align-items:center; gap:.7rem; text-decoration:none; white-space:nowrap; line-height:1.05; }
.mark-text{ display:flex; flex-direction:column; }
/* The GP monogram, cut from the logo by tools/make_logo_assets.py. Height set
   here; the width attribute in header.php only reserves layout space. */
.mark-logo{ height:40px; width:auto; flex:none; }
.mark b{ font-weight:700; font-size:1.05rem; letter-spacing:.04em; text-transform:uppercase; color:#FFF; }
/* The apostrophe was red on the light header; on dark it read as a gap
   ("GOODY S"), so it inherits white now. */
.mark b i{ font-style:normal; color:inherit; }
.mark small{ font-size:.58rem; font-weight:600; letter-spacing:.2em; text-transform:uppercase; color: var(--on-well-faint); margin-top:.25rem; }

.nav{ display:flex; gap: clamp(.9rem,1.8vw,1.9rem); margin-left:auto; }
.nav ul{ display:flex; gap: clamp(.9rem,1.8vw,1.9rem); list-style:none; margin:0; padding:0; }
.nav a{
  font-size:.76rem; font-weight:600; letter-spacing:.11em; text-transform:uppercase;
  color: var(--on-well-muted); text-decoration:none; padding:.35rem 0;
  border-bottom:2px solid transparent;
  transition: color .18s var(--ease), border-color .18s var(--ease);
}
.nav a:hover, .nav a:focus-visible{ color:#FFF; border-bottom-color: var(--red); }
.nav .current-menu-item > a{ color:#FFF; border-bottom-color: var(--red); }

.tel{ font-size:.92rem; font-weight:700; letter-spacing:.02em; color:#FFF;
  text-decoration:none; white-space:nowrap; font-variant-numeric: tabular-nums; }
.tel small{ display:block; font-size:.58rem; font-weight:600; letter-spacing:.18em;
  text-transform:uppercase; color: var(--on-well-faint); }
.tel:hover{ color: var(--red); }

.btn{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:48px; padding:0 1.55em;
  font-size:.76rem; font-weight:700; letter-spacing:.13em; text-transform:uppercase;
  text-decoration:none; white-space:nowrap; border-radius:0;
  border:1px solid var(--red-cta); color:#FFF; background: var(--red-cta);
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.btn:hover, .btn:focus-visible{ background: var(--red); border-color: var(--red); }
.btn.ghost{ background:transparent; color: var(--blue-deep); border-color: #C3C6D4; }
.btn.ghost:hover, .btn.ghost:focus-visible{ border-color: var(--blue); color: var(--blue); background:transparent; }
.btn.on-dark, .dark .btn.ghost, .band .btn.ghost, .close .btn.ghost{
  background:transparent; color:#FFF; border-color: rgba(255,255,255,.4); }
.btn.on-dark:hover, .btn.on-dark:focus-visible,
.dark .btn.ghost:hover, .band .btn.ghost:hover, .close .btn.ghost:hover{
  background: rgba(255,255,255,.08); border-color:#FFF; color:#FFF; }
button.btn{ cursor:pointer; -webkit-appearance:none; appearance:none; }

:focus-visible{ outline:2px solid var(--red); outline-offset:3px; }
.dark :focus-visible, .site-header :focus-visible, .hero :focus-visible, .close :focus-visible{ outline-color:#FFF; }

/* Header fits at every width, or it gives the whole page a horizontal
   scrollbar. 1300, not 1100: Harley's tablet at ~1250px CSS width had the
   button wrapped under the logo (09/02/2026). Name + six nav items + phone +
   button need ~1300px of row; below that the button goes and the hero's own
   CTA carries. */
@media (max-width: 1299px){
  .bar .btn{ display:none; }
}
/* DESKTOP - Katie, 09/02/2026: "the red button is in a random place." Measured:
   the page column caps at --wrap (1240px, 1128px inside the gutters) and logo +
   six nav items + phone + button add up to ~1290px with the default gaps, so
   the button wrapped under the logo at EVERY width above 1300. The header row
   gets its own wider cap and tighter gaps; one row measured at 1300, 1366,
   1440 and 1920. */
@media (min-width: 1300px){
  .bar{ max-width: var(--wrap-wide); gap: clamp(1rem,1.8vw,1.75rem); }
  .nav, .nav ul{ gap: clamp(.9rem,1.3vw,1.4rem); }
}
/* PHONES AND SMALL TABLETS - measured on a 375px viewport, 09/02/2026:
   the sticky header was 149px tall (18% of the screen on every scroll), the
   nav had wrapped to two rows with CONTACT orphaned, nav links were 9.9px type
   on 24px targets. So below 900px:
   - the header scrolls away (the call bar at the bottom carries the phone),
   - the nav is ONE row that scrolls sideways, never wraps, 44px targets,
   - nothing in the header drops below 12px. */
@media (max-width: 899px){
  .site-header{ position:static; backdrop-filter:none; background: var(--ink); }
  .bar{ flex-wrap:wrap; row-gap:.35rem; padding-block:.7rem 0; }
  .nav{ order:3; width:100%; margin-left:0; border-top:1px solid var(--hairline); margin-top:.35rem;
    overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none;
    /* bleed the row to the screen edge so the last item can scroll fully in */
    margin-inline: calc(-1 * var(--gut)); padding-inline: var(--gut); width:auto; }
  .nav::-webkit-scrollbar{ display:none; }
  .nav ul{ width:max-content; flex-wrap:nowrap; justify-content:flex-start; gap:0 1.25rem; }
  .nav a{ display:inline-block; font-size:.78rem; letter-spacing:.06em; padding:.95rem 0; line-height:1; }
  .tel{ margin-left:auto; padding-block:.2rem; }
  .mark small, .tel small{ font-size:.72rem; letter-spacing:.12em; }
}
/* The eyebrow on a phone: "Bulverde, Texas" and the license number, one
   row. The service-area suffix and the words "Master Plumber" go; the RMP
   number stays visible in the header on every page, as the Texas
   advertising rule wants and as the old header did. Measured at 375px:
   the two together wrapped to a second line before this. */
@media (max-width: 620px){
  .eyebrow .sub{ display:none; }
}
@media (max-width: 430px){
  /* Mark + name + phone must share one row at 375px: 335px of row. Measured
     09/02/2026: the name alone is ~198px at .9rem/.09em, the phone ~101px.
     With a 32px mark and the gaps below the row comes in at ~325px. */
  .mark b{ font-size:.82rem; letter-spacing:.02em; }
  .mark small{ font-size:.66rem; letter-spacing:.05em; }
  .tel small{ display:none; }
  .mark{ gap:.5rem; }
  .mark-logo{ height:32px; }
  .bar{ gap:.75rem; }
  .tel{ font-size:.88rem; }
}
/* The rest of the mobile pass - type floor, tap targets, call bar - is at the
   END of this file on purpose. Same-specificity rules resolve by order, and
   the desktop sizes they override are defined further down than here. */

/* ---------- hero ---------- */
.hero{ position:relative; min-height: min(72vh, 680px); display:flex; align-items:center; overflow:hidden; background: var(--well); }
.hero-img,
.hero-video{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 62%; }
/* The video is a background, never a control: no pointer events, and it can
   never sit above the words. */
.hero-video{ z-index:0; pointer-events:none; background:var(--well); }
.hero::after{
  content:""; position:absolute; inset:0;
  background: linear-gradient(105deg,
    rgba(14,18,32,.94) 0%, rgba(14,18,32,.86) 42%, rgba(14,18,32,.55) 72%, rgba(14,18,32,.42) 100%);
}
.hero-body{ position:relative; z-index:2; width:100%; padding-block: clamp(3.4rem,8vw,6.4rem); }
.hero-body .wrap{ max-width: var(--wrap-wide); }
.hero h1{
  font-size: var(--fs-hero); letter-spacing:-.012em; line-height:1.0;
  color:#FFF; max-width:15ch; margin:1.1rem 0 0;
}
/* The accent line. display:block so it always starts its own line, which is
   the Pillars move: three lines of white, one of red. */
.hero h1 em{ font-style:normal; color: var(--red); display:block; }
.lead{ font-size: var(--fs-lead); color: var(--on-well-muted); max-width:52ch; margin:1.5rem 0 0; line-height:1.6; }
.cta{ display:flex; gap:.75rem; flex-wrap:wrap; margin-top:2.2rem; }

/* ---------- nameplate ----------
   Now the dark credentials strip directly under the hero. Where Pillars puts
   "$4B+ / 1M SF": Goody's has no such figures and will not invent any, so the
   slot carries what is checkable. Five cells. minmax(148px) so a ~830px
   tablet fits all five on one row; a 375px phone gets two columns. */
.plate{ background: var(--well); color: var(--on-well); border-bottom:1px solid var(--hairline); }
.plate .wrap{ display:grid; gap:0; grid-template-columns: repeat(auto-fit, minmax(148px,1fr)); }
@media (max-width: 430px){
  .plate .wrap{ grid-template-columns:1fr 1fr; }
  .plate div:nth-child(5){ grid-column:1 / -1; border-right:0; }
}
.plate div{ padding:1.5rem clamp(.75rem,2vw,1.6rem); border-right:1px solid var(--hairline); }
.plate div:last-child{ border-right:0; }
.plate dt{ font-size:.62rem; font-weight:600; letter-spacing:.16em; text-transform:uppercase;
  color: var(--on-well-faint); margin:0 0 .5rem; }
.plate dd{ margin:0; font-size:.98rem; line-height:1.35; color: var(--on-well); font-variant-numeric: tabular-nums; }
.plate dd b{ color:#FFF; font-weight:600; }
.plate a.lic{ color:#FFF; }

/* ---------- trade marquee ---------- */
.marq{ background: var(--ink); border-bottom:1px solid var(--hairline); overflow:hidden; padding-block:1rem; }
.marq-track{ display:flex; gap:3.2rem; width:max-content; animation: slide 42s linear infinite; }
.marq span{
  font-size: clamp(.9rem,1.7vw,1.3rem); font-weight:700; letter-spacing:.05em; text-transform:uppercase;
  color: var(--on-well-faint); white-space:nowrap; display:flex; align-items:center; gap:3.2rem;
}
.marq span::after{ content:""; width:7px; height:7px; background: var(--red); border-radius:50%; flex:none; }
@keyframes slide{ to{ transform: translateX(-50%); } }
/* A browser that asks for reduced motion (Windows with "show animations" off,
   iPhone with Reduce Motion on) gets no scroll - and a stopped marquee sits
   clipped mid-word, which reads as broken (a friend of Harley's saw exactly
   that, 09/03/2026). So the still state is its own layout: one set of the
   words, wrapped and centered, nothing cut off. The second set exists only
   to make the loop seamless, so it goes. */
@media (prefers-reduced-motion: reduce){
  .marq-track{ animation:none; width:auto; flex-wrap:wrap; justify-content:center; gap:.6rem 2.4rem; }
  .marq span{ gap:2.4rem; }
  .marq span:nth-child(n+8){ display:none; }
  .marq span:nth-child(7)::after{ display:none; }
}

/* ---------- sections ---------- */
section{ padding-block: clamp(3.6rem, 7vw, 6.4rem); }
.dark{ background: var(--ink); color: var(--on-well); }
.dark h2, .dark h3{ color:#FFF; }
.dark .head p{ color: var(--on-well-muted); }
.dark a{ color:#FFF; }

/* HEADINGS ARE CENTERED, SITEWIDE - Katie, 09/02/2026. Every h1, h2 and h3,
   plus the label and lead line in a title block. Body copy, bullet lists,
   cards' text, the rolls and the nameplate stay left. The one exception is
   the hero headline, which sits over a left-aligned lead and two buttons -
   Katie approved the exception. */
h1, h2, h3{ text-align:center; }
.hero h1{ text-align:left; }
.head{ max-width:64ch; margin-inline:auto; text-align:center; }
.head p{ margin-inline:auto; }
.page-head .wrap{ text-align:center; }
.band-body .tag{ align-self:center; }
/* A button that stands on its own row under a centered heading is centered
   too - Katie, 09/02/2026. The hero's two buttons stay left with the hero;
   the form's submit stays with the form. */
.band-body > div:last-child{ text-align:center; }
.entry p:has(> a.btn){ text-align:center; }
.head h2{ font-size: var(--fs-h2); color: var(--ink); margin:.9rem 0 0; }
.head p{ font-size: var(--fs-lead); color: var(--muted); margin:1.1rem 0 0; max-width:56ch; }
/* On a dark section the title block goes white. Declared AFTER .head h2 and
   with higher specificity, because `.dark h2` above ties with `.head h2` on
   specificity and lost on order - the heading painted ink on ink and vanished
   (caught live, 09/02/2026). */
.dark .head h2, #contact .head h2{ color:#FFF; }
.dark .head p, #contact .head p{ color: var(--on-well-muted); }

/* ---------- doors (dark tiles, on the homepage and the About page) ---------- */
.doors{ display:grid; gap:1px; background: var(--hairline); margin-top: clamp(2.2rem,4vw,3.4rem); border:1px solid var(--hairline); }
@media (min-width: 860px){ .doors{ grid-template-columns: repeat(3,1fr); } }
.door{ background: var(--ink); display:flex; flex-direction:column; transition: background .25s var(--ease); }
.door:hover{ background: var(--well-soft); }
.door figure{ margin:0; overflow:hidden; }
.door img{ width:100%; aspect-ratio: 16/10; object-fit:cover; transition: transform .7s var(--ease); }
.door:hover img{ transform: scale(1.04); }
.door-body{ padding: clamp(1.5rem,2.6vw,2.4rem); display:flex; flex-direction:column; gap:.9rem; flex:1; }
.door h3{ font-size: var(--fs-h3); color:#FFF; text-align:center; }
.door h3 a{ color:inherit; text-decoration:none; }
.door h3 a:hover{ text-decoration:underline; text-underline-offset:.15em; }
.door li a{ color:inherit; text-decoration:underline; text-underline-offset:.15em; }
.page-head .byline{ margin-top:.9rem; color: var(--on-well-muted); font-size:.92rem; }
.door p{ margin:0; color: var(--on-well-muted); font-size:.99rem; }
.door ul{ margin:.4rem 0 0; padding:0; list-style:none; border-top:1px solid var(--hairline); }
.door li, .door-li{
  font-size:.9rem; font-weight:600; letter-spacing:.01em; color: var(--on-well-muted);
  padding:.6rem 0 .6rem 1.05rem; position:relative; border-bottom:1px solid var(--hairline);
}
.door li::before, .door-li::before{ content:""; position:absolute; left:0; top:1.05em; width:5px; height:5px; background: var(--red); }
.door p a{ color:#FFF; }

/* ---------- feature band (gas on the homepage; the service pages) ---------- */
.band{ background: var(--well); color: var(--on-well); border-block:1px solid var(--hairline); }
.band-grid{ display:grid; gap:0; }
@media (min-width: 900px){ .band-grid{ grid-template-columns: 1.05fr 1fr; align-items:stretch; } }
.band-img{ width:100%; height:100%; min-height:340px; object-fit:cover; }
.band-body{ padding: clamp(2.5rem,5vw,4.5rem) var(--gut); display:flex; flex-direction:column; justify-content:center; gap:1.15rem; }
.band-body h2{ font-size: var(--fs-h2); color:#FFF; }
.band-body p{ margin:0; color: var(--on-well-muted); max-width:46ch; }
.band-body p.band-lead{ color: var(--on-well); font-size: var(--fs-lead); }
.band-body ul{ margin:.2rem 0 0; padding:0; list-style:none; border-top:1px solid var(--hairline); }
.band-body a{ color:#FFF; }

/* ---------- how a job runs ----------
   Numbered because it genuinely is a sequence: nothing downstream happens
   before the step above it. Not decoration. */
.steps{ display:grid; gap: clamp(1.6rem,3vw,2.6rem); grid-template-columns: repeat(auto-fit, minmax(230px,1fr)); margin-top: clamp(2.4rem,4vw,3.6rem); }
.step{ border-top:2px solid var(--ink); padding-top:1.2rem; }
/* Label and heading centered, body left - Katie's sitewide rule for cards
   (09/02/2026). The redesign shipped these left; brought in line 09/03/2026. */
.step-n{ display:block; text-align:center; font-size:.7rem; font-weight:700; letter-spacing:.16em; text-transform:uppercase; color: var(--red); }
.step h3{ font-size:1.05rem; margin-top:.75rem; color: var(--ink); }
.step p{ margin-top:.7rem; color: var(--muted); font-size:.99rem; }

/* ---------- work: the homepage cards ---------- */
.jobs{ display:grid; gap: clamp(1.2rem,2vw,1.6rem); grid-template-columns: repeat(auto-fit, minmax(250px,1fr)); margin-top: clamp(2.4rem,4vw,3.6rem); }
.job-card{ background: var(--white); border:1px solid var(--line); display:flex; flex-direction:column; }
.job-card figure{ margin:0; overflow:hidden; }
.job-card img{ width:100%; aspect-ratio:4/3; object-fit:cover; }
.job-card .job-meta{ padding:1.3rem clamp(1rem,1.6vw,1.4rem) 1.5rem; display:flex; flex-direction:column; gap:.8rem; flex:1; }
.job-card h3{ font-size:1.08rem; color: var(--ink); }
.job-card p{ margin:0; color: var(--muted); font-size:.96rem; flex:1; }

/* ---------- work: the projects page rows ---------- */
.job{ border-top:1px solid var(--line); padding-block: clamp(2rem,4vw,3.1rem); display:grid; gap: clamp(1.25rem,3vw,2.5rem); }
@media (min-width: 900px){ .job{ grid-template-columns: 1.15fr 1fr; align-items:center; } }
.job img{ width:100%; aspect-ratio:16/10; object-fit:cover; }
/* Portrait photos whose subject sits high or low in the frame. Every cropped
   image on the site is object-fit:cover, so these just move the window.
   focus-low  - 90% shows the bottom ~47% of a 3:4 source: the ejector basin,
                manifold and the risers running up out of it.
   focus-high - 33% keeps the rain head and its gooseneck arm in the top. */
img.focus-low{ object-position:50% 90%; }
img.focus-high{ object-position:50% 33%; }
.job .job-meta{ display:flex; flex-direction:column; gap:.85rem; }
.job .job-meta h3{ font-size: clamp(1.3rem,2.2vw,1.8rem); color: var(--ink); }
.job .job-meta p{ margin:0; color: var(--muted); }

/* Spec tags: the same chip on the homepage cards and the projects page. */
.spec{ display:flex; flex-wrap:wrap; gap:.4rem; }
.spec span{
  font-size:.62rem; font-weight:700; letter-spacing:.11em; text-transform:uppercase;
  color: var(--blue); background: var(--paper); border:1px solid var(--line); padding:.34rem .6rem;
}

/* ---------- rolling list of other projects ---------- */
.roll{ margin: clamp(2.4rem,4vw,3.4rem) 0 0; border-top:2px solid var(--ink); }
.roll-row{ display:grid; gap:.35rem 2rem; padding:1.15rem 0; border-bottom:1px solid var(--line); }
@media (min-width: 780px){ .roll-row{ grid-template-columns: 24ch 1fr 8ch; align-items:baseline; } }
/* Stacked (phones and small tablets) the roll reads like the photo cards
   above it: title and year center like the cards' titles, description left.
   Katie, 09/02/2026. */
@media (max-width: 779px){
  .roll dt, .roll dd:last-child{ text-align:center; }
}
.roll dt{ font-size:.88rem; font-weight:700; letter-spacing:.02em; text-transform:uppercase; color: var(--ink); margin:0; }
.roll dd{ margin:0; color: var(--muted); font-size:.98rem; }
.roll dd em{ font-style:normal; font-size:.72rem; font-weight:700; letter-spacing:.1em; color: var(--faint);
  text-transform:uppercase; font-variant-numeric: tabular-nums; }
.roll dt a{ color:inherit; }

/* ---------- photo grid ----------
   Used at the bottom of /projects/ as a dark band, and as a light strip
   inside a service page's .entry. A GRID, not a carousel: everything is
   visible at once, it needs no JavaScript, and nothing is hidden behind a
   control nobody presses. */
.shots{
  display:grid; gap:1px; grid-template-columns:repeat(auto-fit,minmax(250px,1fr));
  margin-top: clamp(2.2rem,4vw,3.2rem);
  background: var(--hairline); border:1px solid var(--hairline);
}
.shot{ background: var(--ink); margin:0; display:flex; flex-direction:column; }
.shot img{ width:100%; aspect-ratio:4/3; object-fit:cover; }
.shot figcaption{
  padding:1rem clamp(.9rem,1.6vw,1.25rem) 1.25rem;
  color: var(--on-well-muted); font-size:.95rem; line-height:1.5;
}
/* Photo sequences. "Every picture tells a story" (Harley, 09/03/2026): the
   grid is split into short groups that each say one thing, with a line of
   setup above. Headings and the setup line are centered, per Katie's sitewide
   rule; the captions inside the tiles stay left like other body copy.
   NOTE the h3 color is inherited from `.dark h2, .dark h3` declared ABOVE
   this - do not add a competing rule here, that is how the ink-on-ink
   heading bug happened on 09/02/2026. */
/* The FIRST story needs its own top margin too - a `.story + .story` rule
   alone leaves it crowded against the section intro. */
.story{ margin-top: clamp(2.6rem,4.5vw,3.6rem); }
.story + .story{ margin-top: clamp(3.4rem,6vw,5rem); }
.story > h3{ text-align:center; margin:0; font-size: clamp(1.35rem,2.2vw,1.75rem); }
.story > p{
  text-align:center; max-width:56ch; margin:.7rem auto 0;
  color: var(--on-well-muted);
}
.story .shots{ margin-top: clamp(1.4rem,2.5vw,2rem); }

/* On a paper section (the service pages) the same grid inverts. */
.entry .shots{ background: var(--line); border-color: var(--line); }
.entry .shot{ background: var(--white); }
.entry .shot figcaption{ color: var(--muted); }
.entry .shots img{ margin-block:0; }

/* ---------- sectors ---------- */
.sectors{ display:grid; gap:1px; grid-template-columns: repeat(auto-fit, minmax(210px,1fr)); margin-top: clamp(2.4rem,4vw,3.4rem); background: var(--hairline); border:1px solid var(--hairline); }
.sector{ background: var(--ink); padding:1.5rem 1.3rem; transition: background .25s var(--ease); }
.sector:hover{ background: var(--well-soft); }
.sector h3{ font-size:.95rem; letter-spacing:.01em; color:#FFF; }
.sector p{ margin-top:.5rem; text-align:center; font-size:.64rem; font-weight:600; letter-spacing:.11em; text-transform:uppercase; color: var(--on-well-faint); }

/* ---------- about ---------- */
.about{ background: var(--white); border-block:1px solid var(--line); }
.about-grid{ display:grid; gap: clamp(2rem,5vw,4rem); }
@media (min-width: 900px){ .about-grid{ grid-template-columns: 1fr 1fr; align-items:center; } }
.about p{ color: var(--muted); }
.about p.first{ color: var(--ink); font-size: var(--fs-lead); }
.about figure{ margin:0; }
.about figure img{ width:100%; aspect-ratio:4/5; object-fit:cover; }
.quote{ border-left:3px solid var(--red); padding-left:1.5rem; margin:1.75rem 0 0;
  font-weight:600; font-size: clamp(1.25rem,2.4vw,1.7rem); line-height:1.3; color: var(--ink); }

/* ---------- contact (dark closing section, homepage and Contact page) ---------- */
#contact{ background: var(--ink); color: var(--on-well); }
#contact .head p{ color: var(--on-well-muted); }
#contact h2{ color:#FFF; }
.contact-split{ display:grid; gap: clamp(2rem,4vw,3.5rem); margin-top: clamp(2rem,4vw,3rem); }
@media (min-width: 900px){ .contact-split{ grid-template-columns: 1.3fr 1fr; align-items:start; } }

.bidform{ background: var(--white); color: var(--ink); border:1px solid var(--line); padding: clamp(1.5rem,3vw,2.5rem); }
.fgrid{ display:grid; gap:1.15rem 1.25rem; }
@media (min-width: 620px){ .fgrid{ grid-template-columns:1fr 1fr; } }
.f-wide{ grid-column:1 / -1; }
.field{ display:flex; flex-direction:column; gap:.45rem; }
.field label{ font-size:.64rem; font-weight:700; letter-spacing:.16em; text-transform:uppercase; color: var(--muted); }
.field label i{ font-style:normal; color: var(--red); }
.field input, .field select, .field textarea{
  font-family: var(--font-body); font-size:1rem; color: var(--ink);
  background: var(--paper); border:1px solid var(--line); border-radius:0;
  padding:.72rem .85rem; width:100%; line-height:1.4;
}
.field select{ -webkit-appearance:none; appearance:none;
  background-image: linear-gradient(45deg, transparent 50%, #5A6072 50%), linear-gradient(135deg, #5A6072 50%, transparent 50%);
  background-position: calc(100% - 18px) 55%, calc(100% - 12px) 55%;
  background-size: 6px 6px, 6px 6px; background-repeat:no-repeat; padding-right:2.4rem; }
.field textarea{ min-height:6.5rem; resize:vertical; }
.field input:focus, .field select:focus, .field textarea:focus{ border-color: var(--blue); outline-color: var(--blue); }
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"]{ border-color: var(--red); }
.formfoot{ display:flex; gap:1.1rem; align-items:center; flex-wrap:wrap; margin-top:1.75rem; }
.formfoot .urgent{ font-size:.9rem; color: var(--muted); }
.formfoot .urgent a{ font-weight:600; text-decoration:none; border-bottom:1px solid var(--line); color: var(--blue-deep); }
.formnote{ font-size:.7rem; font-weight:600; letter-spacing:.12em; text-transform:uppercase; color: var(--faint);
  margin:1.4rem 0 0; padding-top:1.1rem; border-top:1px solid var(--line-soft); }
.bidform :focus-visible{ outline-color: var(--blue); }

/* The honeypot must be reachable by a bot and invisible to a person, without
   display:none - some bots skip fields that are display:none. */
.hp-field{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden; }

.notice{ padding:1rem 1.25rem; margin-bottom:1.75rem; font-size:.9rem; font-weight:600; letter-spacing:.01em;
  border-left:3px solid var(--blue); background: var(--paper); color: var(--ink); }
.notice.ok{ border-left-color:#1D7A4C; }
.notice.bad{ border-left-color: var(--red); }

.cstack{ display:grid; gap: clamp(1.6rem,3vw,2.3rem); }
.cbox dt{ font-size:.64rem; font-weight:700; letter-spacing:.16em; text-transform:uppercase;
  color: var(--on-well-faint); margin-bottom:.6rem; }
.cbox dd{ margin:0; color: var(--on-well-muted); }
.cbox dd a.mail{ color:#FFF; text-decoration:none; border-bottom:1px solid var(--hairline); word-break:break-word; }
.cbox dd a.mail:hover{ color: var(--red); border-bottom-color: var(--red); }
.big-tel{ font-weight:700; font-size: clamp(1.7rem,3.4vw,2.4rem); letter-spacing:-.01em;
  color:#FFF; text-decoration:none; font-variant-numeric: tabular-nums; }
.big-tel:hover{ color: var(--red); }

/* ---------- interior pages ---------- */
.page-head{ background: var(--well); color: var(--on-well); border-bottom:1px solid var(--hairline); padding-block: clamp(2.6rem,6vw,4.6rem); }
.page-head h1{ font-size: var(--fs-h2); color:#FFF; margin-top:.9rem; }
.entry{ max-width:68ch; }
.entry h2{ font-size: clamp(1.4rem,2.4vw,2rem); color: var(--ink); margin:2.6rem 0 0; }
.entry h3{ font-size: var(--fs-h3); color: var(--ink); margin:2rem 0 0; }
.entry p{ color: var(--muted); margin-top:1rem; }
.entry ul, .entry ol{ color: var(--muted); padding-left:1.2rem; margin-top:1rem; }
.entry li{ margin-bottom:.4rem; }
.entry img{ margin-block:2rem; }
.entry blockquote{ border-left:3px solid var(--red); padding-left:1.5rem; margin:1.5rem 0 0;
  color: var(--ink); font-size: var(--fs-lead); font-family: var(--font-display); font-weight:600; }
.entry .btn{ margin-top:.5rem; }

/* ---------- footer ---------- */
footer.site-footer{ border-top:1px solid var(--hairline); padding-block:2.6rem; background: var(--well); color: var(--on-well-faint); }
.footnav ul{ display:flex; flex-wrap:wrap; gap:.6rem 1.6rem; list-style:none; margin:0 0 1.75rem; padding:0 0 1.5rem;
  border-bottom:1px solid var(--hairline); }
.footnav a{ font-size:.7rem; font-weight:600; letter-spacing:.14em; text-transform:uppercase; color: var(--on-well-muted); text-decoration:none; }
.footnav a:hover, .footnav a:focus-visible{ color:#FFF; }
.regnote{ font-size:.7rem; letter-spacing:.03em; color: var(--on-well-faint);
  margin:1.5rem 0 0; padding-top:1.25rem; border-top:1px solid var(--hairline); line-height:1.6; }
.regnote a{ color: var(--on-well-muted); text-decoration:none; border-bottom:1px solid var(--hairline); }
.regnote a:hover{ color:#FFF; }

/* The license number links to the Board's verification page wherever it
   appears. Inherit color so each surface stays as designed; the dotted rule
   is the only tell that it is checkable. */
a.lic{ color:inherit; text-decoration:none; border-bottom:1px dotted currentColor; }
a.lic:hover, a.lic:focus-visible{ color: var(--red); border-bottom-style:solid; }
.foot{ display:flex; gap:1rem 2rem; flex-wrap:wrap; justify-content:space-between; align-items:center; }
.foot small{ color: var(--on-well-faint); font-size:.7rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase; }
.foot .slogan{ color: var(--red); font-weight:700; letter-spacing:.06em; }

/* ---------- motion ---------- */
/* Content is visible by default. Only a page that has confirmed working JS
   hides it to animate it in, so a failed observer can never blank a section. */
.rise{ opacity:1; transform:none; }
.js .rise{ opacity:0; transform: translateY(18px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.js .rise.in{ opacity:1; transform:none; }
@media (prefers-reduced-motion: reduce){
  .js .rise{ opacity:1; transform:none; transition:none; }
  .door img{ transition:none; }
  .door:hover img{ transform:none; }
  html{ scroll-behavior:auto; }
}
html{ scroll-behavior:smooth; }

/* ============================================================
   MOBILE PASS (09/02/2026). Kept at the end of the file: these override
   desktop rules of equal specificity, and the cascade resolves ties by
   source order. Measured on a 375px viewport before and after.
   ============================================================ */

/* ---------- type floor and tap targets ----------
   Nothing a person has to read drops below ~12.5px on a phone, and anything
   they have to tap is at least 44px tall. Desktop sizes are untouched. */
@media (max-width: 899px){
  .tag, .step-n{ font-size:.78rem; letter-spacing:.14em; }
  .plate dt, .cbox dt, .field label, .sector p{ font-size:.78rem; letter-spacing:.12em; }
  .spec span, .roll dd em, .foot small, .formnote, .eyebrow{ font-size:.78rem; }
  .door li, .door-li{ font-size:.9rem; }
  .footnav a, .regnote{ font-size:.8rem; }
  .footnav ul{ gap:.25rem 1.4rem; }
  .footnav a{ display:inline-block; padding:.7rem 0; }
  .btn{ font-size:.82rem; padding:0 1.5em; min-height:44px; }
  .notice{ font-size:.95rem; }
  .cbox dd a.mail{ display:inline-block; padding:.35rem 0; }
  .regnote a, .foot a{ display:inline-block; padding:.4rem 0; }
  .hero{ min-height:0; }
  .hero h1{ max-width:none; }

  /* Measured short on a 375px viewport, 09/03/2026 run-over: header phone
     link 30px, the big CALL number 33px, the bids@ link 40px, footer links
     43px, the logo link 32px. The two phone numbers are the most important
     taps on the page. All brought to the 44px floor. The line under the logo
     was 10.5px, under the 12.5px type floor - raised, not hidden. */
  .site-header .tel{ display:inline-flex; align-items:center; min-height:44px; }
  .site-header .mark{ min-height:44px; }
  .big-tel{ display:inline-block; min-height:44px; padding:.25rem 0; line-height:1.25; }
  .cbox dd a.mail{ padding:.55rem 0; }
  .footnav a{ padding:.8rem 0; }
  .mark small{ font-size:.78rem; }
}

/* ---------- call bar (phones only) ----------
   A fixed bar in the thumb zone: tap to call, or request a bid. This is where
   a plumber's mobile traffic converts; the header stopped being sticky to make
   room for it. The body gets bottom padding so the footer is never hidden
   under it. Hidden at 900px and up, where the header carries the phone. */
.callbar{ display:none; }
@media (max-width: 899px){
  .callbar{
    display:grid; grid-template-columns: 1fr 1fr; gap:1px;
    position:fixed; left:0; right:0; bottom:0; z-index:60;
    background: var(--hairline); border-top:1px solid var(--hairline);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .callbar a{
    display:flex; align-items:center; justify-content:center; gap:.5rem;
    min-height:56px; padding:.6rem .75rem; text-decoration:none;
    font-size:.82rem; font-weight:700; letter-spacing:.08em; text-transform:uppercase;
    font-variant-numeric: tabular-nums;
  }
  .callbar .call{ background: var(--well); color:#FFF; }
  .callbar .bid{ background: var(--red-cta); color:#FFF; }
  body{ padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
}
