/*
Theme Name: High Stakes Epoxy Child
Theme URI: https://highstakesepoxyllc.com/
Template: astra
Description: Hand-coded Astra child theme for High Stakes Epoxy LLC. Replaces the Elementor build with PHP page templates driven by the data functions in inc/. Design ported from the approved homepage mockup.
Version: 1.0.0
Author: High Stakes Epoxy LLC
Text Domain: hs-child
*/

/* ==========================================================================
   FONTS

   Urbanist (headings), Inter (body) and Archivo (eyebrows, labels, stat
   numbers, button text) are the three faces the approved design is drawn in.
   All self-hosted as variable woff2 subset to latin, so first paint does not
   depend on fonts.googleapis.com and no visitor IP reaches Google before
   consent.

   font-display: swap on all three: the fallback stack is metric-similar
   enough that a swap is cheaper than a blocking load, and a contractor site's
   LCP is almost always the hero heading.

   NOTE: assets/fonts/urbanist-variable-latin.woff2 is not committed yet — see
   assets/fonts/README.md. Until it lands, headings fall back to Helvetica
   Neue/Arial and the layout still holds; the weights are the only loss.
   ========================================================================== */

@font-face {
  font-family: 'Urbanist';
  src: url('assets/fonts/urbanist-variable-latin.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('assets/fonts/inter-variable-latin.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Archivo';
  src: url('assets/fonts/archivo-variable-latin.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   TOKENS

   Ported verbatim from the approved mockup. Palette is sampled from the logo:
     Stakes Blue  #3B82D6 (wordmark)  -> identity, structure, links
     Epoxy Green  #92C43D (EPOXY)     -> ACTION ONLY: CTAs, active state
     Concrete     #2D3033 (backdrop)  -> the dark "shop floor" spine
   Neutrals carry a blue bias so they read as chosen, not default.

   The rule that must hold site-wide: blue carries identity, green is reserved
   for actions. A green element that is not a CTA or an active state is a bug.

   Custom properties are declared on :root rather than on .hs because the
   sticky mobile bar and the skip link are rendered outside the scoped tree,
   and a token that resolves in one place and not the other is the kind of bug
   that only shows up on one breakpoint.
   ========================================================================== */

:root {
  /* light host */
  --hs-page:      #F1F4F7;   /* Cured Concrete */
  --hs-band:      #FFFFFF;
  --hs-band-alt:  #E3E8ED;   /* Aggregate */
  --hs-ink:       #101820;   /* Blue-black */
  --hs-text:      #37434F;
  --hs-muted:     #5A6773;   /* 4.70:1 on the worst light surface — see note */
  --hs-line:      #D5DCE3;
  --hs-line-soft: #E5EAEF;

  /* dark spine — the "shop floor" sections */
  --hs-deck:       #14181C;
  --hs-deck-2:     #1D2328;
  --hs-deck-3:     #262D33;
  --hs-deck-line:  #313941;
  --hs-deck-ink:   #EEF3F7;
  --hs-deck-text:  #B3BFCA;
  --hs-deck-muted: #7F8D9A;

  /* brand — straight from the logo */
  --hs-brand:      #3B82D6;   /* Stakes Blue */
  --hs-brand-hi:   #5AA0F0;
  --hs-brand-deep: #1E5A9E;
  /*
   * Small brand-blue TEXT on light surfaces. #3B82D6 is the identity blue and
   * stays that everywhere it is a border, a bullet or an icon (3:1 is the bar
   * for those, and it clears it) — but as 11.5px bold type it only reaches
   * 3.93:1 on white and 3.18:1 on --hs-band-alt, under the 4.5:1 normal text
   * needs. Eyebrows, "Best for" lines and category labels use this instead.
   * It is --hs-brand-deep's value, not a new colour.
   */
  --hs-brand-text: #1E5A9E;   /* 5.66:1 worst case on light */

  --hs-lime:       #92C43D;   /* Epoxy Green — CTAs only */
  --hs-lime-hi:    #A6D950;
  --hs-on-lime:    #101820;

  /* Was #E8B93A, which measured 1.84:1 against the white review card it sits
     on — a rating is meaningful non-text content and needs 3:1. This is 3.57:1
     on white and 4.81:1 on the dark-mode card, so one value covers both. */
  --hs-star: #B07F0D;

  /*
   * Borders that identify an interactive control — a field, a chip, a ghost
   * button. --hs-line is 1.38:1 on white, which is fine for a decorative card
   * edge but fails the 3:1 that WCAG asks of anything you have to see to know
   * a control is there. Card borders keep --hs-line; controls use this.
   */
  --hs-control-line: #788490;
  /* The same job on the dark spine (burger, ghost buttons on --hs-deck), which
     stays dark in both colour schemes so this value does not change. */
  --hs-control-line-dark: #6A7783;

  --hs-radius:    4px;
  --hs-radius-lg: 10px;
  --hs-maxw:      1200px;
  --hs-shadow: 0 1px 2px rgba(16,24,32,.05), 0 12px 32px -18px rgba(16,24,32,.26);

  /* Height the sticky mobile bar reserves, so it can never cover the footer. */
  --hs-stickybar-h: 68px;

  /*
   * Masthead height, as a token because three things have to agree on it: the
   * masthead's own height, the drawer's max-height (it fills whatever is left
   * of the viewport below the pinned header), and anything else that offsets
   * itself from the header. When the height changed at 620px and the drawer's
   * hard-coded 124px did not, the drawer was cut short on exactly the screens
   * where the menu is longest.
   */
  --hs-header-h: 82px;
}

/*
 * Dark mode.
 *
 * The dark spine (--hs-deck*) is part of the design in BOTH schemes — it is a
 * deliberate "shop floor" band, not a dark-mode artifact — so it darkens
 * rather than inverting. Only the light host surfaces swap roles.
 *
 * --hs-brand lifts to #5CA0F0 in dark: #3B82D6 on #171C21 lands at 3.9:1,
 * under the 4.5:1 the eyebrows and links need.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --hs-page:      #101418;
    --hs-band:      #171C21;
    --hs-band-alt:  #1C2228;
    --hs-ink:       #EFF4F8;
    --hs-text:      #BCC7D1;
    --hs-muted:     #8896A2;
    --hs-line:      #2A323A;
    --hs-line-soft: #222930;
    --hs-control-line: #657280;
    --hs-deck:      #0B0E11;
    --hs-deck-2:    #141A1F;
    --hs-deck-3:    #1C232A;
    --hs-brand:      #5CA0F0;
    --hs-brand-text: #5CA0F0;
    --hs-shadow: 0 1px 2px rgba(0,0,0,.4), 0 12px 32px -18px rgba(0,0,0,.8);
    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --hs-page:      #101418;
  --hs-band:      #171C21;
  --hs-band-alt:  #1C2228;
  --hs-ink:       #EFF4F8;
  --hs-text:      #BCC7D1;
  --hs-muted:     #8896A2;
  --hs-line:      #2A323A;
  --hs-line-soft: #222930;
  --hs-control-line: #657280;
  --hs-deck:      #0B0E11;
  --hs-deck-2:    #141A1F;
  --hs-deck-3:    #1C232A;
  --hs-brand:     #5CA0F0;
  --hs-brand-text: #5CA0F0;
  --hs-shadow: 0 1px 2px rgba(0,0,0,.4), 0 12px 32px -18px rgba(0,0,0,.8);
  color-scheme: dark;
}

/* ==========================================================================
   BASE

   Everything below is scoped under .hs — the class functions.php adds to
   <body> only on this theme's own views. Astra's templates, the admin bar and
   any plugin output are untouched wherever our templates are not in play.
   ========================================================================== */

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

body.hs {
  margin: 0;
  background: var(--hs-page);
  color: var(--hs-text);
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  font-size: 16px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

.hs h1, .hs h2, .hs h3, .hs h4 {
  font-family: Urbanist, "Helvetica Neue", Arial, sans-serif;
  color: var(--hs-ink);
  margin: 0;
  line-height: 1.08;
  letter-spacing: -0.025em;
  text-wrap: balance;
  font-weight: 800;
}

.hs p { margin: 0; }
.hs a { color: inherit; text-decoration: none; }
.hs img { max-width: 100%; height: auto; border: 0; vertical-align: middle; }

/* ==========================================================================
   BASE ELEMENTS

   Everything in this block existed only in Astra's stylesheet until now.

   This theme replaced Astra's templates but never its base layer, so any bare
   element it did not style by class was still being typeset by the parent
   theme: h5 and h6 in Urbanist 600 against this design's 700/800/900, lists
   and tables on Astra's metrics, form controls in Astra's blue — and
   `input { outline: none }`, which silently removed the focus indicator the
   accessibility budget requires.

   With these defined, nothing on a .hs page depends on the parent stylesheet
   any more. Scoped under .hs like every other rule here, so Astra's own
   templates and wp-admin are untouched.
   ========================================================================== */

/* h1–h4 are set above with the display treatment. These two are the quiet end
   of the scale — spec labels, card subheads — so they take the heading family
   at a weight that still reads as a heading without competing with an h3. */
.hs h5, .hs h6 {
  font-family: Urbanist, "Helvetica Neue", Arial, sans-serif;
  color: var(--hs-ink);
  margin: 0;
  line-height: 1.25;
  letter-spacing: -0.015em;
  font-weight: 700;
}
.hs h5 { font-size: 18px; }
.hs h6 { font-size: 15.5px; }

/* Zeroed here and re-indented by .prose and .entry-content, which is where a
   list is actually read as a list. Every other list on the site is a layout
   grid that sets its own list-style. */
.hs ul, .hs ol { margin: 0; padding: 0; }
.hs li { margin: 0; }
.hs blockquote { margin: 0; }

/* figure carries a 1em/40px default margin in every browser, which Astra's
   reset was quietly cancelling. Images in blog posts are wrapped in one, so
   without this they would indent 40px from both sides the moment the parent
   stylesheet stops loading. */
.hs figure { margin: 0; }
.hs figcaption { font-size: 13.5px; color: var(--hs-muted); margin-top: 8px; }

.hs hr {
  border: 0;
  border-top: 1px solid var(--hs-line);
  margin: 34px 0;
  height: 0;
}

.hs pre, .hs code, .hs kbd, .hs samp {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.92em;
}
.hs pre { overflow-x: auto; margin: 0; }

.hs fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.hs legend { padding: 0; }
.hs dl, .hs dd { margin: 0; }

/* The service pages' system-spec tables. */
.hs table { border-collapse: collapse; border-spacing: 0; width: 100%; }
.hs th, .hs td {
  text-align: left;
  padding: 11px 14px;
  border-bottom: 1px solid var(--hs-line);
  vertical-align: top;
}
.hs th {
  font-family: Archivo, sans-serif;
  font-size: 11.5px; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--hs-brand-text);
}

/*
 * Form controls.
 *
 * `font: inherit` is the line that matters most: a control that does not
 * inherit the page's font is the single most obvious "two themes are fighting"
 * tell, and browsers do not inherit it by default.
 *
 * No outline reset here. Astra's `input { outline: none }` is exactly what
 * removed the 3px lime focus ring from every field; the ring is defined once,
 * on .hs :focus-visible above, and nothing below is allowed to cancel it.
 */
.hs button, .hs input, .hs select, .hs textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}
.hs button { background: none; border: 0; padding: 0; cursor: pointer; }
.hs input, .hs select, .hs textarea {
  width: 100%;
  max-width: 100%;
  padding: 12px 14px;
  background: var(--hs-band);
  border: 1px solid var(--hs-control-line);
  border-radius: var(--hs-radius);
}
.hs textarea { min-height: 140px; resize: vertical; }
.hs input[type="checkbox"],
.hs input[type="radio"] { width: auto; padding: 0; }

.hs .hs-wrap,
.hs .wrap {
  width: 100%;
  max-width: var(--hs-maxw);
  margin: 0 auto;
  padding: 0 24px;
}

.hs .wrap--narrow { max-width: 860px; }

/* Accessible-but-hidden text, for link context a sighted user reads from
   layout. Matches WordPress core's own .screen-reader-text contract. */
.hs .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;
}

.hs .skip-link:focus {
  position: fixed;
  top: 8px; left: 8px;
  z-index: 200;
  background: var(--hs-lime);
  color: var(--hs-on-lime);
  padding: 12px 18px;
  border-radius: 3px;
  font-family: Archivo, sans-serif;
  font-weight: 700;
  text-decoration: none;
}

/* 3px lime ring, per the accessibility budget. Applied globally inside the
   scope so a control added later cannot ship without a focus indicator. */
.hs :focus-visible { outline: 3px solid var(--hs-lime); outline-offset: 2px; }

.hs .eyebrow {
  font-family: Archivo, sans-serif;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--hs-brand-text);
  margin: 0 0 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.hs .eyebrow::before {
  content: "";
  width: 22px; height: 2px;
  background: var(--hs-lime);
  flex: none;
}

/* ==========================================================================
   BUTTONS
   ========================================================================== */

/*
 * Anchor targets clear the sticky masthead. Without this an in-page jump to
 * #services or #quote lands with the heading hidden behind the header, which
 * reads as "the link did nothing".
 */
.hs [id] { scroll-margin-top: 102px; }
@media (max-width: 620px) { .hs [id] { scroll-margin-top: 86px; } }

.hs .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  font-family: Archivo, sans-serif;
  font-weight: 700; font-size: 13.5px; letter-spacing: .07em; text-transform: uppercase;
  padding: 15px 26px;
  border-radius: 3px;
  border: 1.5px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: transform .12s ease, background-color .15s ease, border-color .15s ease, color .15s ease;
  white-space: nowrap;
}
.hs .btn:active { transform: translateY(1px); }
.hs .btn-lime { background: var(--hs-lime); color: var(--hs-on-lime); }
.hs .btn-lime:hover { background: var(--hs-lime-hi); }
/* rgba(255,255,255,.28) over --hs-deck composites to #56595C, 2.53:1 — under
   the 3:1 a control boundary needs. This token is 3.89:1 on the same ground. */
.hs .btn-ghost-dark { border-color: var(--hs-control-line-dark); color: #fff; background: transparent; }
.hs .btn-ghost-dark:hover { border-color: var(--hs-lime); color: var(--hs-lime); }
.hs .btn-ghost { border-color: var(--hs-control-line); color: var(--hs-ink); background: transparent; }
.hs .btn-ghost:hover { border-color: var(--hs-brand); color: var(--hs-brand-text); }
.hs .btn-block { width: 100%; }

/* ==========================================================================
   UTILITY BAR
   ========================================================================== */

.hs .utility {
  background: var(--hs-deck);
  color: var(--hs-deck-muted);
  font-size: 12.5px;
  border-bottom: 1px solid var(--hs-deck-line);
}
/* Hours hard left, service area hard right, the gap between them doing the
   work. space-between with exactly two children needs no spacer element. */
.hs .utility .wrap { display: flex; align-items: center; justify-content: space-between; gap: 24px; height: 40px; }
.hs .utility b { color: var(--hs-deck-ink); font-weight: 600; }
.hs .utility a { color: var(--hs-lime); text-decoration: none; font-weight: 600; }

/* Hours are the item worth keeping when the bar runs out of room — "are they
   open right now" beats the footprint, which the footer and the areas band
   both state at length. :only-child re-centres nothing: the hours simply sit
   left as before. */
.hs .u-area { text-align: right; }

/* ==========================================================================
   HEADER
   ========================================================================== */

/*
 * The dock is what sticks, not the masthead. It wraps the masthead and the
 * mobile drawer (see header.php) so the drawer opens directly under the pinned
 * header at any scroll position. Sticking the masthead alone left the drawer
 * at its document position, so on a scrolled page the burger appeared dead.
 */
.hs .head-dock {
  position: sticky; top: 0; z-index: 60;
}

/*
 * Sticky offsets for the logged-in admin bar.
 *
 * The admin bar is position:fixed, so a sticky header pinned to top:0 slides
 * underneath it and loses its first 32px the moment an editor scrolls. Only
 * logged-in users ever see this, which is the same blind spot that let the
 * unstyled admin bar ship — nothing checked while logged in.
 *
 * The three values are core's own breakpoints: 32px above 782px, 46px between
 * 601 and 782 where the bar gets taller, and none at or below 600px where the
 * bar stops being fixed and scrolls away with the page.
 */
.admin-bar .hs .head-dock,
.admin-bar .hs .masthead--focus { top: 32px; }

@media screen and (max-width: 782px) {
  .admin-bar .hs .head-dock,
  .admin-bar .hs .masthead--focus { top: 46px; }
}

@media screen and (max-width: 600px) {
  .admin-bar .hs .head-dock,
  .admin-bar .hs .masthead--focus { top: 0; }
}

.hs .masthead {
  background: var(--hs-deck);
  border-bottom: 1px solid var(--hs-deck-line);
}
.hs .masthead .wrap { display: flex; align-items: center; gap: 28px; height: 82px; }

.hs .logo { display: flex; align-items: center; gap: 11px; text-decoration: none; flex: none; }
.hs .logo img { height: 54px; width: auto; display: block; }

/*
 * Wordmark fallback, used until a logo file is mapped in hs_image_map().
 * It sits on --hs-deck, so it needs an explicit light colour: inheriting
 * --hs-text puts dark grey on near-black, which fails contrast badly enough
 * that the site name is effectively invisible in the header.
 */
.hs .logo span {
  font-family: Urbanist, "Helvetica Neue", Arial, sans-serif;
  font-weight: 900;
  font-size: 19px;
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: #fff;
}
.hs .foot-logo img { height: 52px; margin-bottom: 4px; }
.hs .logo-name {
  font-family: Urbanist, sans-serif; font-weight: 900; color: #fff;
  font-size: 17px; line-height: 1; letter-spacing: -0.02em; text-transform: uppercase;
}
.hs .logo-sub {
  font-family: Archivo, sans-serif; font-size: 9.5px; font-weight: 600;
  letter-spacing: .3em; color: var(--hs-lime); text-transform: uppercase; margin-top: 3px;
}

.hs nav.primary { display: flex; gap: 30px; margin-left: auto; }
.hs nav.primary ul { list-style: none; margin: 0; padding: 0; display: flex; gap: 30px; }
.hs nav.primary a {
  font-family: Archivo, sans-serif; font-size: 13px; font-weight: 600;
  letter-spacing: .03em; color: var(--hs-deck-text); text-decoration: none;
  display: flex; align-items: center; gap: 5px;
}
.hs nav.primary a:hover,
.hs nav.primary .current-menu-item > a { color: var(--hs-lime); }

/*
 * Caret on nav items that have a submenu.
 *
 * "Services" is the only item in the site's nav that leads to a set of pages
 * rather than one, and until now nothing said so: the dropdown appeared on
 * hover with no prior hint that there was anything to hover over. The caret is
 * that hint, and it rotates to point up while the menu is open so the symbol
 * reports the current state rather than just advertising the affordance.
 *
 * Drawn from two borders rather than a glyph or an SVG: it inherits
 * currentColor (so it turns lime on hover with the label, for free), it needs
 * no font to have loaded, and it stays crisp at any zoom. Both class names are
 * matched — .has-children from hs_default_menu(), .menu-item-has-children from
 * wp_nav_menu() — so assigning a real menu in Appearance → Menus keeps the
 * caret without a CSS change.
 *
 * The parent <a> is already display:flex with a 5px gap, so this lands as a
 * flex child and needs no margin of its own.
 */
.hs nav.primary .has-children > a::after,
.hs nav.primary .menu-item-has-children > a::after {
  content: "";
  flex: none;
  width: 6px;
  height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  /* The rotated square's visual centre sits below its box centre, so it is
     nudged up to align with the cap height of the label beside it. */
  transform: translateY(-2px) rotate(45deg);
  transition: transform .14s ease;
}

/* Points up while the dropdown is open. :focus-within matches the same
   condition that opens the menu for keyboard users, so the caret never
   disagrees with what is on screen. */
.hs nav.primary .has-children:hover > a::after,
.hs nav.primary .has-children:focus-within > a::after,
.hs nav.primary .menu-item-has-children:hover > a::after,
.hs nav.primary .menu-item-has-children:focus-within > a::after {
  /* +2px, not +1: measured against the label's ink box, the down caret centres
     on row 14 and a +1px up caret lands on 13. Flipping the glyph must not
     also nudge it, or the caret visibly hops when the menu opens. */
  transform: translateY(2px) rotate(-135deg);
}

/* Nested submenu links never carry one — the rule above is scoped to direct
   children of the parent item, but this makes a third-level menu safe too. */
.hs nav.primary .sub-menu a::after { content: none; }

/*
 * Services dropdown.
 *
 * The fallback menu in hs_default_menu() hangs all ten service lines under
 * "Services", so without this the submenu lays out inline and pushes the phone
 * number and the quote button off the right of the viewport — which is exactly
 * how the header broke on first render at 1440px.
 *
 * Opened on :focus-within as well as :hover so it is reachable by keyboard
 * without a script. The submenu stays in the DOM either way, so all ten links
 * are crawlable whether or not it is ever opened.
 */
.hs nav.primary li { position: relative; }
.hs nav.primary .sub-menu {
  display: block;
  position: absolute;
  top: 100%;
  left: -14px;
  z-index: 70;
  min-width: 232px;
  padding: 8px 0;
  margin: 0;
  background: var(--hs-deck-2);
  border: 1px solid var(--hs-deck-line);
  border-radius: var(--hs-radius);
  box-shadow: 0 18px 40px -20px rgba(0,0,0,.8);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
}
.hs nav.primary li:hover > .sub-menu,
.hs nav.primary li:focus-within > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.hs nav.primary .sub-menu li { display: block; }
.hs nav.primary .sub-menu a {
  display: block;
  padding: 9px 18px;
  font-size: 13px;
  white-space: nowrap;
  color: var(--hs-deck-text);
}

/*
 * The drawer shows its submenu inline and indented, inside the <details>
 * below — there is no hover on a touch screen, and a nested flyout there
 * would be unreachable.
 */
.hs .mobile-nav .sub-menu { list-style: none; margin: 0; padding: 0; }

.hs .head-cta { display: flex; align-items: center; gap: 14px; flex: none; }

/*
 * 44x44 minimum, which is the tap-target floor rather than a style choice: at
 * 9px/11px padding the button measured 42x40, and it is the only navigation
 * control that exists on a phone. min-width/min-height rather than padding so
 * the bars stay the size they are drawn at while the hit area grows.
 */
.hs .burger {
  display: none;
  flex-direction: column; align-items: center; justify-content: center;
  min-width: 44px; min-height: 44px; padding: 0;
  background: none; border: 1px solid var(--hs-control-line-dark); border-radius: 3px;
  cursor: pointer;
}
.hs .burger i { display: block; width: 18px; height: 2px; background: #fff; margin: 3px 0; }

/*
 * Mobile drawer. Collapsed by default and revealed by [aria-expanded="true"]
 * on the burger, so the button's ARIA state and the visual state are driven
 * by the same attribute and cannot disagree.
 *
 * max-height + overflow-y is a safety net, not the primary fix — the primary
 * fix is the accordion below. Even so, a drawer that cannot itself scroll if
 * the menu ever grows would push page content down by however much it
 * overflows, on the narrowest viewports where that is most visible.
 */
.hs .mobile-nav {
  display: none;
  background: var(--hs-deck-2); border-bottom: 1px solid var(--hs-deck-line);
  /*
   * Fill the viewport below the pinned header and no more. dvh so the drawer
   * is not measured against a viewport that includes mobile browser chrome
   * which is about to collapse; the vh line above it is the fallback for
   * browsers without dvh.
   */
  max-height: calc(100vh - var(--hs-header-h));
  max-height: calc(100dvh - var(--hs-header-h));
  overflow-y: auto;
  /* Scrolling to the end of the menu must not then start scrolling the page
     underneath it. */
  overscroll-behavior: contain;
}
.hs .mobile-nav[data-open="true"] { display: block; }

/*
 * Lock the page while the drawer is open. Without this the page scrolls behind
 * an open menu, so a thumb drag meant for the service list moves the article
 * underneath and the drawer ends up floating over unrelated content.
 *
 * Set on <body> by main.js and removed on close, so with JS off — where the
 * drawer cannot be opened in the first place — nothing is ever locked.
 */
body.hs-nav-open { overflow: hidden; }
.hs .mobile-nav ul { list-style: none; margin: 0; padding: 8px 0 16px; display: grid; }
.hs .mobile-nav a {
  display: block; padding: 13px 24px; text-decoration: none;
  font-family: Archivo, sans-serif; font-size: 14px; font-weight: 600;
  color: var(--hs-deck-text); border-bottom: 1px solid var(--hs-deck-line);
}
.hs .mobile-nav a:hover { color: var(--hs-lime); }

/*
 * The Services accordion. <details>/<summary> — same zero-JS pattern as the
 * FAQ — collapsed by default so the drawer opens to six top-level rows
 * instead of six rows plus ten always-visible service links. The chevron
 * reuses the FAQ's own +/− language rather than inventing a second symbol
 * for "this expands" elsewhere on the site.
 */
.hs .mobile-nav details { border-bottom: 1px solid var(--hs-deck-line); }
.hs .mobile-nav details .sub-menu a { border-bottom: 1px solid var(--hs-deck-line); }
.hs .mobile-nav details:last-child,
.hs .mobile-nav details .sub-menu li:last-child a { border-bottom: none; }
.hs .mobile-nav summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  list-style: none; cursor: pointer; padding: 13px 24px;
  font-family: Archivo, sans-serif; font-size: 14px; font-weight: 600;
  color: var(--hs-deck-text);
}
.hs .mobile-nav summary::-webkit-details-marker { display: none; }
.hs .mobile-nav summary:hover { color: var(--hs-lime); }
/*
 * The drawer's Services row gets the same caret as the desktop dropdown, not
 * the +/− it used to carry.
 *
 * The original +/− was chosen to match the FAQ accordion, and the FAQ keeps it.
 * The distinction being drawn now is what the control does rather than how it
 * animates: a caret means there are more pages underneath, +/− means a longer
 * answer unfolds in place. Services is the former on both layouts, so it reads
 * the same on both.
 *
 * Sized a little larger than the desktop caret (8px against 6px, 2px borders
 * against 1.5px) because this one is a touch target's indicator at arm's
 * length, not a hover hint under a cursor.
 */
.hs .mobile-nav summary::after {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  margin-right: 4px;
  border-right: 2px solid var(--hs-lime);
  border-bottom: 2px solid var(--hs-lime);
  /*
   * The offsets differ between the two states and are not the desktop pair.
   * A rotated square's ink sits low when it points down and high when it
   * points up, and the error scales with the box — at 8px/2px it measured
   * 1.5px low and 0.5px high against the label's ink centre, which is a
   * visible hop on toggle rather than a rounding detail. These two land both
   * states on the same centre line, so the caret flips without moving.
   */
  transform: translateY(-3.5px) rotate(45deg);
  transition: transform .16s ease;
}
.hs .mobile-nav details[open] summary::after {
  transform: translateY(2px) rotate(-135deg);
}
.hs .mobile-nav .sub-menu a { padding-left: 40px; font-size: 13px; color: var(--hs-deck-muted); }
/* The archive-page link ("All Services") reads as the odd one out among the
   ten specific service names on purpose — it is the shortcut, not a sibling
   of equal weight, so it keeps the drawer's normal link colour and weight. */
.hs .mobile-nav .sub-menu-all { color: var(--hs-deck-text) !important; font-weight: 600; }

/* ==========================================================================
   HERO
   ========================================================================== */

.hs .hero { position: relative; background: var(--hs-deck); overflow: hidden; }
.hs .hero-media { position: absolute; inset: 0; }
.hs .hero-media img { width: 100%; height: 100%; object-fit: cover; opacity: .5; }
.hs .hero::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(120% 90% at 12% 0%, rgba(59,130,214,.20), transparent 55%),
              linear-gradient(180deg, rgba(20,24,28,.52) 0%, rgba(20,24,28,.88) 70%, var(--hs-deck) 100%);
}
/*
 * Interior heroes carrying a photograph.
 *
 * The homepage hero is tall, and its gradient reaches near-opaque deck by the
 * bottom of the section, so its headline always lands on the dark end. An
 * interior hero is about a third of that height, so the headline sits over the
 * LIGHT end of the same gradient — which needs its own treatment.
 *
 * These numbers are a balance, and the first attempt got it wrong in the
 * cautious direction: a scrim calibrated against a pure-white photograph
 * (.74) buried the actual photographs, most of which are dark polished
 * concrete, and the hero read as a plain black band with a wasted HTTP
 * request behind it.
 *
 * Settled on image .62 under a .58→.80 scrim, then measured in the browser
 * rather than trusted: see the contrast check in the build notes. Worst case
 * is still a hypothetical all-white photo, where white headline text computes
 * to 7.4:1. The lede is the tight one there, which is why it gets a lighter
 * ink on photo heroes only — at --hs-deck-text it would be 3.9:1, under the
 * 4.5:1 that 17px body text needs.
 */
.hs .hero--photo .hero-media img { opacity: .62; }
.hs .hero--photo::after {
  background: radial-gradient(120% 90% at 12% 0%, rgba(59,130,214,.18), transparent 55%),
              linear-gradient(180deg, rgba(20,24,28,.58) 0%, rgba(20,24,28,.80) 100%);
}
.hs .hero--photo .hero-lede { color: #D6DEE6; }
.hs .hero--photo .breadcrumb { color: #C3CDD6; }
.hs .hero--inner.hero--photo .wrap { padding-top: 56px; padding-bottom: 52px; }

/*
 * Padding is tighter than it was when this hero also framed a form card
 * (68/62). Now that the section is headline + one CTA row, that much air
 * pushed the proof strip below the fold on ordinary desktop browser windows
 * — a maximized Chrome window on a common 1440x900 display leaves more like
 * 780-820px of usable height once its own chrome is subtracted, and the
 * section needs to fit inside that with room to spare for the proof strip's
 * count-up to actually be witnessed, not scrolled past unseen.
 */
.hs .hero .wrap { position: relative; z-index: 2; padding-top: 44px; padding-bottom: 40px; }

/*
 * Single column, 840px rather than the narrower 720px it started at. This
 * used to be a two-track grid (copy + the quote-card form beside it); with
 * the form removed the copy no longer needs a track to share space with, but
 * it still wants a measure — max-width keeps the headline from stretching
 * across the full 1152px band, which reads as oversized and thin at that
 * font size.
 *
 * 840, specifically, because it is the narrowest width at which this exact
 * headline wraps to three lines instead of four — one fewer line is worth
 * about 63px on its own, which is the single biggest lever in getting the
 * proof strip back above the fold. Below ~888px of actual available content
 * width (most tablet and phone viewports) the cap never engages at all, since
 * the column is already narrower than 840 — this only affects wide screens.
 */
.hs .hero-grid { max-width: 840px; }
.hs .hero .eyebrow { margin-bottom: 10px; }
.hs .hero h1 { color: #fff; font-size: clamp(34px, 4.6vw, 58px); font-weight: 900; }
.hs .hero h1 em { font-style: normal; color: var(--hs-lime); }
.hs .hero-lede { color: var(--hs-deck-text); font-size: 17px; margin-top: 14px; }
/* align-items:center keeps the button and the call link on the same visual
   baseline even though they're different heights — a padded box vs. a line
   of text with an icon. Gap is wider than a button pair needs, because these
   two aren't a matched set; the space itself signals that. */
.hs .hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 28px; margin-top: 20px; }

/*
 * The call link. Not a button: no border, no fill — it is deliberately the
 * lighter of the two actions. min-height matches the .field touch-target
 * rule elsewhere on the site (44px), so it is exactly as easy to tap as the
 * button beside it even though it looks like plain text.
 */
.hs .hero-call {
  display: inline-flex; align-items: center; gap: 9px;
  min-height: 44px;
  color: var(--hs-deck-text);
  text-decoration: none;
  font-family: Archivo, sans-serif;
  font-weight: 700; font-size: 13.5px; letter-spacing: .04em;
  transition: color .15s ease;
}
.hs .hero-call-icon { color: var(--hs-lime); flex: none; transition: color .15s ease; }
.hs .hero-call span {
  border-bottom: 1px solid rgba(255,255,255,.28);
  padding-bottom: 2px;
  transition: border-color .15s ease;
}
.hs .hero-call:hover { color: #fff; }
.hs .hero-call:hover .hero-call-icon { color: var(--hs-lime-hi); }
.hs .hero-call:hover span { border-color: var(--hs-lime); }


/* Interior hero: the compact variant every non-home template opens on. */
.hs .hero--inner .wrap { padding-top: 52px; padding-bottom: 52px; }
.hs .hero--inner h1 { font-size: clamp(30px, 3.8vw, 46px); }

.hs .breadcrumb {
  display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px;
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--hs-deck-muted);
}
.hs .breadcrumb a { color: var(--hs-deck-text); text-decoration: none; }
.hs .breadcrumb a:hover { color: var(--hs-lime); }
.hs .breadcrumb span + span::before { content: "/"; margin-right: 8px; color: var(--hs-deck-line); }

/* ==========================================================================
   PROOF STRIP
   ========================================================================== */

.hs .proof { background: var(--hs-deck-2); border-top: 1px solid var(--hs-deck-line); }
.hs .proof .wrap {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px;
  background: var(--hs-deck-line); padding: 0; max-width: none;
}
.hs .proof-cell { background: var(--hs-deck-2); padding: 26px 24px; text-align: center; }
.hs .proof-num {
  font-family: Archivo, sans-serif; font-weight: 700; font-size: clamp(24px, 3vw, 34px);
  color: #fff; line-height: 1; font-variant-numeric: tabular-nums;
}
.hs .proof-num u { text-decoration: none; color: var(--hs-lime); }
.hs .proof-label {
  font-family: Archivo, sans-serif; font-size: 10.5px; font-weight: 600; letter-spacing: .15em;
  text-transform: uppercase; color: var(--hs-deck-muted); margin-top: 9px;
}

/* ==========================================================================
   BANDS
   ========================================================================== */

.hs .band { padding: 84px 0; background: var(--hs-page); }

/*
 * The one exception to the standard 84px band rhythm: a dark band that
 * follows the proof strip directly. Hero (--hs-deck), proof (--hs-deck-2)
 * and this section (--hs-deck) are three near-identical dark surfaces back
 * to back with no colour change to mark where one ends and the next begins
 * — unlike every other band transition on the page, which moves from dark to
 * light or light to dark and gets a free, obvious "new section" cue from the
 * colour swap alone. Without that cue, a full 84px of top padding here reads
 * as unstructured dead space rather than deliberate breathing room: on any
 * browser window taller than about 825px, a visitor sees the proof numbers
 * and then 141px of plain black with nothing in it before "Start here"
 * appears. Tightened specifically at this one seam; every other transition
 * on the page keeps the full 84px because it already reads as intentional.
 */
.hs .proof + .band-deck { padding-top: 40px; }
.hs .band-white { background: var(--hs-band); }
.hs .band-alt { background: var(--hs-band-alt); }
.hs .band-deck { background: var(--hs-deck); color: var(--hs-deck-text); position: relative; overflow: hidden; }

/*
 * A dark band directly after another dark band. hs_band() adds this class when
 * it happens, because two --hs-deck sections in a row have no boundary at all
 * and read as one very long slab — which is what made /services/ feel like it
 * had lost a section. One step up the dark scale is enough to show the join
 * without breaking the spine into stripes.
 */
.hs .band-deck--step {
  background: var(--hs-deck-2);
  /* The rule is not decoration. The proof strip is already --hs-deck-2, so a
     stepped band landing directly under it would match it exactly and the step
     would do nothing — which is the case on the homepage and /service-areas/.
     A hairline guarantees the join is visible whatever the two backgrounds
     happen to be. */
  border-top: 1px solid var(--hs-deck-line);
}

/* Same problem where the final CTA follows a dark band: a hairline is enough
   here, since the CTA already has its own gradient treatment. */
.hs .cta-final--step { border-top: 1px solid var(--hs-deck-line); }
.hs .band-deck h2, .hs .band-deck h3 { color: #fff; }
.hs .band-deck .eyebrow { color: var(--hs-lime); }

/* The hero and the closing CTA are dark but are not .band-deck, so their
   eyebrows would inherit the dark-on-dark text blue. They take the light end
   of the brand ramp instead — 6.56:1 on --hs-deck. */
.hs .hero .eyebrow,
.hs .cta-final .eyebrow { color: var(--hs-brand-hi); }

/*
 * The heading keeps a measure; the paragraph under it runs the full section
 * width. Constraining the block as a whole was making the sub-copy break at
 * roughly half the band on wide screens, which read as a stray column rather
 * than an intro to the section.
 *
 * The trade is real: a 1200px line at 16.5px is a long measure to track back
 * from. It is survivable here because these paragraphs are one or two
 * sentences — a lede, not body copy — and never more.
 */
.hs .band-head { margin-bottom: 44px; }

/*
 * No max-width on the heading. It used to be capped at a fixed measure (first
 * 62ch on the whole block, then 39rem on the h2 alone), which forced short,
 * punchy titles like "Two very different floors. Two very different jobs."
 * onto two lines even though the band had room for one — an editorial measure
 * fighting the copy instead of framing it.
 *
 * Sized to the band instead: a heading now wraps only when the actual text is
 * wider than the actual column, at whatever the viewport really is. Short
 * titles fall onto one line; the one genuinely long title on the page ("Most
 * failed epoxy floors...") still wraps, because it is still wider than the
 * band — nothing here forces a line count either way, it removes an
 * artificial one.
 */
.hs .band-head h2 { font-size: clamp(28px, 3.4vw, 40px); }
.hs .band-head p { margin-top: 16px; font-size: 16.5px; color: var(--hs-muted); }
.hs .band-deck .band-head p { color: var(--hs-deck-text); }
.hs .band-head.center { text-align: center; }
.hs .band-head.center h2 { margin-left: auto; margin-right: auto; }
.hs .band-head.center .eyebrow { justify-content: center; }

.hs .band-foot { margin-top: 32px; }
.hs .band-foot.center { text-align: center; }

/* ==========================================================================
   SPLIT PATH
   ========================================================================== */

.hs .paths { display: grid; grid-template-columns: 1fr 1fr; gap: 22px; }
.hs .path {
  position: relative; background: var(--hs-deck-2); border: 1px solid var(--hs-deck-line);
  border-radius: var(--hs-radius-lg); padding: 34px 32px 30px; overflow: hidden;
  transition: border-color .18s ease, transform .18s ease, box-shadow .18s ease;
}
.hs .path:hover { border-color: var(--hs-brand); transform: translateY(-3px); }

/*
 * Default tag colour is the identity blue, not lime. Lime is reserved
 * site-wide for actions and active state (see the tokens block at the top of
 * this file); reusing it here on BOTH cards would make neither one read as
 * "the" featured path — colour that is everywhere stops being a signal.
 * .path--featured below reclaims lime for the one card actually being
 * highlighted, the same way the HQ chip in the service-area band uses it to
 * mark "this one" among a row of otherwise-identical options.
 */
.hs .path-tag {
  font-family: Archivo, sans-serif; font-size: 10.5px; font-weight: 700; letter-spacing: .18em;
  text-transform: uppercase; color: var(--hs-brand-hi); margin-bottom: 14px;
}

/*
 * The featured card. Visual weight only — no badge text, no "Most Popular"
 * claim — see the comment in hs_split_path_section() for why. A lime top
 * edge is the same device the quote card used to use for its own "start
 * here" framing; reusing it keeps one visual language for "the one we're
 * pointing at" instead of inventing a second.
 */
.hs .path--featured { border-top: 3px solid var(--hs-lime); box-shadow: 0 24px 48px -30px rgba(0,0,0,.65); }
.hs .path--featured .path-tag { color: var(--hs-lime); }
.hs .path--featured:hover { border-color: var(--hs-brand); border-top-color: var(--hs-lime-hi); }
.hs .path h3 { font-size: 26px; }
.hs .path > p { color: var(--hs-deck-text); margin-top: 12px; font-size: 15px; }
.hs .path ul { list-style: none; padding: 0; margin: 20px 0 0; display: grid; gap: 9px; }
.hs .path li { font-size: 14.5px; color: var(--hs-deck-text); display: flex; gap: 10px; align-items: baseline; }
.hs .path li::before { content: ""; width: 6px; height: 6px; background: var(--hs-brand); flex: none; transform: translateY(-2px); }
.hs .path-note {
  margin-top: 22px; padding: 12px 14px; border-left: 2px solid var(--hs-lime);
  background: rgba(146,196,61,.10); font-size: 13.5px; color: var(--hs-deck-ink);
}
.hs .path .btn { margin-top: 22px; }

/* ==========================================================================
   SERVICES

   Photo-led cards, the same component language as the project cards below
   (.proj): a full-bleed image up top in a fixed 4:3 box, a body underneath.
   Reused deliberately rather than invented fresh — the two are visually the
   same kind of tile (a photo the visitor is judging, a link underneath it)
   and sharing one card language makes the page read as one system instead of
   two grids that happen to sit near each other.
   ========================================================================== */

.hs .svc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 18px; }
.hs .svc {
  border-radius: var(--hs-radius-lg); overflow: hidden; border: 1px solid var(--hs-line);
  background: var(--hs-band); text-decoration: none; display: flex; flex-direction: column;
  transition: border-color .18s ease, transform .18s ease;
}
.hs .svc:hover { border-color: var(--hs-brand); transform: translateY(-3px); }
.hs .svc:hover .svc-more { color: var(--hs-brand-text); gap: 12px; }

.hs .svc-photo { aspect-ratio: 4/3; position: relative; overflow: hidden; background: var(--hs-band-alt); }
.hs .svc-photo img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .3s ease;
}
/* A small zoom on hover — cheap to render, and it's the one cue that a photo
   card in particular benefits from: it says "this is the interactive part"
   without relying on the border-colour change alone. */
.hs .svc:hover .svc-photo img { transform: scale(1.045); }

.hs .svc-body { padding: 20px 22px 22px; display: flex; flex-direction: column; flex: 1; }
.hs .svc-body h3 { font-size: 20px; }

/* Directly under the title now, ahead of the description — see the comment
   in hs_services_section() for why the order changed. */
.hs .svc-best {
  font-family: Archivo, sans-serif; font-size: 10.5px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--hs-brand-text); margin-top: 8px;
}
.hs .svc-desc { font-size: 14.5px; color: var(--hs-muted); margin-top: 10px; flex: 1; }
.hs .svc-more {
  font-family: Archivo, sans-serif; font-size: 12px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--hs-ink); margin-top: 14px;
  display: flex; align-items: center; gap: 8px; transition: gap .15s ease, color .15s ease;
}

/* The card that completes the grid — "not sure which one your slab needs?".
   Its own border-radius now that the grid has real gaps instead of hairline
   dividers; it no longer inherits a shared outer border to sit inside. */
.hs .svc-cta {
  grid-column: span 2; background: var(--hs-deck); color: var(--hs-deck-text);
  border-radius: var(--hs-radius-lg); padding: 32px 30px;
  display: flex; flex-direction: column; justify-content: center;
}
/* No max-width on either: the card spans two grid columns, and a 24ch/46ch
   cap left both the heading and the paragraph wrapping into a narrow strip
   with most of the card's own width sitting empty beside them. */
.hs .svc-cta h3 { color: #fff; font-size: 22px; }
.hs .svc-cta p { color: var(--hs-deck-text); font-size: 14.5px; margin-top: 10px; }
.hs .svc-cta .cta-highlight { margin-top: 20px; align-self: flex-start; }

/*
 * A highlighted link, not a button — for a CTA that sits inside a tile that
 * is already visually distinct (the dark svc-cta card among nine white photo
 * cards) and doesn't need a second box drawing attention on top of that.
 * Lime, bold, uppercase and underlined so it still reads unmistakably as the
 * thing to click; reusable anywhere a CTA needs that weight without a fill —
 * min-height matches the .field touch-target rule (44px) so it is exactly as
 * easy to tap as an actual button.
 */
.hs .cta-highlight {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px;
  color: var(--hs-lime);
  text-decoration: none;
  font-family: Archivo, sans-serif;
  font-weight: 700; font-size: 15px; letter-spacing: .05em; text-transform: uppercase;
  transition: color .15s ease, gap .15s ease;
}
.hs .cta-highlight span {
  border-bottom: 1px solid rgba(146,196,61,.45);
  padding-bottom: 2px;
  transition: border-color .15s ease;
}
.hs .cta-highlight:hover { color: var(--hs-lime-hi); gap: 11px; }
.hs .cta-highlight:hover span { border-color: var(--hs-lime-hi); }

/* ==========================================================================
   WHY
   ========================================================================== */

/* Gap is tighter than the old uncontained layout used (34px/40px) — that much
   whitespace was doing the job of separating the four items; a border does
   the same job in less space, so the grid reads as four cards instead of
   four islands of text with a lot of air between them. */
.hs .why { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; }

/*
 * Card fill is --hs-page, not --hs-band: this section's own background
 * (.band-white) IS --hs-band, so a card filled with the same white would
 * show only as a border with nothing to tell it apart from the section
 * behind it. --hs-page is the same subtle off-white every other light card
 * on a white band uses for exactly this reason.
 */
.hs .why-item {
  background: var(--hs-page); border: 1px solid var(--hs-line); border-radius: var(--hs-radius-lg);
  padding: 28px 26px; transition: border-color .18s ease, transform .18s ease;
}
.hs .why-item:hover { border-color: var(--hs-brand); transform: translateY(-3px); }
.hs .why-item h3 { font-size: 19px; margin-bottom: 10px; }
.hs .why-item p { font-size: 14.5px; color: var(--hs-muted); }
.hs .why-mark {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 700; letter-spacing: .16em;
  color: var(--hs-brand-text); display: block; margin-bottom: 12px;
}

/* ==========================================================================
   PROCESS
   ========================================================================== */

.hs .steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0; border-top: 1px solid var(--hs-deck-line); }
.hs .step { padding: 30px 26px 30px 0; border-right: 1px solid var(--hs-deck-line); position: relative; }
.hs .step:last-child { border-right: none; }
.hs .step:not(:first-child) { padding-left: 26px; }
.hs .step-n {
  font-family: Archivo, sans-serif; font-weight: 700; font-size: 12px; letter-spacing: .18em;
  color: var(--hs-lime); display: block; margin-bottom: 14px;
}
.hs .step h3 { font-size: 18px; }
.hs .step p { font-size: 14px; color: var(--hs-deck-text); margin-top: 10px; }
.hs .step-meta {
  margin-top: 14px; font-family: Archivo, sans-serif; font-size: 10.5px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase; color: var(--hs-deck-muted);
}

/* ==========================================================================
   PROJECTS
   ========================================================================== */

.hs .proj-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px; }
.hs .proj {
  border-radius: var(--hs-radius-lg); overflow: hidden; border: 1px solid var(--hs-line);
  background: var(--hs-band); text-decoration: none; display: block;
}
.hs .proj:hover { border-color: var(--hs-brand); }
.hs .proj-img { aspect-ratio: 4/3; position: relative; overflow: hidden; background: var(--hs-band-alt); }
.hs .proj-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hs .proj-badge {
  position: absolute; left: 12px; top: 12px; z-index: 2;
  background: rgba(11,14,17,.86); color: #fff; backdrop-filter: blur(4px);
  font-family: Archivo, sans-serif; font-size: 10px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; padding: 6px 10px; border-radius: 2px;
}
.hs .proj-body { padding: 18px 20px 20px; }
.hs .proj h3 { font-size: 17px; }
.hs .proj-meta { font-size: 13px; color: var(--hs-muted); margin-top: 6px; }

/* ==========================================================================
   PRICING
   ========================================================================== */

.hs .tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 18px; }
.hs .tier { background: var(--hs-band); border: 1px solid var(--hs-line); border-radius: var(--hs-radius-lg); padding: 28px 26px; }
.hs .tier h3 { font-size: 19px; }
.hs .tier-size {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 600; letter-spacing: .13em;
  text-transform: uppercase; color: var(--hs-muted); margin-top: 8px;
}
.hs .tier-price {
  margin: 20px 0 18px; padding: 16px 0;
  border-top: 1px dashed var(--hs-line); border-bottom: 1px dashed var(--hs-line);
  font-family: Archivo, sans-serif; font-size: 26px; font-weight: 700; color: var(--hs-ink);
  font-variant-numeric: tabular-nums;
}
.hs .tier-price small {
  display: block; font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--hs-muted); font-weight: 600; margin-top: 6px;
}
.hs .tier ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.hs .tier li { font-size: 14px; display: flex; gap: 9px; align-items: baseline; color: var(--hs-text); }
.hs .tier li::before { content: ""; width: 5px; height: 5px; background: var(--hs-brand); flex: none; transform: translateY(-2px); }

/* ==========================================================================
   REVIEWS
   ========================================================================== */

.hs .rev-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 18px; }
.hs .rev {
  background: var(--hs-band); border: 1px solid var(--hs-line);
  border-radius: var(--hs-radius-lg); padding: 26px; display: flex; flex-direction: column;
}
.hs .stars { color: var(--hs-star); font-size: 15px; letter-spacing: 3px; }
.hs .rev-quote { margin-top: 14px; font-size: 15px; color: var(--hs-text); flex: 1; font-style: italic; }
.hs .rev-who {
  margin-top: 18px; font-family: Archivo, sans-serif; font-size: 12px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--hs-ink);
}
.hs .rev-where { font-size: 12px; color: var(--hs-muted); letter-spacing: 0; text-transform: none; font-weight: 400; }

/* ==========================================================================
   AREAS
   ========================================================================== */

.hs .area-cols { display: grid; grid-template-columns: minmax(0,.9fr) minmax(0,1.5fr); gap: 48px; align-items: start; }
.hs .area-intro { color: var(--hs-deck-text); margin-top: 16px; font-size: 16.5px; }
.hs .area-cols .btn, .hs .area-cols .cta-highlight { margin-top: 26px; }
.hs .city-group + .city-group { margin-top: 26px; }
.hs .city-group h4 {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 700; letter-spacing: .17em;
  text-transform: uppercase; color: var(--hs-brand); margin-bottom: 14px;
}
.hs .city-list { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; margin: 0; padding: 0; }
/*
 * inline-flex rather than inline-block so the pin sits on the same baseline
 * as the city name. The icon needs no colour rule of its own: it is
 * fill="currentColor", so it already follows the link through every state
 * below — default, hover, and the lime HQ chip — for free.
 */
.hs .city-list a {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 13.5px; text-decoration: none; color: var(--hs-deck-text);
  border: 1px solid var(--hs-deck-line); border-radius: 40px; padding: 7px 14px;
  transition: border-color .15s ease, color .15s ease, background-color .15s ease;
}
.hs .city-pin { flex: none; }
.hs .city-list a:hover { border-color: var(--hs-lime); color: var(--hs-lime); background: rgba(146,196,61,.10); }
/* The HQ chip is lime because "you are here" is an active state, not decoration. */
.hs .city-list a.hq { border-color: var(--hs-lime); color: var(--hs-on-lime); background: var(--hs-lime); font-weight: 600; }

/* On light bands the chips need the light-surface borders instead. */
.hs .band:not(.band-deck) .city-list a { color: var(--hs-text); border-color: var(--hs-line); }
.hs .band:not(.band-deck) .city-list a:hover { color: var(--hs-brand-text); border-color: var(--hs-brand); background: transparent; }

/* ==========================================================================
   FAQ
   ========================================================================== */

.hs .faq { max-width: 860px; margin: 0 auto; border-top: 1px solid var(--hs-line); }
.hs .faq details { border-bottom: 1px solid var(--hs-line); }
.hs .faq summary {
  list-style: none; cursor: pointer; padding: 22px 44px 22px 0; position: relative;
  font-family: Urbanist, "Helvetica Neue", Arial, sans-serif; font-weight: 700; font-size: 17.5px; color: var(--hs-ink);
}
.hs .faq summary::-webkit-details-marker { display: none; }
.hs .faq summary::after {
  content: "+"; position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  font-family: Archivo, sans-serif; font-size: 22px; font-weight: 500; color: var(--hs-brand); line-height: 1;
}
.hs .faq details[open] summary::after { content: "\2212"; }
.hs .faq-body { padding: 0 44px 24px 0; font-size: 15px; color: var(--hs-muted); }
.hs .faq-body p + p { margin-top: 12px; }

/* ==========================================================================
   POSTS
   ========================================================================== */

.hs .post-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: 18px; }
.hs .post {
  background: var(--hs-band); border: 1px solid var(--hs-line);
  border-radius: var(--hs-radius-lg); padding: 26px; text-decoration: none; display: block;
}
.hs .post:hover { border-color: var(--hs-brand); }
.hs .post-cat {
  font-family: Archivo, sans-serif; font-size: 10.5px; font-weight: 700; letter-spacing: .15em;
  text-transform: uppercase; color: var(--hs-brand-text);
}
.hs .post h3 { font-size: 18px; margin-top: 12px; }
.hs .post-meta { font-size: 12.5px; color: var(--hs-muted); margin-top: 12px; }

/* ==========================================================================
   FINAL CTA
   ========================================================================== */

.hs .cta-final { position: relative; overflow: hidden; background: var(--hs-deck); }
.hs .cta-media { position: absolute; inset: 0; }
.hs .cta-media img { width: 100%; height: 100%; object-fit: cover; opacity: .35; }
.hs .cta-final::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, rgba(11,14,17,.94) 30%, rgba(11,14,17,.55) 100%);
}
.hs .cta-final .wrap { position: relative; z-index: 2; padding-top: 74px; padding-bottom: 74px; }
.hs .cta-grid { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,420px); gap: 48px; align-items: center; }
.hs .cta-final h2 { font-size: clamp(28px, 3.6vw, 42px); color: #fff; }
.hs .cta-final p { color: var(--hs-deck-text); margin-top: 16px; font-size: 16.5px; max-width: 46ch; }
.hs .cta-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }
.hs .cta-nap { color: var(--hs-deck-text); font-size: 15px; display: grid; gap: 14px; }
.hs .cta-nap strong {
  color: #fff; font-family: Archivo, sans-serif; letter-spacing: .14em;
  font-size: 11px; text-transform: uppercase; font-weight: 700;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */

.hs .foot { background: var(--hs-deck-2); color: var(--hs-deck-text); padding: 62px 0 0; border-top: 1px solid var(--hs-deck-line); }
.hs .foot-grid { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1.1fr; gap: 40px; }
.hs .foot h4 {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 700; letter-spacing: .17em;
  text-transform: uppercase; color: #fff; margin-bottom: 16px;
}
.hs .foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.hs .foot a { color: var(--hs-deck-text); text-decoration: none; font-size: 14px; }
.hs .foot a:hover { color: var(--hs-lime); }
.hs .foot-nap { font-size: 14px; display: grid; gap: 8px; margin-top: 16px; }
.hs .foot-nap b { color: #fff; font-weight: 600; }
.hs .foot-bottom {
  margin-top: 48px; border-top: 1px solid var(--hs-deck-line); padding: 22px 0 26px;
  display: flex; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  font-size: 12.5px; color: var(--hs-deck-muted);
}

/* ==========================================================================
   STICKY MOBILE BAR
   ========================================================================== */

.hs .mobile-bar {
  display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 80;
  background: var(--hs-deck); border-top: 1px solid var(--hs-deck-line); padding: 10px; gap: 10px;
}
.hs .mobile-bar .btn { flex: 1; padding: 14px 10px; font-size: 12.5px; }

/* ==========================================================================
   BLOG
   ========================================================================== */

/* 68ch measure, per the brief — the readable line length for long-form. */
.hs .entry-content { max-width: 68ch; font-size: 17px; }
.hs .entry-content > * + * { margin-top: 22px; }
.hs .entry-content h2 { font-size: 27px; margin-top: 44px; }
.hs .entry-content h3 { font-size: 21px; margin-top: 34px; }
.hs .entry-content ul, .hs .entry-content ol { padding-left: 22px; display: grid; gap: 8px; }
.hs .entry-content a { color: var(--hs-brand-text); text-decoration: underline; text-underline-offset: 2px; }
.hs .entry-content img { border-radius: var(--hs-radius-lg); }
.hs .entry-content blockquote {
  margin: 0; padding: 4px 0 4px 20px; border-left: 3px solid var(--hs-lime);
  font-size: 18px; color: var(--hs-ink);
}

.hs .post-layout { display: grid; grid-template-columns: minmax(0,1fr) 260px; gap: 56px; align-items: start; }
.hs .toc { position: sticky; top: 106px; }
.hs .toc h4 {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--hs-brand-text); margin-bottom: 14px;
}
.hs .toc ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.hs .toc a { font-size: 13.5px; color: var(--hs-muted); text-decoration: none; }
.hs .toc a:hover { color: var(--hs-brand-text); }

.hs .author-box {
  margin-top: 44px; padding: 24px; border: 1px solid var(--hs-line);
  border-radius: var(--hs-radius-lg); background: var(--hs-band);
}

.hs .pagination { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 40px; }
.hs .pagination .page-numbers {
  padding: 9px 15px; border: 1px solid var(--hs-line); border-radius: 3px;
  text-decoration: none; font-family: Archivo, sans-serif; font-size: 13px; font-weight: 600;
}
.hs .pagination .page-numbers.current { background: var(--hs-lime); color: var(--hs-on-lime); border-color: var(--hs-lime); }

/* ==========================================================================
   INTERIOR PAGES
   Sections used by the service, city, gallery, contact and quote templates.
   See inc/sections-interior.php.
   ========================================================================== */

/* Long body copy: the service intros, the per-city local intros and anything
   pasted into the WordPress editor. Capped in rem rather than ch — ch is
   font-size-relative, so a cap set here in ch would mean something different
   inside a heading than inside a paragraph. 38rem is roughly 70 characters at
   the body size, which is the readable line length these pages need. */
.hs .prose { max-width: 38rem; }
.hs .prose > * + * { margin-top: 18px; }
.hs .prose p { color: var(--hs-text); }
.hs .prose h2 { font-size: 27px; margin-top: 38px; }
.hs .prose h3 { font-size: 20px; margin-top: 30px; }
.hs .prose ul, .hs .prose ol { padding-left: 22px; }
.hs .prose li + li { margin-top: 8px; }
.hs .prose .lede { font-size: 18px; color: var(--hs-ink); }
.hs .prose .best-for {
  display: inline-block; font-family: Archivo, sans-serif; font-size: 12px;
  font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--hs-brand-text); background: rgba(59,130,214,.10);
  border-radius: 3px; padding: 7px 12px;
}

/* The big internal-linking lists: ten services, or thirty-four cities. Columns
   rather than one tall list, because thirty-four stacked links is a screen and
   a half of scrolling past the same shape. auto-fill with a min track keeps it
   one column on a phone with no breakpoint of its own. */
.hs .link-columns {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 2px 28px;
}
.hs .link-columns li { border-bottom: 1px solid var(--hs-line); }
.hs .link-columns a {
  display: block; padding: 11px 2px; font-size: 14.5px;
  color: var(--hs-text); text-decoration: none;
}
.hs .link-columns a:hover { color: var(--hs-brand-text); }
.hs .city-group + .city-group { margin-top: 34px; }
.hs .city-group > h3 {
  font-family: Archivo, sans-serif; font-size: 12px; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--hs-muted);
  margin-bottom: 12px;
}

/* Contact: NAP beside the map. Same two-column shape as .cta-grid, and it
   collapses at the same 760px for the same reason — see the note on that
   breakpoint below. */
.hs .nap-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 48px; align-items: start;
}
.hs .nap h2 { font-size: 27px; margin-bottom: 22px; }

/* No map to sit beside: one column, and the address rows spread across the
   full width rather than stacking down the left in a half-empty band. */
.hs .nap-grid--solo { grid-template-columns: 1fr; }
.hs .nap-grid--solo .nap-rows {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 8px 32px; align-items: start;
}
.hs .nap-grid--solo .nap-row { margin-bottom: 0; }

.hs .nap-row { margin-bottom: 18px; font-size: 15px; color: var(--hs-text); }
.hs .nap-row strong {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--hs-muted);
}
.hs .nap-phone {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: Archivo, sans-serif; font-size: 21px; font-weight: 700;
  color: var(--hs-brand-text); text-decoration: none;
}
.hs .nap-phone:hover { text-decoration: underline; }
.hs .nap-map {
  aspect-ratio: 4 / 3; border: 1px solid var(--hs-line);
  border-radius: var(--hs-radius-lg); overflow: hidden; background: var(--hs-band-alt);
}
.hs .nap-map iframe { width: 100%; height: 100%; border: 0; display: block; }

/* Gallery. The filters are links, so they need to look pressable and to show
   which one is active without relying on colour alone — the active one also
   carries aria-current. */
.hs .filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 28px; }
.hs .filter {
  display: inline-flex; align-items: center; min-height: 40px; padding: 0 16px;
  border: 1px solid var(--hs-control-line); border-radius: 999px; background: var(--hs-band);
  font-family: Archivo, sans-serif; font-size: 13px; font-weight: 600;
  color: var(--hs-text); text-decoration: none;
}
.hs .filter:hover { border-color: var(--hs-brand); color: var(--hs-brand-text); }
.hs .filter.is-active {
  background: var(--hs-lime); border-color: var(--hs-lime);
  color: var(--hs-on-lime); font-weight: 700;
}
.hs .gallery-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 18px;
}
.hs .gallery-item {
  margin: 0; border: 1px solid var(--hs-line); border-radius: var(--hs-radius-lg);
  overflow: hidden; background: var(--hs-band);
}
.hs .gallery-item img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
}
.hs .gallery-item figcaption { padding: 15px 17px; display: grid; gap: 4px; }
.hs .gallery-item strong { font-family: Archivo, sans-serif; font-size: 15px; }
.hs .gallery-item span { font-size: 13px; color: var(--hs-muted); }

/* The JotForm iframe. An iframe cannot size itself to its content from the
   outside, so the height is fixed — too tall shows whitespace, too short hides
   the submit button, and only one of those loses a lead.

   1420px is measured, not guessed: the form rendered on its own comes to
   ~1340px to the bottom of the Submit button, and its height barely changes
   with width because its inner layout does not reflow. The margin on top
   absorbs the hCaptcha challenge box when it expands. Re-measure if the form's
   fields change. */
.hs .form-embed {
  max-width: 700px; margin: 0 auto; border: 1px solid var(--hs-line);
  border-radius: var(--hs-radius-lg); overflow: hidden; background: var(--hs-band);
}
.hs .form-embed iframe { width: 100%; height: 1420px; border: 0; display: block; }
.hs .form-alt {
  max-width: 700px; margin: 22px auto 0; text-align: center;
  font-size: 14.5px; color: var(--hs-muted);
}

.hs .next-steps { counter-reset: step; list-style: none; padding-left: 0; }
.hs .next-steps li {
  counter-increment: step; position: relative; padding-left: 42px; margin-top: 16px;
}
.hs .next-steps li::before {
  content: counter(step); position: absolute; left: 0; top: -2px;
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--hs-lime); color: var(--hs-on-lime);
  font-family: Archivo, sans-serif; font-size: 13px; font-weight: 700;
  display: grid; place-items: center;
}

/* The three explainer blocks on the service-areas hub. Three columns of prose
   rather than one 38rem measure stacked three deep, which on this page would
   push the city index a screen and a half further down. */
.hs .areas-copy {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 38px;
}
.hs .areas-copy h2 { font-size: 21px; margin-bottom: 12px; }
.hs .areas-copy p { font-size: 14.5px; color: var(--hs-text); }
.hs .areas-copy p + p { margin-top: 12px; }

/* Published price / lifespan / install time on a service page. Sits directly
   under the intro prose, full band width rather than inside the .prose column,
   because these three facts are the reason a lot of visitors opened the page
   and should not be buried in a 38rem measure. */
.hs .svc-facts {
  margin-top: 34px; padding-top: 26px; border-top: 1px solid var(--hs-line);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 22px 32px;
}
.hs .svc-fact { display: grid; gap: 5px; }
.hs .svc-fact-k {
  font-family: Archivo, sans-serif; font-size: 11px; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase; color: var(--hs-muted);
}
.hs .svc-fact-v {
  font-family: Archivo, sans-serif; font-size: 23px; font-weight: 700;
  color: var(--hs-brand-text); line-height: 1.15;
}
.hs .svc-facts-note {
  grid-column: 1 / -1; font-size: 13px; color: var(--hs-muted); max-width: 46rem;
}

/* "Where it works" — same card rhythm as .why but without the numbered mark. */
.hs .where-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 18px;
}
.hs .where-item {
  padding: 22px 22px 24px; border: 1px solid var(--hs-line);
  border-radius: var(--hs-radius-lg); background: var(--hs-band);
}
.hs .where-item h3 { font-size: 17px; margin-bottom: 8px; }
.hs .where-item p { font-size: 14.5px; color: var(--hs-muted); }

/* Per-service process. Its own grid rather than the homepage's .steps, which
   is a fixed four-column rule with dividing borders; these sets run from three
   steps (exterior cleaning) to six (flake), and auto-fit handles all of them
   without a count-specific rule per service. */
.hs .proc {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 24px;
}
.hs .proc-step { display: grid; gap: 9px; align-content: start; }
.hs .proc-n {
  display: grid; place-items: center; width: 34px; height: 34px; border-radius: 50%;
  background: var(--hs-lime); color: var(--hs-on-lime);
  font-family: Archivo, sans-serif; font-size: 13px; font-weight: 700;
}
.hs .proc-step h3 { font-size: 17px; }
.hs .proc-step p { font-size: 14px; color: var(--hs-deck-text); }

/*
 * The focus pages' stripped chrome — see hs_is_focus_page().
 *
 * These pages render the masthead without a dock around it (there is no burger
 * and no drawer to keep attached to it), so the focus header carries its own
 * sticky. It needs one: the phone number is the only alternative to filling in
 * the form, and on a long quote page it would otherwise scroll away at exactly
 * the point someone gives up on the form.
 */
.hs .masthead--focus { position: sticky; top: 0; z-index: 60; }
.hs .masthead--focus .wrap { justify-content: space-between; }
.hs .focus-call {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  font-family: Archivo, sans-serif; font-size: 16px; font-weight: 700;
  color: var(--hs-deck-ink); text-decoration: none;
}
.hs .focus-call:hover { color: var(--hs-lime); }
.hs .foot--focus { padding-top: 26px; padding-bottom: 26px; }
.hs .foot--focus .foot-bottom { border-top: 0; margin-top: 0; padding-top: 0; }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */

@media (max-width: 1080px) {
  .hs .area-cols { grid-template-columns: 1fr; gap: 34px; }

  /*
   * Narrower, not collapsed. Jumping straight from a 420px NAP column to a
   * single full-width stack left a real gap in the middle of the range: the
   * short copy and the NAP block both sat left-aligned in an increasingly
   * wide column, using less and less of the width the wider the viewport
   * actually got, down to roughly 800px where it looked worst. A 240px NAP
   * column keeps the two-column arrangement working — tested down to
   * 760px before the quote/call buttons start wrapping — so the layout
   * keeps using its own width instead of degrading early. It only drops to
   * a true single column at 860px, in the same breakpoint mobile nav uses.
   */
  .hs .cta-grid { grid-template-columns: minmax(0,1fr) minmax(180px,240px); gap: 32px; }
  .hs .foot-grid { grid-template-columns: 1fr 1fr; }
  .hs .steps { grid-template-columns: 1fr 1fr; }
  .hs .step { border-bottom: 1px solid var(--hs-deck-line); }
  .hs .step:nth-child(2n) { border-right: none; }
  .hs .post-layout { grid-template-columns: 1fr; gap: 32px; }
  .hs .toc { position: static; }
}

@media (max-width: 860px) {
  .hs nav.primary { display: none; }

  /*
   * The auto margin has to sit on .head-cta, not on .burger.
   *
   * .burger is a child of .head-cta, and .head-cta is shrink-to-fit around it,
   * so margin-left:auto there had no free space to absorb and did nothing. The
   * element that needs pushing is .head-cta itself, inside .masthead .wrap —
   * and it was given a fixed 12px instead, which parked the burger flush
   * against the logo with the entire right half of the header empty.
   */
  .hs .burger { display: flex; margin-left: 0; }
  .hs .head-cta { margin-left: auto; }

  .hs .paths { grid-template-columns: 1fr; }
  .hs .proof .wrap { grid-template-columns: 1fr 1fr; }
  .hs .band { padding: 60px 0; }
  .hs .mobile-bar { display: flex; }
  /* Reserve the bar's height so it can never cover the footer. */
  body.hs { padding-bottom: var(--hs-stickybar-h); }
}

@media (max-width: 660px) {
  .hs .svc-cta { grid-column: span 1; }
}

@media (max-width: 620px) {
  /* Keep the token in step with the actual height — the drawer measures
     itself against it. */
  :root { --hs-header-h: 66px; }
  .hs .masthead .wrap { gap: 12px; height: 66px; }
  .hs .logo { min-width: 0; }
  .hs .logo img { height: 34px; }
  .hs .hero .wrap { padding-top: 44px; padding-bottom: 44px; }

  /*
   * The quote button leaves the masthead here, not at 860px.
   *
   * Between 620 and 860 there is room for the logo, the button and the burger
   * with space to spare — a 768px tablet had a half-empty header and no visible
   * CTA at all. Below 620 the row genuinely runs out of width, and the sticky
   * bottom bar is already carrying both the quote and the call from 860 down,
   * so nothing is lost by dropping it here.
   */
  .hs .head-cta .btn { display: none; }
}

/*
 * .cta-grid's own breakpoint, not folded into the 860px block above. 860px
 * is where the mobile nav and sticky bar switch on — unrelated reasons — and
 * reusing it here would drop this grid to a single column earlier than the
 * content needs to: the quote/call buttons stay side by side with the
 * narrower 240px NAP column down to 760px (tested directly), so collapsing
 * any earlier than that gives up width the layout could still use.
 */
@media (max-width: 760px) {
  .hs .cta-grid { grid-template-columns: 1fr; }
  /* Same reasoning as .cta-grid: a two-column NAP-and-map split holds up
     until the map gets too narrow to read street names, which is right about
     here. */
  .hs .nap-grid { grid-template-columns: 1fr; gap: 34px; }
}

@media (max-width: 700px) {
  .hs .u-area { display: none; }
}

@media (max-width: 560px) {
  .hs .steps { grid-template-columns: 1fr; }
  .hs .step { border-right: none; padding-left: 0 !important; }
  .hs .foot-grid { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .hs *, .hs *::before, .hs *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
}
