/* base.css — fleet-shared foundation. NEVER edited per client.
   Brand comes from :root tokens (head.php) + one skin file.
   Skins may set: --radius, --shadow, --section-bg-alt, --hero-overlay,
   --btn-style hooks, heading transforms. Keep skins small. */

*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth;overflow-x:clip}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{overflow-x:clip;font-family:var(--body);background:var(--paper,#fff);
  color:var(--ink,#1c1c1c);line-height:1.65;-webkit-font-smoothing:antialiased}
img,video{max-width:100%;display:block}
a{color:inherit}
.wrap{max-width:1140px;margin:0 auto;padding:0 22px}
h1,h2,h3{font-family:var(--display);font-weight:800;line-height:1.08;letter-spacing:-.015em}
h1{font-size:clamp(2.2rem,5.2vw,3.6rem)}
h2{font-size:clamp(1.7rem,3.6vw,2.5rem);margin:.5rem 0 1rem}
.eyebrow{display:inline-block;font-weight:700;font-size:.8rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--primary)}
.sub{font-size:1.05rem;max-width:58ch;color:var(--muted,#4b4b4b)}
section{padding:4.4rem 0}
.section-alt{background:var(--section-bg-alt,#f6f6f4)}

/* a11y */
.skip{position:absolute;left:-9999px;top:0;background:var(--accent);color:var(--dark);
  padding:.6rem 1rem;font-weight:600;z-index:200}
.skip:focus{left:0}
:focus-visible{outline:3px solid var(--primary);outline-offset:3px}

/* buttons */
.btn{display:inline-flex;align-items:center;gap:.5rem;font-weight:600;font-size:.95rem;
  text-decoration:none;padding:.75rem 1.35rem;border-radius:var(--radius,10px);cursor:pointer;
  border:2px solid var(--dark);background:#fff;color:var(--dark);
  box-shadow:var(--shadow,0 2px 8px rgba(0,0,0,.12));transition:transform .12s ease}
.btn:hover{transform:translateY(-2px)}
.btn-accent{background:var(--accent);border-color:var(--accent-border,var(--dark));color:var(--accent-text,var(--dark))}
.btn-primary{background:var(--primary);border-color:var(--primary);color:#fff}
.btn-big{font-size:1.05rem;padding:.95rem 1.5rem;justify-content:center}

/* header */
.site-header{position:fixed;inset:0 0 auto 0;z-index:100;background:var(--paper,#fff);
  border-bottom:var(--header-line,1px solid #e4e4e0);display:flex;align-items:center;
  justify-content:space-between;padding:12px 22px;gap:16px}
.brand img{height:48px;width:auto}
/* Optional script wordmark beside the logo mark ($cfg['wordmark'], header.php).
   Matches NOTHING unless a site sets that key, so this is a no-op by
   construction on every site that doesn't. It lives here rather than in a skin
   because `wordmark` is a FLEET config option — a site on any skin that sets it
   must get a correct header, not just the one vertical that asked first.
   `.brand .brand-wordmark` (0,2,0) is required to out-specify `.brand img`
   (0,1,1) above; a bare `.brand-wordmark` is (0,1,0) and silently loses.
   The flex rule hangs off the `brand-lockup` CLASS that header.php adds only
   when a wordmark exists, NOT off :has(). Two reasons: :has() is unsupported on
   Firefox before 121, and `img{display:block}` at the top of this file means the
   fallback is not "slightly off" but the wordmark STACKED UNDER the logo — which
   is exactly what it did in the wild. A class also avoids making .brand a flex
   container on sites that have no wordmark, which would drop the inline
   descender space and shift their header height by a pixel or two. */
.brand .brand-wordmark{height:34px;width:auto;flex:0 0 auto}
.brand-lockup{display:flex;align-items:center;gap:10px}
/* flex:0 0 auto above is load-bearing, not decoration: without it the header's
   flex layout SHRINKS the wordmark's width while `height:34px` holds the height
   fixed, distorting the lettering horizontally. Measured at 862px: 202px wide
   against a correct 209px, i.e. 3.5% squashed — subtle enough to ship unnoticed
   and wrong. Now it keeps its ratio and the bar reflows around it instead.
   And a wordmark is ~160px wider than a bare logo mark, which is enough to
   overflow the bar in the band where the desktop nav is still showing. Measured
   with a 4-item nav: the full lockup needs ~939px, the mark alone ~720px. So the
   wordmark stands down between the mobile breakpoint and 940px, and comes back
   below 861px where the nav collapses and the room returns. Both bounds are
   needed — a bare max-width rule would hide it on phones too, where it fits. */
@media (min-width:861px) and (max-width:940px){.brand .brand-wordmark{display:none}}
.main-nav{display:flex;align-items:center;gap:22px}
.main-nav a{text-decoration:none;font-size:.93rem;font-weight:500}
.main-nav a:hover,.main-nav a[aria-current]{color:var(--primary)}
.hdr-cta{display:flex;align-items:center;gap:14px}
.tel-mini{font-weight:600;font-size:.9rem;text-decoration:none;white-space:nowrap}
.menu-btn{display:none;background:#fff;border:2px solid var(--dark);border-radius:8px;
  padding:.5rem .8rem;font-family:var(--display);font-weight:800;cursor:pointer}
.mobile-nav{display:none;position:fixed;top:66px;left:0;right:0;z-index:99;background:var(--paper,#fff);
  border-bottom:1px solid #e4e4e0;padding:1rem 22px 1.3rem;max-height:calc(100vh - 66px);overflow:auto}
.mobile-nav.open{display:block}
.mobile-nav a{display:block;padding:.7rem 0;font-weight:600;text-decoration:none;border-bottom:1px solid #eee}
/* Primary CTA repeated at the top of the mobile menu — the desktop .hdr-cta
   button is hidden below 860px (site-header rule below) and the mobile nav
   previously offered no equivalent, only a Call link at the very bottom.
   Higher specificity than ".mobile-nav a" (2 classes+tag beats 1 class+tag)
   so it wins over the plain-link rule above instead of fighting it. */
.mobile-nav a.mobile-cta{display:flex;justify-content:center;align-items:center;
  margin:.2rem 0 1rem;padding:.85rem 1rem;border:2px solid var(--accent-border,var(--dark));
  border-radius:var(--radius,10px);background:var(--accent);color:var(--accent-text,var(--dark))}
/* 860, not 960: with a dropdown nav the top level is only ~4 items (~350px),
   so the desktop bar fits comfortably down to here. At 960 a Windows laptop at
   125-150% display scaling reports under the breakpoint and silently gets the
   MOBILE menu — which reads as "the desktop dropdown is broken". */
@media (max-width:860px){.main-nav{display:none}.tel-mini{display:none}
  .hdr-cta .btn{display:none}.menu-btn{display:inline-flex}.brand img{height:40px}
  .brand .brand-wordmark{height:26px}}

/* ---------- dropdown nav (parents are inferred from the URL path) ----------
   Desktop opens on :hover AND :focus-within, so keyboard users get the same
   menu without any JS. Never hover-only — that strands keyboard and switch
   users on the parent page. */
.nav-item{position:relative;display:flex;align-items:center}
.nav-item > a{text-decoration:none;font-size:.93rem;font-weight:500;
  display:inline-flex;align-items:center;gap:.32rem;padding:.5rem 0}
.nav-item > a:hover,.nav-item > a[aria-current],.nav-item > a.is-ancestor{color:var(--primary)}
.nav-caret{background:none;border:0;cursor:pointer;padding:.5rem .1rem .5rem .3rem;
  display:inline-flex;align-items:center;color:inherit;line-height:1}
.caret{width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;
  border-top:5px solid currentColor;opacity:.55;transition:transform .15s ease}
.nav-item:hover .caret,.nav-item:focus-within .caret,.nav-item.open .caret{transform:rotate(180deg);opacity:1}
.sub-menu{position:absolute;top:100%;left:50%;transform:translate(-50%,6px);
  min-width:210px;background:var(--paper,#fff);border:1px solid #e4e4e0;
  border-radius:var(--radius,10px);box-shadow:0 12px 30px rgba(0,0,0,.14);
  padding:.5rem;opacity:0;visibility:hidden;pointer-events:none;
  transition:opacity .15s ease,transform .15s ease;z-index:120}
.sub-menu.cols2{min-width:400px;columns:2;column-gap:.4rem}
.nav-item:hover .sub-menu,.nav-item:focus-within .sub-menu,.nav-item.open .sub-menu{
  opacity:1;visibility:visible;pointer-events:auto;transform:translate(-50%,0)}
.sub-menu a{display:block;padding:.5rem .7rem;font-size:.9rem;font-weight:500;
  text-decoration:none;border-radius:7px;break-inside:avoid;white-space:nowrap}
.sub-menu a:hover,.sub-menu a[aria-current]{background:var(--section-bg-alt,#f6f6f4);color:var(--primary)}
/* hover bridge — stops the menu closing in the gap between link and panel */
.nav-item.has-sub::after{content:"";position:absolute;top:100%;left:0;right:0;height:10px}

/* ---------- mobile nav: collapsed submenus ---------- */
.m-row{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  border-bottom:1px solid #eee}
.m-row a{flex:1;border-bottom:0 !important}
.m-toggle{flex:0 0 auto;background:none;border:0;padding:.7rem .4rem;cursor:pointer;
  font-family:var(--display);font-weight:800;font-size:1.25rem;line-height:1;color:var(--primary);
  min-width:44px;min-height:44px}
.m-sub{padding-left:.9rem;border-left:2px solid var(--accent);margin:.2rem 0 .5rem}
.m-sub[hidden]{display:none}
.m-sub a{font-weight:500;font-size:.94rem;padding:.55rem 0}

/* ---------- HERO (standard: photo + scroll motion, no video weight) ---------- */
.hero{position:relative;min-height:76vh;display:flex;align-items:center;
  padding:7.5rem 0 4rem;overflow:hidden;color:#fff}
.hero-media{position:absolute;inset:-12% 0;z-index:0}
.hero-media img{width:100%;height:100%;object-fit:cover}
.hero-shade{position:absolute;inset:0;z-index:1;background:var(--hero-overlay,
  linear-gradient(180deg,rgba(10,10,12,.62),rgba(10,10,12,.38) 50%,rgba(10,10,12,.66)))}
.hero .wrap{position:relative;z-index:2;width:100%}
/* Text-shadow safety net, not a color fix: measured on yossefs-laffa-milia
   that even a deliberately-darkened --hero-overlay (see restaurant skin)
   still leaves a bright patch somewhere in most real photos (a window, a
   pale wall, a plate) — sampled at 215,206,181 there, an accent color close
   in lightness to the photo's own tones (a common case: warm accent, warm
   food/wood photography) measured 1.6:1 against it even under the darker
   overlay, nowhere near AA. A gradient can only darken the AVERAGE; it can't
   promise every accent color clears every photo everywhere text might sit.
   The shadow is what actually holds regardless of the color pairing or
   what's in the shot behind it — cheap, additive, invisible when the
   backdrop is already dark, so it costs nothing on sites that never hit
   this. h1 inherits it too since the same bright-patch risk applies. */
.hero .eyebrow{color:var(--accent);text-shadow:0 1px 3px rgba(0,0,0,.85),0 2px 14px rgba(0,0,0,.55)}
.hero h1{text-shadow:0 2px 6px rgba(0,0,0,.55),0 1px 3px rgba(0,0,0,.7)}
.hero .sub{color:rgba(255,255,255,.92);text-shadow:0 1px 4px rgba(0,0,0,.5)}
.hero-grid{display:grid;grid-template-columns:1fr;gap:2.2rem;align-items:center}
.hero-grid.has-form{grid-template-columns:1.05fr .95fr}
@media (max-width:920px){.hero-grid.has-form{grid-template-columns:1fr}}
.hero .cta-row{display:flex;flex-wrap:wrap;gap:14px;margin-top:1.8rem}

/* scroll-driven hero pan/zoom — CSS-only where supported */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero-media img{animation:heroPan linear both;animation-timeline:scroll();
      animation-range:0 120vh;transform-origin:center}
    @keyframes heroPan{from{transform:scale(1.12) translateY(0)}to{transform:scale(1) translateY(6%)}}
  }
}

/* ---------- scroll reveals (IO adds .in via site.js; CSS-only upgrade below) ---------- */
@media (prefers-reduced-motion: no-preference){
  .rv{opacity:0;transform:translateY(16px);transition:opacity .55s ease,transform .55s ease}
  .rv.in{opacity:1;transform:none}
}

/* ---------- content blocks ---------- */
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:2.3rem}
@media (max-width:960px){.grid3{grid-template-columns:repeat(2,1fr)}}
@media (max-width:620px){.grid3{grid-template-columns:1fr}}
.tile{background:#fff;border:var(--tile-border,1px solid #e4e4e0);
  border-radius:var(--radius,12px);padding:1.6rem 1.5rem;box-shadow:var(--shadow,0 2px 10px rgba(0,0,0,.06))}
.tile h3{font-size:1.08rem;margin-bottom:.5rem}
.tile p{font-size:.94rem;color:var(--muted,#4b4b4b)}
.split{display:grid;grid-template-columns:1.1fr .9fr;gap:44px;align-items:center}
@media (max-width:860px){.split{grid-template-columns:1fr}}
/* Uncropped, and capped so the photo never dominates the row.
   WIDTH-driven with a ratio-derived cap: width:100% fills the column, max-width
   stops it before it would exceed the height cap (420px desktop, 320px phones),
   and height:auto lets the ratio set the height.

   Why not the old `height:420px; width:auto`: for a LANDSCAPE ratio the derived
   width (420 x 4/3 = 560px) is wider than the .9fr column (473px at a 1140px
   wrap), so max-width:100% clamped it to 473x420 — ratio 1.127, not 1.333 — and
   object-fit:cover then quietly cropped ~18% off the SIDES of every landscape
   photo. Measured on a real render, invisible in the stylesheet. Portrait hid
   the bug for a year because 420 x 3/4 = 315px always fitted the column.
   Width-driven fits both orientations with no crop at any viewport.

   Do NOT switch to width:auto + max-height — that leaves a lazy image at 0x0
   until it loads (measured), the exact layout shift the width/height attributes
   exist to prevent. width:100% + aspect-ratio reserves the box either way. */
.split img{width:100%;max-width:calc(420px * var(--photo-ratio,3/4));
  height:auto;aspect-ratio:var(--photo-ratio,3/4);
  object-fit:cover;display:block;margin:0 auto;
  border-radius:var(--radius,12px);box-shadow:var(--shadow,0 6px 24px rgba(0,0,0,.12))}
@media (max-width:860px){.split img{max-width:calc(320px * var(--photo-ratio,3/4))}}

/* ---------- before / after pairs (cleanouts, restoration, painting, detailing) ----------
   Markup: .ba-set > div > (.ba > figure.ba-before + figure.ba-after) + .ba-cap
   Pairs must be the SAME shot from the SAME position — that is the whole point.

   PHONE PHOTOS ARE PORTRAIT. Rendered at their native 3:4 they tower: two of
   them side by side in a 1140px wrap is 750px tall, and a stack of three pairs
   on a phone is an endless scroll nobody reaches the bottom of. So we CROP to
   landscape with object-fit rather than letting the source dictate height. */
/* DO NOT crop these to landscape. Client photos come off a phone in portrait
   (3:4); forcing them into a 4:3 box throws away ~44% of the frame, which is
   exactly the half of a room that shows how full it was. The good junk-removal
   galleries all use LANDSCAPE SOURCE photos shown uncropped — so we match the
   box to the source instead of the other way round, and control height by
   limiting how wide a PAIR gets rather than by cutting the picture.
   --photo-ratio matches the client's photos: 3/4 portrait (default) or 4/3 if
   they shoot landscape. Set it ONCE per site (it drives .split img too); never
   crop against it. */
.ba-set{display:grid;gap:2.6rem;margin-top:2.3rem;justify-items:center}
.ba{display:grid;grid-template-columns:1fr 1fr;gap:12px;width:100%;max-width:560px}
.ba figure{margin:0;position:relative}
.ba img{width:100%;height:auto;aspect-ratio:var(--photo-ratio,3/4);object-fit:cover;
  border-radius:var(--radius,12px);border:var(--tile-border,1px solid #e4e4e0)}
.ba figcaption{position:absolute;top:10px;left:10px;font-family:var(--display);font-weight:800;
  font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;padding:.32rem .62rem;
  border-radius:6px;background:var(--dark);color:#fff}
.ba .ba-after figcaption{background:var(--accent);color:var(--accent-text,var(--dark))}
.ba-cap{margin-top:.7rem;font-size:.92rem;color:var(--muted,#4b4b4b)}
.ba-hint{display:none;font-size:.82rem;color:var(--muted,#4b4b4b);margin-top:.8rem}

/* Phone: swipe between PAIRS instead of scrolling past six tall photos.
   Within a pair, before STACKS ABOVE after rather than sitting beside it —
   two 140px thumbnails side by side on a 375px screen are too small to read,
   which defeats the point. Stacked, each photo gets the full card width and
   the comparison still works because they are adjacent. */
@media (max-width:760px){
  .ba-set{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;scrollbar-width:none;
    margin-left:-22px;margin-right:-22px;padding:0 22px 4px;scroll-padding-left:22px}
  .ba-set::-webkit-scrollbar{display:none}
  .ba-set > *{flex:0 0 86%;scroll-snap-align:start}
  /* Side by side on a phone puts each photo at ~160px, which is too small to
     read — the exact complaint that started this. Stacked, each gets the full
     card width and the pair still reads as a pair because they are adjacent
     and labelled. The carousel means only one card is on screen at a time. */
  .ba{grid-template-columns:1fr;gap:8px;max-width:none}
  .ba-hint{display:block}
}

/* ---------- plain fact list (services, FAQ answers) ---------- */
.ticks{list-style:none;margin-top:1rem;columns:2;column-gap:2rem}
.ticks li{font-size:.94rem;padding:.2rem 0 .2rem 1.4rem;position:relative;break-inside:avoid}
.ticks li::before{content:"";position:absolute;left:0;top:.62em;width:9px;height:9px;
  background:var(--accent);border-radius:2px}
@media (max-width:620px){.ticks{columns:1}}

/* ---------- FAQ ---------- */
.faq{margin-top:1.6rem;max-width:74ch}
.faq details{border-bottom:1px solid #dededa;padding:1rem 0}
.faq summary{font-family:var(--display);font-weight:800;font-size:1.02rem;cursor:pointer;
  list-style:none;display:flex;justify-content:space-between;gap:1rem;align-items:center}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";color:var(--primary);font-size:1.3rem;line-height:1}
.faq details[open] summary::after{content:"–"}
.faq p{margin-top:.7rem;font-size:.95rem;color:var(--muted,#4b4b4b);max-width:68ch}

/* ---------- steps ---------- */
.steps{counter-reset:step;display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:2.3rem}
@media (max-width:900px){.steps{grid-template-columns:repeat(2,1fr)}}
@media (max-width:520px){.steps{grid-template-columns:1fr}}
.steps li{list-style:none;counter-increment:step}
.steps li::before{content:counter(step);display:flex;align-items:center;justify-content:center;
  width:38px;height:38px;border-radius:50%;background:var(--accent);color:var(--accent-text,var(--dark));
  font-family:var(--display);font-weight:800;margin-bottom:.7rem}
.steps h3{font-size:1rem;margin-bottom:.35rem}
.steps p{font-size:.92rem;color:var(--muted,#4b4b4b)}

/* ---------- lead form panel ---------- */
.lead-panel{background:#fff;color:var(--ink,#1c1c1c);border-radius:var(--radius,14px);
  overflow:hidden;border:var(--tile-border,1px solid #e4e4e0);
  box-shadow:var(--shadow,0 10px 34px rgba(0,0,0,.18))}
.lead-head{padding:1rem 1.3rem;border-bottom:var(--tile-border,1px solid #e4e4e0);
  font-family:var(--display);font-weight:800;font-size:1.1rem}
.lead-form{padding:1.3rem;display:grid;gap:1rem}
.lead-form label{display:grid;gap:.35rem;font-weight:600;font-size:.86rem}
.lead-form input,.lead-form textarea{font-family:var(--body);font-size:.95rem;
  padding:.72rem .8rem;border:1.5px solid #c9c9c4;border-radius:8px;background:#fff}
.lead-form input:focus,.lead-form textarea:focus{outline:3px solid var(--primary);outline-offset:0}
.lead-form .fine{font-size:.8rem;color:var(--muted,#4b4b4b)}
.lead-form .fine a{font-weight:600}
.hp{position:absolute;left:-9999px;opacity:0;height:0;overflow:hidden}
@media (max-width:560px){
  .lead-form input,.lead-form textarea{font-size:16px;padding:.8rem .85rem} /* stops iOS zoom */
}

/* ---------- client portal ---------- */
.portal-stats{display:grid;grid-template-columns:repeat(4,1fr);gap:14px;margin-top:1.8rem}
@media (max-width:620px){.portal-stats{grid-template-columns:repeat(2,1fr)}}
.portal-stat{background:#fff;border:var(--tile-border,1px solid #e4e4e0);border-radius:var(--radius,12px);
  padding:1rem 1.1rem;text-align:center}
.portal-stat b{display:block;font-family:var(--display);font-weight:800;font-size:1.7rem;color:var(--primary)}
.portal-stat span{font-size:.8rem;color:var(--muted,#4b4b4b);text-transform:uppercase;letter-spacing:.04em}
.portal-toolbar{display:flex;align-items:center;gap:1rem;flex-wrap:wrap;margin:1.6rem 0}
.portal-toolbar input{flex:1 1 260px;max-width:420px;padding:.72rem .8rem;
  border:1.5px solid #c9c9c4;border-radius:8px;font-size:.95rem}
.portal-count{font-size:.85rem;color:var(--muted,#4b4b4b);white-space:nowrap}
.portal-ago{font-size:.78rem;color:var(--muted,#4b4b4b)}
.portal-badge-new{display:inline-block;background:var(--accent);color:var(--accent-text,var(--dark));
  font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.04em;
  padding:.15rem .45rem;border-radius:5px;vertical-align:middle}
.portal-table{width:100%;border-collapse:collapse;font-size:.9rem;min-width:640px}
.portal-table th{text-align:left;font-family:var(--display);font-weight:800;font-size:.75rem;
  letter-spacing:.05em;text-transform:uppercase;padding:.6rem .7rem;border-bottom:2px solid #ddd;
  color:var(--muted,#4b4b4b)}
.portal-table td{padding:.65rem .7rem;border-bottom:1px solid #eee;vertical-align:top}
.portal-table tr:hover td{background:var(--section-bg-alt,#f6f6f4)}
.portal-table td a{text-decoration:none;font-weight:600}
@media (max-width:640px){
  /* stacked "label: value" cards instead of a horizontally-scrolled table —
     a lead list read on a phone in a truck should not need side-scrolling */
  .portal-table thead{display:none}
  .portal-table, .portal-table tbody, .portal-table tr, .portal-table td{display:block;width:100%}
  .portal-table tr{border:1px solid #e4e4e0;border-radius:10px;margin-bottom:.9rem;padding:.4rem .8rem}
  .portal-table td{border-bottom:0;padding:.35rem 0}
  .portal-table td::before{content:attr(data-label) ": ";font-weight:700;color:var(--muted,#4b4b4b)}
}

/* ---------- reviews ---------- */
.reviews-shell{margin-top:2rem}
.reviews-more{margin-top:1rem;font-size:.92rem}
.reviews-more a{font-weight:600;color:var(--primary)}

/* ---------- footer ---------- */
/* Kept deliberately compact: the footer is the least-read part of the page and
   every row of it pushes the real content further from the viewer. Hours are
   collapsed into day RANGES in footer.php rather than seven near-identical
   rows, which is the single biggest saving. */
/* No margin-top here (FLEET FIX, 2026-08-18): a margin renders in BODY's
   background, not the footer's --dark background, so it read as an invisible
   sliver of extra white space on every prior site only because their last
   section before the footer always happened to be plain white too (same
   color as body). The first site whose last section is .section-alt
   (carpet-boss-restoration) exposed it as a real, visible off-white/white/dark
   seam. Sections already carry 4.4rem of their own top+bottom padding
   (base.css `section{padding:4.4rem 0}`), so no extra gap was actually needed
   — removing it tightens every existing site by 2rem of white-on-white
   spacing nobody could see, and closes the visible seam here. */
.site-footer{background:var(--dark);color:#e8e8e6;padding:2.3rem 0 1rem}
/* minmax(0,1fr), not 1fr: a bare 1fr is minmax(auto,1fr), so a column holding a
   long unbreakable town name grows past its share and skews the whole row. */
.foot-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));
  gap:1.5rem 2rem;align-items:start}
.foot-areas{list-style:none;font-size:.86rem;columns:2;column-gap:1rem}
.foot-areas li{padding:.1rem 0;break-inside:avoid}
.foot-areas a{text-decoration:none}
.foot-areas a:hover{color:var(--accent)}
.foot-areas-all{font-weight:600;color:var(--accent);white-space:nowrap}
/* Stay two-up on phones — a single stacked column turns four short blocks into
   an 800px wall of footer between the last CTA and the bottom of the page.
   These overrides MUST come after the base .foot-areas rules above, or the
   base columns:2 wins on equal specificity and the phone layout skews. */
@media (max-width:760px){
  .foot-grid{grid-template-columns:repeat(2,minmax(0,1fr));gap:1.3rem 1.2rem}
  .foot-hours li{max-width:none}
  /* Areas stays a normal grid cell, single sub-column. Spanning it full width
     to keep two sub-columns was tried and MEASURED WORSE (695px vs 567px):
     the span gives it a row of its own instead of letting it sit beside
     another block. Do not "fix" this back. */
  .foot-areas{columns:1}
}
@media (max-width:340px){.foot-grid{grid-template-columns:minmax(0,1fr)}}
.foot-logo{height:32px;width:auto;margin-bottom:.6rem}
.foot-nap,.foot-area{font-size:.86rem;line-height:1.5}
.foot-area{margin-top:.35rem;color:rgba(232,232,230,.75)}
.foot-nap a{text-decoration:none;font-weight:600}
.foot-head{font-family:var(--display);display:block;margin-bottom:.45rem;font-size:.95rem}
.foot-hours{list-style:none;font-size:.86rem}
.foot-hours li{display:flex;justify-content:space-between;gap:.8rem;padding:.1rem 0;max-width:230px}
.foot-links{list-style:none;font-size:.86rem}
.foot-links li{padding:.1rem 0}
.foot-links a{text-decoration:none}
.foot-links a:hover{color:var(--accent)}
.foot-legal{margin-top:1.4rem;padding-top:.85rem;border-top:1px solid rgba(255,255,255,.15);
  font-size:.78rem;color:rgba(232,232,230,.7)}
.foot-legal a{color:inherit}
