/*
 * Breakara Demolition Brooklyn.
 *
 * Realises the operator-supplied removals_v2.5 template: its composition, its Roboto type
 * scale, its 1170px container, its card radius, and the structural ROLE each colour plays.
 *
 * The HUE is Breakara's, not the template's. Operator decision 2026-08-21: a cluster is one
 * real brand and its local properties must look like that business, so the template’s muted
 * green is substituted by Breakara hazard yellow in exactly the same structural role the
 * green played. This is the convention the rest of the cluster already follows.
 *
 * Hazard yellow is the one saturated colour and it never tints a large background except
 * the call-to-action band and the copy bar, which is the restraint the template’s green
 * showed. Everything that was a solid green panel is graphite instead.
 *
 * Tokens are copied, never imported. Deviations are recorded in DESIGN-DNA.md.
 */

/* ------------------------------------------------------------------ fonts */
@font-face{font-family:Roboto;font-style:normal;font-weight:300;font-display:swap;src:url(/assets/fonts/roboto-300.88c0fef59b53.woff2) format("woff2")}
@font-face{font-family:Roboto;font-style:normal;font-weight:400;font-display:swap;src:url(/assets/fonts/roboto-400.6d6be3a7d40f.woff2) format("woff2")}
@font-face{font-family:Roboto;font-style:normal;font-weight:500;font-display:swap;src:url(/assets/fonts/roboto-500.a99e7e70a822.woff2) format("woff2")}
@font-face{font-family:Roboto;font-style:normal;font-weight:700;font-display:swap;src:url(/assets/fonts/roboto-700.b64aec59c234.woff2) format("woff2")}
@font-face{font-family:Roboto;font-style:normal;font-weight:900;font-display:swap;src:url(/assets/fonts/roboto-900.297d8ec23216.woff2) format("woff2")}

/* ----------------------------------------------------------------- tokens */
:root{
  --primary:#f6bd19;          /* the cluster's hazard yellow. CTA band, copy bar, accents */
  --primary-dark:#dfa806;     /* pressed state */
  --primary-ink:#7a5f00;      /* ochre, the hue made legible as text on white */
  --primary-line:#f7d97e;     /* hairline in the hue */
  --primary-tint:#fdf3d8;     /* the faintest wash, quiet grounds only */
  --ink:#343333;              /* headings */
  --body:#565a5c;             /* body copy */
  --muted:#7b7f81;
  --ground:#fff;
  --ground-alt:#f9f9f9;       /* the alternating section ground */
  --footer:#222;              /* dark bands and the footer */
  --dark-2:#3d3c3c;           /* a card sitting on a dark band */
  --rule:#e2e2e0;
  --stripes:repeating-linear-gradient(135deg,rgba(0,0,0,.05) 0 14px,rgba(0,0,0,0) 14px 28px);
  --shadow:0 2px 10px -2px rgba(0,0,0,.41);
  --container:1170px;
  --gutter:20px;
  --measure:70ch;
  --radius:10px;
  --radius-sm:3px;
  --s1:8px; --s2:16px; --s3:24px; --s4:32px; --s5:48px; --s6:72px; --s7:96px;
}

/* ------------------------------------------------------------------ reset */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--ground);color:var(--body);
  font-family:Roboto,-apple-system,"Segoe UI",Arial,sans-serif;
  font-size:17px;line-height:1.65;-webkit-font-smoothing:antialiased;
}
img{max-width:100%;height:auto;display:block}
h1,h2,h3,h4{color:var(--ink);margin:0 0 var(--s2);line-height:1.2;font-weight:700}
h1{font-size:clamp(2rem,4.2vw,3.1rem);font-weight:900;letter-spacing:-.02em}
h2{font-size:clamp(1.5rem,2.6vw,2.15rem);letter-spacing:-.01em}
h3{font-size:1.22rem}
p{margin:0 0 var(--s2)}
a{color:var(--primary-ink);text-decoration:none;transition:color .2s ease}
a:hover{color:var(--ink)}
:focus-visible{outline:3px solid var(--primary);outline-offset:3px}
ul.plain{list-style:none;margin:0;padding:0}
ul.plain.inline{display:flex;gap:var(--s3)}
.container{width:100%;max-width:var(--container);margin:0 auto;padding:0 var(--gutter)}
.measure{max-width:var(--measure)}
.center{text-align:center}
.section{padding:var(--s6) 0}
.section_title{text-align:center;margin-bottom:var(--s2);text-transform:uppercase;letter-spacing:.02em}
.section_intro{text-align:center;max-width:60ch;margin:0 auto var(--s5);color:var(--muted)}
.skip{position:absolute;left:-9999px;top:0;background:var(--primary);color:#fff;padding:var(--s2) var(--s3);z-index:200}
.skip:focus{left:0}

/* --------------------------------------------------------------- controls */
.btn{
  display:inline-block;background:var(--primary);color:var(--ink);font-weight:700;
  padding:13px 26px;border-radius:var(--radius-sm);border:2px solid var(--primary);
  transition:background .2s ease,border-color .2s ease;
}
.btn:hover{background:var(--primary-dark);border-color:var(--primary-dark);color:var(--ink)}
.btn_lg{padding:17px 34px;font-size:1.06rem}
.btn_light{background:var(--footer);color:#fff;border-color:var(--footer)}
.btn_light:hover{background:#000;border-color:#000;color:#fff}

/* ----------------------------------------------------------------- header */
#top_line{height:30px;font-size:.81rem;border-bottom:1px solid rgba(0,0,0,.1);background:#fff}
.top_line_inner{display:flex;align-items:center;justify-content:space-between;height:30px}
.top_line_tag{color:var(--muted)}
.top_line_phone{font-weight:700;color:var(--ink)}
header{background:#fff;padding:14px 0;position:sticky;top:0;z-index:100;border-bottom:1px solid var(--rule)}
.header_inner{display:flex;align-items:center;gap:var(--s3)}
#logo img{height:46px;width:auto;min-width:180px;object-fit:contain;object-position:left center}
.main-menu{margin-left:auto}
.main-menu ul{list-style:none;margin:0;padding:0;display:flex;gap:var(--s3)}
.main-menu a{color:var(--ink);font-size:.875rem;font-weight:500;padding:6px 0;border-bottom:2px solid transparent}
.main-menu a:hover,.main-menu a[aria-current=page]{color:var(--ink);border-bottom-color:var(--primary)}
.header_cta{padding:9px 18px;font-size:.875rem;white-space:nowrap;align-self:center}
.nav_toggle{display:none;background:none;border:0;padding:10px;cursor:pointer}
.nav_toggle span{display:block;width:24px;height:2px;background:var(--ink);margin:5px 0}

/* ------------------------------------------------------------------- hero */
/* The template's relationship: photograph BEHIND a dark mask, statement OVER it,
   vertically centred. Not an image stacked above a text block. */
.hero{background-size:cover;background-position:center;background-color:var(--ink)}
.hero .opacity-mask{
  background:linear-gradient(90deg,rgba(20,24,22,.86) 0%,rgba(20,24,22,.66) 55%,rgba(20,24,22,.42) 100%);
  display:flex;align-items:center;min-height:clamp(420px,56vh,620px);
}
/* THE HERO USES THE CONTAINER, like every other block on the page.
   It used to cap itself at 860px, which was right when the hero was a single column of
   statement text and wrong the moment a second column appeared beside it. The cap survived
   the two-column change, so the grid was squeezed into 860 of the container's 1170 and the
   whole hero sat centred inside a header it no longer lined up with: measured at 1280, the
   H1 started at x=227 while the logo above it started at x=72.

   The baseline reference puts the hero container at the full 1170 on every page, with or
   without a form, and constrains the STATEMENT rather than the container. That is what this
   does now. */
.hero_inner{padding:var(--s6) var(--gutter)}

/* The reading measure moved here, off the container. On the homepage the two-column grid
   already makes this column narrower than 780, so the cap only does anything on the pages
   that have no form -- which is exactly where an H1 would otherwise run the full 1170. */
.hero_statement{max-width:780px}
.hero h1{color:#fff;margin-bottom:var(--s3)}
.kicker{margin:0 0 var(--s3)}
.kicker span{
  display:inline-block;background:var(--primary);color:var(--ink);
  font-weight:900;text-transform:uppercase;letter-spacing:.12em;
  font-size:.74rem;padding:7px 14px;
}
.lede{color:rgba(255,255,255,.94);font-size:clamp(1.06rem,1.7vw,1.28rem);max-width:62ch;margin-bottom:var(--s4)}
.hero_actions{margin:0}

/* The trust row, on the baseline geometry: a tick in the hazard hue, white bold 14px,
   wrapping to a second line rather than squeezing. */
.hero-trust{display:flex;flex-wrap:wrap;gap:8px 18px;list-style:none;margin:0 0 20px;padding:0}
.hero-trust li{display:inline-flex;align-items:center;gap:7px;margin:0;font-size:14px;font-weight:700;letter-spacing:.01em;color:#fff}
.hero-trust li::before{content:"✓";color:var(--primary);font-size:15px;font-weight:900;line-height:1}

/* ---------------------------------------------- the primary band under it */
#get_quote{background-color:var(--primary);background-image:var(--stripes);color:var(--ink);padding:var(--s4) 0}
#get_quote h2{color:var(--ink);font-size:1.5rem;margin:0 0 6px}
#get_quote p{margin:0;color:rgba(43,46,49,.86)}
.band_inner{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);flex-wrap:wrap}
.band_action{margin:0}

/* ------------------------------------------------------------------ grids */
.grid_3,.grid_4{display:grid;gap:var(--s3)}
.grid_3{grid-template-columns:repeat(3,1fr)}
.grid_4{grid-template-columns:repeat(4,1fr)}

/* A plain three-up on the light ground, for blocks with no imagery. */
.feat_card{background:#fff;border:1px solid var(--rule);border-top:4px solid var(--primary);border-radius:var(--radius);padding:var(--s4) var(--s3)}
.feat_card h3{margin-bottom:10px}
.feat_card p{margin:0;font-size:.97rem}

/* The process band: dark full-bleed, icon cards, the stage name in the hue. */
.process{background:var(--footer);color:rgba(255,255,255,.86)}
.process .section_title{color:#fff}
.band-lead{text-align:center;max-width:62ch;margin:0 auto var(--s5);color:rgba(255,255,255,.72)}
.feat-grid{display:grid;gap:24px;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));list-style:none;margin:0;padding:0}
/* A sequence reads best without an orphan on a second row, so the column count follows
   the number of stages rather than whatever happens to fit. */
.feat-grid[data-n="3"]{grid-template-columns:repeat(3,1fr)}
.feat-grid[data-n="4"]{grid-template-columns:repeat(4,1fr)}
.feat-grid[data-n="5"]{grid-template-columns:repeat(3,1fr)}
.box_feat{
  background:var(--dark-2);border-radius:var(--radius);padding:30px 26px 26px;text-align:center;
  border-top:4px solid var(--primary);position:relative;
}
.box_feat_mark{display:block;position:relative;width:72px;height:72px;margin:0 auto 18px}
.box_feat_mark svg{width:72px;height:72px;display:block}
.box_feat_num{
  position:absolute;right:-10px;bottom:-6px;width:26px;height:26px;border-radius:50%;
  background:var(--primary);color:var(--ink);font-size:.8rem;font-weight:900;
  display:flex;align-items:center;justify-content:center;
}
.box_feat h3{
  font-size:1.02rem;text-transform:uppercase;letter-spacing:.04em;color:var(--primary);
  margin-bottom:10px;
}
.box_feat h3::before,.box_feat h3::after{content:"/";color:rgba(255,255,255,.45)}
.box_feat h3::before{margin-right:9px}
.box_feat h3::after{margin-left:9px}
.box_feat p{margin:0;color:rgba(255,255,255,.82);font-size:.95rem;text-align:left}

/* The area grid: a photograph, the hue under it, then the reading. */
.place_grid{display:grid;gap:24px;grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.place{background:#fff;border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow-soft,none)}
.place img{width:100%;aspect-ratio:3/2;object-fit:cover;border-bottom:3px solid var(--primary)}
.place_body{padding:var(--s3)}
.place_body h3{color:var(--primary-ink);font-size:1.06rem;margin-bottom:8px}
.place_body p{margin:0;font-size:.95rem}

.services .service_card{display:block;border:1px solid var(--rule);border-radius:var(--radius);overflow:hidden;background:#fff;transition:box-shadow .2s ease,transform .2s ease}
.services .service_card:hover{box-shadow:0 12px 28px rgba(0,0,0,.1);transform:translateY(-3px)}
.service_card img{width:100%;aspect-ratio:3/2;object-fit:cover;border-bottom:3px solid var(--primary)}
.service_card h3{margin:var(--s3) var(--s3) 8px}
.service_card p{margin:0 var(--s3) var(--s2);color:var(--body);font-size:.96rem}
.service_card .more{display:inline-block;margin:0 var(--s3) var(--s3);color:var(--primary-ink);font-weight:700;font-size:.92rem;text-transform:lowercase}
.service_card .more::after{content:" \2192"}

/* ------------------------------------------------- the condition strip */
/* The measured-facts slot. Where a competitor puts invented credentials. */
.conditions{background:var(--ground-alt);border-top:1px solid var(--rule);border-bottom:1px solid var(--rule)}
.condition{background:#fff;border:1px solid var(--rule);border-radius:var(--radius);padding:var(--s3)}
.condition .stat{font-size:2.5rem;font-weight:900;color:var(--ink);line-height:1;margin:0 0 6px;letter-spacing:-.03em}
.condition .stat::after{content:"";display:block;width:44px;height:4px;background:var(--primary);margin-top:12px}
.condition .stat_label{font-weight:700;color:var(--ink);margin:0 0 10px}
.condition .stat_note{font-size:.93rem;color:var(--muted);margin:0}

/* ------------------------------------------------------------------ split */
.split{display:grid;grid-template-columns:1fr 1fr;gap:var(--s5);align-items:center}
.split_left .split_media{order:2}
.split_media img{border-radius:var(--radius);width:100%;aspect-ratio:4/3;object-fit:cover}
.split_text p:last-child{margin-bottom:0}

/* ------------------------------------------------------------------ steps */
.steps{list-style:none;counter-reset:s;margin:0;padding:0;display:grid;gap:var(--s3);max-width:var(--measure)}
.steps li{counter-increment:s;position:relative;padding-left:64px}
.steps li::before{
  content:counter(s);position:absolute;left:0;top:0;width:44px;height:44px;border-radius:50%;
  background:var(--primary);color:var(--ink);font-weight:900;display:flex;align-items:center;justify-content:center;
}
.steps h3{margin-bottom:4px}
.steps p{margin:0}

/* -------------------------------------------------------------- coverage */
/* Every covered area gets the SAME tile, the same size and the same weight. The only
   difference is that one carries a link and one does not, which is what a link looks
   like. Nothing here marks an unlinked area as lesser, because it is not. */
.coverage{background:var(--ground-alt);border-top:1px solid var(--rule);border-bottom:1px solid var(--rule)}
.coverage .section_intro{margin-bottom:0}
/* The citywide relationship sits under the tiles, as a sentence rather than a sixth
   tile, because the hub is this site parent and not another borough. */
.coverage_parent{text-align:center;margin:var(--s4) 0 0;color:var(--body)}
.coverage_parent a{font-weight:700}
.coverage_list{list-style:none;margin:var(--s4) 0 0;padding:0;display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px}
.coverage_list li{background:#fff;border:1px solid var(--rule);border-top:4px solid var(--primary);border-radius:var(--radius-sm);padding:20px 18px;text-align:center;font-size:1.06rem;font-weight:700;color:var(--ink)}
.coverage_list li a{font-weight:700;color:var(--primary-ink);display:block}
.coverage_list li a::after{content:" →"}
.coverage_list li a:hover{color:var(--ink)}

/* ------------------------------------------------------------------- faq */
.faq{border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{
  cursor:pointer;padding:18px 44px 18px 0;position:relative;list-style:none;
  min-height:56px;display:flex;align-items:center;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary h3{display:inline;margin:0;font-size:1.06rem;color:var(--ink)}
.faq summary:hover h3{color:var(--primary-ink)}
.faq summary::after{
  content:"+";position:absolute;right:6px;top:50%;transform:translateY(-50%);
  font-size:26px;font-weight:400;color:var(--primary-ink);line-height:1;
}
.faq details[open] summary::after{content:"\2212"}
.faq .answer{padding:0 0 var(--s3)}
.faq .answer p:last-child{margin-bottom:0}

.page_head{background:var(--ground-alt);border-bottom:1px solid var(--rule);padding:var(--s6) 0 var(--s5)}
.page_head h1{margin:0;font-size:clamp(1.9rem,3.4vw,2.6rem)}

/* -------------------------------------------------------------- final cta */
.cta_final{background:var(--ground-alt);border-top:3px solid var(--primary)}
.cta_final .measure{margin:0 auto}

/* ---------------------------------------------------------------- footer */
footer{background:var(--footer);color:#fff;padding:var(--s6) 0 0}
footer h3{color:#fff;font-size:1.05rem;font-weight:700;margin-bottom:var(--s2)}
footer a{color:rgba(255,255,255,.82)}
footer a:hover{color:#fff}
.footer_grid ul.plain a{color:var(--primary)}
.footer_grid ul.plain a:hover{color:#fff}
.footer_grid{display:grid;grid-template-columns:2fr 1fr 1fr;gap:var(--s5)}
.footer_logo{height:52px;width:auto;margin-bottom:var(--s2)}
.footer_lede{color:rgba(255,255,255,.7);max-width:38ch}
.footer_phone a{font-size:1.3rem;font-weight:900;color:#fff}
.footer_grid ul.plain li{margin-bottom:10px}
#copy{background-color:var(--primary);background-image:var(--stripes);margin-top:var(--s5);padding:var(--s3) 0}
.copy_inner{display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:var(--s2)}
#copy p{margin:0;color:rgba(43,46,49,.8);font-size:.9rem}
#copy a{font-size:.9rem;color:var(--ink);font-weight:700}
#copy a:hover{color:#000}

/* --------------------------------------------------------- sticky mobile */
.sticky_call{display:none}

/* ---------------------------------------------------------- breakpoints */
@media (max-width:980px){
  .grid_4{grid-template-columns:repeat(2,1fr)}
  .feat-grid[data-n="3"],.feat-grid[data-n="4"],.feat-grid[data-n="5"]{grid-template-columns:repeat(2,1fr)}
  .grid_3{grid-template-columns:1fr}
  .split{grid-template-columns:1fr;gap:var(--s3)}
  .split_left .split_media{order:0}
  .footer_grid{grid-template-columns:1fr 1fr}
  .header_cta{display:none}
  .nav_toggle{display:block;margin-left:auto}
  .main-menu{
    margin-left:0;position:absolute;top:100%;left:0;right:0;background:#fff;
    border-bottom:1px solid var(--rule);display:none;padding:var(--s2) var(--s3);
  }
  .main-menu.open{display:block}
  .main-menu ul{flex-direction:column;gap:0}
  .main-menu a{display:block;padding:14px 0;min-height:44px;border-bottom:1px solid var(--rule)}
  /* Tap targets: footer and utility links are 19-25px tall by default, which is under
     the 44px minimum on touch. Padding rather than font size, so the type scale holds. */
  .footer_grid ul.plain li{margin-bottom:2px}
  .footer_grid ul.plain a{display:inline-block;padding:11px 0;min-height:44px}
  .coverage_list li{padding:18px 14px;font-size:1rem}
  .top_line_phone{display:inline-block;padding:8px 0;min-height:44px;display:flex;align-items:center}
  #copy a{display:inline-block;padding:11px 0;min-height:44px}
  /* The sticky call control, and the room the page reserves so it covers nothing.
     The padding sits on the dark copyright bar rather than on body, so the reserved
     space is footer ground rather than a white strip under the footer. */
  .sticky_call{display:block;position:fixed;left:0;right:0;bottom:0;z-index:150;background:var(--primary);box-shadow:0 -2px 14px rgba(0,0,0,.22)}
  .sticky_call a{display:block;text-align:center;color:var(--ink);font-weight:700;padding:19px 16px;min-height:44px}
  #copy{padding-bottom:calc(var(--s3) + 64px)}
}
@media (max-width:640px){
  body{font-size:16px}
  .section{padding:var(--s5) 0}
  .grid_4{grid-template-columns:1fr}
  .feat-grid[data-n="3"],.feat-grid[data-n="4"],.feat-grid[data-n="5"]{grid-template-columns:1fr}
  .footer_grid{grid-template-columns:1fr;gap:var(--s4)}
  .top_line_tag{display:none}
  .top_line_inner{justify-content:flex-end}
  .band_inner{flex-direction:column;align-items:flex-start;gap:var(--s3)}
  .hero .opacity-mask{background:linear-gradient(180deg,rgba(20,24,22,.78) 0%,rgba(20,24,22,.88) 100%)}
  /* The horizontal gutter is KEPT at phone widths. This rule used to zero it, which put
     the kicker chip, the H1 and the lede hard against the left edge of the viewport. That
     had been true since before the refine pass and was easy to miss on white text over a
     dark photograph; it stopped being easy to miss the moment a light form card sat in the
     same container and ran edge to edge. .hero_inner is also .container, so this restores
     what the container already gives every other block on the page. */
  .hero_inner{padding:var(--s5) var(--gutter)}
  .steps li{padding-left:56px}
}
@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
  .services .service_card:hover{transform:none}
}
@media print{
  header,#top_line,.sticky_call,footer{display:none}
}

/* ==========================================================================
   THE REFINEMENT PASS — 2026-08-25
   ==========================================================================
   This site arrived in better shape than its siblings. The hero mask was already
   directional, the display range already ran 49.6px to 33.3px, the service card
   already lifted on hover, and the condition strip already carried the argument
   DESIGN-DNA section 3 says it must. What follows finishes it rather than
   rebuilds it.

   Measured on the served build rather than judged from the source:

     - getComputedStyle over every element of the home page returned ZERO
       box-shadows. `--shadow-soft` is REFERENCED by .place and was never
       DEFINED, so that rule resolved to its `none` fallback and the tile has sat
       flat since it was written. A dead token is the silent kind of defect: the
       source says elevation, the page has none, and nothing reports it.
     - ZERO animations and ZERO reveal targets. No js class on <html>.
     - Every section was 72px top and bottom. A metre, and therefore no emphasis.
     - `--muted` is #7b7f81: 4.04:1 on white and 3.84:1 on the #f9f9f9 ground,
       failing AA on both, and it carries every section intro and every condition
       note.

   THE MOTIF HERE IS NOT THE CLUSTER'S DIAGONAL, AND THAT IS DELIBERATE.
   Staten Island's refinement took the logo's diagonal slice as its shape
   language, and porting that here would break this repository's own recorded
   anti-patterns: DESIGN-DNA section 3 forbids a hazard-tape motif and chevron
   warning stripes in as many words, and names the visual metaphor as **the
   controlled opening** — "a clean rectangular void cut where a wall was, with
   everything either side of it intact. Strong rectangular blocks, hard edges,
   generous margins, photographs composed on right angles."

   So this pass is ORTHOGONAL throughout. Rules terminate square. Cards rise
   straight rather than travelling up and to the right. Nothing is set at 135
   degrees. Brooklyn is a sibling of Staten Island, not a copy of it.
   ========================================================================== */

/* -------- B.1 Tokens the pass needs ------------------------------------
   Warm rather than neutral black: this brand is a warm yellow on a warm
   graphite, and a pure-black shadow under a warm surface reads as dirt. */
:root {
  --lift-1: 0 1px 2px rgba(28, 24, 16, .05), 0 2px 8px -3px rgba(28, 24, 16, .09);
  --lift-2: 0 2px 5px rgba(28, 24, 16, .06), 0 12px 26px -8px rgba(28, 24, 16, .16);
  --lift-3: 0 4px 10px rgba(28, 24, 16, .07), 0 26px 52px -14px rgba(28, 24, 16, .26);

  /* DEFINED AT LAST. `.place` has read `var(--shadow-soft, none)` since it was
     written and this token has never existed, so every area tile fell through to
     the fallback and rendered flat. Pointed at the scale above rather than given
     a fourth private value. */
  --shadow-soft: var(--lift-1);

  --ease-out: cubic-bezier(.22, .61, .36, 1);

  /* WAS #7b7f81 — 4.04:1 on white and 3.84:1 on the #f9f9f9 alternating ground,
     so it failed AA on BOTH grounds it is used over, while carrying every
     .section_intro, the utility-line tag and every .stat_note. All ordinary-size
     running text. #6f7375 measures 4.79:1 on white and 4.55:1 on #f9f9f9 and
     passes on both.

     THIS IS THE VALUE STATEN ISLAND USES, and here that is correct rather than
     copied: this site shares that site's #f9f9f9 ground. It would NOT be correct
     on Bronx, Queens or Manhattan, whose tinted ground is #f4f3f1, where the
     same value measures 4.32:1 and fails. The value follows the ground, never
     the sibling. */
  --muted: #6f7375;
}

/* -------- B.2 The condition strip leads ---------------------------------
   DESIGN-DNA section 3 calls this the signature layout idea and says it "carries
   the site's entire credibility argument in place of the licence claims it does
   not have". It was set at 40px, smaller than the hero H1 and barely above a
   section title. It is now the loudest type on any page below the hero, in
   tabular figures so the digits align between tiles.

   NOTHING HERE COUNTS UP. DESIGN-DNA section 3 bans counters by name, an animated
   counter is the house style of the trust badge this strip exists to replace, and
   these are borough measurements rather than a record of this business's work.
   The figure is printed, at the size it deserves. */
.condition .stat {
  font-size: clamp(2.6rem, 4.4vw, 3.6rem);
  letter-spacing: -.035em;
  font-variant-numeric: tabular-nums;
}
/* The underline is DRAWN, scaling out from its left edge as the tile arrives, and
   it terminates SQUARE. This is the site's one accent mark and the place the
   orthogonal metaphor is most explicit. */
.condition .stat::after {
  transform-origin: left center;
  transition: transform .78s var(--ease-out) .12s;
}
.js .condition .stat::after { transform: scaleX(0); }
.js .condition.is-in .stat::after { transform: scaleX(1); }

/* -------- B.3 Surfaces, which could not say they were above -------------
   Every tile on the site sat flat behind a 1px keyline. */
.condition, .feat_card, .coverage_list li {
  box-shadow: var(--lift-1);
  transition: transform .3s var(--ease-out), box-shadow .3s var(--ease-out), border-color .2s ease;
}
.place { box-shadow: var(--lift-1); transition: transform .3s var(--ease-out), box-shadow .3s var(--ease-out); }

/* STRAIGHT UP, not up and to the right. The diagonal belongs to Staten Island;
   this site's metaphor is the clean rectangular opening and its blocks move on
   one axis. */
.services .service_card:hover,
.services .service_card:focus-visible,
.place:hover, .place:focus-within {
  transform: translateY(-6px);
  box-shadow: var(--lift-3);
}
.coverage_list li:has(a):hover { transform: translateY(-4px); box-shadow: var(--lift-2); }

/* The photograph moves under its own crop. Both cards already clip their image
   with overflow: hidden and object-fit: cover, so the crop is the frame. */
.service_card img, .place img { transition: transform .66s var(--ease-out); }
.services .service_card:hover img,
.services .service_card:focus-visible img,
.place:hover img { transform: scale(1.05); }

/* THE ARROW TRAVELS, AND IT CANNOT ORPHAN. Both of these were `content: " \2192"`
   — a normal space before the glyph, which is a legal line-break opportunity, so
   on a narrow card the arrow could drop to a line of its own under the link text.
   A non-breaking space has no break opportunity in front of it. The travel is on
   margin-left rather than transform, so the glyph moves and the layout does not. */
.service_card .more::after,
.coverage_list li a::after {
  content: "\00a0\2192";
  transition: margin-left .24s var(--ease-out);
}
.services .service_card:hover .more::after,
.coverage_list li a:hover::after,
.coverage_list li a:focus-visible::after { margin-left: 5px; }

.faq details { transition: background-color .2s ease; }
.faq details[open] { background: var(--ground-alt); }
.faq summary::after { transition: transform .3s var(--ease-out); }

/* -------- B.3b Tap targets at desktop, not only on touch ----------------
   The probe measured 22 links at 32px and 20px tall. Every one is an
   `<li><a>` in the header navigation or a footer list, and the cause is that
   both are `display: inline`, so the `padding: 6px 0` they already declare never
   expands the line box at all — it paints, and the hit area does not grow.

   THIS SITE ALREADY DECIDED 44px MATTERS. The <= 980px breakpoint gives these
   exact links `min-height: 44px` with a comment saying tap targets under the
   minimum are a defect. It just never applied the same floor above 980, where a
   trackpad and a shaky hand are no more accurate than a thumb. Applying it at
   every width is consistency with a decision this repository has already made,
   not a new one.

   inline-flex rather than more padding, because padding cannot do this job on an
   inline box. The two links the probe still reports are inline links inside
   running prose, and WCAG 2.5.8 excepts a target in a sentence. */
.main-menu a,
.footer_grid ul.plain a,
#copy a {
  display: inline-flex; align-items: center; min-height: 44px;
}
/* The coverage tile's link is already `display: block` and still only 28px tall,
   because a block box is only as tall as its line. It is centred rather than
   left-aligned like the lists above, because the tile it sits in is centred. */
.coverage_list li a {
  display: flex; align-items: center; justify-content: center; min-height: 44px;
}

/* THE FAQ BOUNDS ITSELF NOW, RATHER THAN RELYING ON WHATEVER WRAPS IT.
   Every page today renders it inside `<div class="container measure">`, so it has
   always LOOKED bounded, and `production-integrity.mjs` was right to report that
   no bounded width was declared for the container: the rule it reads is `.faq`
   itself, and that rule only ever set a border.

   The check is protecting something real rather than being pedantic. Bounding by
   parent means the day a page renders this block in a bare `.container` the
   questions stretch the full 1170px and nothing warns anybody. A component that
   is unreadable at full width should carry its own maximum.

   The value is the same `--measure` its wrapper already applies, so this changes
   not one pixel of any current page — verified by diffing the rendered text and
   the layout before and after. It only removes the dependency. */
.faq { max-width: var(--measure); margin-inline: auto; }

.btn {
  box-shadow: 0 1px 2px rgba(28, 24, 16, .12);
  transition: background .2s ease, border-color .2s ease,
              transform .2s var(--ease-out), box-shadow .2s var(--ease-out);
}
.btn:hover, .btn:focus-visible { transform: translateY(-2px); box-shadow: var(--lift-2); }
.btn:active { transform: translateY(0); box-shadow: 0 1px 2px rgba(28, 24, 16, .12); }

/* -------- B.3c The FAQ heading is centred over its block ----------------
   Operator instruction 2026-08-26, propagating the change made on the hub.

   Measured before the change: the heading rendered `text-align: start` at
   x359 w547, exactly the same box as the `.faq` beneath it. So it was already
   bounded and already aligned with the block, and only the text inside was
   ranged left. Every other property in this cluster already centres it - Bronx
   and Queens through `.section-title`, Manhattan through `.faq__heading`, and
   the hub since yesterday - so Brooklyn was the one that did not.

   Scoped by `:has()` to the container that actually holds an FAQ, so no other
   heading on the site is touched. Where `:has()` is unsupported the heading keeps
   the alignment it has today, which is the current state rather than a broken one. */
.container:has(> .faq) > h2 { text-align: center; }


/* -------- B.4 The hazard tape this site's own DESIGN-DNA forbids --------
   `#get_quote` and `#copy` both painted `--stripes` over the brand hue:
   `repeating-linear-gradient(135deg, rgba(0,0,0,.05) 0 14px, transparent 14px
   28px)`. Five per cent black sounds subtle and is not — across a full-bleed
   yellow band it renders as bold diagonal banding, and the widest, most
   prominent brand surface on the site read as hazard warning tape.

   DESIGN-DNA section 3, under anti-patterns, is explicit: "No hazard-tape motif,
   no chevron warning stripes. The hue is hazard yellow because it is the brand's,
   not because the site is trying to look dangerous." STATE.json names
   DESIGN-DNA.md as this repository's design authority, so the stylesheet was
   contradicting the file that governs it, on every page.

   The texture is replaced rather than merely deleted, because a flat full-bleed
   yellow band is a lot of undifferentiated colour. What replaces it runs
   VERTICALLY: a hairline rhythm at 90 degrees, which reads as structure — studs,
   lath, a stair run, the things this site's photography is actually of — and
   cannot read as a chevron. It is half the contrast of what it replaces. */
:root {
  --rhythm: repeating-linear-gradient(90deg, rgba(0, 0, 0, .028) 0 2px, rgba(0, 0, 0, 0) 2px 26px);
}
#get_quote, #copy { background-image: var(--rhythm); }

/* -------- B.5 A band with no action was still laid out as one -----------
   `.band_inner` is `justify-content: space-between`, and the band's action is
   conditional on a phone number this Point does not have, so the band renders a
   single message stranded on the left of the full container with the rest empty
   — a layout expressing an element that is not there. Where the action is
   genuinely absent the message centres and takes a readable measure.

   NOTHING IS ADDED TO FILL IT and no number is invented. Scoped to :only-child,
   so the moment a phone exists the action returns and this rule stops applying
   on its own.

   SEPARATELY, AND NOT FIXABLE HERE: the band's copy reads "Call and describe the
   building", on every page of a site that publishes no number anywhere. That is
   a CONTENT defect, not a presentation one, and copy is not this stage's to
   change. Recorded in CHANGELOG.md and STATE.json for the Builder and the
   operator. */
.band_inner > div:only-child {
  max-width: 74ch;
  margin-left: auto; margin-right: auto;
  text-align: center;
}

/* -------- B.6 Section rhythm --------------------------------------------
   Every section was 72px top and bottom. The two that are meant to land harder
   get more room than the sections that merely continue: the conditions strip,
   which carries the credibility argument, and the process band, which is the one
   full-bleed dark moment on the page. */
.conditions { padding: calc(var(--s6) * 1.2) 0; }
.process { padding: calc(var(--s6) * 1.25) 0; }

/* -------- B.7 The hero, which was the one thing already alive ----------
   The mask was already directional and is left alone: 90deg from .86 to .42,
   heaviest under the copy and clearing across the frame. That is the treatment
   this pass would otherwise have introduced, and it was already right.

   What the hero did not have was any movement. Six per cent of scale across 34
   seconds is below the rate at which movement is seen AS movement, so the band
   never appears to animate; a reader who scrolls back up simply finds the frame
   has opened out.

   The photograph is on the section's own background-image, set per page by a
   generated rule, so there is no <img> to scale. `background-image: inherit` on a
   pseudo-element takes the parent's computed value — the same url — so the drift
   layer is the same photograph painted over the parent's static copy, never
   scaling below 1.015 so the copy underneath is never exposed. No markup change
   and no second request.

   `overflow: hidden` is required and is safe here: nothing in the hero sits at a
   negative offset. */
.hero { position: relative; overflow: hidden; }
.hero::before {
  content: ""; position: absolute; inset: 0;
  background-image: inherit;
  background-size: cover; background-position: center;
  animation: hero-open 34s var(--ease-out) infinite alternate;
  will-change: transform;
  pointer-events: none;
}
.hero .opacity-mask { position: relative; z-index: 1; }
@keyframes hero-open {
  from { transform: scale(1.015); }
  to   { transform: scale(1.075) translate3d(-1%, -.8%, 0); }
}

/* -------- B.8 The motion vocabulary -------------------------------------
   This site had NO reveal of any kind. Four families now arrive differently, and
   the difference says what kind of thing is arriving. ALL OF THEM ARE
   ORTHOGONAL: nothing travels on a diagonal, because that is Staten Island's
   shape language and this site's is the square opening.

     a heading                rises a little, quickly, and gets out of the way
     a tile, card or stage    rises straight, and its rule draws itself in
     a photograph             rises and settles out of a very slight scale
     a coverage tile          rises straight, linked and unlinked identically

   NOTHING IS HIDDEN UNTIL A SCRIPT HAS CONFIRMED IT CAN UNHIDE IT. Every rest
   state is scoped to `.js`, which boot.js sets from <head> before first paint. */
.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 20px, 0);
  transition: opacity .62s var(--ease-out), transform .62s var(--ease-out);
}
.js .section_title[data-reveal] {
  transform: translate3d(0, 12px, 0);
  transition-duration: .46s;
}
.js .condition[data-reveal],
.js .feat_card[data-reveal],
.js .box_feat[data-reveal],
.js .coverage_list li[data-reveal] { transform: translate3d(0, 26px, 0); }
.js .split_media[data-reveal],
.js .place[data-reveal] { transform: translate3d(0, 24px, 0) scale(.985); }
.js [data-reveal].is-in { opacity: 1; transform: none; }

/* AND THE COLLISION THAT CREATES, RESTATED RATHER THAN LEFT TO LUCK.
   `.js [data-reveal].is-in { transform: none }` is (0,3,0). `.place:hover` is
   (0,1,1) and `.coverage_list li:has(a):hover` is (0,2,2). Both are reveal
   targets, so the FINISHED REVEAL OUTRANKS THE LIFT on every one a reader can
   actually point at, and the hover does nothing while looking perfectly correct
   in the source. Declared here at a weight that wins.

   `.service_card` is deliberately NOT in this list: it carries no data-reveal,
   because the homepage set becomes a carousel whose cards are cloned at runtime.
   See B.10. */
.js .place[data-reveal].is-in:hover,
.js .place[data-reveal].is-in:focus-within { transform: translateY(-6px); }
.js .coverage_list li[data-reveal].is-in:has(a):hover { transform: translateY(-4px); }

/* ==========================================================================
   B.10 THE SERVICES SHOWCASE — SiteKit animated-carousel-v1, 2026-08-25
   ==========================================================================
   Declared in data/site-plan.json at project.ui_contracts.services_showcase on
   explicit operator instruction. Before it the four services were a static grid
   and this repository was a legacy candidate, which preflight --post-refine
   correctly failed on the UI-contract rule as migration debt.

   SiteKit's behaviours.js owns the endless loop, the clone sets on both sides,
   the arrows and every hold on automatic motion, and carries the marker
   SITEKIT-CAROUSEL-V1 that production-integrity.mjs requires of any page
   declaring [data-carousel-autoplay]. safeguards.css already makes the track a
   native scroll container, already sets every child to flex: 0 0 auto, and
   already exempts an autoplaying track from snapping for its whole life. None of
   that is restated here.

   THE ONE THING THAT DECIDES WHETHER IT MOVES AT ALL IS IN THIS FILE.
   behaviours.js measures the ORIGINAL cards, never the cloned track:

       var overflows = function () { return setWidth() - track.clientWidth > 1; };

   A set that already fits gets no clones, no controls and NO MOTION, on purpose,
   because arrows that cannot act read as broken. Every breakpoint below is chosen
   so FOUR cards overflow, and each carries its arithmetic. The container is
   1170px with 24px of padding each side, so the widest track is 1122px.
   ========================================================================== */

.showcase { position: relative; }

/* -------- B.10.1 The controls -------------------------------------------
   Inside [data-carousel], because that is where the contract looks for them.
   Real <button>s with real accessible names.

   Graphite on white, not hazard. This site has exactly one filled-hazard surface
   language and the band already owns it; a pair of yellow arrows beside the
   service cards would compete with the brand band for the same attention. Square
   corners at --radius-sm, because the shape language here is the right angle. */
.showcase-nav { display: flex; justify-content: flex-end; gap: 10px; margin: 0 0 18px; }
.cbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; padding: 0;
  border: 1px solid var(--rule); border-radius: var(--radius-sm);
  background: #fff; color: var(--ink);
  font-size: 17px; line-height: 1; cursor: pointer;
  box-shadow: var(--lift-1);
  transition: background-color .2s ease, color .2s ease, border-color .2s ease,
              transform .22s var(--ease-out), box-shadow .22s var(--ease-out);
}
.cbtn:hover { background: var(--primary); border-color: var(--primary); color: var(--ink); box-shadow: var(--lift-2); }
/* The travel matches the direction the control moves the track, so the button
   says which way it is about to go before it is pressed. */
.cbtn[data-carousel-prev]:hover { transform: translateX(-2px); }
.cbtn[data-carousel-next]:hover { transform: translateX(2px); }
.cbtn:active { transform: translateY(1px); box-shadow: var(--lift-1); }
.cbtn:focus-visible { outline: 3px solid var(--primary); outline-offset: 3px; }

/* -------- B.10.2 The track ----------------------------------------------
   `overflow-x: auto` computes overflow-y to auto as well, so a card that lifts on
   hover is clipped by its own track unless the track is padded. The negative
   inline margin puts the cards back on the container's own edge. */
.showcase-track {
  gap: var(--s3);
  margin: 0 -6px;
  padding: 8px 6px 26px;
  list-style: none;
  /* The arrows are the affordance, and a scrollbar under a track that is always
     drifting is a control that appears to move on its own. Finger, trackpad and
     keyboard scrolling are untouched. */
  scrollbar-width: none;
}
.showcase-track::-webkit-scrollbar { display: none; }
.showcase-item { display: flex; }
.showcase-item > .service_card { width: 100%; display: flex; flex-direction: column; }
.showcase-item > .service_card p { flex: 1 1 auto; }

/* -------- B.10.3 How many cards a width shows ---------------------------
   4 x basis + 3 x 24 must exceed the track. Percentages resolve against the
   track, so anything at or above 26% overflows on its own. */
.showcase-item { flex: 0 0 84%; }                                   /* 4 x 84% = 336% of W */

@media (min-width: 560px) { .showcase-item { flex-basis: 62%; } }   /* 248% of W */
@media (min-width: 768px) { .showcase-item { flex-basis: 46%; } }   /* 184% of W */
@media (min-width: 992px) { .showcase-item { flex-basis: 40%; } }   /* 160% of W */

@media (min-width: 1200px) {
  /* 29% of the 1122px content width is 325px, so the set measures
     4 x 325 + 3 x 24 = 1372 against a 1122 track: 250px of overflow, which is
     most of a card pitch of real travel. Roughly 3.2 cards are visible, which is
     also the composition that tells a reader the row continues.

     NEVER narrow these without re-checking the overflow. The failure is silent:
     a still carousel that passes every gate. */
  .showcase-item { flex-basis: clamp(280px, 29%, 340px); }
}

/* -------- B.10.4 The pace ------------------------------------------------
   data-carousel-speed="28", in px/second, inside the behaviour's 10-70 clamp.
   The card pitch at the widest breakpoint is 325 + 24 = 349px, so a card advances
   one place every 12.5 seconds — inside the eight to fourteen the refine stage
   asks for. Fast enough to read as movement rather than as a rendering fault,
   slow enough that nobody is chasing a heading they were half way through.

   NO data-reveal ON A CARD. The behaviour clones the set at runtime and the
   reveal observer only watches what it queried at boot, so a cloned card would
   sit at opacity 0 for ever. The reveal is on the showcase root, which is never
   cloned. The card is otherwise unchanged from the static grid it also renders
   in on the service pages, and the two must not drift apart. */

/* ==========================================================================
   THE HERO LEAD FORM — 2026-08-26
   ==========================================================================
   Operator instruction: the form goes in the hero, on every property in the
   cluster.

   THE HERO IS NOW TWO COLUMNS at desktop, statement left and form right, and the
   mask on this site was ALREADY directional — heaviest where the copy is and
   clearing to the far side. The treatment that was already correct for the
   photograph turns out to be correct for a light card sitting on it.

   BELOW 62rem THE FORM GOES UNDER THE STATEMENT rather than beside it. A form
   squeezed into half a phone screen is a form nobody completes.
   ========================================================================== */
.hero__form, .hero_form { width: 100%; }
@media (min-width: 62rem) {
  /* SCOPED TO A HERO THAT HAS A FORM. The form is on the homepage only, and every
     other page shares this same hero template. An unscoped two-column rule would
     leave those pages holding an empty right-hand column, which reads as a broken
     container rather than as a decision. */
  .hero .container:has(.lead-form), .hero .opacity-mask > .container:has(.lead-form) {
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(0, .88fr);
    gap: 52px;
    align-items: center;
  }
  .hero__form, .hero_form { justify-self: end; max-width: 26.5rem; }
}
@media (max-width: 61.99rem) {
  .hero__form, .hero_form { margin-top: 32px; max-width: 30rem; }
}

/* -------- The form is a card, because it is genuinely a surface ----------
   This is the one place on the page where a surface really IS above another: a
   light panel on a photograph. It takes the top of the elevation scale and a 4px
   hazard edge, so the brand owns the moment rather than the browser's default
   white. */
.lead-form {
  background: var(--white, #fff);
  border-top: 4px solid var(--hazard, var(--primary, #f6bd19));
  border-radius: 3px;
  box-shadow: var(--lift-3, 0 4px 10px rgba(28,24,16,.07), 0 26px 52px -14px rgba(28,24,16,.26));
  padding: 24px 24px 20px;
  color: var(--ink, #343333);
  text-align: left;
}
.lead-form-heading { font-size: 1.14rem; margin: 0 0 15px; color: var(--ink, #343333); }

.lead-row { display: grid; gap: 0 13px; }
@media (min-width: 30rem) { .lead-row { grid-template-columns: 1fr 1fr; } }

.lead-field { margin: 0 0 13px; }
.lead-field label {
  display: block; font-size: .8rem; font-weight: 700; letter-spacing: .02em;
  color: var(--ink, #343333); margin-bottom: 6px;
}
.lead-optional { font-weight: 400; color: var(--steel, var(--body, #565a5c)); letter-spacing: 0; }
.lead-field input,
.lead-field textarea {
  width: 100%; box-sizing: border-box;
  font: inherit; font-size: .95rem; color: var(--ink, #343333);
  background: var(--white, #fff);
  border: 1px solid var(--rule, #dddcd8); border-radius: 2px;
  padding: 10px 12px;
  /* 44px minimum, like every other control. A field a thumb misses is a lead
     lost at the last step. */
  min-height: 44px;
  transition: border-color .18s ease, box-shadow .18s ease;
}
.lead-field textarea { min-height: 64px; resize: vertical; }
.lead-field input:hover,
.lead-field textarea:hover { border-color: #c9c9c6; }
.lead-field input:focus-visible,
.lead-field textarea:focus-visible {
  outline: 3px solid var(--focus, var(--hazard-ink, var(--primary-ink, #7a5f00)));
  outline-offset: 2px;
  border-color: var(--hazard, var(--primary, #f6bd19));
}

/* THE HONEYPOT IS NOT `display: none`. A field a bot can detect as hidden is a
   field it learns to skip, and some assistive technology skips display:none too,
   which is why it also carries aria-hidden and tabindex="-1". Positioned out of
   the flow instead: no space, and unreachable by keyboard, pointer or screen
   reader. */
.lead-hp {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

.lead-actions { margin: 2px 0 0; }
.lead-actions .btn, .lead-actions button { width: 100%; text-align: center; }

/* `role="status" aria-live="polite"`, so it is announced when it changes and
   silent when empty. It reserves no space until it has something to say, because
   an empty gap under a button reads as a missing element. */
.lead-status { margin: 11px 0 0; font-size: .88rem; line-height: 1.45; }
.lead-status:empty { display: none; }
.lead-status[data-state="busy"]  { color: var(--steel, var(--body, #565a5c)); }
.lead-status[data-state="ok"]    { color: #1c6b3a; font-weight: 700; }
.lead-status[data-state="error"] { color: #a3261c; font-weight: 700; }

.lead-noscript { margin: 0 0 11px; font-size: .88rem; color: var(--steel, var(--body, #565a5c)); }
.lead-consent { margin: 11px 0 0; font-size: .78rem; line-height: 1.5; color: var(--steel, var(--body, #565a5c)); }

/* The privacy link inside it was a 120x15 tap target, the ONE control on this site
   under the 24px WCAG 2.2 AA minimum and the only one the baseline does not also have.
   Padding rather than a bigger font: the consent line is deliberately quiet and should
   stay quiet, so the hit area grows and the type does not. inline-block is what makes
   the vertical padding count toward the box a pointer actually has to hit. */
.lead-consent a { display: inline-block; padding-block: 5px; }

/* -------- Two primaries in one region, and why that is allowed -----------
   The hero now carries a filled call button and a filled submit. The probe reads
   two competing primaries and that is a fair reading of the pixels, but they are
   one action per REGION: the statement column offers the call, the form column
   offers the send, and the card's elevation is what makes the second region a
   region rather than a loose second button.

   The submit is deliberately not a ghost. A send control quieter than the button
   beside it steers the reader away from the thing just added. */


/* ==========================================================================
   THE HERO CLIP — 2026-08-26
   ==========================================================================
   Operator instruction: the hero carries a video, as the baseline's does.

   THE ELEMENT IS EMITTED ONLY WHEN A CLIP ACTUALLY EXISTS. The build checks for
   the file and, finding none, renders the hero exactly as it renders today and
   says so on the console. A <video> pointing at a 404 is a broken element that
   every check passes, which is the worst of the three possible states. Drop a
   clip at the path the build names and it appears with no further edit.

   THE POSTER IS NOT A FALLBACK, IT IS THE HERO. It paints immediately, carries
   the LCP, and is the whole hero for a reader who never receives the clip: on a
   reduced-motion preference, on a metered or 2G connection, before load fires,
   and wherever autoplay is declined. The clip is layered ON it at the same
   stacking position, so there is no reflow and nothing to see if it never comes.

   NO KEN BURNS ON A HERO THAT CARRIES A CLIP. Scaling a still under its own
   playback is two motions arguing, and it is why the baseline leaves its hero as
   the one section its refinement pass gave no drift.
   ========================================================================== */
.hero { position: relative; }
.hero-video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  z-index: 0;
  pointer-events: none;
}
/* The clip sits UNDER everything the hero says. Both the masked and unmasked
   hero shapes in this cluster are covered, because a z-index on a static element
   does nothing and the omission would put the clip over the headline. */
.hero > .hero__mask { z-index: 1; }
.hero > .container,
.hero > .opacity-mask,
.hero__form { position: relative; z-index: 2; }


/* ==========================================================================
   B.9 THE REDUCED-MOTION PATH, RESTATED
   ==========================================================================
   THIS BLOCK IS LOAD-BEARING AND MUST STAY LAST IN THIS FILE.

   The stylesheet already carries `@media (prefers-reduced-motion: reduce)
   { * { transition: none !important; animation: none !important } }` further up.
   That block is NOT enough and would have shipped a broken page: it resets
   transition and animation and it does NOT reset `opacity` or `transform`. Every
   reveal above arms itself at `opacity: 0`, so a reader who asked for less motion
   would have got a page whose content was permanently invisible, with the
   transition that was meant to reveal it switched off.

   That is also the exact condition render-probe.mjs raises as a hard INVARIANT
   rather than a suspicion, because the probe captures WITH the preference
   emulated — so the screenshots meant to prove this design would have been
   screenshots of the defect.

   `transform: none` is the identity transform, which is what the drawn underline
   wants: a rule that never animates is a rule at full width. */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js .section_title[data-reveal],
  .js .condition[data-reveal],
  .js .feat_card[data-reveal],
  .js .box_feat[data-reveal],
  .js .coverage_list li[data-reveal],
  .js .split_media[data-reveal],
  .js .place[data-reveal] { opacity: 1 !important; transform: none !important; }

  .js .condition .stat::after { transform: none !important; }

  .hero::before { animation: none !important; transform: none !important; }

  /* And the hover travel, consistently. Suppressing transforms on reveal targets
     already killed the tile lifts; the button and the service card are not reveal
     targets and would otherwise still displace themselves while their neighbours
     did not. Nothing about the affordance is lost — every one of these still
     answers a pointer with its elevation and its colour. */
  .btn:hover, .btn:focus-visible, .btn:active,
  .services .service_card:hover, .services .service_card:focus-visible,
  .cbtn:hover, .cbtn:active { transform: none !important; }
}


/* Hero photography, one rule per page. Set here rather than in a style
   attribute because the Content-Security-Policy forbids inline styles. */
.hero--home{background-image:url("/assets/img/hero-home.e0bda546c7b3.webp")}
.hero--interior-demolition{background-image:url("/assets/img/hero-interior-demolition.5b0f3f02b16f.webp")}
.hero--building-demolition{background-image:url("/assets/img/hero-building-demolition.27a44da7b414.webp")}
.hero--concrete-removal{background-image:url("/assets/img/hero-concrete-removal.22fc16735262.webp")}
.hero--debris-removal{background-image:url("/assets/img/hero-debris-removal.5aca4d9f2bdc.webp")}
.hero--what-decides-the-cost{background-image:url("/assets/img/hero-cost.337e4f306e6c.webp")}
.hero--where-we-work{background-image:url("/assets/img/hero-where-we-work.687d6d0e2a94.webp")}
.hero--about{background-image:url("/assets/img/hero-about.744613a28eff.webp")}
.hero--contact{background-image:url("/assets/img/hero-contact.b7c243c416fe.webp")}
