/* ============================================================
   cleanouts.css — the /cleanouts landing page

   Loaded AFTER v2.css and junk-removal.css, and only by /cleanouts/.
   Everything shared comes from those two: the colour tokens, the
   header, the footer, the quickbar and the type scale from v2.css;
   .shead, .btn, .shero, .bax, .faq and .cta from junk-removal.css,
   whose own header says it is deliberately generic and meant to be
   loaded by any service page. (.hsteps and .jrevs were used here too
   until 2026-09-12; How It Works and Reviews are now the page-local
   .cflow and .grevs below.)

   THIS FILE IS ONLY WHAT THE CLEANOUTS PAGE ADDS. If a rule here
   would be useful to a second page, it belongs in junk-removal.css
   instead — but move it deliberately, because that file is loaded by
   a page that currently ranks.

   ------------------------------------------------------------
   SECTION BACKGROUND RHYTHM — read this before changing any
   background on this page.

   The standing rule from junk-removal.css: NO TWO ADJACENT SECTIONS
   SHARE A BACKGROUND. That is what stops a fourteen-section page
   reading as one long scroll. The page is also a LIGHT page, which
   is a standing client instruction rather than a preference here.

     hero        dark photograph    .shero
     what it is  white              .ctrust
     what we clear surface          .tracks     twelve .cotype cards
     included    white              .incl
     before/after  surface          .bax        (its own default)
     how it works  white            .cflow
     what it costs surface          .cost
     reviews     white              .grevs
     quote form  DARK               .qform      gradient + noise
     areas       white              .areas
     faq         surface            .faq        OVERRIDDEN, see below
     final cta   white              .cta        OVERRIDDEN, see below
     footer      dark               .sfoot

   REVISED 2026-09-12. The "which one" comparison section (.choose,
   white) sat between Before & After and How It Works and was removed
   at the client's request. Taking it out put two surface sections
   next to each other, so the three sections below it that were being
   rebuilt anyway flipped: How It Works to white, What It Costs to
   surface (its cards to white), Reviews to white. Nothing that was
   not already in the brief changed colour.

   Two of the rows above are overrides of a junk-removal.css default
   and they are the only two: .faq ships white and .cta ships
   --surface there, and on THIS page's order both would collide with
   the section above them. They are one line each and they are marked.
   Changing any other background means re-checking the whole column.

   ------------------------------------------------------------
   THE DARK-SECTION RULE. There is exactly one dark fill above the
   footer on this page — .qform — and it is a two-stop gradient with
   a .noise-overlay div on top at opacity .035. A FLAT dark fill is
   what the display pipeline (GPU driver, Windows colour management,
   panel firmware) spatial-dithers into a faint diagonal hairline
   running the full width of the band, at a slope of about 0.13. The
   gradient and the noise give the dither nothing to latch onto. The
   noise div is load-bearing markup, not decoration — do not drop it,
   and do not "simplify" the gradient to a solid.
   ============================================================ */


/* ============================================================
   PAGE TOKENS
   ============================================================ */
.ctrust,
.tracks,
.incl,
.cflow,
.cost,
.grevs,
.qform,
.areas {
  /* Same rail and section padding as every junk-removal.css section,
     read from that file's :root rather than redeclared, so a change
     there moves this page too. */
  padding: var(--sec-pad) 20px;
}

.ctrust__inner,
.tracks__inner,
.incl__inner,
.cflow__inner,
.cost__inner,
.grevs__inner,
.qform__inner,
.areas__inner {
  max-width: var(--rail);
  margin: 0 auto;
}


/* ------------------------------------------------------------
   EYEBROW CONTRAST — a fix, not a restyle.

   junk-removal.css puts .shead__eyebrow on --accent-green #71B745
   and its own comment calls that "a live accessibility bug": the
   green measures 2.24:1 on --surface and 2.46:1 on white, and it is
   14-18px text, so it needs 4.5:1. That file already carries the
   value that fixes it — --after-ink #176928, which measures 6.20:1
   on --surface and 6.80:1 on white — and says so.

   This page uses it. The fix is scoped to this page rather than
   applied in junk-removal.css because that file is loaded by a page
   that ranks and a colour change there is the client's call, not a
   side effect of building a new page. Take it site-wide when
   somebody picks that bug up.

   ON THE DARK SECTION THE GREEN IS FINE and stays: #71B745 on
   #131B2E measures 7.4:1. --after-ink on the same ground would be
   2.2:1 and unreadable, so .qform explicitly opts back out. */
.ctrust .shead__eyebrow,
.tracks .shead__eyebrow,
.incl .shead__eyebrow,
.cflow .shead__eyebrow,
.cost .shead__eyebrow,
.grevs .shead__eyebrow,
.areas .shead__eyebrow,
.faq .shead__eyebrow,
.bax__eyebrow {
  color: var(--after-ink);
}
.qform .shead__eyebrow { color: var(--accent-green); }


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

   .shero itself, its photograph, its scrim, its title and its lede
   are all junk-removal.css's and are untouched. This page adds two
   things to the centred column: a locality eyebrow above the H1 and
   a row of proof chips below the buttons.
   ============================================================ */

/* THE SCRIM IS STRONGER HERE THAN junk-removal.css's, AND IT WAS
   MEASURED RATHER THAN GUESSED. That file's own note says "IF THE
   PHOTOGRAPH CHANGES, RE-MEASURE", so this is that measurement.

   Its ellipse — 78% x 62% at 50% 50%, falling to 2% at the edges —
   was tuned for gallery-12.jpg, a frame whose bright areas are sky
   ABOVE the type and a fence BEHIND a single subject. cta-cleanout.webp
   is a different problem: the bright pixels are distributed through
   the middle of the frame (a white mattress, pale cartons, a chrome
   shopping cart) exactly where the headline sits, and the crop lands
   on different parts of them at every aspect ratio.

   Measured with the repo's own method — record the copy's real boxes,
   hide the copy, screenshot the untouched background, take the p90
   luminance (the near-worst realistic backdrop, not the flattering
   mean) and compute the ratio against white. WCAG floors: 3.0 for the
   headline, which is large text, 4.5 for everything else.

   With junk-removal.css's scrim, unmodified:

                 1920   1440   1180    820    390    375   floor
     eyebrow     4.30   5.65   5.77   2.98   2.50   2.47    4.5
     headline    5.12   5.60   5.33   6.12   2.79   2.75    3.0
     lede        6.79   8.15   8.36   8.23   5.45   5.66    4.5
     chips       7.09  14.59  12.24  14.32  12.56  12.70    4.5

   Five failures, and the two on a phone are the ones that matter:
   the H1 itself was under its floor on the width most of this page's
   traffic arrives at.

   THE FIX IS A SECOND LAYER, NOT A BIGGER ELLIPSE. Widening the
   ellipse darkens the mid-zone between the centre and the edges,
   which is the exact thing junk-removal.css's note says made an
   earlier scrim read as a tint on the photograph. A soft vertical
   veil weighted to the top and bottom instead leaves the centre of
   the picture — the pile itself, the thing worth looking at — close
   to untouched, and puts the density where the eyebrow and the
   headline actually sit. The ellipse underneath is kept and only
   slightly deepened.

   After, same method, same boxes, p90 again:

                 1920   1440   1180    820    390    375   floor
     eyebrow     9.21  10.69  10.86   6.14   6.18   6.19    4.5
     headline    9.34   9.81   9.43   9.28   6.14   6.11    3.0
     lede       10.99  12.09  12.26  11.33   8.49   8.65    4.5
     chips      11.21  16.57  15.25  15.96  15.33  15.45    4.5

   Every cell clears its floor, and the phone column clears it by
   about 2x rather than by 4x — which is the point. The first attempt
   at the mobile veil bought 10.44 on the headline and turned the
   photograph into a dark texture; it was backed off until the pile,
   the cartons and the shopping cart read as objects again. Contrast
   you cannot see the picture through is not free.

   RE-MEASURE IF THE PHOTOGRAPH CHANGES. The script that produces the
   table above is the same method as tools/luma-v2.js. */
.shero__scrim {
  background:
    radial-gradient(ellipse 86% 70% at 50% 48%,
                    rgba(8, 14, 28, .70)  0%,
                    rgba(8, 14, 28, .40) 58%,
                    rgba(8, 14, 28, .04) 100%),
    linear-gradient(180deg,
                    rgba(8, 14, 28, .46)  0%,
                    rgba(8, 14, 28, .16) 38%,
                    rgba(8, 14, 28, .16) 62%,
                    rgba(8, 14, 28, .40) 100%);
}

/* A PHONE IS A DIFFERENT PHOTOGRAPH. At 375 the cover crop throws
   away most of the frame's width and lands the type on the pale
   cartons and the mattress, which is where the two failures above
   came from. The band is also short enough that the type fills it,
   so there is no "rest of the picture" left to protect — the veil
   can be flat and heavy without costing anything. */
@media (max-width: 700px) {
  .shero__scrim {
    background:
      radial-gradient(ellipse 120% 70% at 50% 46%,
                      rgba(8, 14, 28, .58)  0%,
                      rgba(8, 14, 28, .44) 60%,
                      rgba(8, 14, 28, .22) 100%),
      linear-gradient(180deg,
                      rgba(8, 14, 28, .40)  0%,
                      rgba(8, 14, 28, .20) 40%,
                      rgba(8, 14, 28, .20) 60%,
                      rgba(8, 14, 28, .40) 100%);
  }
}

/* Above the H1 rather than below it, so the first thing read on a
   page reached from a local search is the locality. Small, spaced
   and quiet — it is a label, not a line of copy. */
.shero__eyebrow {
  margin: 0 0 18px;
  font-size: clamp(13px, 1.1vw, 15px);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  /* Not --accent-green: this sits at the top of the scrim ellipse
     where the photograph is at its brightest, and the green loses.
     White at 88% keeps it subordinate to the headline without
     dropping below the ratio the scrim was measured for. */
  color: rgba(255, 255, 255, .88);
}

/* THREE BUTTONS, NOT TWO, so wrapping is the normal case rather than
   the exception. junk-removal.css's .shero__actions already wraps
   and centres; this only tightens the gap so three pills fit on one
   line at 1024 and break to 2 + 1 rather than 1 + 1 + 1 at 768. */
.shero__actions { gap: 12px; }

.shero__chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px 22px;
  margin: clamp(26px, 3.4vh, 40px) 0 0;
  padding: 0;
  list-style: none;
}

.shero__chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: clamp(13px, 1vw, 15px);
  font-weight: 600;
  line-height: 1.3;
  /* Full white, not the 82% the lede uses. These sit lowest in the
     ellipse, where the scrim has already fallen off to almost
     nothing, and they are the smallest type on the photograph. */
  color: #FFFFFF;
  text-shadow: 0 1px 12px rgba(8, 14, 28, .55);
}

.shero__chip svg {
  width: 16px;
  height: 16px;
  flex: none;
  fill: var(--accent-green);
}


/* ============================================================
   .ctrust — "a cleanout is the whole space"

   A spacer with a job. It is the shortest section on the page and
   the most important 40 words on it: most people searching for a
   cleanout have not settled on cleanout vs junk removal vs dumpster,
   and the ones who guess wrong bounce. Deliberately typographic —
   no photograph, no cards, nothing to look at but the sentence.
   ============================================================ */
.ctrust {
  background: #FFFFFF;
  text-align: center;
}

.ctrust__inner { max-width: 940px; }

.ctrust__title {
  margin: 0;
  font-family: var(--font);
  font-weight: 300;
  font-size: clamp(26px, 3vw, 40px);
  line-height: 1.12;
  letter-spacing: -.04em;
  color: var(--head-ink);
  text-wrap: balance;
}

.ctrust__copy {
  margin: 22px 0 0;
  font-size: clamp(16px, 1.15vw, 18px);
  font-weight: 500;
  line-height: 1.65;
  color: var(--body-ink);
  text-wrap: pretty;
}

.ctrust__meta {
  margin: 26px 0 0;
  padding-top: 22px;
  border-top: 1px solid #E4E7EE;
  font-size: 15px;
  font-weight: 500;
  color: var(--body-ink);
}
.ctrust__meta strong { color: var(--head-ink); font-weight: 700; }


/* ============================================================
   .tracks / .cotype — "What We Clear", twelve service cards

   One card per cleanout service, and each card is exactly three
   things: photograph, name, one sentence. No chips, tags or lists —
   that was the client's brief on 2026-09-12, and the markup comment
   explains the photograph choices.

   CARD GEOMETRY. The photograph is a fixed 3:2 box, so every card's
   image is the same height at a given width no matter what the file's
   own proportions are. With a 21px title and three lines of 15px copy
   underneath, the image is ~62% of the card at 1440 and ~60% at 768
   and 375 — inside the 55-65% the brief asked for. 4:3 was tried on
   paper first and came out at ~66-69%.

   THREE / TWO / ONE. Three columns down to 961, two down to 641, one
   below that. The two-column band deliberately runs through 768
   (portrait tablet) rather than collapsing there like the other grids
   on this page used to: at 768 each card is ~352px, which still gives
   the photograph real size.

   Radius and border are the page's existing card values (20px,
   #E4E7EE); the hover is a 3px lift, a soft shadow and a 3% image
   scale, desktop pointers only, off under reduced motion.
   ============================================================ */
.tracks { background: var(--surface); }

.cotypes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
  margin-top: 46px;
}

.cotype {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid #E4E7EE;
  border-radius: 20px;
  background: #FFFFFF;
  transition: transform .25s ease, box-shadow .25s ease;
}

.cotype__media {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: #1A2338;   /* holds the box while the photo decodes */
}

.cotype__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
  display: block;
  transition: transform .45s ease;
}

/* THE CLIENT'S haul-*.webp EXPORTS HAVE A CAPTION PLATE BURNED INTO
   THE BOTTOM ~12.3% OF THE PIXELS (measured on haul-homes.webp,
   459x424). Anchoring the crop to the top is enough to lose it at 3:2:
   a 459x424 frame covering a 3:2 box is scaled to the box's width, and
   the box then shows only the top ~72% of the frame's height — the
   plate starts at 87.7%. Same files and same reason as .clears__shot
   in junk-removal.css.

   THEY ALSO CARRY 4px OF PURE BLACK DOWN THE RIGHT EDGE (measured: the
   last four pixel columns of all four files average 0 luminance, the
   fifth is picture). Left alone that is a dark hairline along the right
   side of the card. The element is 102% wide and anchored left, so the
   strip — 0.87% of the frame — lands in the 2% that .cotype__media
   clips. */
.cotype__img--plate {
  right: auto;
  width: 102%;
  object-position: 50% 0;
}

.cotype__body {
  flex: 1 1 auto;
  padding: 22px 24px 26px;
}

.cotype__title {
  margin: 0 0 8px;
  font-family: var(--font);
  font-weight: 600;
  font-size: clamp(18px, 1.45vw, 21px);
  line-height: 1.2;
  letter-spacing: -.02em;
  color: var(--head-ink);
}

.cotype__desc {
  margin: 0;
  font-size: 15px;
  font-weight: 500;
  line-height: 1.6;
  color: var(--body-ink);
  text-wrap: pretty;
}

@media (hover: hover) and (pointer: fine) {
  .cotype:hover {
    transform: translateY(-3px);
    box-shadow: 0 14px 34px rgba(11, 18, 38, .10);
  }
  .cotype:hover .cotype__img { transform: scale(1.03); }
}

.tracks__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  margin-top: 40px;
}


/* ============================================================
   .incl — what's included / what we cannot take

   TWO PANELS, AND THE SECOND IS NOT AN AFTERTHOUGHT. A cleanout
   quote goes wrong when the crew arrives to half a garage of paint
   cans, so the exclusions sit beside the inclusions rather than
   three screens down in an FAQ answer.
   ============================================================ */
.incl { background: #FFFFFF; }

.incl__grid {
  display: grid;
  /* 1.15fr / 1fr rather than even halves: the "in the price" column
     carries nine items to the other's six plus two paragraphs, and
     even halves left it noticeably shorter. */
  grid-template-columns: 1.15fr 1fr;
  gap: 22px;
  margin-top: 44px;
}

.incl__panel {
  padding: 34px 32px;
  border-radius: 20px;
}

.incl__panel--yes {
  border: 1px solid #CFE3D6;
  background: #F4FAF6;
}

.incl__panel--no {
  border: 1px solid #E4E7EE;
  background: var(--surface);
}

.incl__head {
  margin: 0 0 22px;
  font-family: var(--font);
  font-weight: 700;
  font-size: 18px;
  letter-spacing: -.01em;
  color: var(--head-ink);
}

.incl__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.incl__list li {
  position: relative;
  padding: 0 0 0 30px;
  margin-bottom: 13px;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.55;
  color: var(--body-ink);
}
.incl__list li:last-child { margin-bottom: 0; }

/* CSS marks rather than inline SVG or an emoji. Two lists of nine
   and six would be 15 repeated <svg> blocks in the markup for a
   glyph that carries no information a screen reader needs — the
   heading above each list already says which list it is. */
.incl__list li::before {
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
}

.incl__panel--yes .incl__list li::before {
  content: '\2713';           /* check mark */
  background: #176928;
  color: #FFFFFF;
}

.incl__panel--no .incl__list li::before {
  content: '\00D7';           /* multiplication sign, i.e. a cross */
  background: #D7DCE6;
  color: #3C4358;
  font-size: 14px;
}

.incl__note {
  margin: 0 0 22px;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.6;
  color: #5A6076;
}
.incl__note--tail {
  margin: 22px 0 0;
  padding-top: 20px;
  border-top: 1px solid #DDE2EC;
}


/* ============================================================
   .bax--centered — Before & After, centred head, no captions

   A MODIFIER, NOT AN EDIT TO .bax. junk-removal.css owns the band and
   /junk-removal-page keeps its left-aligned head row. Here the head
   becomes a full-width centred column: eyebrow, title, then the count
   and arrows underneath. Centring the title inside the old row would
   not centre it on the page, because the controls take the right-hand
   side of that row.

   The per-slide job captions (.bax__cap) were removed from the markup
   on 2026-09-12, so there is nothing under the photographs but the
   BEFORE / AFTER labels, and no gap to reserve for them.
   ============================================================ */
.bax--centered .bax__top {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  text-align: center;
  margin-bottom: clamp(20px, 2vw, 28px);
}
.bax--centered .bax__head { width: 100%; }
/* balance is safe here and not on /junk-removal-page: centred type
   that wraps to two ragged lines looks broken, left-aligned type does
   not. */
.bax--centered .bax__title { text-wrap: balance; }
.bax--centered .bax__nav { justify-content: center; }


/* ============================================================
   .cflow — How It Works, one connected four-step flow

   Page-local replacement for .hsteps (see the markup comment). The
   geometry every connector depends on is three numbers, so they are
   custom properties rather than repeated magic values:

     --mark   the ring's diameter
     --halo   white space kept clear around each ring
     --gap    the column gap between steps

   DESKTOP. Four equal columns. Each step except the last draws its
   connector in ::after, starting at the right edge of its own ring
   (50% + half a ring + halo) and running to the left edge of the next
   ring. Equal columns put the next ring's centre exactly one column
   plus one gap to the right, so the width is (100% + gap) minus one
   ring minus two halos — exact at every width, no approximated rail.
   It sits at the ring's vertical centre, a row that contains nothing
   but the rings; the numerals are above it and the titles below.

   PHONE (<= 860). The same list becomes a two-column grid per step:
   the ring in a narrow marker column, numeral + title + copy beside
   it. The connector turns vertical, runs down the marker column from
   under this ring to the top of the next one, and never enters the
   text column.
   ============================================================ */
.cflow {
  --mark: 76px;
  --halo: 10px;
  --gap: 32px;
  background: #FFFFFF;
}

.cflow__steps {
  list-style: none;
  margin: 52px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--gap);
}

.cflow__step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.cflow__num {
  display: block;
  height: 20px;
  margin-bottom: 14px;
  font-family: var(--font);
  font-size: 14px;
  font-weight: 700;
  line-height: 20px;
  letter-spacing: .14em;
  color: var(--after-ink);
  font-variant-numeric: tabular-nums;
}

.cflow__mark {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  flex: none;
  width: var(--mark);
  height: var(--mark);
  border: 1.5px solid #D5DEEF;
  border-radius: 50%;
  background: #F4F7FD;
  box-shadow: 0 8px 22px rgba(47, 111, 229, .10);
}

.cflow__icon {
  width: 32px;
  height: 32px;
  fill: var(--blue);
}

/* Connector, desktop: see the header note for the arithmetic. top is
   the numeral row (20 + 14) plus half a ring. */
.cflow__step:not(:last-child)::after {
  content: "";
  position: absolute;
  z-index: 0;
  top: calc(34px + var(--mark) / 2 - 1px);
  left: calc(50% + var(--mark) / 2 + var(--halo));
  width: calc(100% + var(--gap) - var(--mark) - 2 * var(--halo));
  height: 2px;
  border-radius: 2px;
  background: #D5DEEF;
}

.cflow__text { margin-top: 22px; }

.cflow__title {
  margin: 0 0 8px;
  font-family: var(--font);
  font-weight: 700;
  font-size: clamp(18px, 1.5vw, 21px);
  line-height: 1.25;
  letter-spacing: -.015em;
  color: var(--head-ink);
  text-wrap: balance;
}

.cflow__copy {
  max-width: 28ch;
  margin: 0 auto;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.6;
  color: var(--body-ink);
  text-wrap: pretty;
}


/* ============================================================
   .cost — what a cleanout costs

   EXACTLY THREE FACTORS: WEIGHT, ACCESS, LOCATION — the client's own,
   given on 2026-09-12 when the earlier volume / access / "what is in
   it" explanation was reported as inaccurate.

   NO FIGURES ANYWHERE IN THIS SECTION, deliberately. This site
   publishes no cleanout prices, and inventing a "from $XXX" here
   would be a fabricated business fact on the page whose whole job is
   to be trusted.

   Surface section, white cards: the section flipped to --surface when
   the comparison section above it was removed (see the rhythm table),
   and --surface cards on a --surface ground would have no edge.
   ============================================================ */
.cost { background: var(--surface); }

.cost__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 22px;
  margin-top: 46px;
}

.cost__card {
  padding: 30px 30px 32px;
  border: 1px solid #E4E7EE;
  border-radius: 20px;
  background: #FFFFFF;
}

.cost__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 22px;
}

/* Same filled 24px glyph family and the same ring treatment as
   .cflow__mark, one size down, so the two sections read as one
   system. */
.cost__icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border: 1.5px solid #D5DEEF;
  border-radius: 50%;
  background: #F4F7FD;
}
.cost__icon svg {
  width: 26px;
  height: 26px;
  fill: var(--blue);
}

.cost__n {
  font-family: var(--font);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: .14em;
  color: var(--after-ink);
  font-variant-numeric: tabular-nums;
}

.cost__name {
  margin: 0 0 10px;
  font-family: var(--font);
  font-weight: 600;
  font-size: clamp(20px, 1.6vw, 24px);
  line-height: 1.15;
  letter-spacing: -.025em;
  color: var(--head-ink);
}

.cost__copy {
  margin: 0;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.62;
  color: var(--body-ink);
  text-wrap: pretty;
}

.cost__cta {
  margin-top: 40px;
  text-align: center;
}

.cost__ask {
  margin: 0 0 18px;
  font-family: var(--font);
  font-size: clamp(18px, 1.5vw, 21px);
  font-weight: 600;
  line-height: 1.35;
  color: var(--head-ink);
}

.cost__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
}


/* ------------------------------------------------------------
   .bax__label — a 12px floor instead of 11.

   junk-removal.css sets the Before/After labels to
   clamp(11px, 1vw, 13px), which resolves to 11px on anything under
   1100px wide — i.e. on every phone and tablet. "BEFORE" and "AFTER"
   are not decoration; they are the two words that make the whole
   comparison legible, and 11px is under the floor tools/cleanouts-qa.js
   enforces for readable type.

   Raising the bottom of the clamp rather than the whole thing: the
   ceiling stays 13px, so nothing changes above 1300px and the
   section looks identical on desktop. Page-local for the same reason
   the eyebrow fix is — junk-removal.css is loaded by a page that
   ranks, and a type change there is not this build's call. */
.bax__label { font-size: clamp(12px, 1vw, 13px); }


/* ============================================================
   .grevs — the Google review slider

   Page-local; replaces the .jrevs grid this page used until 2026-09-12.
   The markup comment says what is live and what is snapshot, and
   /assets/js/google-reviews.js explains the behaviour. Three things
   the CSS itself is responsible for:

   PER VIEW: 3 / 2 / 1. The track is a one-row grid whose column width
   is a fraction of its own content box, so exactly three cards fit
   above 960, two down to 641 and one below. It scrolls natively with
   scroll-snap, so touch swipe and trackpads need no script.

   EQUAL HEIGHTS WITHOUT CUTTING WORDS. Grid rows stretch every card to
   the tallest in the row, the date sits on margin-top:auto, and — only
   once the script has confirmed it can offer Read more — review text is
   clamped to six lines. The words are always in the DOM; the clamp is a
   visual limit with a button on it, never a truncation.

   THE TRACK HAS 8px OF PADDING so a card's border and the keyboard
   focus ring are not clipped by the scroll container. The viewport pulls
   back by the same 8px so the cards still line up with the rail, and
   scroll-padding matches so the snap edge does not move.

   Cards are --surface on a white section — the section went white when
   the comparison section above was removed (see the rhythm table), and
   a tinted card reads better on white than a shadowed one.
   ============================================================ */
.grevs { background: #FFFFFF; }

/* --- rating summary ------------------------------------------- */
.grevs__summary {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  width: fit-content;
  max-width: 100%;
  margin: 28px auto 0;
  padding: 16px 28px 16px 22px;
  border: 1px solid #E4E7EE;
  border-radius: 20px;
  background: var(--surface);
}

.grevs__glogo { flex: none; line-height: 0; }
.grevs__glogo svg { width: 46px; height: 46px; }

.grevs__score { min-width: 0; text-align: left; }

.grevs__grade {
  margin: 0;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--head-ink);
}

.grevs__rating {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 3px 0 0;
}

.grevs__num {
  font-family: var(--font);
  font-size: 30px;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--head-ink);
  font-variant-numeric: tabular-nums;
}

/* STARS ARE TWO LAYERS OF ONE GLYPH — grey underneath, Google's star
   yellow (#FBBC04, the colour the home page's review stars already use)
   on top, clipped to --pct. So a live 4.8 shows 96% of five stars
   instead of rounding up to five or down to four. */
.grevs__stars,
.grev__stars {
  --pct: 100%;
  position: relative;
  display: inline-block;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 19'%3E%3Cpath fill='%23D5DBE5' d='M10 0l2.5 6.5H20l-6 4.4 2.3 6.6L10 13.6 3.7 17.5 6 10.9 0 6.5h7.5z'/%3E%3C/svg%3E") 0 0 / auto 100% repeat-x;
}
.grevs__stars::before,
.grev__stars::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--pct);
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 19'%3E%3Cpath fill='%23FBBC04' d='M10 0l2.5 6.5H20l-6 4.4 2.3 6.6L10 13.6 3.7 17.5 6 10.9 0 6.5h7.5z'/%3E%3C/svg%3E") 0 0 / auto 100% repeat-x;
}
.grevs__stars { width: 116px; height: 20px; }   /* 5 stars at 22:19 */

.grevs__based {
  margin: 5px 0 0;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--body-ink);
}
.grevs__based strong { font-weight: 800; color: var(--head-ink); }

.grevs__source {
  margin: 2px 0 0;
  font-size: 12.5px;
  font-weight: 500;
  color: #5A6076;
}

/* --- the track ------------------------------------------------ */
.grevs__viewport {
  margin: 34px -8px 0;
}

.grevs__track {
  --per: 3;
  --gap: 24px;
  list-style: none;
  margin: 0;
  padding: 8px;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - (var(--per) - 1) * var(--gap)) / var(--per));
  column-gap: var(--gap);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: 8px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}
.grevs__track::-webkit-scrollbar { display: none; }
.grevs__track:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: -3px;
  border-radius: 24px;
}

/* --- a card --------------------------------------------------- */
.grev {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 24px 24px 20px;
  border: 1px solid #E4E9EF;
  border-radius: 20px;
  background: var(--surface);
  scroll-snap-align: start;
}

.grev__head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.grev__avatar,
.grev__photo {
  flex: none;
  width: 40px;
  height: 40px;
  border-radius: 50%;
}

/* Six tones, every one at least 4.5:1 against the white initial. */
.grev__avatar {
  display: grid;
  place-items: center;
  font-family: var(--font);
  font-size: 17px;
  font-weight: 700;
  color: #FFFFFF;
  background: #2F6FE5;
}
.grev__avatar--c1 { background: #176928; }
.grev__avatar--c2 { background: #B3261E; }
.grev__avatar--c3 { background: #6B3FA8; }
.grev__avatar--c4 { background: #0B6E78; }
.grev__avatar--c5 { background: #8A5300; }

.grev__photo { object-fit: cover; background: #DDE3EC; }

.grev__who { flex: 1 1 auto; min-width: 0; }

.grev__name {
  margin: 0;
  font-family: var(--font);
  font-size: 15.5px;
  font-weight: 700;
  line-height: 1.3;
  color: var(--head-ink);
  overflow-wrap: anywhere;
}
.grev__name a { color: inherit; text-decoration: none; }
.grev__name a:hover { text-decoration: underline; text-underline-offset: 3px; }

.grev__src {
  margin: 1px 0 0;
  font-size: 12.5px;
  font-weight: 500;
  color: #5A6076;
}

/* Google's "G", the same four-colour mark as the summary, at the size a
   card needs. A background rather than twenty inline copies of the SVG. */
.grev__g {
  flex: none;
  align-self: flex-start;
  width: 20px;
  height: 20px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill='%23FFC107' d='M43.611 20.083H42V20H24v8h11.303c-1.649 4.657-6.08 8-11.303 8-6.627 0-12-5.373-12-12s5.373-12 12-12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 12.955 4 4 12.955 4 24s8.955 20 20 20 20-8.955 20-20c0-1.341-.138-2.65-.389-3.917z'/%3E%3Cpath fill='%23FF3D00' d='M6.306 14.691l6.571 4.819C14.655 15.108 18.961 12 24 12c3.059 0 5.842 1.154 7.961 3.039l5.657-5.657C34.046 6.053 29.268 4 24 4 16.318 4 9.656 8.337 6.306 14.691z'/%3E%3Cpath fill='%234CAF50' d='M24 44c5.166 0 9.86-1.977 13.409-5.192l-6.19-5.238A11.91 11.91 0 0 1 24 36c-5.202 0-9.619-3.317-11.283-7.946l-6.522 5.025C9.505 39.556 16.227 44 24 44z'/%3E%3Cpath fill='%231976D2' d='M43.611 20.083H42V20H24v8h11.303a12.04 12.04 0 0 1-4.087 5.571l.003-.002 6.19 5.238C36.971 39.205 44 34 44 24c0-1.341-.138-2.65-.389-3.917z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.grev__stars {
  width: 93px;    /* 5 stars at 22:19 */
  height: 16px;
  margin: 16px 0 12px;
}

.grev__text {
  margin: 0;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.6;
  color: var(--body-ink);
  overflow-wrap: anywhere;
}

.is-enhanced .grev__text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  overflow: hidden;
}
.is-enhanced .grev.is-open .grev__text {
  display: block;
  -webkit-line-clamp: unset;
  line-clamp: none;
  overflow: visible;
}

.grev__more {
  align-self: flex-start;
  min-height: 44px;           /* a touch target, even though it reads as a link */
  margin: 2px 0 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font);
  font-size: 14.5px;
  font-weight: 700;
  color: var(--blue-line);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.grev__more:hover { color: var(--blue-hover); }
.grev__more:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; border-radius: 4px; }

.grev__date {
  margin: auto 0 0;
  padding-top: 14px;
  font-size: 13px;
  font-weight: 500;
  color: #5A6076;
}
.grev__view { color: var(--blue-line); text-decoration: underline; text-underline-offset: 3px; }

/* --- controls ------------------------------------------------- */
.grevs__controls {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 20px;
}
.grevs__controls[hidden] { display: none; }

.grevs__progress {
  position: relative;
  flex: 1 1 auto;
  height: 4px;
  overflow: hidden;
  border-radius: 4px;
  background: #E1E7EF;
}

.grevs__bar {
  position: absolute;
  top: 0;
  left: 0;
  width: 15%;
  height: 100%;
  border-radius: 4px;
  background: var(--blue);
  transition: left .25s ease, width .25s ease;
}

.grevs__count {
  margin: 0;
  min-width: 6.4em;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: .04em;
  text-align: center;
  white-space: nowrap;
  color: var(--head-ink);
  font-variant-numeric: tabular-nums;
}

/* Same 44px outlined ring as the Before & After arrows on this page. */
.grevs__arrow {
  flex: none;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1.5px solid rgba(11, 18, 38, .22);
  border-radius: 50%;
  background: #FFFFFF;
  color: var(--head-ink);
  cursor: pointer;
  transition: background-color .2s linear, border-color .2s linear, color .2s linear, opacity .2s linear;
}
.grevs__arrow:hover { background: var(--head-ink); border-color: var(--head-ink); color: #FFFFFF; }
.grevs__arrow:focus-visible { outline: 3px solid var(--blue); outline-offset: 2px; }
.grevs__arrow[disabled] { opacity: .3; cursor: default; pointer-events: none; }
.grevs__arrow svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.grevs__foot {
  margin-top: 30px;
  text-align: center;
}


/* ============================================================
   .qform — the quote form

   THE PAGE'S CONVERSION FLOOR, and the only dark fill above the
   footer. Gradient plus the noise layer, per the dark-section rule
   at the top of this file.

   THE FORM IS ON THE PAGE. Every "Get A Free Quote" on this page is
   an in-page #quote jump rather than a link to /get-a-free-quote, so
   nobody is handed a navigation before they are handed a form. The
   ids are exactly the ones /assets/js/quote-form.js binds to; see
   the block comment above the markup.
   ============================================================ */
.qform {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* Two stops, five luminance steps apart. It does not need to read
     as a gradient — it needs to not be flat. */
  background: linear-gradient(180deg, #131B2E 0%, #0F172A 100%);
  color: #FFFFFF;
  scroll-margin-top: 96px;   /* clears the sticky header on a #quote jump */
}

.qform__inner {
  position: relative;
  z-index: 2;
  display: grid;
  /* Copy narrower than the form. The form is the thing being used;
     the copy is the reason to use it. */
  grid-template-columns: 1fr 1.08fr;
  gap: clamp(32px, 4vw, 64px);
  align-items: start;
}

.qform__title {
  margin: 0;
  font-family: var(--font);
  font-weight: 300;
  font-size: clamp(28px, 3.2vw, 44px);
  line-height: 1.1;
  letter-spacing: -.04em;
  color: #FFFFFF;
  text-wrap: balance;
}

.qform__lede {
  margin: 20px 0 0;
  font-size: clamp(16px, 1.15vw, 18px);
  font-weight: 500;
  line-height: 1.65;
  color: rgba(255, 255, 255, .82);
  text-wrap: pretty;
}

.qform__pts {
  margin: 30px 0 0;
  padding: 0;
  list-style: none;
}
.qform__pts li {
  position: relative;
  padding-left: 30px;
  margin-bottom: 13px;
  font-size: 15.5px;
  font-weight: 600;
  line-height: 1.5;
  color: #FFFFFF;
}
.qform__pts li::before {
  content: '\2713';
  position: absolute;
  left: 0;
  top: 0;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--accent-green);
  color: #0B1226;
  font-size: 12px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
}

.qform__or {
  margin: 30px 0 0;
  padding-top: 26px;
  border-top: 1px solid rgba(255, 255, 255, .16);
  font-size: 15px;
  font-weight: 500;
  color: rgba(255, 255, 255, .72);
}
.qform__or span { margin: 0 6px; color: rgba(255, 255, 255, .4); }

.qform__tel {
  display: inline-block;
  /* 44px of tappable height on a phone even though this reads as a
     text link — it is one of the three actions the page exists for. */
  min-height: 44px;
  padding: 11px 0;
  color: #FFFFFF;
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 4px;
}
.qform__tel:hover { color: var(--accent-green); }

/* --- the card ------------------------------------------------ */
.qform__card {
  padding: clamp(26px, 2.6vw, 38px);
  border-radius: 22px;
  background: #FFFFFF;
  box-shadow: 0 24px 60px rgba(4, 8, 20, .34);
  /* Stacked layouts send #quote here rather than to the section; see
     the "#quote LANDS ON THE FORM" script in cleanouts/index.html.
     Same header clearance as .qform. */
  scroll-margin-top: 96px;
}
/* tabindex="-1" only so the #quote script can move focus in. It is
   never a Tab stop, so it gets no ring; the fields keep theirs. */
.qform__card:focus { outline: none; }

.qform__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.qform__field { margin-bottom: 16px; }
.qform__row .qform__field { margin-bottom: 16px; }

.qform__field label {
  display: block;
  margin-bottom: 7px;
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: .01em;
  color: var(--head-ink);
}
.qform__opt { font-weight: 500; color: #7A8195; }

.qform__field input,
.qform__field select,
.qform__field textarea {
  width: 100%;
  min-height: 48px;             /* clears the 44px touch minimum */
  padding: 12px 14px;
  border: 1px solid #D7DCE6;
  border-radius: 10px;
  background: #FFFFFF;
  font-family: var(--font);
  /* 16px AND NOT ONE PIXEL LESS. iOS Safari zooms the whole viewport
     when a focused input is under 16px, and it does not zoom back
     out. That is the single most common way a mobile form loses
     people. */
  font-size: 16px;
  font-weight: 500;
  color: var(--head-ink);
  transition: border-color .15s linear, box-shadow .15s linear;
  -webkit-appearance: none;
  appearance: none;
}

.qform__field textarea {
  min-height: 110px;
  line-height: 1.55;
  resize: vertical;
}

/* The native select arrow is stripped by appearance:none above, so
   it has to be drawn back. Inline SVG in the background rather than
   a file: it is 180 bytes and a request would not be. */
.qform__field select {
  padding-right: 40px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' fill='none' stroke='%234C5265' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  cursor: pointer;
}

.qform__field input::placeholder,
.qform__field textarea::placeholder { color: #9AA1B2; }

.qform__field input:focus,
.qform__field select:focus,
.qform__field textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(47, 111, 229, .18);
}
/* Keyboard users get a ring that does not depend on the brand blue
   being distinguishable from the resting border. */
.qform__field input:focus-visible,
.qform__field select:focus-visible,
.qform__field textarea:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 2px;
}

/* quote-form.js adds .err to a field it has rejected client-side,
   and moves focus there. The message in #formStatus says what is
   wrong; the border says which box. */
.qform__field input.err,
.qform__field select.err,
.qform__field textarea.err {
  border-color: #C4362F;
  box-shadow: 0 0 0 3px rgba(196, 54, 47, .14);
}

/* #formStatus is written by quote-form.js and starts empty. Collapsed
   to nothing until it has content, so it does not reserve a gap
   above the button on a form nobody has submitted yet. */
.qform__status {
  margin: 0;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.5;
  color: var(--body-ink);
}
.qform__status:empty { display: none; }
.qform__status:not(:empty) { margin: 0 0 16px; }
.qform__status.is-ok  { color: #176928; }
.qform__status.is-err { color: #C4362F; }
.qform__status a { color: inherit; text-decoration: underline; }

.qform__submit {
  width: 100%;
  min-height: 54px;
  padding: 0 28px;
  border: 1px solid var(--blue);
  border-radius: 100px;
  background: var(--blue);
  color: #FFFFFF;
  font-family: var(--font);
  font-size: 16px;
  font-weight: 700;
  letter-spacing: .02em;
  cursor: pointer;
  transition: background-color .2s linear, border-color .2s linear;
}
.qform__submit:hover { background: var(--blue-hover); border-color: var(--blue-hover); }
.qform__submit:focus-visible { outline: 3px solid #0B1226; outline-offset: 3px; }
/* quote-form.js disables the button and swaps its value while the
   POST is in flight. */
.qform__submit:disabled { opacity: .62; cursor: default; }

.qform__small {
  margin: 14px 0 0;
  text-align: center;
  font-size: 13px;
  font-weight: 500;
  color: #7A8195;
}

.qform__noscript {
  margin: 18px 0 0;
  font-size: 14.5px;
  font-weight: 500;
  line-height: 1.6;
  color: var(--body-ink);
}
.qform__noscript a { color: var(--blue-line); font-weight: 700; }


/* ============================================================
   .areas — service areas

   THE SPELLINGS HERE ARE CORRECT AND THE FOOTER'S ARE NOT, and that
   is deliberate. The footer is the live site's own markup carried
   over by the parity audit with its mistakes intact ("Belmark",
   "Bradly Beach", "Colt Neck", Matawan/Aberdeen twice, all 29 links
   pointing at "#"). Changing it is a site-wide decision and belongs
   to the client. But a service-area list is the one place on a local
   page where a misspelt town is actively expensive, because it is
   the text a crawler matches against the query — so this section
   carries the correct names and the counties they sit in.

   NOT LINKED. There are no town pages, and generating 29
   near-identical ones off this template is how a local site walks
   into Google's doorway-page policy.
   ============================================================ */
.areas { background: #FFFFFF; }

.areas__cols {
  display: grid;
  /* Weighted to the first column, which carries 19 of the 30 names. */
  grid-template-columns: 1.6fr 1fr 1fr;
  gap: 32px;
  margin-top: 44px;
}

.areas__head {
  margin: 0 0 18px;
  padding-bottom: 14px;
  border-bottom: 1px solid #E4E7EE;
  font-family: var(--font);
  font-weight: 700;
  font-size: 15px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--head-ink);
}

.areas__list {
  margin: 0;
  padding: 0;
  list-style: none;
  /* Two columns inside the wide first group, one inside the narrow
     ones — column-width does that on its own without a breakpoint
     per column. */
  columns: 160px auto;
  column-gap: 24px;
}

.areas__list li {
  break-inside: avoid;
  margin-bottom: 10px;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.5;
  color: var(--body-ink);
}

.areas__note {
  max-width: 62rem;
  margin: 38px 0 0;
  padding-top: 26px;
  border-top: 1px solid #E4E7EE;
  font-size: 15.5px;
  font-weight: 500;
  line-height: 1.65;
  color: var(--body-ink);
}
.areas__note a {
  color: var(--blue-line);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.areas__note a:hover { color: var(--blue-hover); }


/* ============================================================
   RHYTHM OVERRIDES — the only two on the page.

   Both are forced by THIS page's section order, not by anything
   wrong with the components. See the rhythm table at the top.
   ============================================================ */

/* .faq ships white in junk-removal.css. Here it follows .areas,
   which is white. */
.faq { background: var(--surface); }

/* .cta ships --surface. Here it follows .faq, which is now surface. */
.cta { background: #FFFFFF; }

/* .cta__panel inherits its ground from .cta on the junk page; state
   it explicitly so the panel does not go transparent over the new
   white and lose its edge against .cta__media. */
.cta__panel { background: #FFFFFF; }


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

   Checked at 375, 430, 768, 1024 and 1440. The rules below are in
   descending order so each one only has to undo the step above it.
   ============================================================ */

/* --- 1024: the form and the included panels stack -------------- */
@media (max-width: 1024px) {

  .qform__inner { grid-template-columns: minmax(0, 1fr); }
  /* Copy above the form on a stacked layout: the reason to fill it
     in has to arrive before the fields do. */
  .qform__copy  { max-width: 62rem; }

  .incl__grid   { grid-template-columns: minmax(0, 1fr); }
  .areas__cols  { grid-template-columns: 1fr 1fr; gap: 28px 32px; }
}

/* --- 960: service cards and reviews go two-up ------------------ */
/* Not 1024. With a fixed 3:2 photograph the image's share of a card
   depends on how many lines the sentence under it takes, and a two-up
   card at 1024 is so wide that the sentence fits on two lines and the
   photograph becomes ~71% of the card. Three-up holds down to ~960 with
   the image near 56-58%; two-up at 768 lands at ~61%. The review row
   changes at the same width so the two grids agree. */
@media (max-width: 960px) {
  .cotypes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grevs__track { --per: 2; --gap: 20px; }
}

/* --- 900: cost factors stack, icon beside the words ------------ */
/* Three columns at 768 left each factor ~180px of text measure and the
   Access sentence ran to six lines. One column with the icon in its
   own gutter reads as a list of three and stays short. */
@media (max-width: 900px) {
  .cost__grid {
    grid-template-columns: minmax(0, 1fr);
    max-width: 640px;
    margin-inline: auto;
    gap: 16px;
  }
  .cost__card {
    display: grid;
    grid-template-columns: 56px minmax(0, 1fr);
    column-gap: 20px;
    align-items: start;
    padding: 24px 24px 26px;
  }
  .cost__top {
    grid-column: 1;
    grid-row: 1 / span 2;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    margin: 0;
  }
  .cost__name { grid-column: 2; margin: 4px 0 8px; }
  .cost__copy { grid-column: 2; }
}

/* --- 860: How It Works turns vertical --------------------------- */
/* See the .cflow header for why the connector cannot touch text in
   this layout: it lives in the marker column, and the words are in the
   other one. It runs from under this ring (+ halo) to the halo above
   the next ring, which starts exactly at this step's bottom edge. */
@media (max-width: 860px) {
  .cflow { --mark: 60px; --halo: 8px; }

  .cflow__steps {
    grid-template-columns: minmax(0, 1fr);
    max-width: 560px;
    margin-inline: auto;
  }

  .cflow__step {
    display: grid;
    grid-template-columns: var(--mark) minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: 18px;
    align-items: start;
    padding-bottom: 30px;
    text-align: left;
  }
  .cflow__step:last-child { padding-bottom: 0; }

  .cflow__mark { grid-column: 1; grid-row: 1 / span 2; }
  .cflow__icon { width: 26px; height: 26px; }
  .cflow__num  { grid-column: 2; grid-row: 1; height: auto; margin: 4px 0 4px; }
  .cflow__text { grid-column: 2; grid-row: 2; margin-top: 0; }
  .cflow__copy { max-width: none; margin: 0; }

  .cflow__step:not(:last-child)::after {
    top: calc(var(--mark) + var(--halo));
    bottom: var(--halo);
    left: calc(var(--mark) / 2 - 1px);
    width: 2px;
    height: auto;
  }
}

/* --- 768 ---------------------------------------------------------- */
@media (max-width: 768px) {
  .areas__cols { grid-template-columns: minmax(0, 1fr); gap: 30px; }
  .areas__list { columns: 150px auto; }

  /* Four chips on two lines rather than four cramped ones on one. */
  .shero__chips { gap: 12px 18px; }

  .incl__panel { padding: 28px 24px; }
}

/* --- 640: service cards go single column ------------------------ */
@media (max-width: 640px) {
  .cotypes { grid-template-columns: minmax(0, 1fr); gap: 18px; }

  /* One review per view. */
  .grevs__track { --per: 1; --gap: 14px; }
  .grev { padding: 22px 20px 18px; }

  .grevs__summary { gap: 14px; padding: 14px 20px 14px 16px; }
  .grevs__glogo svg { width: 38px; height: 38px; }
  .grevs__num { font-size: 26px; }
  .grevs__stars { width: 104px; height: 18px; }

  .grevs__controls { gap: 10px; }
  .grevs__count { min-width: 5.6em; }
}

/* --- 430 and 375: phone --------------------------------------- */
@media (max-width: 560px) {
  /* THE QUICKBAR SITS OVER THE BOTTOM OF THE PAGE. v2.js parks the
     two sticky pills above the footer, but between the hero and the
     footer they float over whatever is under them. The last section
     before the footer is .cta, so the page gets bottom padding
     rather than each section guessing. Measured against the pill
     row's height plus the safe-area inset on a notched phone. */
  body { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)); }

  .ctrust,
  .tracks,
  .incl,
  .cflow,
  .cost,
  .grevs,
  .qform,
  .areas {
    padding-left: 18px;
    padding-right: 18px;
  }

  /* THREE BUTTONS, FULL WIDTH, STACKED. At 375 three pills side by
     side are each ~105px, which is under the 44px-square target once
     the label is inside them, and the labels wrap to two lines. Full
     width is both bigger and easier to hit with a thumb. */
  .shero__actions { flex-direction: column; width: 100%; gap: 10px; }
  .shero__actions .btn { width: 100%; }

  .shero__chips {
    /* Ranged left in a two-column grid rather than centred and
       wrapped: centred chips of different lengths on four lines is a
       ragged block, and this is the last thing above the fold. */
    display: grid;
    grid-template-columns: 1fr 1fr;
    justify-content: stretch;
    gap: 12px 14px;
    text-align: left;
  }
  .shero__chip { font-size: 12.5px; }

  .tracks__foot,
  .cost__actions { flex-direction: column; }
  .tracks__foot .btn,
  .cost__actions .btn { width: 100%; }

  .cotype__body { padding: 18px 20px 22px; }

  .cost__card {
    grid-template-columns: 48px minmax(0, 1fr);
    column-gap: 16px;
    padding: 22px 20px 24px;
  }
  .cost__icon { width: 48px; height: 48px; }
  .cost__icon svg { width: 22px; height: 22px; }

  /* One column of fields. Name and Phone side by side at 375 leaves
     each about 150px, which is not enough to see a typed phone
     number in. */
  .qform__row { grid-template-columns: minmax(0, 1fr); gap: 0; }

  .qform__card { padding: 22px 18px; border-radius: 18px; }

  /* "Rather not type? Call ... · Text us" wraps between the two links at
     this width and strands the separator at the end of the first line.
     Stack the pair instead and drop the dot, which only exists to
     separate them on one line. */
  .qform__or { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
  .qform__or span { display: none; }
  .qform__tel { padding: 9px 0; }

  /* TWO COLUMNS, NOT ONE, and the reason is height rather than taste. The
     Monmouth group alone is 19 names; as a single column it runs about 630px,
     and the three groups together push a phone past 1000px of nothing but
     town names. Two columns halves that and still fits the longest name
     ("Atlantic Highlands", ~135px at this size) inside a ~170px column at
     375. The section stops being a wall and becomes a list you can scan. */
  .areas__list { columns: 2; column-gap: 16px; }
  .areas__list li { font-size: 15px; }
}

/* A 320px viewport still exists on an SE in landscape-locked apps.
   Nothing here should ever produce a horizontal scrollbar, so the
   one element that can — the chip grid — drops to a single column. */
@media (max-width: 360px) {
  .shero__chips { grid-template-columns: minmax(0, 1fr); }
}


/* ============================================================
   MOTION

   Everything on this page that moves is a colour or shadow
   transition of 150-200ms, the service cards' small hover lift, the
   .bax carousel's smooth scroll (v2.js's) and the review slider's
   (google-reviews.js, which checks the same media query before it
   asks for smooth scrolling). Honour the system setting for all of it.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .qform__field input,
  .qform__field select,
  .qform__field textarea,
  .qform__submit,
  .cotype,
  .cotype__img,
  .grevs__bar,
  .grevs__arrow {
    transition: none;
  }
  .grevs__track { scroll-behavior: auto; }
  .cotype:hover,
  .cotype:hover .cotype__img { transform: none; }
}


/* ============================================================
   PRINT

   People print a quote page to take to an executor meeting or a
   landlord. Drop the chrome, keep the phone number visible, and stop
   the dark band burning a page of toner.
   ============================================================ */
@media print {
  .above-header,
  .site-header,
  .quickbar,
  .bax__nav,
  .shero__photo,
  .shero__scrim,
  .noise-overlay,
  .sfoot__noise { display: none !important; }

  .shero,
  .qform {
    background: #FFFFFF !important;
    color: #000000 !important;
  }
  .shero__title,
  .shero__eyebrow,
  .shero__chip,
  .qform__title,
  .qform__lede,
  .qform__pts li,
  .qform__tel { color: #000000 !important; }

  /* THE GHOST BUTTONS WOULD OTHERWISE PRINT BLANK. .btn--ghost-light and
     .cta__btn--ghost are white text inside a white-or-transparent border,
     because they were drawn to sit on a photograph and on a dark band. Both
     grounds have just been forced to white above, so without this the two
     hero call-to-actions and the closing "Text Us Now!" print as empty
     outlines — the phone number on a printed page disappears. */
  .btn--ghost-light,
  .cta__btn--ghost {
    color: #000000 !important;
    border-color: #000000 !important;
    background: transparent !important;
  }
  .cta__btn {
    color: #000000 !important;
    background: transparent !important;
    border: 1px solid #000000 !important;
  }

  .cotype,
  .cflow__step,
  .cost__card,
  .grev,
  .incl__panel { break-inside: avoid; }

  /* Paper does not scroll sideways: every review prints, in full. */
  .grevs__controls,
  .grev__more { display: none !important; }
  .grevs__track {
    display: block;
    overflow: visible;
    padding: 0;
  }
  .grev { margin-bottom: 12px; }
  .is-enhanced .grev__text {
    display: block;
    -webkit-line-clamp: unset;
    overflow: visible;
  }

  /* A printed page has no tap targets, so every phone and email
     target has to survive as readable text. Scoped to tel:/mailto:
     so it does not print "(#quote)" after every in-page jump. */
  a[href^="tel:"]::after,
  a[href^="sms:"]::after,
  a[href^="mailto:"]::after {
    content: ' [' attr(href) ']';
    font-weight: 400;
  }
}
