/* ==========================================================================
   CACTUS STATE PLUMBING — THEME STYLESHEET
   ==========================================================================

   This file carries the approved design over directly. The design supplied
   its styling as inline style="" attributes on each element; those have been
   lifted into the named classes below without changing any value, because
   inline styles cannot carry media queries and the design needs a responsive
   layer that it did not itself specify.

   Read this file top to bottom:
     1. Tokens          — colours, fonts, spacing. The design's variables.
     2. Reset & base    — from the design system stylesheet.
     3. Layout          — page shell, sections, grids.
     4. Components      — buttons, tags, blueprint frames, image slots.
     5. Header & footer
     6. Responsive      — the mobile-first layer, authored for this build.
     7. Accessibility   — focus, reduced motion, skip link.

   WP Rocket minifies this in production. Do not minify it by hand.
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ==========================================================================
   Values below come from the design system stylesheet
   (_ds/industry-.../styles.css) with the page-level overrides that the
   approved design applied on top of it.

   THREE VALUES WERE ADJUSTED FOR ACCESSIBILITY. Each is marked "AA NUDGE"
   with the before/after contrast ratio. Nothing else was changed.
   ========================================================================== */

:root {
  /* --- Ground ------------------------------------------------------------ */
  --color-bg:      #f2f2f3;
  --color-surface: #e9e9ea;
  --color-text:    #1d1f20;
  --color-divider: color-mix(in srgb, #1d1f20 16%, transparent);

  /* --- Accent: the green ------------------------------------------------- */
  --color-accent:     #35806a;
  --color-accent-100: #e8f2ee;
  --color-accent-200: #cbe3da;
  --color-accent-300: #a6cfc1;
  --color-accent-400: #6fae9b;
  --color-accent-500: #3f8a74;
  --color-accent-600: #2f6f5e;
  --color-accent-700: #235445;
  --color-accent-800: #173d31;
  --color-accent-900: #0f2d24;

  /* --- Accent 2: the tan ------------------------------------------------- */
  --color-accent-2:     #bb8355;
  --color-accent-2-100: #f6ece3;
  --color-accent-2-200: #ecd7c4;
  --color-accent-2-300: #ddb99b;
  --color-accent-2-400: #c99b74;
  --color-accent-2-500: #bb8355;
  --color-accent-2-600: #a76d40;
  --color-accent-2-700: #855433;
  --color-accent-2-800: #5f3c25;
  --color-accent-2-900: #45291b;

  /* --- AA NUDGE #1 -------------------------------------------------------
     Interactive green, used for the primary button background and link
     hover. The design used --color-accent (#35806a), which gives 4.22:1
     against #f2f2f3 — below the 4.5:1 AA minimum for text under 18.66px.
     --color-accent-600 (#2f6f5e) gives 5.28:1 and is visually near-identical.
     ---------------------------------------------------------------------- */
  --color-interactive:       #2f6f5e;
  --color-interactive-hover: #235445; /* accent-700, 7.74:1 */

  /* --- Muted text ramps ---------------------------------------------------
     The design mixed the text colour with transparent at various percentages.
     These are those exact mixes, named so they stay consistent.

     AA NUDGE #2: the design used 60% for footer column headings and the
     copyright bar (4.25:1 — fails). The lowest step here is 65% (4.92:1),
     which the design already uses elsewhere. All 60% uses map to --text-soft.
     ---------------------------------------------------------------------- */
  --text-strong: color-mix(in srgb, var(--color-text) 82%, transparent); /*  8.62:1 */
  --text-body:   color-mix(in srgb, var(--color-text) 80%, transparent); /*  8.06:1 */
  --text-muted:  color-mix(in srgb, var(--color-text) 72%, transparent); /*  6.18:1 */
  --text-soft:   color-mix(in srgb, var(--color-text) 65%, transparent); /*  4.92:1 — AA floor */

  /* On the dark green sections, muted text is the background colour mixed
     down instead. All of these clear AA comfortably. */
  --text-on-dark:        color-mix(in srgb, var(--color-bg) 88%, transparent); /* 10.51:1 */
  --text-on-dark-muted:  color-mix(in srgb, var(--color-bg) 82%, transparent); /*  9.36:1 */
  --text-on-dark-soft:   color-mix(in srgb, var(--color-bg) 72%, transparent); /*  7.53:1 */

  /* --- Body type ----------------------------------------------------------
     Raised across the board from the design's 15px base. This customer base
     skews older homeowners, and the site gets read on a phone in a bad
     situation — a burst line, no hot water, standing water. Erring large is
     the right error to make here.

     The DISPLAY scale is deliberately untouched: headings still carry the
     design's own clamp() values, in section 4.
     ---------------------------------------------------------------------- */
  --text-base: clamp(16.5px, 0.35vw + 15.4px, 18px);   /* was a flat 15px */
  --text-lead: clamp(18px, 0.5vw + 16.4px, 20px);      /* was a flat 17px */
  --text-sm:   clamp(14.5px, 0.3vw + 13.5px, 15.5px);  /* was a flat 13px */

  /* --- Buttons ------------------------------------------------------------
     Sized so every button clears the 44px minimum tap target on its own,
     without relying on a min-height to prop it up: 16px text at line-height
     1.2 is 19.2px, plus 13px padding top and bottom, plus 2px of border.
     ---------------------------------------------------------------------- */
  --btn-font:  clamp(15.5px, 0.3vw + 14.5px, 17px);    /* was a flat 14px */
  --btn-pad-y: 13px;                                    /* was 6.8px */
  --btn-pad-x: 22px;                                    /* was 12.24px */

  /* --- Type -------------------------------------------------------------- */
  --font-heading: "Barlow Condensed", system-ui, -apple-system, sans-serif;
  --font-heading-weight: 600;
  --font-body: "Barlow", system-ui, -apple-system, sans-serif;

  /* --- Spacing ----------------------------------------------------------- */
  --space-1: 3.4px;
  --space-2: 6.8px;
  --space-3: 10.2px;
  --space-4: 13.6px;
  --space-6: 20.4px;
  --space-8: 27.2px;

  /* --- Layout -------------------------------------------------------------
     The design's container: max 1200px with a fluid gutter that runs from
     20px on a phone to 72px on a wide screen. */
  --container:  1200px;
  --container-narrow: 900px;
  --gutter: clamp(20px, 5vw, 72px);

  /* Vertical rhythm, taken from the design's repeated clamp() values. */
  --section-y:       clamp(44px, 6vw, 80px);
  --section-y-large: clamp(48px, 6vw, 88px);

  /* --- Form states --------------------------------------------------------
     The design has no form artboard, so these are derived rather than taken:
     a brick red that sits in the same desert family as --color-accent-2
     instead of a generic browser red, and the existing accent for success.

     #9c3b28 on --color-bg (#f2f2f3) measures 6.05:1, so error text clears AA
     at body size and AAA at large. The tinted backgrounds are light enough
     that --color-text still clears AA on top of them.
     ---------------------------------------------------------------------- */
  --color-error:    #9c3b28;
  --color-error-bg: #fbeeea;
  --color-success:    var(--color-accent-700);
  --color-success-bg: var(--color-accent-100);

  /* --- Shape ------------------------------------------------------------- */
  /* The design system sets every component to square corners: the whole look
     is wireframe / blueprint. Radius tokens exist but resolve to 0. */
  --radius-sm: 0;
  --radius-md: 0;
  --radius-lg: 0;

  /* Minimum tap target. Referenced rather than repeated. */
  --tap: 44px;
}


/* ==========================================================================
   2. FONTS — self-hosted
   ==========================================================================
   No request goes to Google. The files sit in assets/fonts.
   font-display:swap shows the fallback immediately and swaps when the webfont
   lands, which avoids invisible text on a slow connection.
   ========================================================================== */

@font-face {
  font-family: "Barlow";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/barlow-400.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: "Barlow";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/barlow-500.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: "Barlow";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/barlow-700.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: "Barlow Condensed";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/barlow-condensed-400.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: "Barlow Condensed";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/barlow-condensed-600.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;
}


/* ==========================================================================
   3. RESET & BASE
   ==========================================================================
   Carried from the design system stylesheet.
   ========================================================================== */

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

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.6;
  font-weight: 400;
  text-wrap: pretty;
  /* Belt and braces against horizontal scroll at any width. The responsive
     rules below are what actually prevent it; this catches anything missed. */
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 var(--space-2);
}

p { margin: 0 0 var(--space-3); }
p:last-child { margin-bottom: 0; }

a { color: var(--color-accent-700); text-underline-offset: 3px; }
a:hover { color: var(--color-interactive-hover); } /* AA NUDGE #1 */

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

/* Uppercase heading treatment used throughout the design. */
.u-caps {
  text-transform: uppercase;
  letter-spacing: 0.01em;
}

/* The small uppercase label above most headings. */
.eyebrow {
  display: block;
  font-family: var(--font-heading);
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  font-weight: 600;
  margin: 0 0 12px;
}
.eyebrow--hero {
  display: inline-block;
  letter-spacing: 0.16em;
  margin-bottom: 18px;
}
.eyebrow--on-dark { color: var(--color-accent-2-400); }

/* The hairline rule under an eyebrow. */
.rule {
  height: 1px;
  border: 0;
  background: var(--color-divider);
  margin: 0 0 30px;
}

.text-muted { color: var(--text-muted); }
.text-soft  { color: var(--text-soft); }


/* ==========================================================================
   4. LAYOUT
   ========================================================================== */

/* The centred content column used by every section in the design. */
.container {
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: var(--container-narrow); }
.container--mid    { max-width: 1000px; }

.section        { padding-block: var(--section-y); }
.section--large { padding-block: var(--section-y-large); }
.section--edge  { border-bottom: 1px solid var(--color-divider); }

/* The dark green full-bleed band. */
.section--dark {
  background: var(--color-accent-900);
  color: var(--color-bg);
}
.section--dark a { color: var(--color-accent-2-300); }
.section--dark .rule { background: color-mix(in srgb, var(--color-bg) 22%, transparent); }

/* --- The same band, with a photograph under the green --------------------
   Added to a .section--dark ONLY when a photo has actually been uploaded, so
   with no photo none of this exists and the band is the flat green above.

   The band stays full-bleed. No border, no radius, no shadow: the only thing
   that changes is what is underneath the green.

   CONTRAST
   --------
   The overlay runs 82% in the middle to 90% at the edges. That ceiling is not
   a taste decision. Every text colour in this file has a measured ratio
   against flat --color-accent-900, and a photograph showing through would
   lift the background and drop all of them. These are the worst-case figures,
   measured over a PURE WHITE photograph, where the band reads #3a524b:

     --text-on-dark       6.22:1
     --text-on-dark-soft  4.78:1   <- the lightest type used on these bands

   Both clear AA. Do not go lighter without recomputing: at 80% the soft token
   lands on 4.53:1, which passes with no margin at all, and anything past that
   breaks the promises made in section 3. The real photograph is mid-toned, so
   the live figures are better than these — but the ceiling is set by the
   worst case, not the likely one.

   The radial shape is also the "subtle vignette": darkest where the band
   meets the page, which both adds depth and protects the section's edges.
   -------------------------------------------------------------------------- */
.section--photo { position: relative; isolation: isolate; }

.section--photo > .band-photo {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.section--photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: radial-gradient(
    120% 100% at 50% 50%,
    color-mix(in srgb, var(--color-accent-900) 82%, transparent) 0%,
    color-mix(in srgb, var(--color-accent-900) 90%, transparent) 100%
  );
}


/* ==========================================================================
   5. COMPONENTS
   ========================================================================== */

/* --- Buttons -------------------------------------------------------------
   From the design system, with the blueprint override that squares the
   corners and adds the hairline border. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 15px;
  line-height: 1.2;
  color: var(--color-text);
  background: transparent;
  border: 1px solid var(--color-divider);
  border-radius: 0;
  /* Padding is set so the button clears the 44px minimum tap target without
     changing the design's visual proportions. */
  padding: 12px 20px;
  min-height: var(--tap);
}
.btn:disabled { opacity: 0.45; cursor: not-allowed; }

.btn-primary {
  background: var(--color-interactive);       /* AA NUDGE #1 */
  border-color: var(--color-interactive);
  color: var(--color-bg);
}
.btn-primary:hover,
.btn-primary:focus-visible {
  background: var(--color-interactive-hover);
  border-color: var(--color-interactive-hover);
  color: var(--color-bg);
}

.btn-secondary { border-color: var(--color-divider); color: var(--color-text); }
.btn-secondary:hover { background: color-mix(in srgb, var(--color-text) 7%, transparent); }

/* On the dark band the secondary button needs a light outline instead. */
.section--dark .btn-secondary {
  border-color: color-mix(in srgb, var(--color-bg) 45%, transparent);
  color: var(--color-bg);
}
.section--dark .btn-secondary:hover {
  background: color-mix(in srgb, var(--color-bg) 12%, transparent);
}

/* The inline "View service page →" text link. */
.btn-inline {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  align-self: flex-start;
  background: none;
  border: 0;
  padding: 10px 0;          /* Vertical padding gives it a 44px tap height. */
  min-height: var(--tap);
  cursor: pointer;
  font-family: var(--font-heading);
  font-size: var(--btn-font);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  font-weight: 600;
  text-decoration: none;
}
.btn-inline:hover { color: var(--color-interactive-hover); text-decoration: underline; }

.csp-icon { display: block; flex: none; }


/* --- Tags ---------------------------------------------------------------- */
.tag {
  display: inline-flex;
  align-items: center;
  font-size: var(--text-sm);
  letter-spacing: 0.02em;
  padding: 5px 10px;
  border-radius: 0;
}
.tag-accent  { background: var(--color-accent-100); color: var(--color-accent-800); }
.tag-outline { border: 1px solid var(--color-accent-700); color: var(--color-accent-700); }


/* --- Blueprint frame -----------------------------------------------------
   The registration-mark corners that give the design its drafting-table
   character. Carried over from the design system exactly. */
.blueprint {
  position: relative;
  border: 1px solid var(--color-divider);
  border-radius: 0;
}
.blueprint > .corner {
  position: absolute;
  width: 11px;
  height: 11px;
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.blueprint > .corner::before,
.blueprint > .corner::after { content: ""; position: absolute; background: currentColor; }
.blueprint > .corner::before { left: 5px; top: 0; width: 1px; height: 100%; }
.blueprint > .corner::after  { top: 5px; left: 0; width: 100%; height: 1px; }
.blueprint > .corner.tl { top: -6px; left: -6px; }
.blueprint > .corner.tr { top: -6px; right: -6px; }
.blueprint > .corner.bl { bottom: -6px; left: -6px; }
.blueprint > .corner.br { bottom: -6px; right: -6px; }

/* On the dark band the corner marks need to be light to stay visible. */
.section--dark .blueprint { border-color: color-mix(in srgb, var(--color-bg) 26%, transparent); }
.section--dark .blueprint > .corner { color: color-mix(in srgb, var(--color-bg) 60%, transparent); }

/* --- The duotone wash: REMOVED ------------------------------------------
   The approved design put a green colour wash over every photograph — an
   ::after layer filled with --color-accent at mix-blend-mode: color, which
   replaces each image's own hue with the brand green. Owner's instruction on
   2026-08-27 was to take it off: photographs render with their own colour.

   This is a deliberate departure from the approved artboards, which is why it
   is recorded here rather than quietly deleted. design-reference/ still shows
   the wash, because that folder is the record of what was approved and is not
   edited.

   The .duotone class is left on the markup. It matches the design reference
   and costs nothing, and if the wash is ever wanted back it goes here.

   Nothing structural is lost with these rules gone: every use of .duotone in
   this theme is .blueprint.duotone, which already set overflow: visible, and
   .blueprint supplies the position: relative the corner marks need. The child
   overflow rules existed only to clip the wash to the image box.
   ------------------------------------------------------------------------- */


/* --- Unfilled image placeholder ------------------------------------------
   Deliberately loud. This is not a neutral grey box that can survive to
   launch unnoticed — it is hazard striping and a caps warning, sized to be
   legible in a screenshot. inc/helpers.php explains the reasoning; the Launch
   Readiness screen counts every one of these.
   -------------------------------------------------------------------------- */
.csp-image-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 20px;
  text-align: center;
  border: 2px dashed color-mix(in srgb, var(--color-text) 45%, transparent);
  color: var(--text-muted);

  /* Diagonal hazard striping, drawn in CSS so it costs no request and scales
     to any slot size. */
  background-color: var(--color-surface);
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 14px,
    color-mix(in srgb, var(--color-text) 7%, transparent) 14px 28px
  );
}

.csp-image-slot__flag {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: clamp(13px, 1.6vw, 17px);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 1.2;
  padding: 7px 14px;
  color: var(--color-bg);
  background: var(--color-text);
}

.csp-image-slot__label {
  font-size: var(--text-sm);
  line-height: 1.4;
  max-width: 34ch;
}

/* On the dark band the placeholder inverts so it stays just as loud. */
.section--dark .csp-image-slot {
  border-color: color-mix(in srgb, var(--color-bg) 55%, transparent);
  color: var(--text-on-dark-soft);
  background-color: color-mix(in srgb, var(--color-bg) 8%, transparent);
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 14px,
    color-mix(in srgb, var(--color-bg) 10%, transparent) 14px 28px
  );
}
.section--dark .csp-image-slot__flag {
  color: var(--color-accent-900);
  background: var(--color-bg);
}

/* The wash that this rule used to switch off over a placeholder is gone —
   see "The duotone wash: REMOVED" above. */


/* --- FAQ accordion -------------------------------------------------------
   Uses native <details>/<summary>, so it works with no JavaScript and is
   keyboard accessible for free. */
.faq-item {
  border-top: 1px solid var(--color-divider);
  padding: 18px 0;
}
.faq-item:last-of-type { border-bottom: 1px solid var(--color-divider); }

.faq-item > summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  list-style: none;
  cursor: pointer;
  font-family: var(--font-heading);
  font-size: clamp(17px, 2.2vw, 20px);
  letter-spacing: 0.01em;
  text-transform: uppercase;
  min-height: var(--tap);
}
.faq-item > summary::-webkit-details-marker { display: none; }

.faq-plus {
  flex: none;
  color: var(--color-interactive);
  font-size: 24px;
  line-height: 1;
  transition: transform 0.2s;
}
.faq-item[open] .faq-plus { transform: rotate(45deg); }

.faq-item__answer {
  font-size: 15px;
  line-height: 1.6;
  margin: 14px 0 0;
  color: var(--text-body);
}


/* --- Heading scale -------------------------------------------------------
   The approved design sets every heading size inline, per instance. Those
   exact values live here instead, so no template carries a style attribute.
   The four section modifiers are the four sizes the design actually uses —
   they look nearly identical but they are not, so they are kept apart rather
   than averaged into one.
   -------------------------------------------------------------------------- */
.h-hero {
  font-size: clamp(38px, 5.2vw, 66px);
  line-height: 1.0;
  letter-spacing: 0.01em;
  margin: 0;
}

/* Service and city pages: one step down from the home page hero. */
.h-page {
  font-size: clamp(36px, 4.8vw, 60px);
  line-height: 1.0;
  letter-spacing: 0.01em;
  margin: 0;
}

.h-section {
  font-size: clamp(26px, 3.2vw, 40px);
  line-height: 1.03;
  letter-spacing: 0.01em;
  margin: 0;
}
.h-section--services { font-size: clamp(28px, 3.6vw, 42px); line-height: 1.02; margin: 0 0 34px; max-width: 20ch; }
.h-section--about    { font-size: clamp(26px, 3.2vw, 38px); line-height: 1.05; margin: 0 0 22px; }
.h-section--faq      { margin: 0 0 26px; }
.h-section--cta      { font-size: clamp(26px, 3.4vw, 42px); line-height: 1.02; }

.h-card {
  font-size: 22px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  margin: 0;
}


/* --- Hero ----------------------------------------------------------------- */

/* The text column of a hero. The figure beside it carries its own margin. */
.hero-col { padding-block: clamp(44px, 6vw, 80px); }

/* --- Tagline -------------------------------------------------------------
   The brand line, between the headline and the lead. It is set in the
   heading face at a size below the h1 and above the lead, so it reads as a
   second line of the headline rather than as the start of the body copy.
   Sentence case, not uppercase: the h1 above it is already uppercase, and
   two uppercase blocks stacked lose the hierarchy between them.
   -------------------------------------------------------------------------- */
.hero-tagline {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: clamp(20px, 2.2vw, 26px);
  line-height: 1.15;
  letter-spacing: 0.01em;
  margin: 14px 0 0;
  color: var(--color-accent-700);
}

.hero-lead {
  font-size: var(--text-lead);
  line-height: 1.6;
  max-width: 52ch;
  margin: 22px 0 0;
  color: var(--text-strong);
}

/* The row of buttons under the hero copy, and the row of chips under those. */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 30px;
}
/* The same row inside the closing CTA band, where the 30px top margin the
   hero needs would push the buttons out of line with the heading beside
   them — the band centres its children instead of stacking them. */
.btn-row--cta { margin-top: 0; }
.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 26px;
}

/* The design specifies four chips in a plain wrapping row and no maximum. At
   the design's own 1280px preview they fit on one line; in the two-column
   hero between roughly 900px and 1200px the fourth drops alone, leaving a
   3 + 1 orphan.
   In that band only, lay them out two-up so the wrap is even. Above and below
   it the design's own flex row is untouched. */
@media (min-width: 900px) and (max-width: 1200px) {
  .tag-row {
    display: grid;
    grid-template-columns: repeat(2, auto);
    justify-content: start;
    justify-items: start;
  }
}


/* --- Header request button -----------------------------------------------
   The call button stays at every width — it is the conversion. The request
   button is hidden below the nav breakpoint, where the sticky bottom bar
   already offers both actions and the header has no room for a second one.
   -------------------------------------------------------------------------- */
@media (max-width: 899px) {
  .header-request { display: none; }
}


/* --- Breadcrumb ----------------------------------------------------------
   Marked up as an <ol> so it announces itself correctly, which means the list
   defaults have to be turned off explicitly: without list-style:none and the
   padding reset it renders as a numbered, vertically stacked list.
   -------------------------------------------------------------------------- */
.breadcrumb { padding: 18px 0 0; }

.breadcrumb ol {
  list-style: none;      /* kills the "1. 2. 3." markers */
  margin: 0;
  padding: 0;            /* kills the indent the markers left behind */

  display: flex;
  flex-wrap: wrap;       /* on a phone it wraps to a second line, not a column */
  align-items: baseline;
  row-gap: 4px;

  font-family: var(--font-heading);
  font-size: var(--text-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-soft);
}

/* Each crumb is inline, so a wrap breaks between crumbs rather than stacking
   every one of them. */
.breadcrumb li {
  display: inline-flex;
  align-items: baseline;
}

.breadcrumb a {
  color: var(--color-accent-700);
  text-decoration: none;
}
.breadcrumb a:hover,
.breadcrumb a:focus-visible {
  color: var(--color-interactive-hover);
  text-decoration: underline;
}

.breadcrumb__sep {
  margin: 0 8px;
  color: var(--text-soft);
}

/* The current page is the last crumb and is not a link. */
.breadcrumb [aria-current="page"] { color: var(--text-muted); }


/* --- Inner page head ------------------------------------------------------
   The eyebrow / heading / intro block that opens the services and service
   pages, under the breadcrumb.
   -------------------------------------------------------------------------- */
.page-head {
  padding: clamp(32px, 4vw, 52px) 0 clamp(36px, 4vw, 56px);
  max-width: 760px;
}


/* --- Framed figure -------------------------------------------------------
   The blueprint photo frame used in the hero, the about section and the
   service-area map. The design's green wash over the photograph was removed
   on the owner's instruction — see "The duotone wash: REMOVED" above.
   -------------------------------------------------------------------------- */
.figure-frame { margin-block: clamp(24px, 4vw, 56px); }

/* In the service-area grid the figure sits flush with the top of the column. */
.figure-frame--flush { margin: 0; }

/* --- Matted figure -------------------------------------------------------
   A figure that sits ON a photographic band rather than on the page. Today
   that is exactly one image on the whole site — the about-band portrait on
   the home page — but this is written as a rule rather than a one-off so a
   band that gains an image later behaves correctly without new CSS.

   The white matte does the job the blueprint corner ticks do everywhere else:
   separate the photograph from its ground. On a desert photo the ticks would
   be light-on-busy at 60% opacity and simply disappear, and stacking a matte
   AND ticks is fussy, so template-parts/figure-frame.php drops the ticks for
   this variant. Corners stay hard, like everything else in this design.

   The matte is pure white, not --color-bg. Against the off-white page an
   off-white border would read as a gap; against a photograph a white one
   reads as a mount.

   WHY THE SELECTOR CARRIES .blueprint
   -----------------------------------
   Because ".section--dark .blueprint" further up this file repaints the
   frame's border-color to --color-bg at 26% alpha — nearly transparent, which
   is right for a hairline on flat green and completely wrong for a 10px
   mount. Two classes beats one, so a plain ".figure-frame--matte" LOSES that
   fight and the mount renders as a washed-out band with the overlay and the
   photograph showing straight through it. Adding .blueprint here matches that
   rule's specificity, and this block sits later in the file, so it wins.
   Do not simplify this selector back to one class.
   -------------------------------------------------------------------------- */
.figure-frame--matte.blueprint {
  position: relative;
  border: 10px solid #fff;
}

/* The subtle vignette: depth on the photograph itself, inside the mount. */
.figure-frame--matte::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 56px 8px color-mix(in srgb, #1d1f20 26%, transparent);
}


/* --- Facts panel ---------------------------------------------------------
   The bordered table of business facts under the home page hero. Every cell
   is optional: a fact with no value in Business Info is not rendered, and the
   grid closes up around it.
   -------------------------------------------------------------------------- */
.facts-panel { padding: 0; }

.facts-panel__head {
  display: flex;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--color-divider);
}
.facts-panel__title,
.facts-panel__meta {
  padding: 12px 22px;
  font-family: var(--font-heading);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.facts-panel__title {
  flex: 1;
  min-width: 16ch;
  font-weight: 600;
}
.facts-panel__meta {
  border-left: 1px solid var(--color-divider);
  color: var(--text-soft);
}

.fact {
  padding: 22px;
  border-right: 1px solid var(--color-divider);
  border-bottom: 1px solid var(--color-divider);
}

/* The right-hand cell of each row has no border to double up with the frame.
   Which cell that is changes with the column count, so it is set per
   breakpoint alongside the grid itself, at the bottom of section 9. */

.fact__label {
  font-family: var(--font-heading);
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  margin-bottom: 8px;
}
.fact__value {
  font-size: var(--text-base);
  line-height: 1.5;
  /* A fact cell is a third of the container at most. "pre-arranged" and
     similar long hyphenated strings must wrap inside it rather than run out
     of the box. */
  overflow-wrap: break-word;
  hyphens: manual;
}

/* Each line of a multi-line value sits on its own row. The line break comes
   from the element, not from a <br> in the stored value. */
.fact__note + .fact__note { margin-top: 2px; }
.fact__note  { color: var(--text-soft); }

/* The phone number is the one fact rendered at display size. */
.fact__value--phone {
  font-family: var(--font-heading);
  font-size: 26px;
  letter-spacing: 0.01em;
  text-decoration: none;
  color: var(--color-text);
}
.fact__value--phone:hover { color: var(--color-interactive-hover); }


/* --- Service card --------------------------------------------------------- */
.svc-card {
  padding: 24px;
  display: flex;
  flex-direction: column;
}
.svc-card__text {
  font-size: var(--text-base);
  line-height: 1.55;
  margin: 14px 0 0;
  color: var(--text-body);
}
/* The "View service page" link is pushed to the foot of the card so the links
   line up across a row of cards of unequal length. */
.svc-card__link {
  margin-top: auto;
  padding-top: 18px;
  align-self: flex-start;
}


/* --- About statistics ----------------------------------------------------- */
.about-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 28px;
  margin-top: 32px;
}
.about-stat__value {
  font-family: var(--font-heading);
  font-size: 30px;
  color: var(--color-accent-2-400);
}
.about-stat__label {
  font-size: var(--text-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-on-dark-soft);
}


/* --- Service-area city list ----------------------------------------------- */
.city-chips {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
  margin-top: 26px;
}
.city-chip {
  font-family: var(--font-heading);
  font-size: var(--text-lead);
  letter-spacing: 0.03em;
  text-transform: uppercase;
}
a.city-chip { text-decoration: none; color: var(--color-text); }
a.city-chip:hover { color: var(--color-interactive-hover); text-decoration: underline; }


/* --- Signs list ----------------------------------------------------------
   The arrow-led list on the dark band of a service page. Two columns from
   700px; the arrow is decorative and hidden from screen readers in the
   markup.
   -------------------------------------------------------------------------- */
.sign {
  display: flex;
  gap: 14px;
  align-items: baseline;
}
.sign__arrow {
  font-family: var(--font-heading);
  color: var(--color-accent-2-400);
  flex: none;
}
.sign__text {
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--text-on-dark-muted);
}


/* --- Chips that are links ------------------------------------------------
   The "More services" row. Same chip as the hero tags, but each one is a
   real link, so it needs the link treatment removed and a hover state added.
   -------------------------------------------------------------------------- */
a.tag {
  text-decoration: none;
  min-height: var(--tap);
  padding-inline: 12px;
}
a.tag-outline:hover,
a.tag-outline:focus-visible {
  background: var(--color-accent-100);
  color: var(--color-accent-800);
}

/* The links row keeps the plain wrapping flex behaviour at every width — the
   even-wrap rule above is for the four hero chips only. */
.tag-row--links { display: flex !important; }


/* --- Small print ---------------------------------------------------------
   The qualifying lines under the services grid and the city list — what is
   and is not covered. Deliberately quiet, deliberately present.
   -------------------------------------------------------------------------- */
.note {
  font-size: var(--text-sm);
  line-height: 1.5;
  margin: 22px 0 0;
  color: var(--text-soft);
}
.note--lead { font-size: var(--text-lead); line-height: 1.6; margin: 18px 0 0; color: var(--text-body); }


/* --- Closing CTA band ----------------------------------------------------- */
.cta-band__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 24px 40px;
  align-items: center;
  justify-content: space-between;
  padding-block: clamp(44px, 6vw, 72px);
}
.cta-band__text {
  font-size: var(--text-lead);
  line-height: 1.5;
  margin: 12px 0 0;
  color: var(--text-on-dark-muted);
}
.cta-band .btn-primary { font-size: 18px; padding: 14px 26px; }


/* --- Editor content -------------------------------------------------------
   Anything typed into the WordPress editor: page.php, the optional body copy
   on service and city pages, the contact page's left column.

   The base styles in section 3 already set the body face, paragraph rhythm
   and link colour. What they do not set is heading SIZE — the design's
   headings all carry a class, and editor headings carry none, so without
   these an H2 written in the editor falls back to the browser's 1.5em.
   -------------------------------------------------------------------------- */
.entry-content > :first-child { margin-top: 0; }
.entry-content > :last-child  { margin-bottom: 0; }

.entry-content h2 {
  font-size: clamp(24px, 2.6vw, 32px);
  text-transform: uppercase;
  margin: 1.6em 0 var(--space-3);
}
.entry-content h3 {
  font-size: clamp(20px, 2vw, 24px);
  margin: 1.5em 0 var(--space-2);
}
.entry-content h4 {
  font-size: var(--text-lead);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin: 1.4em 0 var(--space-2);
}

.entry-content ul,
.entry-content ol {
  margin: 0 0 var(--space-6);
  padding-left: 22px;
}
.entry-content li { margin-bottom: var(--space-2); }
.entry-content li:last-child { margin-bottom: 0; }
.entry-content li > ul,
.entry-content li > ol { margin-top: var(--space-2); }

.entry-content a { text-decoration: underline; }

.entry-content blockquote {
  margin: var(--space-8) 0;
  padding: var(--space-4) 0 var(--space-4) var(--space-6);
  border-left: 3px solid var(--color-accent-300);
  font-size: var(--text-lead);
  color: var(--text-strong);
}

.entry-content img,
.entry-content figure { margin-block: var(--space-8); }

.entry-content hr {
  border: 0;
  border-top: 1px solid var(--color-divider);
  margin: var(--space-8) 0;
}

/* On the request page the editor copy introduces the form, so it sits tight
   against it rather than opening a gap the width of a section. */
.entry-content--above-form { margin-bottom: var(--space-8); }


/* --- Contact / request two-column layout ---------------------------------
   The form on the left, the facts panel on the right. Mobile-first single
   column; the second column arrives with the rest of the site's grids at
   900px. Stays top-aligned rather than centred, because the two columns are
   never the same height.
   -------------------------------------------------------------------------- */
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(32px, 5vw, 64px);
  align-items: start;
}


/* --- Forms ----------------------------------------------------------------
   The design does not include a form artboard, so this is derived from the
   components that do exist: square corners, hairline borders, the Barlow
   Condensed uppercase label treatment used by .fact__label, and the button
   sizing already proven to clear the 44px tap target.

   Written against PLAIN ELEMENTS first so any form — Fluent Forms, a Jobber
   embed's own markup, a plugin swapped in later, or a plain HTML form —
   lands looking like the rest of the site. Fluent Forms' own class names are
   mapped onto the same rules further down rather than styled separately.
   -------------------------------------------------------------------------- */

.entry-content label,
.csp-form label {
  display: block;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: var(--text-sm);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-text);
  margin-bottom: var(--space-2);
}

/* The control itself. Listed by type rather than as a bare `input` so
   checkboxes, radios and the submit button are not caught by it. */
.entry-content input[type="text"],
.entry-content input[type="email"],
.entry-content input[type="tel"],
.entry-content input[type="url"],
.entry-content input[type="number"],
.entry-content input[type="date"],
.entry-content input[type="time"],
.entry-content input[type="search"],
.entry-content input[type="password"],
.entry-content textarea,
.entry-content select,
.csp-form input[type="text"],
.csp-form input[type="email"],
.csp-form input[type="tel"],
.csp-form input[type="url"],
.csp-form input[type="number"],
.csp-form input[type="date"],
.csp-form input[type="time"],
.csp-form input[type="search"],
.csp-form input[type="password"],
.csp-form textarea,
.csp-form select {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: 11px 14px;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid color-mix(in srgb, var(--color-text) 30%, transparent);
  border-radius: var(--radius-sm);
  appearance: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.entry-content textarea,
.csp-form textarea {
  min-height: 150px;
  resize: vertical;
}

/* A select needs its own chevron once appearance is stripped. Inline SVG so
   it costs no request; the colour is baked because a data URI cannot read a
   custom property. */
.entry-content select,
.csp-form select {
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9' fill='none' stroke='%231d1f20' stroke-width='2'%3E%3Cpath d='M1 1l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

.entry-content ::placeholder,
.csp-form ::placeholder {
  color: var(--text-soft);
  opacity: 1; /* Firefox dims placeholders by default, which fails contrast. */
}

/* Focus. Deliberately louder than the browser default: this customer is
   often filling the form one-handed on a phone in an emergency. */
.entry-content input:focus,
.entry-content textarea:focus,
.entry-content select:focus,
.csp-form input:focus,
.csp-form textarea:focus,
.csp-form select:focus {
  outline: none;
  border-color: var(--color-interactive);
  box-shadow: 0 0 0 3px var(--color-accent-200);
}

/* Checkboxes and radios keep the browser's own control — a hand-built one
   is a well-known screen-reader hazard — and only take the brand colour. */
.entry-content input[type="checkbox"],
.entry-content input[type="radio"],
.csp-form input[type="checkbox"],
.csp-form input[type="radio"] {
  accent-color: var(--color-interactive);
  width: 20px;
  height: 20px;
  margin-right: var(--space-3);
  vertical-align: middle;
}

/* Submit. Matches .btn-primary without depending on the plugin adding that
   class, because none of them do. */
.entry-content button[type="submit"],
.entry-content input[type="submit"],
.csp-form button[type="submit"],
.csp-form input[type="submit"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--tap);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: var(--btn-font);
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-bg);
  background: var(--color-interactive);
  border: 1px solid var(--color-interactive);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background-color 0.15s, border-color 0.15s;
}
.entry-content button[type="submit"]:hover,
.entry-content input[type="submit"]:hover,
.csp-form button[type="submit"]:hover,
.csp-form input[type="submit"]:hover {
  background: var(--color-interactive-hover);
  border-color: var(--color-interactive-hover);
}
.entry-content button[type="submit"]:disabled,
.csp-form button[type="submit"]:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}


/* --- Fluent Forms ---------------------------------------------------------
   Mapping the plugin's own class names onto the treatment above. Fluent
   Forms ships a stylesheet of its own that loads after this one, so these
   selectors are written specifically enough to win rather than being marked
   !important.
   -------------------------------------------------------------------------- */
.fluentform .ff-el-group { margin-bottom: var(--space-6); }
.fluentform .ff-el-group:last-child { margin-bottom: 0; }

.fluentform .ff-el-input--label label {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: var(--text-sm);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-text);
  margin-bottom: var(--space-2);
}

/* The required marker. Tan rather than red — nothing has gone wrong yet. */
.fluentform .ff-el-is-required.asterisk-right label:after,
.fluentform .ff-el-is-required.asterisk-left label:before {
  color: var(--color-accent-2-700);
}

.fluentform .ff-el-form-control {
  width: 100%;
  min-height: var(--tap);
  padding: 11px 14px;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1.4;
  color: var(--color-text);
  /* background-COLOR, not the shorthand: the shorthand would wipe out the
     chevron background-image on the select rule below, which sits earlier in
     the file but loses to this selector's higher specificity. */
  background-color: var(--color-bg);
  border: 1px solid color-mix(in srgb, var(--color-text) 30%, transparent);
  border-radius: var(--radius-sm);
  box-shadow: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.fluentform textarea.ff-el-form-control { min-height: 150px; }

/* The plugin's select needs the chevron and the stripped appearance too. */
.fluentform select.ff-el-form-control {
  appearance: none;
  padding-right: 42px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9' fill='none' stroke='%231d1f20' stroke-width='2'%3E%3Cpath d='M1 1l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
}

.fluentform .ff-el-form-control:focus {
  outline: none;
  border-color: var(--color-interactive);
  box-shadow: 0 0 0 3px var(--color-accent-200);
}

.fluentform .ff-el-form-control::placeholder { color: var(--text-soft); opacity: 1; }

/* The plugin's small helper text under a field. */
.fluentform .ff-el-help-message {
  font-size: var(--text-sm);
  color: var(--text-muted);
  margin-top: var(--space-2);
}

.fluentform .ff-btn-submit {
  min-height: var(--tap);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: var(--btn-font);
  line-height: 1.2;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-bg);
  background: var(--color-interactive);
  border: 1px solid var(--color-interactive);
  border-radius: var(--radius-sm);
  box-shadow: none;
  cursor: pointer;
}
.fluentform .ff-btn-submit:hover,
.fluentform .ff-btn-submit:focus {
  background: var(--color-interactive-hover);
  border-color: var(--color-interactive-hover);
  color: var(--color-bg);
}

/* Validation. The border alone is not enough — a red outline is invisible to
   a colour-blind visitor, so the message underneath carries the meaning and
   the colour only reinforces it. */
.fluentform .ff-el-is-error .ff-el-form-control { border-color: var(--color-error); }
.fluentform .ff-el-is-error .ff-el-form-control:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-error) 22%, transparent);
}
.fluentform .error,
.fluentform .text-danger,
.fluentform .error-text {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--color-error);
  margin-top: var(--space-2);
}

.fluentform .ff-errors-in-stack,
.ff-message-error {
  background: var(--color-error-bg);
  border-left: 3px solid var(--color-error);
  color: var(--color-text);
  padding: var(--space-4) var(--space-6);
  margin-bottom: var(--space-6);
  border-radius: var(--radius-sm);
}

.ff-message-success {
  background: var(--color-success-bg);
  border-left: 3px solid var(--color-success);
  color: var(--color-text);
  padding: var(--space-4) var(--space-6);
  border-radius: var(--radius-sm);
}


/* --- Embedded third-party form (Jobber) -----------------------------------
   The embed brings its own markup and its own stylesheet, so this only gives
   it room and stops a fixed-width iframe pushing the page sideways on a
   phone. It is not restyled — that is Jobber's to own.
   -------------------------------------------------------------------------- */
.jobber-embed { max-width: 100%; }
.jobber-embed iframe {
  display: block;
  width: 100%;
  max-width: 100%;
  border: 0;
}

/* The Google reviews widget. A third-party script owns everything inside
   this wrapper, so the only job here is to stop it bursting the container or
   pushing a horizontal scrollbar onto the page — widget stylesheets are
   written against full-width demo pages and often assume more room than a
   1200px container gives them. */
.reviews-embed { max-width: 100%; overflow-x: auto; }
.reviews-embed iframe,
.reviews-embed img {
  max-width: 100%;
}

/* The loud placeholder shown while no embed has been pasted in. Same hazard
   striping as a missing photo, sized for a block of page rather than an
   image slot. */
.csp-embed-slot {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  min-height: 280px;
  padding: var(--space-8) var(--space-6);
  text-align: center;
  border: 2px dashed color-mix(in srgb, var(--color-text) 45%, transparent);
  color: var(--text-muted);
  background-color: var(--color-surface);
  background-image: repeating-linear-gradient(
    45deg,
    transparent 0 14px,
    color-mix(in srgb, var(--color-text) 7%, transparent) 14px 28px
  );
}


/* ==========================================================================
   6. HEADER
   ========================================================================== */

/* --- Promotion bar (only exists when a promotion is set) ----------------- */
.promo-bar {
  background: var(--color-accent-900);
  color: var(--color-bg);
  font-family: var(--font-heading);
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.promo-bar__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  align-items: center;
  justify-content: space-between;
  padding-block: 9px;
}
.promo-bar__claim {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
.promo-bar__highlight { color: var(--color-accent-2-400); }
.promo-bar__sep { opacity: 0.5; }
.promo-bar a {
  color: var(--color-bg);
  text-decoration: none;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.promo-bar a:hover { color: var(--color-accent-2-300); text-decoration: underline; }


/* --- Main header --------------------------------------------------------- */
.site-header {
  border-bottom: 1px solid var(--color-divider);
  background: var(--color-bg);
  position: sticky;
  top: 0;
  z-index: 20;
}
.site-header__inner {
  display: flex;
  align-items: center;
  gap: 16px;
  justify-content: space-between;
  padding-block: 12px;
}

/* --- Brand lockup -------------------------------------------------------- */
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: inherit;
  flex: none;
}
.brand__mark {
  width: 46px;
  height: 46px;
  object-fit: cover;
  display: block;
  flex: none;
}
.brand__text { display: flex; flex-direction: column; line-height: 1; min-width: 0; }
.brand__name {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: clamp(17px, 2.4vw, 21px);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--color-text);
}
.brand__strap {
  font-family: var(--font-heading);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-accent-700);
  margin-top: 3px;
}

/* --- Header actions: nav + phone ---------------------------------------- */
.site-header__actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* The header call button. This element is never hidden at any width — it is
   the conversion on this site. Below the nav breakpoint it narrows to the
   handset icon alone (see the mobile navigation section), but it stays in the
   header bar, outside the menu, and the number stays in its accessible name. */
.header-call {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
}

/* --- Primary navigation -------------------------------------------------- */
.primary-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 26px;
}
.primary-nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  text-decoration: none;
  font-family: var(--font-heading);
  font-size: 15px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text);
}
.primary-nav a:hover,
.primary-nav .current-menu-item > a,
.primary-nav .current-menu-ancestor > a {
  color: var(--color-accent-700);
  text-decoration: underline;
  text-underline-offset: 6px;
}

/* Dropdown parents (Services, Service Areas). */
.primary-nav li { position: relative; }
.primary-nav .sub-menu {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 240px;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  background: var(--color-bg);
  border: 1px solid var(--color-divider);
  padding: 6px 0;
  z-index: 30;
}
.primary-nav .sub-menu a {
  display: flex;
  padding: 8px 18px;
  font-size: 14px;
  letter-spacing: 0.04em;
  width: 100%;
}
.primary-nav .sub-menu a:hover { background: var(--color-accent-100); text-decoration: none; }

/* Open the dropdown on hover, on keyboard focus anywhere inside it, and when
   the toggle button reports itself as expanded. All three matter: hover for
   the mouse, focus-within for the keyboard, aria-expanded for touch. */
.primary-nav li:hover > .sub-menu,
.primary-nav li:focus-within > .sub-menu,
.primary-nav li.is-open > .sub-menu { display: flex; }

/* --- Menu toggle (hidden on desktop, shown at the nav breakpoint) -------- */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: var(--tap);
  height: var(--tap);
  padding: 0;
  background: transparent;
  border: 1px solid var(--color-divider);
  cursor: pointer;
  color: var(--color-text);
}
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 20px;
  height: 2px;
  background: currentColor;
  transition: transform 0.2s, opacity 0.2s;
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before,
.nav-toggle__bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle__bars::before { top: -6px; }
.nav-toggle__bars::after  { top: 6px; }

/* The X state when the menu is open. */
.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after  { transform: translateY(-6px) rotate(-45deg); }


/* ==========================================================================
   7. FOOTER
   ========================================================================== */

.site-footer {
  background: var(--color-bg);
  border-top: 1px solid var(--color-divider);
}
/* Mobile-first: one column. Widens in the responsive section below.
   The design shows 2fr 1fr 1fr; that returns at 900px. */
.site-footer__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 32px;
  padding-block: clamp(40px, 5vw, 64px);
}
.site-footer__brand {
  display: flex;
  align-items: center;
  gap: 12px;
}
.site-footer__brand-name {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
/* The tagline under the footer name. This is what makes the line site-wide:
   the footer is on every page, so the brand line is too. */
.site-footer__tagline {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 15px;
  letter-spacing: 0.04em;
  line-height: 1.3;
  margin: 6px 0 0;
  /* accent-700 on --color-bg, the same pairing .brand__strap already uses in
     the header. accent-2-400 would have been the design's tan, but the footer
     sits on the light ground, where that tan measures about 2:1. */
  color: var(--color-accent-700);
}
.site-footer__blurb {
  font-size: 14px;
  line-height: 1.6;
  margin: 16px 0 0;
  max-width: 44ch;
  color: var(--text-muted);
}
.site-footer__roc {
  margin-top: 16px;
  font-family: var(--font-heading);
  font-size: 14px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-accent-700);
}
.site-footer__heading {
  font-family: var(--font-heading);
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-soft);          /* AA NUDGE #2 — was 60% */
  margin-bottom: 14px;
}
/* The Service Areas heading links to the hub when one exists. */
.site-footer__heading a { color: inherit; text-decoration: none; }
.site-footer__heading a:hover { color: var(--color-accent-700); text-decoration: underline; }
.site-footer__list { list-style: none; margin: 0; padding: 0; }
.site-footer__list a,
.site-footer a.site-footer__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-size: 15px;
  text-decoration: none;
  color: var(--color-text);
  word-break: break-word;
}
.site-footer__list a:hover,
.site-footer a.site-footer__link:hover {
  color: var(--color-accent-700);
  text-decoration: underline;
}
.site-footer__hours {
  font-size: 14px;
  line-height: 1.6;
  margin-top: 12px;
  color: var(--text-muted);
}
.site-footer__bar { border-top: 1px solid var(--color-divider); }
.site-footer__bar-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  justify-content: space-between;
  padding-block: 18px;
  font-size: 13px;
  color: var(--text-soft);          /* AA NUDGE #2 — was 60% */
}

/* Secondary links in the bottom bar — About, Privacy, Terms.
   Separated by a middot drawn in CSS rather than typed into the markup, so
   the separator never survives a link that conditionally did not render. */
.site-footer__secondary {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  align-items: center;
}
.site-footer__secondary a {
  color: inherit;
  text-decoration: none;
  position: relative;
  /* Padding here, negative margin on the row, so the tap target grows
     without the bar itself getting taller. */
  display: inline-flex;
  align-items: center;
  padding-block: 8px;
}
.site-footer__secondary { margin-block: -8px; }
.site-footer__secondary a + a::before {
  content: "·";
  position: absolute;
  left: -9px;
  color: var(--color-divider);
}
.site-footer__secondary a:hover,
.site-footer__secondary a:focus-visible {
  color: var(--text-strong, inherit);
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* ==========================================================================
   8. STICKY MOBILE CALL BAR
   ==========================================================================
   The design shows a persistent header CTA. On a phone that intent becomes a
   fixed bar at the bottom of the screen — the thumb reaches it without
   scrolling, which is the whole point for someone standing in a flooding
   laundry room.
   Only rendered below the nav breakpoint. See the responsive section.
   ========================================================================== */

.sticky-call {
  display: none;                 /* Turned on in the responsive layer. */
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  background: var(--color-accent-900);
  border-top: 1px solid var(--color-accent-800);
  padding: 8px 12px;
  padding-bottom: calc(8px + env(safe-area-inset-bottom, 0px));
}
.sticky-call__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
}
.sticky-call .btn {
  width: 100%;
  min-height: 48px;
  font-size: 16px;
}
.sticky-call .btn-secondary {
  border-color: color-mix(in srgb, var(--color-bg) 45%, transparent);
  color: var(--color-bg);
}
/* When only one button is present, let it fill the bar. */
.sticky-call__grid > :only-child { grid-column: 1 / -1; }


/* ==========================================================================
   9. RESPONSIVE
   ==========================================================================
   AUTHORED FOR THIS BUILD. The approved design contains no media queries —
   it specifies the desktop rendering only. These rules build up from a 360px
   baseline to that desktop rendering, using the design's own grid class
   names as the hooks.

   Tested widths: 360, 390, 768, 1024, 1280, 1440.

   Breakpoints:
     up to 899px  — single column, mobile nav, sticky call bar
     900px+       — two-column grids return, nav goes horizontal
     1024px+      — three-column service grid returns
   ========================================================================== */

/* --- The grids the design declares but never styles ----------------------
   At the desktop widths these produce exactly what the design shows. Below
   the breakpoints they stack, which the design does not specify. */

.hero-grid,
.about-grid,
.area-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* Mobile: one column. */
  gap: clamp(28px, 5vw, 72px);
  align-items: center;
}

.svc-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* Mobile: one column. */
  gap: clamp(20px, 3vw, 40px);
}

.signs-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* Mobile: one column. */
  gap: 16px 40px;
}

.facts-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);   /* Mobile: stacked cards. */
}

/* --- Tablet and up ------------------------------------------------------- */
@media (min-width: 700px) {
  .svc-grid   { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .signs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .facts-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* Footer: brand block spans the full width, the two link columns pair up.
     Three columns at 768px would be too cramped to tap comfortably. */
  .site-footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .site-footer__grid > :first-child { grid-column: 1 / -1; }
}

/* --- The nav breakpoint --------------------------------------------------
   900px is where the four nav items plus the call button stop fitting on one
   line without crowding. */
@media (min-width: 900px) {
  .hero-grid  { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .about-grid { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .area-grid  { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: start; }

  /* The form takes the wider column; the facts panel is a fixed-ish rail so
     its label/value rows never stretch far enough to be hard to pair up. */
  .contact-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 380px); }
}

@media (min-width: 900px) {
  /* Brand across the top, then the three link columns share the row. The
     design's 2fr brand column returns at 1100px, where there is room for it
     alongside four columns rather than three. */
  .site-footer__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .site-footer__grid > :first-child { grid-column: 1 / -1; }
}

/* --- Four footer columns -------------------------------------------------
   The design drew three: brand, contact, links. That worked when the links
   column held seven services. It stopped working once the six cities joined
   it — thirteen links ran the column to three times the height of the brand
   block beside it, leaving the whole left half of the footer empty.

   Splitting services and service areas into their own columns balances the
   four blocks and shortens the footer. The brand column keeps more width than
   the link columns because it carries a paragraph, not a list. */
@media (min-width: 1100px) {
  /* Not the design's 2fr brand column — four columns leave it less room than
     three did, and the ratios here are measured rather than guessed.

     At the 1200px container the four columns share 972px after gaps. The
     contact column gets the extra share because it holds the one string that
     cannot be broken sensibly: cactusstateplumbing@gmail.com needs 228px, and
     an even split gave it 213, which is what wrapped it to "gmail.c / om".
     1.3 / 1.2 / 1 / 1 puts contact at ~259px and still leaves the two link
     columns wider than they were. */
  .site-footer__grid {
    grid-template-columns:
      minmax(0, 1.3fr) minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr);
  }
  .site-footer__grid > :first-child { grid-column: auto; }
}

@media (min-width: 1024px) {
  .svc-grid   { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .facts-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* The facts panel draws its own cell borders, which would double up with the
   blueprint frame on whichever cell ends a row. That cell changes with the
   column count, so it is cleared per breakpoint. */
.facts-grid > .fact:last-child { border-right: 0; }

@media (min-width: 700px) {
  .facts-grid > .fact:nth-child(2n) { border-right: 0; }
}

@media (min-width: 1024px) {
  .facts-grid > .fact:nth-child(2n) { border-right: 1px solid var(--color-divider); }
  .facts-grid > .fact:nth-child(3n) { border-right: 0; }
}

/* The local-detail panel on a city page holds exactly four facts — hardness,
   source, housing era, pipe materials. The business facts panel's three
   columns would leave the fourth stranded on a half-empty row, so this one
   pairs them 2x2. It stays a single column on a phone like every other grid.

   Placed after the breakpoints for the same reason as the rail rules below:
   these tie with the nth-child rules on specificity, so order decides. */
@media (min-width: 700px) {
  .facts-panel--local .facts-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .facts-panel--local .facts-grid > .fact:nth-child(2n) { border-right: 0; }
  .facts-panel--local .facts-grid > .fact:nth-child(2n+1) { border-right: 1px solid var(--color-divider); }
}

/* The facts panel in the contact / request page's side rail.
   Those column counts above are keyed to the VIEWPORT, and the rail is only
   380px wide however wide the window is — so on a desktop the panel would
   split into three ~110px columns and every label would sit on top of its
   own value. In the rail it stays one column at every width.

   Placed after the breakpoints deliberately: these selectors tie with the
   nth-child rules above on specificity, so source order is what decides. */
.contact-grid .facts-grid { grid-template-columns: minmax(0, 1fr); }
.contact-grid .facts-grid > .fact { border-right: 0; }
.contact-grid .facts-grid > .fact:last-child { border-bottom: 0; }


/* --- Mobile navigation ---------------------------------------------------
   Below 900px the nav links collapse into a toggle panel and the header bar
   becomes three columns: menu toggle left, brand centred, call right.

   THE CALL BUTTON DOES NOT COLLAPSE — .header-call stays in the header bar at
   every width, because the call is the conversion on this site. Below 900px it
   narrows to the handset icon alone; the number itself stays in the accessible
   name, in the promo bar above, and in the sticky bottom bar. */
@media (max-width: 899px) {

  .nav-toggle { display: inline-flex; }

  /* .site-header__actions is dissolved with display:contents so the toggle,
     the nav and the call button become grid items of the header bar in their
     own right. Without it the toggle and the button are locked together in one
     cell and the brand cannot sit between them.

     The two outer columns are fixed at the tap target width so the middle
     column is symmetric — the brand lands on the true centre of the bar, not
     on the centre of whatever space the buttons happen to leave. */
  .site-header__inner {
    position: relative; /* The drop-down panel below is positioned against it. */
    display: grid;
    grid-template-columns: var(--tap) 1fr var(--tap);
    align-items: center;
    gap: 10px;
  }
  .site-header__actions { display: contents; }

  .nav-toggle  { grid-column: 1; grid-row: 1; justify-self: start; }
  .header-call { grid-column: 3; grid-row: 1; justify-self: end; }

  .brand {
    grid-column: 2;
    grid-row: 1;
    justify-self: center;
    max-width: 100%;
    min-width: 0;
    gap: 10px;
  }

  /* The call button becomes a square icon button. The number is still the
     link's accessible name — the label span is clipped, not display:none, so
     a screen reader still announces "602.884.7771" rather than an unlabelled
     link. */
  .header-call.btn {
    width: var(--tap);
    height: var(--tap);
    min-height: var(--tap);
    padding: 0;
    gap: 0;
    justify-content: center;
  }
  .header-call.btn > span {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .header-call .csp-icon { width: 20px; height: 20px; }

  .primary-nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-divider);
    box-shadow: 0 12px 32px color-mix(in srgb, #2b2b2d 22%, transparent);

    /* The 100% in both lines below is the header bar's own height — the panel
       is positioned against .site-header__inner — so the cap works out as
       "everything below the header".

       100dvh, NOT 100vh. On iOS Safari 100vh is the LARGE viewport: the height
       the page would have if the address bar were retracted. It is taller than
       what is actually on screen, so a panel capped with it hangs off the
       bottom and its last items cannot be scrolled to. dvh tracks the visible
       height instead. The 100vh line stays first, as the fallback for browsers
       with no dvh support — they get the old behaviour rather than no cap. */
    max-height: calc(100vh - 100%);
    max-height: calc(100dvh - 100%);

    overflow-y: auto;
    /* Don't let a flick at the end of the list start scrolling the page
       behind the open menu. */
    overscroll-behavior: contain;
  }
  .primary-nav.is-open { display: block; }

  .primary-nav ul {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 8px var(--gutter) 16px;
  }

  /* The sticky Call / Request bar steps aside while the menu is open.

     It is position:fixed at the bottom of the screen, and the menu panel
     scrolls underneath it, so it covered the last ~76px of the list — Contact
     and Submit a Request — with no way to scroll them clear.

     Padding the bottom of the list was tried first and is NOT a reliable fix:
     trailing space inside an overflow container is inconsistently honoured at
     the end of a scroll, and even where it works it leaves a dead gap under
     the last item. Removing the obstruction is deterministic.

     Nothing is lost by hiding it. The open menu already fills the screen, and
     the header's own call button stays visible at the top of it the whole
     time, so calling is still one tap away.

     assets/js/nav.js puts .nav-is-open on <body>; the bar lives in footer.php,
     far from the panel in the DOM, so CSS could not otherwise see the state. */
  .nav-is-open .sticky-call { display: none; }
  .primary-nav li { width: 100%; }
  .primary-nav a {
    width: 100%;
    padding-block: 6px;
    border-bottom: 1px solid var(--color-divider);
  }

  /* Sub-menus stack inline rather than floating. */
  .primary-nav .sub-menu {
    display: block;
    position: static;
    border: 0;
    padding: 0 0 0 18px;
    min-width: 0;
    box-shadow: none;
  }
  .primary-nav .sub-menu a { padding: 6px 0; font-size: 14px; }

  /* The sticky bottom call bar appears only at these widths. */
  .sticky-call { display: block; }

  /* Leave room for the bar so it never covers the last line of the footer. */
  body { padding-bottom: 76px; }
}

/* --- Narrow phones (360–420px) -------------------------------------------
   The call button is already icon-only below 900px, so nothing more has to
   give there. What is left is the brand lockup in the middle column: the mark
   shrinks and the strapline is hidden, because the footer repeats it. */
@media (max-width: 480px) {

  .brand__mark  { width: 38px; height: 38px; }
  .brand__strap { display: none; }

  .site-footer__grid { gap: 28px; }

  .promo-bar { font-size: 12px; }
  .promo-bar__inner { justify-content: center; text-align: center; }
}

/* At the narrowest widths the trading name wraps onto a second line rather
   than shunting the mark off the centre of the bar. */
@media (max-width: 400px) {
  .brand      { gap: 8px; }
  .brand__mark { width: 34px; height: 34px; }
  .brand__name { font-size: 15px; }
}


/* --- Tables reflow to cards ----------------------------------------------
   No sideways scrolling on a phone. Any table in editor content becomes a
   stack of labelled rows. */
@media (max-width: 700px) {
  .entry-content table,
  .entry-content thead,
  .entry-content tbody,
  .entry-content th,
  .entry-content td,
  .entry-content tr { display: block; width: 100%; }

  .entry-content thead { position: absolute; left: -9999px; }

  .entry-content tr {
    border: 1px solid var(--color-divider);
    margin-bottom: 12px;
    padding: 8px 12px;
  }
  .entry-content td { border: 0; padding: 6px 0; }
}


/* ==========================================================================
   10. ACCESSIBILITY
   ========================================================================== */

/* --- Skip link -----------------------------------------------------------
   Off-screen until focused, then it appears at the top of the page. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 12px 20px;
  background: var(--color-accent-900);
  color: var(--color-bg);
  font-family: var(--font-heading);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  text-decoration: none;
}
.skip-link:focus {
  left: 0;
  color: var(--color-bg);
}

/* --- Focus ---------------------------------------------------------------
   A visible focus ring on every interactive element. The 2px offset keeps it
   clear of the element's own border. */
:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--color-interactive);
  outline-offset: 2px;
}
/* On the dark band the green ring would disappear, so use the tan. */
.section--dark :focus-visible,
.promo-bar :focus-visible,
.sticky-call :focus-visible {
  outline-color: var(--color-accent-2-300);
}

::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

/* --- Screen-reader-only text --------------------------------------------- */
.screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* --- Reduced motion ------------------------------------------------------
   Respect the operating-system preference. Nothing animates for anyone who
   has asked for that. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Print ---------------------------------------------------------------
   Somebody will print a service page. Drop the chrome. */
@media print {
  .site-header, .site-footer, .sticky-call, .promo-bar, .skip-link { display: none !important; }
  body { padding-bottom: 0; }
}
