/* ── responsive ─────────────────────────────────────────── */
@media (max-width:1120px){
  .feature-quad{grid-template-columns:repeat(2,1fr)}
  .cards{grid-template-columns:repeat(2,1fr)}
  .card-wide{grid-column:span 2}
  .steps,.cost-grid{grid-template-columns:repeat(2,1fr)}
  .glass-stats{grid-template-columns:repeat(2,1fr)}
  .glass-stats li:nth-child(2){border-right:0}
  .glass-stats li:nth-child(-n+2){border-bottom:1px solid var(--line)}
  .foot-grid{grid-template-columns:1fr 1fr}

  /* the inline nav does not fit; it moves into the panel behind the burger */
  .nav{display:none}
  .burger{display:inline-flex}
  .codes-foot{align-items:flex-start}
}
@media (max-width:860px){
  .feature-pair{grid-template-columns:1fr}
  /* minmax(0,1fr) rather than 1fr, and it is load-bearing.

     A bare `1fr` track has an automatic minimum of min-content, so a single child that cannot wrap
     sets the width of the whole column and every sibling stretches to match it. The hero has
     exactly such a child: .kicker is an inline-flex pill that does not wrap above 370px, and the
     moment the blog handed it a long category name — "MAINTENANCE & PREVENTION", uppercase at
     .26em tracking — the track went to 493px inside a 350px container and took the lede and the
     booking form with it.

     🔴 A scrollWidth check did not catch it. .hero clips its overflow for the photograph, so the
     document reported no horizontal scroll while a third of the copy sat outside the screen.
     Measure elements against their container; measuring the document against the viewport misses
     everything that is clipped rather than scrolled. */
  .hero-inner,.codes-grid,.card-wide-inner{grid-template-columns:minmax(0,1fr)}

  /* And the pill folds from here rather than only at 370px. Clipping a label is a better failure
     than overflowing with it, but wrapping is not a failure at all. */
  .kicker{flex-wrap:wrap;letter-spacing:.18em;line-height:1.6}

  /* Stacked, the hero was heading → lede → buttons → four stat tiles → booking form, and on a
     390-wide screen those tiles are 464 pixels of them. Measured on the device rather than in the
     stylesheet: the form landed at 1195px, a screen and a half down, on a site whose owner asked
     for the form on every page and high up because the site exists to produce leads.
     
     So on a stacked hero the form comes before the numbers. The copy column becomes display:
     contents so its children and the form are siblings in one grid and can be ordered against each
     other — and the reorder is safe for the keyboard, because the only thing that moves past the
     form is a list of statistics with nothing focusable in it.
     
     row-gap goes to zero because every child already carries its own margin; a grid gap sized for
     two columns applied between six stacked blocks loosens the whole first screen. */
  .hero-inner-form{row-gap:0}
  .hero-inner-form > .hero-copy{display:contents}

  /* 🔴 row-gap:0 above assumes every child brings its own spacing, and that is true of the copy —
     each of those elements has a margin-bottom. It is NOT true of the two reordered children: the
     form and the stats both sit flush against whatever lands above them. The stats were given a
     margin below; the form was not, so the buttons ended up welded to the top of the booking panel
     with a measured gap of exactly 0 while every other pair in the hero had 17 to 35px.

     Same value as the stats, so the stacked hero keeps one rhythm. */
  .hero-inner-form > .glass-form{order:2;margin-top:clamp(1.6rem,1.2rem + 1.4vw,2.4rem)}
  .hero-inner-form .glass-stats{order:3;margin-top:clamp(1.6rem,1.2rem + 1.4vw,2.4rem)}

  /* the desktop scrim is angled: dark on the left where the copy sits, clear on the
     right where the photograph does the work. Stacked, that angle is meaningless, so
     it becomes vertical — but at the old .86/.94 the photograph disappeared entirely
     and every phone got a flat charcoal slab instead of the design. These values were
     checked for AA: white on the lightest band is ~5:1 even over a bright daylight frame. */
  .hero-media img{object-position:center 38%}
  .hero-media::after{
    background:
      linear-gradient(to bottom,
        color-mix(in srgb,var(--scrim) 70%,transparent) 0 30%,
        color-mix(in srgb,var(--scrim) 58%,transparent) 55%,
        color-mix(in srgb,var(--scrim) 80%,transparent) 82%,
        var(--night) 100%),
      radial-gradient(80% 34% at 72% 6%,color-mix(in srgb,var(--scrim-glow) 14%,transparent),transparent 62%);
  }
  /* On a phone the copy runs the full width of a daylight photograph instead of sitting in a
     darkened left column, so the bright variant needs more of the scrim, not less. */
  .hero-bright .hero-media::after{
    background:
      linear-gradient(to bottom,
        color-mix(in srgb,var(--scrim) 86%,transparent) 0 34%,
        color-mix(in srgb,var(--scrim) 78%,transparent) 60%,
        color-mix(in srgb,var(--scrim) 88%,transparent) 84%,
        var(--night) 100%),
      radial-gradient(80% 34% at 72% 6%,color-mix(in srgb,var(--scrim-glow) 10%,transparent),transparent 62%);
  }

  .showcase-inner{justify-content:stretch}
  .glass-panel{max-width:none}
  .coverage{grid-template-columns:1fr}
  .citylist{columns:3}
  .head-cta .tel{display:none}
  body{padding-bottom:calc(64px + env(safe-area-inset-bottom,0px))}
  .sticky-call{
    display:block;position:fixed;inset:auto 0 0 0;z-index:60;
    background:var(--brass);color:var(--on-accent);text-align:center;text-decoration:none;
    padding:1.05rem;padding-bottom:calc(1.05rem + env(safe-area-inset-bottom,0px));
    font-weight:700;
  }
}
@media (max-width:560px){
  /* 23 pixels tall is under every guideline for something a thumb has to hit. The text stays the
     size it is; the box around it grows. */
  .crumbs a{display:inline-block;padding:.72rem 0}
  /* The byline's links are the same problem: a line of small type with a category, an author and a
     date in it, each of them tappable and each about eleven pixels tall on its own. */
  .article-meta a{display:inline-block;padding:.5rem 0}
  .crumbs{gap:.2rem .5rem}

  /* WCAG 2.2 AA asks for 24 by 24. Measured on the device, the header's phone link came out at 19
     and every card's read-more link at 23 — under it by a hair, which is the kind of miss a
     stylesheet never shows you. The type does not change; the box around it does. */
  .site-head .tel{display:inline-flex;align-items:center;min-height:24px}
  .ghost-link{min-height:24px}
  /* The coverage lists are a hundred place names, and every one of them was 19px tall. */
  .citylist a,.county h3 a,.hoodlist a,.legal-links a,.site-foot nav a{display:inline-block;min-height:24px}
  /* A phone number linkified inside a sentence is exempt — 2.5.8 excludes targets that are inline
     in a block of text — and padding one would break the line it sits in. */
  .citylist li{margin-bottom:.15rem}

  .feature-quad{grid-template-columns:1fr}
  .cards,.steps,.cost-grid,.glass-stats{grid-template-columns:1fr}
  .card-wide{grid-column:auto}
  .glass-stats li{border-right:0;border-bottom:1px solid var(--line)}
  .glass-stats li:last-child{border-bottom:0}
  .citylist{columns:2}
  .foot-grid{grid-template-columns:1fr;gap:2rem}

  /* two half-width pills side by side leave a ragged edge on a phone;
     full width also gives the primary action a proper thumb target */
  .hero-actions{gap:.7rem}
  .hero-actions .btn{flex:1 0 100%;justify-content:center}
  .cta-actions .btn{flex:1 0 100%;justify-content:center}

  .legal-links{gap:.5rem 1.1rem}

  /* the header keeps the brand and the burger; booking lives in the panel and in
     the sticky call bar, so the bar does not get crowded on a small phone */
  .head-cta .btn{display:none}
  .decoder{grid-template-columns:1fr}
  .dec-part{display:flex;align-items:baseline;gap:1rem;padding:.95rem 1.1rem}
  .dec-part b{min-width:3.2rem}
  .dec-part span{margin-top:0}
  .dec-part em{margin-top:.1rem}
  .fmt li{flex-direction:column;gap:.35rem}
  .fmt code{min-width:0}
  .codes-foot .btn{width:100%;justify-content:center}
}
/* the 320-360 band only. At 390 (the common iPhone width) the county line and the
   full-size headline both still fit, and stepping them down there just made the
   hero look timid on the most popular phone on the market. */
@media (max-width:370px){
  .citylist{columns:1}
  /* the county line is the widest unwrappable string on the page; let it fold */
  .kicker{
    flex-wrap:wrap;letter-spacing:.14em;font-size:.64rem;
    padding:.45rem .85rem;line-height:1.6;
  }
  /* "to temperature." is held together by a non-breaking space so that "to" is
     never stranded on its own line. At 320 that phrase is wider than the column,
     so the type steps down rather than the phrase breaking apart. */
  .hero h1{font-size:2.1rem}
}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation:none !important;transition-duration:.01ms !important}
}


@media (max-width:860px){
  /* Four pills fit on a phone; eight would take four rows and push the list itself off the screen.
     A scrolling row keeps the filter one line tall however many groups a brand ends up with. */
  .code-pills{
    flex-wrap:nowrap;overflow-x:auto;scroll-snap-type:x proximity;
    margin-inline:calc(var(--pad,1.25rem) * -1);padding-inline:var(--pad,1.25rem);
    /* 🔴 Without this the padding above is thrown away. scroll-snap aligns a pill to the edge of
       the scrollport, and the scrollport's edge ignores padding — so the row silently scrolled
       itself by exactly the padding and the first pill sat flush against the screen while every
       card below it was inset. The margin and padding were right all along; the snapping undid
       them. Measured as scrollLeft:20 on a row nobody had touched. */
    scroll-padding-inline:var(--pad,1.25rem);
    scrollbar-width:none;
  }
  .code-pills::-webkit-scrollbar{display:none}
  .code-pill{flex:0 0 auto;scroll-snap-align:start}
}
