/* =========================================================================
   Valley Mobile Auto Glass — commercial system v2
   White base · strong navy blocks · large photography · chunky sans.
   Direction: established regional auto glass company. Trust + urgency.
   No serif anywhere. No pale washes. Action is always red and always visible.
   Every text pairing WCAG-AA verified by computation before build.
   ========================================================================= */

:root{
  --w:#ffffff;
  --snow:#f2f5f7;          /* alternating band, never the main ground */
  --line:#dde4e9;
  --line-2:#c9d4dc;

  --ink:#101d28;
  --ink-soft:#4a5b68;

  --navy:#123a5a;          /* block ground + headings */
  --navy-d:#0b2740;        /* deepest block / footer */
  --blue:#1a6ba0;          /* links, secondary accents */

  --red:#c8281f;           /* ACTION only — calls, primary CTAs */
  --red-d:#a81f18;         /* hover */
  --rose:#ffb4ab;          /* accent TEXT on navy (6.95:1) */

  --ease:cubic-bezier(.16,1,.3,1);
  --shell:min(1280px,92vw);
  --hdr-h:82px;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0; background:var(--w); color:var(--ink);
  font-family:'Archivo','Helvetica Neue',Arial,sans-serif;
  font-size:17px; line-height:1.6; -webkit-font-smoothing:antialiased;
}
img{max-width:100%; display:block}
a{color:inherit}

/* Heading system.
   The old scale stacked four emphasis devices on the same text - 900/800 weight,
   ALL CAPS, tight tracking, and a very large size - so every section heading
   shouted. Measured: h2 rendered at 42px, 2.6x the body copy and only 6px short
   of the h1, so a page had almost no hierarchy between its title and its
   sections, and a 27-character heading still wrapped to two lines.
   The fix is to let ONE device do the work at each level:
     - h1 keeps caps (it is the page title, and there is only one) but drops to
       800 and a calmer size.
     - h2 drops CAPS entirely and steps down to ~1.9x body. Sentence case at 700
       reads as a section heading without competing with the h1; the eyebrow
       chip above it already provides the all-caps signal.
     - Tracking is relaxed everywhere: tight letter-spacing amplifies apparent
       weight and closes the counters of S, A and R at display sizes. */
h1,h2,h3,h4{
  font-family:'Archivo',sans-serif; font-weight:700;
  line-height:1.12; letter-spacing:-.015em; color:var(--navy); margin:0;
  text-wrap:balance;
}
h1{font-size:clamp(1.95rem,3.4vw,2.9rem); font-weight:800; letter-spacing:-.02em;
   text-transform:uppercase; line-height:1.08; color:var(--ink)}
h2{font-size:clamp(1.45rem,2.1vw,1.95rem); font-weight:700; letter-spacing:-.014em;
   line-height:1.16}
h3{font-size:clamp(1.02rem,1.35vw,1.18rem); font-weight:700; letter-spacing:-.006em}
h4{font-size:1rem; font-weight:700}
p{margin:0 0 1rem}
strong{font-weight:700}

/* eyebrow — a solid red tab, not a hairline */
.eyebrow{
  display:inline-block; background:var(--red); color:#fff;
  font-size:.7rem; font-weight:800; letter-spacing:.14em; text-transform:uppercase;
  padding:.42rem .78rem; margin:0 0 1.1rem;
}
.eyebrow.alt{background:var(--navy)}
.eyebrow.on-dark{background:var(--rose); color:var(--navy-d)}

.lede{font-size:clamp(1.03rem,1.2vw,1.16rem); color:var(--ink-soft); max-width:62ch}
.dark .lede{color:rgba(255,255,255,.88)}

.shell{width:var(--shell); margin-inline:auto}
section{padding:clamp(62px,8vh,104px) 0}
/* A short section got the same 96px top and bottom as a 900px one, so a band
   holding ~200px of copy was more air than substance and read as a gap in the
   page rather than a unit of content (35 sections across 23 pages).
   .tight trims the padding for genuinely small sections; the renderer applies it
   from the content's own size, so it can never fight a long section. */
section.tight{padding:clamp(40px,5vh,64px) 0}
.snow{background:var(--snow)}
.dark{background:var(--navy); color:#fff}
.darker{background:var(--navy-d); color:#fff}
.dark h2,.dark h3,.dark h4,.darker h2,.darker h3,.darker h4{color:#fff}
.dark p,.darker p{color:rgba(255,255,255,.88)}
.darker .lede{color:rgba(255,255,255,.88)}
.darker .checks svg{color:var(--rose)}
.darker .areas a{background:rgba(255,255,255,.09); color:#fff; border-color:rgba(255,255,255,.24)}
.darker .areas a:hover{background:#fff; color:var(--navy); border-color:#fff}

/* section head */
.shead{margin-bottom:clamp(1.9rem,3.4vw,2.8rem); max-width:74ch}
.shead h2{max-width:30ch}
h2{margin-bottom:1.05rem}
h2 + .lede{margin-top:0}

/* ---------- buttons: solid, chunky, unmistakable ------------------------- */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:.6rem;
  font-weight:800; font-size:.86rem; letter-spacing:.06em; text-transform:uppercase;
  text-decoration:none; padding:1.12rem 1.75rem; border:2px solid var(--red);
  background:var(--red); color:#fff; position:relative;
  transition:background .28s var(--ease), border-color .28s var(--ease), transform .28s var(--ease);
}
.btn:hover{background:var(--red-d); border-color:var(--red-d); transform:translateY(-2px)}
.btn .arw{transition:transform .3s var(--ease)}
.btn:hover .arw{transform:translateX(4px)}
.btn-navy{background:var(--navy); border-color:var(--navy)}
.btn-navy:hover{background:var(--navy-d); border-color:var(--navy-d)}
.btn-out{background:transparent; color:var(--navy); border-color:var(--line-2)}
.btn-out:hover{background:var(--navy); border-color:var(--navy); color:#fff}
.btn-out.on-dark{color:#fff; border-color:rgba(255,255,255,.4)}
.btn-out.on-dark:hover{background:#fff; color:var(--navy); border-color:#fff}
.btn-lg{padding:1.28rem 2.1rem; font-size:.92rem}
.btn-block{width:100%}

/* ---------- header ------------------------------------------------------- */
.topbar{background:var(--navy-d); color:#fff}
.topbar-in{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  min-height:40px; font-size:.79rem; font-weight:500;
}
.topbar b{color:var(--rose); font-weight:700}
.topbar .tb-r{display:flex; gap:1.4rem; align-items:center}

.hdr{position:sticky; top:0; z-index:70; background:#fff; border-bottom:1px solid var(--line)}
.hdr.stuck{box-shadow:0 3px 18px rgba(16,29,40,.11)}
.hdr-in{display:flex; align-items:center; gap:1.2rem; min-height:var(--hdr-h)}
.brand{display:flex; align-items:center; gap:.7rem; text-decoration:none; margin-right:auto}
.brand img{width:52px; height:52px}
.brand b{font-size:1rem; font-weight:900; letter-spacing:-.01em; text-transform:uppercase;
         color:var(--navy); line-height:1.1; display:block}
.brand span{display:block; font-size:.66rem; font-weight:600; letter-spacing:.13em;
            text-transform:uppercase; color:var(--red)}
/* In the FOOTER the same brand lockup sits on near-black navy, where --red is
   2.74:1 - under AA for this 10.5px text. --rose is the established on-dark
   accent elsewhere in the system and clears it comfortably. */
.ftr .brand b{color:#fff}
.ftr .brand span{color:var(--rose)}

.nav{display:flex; align-items:center; gap:.15rem}
.nav>a,.nav .has-menu>a{
  display:block; text-decoration:none; font-size:.86rem; font-weight:700;
  text-transform:uppercase; letter-spacing:.02em; color:var(--ink);
  padding:.7rem .8rem; transition:color .25s var(--ease);
}
.nav a:hover,.nav a[aria-current]{color:var(--red)}

.hdr-cta{display:flex; align-items:center; gap:.7rem}
.hdr-tel{
  display:flex; flex-direction:column; text-decoration:none; line-height:1.15;
}
.hdr-tel small{font-size:.64rem; font-weight:700; letter-spacing:.1em;
               text-transform:uppercase; color:var(--ink-soft)}
.hdr-tel b{font-size:1.16rem; font-weight:900; color:var(--red); letter-spacing:-.01em}

.has-menu{position:relative}
.menu{
  position:absolute; top:100%; left:0; min-width:300px; background:#fff;
  border:1px solid var(--line); border-top:3px solid var(--red);
  box-shadow:0 20px 44px rgba(16,29,40,.16); padding:.4rem;
  opacity:0; visibility:hidden; transform:translateY(-6px);
  transition:opacity .25s var(--ease), transform .25s var(--ease), visibility .25s;
}
.has-menu:hover .menu,.has-menu:focus-within .menu{opacity:1; visibility:visible; transform:none}
.menu a{display:block; padding:.6rem .8rem; font-size:.85rem; font-weight:600;
        text-decoration:none; text-transform:none; letter-spacing:0}
.menu a:hover{background:var(--snow); color:var(--red)}
.menu.cols{min-width:460px; display:grid; grid-template-columns:1fr 1fr}

.burger{display:none; background:var(--navy); border:0; padding:.72rem .8rem; cursor:pointer}
.burger span{display:block; width:20px; height:2.5px; background:#fff; margin:4px 0}

/* ---------- hero: big photo, hard navy, immediate action ----------------- */
/* .hero is a <section>, so the generic `section{padding:...}` rule applies its
   own 72px bottom padding ON TOP of .hero-in's — the two stacked into a ~158px
   void above the action bar on every page. The hero manages its own rhythm via
   .hero-in, so zero it here. */
.hero{position:relative; background:var(--navy-d); color:#fff; overflow:hidden; padding:0}
.hero-bg{position:absolute; inset:0}
/* The source photos are square (1100x1100). Left to itself the img contributes
   its own intrinsic height to the hero, pushing the section ~105px taller than
   its copy and leaving a void above the action bar. absolute + object-fit makes
   the hero's height come from the COPY, with the photo cropping to fill. */
.hero-bg img{position:absolute; inset:0; width:100%; height:100%;
             object-fit:cover; object-position:center 38%}
.hero-bg::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(100deg, rgba(11,39,64,.96) 0%, rgba(11,39,64,.92) 42%,
             rgba(11,39,64,.62) 66%, rgba(11,39,64,.34) 100%);
}
.hero-in{position:relative; padding:clamp(50px,7vw,86px) 0 clamp(54px,7vw,88px)}
.hero-copy{max-width:min(660px,62%)}
/* Proof chips are supporting evidence, not body copy. They live outside the
   copy column's 62% cap so they resolve to two tidy rows, not a ragged 2/2/1.
   (A child cannot exceed its parent's max-width — widening .proof alone is a
   no-op; the constraint has to be lifted here.) */
.hero-proof{max-width:min(900px,84%); margin-top:1.4rem}

.hero h1{color:#fff; margin-bottom:1.1rem}
.hero h1 .hl{
  color:#fff; background:var(--red); padding:0 .18em .06em;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
}
.hero .lede{color:rgba(255,255,255,.9); font-size:clamp(1.02rem,1.2vw,1.12rem)}

.hero-cta{display:flex; flex-wrap:wrap; gap:.8rem; margin:1.7rem 0 1.5rem}

/* proof bar — solid chips, not check marks in a list */
/* Proof chips sized themselves to their own text (white-space:nowrap), so five
   or six chips of different lengths packed unevenly and left a lone orphan on
   the last row - 30 of 31 pages. Letting them grow to share the leftover space
   evens the rows out; wrapping is allowed so a long label no longer forces the
   chip to hold a width nothing else can match. */
.proof{display:flex; flex-wrap:wrap; gap:.5rem; padding:0; margin:0; list-style:none}
.proof li{
  display:flex; align-items:center; gap:.5rem; font-size:.76rem; font-weight:700;
  letter-spacing:.01em; background:rgba(255,255,255,.11); color:#fff;
  border-left:3px solid var(--red); padding:.5rem .72rem;
  /* Grow to even out a row, but never past a sane label width: an unrestrained
     flex-grow stretched a lone trailing chip across ~900px, which reads worse
     than the orphan it was meant to fix. */
  flex:1 1 auto; max-width:22rem;
}
@media (max-width:1240px){.proof li{font-size:.72rem; padding:.45rem .6rem}}
/* On a phone the chips stack two-up: one per row wastes the width, and the
   natural-width packing produced a lumpy 1/1/2/1 arrangement. */
@media (max-width:620px){
  .proof{display:grid; grid-template-columns:1fr 1fr; gap:.45rem}
  .proof li{font-size:.7rem; padding:.5rem .6rem}
  .proof li:last-child:nth-child(odd){grid-column:1 / -1}
}

/* red action bar riding the hero fold */
.actionbar{background:var(--red); color:#fff}
.actionbar-in{
  display:flex; flex-wrap:wrap; align-items:center; justify-content:space-between;
  gap:1rem; padding:1.05rem 0;
}
.actionbar p{margin:0; font-weight:800; font-size:1.02rem; letter-spacing:.01em; text-transform:uppercase}
.actionbar .ab-tel{
  display:inline-flex; align-items:center; gap:.6rem; text-decoration:none;
  background:#fff; color:var(--red); font-weight:900; font-size:1.08rem;
  padding:.72rem 1.3rem; transition:transform .28s var(--ease);
}
.actionbar .ab-tel:hover{transform:translateY(-2px)}

/* ---------- trust strip -------------------------------------------------- */
/* The marquee ran edge to edge, so logos were sliced in half against both
   viewport edges instead of gliding in and out. A mask fades the ends into the
   white ground; -webkit- included because Safari still needs the prefix. */
/* The marquee ran edge to edge, so logos were sliced against both viewport
   edges instead of gliding in and out. Fade the ends with a pair of gradient
   overlays pinned to the STRIP (a mask on .track would travel with the
   animation and wash across the logos). Pseudo-elements avoid mask-image
   support questions entirely and paint the same white as the band. */
.strip{border-bottom:1px solid var(--line); padding:1.6rem 0; overflow:hidden;
       background:#fff; position:relative}
.strip::before,.strip::after{
  content:''; position:absolute; top:0; bottom:0; width:clamp(40px,7vw,110px);
  z-index:2; pointer-events:none;
}
.strip::before{left:0;  background:linear-gradient(90deg,#fff,rgba(255,255,255,0))}
.strip::after {right:0; background:linear-gradient(270deg,#fff,rgba(255,255,255,0))}
.strip-lab{font-size:.7rem; font-weight:800; letter-spacing:.15em; text-transform:uppercase;
           color:var(--ink-soft); text-align:center; margin:0 0 1.1rem}
.track{display:flex; width:max-content; animation:slide 36s linear infinite}
.strip:hover .track{animation-play-state:paused}
@keyframes slide{to{transform:translateX(-50%)}}
/* .55 opacity ON TOP of grayscale left the lighter marks (Ford, Toyota, ASE)
   barely readable against white. Grayscale already does the unifying work, so
   the opacity only needs to take the edge off. */
.track img{height:36px; width:auto; margin:0 clamp(1.4rem,3vw,2.8rem);
           opacity:.78; filter:grayscale(1); transition:opacity .3s var(--ease), filter .3s var(--ease)}
.track img:hover{opacity:1; filter:none}

/* ---------- service cards: photo-led, solid, clickable ------------------- */
.svc-grid{display:grid; grid-template-columns:repeat(3,1fr); gap:1.5rem}
.svc{
  display:flex; flex-direction:column; text-decoration:none; color:inherit;
  background:#fff; border:1px solid var(--line);
  transition:border-color .3s var(--ease), transform .3s var(--ease), box-shadow .3s var(--ease);
}
.svc:hover{border-color:var(--navy); transform:translateY(-4px); box-shadow:0 16px 34px rgba(16,29,40,.13)}
.svc-img{aspect-ratio:16/10; overflow:hidden; background:var(--snow); position:relative}
.svc-img img{width:100%; height:100%; object-fit:cover; transition:transform .6s var(--ease)}
.svc:hover .svc-img img{transform:scale(1.05)}
.svc-b{padding:1.35rem 1.4rem 1.5rem; display:flex; flex-direction:column; flex:1}
.svc-b h3{margin-bottom:.5rem}
.svc:hover h3{color:var(--red)}
.svc-b p{font-size:.92rem; color:var(--ink-soft); margin-bottom:1rem; flex:1}
.svc-go{font-size:.74rem; font-weight:800; letter-spacing:.04em; text-transform:uppercase;
        color:var(--red); display:inline-flex; align-items:center; gap:.45rem;
        text-wrap:balance}
.svc:hover .svc-go .arw{transform:translateX(4px)}
.svc-go .arw{transition:transform .3s var(--ease)}

/* ---------- numbered feature blocks -------------------------------------- */
/* Card height. Both extremes fail, and so does faking it:
     - align-items:start  => ragged bottoms; with a visible border that reads as
       broken (53 of 196 rows, up to 229px apart).
     - align-items:stretch => short cards become mostly-empty boxes when one
       sibling runs long (319 cards carried up to 230px of dead space).
     - stretching the paragraph to absorb slack passes a "no gap below the last
       child" check while still LOOKING hollow - the metric moves, the design
       does not.
   Real fix: stop letting one long card set the height for everything. Cards
   size to their own content (even bottoms are not worth hollow boxes), and the
   border is softened to a top rule + hairline so unequal heights read as a
   deliberate stepped rhythm rather than a broken grid. */
.feat{display:grid; grid-template-columns:repeat(auto-fit,minmax(215px,1fr));
       gap:1.4rem; align-items:start}
/* Cards size to their own content. Equalising heights instead just moves the
   problem inside the box: a short card next to a long one becomes a mostly
   empty rectangle (measured: 319 cards, up to 230px of dead space).
   What made unequal heights read as BROKEN was the full box border - four hard
   edges stopping at different heights. Anchoring each card to a top rule and
   dropping the outline lets the cards end wherever their copy ends and read as
   a stepped rhythm. The tint keeps them grouped without drawing a bottom edge. */
.feat-i{background:var(--snow); border:0; border-top:3px solid var(--red);
        padding:1.25rem 1.3rem 1.4rem;
        display:flex; flex-direction:column}
.dark .feat-i{background:rgba(255,255,255,.07); border-top-color:var(--rose)}
.feat-i > :last-child{margin-bottom:0}
/* .snow sections share the card tint, so lift the cards to white there. */
.snow .feat-i{background:#fff}
/* The client's per-service links sit alone in the card's last paragraph - 209
   of them across the 19 location pages, every one a standalone call to action
   rather than inline prose. They were rendering as plain blue underlined body
   links, which is not how a card CTA reads anywhere else in this system.
   Style them to match .svc-go. The link TEXT is the client's and is untouched;
   only its presentation changes. */
.feat-i > p:last-child:has(> a:only-child){margin-top:.9rem}
.feat-i > p:last-child > a:only-child{
  font-size:.74rem; font-weight:800; letter-spacing:.04em; text-transform:uppercase;
  color:var(--red); text-decoration:none; display:inline-flex; align-items:center;
  gap:.45rem; text-wrap:balance;
  border-bottom:2px solid transparent; padding-bottom:2px;
  transition:border-color .25s var(--ease), color .25s var(--ease);
}
.feat-i > p:last-child > a:only-child:hover{border-bottom-color:var(--red)}
.dark .feat-i > p:last-child > a:only-child{color:var(--rose)}
.dark .feat-i > p:last-child > a:only-child:hover{border-bottom-color:var(--rose)}

.feat-i .n{font-size:.72rem; font-weight:800; letter-spacing:.12em; color:var(--red)}
.dark .feat-i .n{color:var(--rose)}
.feat-i h3{margin:.55rem 0 .5rem}
.feat-i p{margin:0; font-size:.9rem; color:var(--ink-soft)}
.dark .feat-i p{color:rgba(255,255,255,.85)}

/* ---------- checklist ---------------------------------------------------- */
.checks{list-style:none; margin:0; padding:0; display:grid; gap:.62rem}
.checks li{display:flex; gap:.7rem; align-items:flex-start; font-size:.96rem}
.checks svg{flex:none; margin-top:.22rem; color:var(--red)}
.dark .checks svg{color:var(--rose)}
.checks.two{grid-template-columns:1fr 1fr; gap:.62rem 1.6rem}
.checks{margin-bottom:1.1rem}
.checks + p{margin-top:0}

/* ---------- steps -------------------------------------------------------- */
.steps{list-style:none; margin:0; padding:0; display:grid; gap:1px; background:var(--line)}
.steps li{background:#fff; display:grid; grid-template-columns:64px 1fr; gap:1.2rem;
          align-items:start; padding:1.4rem 1.3rem}
.dark .steps{background:rgba(255,255,255,.16)}
.dark .steps li{background:var(--navy)}
.steps .n{
  width:44px; height:44px; display:grid; place-items:center; background:var(--red);
  color:#fff; font-weight:900; font-size:.95rem;
}
.steps b{display:block; font-size:1.02rem; font-weight:800; margin-bottom:.22rem; color:var(--navy)}
.dark .steps b{color:#fff}
/* Cap the step copy's measure: in the full-width shell these ran ~155
   characters a line, well past comfortable reading. */
.steps p{margin:0; font-size:.93rem; color:var(--ink-soft); max-width:78ch}
.dark .steps p{color:rgba(255,255,255,.85)}

/* ---------- reviews ------------------------------------------------------ */
.revs{display:grid; grid-template-columns:repeat(3,1fr); gap:1.5rem; align-items:stretch}
a.rev{display:flex; text-decoration:none; color:inherit}
.rev-in{background:#fff; border:1px solid var(--line); padding:1.6rem; display:flex;
        flex-direction:column; width:100%; transition:border-color .3s var(--ease), transform .3s var(--ease)}
a.rev:hover .rev-in{border-color:var(--navy); transform:translateY(-3px)}
.stars{color:#9c6100; letter-spacing:.13em; font-size:.95rem; margin-bottom:.8rem}
.rev-in p{font-size:.95rem; flex:1; margin-bottom:1rem}
.rev-w{font-weight:800; font-size:.82rem; letter-spacing:.05em; text-transform:uppercase; color:var(--red)}

/* ---------- split blocks ------------------------------------------------- */
/* The photo column STRETCHES to the row instead of holding a fixed 4/3 box.
   With a locked aspect-ratio the image was always 462px tall while the prose
   beside it ran 376-788px, so `align-items:center` floated the short column and
   opened voids above AND below it - up to 327px on /auto-glass-repair/.
   Stretching removes the void; min-height keeps the photo from collapsing when
   the text is short, and object-fit keeps it uncropped-looking either way. */
.split{display:grid; grid-template-columns:1fr 1fr; gap:clamp(1.6rem,3.4vw,3.2rem); align-items:stretch}
.split.wide-l{grid-template-columns:1.15fr .85fr}
.shot{position:relative; overflow:hidden; background:var(--snow);
      min-height:340px; height:100%}
.shot img{width:100%; height:100%; object-fit:cover; display:block}
/* Text column stays vertically centred against the now full-height photo. */
.split > :not(.shot){align-self:center}
.shot.tall{aspect-ratio:1/1}

/* ---------- FAQ ---------------------------------------------------------- */
.faq{border-top:2px solid var(--navy)}
.faq details{border-bottom:1px solid var(--line); background:#fff}
.faq summary{
  list-style:none; cursor:pointer; padding:1.3rem 3rem 1.3rem 0; position:relative;
  font-weight:700; font-size:1.02rem; color:var(--navy); transition:color .25s var(--ease);
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--red)}
.faq summary::after{
  content:''; position:absolute; right:.6rem; top:50%; width:12px; height:12px;
  border-right:2.5px solid var(--red); border-bottom:2.5px solid var(--red);
  transform:translateY(-70%) rotate(45deg); transition:transform .3s var(--ease);
}
.faq details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq .ans{padding:0 3rem 1.4rem 0; color:var(--ink-soft); font-size:.96rem; max-width:80ch}

/* ---------- areas -------------------------------------------------------- */
.areas{display:flex; flex-wrap:wrap; gap:.55rem}
.areas a{
  text-decoration:none; font-size:.87rem; font-weight:600; color:var(--navy);
  border:1px solid var(--line-2); background:#fff; padding:.6rem 1rem;
  transition:background .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
}
.areas a:hover{background:var(--navy); color:#fff; border-color:var(--navy)}
.dark .areas a{background:rgba(255,255,255,.09); color:#fff; border-color:rgba(255,255,255,.24)}
.dark .areas a:hover{background:#fff; color:var(--navy); border-color:#fff}

/* Static chips for place names that are NOT pages (neighbourhoods, nearby
   communities). The client supplies these as one comma-separated sentence,
   which rendered as an undifferentiated run-on line across the full width -
   a list that did not look like a list. Same chip shape as .areas so the two
   read as one family, minus the link affordance since there is nowhere to go. */
.chips{display:flex; flex-wrap:wrap; gap:.5rem; margin:.35rem 0 0}
.chips span{
  font-size:.85rem; font-weight:600; color:var(--ink);
  border:1px solid var(--line); background:var(--snow); padding:.5rem .85rem;
}
.snow .chips span{background:#fff}
.dark .chips span{background:rgba(255,255,255,.08); color:#fff; border-color:rgba(255,255,255,.2)}
.chip-group + .chip-group{margin-top:1.5rem}
.chip-group h3{margin:0 0 .7rem}

/* ---------- map ---------------------------------------------------------- */
.map{aspect-ratio:16/9; background:var(--snow); border:1px solid rgba(255,255,255,.2)}
.map iframe{width:100%; height:100%; border:0; display:block}

/* ---------- footer ------------------------------------------------------- */
.ftr{background:var(--navy-d); color:rgba(255,255,255,.8); padding:clamp(2.8rem,5vw,4rem) 0 0}
.ftr h4{font-size:.75rem; font-weight:800; letter-spacing:.14em; text-transform:uppercase;
        color:var(--rose); margin-bottom:1rem}
.ftr a{color:rgba(255,255,255,.8); text-decoration:none; transition:color .25s var(--ease)}
.ftr a:hover{color:#fff}
.ftr-grid{display:grid; grid-template-columns:1.6fr 1fr 1fr 1.1fr; gap:2.2rem}
.ftr ul{list-style:none; margin:0; padding:0; display:grid; gap:.45rem; font-size:.88rem}
.ftr-btm{margin-top:2.6rem; border-top:1px solid rgba(255,255,255,.14); padding:1.3rem 0;
         display:flex; flex-wrap:wrap; gap:.8rem; justify-content:space-between;
         font-size:.79rem; color:rgba(255,255,255,.6)}

/* sticky mobile call bar */
.callbar{display:none}

/* ---------- reveal ------------------------------------------------------- */
.ro{opacity:0; transform:translateY(24px); transition:opacity .8s var(--ease), transform .8s var(--ease)}
.ro.in{opacity:1; transform:none}
.ro.r1{transition-delay:.07s}.ro.r2{transition-delay:.14s}.ro.r3{transition-delay:.21s}

/* ---------- responsive --------------------------------------------------- */
@media (max-width:1100px){
  .svc-grid{grid-template-columns:1fr 1fr}
  .hero-copy{max-width:72%}
  .ftr-grid{grid-template-columns:1fr 1fr}
}
@media (max-width:900px){
  .hero-proof{max-width:100%}
  .nav{
    position:fixed; inset:calc(var(--hdr-h) + 40px) 0 auto; background:#fff;
    flex-direction:column; align-items:stretch; padding:.8rem; gap:0;
    border-bottom:3px solid var(--red); max-height:calc(100vh - 130px); overflow:auto;
    transform:translateY(-10px); opacity:0; visibility:hidden;
    transition:opacity .3s var(--ease), transform .3s var(--ease), visibility .3s;
    box-shadow:0 18px 34px rgba(16,29,40,.16);
  }
  .nav.open{opacity:1; visibility:visible; transform:none}
  .nav>a,.nav .has-menu>a{border-bottom:1px solid var(--line); padding:.85rem .6rem}
  .menu{position:static; opacity:1; visibility:visible; transform:none; box-shadow:none;
        border:0; border-top:0; padding:0 0 .5rem .9rem; min-width:0}
  .menu.cols{grid-template-columns:1fr; min-width:0}
  .burger{display:block}
  .hero-copy{max-width:100%}
  .hero-bg::after{background:linear-gradient(180deg, rgba(11,39,64,.93), rgba(11,39,64,.97))}
  .split,.split.wide-l,.revs{grid-template-columns:1fr}
  .checks.two{grid-template-columns:1fr}
  .topbar .tb-r span:first-child{display:none}
}
@media (max-width:620px){
  body{font-size:16px}
  .hero-in{padding:clamp(34px,6vw,48px) 0 clamp(30px,5vw,40px)}
  .svc-grid{grid-template-columns:1fr}
  .hero-cta .btn{width:100%}
  .actionbar-in{flex-direction:column; align-items:stretch; text-align:center}
  .actionbar .ab-tel{justify-content:center}
  .hdr-tel{display:none}
  .ftr-grid{grid-template-columns:1fr}
  body{padding-bottom:64px}
  .callbar{
    display:grid; grid-template-columns:1fr 1fr; position:fixed; bottom:0; left:0; right:0;
    z-index:80; border-top:2px solid var(--red);
  }
  .callbar a{
    display:flex; align-items:center; justify-content:center; gap:.5rem; padding:1.1rem .6rem;
    text-decoration:none; font-weight:800; font-size:.85rem; letter-spacing:.05em;
    text-transform:uppercase; background:var(--red); color:#fff;
  }
  .callbar a+a{background:var(--navy)}
}

/* ---------- gates -------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important; animation-iteration-count:1!important;
                       transition-duration:.001ms!important}
  .ro{opacity:1; transform:none}
}
.no-js .ro{opacity:1; transform:none}
:focus-visible{outline:3px solid var(--red); outline-offset:2px}
/* The red ring is invisible on a red ground (1:1) - a keyboard user tabbing
   through the action bar loses their place entirely. Switch to white there.
   Same reasoning for the red primary button. */
.actionbar :focus-visible,.btn:not(.btn-out):focus-visible{outline-color:#fff}
.skip{position:absolute; left:-9999px}
.skip:focus{left:1rem; top:1rem; z-index:99; background:var(--navy); color:#fff; padding:.8rem 1.1rem}

/* ---------- breadcrumbs -------------------------------------------------- */
.crumbs{background:var(--snow); border-bottom:1px solid var(--line); font-size:.82rem}
.crumbs .shell{padding:.8rem 0; display:flex; flex-wrap:wrap; gap:.45rem; align-items:center}
/* Breadcrumb links were a 21px tap target on a phone - these are real
   navigation, not inline prose, so they need a thumb-sized hit area. Vertical
   padding grows the target without changing the visual row height much, and the
   negative margin keeps the crumbs on one line. */
.crumbs a{color:var(--ink-soft); text-decoration:none; transition:color .25s var(--ease);
          display:inline-block; padding:.62rem 0; margin:-.62rem 0}
.crumbs a:hover{color:var(--red)}
/* --line-2 is a BORDER tint (1.38:1 on the snow ground) - far too light for a
   glyph. The separator is not decorative: it is the only thing distinguishing
   one crumb from the next, so it has to meet AA like any other text. */
.crumbs span{color:var(--ink-soft)}
.crumbs span[aria-current]{color:var(--navy); font-weight:700}

/* sub-page hero: shorter than the homepage hero */
.hero-sub .hero-in{padding:clamp(42px,5.5vw,68px) 0 clamp(44px,5.5vw,70px)}
/* The proof chips are the last thing in the hero, so the section's bottom
   padding stacks beneath them and left a constant ~158px void above the action
   bar on every page. Trim it when the chips are present.
   NOTE: this must come AFTER .hero-sub .hero-in — that rule has equal
   specificity, so an earlier declaration silently loses. */
.hero-in:has(.hero-proof),
.hero-sub .hero-in:has(.hero-proof){padding-bottom:clamp(26px,2.6vw,36px)}
/* Sub-page h1 tracks the base scale. It used to be capped at 3rem, which after
   the scale reduction left it noticeably larger than the h1 rule it overrides. */
.hero-sub h1{font-size:clamp(1.9rem,3.2vw,2.7rem)}

/* ---------- tables (wiki / spec content) --------------------------------- */
/* overflow-x:auto alone does NOT contain the 520px table. Its ANCESTORS have to
   be allowed to shrink first: a grid/flex item defaults to min-width:auto, i.e.
   never smaller than its content, so .ro.prose held itself at 520px inside a
   359px shell and pushed the whole PAGE wide. The fixed header then filled that
   widened viewport, which made the nav look like the culprit when it was only a
   symptom. min-width:0 on the item is the actual fix; the wrapper then scrolls
   the table inside itself. */
.tbl-wrap{overflow-x:auto; margin:1.2rem 0; max-width:100%; min-width:0}
.shell > *,.split > *,.close-grid > *{min-width:0}
.tbl{border-collapse:collapse; width:100%; min-width:520px; font-size:.92rem}
.tbl th,.tbl td{border:1px solid var(--line); padding:.7rem .85rem; text-align:left; vertical-align:top}
.tbl th{background:var(--navy); color:#fff; font-weight:700}
.tbl tr:nth-child(even) td{background:var(--snow)}
.dark .tbl th{background:var(--navy-d)}
.dark .tbl td{border-color:rgba(255,255,255,.2); color:rgba(255,255,255,.9)}
.dark .tbl tr:nth-child(even) td{background:rgba(255,255,255,.06)}

/* inline links in body copy */
.shell p a{color:var(--blue); text-decoration:underline; text-underline-offset:2px}
.shell p a:hover{color:var(--red)}
/* A .btn placed inside a <p> (the location pages do this) was inheriting the
   blue body-link colour ON TOP of the red button ground: 1.03:1, i.e. the label
   was effectively invisible. A button is never body copy - it keeps its own
   colour and never takes the underline. */
.shell p a.btn{color:#fff; text-decoration:none}
.shell p a.btn.btn-out{color:var(--navy)}
.shell p a.btn.btn-out.on-dark{color:#fff}
/* Same inheritance problem in the footer: the phone number sits in a <p>, so
   the blue body-link colour landed on the near-black navy ground at 2.65:1.
   The footer sets its own link colour; let it win. */
.ftr .shell p a,.ftr p a{color:rgba(255,255,255,.86); text-decoration:none}
.ftr .shell p a:hover,.ftr p a:hover{color:#fff}
/* On any dark ground the blue link is unreadable (2.1:1). The hero counts too —
   it is a dark ground even though it isn't .dark.
   Underline is dropped on dark: a coloured, underlined run mid-sentence over a
   photo reads as an error state, and 27 of 31 pages have one in the hero. */
.dark p a,.darker p a,.hero p a,.hero .lede a,.quote-intro p a{
  color:var(--rose); text-decoration:none;
  border-bottom:1px solid rgba(255,180,171,.55);
  transition:color .25s var(--ease), border-color .25s var(--ease);
}
.hero p a:hover,.hero .lede a:hover,.dark p a:hover,.darker p a:hover{
  color:#fff; border-bottom-color:#fff;
}
.checks a{color:var(--blue)}
.dark .checks a{color:var(--rose)}

/* Exactly two sub-blocks read as a pair, so run them as two columns instead of
   stacking one narrow column down the left and leaving the shell half empty. */
.duo{display:grid; grid-template-columns:1fr 1fr; gap:clamp(1.8rem,4vw,3.6rem); align-items:start}
@media (max-width:900px){ .duo{grid-template-columns:1fr; gap:2rem} }

/* prose block: a section with no sub-headings and no photo. Capping the measure
   keeps it readable and stops it reading as a half-empty two-column grid. */
.prose{max-width:74ch}
.prose .checks.two{grid-template-columns:1fr 1fr}

/* Short prose sections (no photo, no cards, no list) had the heading AND the
   copy stacked in one 721px column, leaving the right half of a 1280px shell
   empty for the section's whole height - 20 sections across the service pages.
   There is no hidden structure in that copy to turn into cards, so the fix is
   layout, not invention: set the head beside the copy. The measure stays
   readable, the band fills its width, and the heading gets the emphasis of its
   own column. Collapses back to a single column on narrow screens. */
@media (min-width:901px){
  .shell.prose-split{display:grid; grid-template-columns:minmax(260px,.8fr) 1.2fr;
                     gap:clamp(2rem,4.5vw,4.5rem); align-items:start}
  /* The left column is the LABEL: eyebrow + title only. Keeping the lede there
     put most of the words on the left and stranded a one-sentence remainder on
     the right - the same imbalance in a new shape. The RENDERER therefore emits
     the lede into the body column for this treatment; it is never hidden with
     CSS, which would be a content bug and would also fool a DOM validator. */
  .shell.prose-split > .shead{margin-bottom:0; grid-column:1; grid-row:1}
  .shell.prose-split > .prose{grid-column:2; grid-row:1; max-width:62ch}
}

/* Feature-grid column counts chosen so the last row is never a lone orphan.
   The default auto-fit is fine for most counts; these are the awkward ones. */
@media (min-width:1041px){
  .feat-4{grid-template-columns:repeat(4,1fr)}
  .feat-6{grid-template-columns:repeat(3,1fr)}
  .feat-7{grid-template-columns:repeat(4,1fr)}
  .feat-8{grid-template-columns:repeat(4,1fr)}
  .feat-9{grid-template-columns:repeat(3,1fr)}
  .feat-10{grid-template-columns:repeat(5,1fr)}
  /* 11 is the services list on every location page. The table stopped at 10, so
     it fell through to auto-fit and laid out 5/5/1 - a lone orphan card beside
     four empty slots on all 19 pages. 4 columns gives 4/4/3. */
  .feat-11{grid-template-columns:repeat(4,1fr)}
  .feat-12{grid-template-columns:repeat(4,1fr)}
}

/* ---------- quote form (shared, sits directly after the hero) ------------- */
.quote-band{background:var(--navy); color:#fff; padding:clamp(48px,6vw,76px) 0}
.quote-grid{display:grid; grid-template-columns:.85fr 1.15fr; gap:clamp(1.8rem,4vw,3.4rem); align-items:start}
.quote-intro h2{color:#fff}
.quote-intro .lede{color:rgba(255,255,255,.88)}
.quote-intro .checks svg{color:var(--rose)}
.quote-call{margin-top:1.5rem; font-size:.95rem; color:rgba(255,255,255,.88)}
.quote-call a{display:block; font-size:1.5rem; font-weight:900; color:#fff; text-decoration:none;
              letter-spacing:-.01em; margin-top:.2rem}
.quote-call a:hover{color:var(--rose)}
.quote-call span{display:block; font-size:.84rem; color:rgba(255,255,255,.7); margin-top:.15rem}

.quote-card{background:#fff; border-top:5px solid var(--red); padding:clamp(1.4rem,2.6vw,2rem);
            box-shadow:0 20px 50px rgba(5,20,34,.3)}
.qform .qf-row{margin-bottom:1rem}
.qform label{display:block; font-size:.78rem; font-weight:800; letter-spacing:.05em;
             text-transform:uppercase; color:var(--navy); margin-bottom:.35rem}
.qform label span{color:var(--red)}
.qform input,.qform textarea{
  width:100%; font:inherit; font-size:.98rem; color:var(--ink); background:var(--snow);
  border:1px solid var(--line-2); border-radius:0; padding:.82rem .9rem;
  transition:border-color .2s var(--ease), background .2s var(--ease);
}
.qform input:focus,.qform textarea:focus{
  outline:none; border-color:var(--red); background:#fff; box-shadow:0 0 0 3px rgba(200,40,31,.14);
}
.qform textarea{resize:vertical; min-height:104px}
.qf-two{display:grid; grid-template-columns:1fr 1fr; gap:0 1rem}
.qf-captcha input{max-width:130px}
.qf-captcha b{color:var(--red); font-weight:900; letter-spacing:.03em}
/* honeypots: off-screen, never display:none (some bots skip hidden fields) */
.qf-hp{position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden}
.qform button[type=submit]{margin-top:.5rem}
.qform button[disabled]{opacity:.6; cursor:not-allowed}
.qf-note{margin:.75rem 0 0; font-size:.86rem; color:var(--ink-soft)}
.qf-note-err{color:var(--red); font-weight:600}
.qf-result{margin-top:.9rem; font-size:.92rem}
.qf-result .success{background:#e8f5ec; border-left:4px solid #1a7f43; color:#12331f;
                    padding:.9rem 1rem; margin:0; font-weight:600}
.qf-result .error{background:#fdeceb; border-left:4px solid var(--red); color:#5c1712;
                  padding:.9rem 1rem; margin:0; font-weight:600}
@media (max-width:900px){
  .quote-grid{grid-template-columns:1fr; gap:1.8rem}
}
@media (max-width:520px){
  .qf-two{grid-template-columns:1fr}
}

/* =========================================================================
   DEPTH & MOTION LAYER
   Motion tone matches the design tone: confident / direct / dependable.
   One easing curve, one travel direction (rise), short distances. Every
   effect serves entrance, feedback, continuity or atmosphere — nothing
   decorative. All of it collapses under prefers-reduced-motion.
   ========================================================================= */

/* ---- depth: real elevation instead of flat blocks ----------------------- */
.svc{box-shadow:0 1px 2px rgba(16,29,40,.06), 0 6px 16px -8px rgba(16,29,40,.12)}
.svc:hover{box-shadow:0 18px 40px -12px rgba(16,29,40,.28)}
/* No drop shadow on .feat-i: a shadow redraws the very bottom edge the flat
   treatment removes, which is what made unequal card heights look broken.
   Depth here comes from the tinted ground and the red top rule instead. */
.feat-i{transition:transform .4s var(--ease), background-color .4s var(--ease)}
.feat-i:hover{transform:translateY(-3px)}
.rev-in{box-shadow:0 1px 2px rgba(16,29,40,.05), 0 8px 22px -14px rgba(16,29,40,.16)}
a.rev:hover .rev-in{box-shadow:0 18px 38px -14px rgba(16,29,40,.26)}
.quote-card{box-shadow:0 26px 60px -20px rgba(5,20,34,.55), 0 2px 6px rgba(5,20,34,.25)}

/* the hero photo gets a slow scale so the page feels alive on arrival */
@keyframes heroDrift{from{transform:scale(1.06)} to{transform:scale(1)}}
.hero-bg img{animation:heroDrift 12s var(--ease) forwards}

/* section grounds get a hairline seam so bands read as stacked planes */
.snow{box-shadow:inset 0 1px 0 var(--line), inset 0 -1px 0 var(--line)}

/* ---- entrance choreography ---------------------------------------------- */
/* One direction (rise), 24px, staggered by sibling — never per-element JS. */
.ro{will-change:opacity, transform}
.ro.r1{transition-delay:.07s}
.ro.r2{transition-delay:.14s}
.ro.r3{transition-delay:.21s}

/* cards inside a revealed grid stagger themselves */
.feat.in .feat-i,
.svc-grid.in .svc,
.revs.in .rev{opacity:0; transform:translateY(22px);
  animation:riseIn .75s var(--ease) forwards}
@keyframes riseIn{to{opacity:1; transform:none}}
.feat.in .feat-i:nth-child(1),.svc-grid.in .svc:nth-child(1),.revs.in .rev:nth-child(1){animation-delay:.02s}
.feat.in .feat-i:nth-child(2),.svc-grid.in .svc:nth-child(2),.revs.in .rev:nth-child(2){animation-delay:.10s}
.feat.in .feat-i:nth-child(3),.svc-grid.in .svc:nth-child(3),.revs.in .rev:nth-child(3){animation-delay:.18s}
.feat.in .feat-i:nth-child(4),.svc-grid.in .svc:nth-child(4){animation-delay:.26s}
.feat.in .feat-i:nth-child(5),.svc-grid.in .svc:nth-child(5){animation-delay:.32s}
.feat.in .feat-i:nth-child(n+6),.svc-grid.in .svc:nth-child(n+6){animation-delay:.38s}

/* the eyebrow tab wipes in from its own left edge */
.shead.in .eyebrow{animation:tabIn .5s var(--ease) both}
@keyframes tabIn{from{clip-path:inset(0 100% 0 0)} to{clip-path:inset(0 0 0 0)}}

/* section headings draw a rule as they arrive */
.shead h2{position:relative}
.shead.in h2::after{content:''; position:absolute; left:0; bottom:-.5rem; height:3px; width:56px;
  background:var(--red); transform-origin:left; animation:ruleDraw .7s var(--ease) .12s both}
@keyframes ruleDraw{from{transform:scaleX(0)} to{transform:scaleX(1)}}
.dark .shead.in h2::after,.darker .shead.in h2::after{background:var(--rose)}

/* ---- feedback: hover states with a single curve -------------------------- */
.checks li{transition:transform .3s var(--ease)}
.checks li:hover{transform:translateX(3px)}
.areas a{position:relative; overflow:hidden; isolation:isolate}
.areas a::before{content:''; position:absolute; inset:0; z-index:-1; background:var(--navy);
  transform:translateY(101%); transition:transform .35s var(--ease)}
.areas a:hover::before{transform:none}
.faq summary{transition:color .25s var(--ease), padding-left .3s var(--ease)}
.faq details[open] summary,.faq summary:hover{padding-left:.5rem}
.steps li{transition:background .3s var(--ease)}
.steps li:hover{background:var(--snow)}
.dark .steps li:hover{background:rgba(255,255,255,.06)}

/* header condenses on scroll — continuity between states */
.hdr{transition:box-shadow .4s var(--ease), min-height .4s var(--ease)}
.hdr.stuck .hdr-in{min-height:66px}
.hdr .hdr-in{transition:min-height .4s var(--ease)}

/* scroll progress hairline */
.progress{position:fixed; top:0; left:0; height:3px; width:100%; z-index:90;
  background:var(--red); transform:scaleX(0); transform-origin:left; pointer-events:none}

/* ---- gates --------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  .hero-bg img{animation:none}
  .feat.in .feat-i,.svc-grid.in .svc,.revs.in .rev{opacity:1; transform:none; animation:none}
  .shead.in .eyebrow,.shead.in h2::after{animation:none}
  .shead.in h2::after{transform:none}
  .progress{display:none}
}
@media (hover:none){
  .feat-i:hover,.checks li:hover{transform:none}
}
.no-js .feat .feat-i,.no-js .svc-grid .svc,.no-js .revs .rev{opacity:1; transform:none}

/* closing band: copy + CTA on the left, contact card on the right.
   Without this the section was a single prose column with an empty right half
   on all 31 pages. */
.close-grid{display:grid; grid-template-columns:1.25fr .75fr;
            gap:0 clamp(1.6rem,3.4vw,3rem); align-items:start;
            grid-auto-rows:min-content}   /* min-content: rows were stretching apart */
.close-grid > .shead,.close-grid > .ro:not(.close-card),.close-grid > .hero-cta{grid-column:1}
.close-grid > .hero-cta{margin:1.2rem 0 0}
.close-card{grid-column:2; grid-row:1 / span 4; align-self:start;
  background:rgba(255,255,255,.07); border:1px solid rgba(255,255,255,.18);
  border-top:4px solid var(--rose); padding:1.5rem 1.4rem; display:grid; gap:.2rem}
.close-card .cc-k{font-size:.68rem; font-weight:800; letter-spacing:.14em;
  text-transform:uppercase; color:var(--rose); margin-top:.9rem}
.close-card .cc-k:first-child{margin-top:0}
.close-card .cc-v{font-size:.94rem; color:rgba(255,255,255,.9); line-height:1.5}
.close-card .cc-tel{font-size:1.55rem; font-weight:900; color:#fff; text-decoration:none;
  letter-spacing:-.01em; transition:color .25s var(--ease)}
.close-card .cc-tel:hover{color:var(--rose)}
@media (max-width:900px){
  .close-grid{grid-template-columns:1fr}
  .close-card{grid-column:1; grid-row:auto}
}
