﻿/* Auto Tops and Trim â€” stylesheet.
   Design tokens lifted from the existing site: Archivo, the blue palette,
   the NN â€” LABEL section headers and the 44x3 blue bar device.
   Mobile-first. Nav works with JavaScript disabled. */

@font-face{font-family:'Archivo';font-style:normal;font-weight:100 900;font-display:swap;
  src:url(fonts/font-327592e7.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Archivo';font-style:normal;font-weight:100 900;font-display:swap;
  src:url(fonts/font-d7dfbe24.woff2) format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'Archivo';font-style:normal;font-weight:100 900;font-display:swap;
  src:url(fonts/font-aeec607a.woff2) format('woff2');
  unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}

:root{
  --ink:#2A2E33;
  --ink-70:rgba(42,46,51,.78);
  --ink-60:rgba(42,46,51,.6);
  --ink-35:rgba(42,46,51,.35);
  --blue:#2F6FB0;
  --blue-lt:#5E9BD9;
  --blue-btn:#1E5C99;
  --blue-deep:#16344F;
  --pale:#9CC3E8;
  /* The one sanctioned warm colour, and only ever for a rating star — this is
     not the rejected tan accent. Was a bare literal in .stars; tokenised
     2026-08-09 so the hero trust strip could not drift to a second gold. */
  --star-gold:#E8A33D;
  --band:#E8EEF6;
  --band-2:#F1F5F9;
  --rule:#D9E2ED;
  --dark:#23282E;
  --white:#FFFFFF;
  --wrap:1200px;
  --gut:clamp(20px,4vw,56px);
  --tap:46px;
  /* corner radii â€” media reads softened, controls stay tighter */
  --r-media:16px;
  --r-card:14px;
  --r-ctl:8px;
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;background:var(--white);color:var(--ink);
  font:400 17px/1.66 'Archivo',system-ui,-apple-system,sans-serif;
  -webkit-font-smoothing:antialiased;
}
/* Sideways drag on phones â€” do NOT put overflow on <html> or <body>.
   When <html> is `visible`, <body>'s overflow PROPAGATES to the viewport, so
   setting it on either one is the same thing, and at viewport level it breaks
   position:fixed on iOS â€” that is what stranded the call bar mid-screen.
   Clipping the individual landmarks contains any stray width without
   propagating. `clip` not `hidden`, so no scroll container is created, and the
   fixed call bar and lightbox both live outside these elements. */
main,.site-foot,.site-head{max-width:100%}
@supports (overflow:clip){main,.site-foot,.site-head{overflow-x:clip}}
html{overscroll-behavior-x:none}
img{max-width:100%;height:auto;display:block;background:#EDF1F5}
a{color:var(--blue)}
p{margin:0}
ul{margin:0}
h1,h2,h3,h4{margin:0;font-weight:800;letter-spacing:-.028em;line-height:1.07;text-wrap:balance}
h1{font-size:clamp(31px,4.4vw,54px)}
h2{font-size:clamp(28px,3.2vw,44px)}
h3{font-size:clamp(18px,1.5vw,21px);letter-spacing:-.015em;line-height:1.2}

.skip{position:absolute;left:-9999px;background:var(--blue-btn);color:#fff;padding:12px 18px;z-index:200}
.skip:focus{left:8px;top:8px}
:focus-visible{outline:3px solid var(--blue);outline-offset:2px}

.wrap{width:100%;max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gut)}
.narrow{max-width:820px}
.center{text-align:center}
.lead{font-size:17px;line-height:1.66;max-width:54ch;color:var(--ink-70)}
.center .lead{margin-inline:auto}

/* ---- section header:  01 â€” WHY CHOOSE US ---- */
.shead{display:flex;align-items:center;gap:14px;margin-bottom:18px;flex-wrap:wrap}
.shead.mid{justify-content:center}
.shead .n{font-size:12px;font-weight:800;letter-spacing:.06em;color:var(--ink)}
.shead .dash{width:26px;height:1px;background:var(--ink-35);flex:none}
.shead .lab{font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;font-weight:700;color:var(--blue)}

.band{padding:clamp(46px,7vw,104px) 0}
.band.tint{background:var(--band)}
.band.tint2{background:var(--band-2)}
.band.dark{background:var(--dark);color:#E9EEF3}
.band.dark h1,.band.dark h2,.band.dark h3{color:#fff}
.band.dark .lead{color:#B9C6D2}
.band.dark .shead .n{color:#fff}
.band.dark .shead .dash{background:rgba(255,255,255,.4)}
.band.dark .shead .lab{color:var(--pale)}
.stack{display:flex;flex-direction:column;gap:clamp(16px,2vw,24px)}

/* ---- header ---- */
.site-head{position:sticky;top:0;z-index:100;background:var(--dark);color:#fff}
.head-in{max-width:var(--wrap);margin-inline:auto;padding:11px var(--gut);
  display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.brand{display:flex;flex-direction:column;gap:1px;text-decoration:none;color:#fff;margin-right:auto}
.brand-name{font-weight:800;font-size:clamp(15px,3.4vw,18px);letter-spacing:-.01em}
.brand-name em{color:var(--blue-lt);font-style:normal}
.brand-sub{font-size:9.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--pale)}
.head-call{display:none;background:var(--blue-btn);color:#fff;text-decoration:none;font-weight:700;
  padding:11px 16px;white-space:nowrap;font-size:14.5px}
.head-call:hover{background:var(--blue-deep)}
.navtoggle{position:absolute;opacity:0;pointer-events:none}
.burger{width:var(--tap);height:var(--tap);display:flex;flex-direction:column;justify-content:center;
  gap:5px;cursor:pointer;padding:0 10px;margin-right:-8px}
.burger span{display:block;height:2px;background:#fff;transition:transform .2s,opacity .2s}
.navtoggle:checked + .burger span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.navtoggle:checked + .burger span:nth-child(2){opacity:0}
.navtoggle:checked + .burger span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.nav{flex-basis:100%;max-height:0;overflow:hidden;transition:max-height .28s ease}
.navtoggle:checked ~ .nav{max-height:560px}
.nav ul{list-style:none;padding:0;margin:6px 0 10px;display:flex;flex-direction:column}
.nav a{display:flex;align-items:center;min-height:var(--tap);color:#DCE5EE;text-decoration:none;
  font-weight:600;font-size:15.5px;border-bottom:1px solid rgba(255,255,255,.10)}
.nav a.on{color:#fff}
.nav a.on::before{content:"";width:3px;height:17px;background:var(--blue-lt);margin-right:10px}
@media (min-width:1000px){
  .burger{display:none}
  .nav{flex-basis:auto;max-height:none;overflow:visible;order:3}
  .nav ul{flex-direction:row;gap:22px;margin:0}
  .nav a{border:0;min-height:auto;font-size:14px;font-weight:600}
  .nav a.on::before{display:none}
  .nav a.on{box-shadow:inset 0 -2px 0 var(--blue-lt)}
  .head-call{display:inline-block;order:4}
  /* margin-right:auto, NOT a fixed value. The base .brand rule sets `auto` so the
     nav and call button are pushed out to the right edge. Overriding it with a
     fixed 30px removed that push, so logo, nav and button all packed to the left
     and left dead space on the right of the header. The gap is handled by
     min-width instead, which keeps the breathing room without killing the push. */
  .brand{margin-right:auto;min-width:0}
  .nav ul{margin-right:26px}
  .head-in{flex-wrap:nowrap}
}

/* ---- hero ---- */
.hero{background:var(--dark);color:#fff;padding:clamp(34px,5vw,72px) 0}
.hero .wrap{display:grid;gap:clamp(24px,3.4vw,48px)}
.hero h1{color:#fff}
.hero .lead{color:#BDCAD6;max-width:52ch}
.hero .shead .n{color:#fff}
.hero .shead .dash{background:rgba(255,255,255,.4)}
.hero .shead .lab{color:var(--pale)}
.hero-media img{width:100%;object-fit:cover}
@media (min-width:900px){.hero .wrap{grid-template-columns:1.02fr 1fr;align-items:center}}

/* ---- CSS-only crossfade slideshow (no JavaScript) ----
   Lives in the standard .hero-media slot, so the hero keeps its original
   proportions and the slideshow simply replaces the single static photo. */
.slideshow{position:relative;aspect-ratio:4/3;overflow:hidden;
  background:#1B2026;min-width:0}
@media (min-width:900px){.slideshow{aspect-ratio:16/11}}
.slideshow figure{position:absolute;inset:0;margin:0;opacity:0;
  animation:slidefade 8s linear infinite}
.slideshow figure img{width:100%;height:100%;object-fit:cover}
/* 4 slides over 8s: 2s each, on the owner's instruction. Each slide holds for a
   quarter of the cycle, so the visible window is 25%.
   The crossfade is a PERCENTAGE of the cycle, so shortening the cycle shortens
   the fade with it: 3% of 8s is ~0.24s.
   The delay divisor in build_pages.py must match this duration, and these
   percentages must match the slide COUNT. */
@keyframes slidefade{
  0%{opacity:0}
  3%{opacity:1}
  25%{opacity:1}
  28%{opacity:0}
  100%{opacity:0}
}
.dots{position:absolute;left:0;right:0;bottom:12px;display:flex;justify-content:center;
  gap:7px;z-index:2}
.dots span{width:26px;height:3px;border-radius:2px;background:rgba(255,255,255,.34);
  animation:doton 8s linear infinite}
@keyframes doton{0%,25%{background:rgba(255,255,255,.92)}
  26%,100%{background:rgba(255,255,255,.34)}}

/* reduced motion: hold the first slide, no cycling */
@media (prefers-reduced-motion:reduce){
  .slideshow figure{animation:none;opacity:0}
  .slideshow figure:first-child{opacity:1}
  .dots span{animation:none}
  .dots span:first-child{background:rgba(255,255,255,.92)}
}

/* ---- buttons ---- */
.btnrow{display:flex;flex-wrap:wrap;gap:12px}
.center .btnrow{justify-content:center}
.btn{display:inline-flex;align-items:center;justify-content:center;min-height:var(--tap);
  padding:14px 24px;font-weight:700;font-size:16px;text-decoration:none;
  border:1px solid transparent;cursor:pointer;font-family:inherit}
.btn-primary{background:var(--blue-btn);color:#fff;border-color:var(--blue-btn)}
.btn-primary:hover{background:var(--blue-deep);border-color:var(--blue-deep)}
.btn-ghost{background:transparent;color:var(--ink);border-color:rgba(42,46,51,.25)}
.btn-ghost:hover{border-color:var(--ink);background:rgba(42,46,51,.04)}
.dark .btn-ghost,.hero .btn-ghost{color:#fff;border-color:rgba(255,255,255,.45)}
.dark .btn-ghost:hover,.hero .btn-ghost:hover{background:rgba(255,255,255,.10);border-color:#fff}
.btn.wide{width:100%}
.microline{font-size:11.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-60)}
.dark .microline{color:var(--pale)}

/* ---- grids ---- */
.grid{display:grid;gap:clamp(18px,2.4vw,30px)}
.g2{grid-template-columns:1fr}
.g3{grid-template-columns:1fr}
.g4{grid-template-columns:1fr}
@media (min-width:640px){.g2,.g3,.g4{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1000px){.g3{grid-template-columns:repeat(3,1fr)}.g4{grid-template-columns:repeat(4,1fr)}}

/* ---- numbered feature columns (01 02 03 04, outlined) ---- */
.feats{display:grid;gap:clamp(22px,2.6vw,30px);grid-template-columns:1fr}
@media (min-width:640px){.feats{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1000px){.feats{grid-template-columns:repeat(4,1fr)}}
.feat{display:flex;flex-direction:column;gap:10px;padding-left:22px;border-left:1px solid var(--rule)}
/* numeral was var(--rule) #D9E2ED, which is 1.12:1 on a tint band â€” unreadable.
   --blue is 4.5:1 on tint and 5.2:1 on white, and stays inside the locked palette. */
.feat .big{font-size:clamp(38px,3.4vw,46px);font-weight:800;line-height:1;
  color:var(--blue);letter-spacing:-.04em}
.dark .feat .big{color:var(--pale)}
.dark .feat{border-left-color:rgba(255,255,255,.22)}
/* --rule is nearly the tint colour itself, so hairlines vanish on tinted bands */
.tint .feat,.tint .faq,.tint .faq details{border-color:#C3D2E3}
.feat h3{font-size:18px}
.feat p{font-size:15px;color:var(--ink-70);line-height:1.62}

/* ---- cards ---- */
.card{background:var(--white);border:1px solid var(--rule);overflow:hidden;
  display:flex;flex-direction:column}
.card img{width:100%;object-fit:cover}
.card-body{padding:20px;display:flex;flex-direction:column;gap:9px;flex:1}
.card p{color:var(--ink-70);font-size:15px}
.card-link{margin-top:auto;font-weight:700;text-decoration:none;color:var(--blue);
  display:inline-flex;align-items:center;min-height:30px;font-size:14.5px;letter-spacing:.01em}
.card-link::after{content:" \2192";margin-left:7px}
a.card{text-decoration:none;color:inherit}
a.card:hover{border-color:var(--blue-lt);box-shadow:0 14px 34px rgba(22,52,79,.10)}
.tint .card{background:var(--white)}

/* ---- photo card with gradient overlay ---- */
.pcard{position:relative;overflow:hidden;display:flex;align-items:flex-end;
  text-decoration:none;color:#fff;min-height:290px;isolation:isolate}
.pcard img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;
  transition:transform .5s ease}
.pcard::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(to top,rgba(20,25,31,.90) 0%,rgba(20,25,31,.58) 38%,rgba(20,25,31,.14) 72%,rgba(20,25,31,.05) 100%)}
.pcard:hover img{transform:scale(1.04)}
.pcard .cat{position:absolute;top:16px;left:18px;z-index:2;font-size:10.5px;font-weight:700;
  letter-spacing:.15em;text-transform:uppercase;color:#fff}
.pcard .pbody{position:relative;z-index:2;padding:20px;display:flex;flex-direction:column;gap:7px}
.pcard h3{color:#fff;font-size:clamp(19px,1.7vw,23px)}
.pcard p{color:rgba(255,255,255,.86);font-size:14.5px;line-height:1.55;max-width:38ch}
.pcard .go{margin-top:4px;font-size:13px;font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--pale)}
.pcard .go::after{content:" \2192"}

/* asymmetric bento: 2 + 2 + tall, then 1 wide */
.bento{display:grid;gap:14px;grid-template-columns:1fr}
@media (min-width:760px){
  .bento{grid-template-columns:repeat(6,1fr);grid-auto-rows:minmax(230px,auto)}
  .bento > :nth-child(1){grid-column:span 2}
  .bento > :nth-child(2){grid-column:span 2}
  .bento > :nth-child(3){grid-column:span 2;grid-row:span 2}
  .bento > :nth-child(4){grid-column:span 4}
}

/* ---- page + navigation motion ---- */
@view-transition{navigation:auto}
@keyframes pagein{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
main{animation:pagein .38s cubic-bezier(.22,.61,.36,1) both}
@media (prefers-reduced-motion:reduce){
  main{animation:none}
  @view-transition{navigation:none}
}

/* ---- scroll-driven reveals -------------------------------------------------
   Still zero JavaScript: `animation-timeline: view()` drives these off scroll
   position natively. Wrapped in @supports so browsers without it simply show
   everything, already in its final state â€” nothing can get stuck invisible. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion:no-preference){
    @keyframes rise{from{opacity:0;transform:translateY(26px)}to{opacity:1;transform:none}}
    @keyframes settle{from{opacity:0;transform:translateY(34px) scale(.985)}to{opacity:1;transform:none}}

    .band .stack > *,
    .feat,.card,.pcard,.svc,.flow-step,.masonry figure,.review,.stat,.t{
      animation:rise linear both;
      animation-timeline:view();
      animation-range:entry 0% entry 46%;
    }
    /* containers whose children animate individually must not animate too,
       or the reveal runs twice and reads as a stutter */
    .band .stack > .flow,
    .band .stack > .masonry,
    .band .stack > .grid,
    .band .stack > .svclist,
    .band .stack > .feats,
    .band .stack > .bento{animation:none}
    /* bigger blocks get a slightly softer, longer entrance */
    .svc,.flow-step,.bento > *{
      animation-name:settle;
      animation-range:entry 0% entry 58%;
    }
    /* the marquee and the hero drive themselves â€” don't double-animate them */
    .revtrack,.revmarquee,.hero .stack > *,.hero-media{animation-timeline:auto}
    .hero .stack > *,.hero-media{animation:none}
  }
}

/* soften every interactive surface so nothing snaps */
a,.btn,.card,.pcard,.tile img,.masonry figure img,.flow-n,.lb-x,.lb-nav{
  transition:color .2s ease,background-color .22s ease,border-color .22s ease,
             box-shadow .28s ease,transform .35s cubic-bezier(.22,.61,.36,1),opacity .2s ease}
@media (prefers-reduced-motion:reduce){
  a,.btn,.card,.pcard,.tile img,.masonry figure img,.flow-n,.lb-x,.lb-nav{transition:none}
}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}

/* ---- lightbox (CSS only, :target â€” back button closes it) ---- */
.lb-open{display:block;cursor:pointer;position:relative}
/* .lb MUST stay outside <main>. <main> runs the `pagein` transform animation, and a
   transform-animated ancestor becomes the containing block for position:fixed â€” which
   made this size to the height of <main>, opening photos far down the page. */
.lb{position:fixed;top:0;left:0;width:100%;height:100vh;height:100dvh;z-index:200;
  display:none;align-items:center;justify-content:center;overscroll-behavior:contain;
  background:rgba(14,20,26,.94);padding:clamp(14px,3vw,44px)}
/* The backdrop is deliberately NOT animated. It used to run
   `animation:lbin .26s` fading opacity 0 -> 1, which looked fine when opening a
   photo from the page but was wrong when moving between photos: each prev/next
   click hides one .lb and shows the next, so the backdrop faded up from
   transparent every time and the page flashed through behind it for a quarter
   of a second.
   With the backdrop painting solid immediately, consecutive lightboxes are
   visually continuous â€” the dark layer never drops out â€” and only the photo
   itself transitions. Do not put an opacity animation back on .lb. */
.lb:target{display:flex}
/* the photo still eases in, which is what reads as the transition now */
.lb-inner{max-width:min(1200px,100%);max-height:100%;display:flex;flex-direction:column;
  gap:12px;align-items:center;animation:lbzoom .28s cubic-bezier(.22,.61,.36,1) both}
@keyframes lbzoom{from{transform:scale(.985);opacity:0}to{transform:none;opacity:1}}
.lb-inner img{max-width:100%;max-height:82vh;width:auto;height:auto;object-fit:contain;background:none}
.lb-cap{color:#D6DEE6;font-size:14px;text-align:center;max-width:60ch}
.lb-cap .cat{color:#8FA1B0;font-size:11px;letter-spacing:.13em;text-transform:uppercase;
  display:block;margin-top:4px;font-weight:600}
.lb-close{position:absolute;top:0;left:0;right:0;bottom:0;z-index:1;cursor:default;
  font-size:0;text-decoration:none}
.lb-x{position:absolute;top:clamp(10px,2vw,22px);right:clamp(10px,2vw,22px);z-index:3;
  width:46px;height:46px;display:grid;place-items:center;color:#fff;font-size:26px;
  line-height:1;text-decoration:none;background:rgba(255,255,255,.10);border-radius:50%}
.lb-x:hover{background:rgba(255,255,255,.20)}
.lb-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:3;width:52px;height:52px;
  display:grid;place-items:center;color:#fff;font-size:28px;text-decoration:none;
  background:rgba(255,255,255,.10);border-radius:50%}
.lb-nav:hover{background:rgba(255,255,255,.20)}
.lb-prev{left:clamp(6px,1.5vw,20px)}
.lb-next{right:clamp(6px,1.5vw,20px)}
@media (max-width:560px){.lb-nav{width:44px;height:44px;font-size:24px}}

/* ---- masonry: every photo at its own aspect ratio, never cropped ---- */
.masonry{columns:2;column-gap:12px}
@media (min-width:760px){.masonry{columns:3;column-gap:16px}}
@media (min-width:1100px){.masonry{columns:4;column-gap:16px}}
.masonry figure{break-inside:avoid;-webkit-column-break-inside:avoid;page-break-inside:avoid;
  margin:0 0 12px;position:relative;overflow:hidden;background:#EDF1F5;display:block}
@media (min-width:760px){.masonry figure{margin-bottom:16px}}
.masonry img{width:100%;height:auto;display:block;transition:transform .5s ease}
.masonry figure:hover img{transform:scale(1.04)}
.masonry figcaption{position:absolute;left:0;right:0;bottom:0;padding:26px 12px 11px;
  font-size:11.5px;font-weight:700;letter-spacing:.04em;color:#fff;line-height:1.4;
  background:linear-gradient(to top,rgba(20,25,31,.88),rgba(20,25,31,.55) 55%,rgba(20,25,31,0))}
.masonry figcaption .cat{display:block;font-weight:500;color:rgba(255,255,255,.72);font-size:10.5px;
  letter-spacing:.12em;text-transform:uppercase;margin-top:3px}

/* ---- gallery tiles ---- */
.tile{margin:0;background:var(--white);border:1px solid var(--rule)}
.tile img{width:100%;aspect-ratio:4/3;object-fit:cover}
.tile figcaption{padding:10px 12px;font-size:12.5px;font-weight:600;letter-spacing:.03em;color:var(--ink-70)}

/* ---- blue-square bullet list ---- */
.ticks{list-style:none;padding:0;display:grid;gap:11px}
.ticks li{position:relative;padding-left:22px;color:var(--ink-70);font-size:15.5px}
.ticks li::before{content:"";position:absolute;left:0;top:.58em;width:8px;height:8px;background:var(--blue-lt)}
.dark .ticks li{color:#C2CEDA}

/* ---- testimonials: 44x3 blue bar ---- */
.revrail{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(272px,84%);gap:clamp(20px,3vw,40px);
  overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:12px;
  margin-inline:calc(var(--gut) * -1);padding-inline:var(--gut)}
.revrail > *{scroll-snap-align:start}
@media (min-width:900px){.revrail{grid-auto-flow:row;grid-template-columns:repeat(3,1fr);
  overflow:visible;margin-inline:0;padding-inline:0}}

/* ---- auto-sliding review marquee ---- */
.revmarquee{overflow:hidden;position:relative;
  margin-inline:calc(var(--gut) * -1);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.revtrack{display:flex;align-items:stretch;gap:clamp(26px,3vw,54px);width:max-content;padding-block:4px;
  padding-inline:clamp(13px,2vw,27px);animation:revscroll 46s linear infinite}
.revmarquee:hover .revtrack,.revmarquee:focus-within .revtrack{animation-play-state:paused}
.revtrack .review{width:min(80vw,390px);flex:none}
@keyframes revscroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){
  .revmarquee{overflow-x:auto;mask-image:none;-webkit-mask-image:none}
  .revtrack{animation:none}
}
/* natural review card: avatar, name, stars + date, then the quote */
.review{display:flex;flex-direction:column;gap:14px;max-width:44ch;text-align:left;
  /* opaque, not rgba: a translucent card lets the quilting read straight through
     the review text. This is the same colour the old 5.5% white overlay produced. */
  background:#2F343A;border:1px solid rgba(255,255,255,.11);
  padding:22px 22px 24px}
.rev-top{display:flex;align-items:center;gap:12px}
.avatar{width:42px;height:42px;border-radius:50%;flex:none;display:grid;place-items:center;
  font-weight:800;font-size:16px;color:#fff;line-height:1;overflow:hidden}
.avatar img{width:100%;height:100%;object-fit:cover}
.rev-id{display:flex;flex-direction:column;gap:3px;min-width:0}
.rev-name{font-weight:700;font-size:15px;color:#fff;letter-spacing:-.01em}
.rev-sub{font-size:12.5px;color:#93A5B4}
.rev-line{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.rev-date{font-size:12.5px;color:#93A5B4}
.review blockquote{margin:0;font-size:16px;line-height:1.65;color:#DCE4EB}
.stars{color:var(--star-gold);font-size:15px;letter-spacing:.16em;line-height:1}
.stars span{position:absolute;left:-9999px}
.dark .review blockquote{color:#E6ECF2}
.dark .review .who{color:#fff}
.dark .review .who span{color:#9FB0BF}
.dark .googlelink{color:var(--pale)}
.dark .rev-hint{color:#8FA1B0}
/* centred variant */

/* slider affordance */
.rev-hint{display:flex;align-items:center;justify-content:center;gap:9px;font-size:12px;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-60)}
@media (min-width:900px){.rev-hint{display:none}}
.googlelink{display:inline-flex;align-items:center;gap:9px;min-height:var(--tap);
  font-weight:700;font-size:15px;text-decoration:none;color:var(--blue)}
.googlelink::after{content:" \2192"}

/* ---- process flow: connected numbered timeline ---- */
.flow{display:flex;flex-direction:column}
.flow-step{--node:clamp(50px,5.4vw,66px);position:relative;display:grid;
  grid-template-columns:var(--node) minmax(0,1fr);
  column-gap:clamp(15px,2.2vw,26px);row-gap:clamp(14px,2vw,20px);
  padding-bottom:clamp(32px,4.2vw,60px)}
.flow-step:last-child{padding-bottom:0}
/* the rail linking one node to the next */
.flow-step::before{content:"";position:absolute;left:calc(var(--node) / 2 - 1px);
  top:var(--node);bottom:0;width:2px;background:var(--rule)}
.flow-step:last-child::before{content:none}
.flow-n{width:var(--node);height:var(--node);border-radius:50%;
  border:2px solid var(--blue-lt);color:var(--blue);background:var(--white);
  display:grid;place-items:center;font-weight:800;letter-spacing:-.03em;
  font-size:clamp(16px,1.6vw,21px);position:relative;z-index:1;
  transition:background .25s ease,color .25s ease,border-color .25s ease}
.flow-step:hover .flow-n{background:var(--blue);border-color:var(--blue);color:#fff}
.flow-body{display:flex;flex-direction:column;gap:9px;min-width:0;
  padding-top:clamp(4px,1vw,12px)}
.flow-body h3{font-size:clamp(19px,1.9vw,25px);letter-spacing:-.022em}
.flow-body p{color:var(--ink-70);max-width:60ch}
.flow-tag{font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--blue)}
.flow-media{grid-column:2;min-width:0}
.flow-media img{width:100%;height:auto}
@media (min-width:900px){
  .flow-step{grid-template-columns:var(--node) minmax(0,1.04fr) minmax(0,1fr);
    align-items:start;column-gap:clamp(22px,2.8vw,40px)}
  .flow-media{grid-column:3;grid-row:1}
}
@media (prefers-reduced-motion:reduce){.flow-n{transition:none}}

/* ---- stat band ---- */
.stats{display:grid;gap:clamp(20px,3vw,34px);grid-template-columns:repeat(2,1fr);text-align:center}
@media (min-width:820px){.stats{grid-template-columns:repeat(4,1fr)}}
.stat{display:flex;flex-direction:column;gap:5px}
.stat b{font-size:clamp(30px,3.4vw,44px);font-weight:800;letter-spacing:-.03em;line-height:1;color:#fff}
.stat span{font-size:12px;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:var(--pale)}

/* ---- map ---- */
.mapwrap{position:relative;width:100%;aspect-ratio:4/3;background:#E4EAEF;overflow:hidden}
@media (min-width:900px){.mapwrap{aspect-ratio:16/11}}
.mapwrap iframe{position:absolute;inset:0;width:100%;height:100%;border:0}

/* ---- centred article head ---- */
.article-head{text-align:center;max-width:760px;margin-inline:auto;display:flex;
  flex-direction:column;gap:14px;align-items:center}
.article-head h1{max-width:22ch}
.article-figure{margin:clamp(22px,3vw,38px) 0}
.article-figure img{width:100%;height:auto}

/* ---- faq ---- */
.faq{border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{cursor:pointer;list-style:none;padding:19px 38px 19px 0;position:relative;
  font-weight:700;font-size:17px;min-height:var(--tap);display:flex;align-items:center;
  letter-spacing:-.012em}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";position:absolute;right:4px;font-size:22px;font-weight:400;color:var(--blue)}
.faq details[open] summary::after{content:"\2013"}
.faq .ans{padding:0 0 20px;color:var(--ink-70);max-width:68ch;font-size:16px}

/* ---- contact layout: compact, form card + info column ---- */
.band.compact{padding:clamp(30px,4vw,56px) 0 clamp(38px,5vw,72px)}
.contact-head{max-width:60ch;margin-bottom:clamp(24px,3vw,38px)}
.contact-head h1{font-size:clamp(29px,3.6vw,44px);margin-bottom:12px}
.contact-head .lead{font-size:16.5px}
.contact-grid{display:grid;gap:clamp(22px,2.6vw,38px);grid-template-columns:1fr;align-items:start}
@media (min-width:900px){.contact-grid{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}}
.formcard{background:#fff;box-shadow:0 20px 44px rgba(42,46,51,.09);
  border:1px solid var(--rule);padding:clamp(20px,2.4vw,30px)}
.formcard-h{font-size:clamp(19px,1.8vw,23px);margin-bottom:16px}
.infocol{display:flex;flex-direction:column;gap:clamp(18px,2vw,26px)}

/* info column â€” blue square dots, the site's own device */
.infolist{list-style:none;padding:0;display:flex;flex-direction:column;gap:15px}
.infolist li{position:relative;padding-left:22px}
.infolist li::before{content:"";position:absolute;left:0;top:.46em;width:8px;height:8px;background:var(--blue-lt)}
.infolist .k{display:block;font-size:10.5px;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:var(--blue);margin-bottom:3px}
.infolist .v{font-size:15.5px;line-height:1.5;color:var(--ink-70)}
.infolist .v strong{color:var(--ink);font-weight:700}
.infolist a{text-decoration:none}
.infolist .big{font-size:22px;font-weight:800;letter-spacing:-.02em;color:var(--ink);display:inline-block}
.infolist .hours{font-size:15px}
.infolist .hours th,.infolist .hours td{padding:2px 0}
/* wide + short, like the old contact page â€” not a tall block */
.infocol .mapwrap{aspect-ratio:16/9}
@media (min-width:900px){.infocol .mapwrap{aspect-ratio:12/5}}

/* tighter form inside the compact card */
.formcard .quote{gap:13px}
.formcard .f2,.formcard .f3{gap:13px}

/* ---- form ---- */
.quote{display:flex;flex-direction:column;gap:16px}
.quote label{display:flex;flex-direction:column;gap:7px;font-weight:600;font-size:13.5px;
  letter-spacing:.03em}
.quote input,.quote textarea{font:400 16px/1.5 'Archivo',system-ui,sans-serif;padding:12px 13px;
  border:1px solid rgba(42,46,51,.22);background:#fff;color:var(--ink);width:100%;min-height:var(--tap)}
.quote textarea{min-height:124px;resize:vertical}
.quote input:focus,.quote textarea:focus{border-color:var(--blue);outline:2px solid rgba(47,111,176,.22)}

/* ---- SMS consent (TCPA) ----------------------------------------------------
   MUST sit after the .quote rules above. `.quote label` is a column flexbox and
   `.quote input` is a full-width padded text field â€” at equal specificity those
   win on source order and render the checkbox as a giant square. Hence the
   attribute selector, which outranks them. */
/* Honeypot wrapper. Must stay visually gone but still present in the DOM and
   still submitted, so a bot that fills every input trips it. Off-screen rather
   than display:none, because some bots skip hidden fields. */
.quote .hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.quote label.consent{display:grid;grid-template-columns:auto minmax(0,1fr);
  gap:10px;align-items:start;font-weight:400;font-size:13px;line-height:1.55;
  color:var(--ink-70);cursor:pointer}
.quote label.consent input[type="checkbox"]{
  appearance:auto;width:18px;height:18px;min-width:18px;flex:none;padding:0;
  margin:2px 0 0;border:0;border-radius:0;accent-color:var(--blue-btn)}
.quote label.consent span{display:block}
.f2,.f3{display:grid;gap:16px;grid-template-columns:1fr}
@media (min-width:560px){.f2{grid-template-columns:1fr 1fr}.f3{grid-template-columns:repeat(3,1fr)}}
.formnote{font-size:13.5px;color:var(--ink-60)}

/* ---- article ---- */
.article{max-width:720px;margin-inline:auto}
.article p{margin-bottom:1.2em;color:var(--ink-70)}
.article p:last-child{margin-bottom:0}
.meta{font-size:11.5px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-60)}

.hours{border-collapse:collapse;font-size:15.5px}
.hours th,.hours td{text-align:left;padding:5px 0;font-weight:400;vertical-align:top}
.hours th{font-weight:700;padding-right:18px;white-space:nowrap}

/* ---- footer ---- */
/* a step lighter than --dark so the footer does not land as a heavy black slab */
/* padding-bottom clears the fixed .callbar: its 46px min-height plus 8px gap.
   Keep these two in step â€” shrink the bar without shrinking this and the footer
   ends with dead space; shrink this too far and the bar covers the last line. */
.site-foot{background:#2A2F36;color:#B4C2CE;padding-bottom:calc(54px + env(safe-area-inset-bottom))}
.foot-in{max-width:var(--wrap);margin-inline:auto;padding:clamp(38px,5vw,68px) var(--gut);
  display:grid;gap:32px;grid-template-columns:1fr}
@media (min-width:640px){.foot-in{grid-template-columns:repeat(2,1fr)}}
@media (min-width:1000px){.foot-in{grid-template-columns:1.5fr 1fr 1fr 1.1fr}}
.foot-col{display:flex;flex-direction:column;gap:10px}
.foot-col ul{list-style:none;padding:0;display:flex;flex-direction:column;gap:1px}
.foot-col a{color:#B4C2CE;text-decoration:none;display:inline-flex;align-items:center;min-height:32px;font-size:15px}
.foot-col a:hover{color:#fff}
.foot-brand{font-weight:800;color:#fff;font-size:17px;letter-spacing:-.01em}
.foot-brand em{color:var(--blue-lt);font-style:normal}
.foot-h{font-size:11px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;color:var(--pale)}
.foot-phone{font-size:20px;font-weight:800;color:#fff !important;letter-spacing:-.01em}
.foot-area{font-size:13px;color:#8B9CAB}
.site-foot .hours th,.site-foot .hours td{color:#B4C2CE}
.foot-bar{border-top:1px solid rgba(255,255,255,.10);padding:16px var(--gut);text-align:center;font-size:13px}

/* ---- sticky mobile call bar ---- */
.callbar{position:fixed;left:0;right:0;bottom:0;z-index:120;display:flex;align-items:center;
  justify-content:center;gap:9px;background:var(--blue-btn);color:#fff;text-decoration:none;
  font-weight:700;min-height:46px;padding:6px 16px calc(6px + env(safe-area-inset-bottom));
  font-size:15.5px;box-shadow:0 -4px 18px rgba(0,0,0,.20)}
@media (min-width:1000px){.callbar{display:none}.site-foot{padding-bottom:0}}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms !important;transition-duration:.01ms !important;scroll-behavior:auto !important}
}

/* rating: typographic, deliberately NOT a bordered box so it doesn't read
   as another review card sitting above the real ones */
.ratingbadge{display:flex;flex-direction:column;align-items:center;gap:9px;
  margin:4px auto 0;padding:0;border:0;background:none}
.ratingbadge .stars{margin:0;font-size:20px;letter-spacing:.22em}
.ratingbadge .line{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;justify-content:center}
.ratingbadge .score{font-size:clamp(30px,3.4vw,40px);font-weight:800;line-height:1;
  letter-spacing:-.035em;color:#fff}
.ratingbadge .cnt{font-size:14px;color:#9FB0BF}
.ratingbadge .cnt b{color:#fff;font-weight:700}

/* ---- services list: alternating photo + detail rows ---- */
.svclist{display:flex;flex-direction:column;gap:clamp(34px,5vw,72px)}
.svc{display:grid;gap:clamp(18px,3vw,44px);grid-template-columns:1fr;align-items:center}
.svc-media img{width:100%;height:auto}
.svc-body{display:flex;flex-direction:column;gap:14px;align-items:flex-start}
.svc-n{font-size:12px;font-weight:800;letter-spacing:.06em;color:var(--blue)}
.svc-body h2{font-size:clamp(24px,2.6vw,34px)}
.svc-body .ticks{margin-bottom:4px}
@media (min-width:860px){
  .svc{grid-template-columns:1fr 1fr}
  .svc:nth-child(even) .svc-media{order:2}
}

/* ---- rounded corners -------------------------------------------------------
   Media reads softened rather than sharp-cornered. Grouped here at the end so
   the radii are a single, deliberate set instead of scattered magic numbers. */
/* Where a photo scales on hover, the radius MUST live on the clipping container,
   not the image. Put it on the image and the scaled-up copy is clipped by the
   still-square parent, so the corners snap sharp on hover. */
.masonry figure,.tile,.card,.pcard{overflow:hidden}
.masonry figure,.tile{border-radius:var(--r-media)}
.card,.pcard,.formcard,.review{border-radius:var(--r-card)}
/* a rounded child inside a rounded, clipped parent must not double up */
.masonry figure img,.tile img,.card img,.pcard img{border-radius:0}

/* images with no clipping parent carry the radius themselves */
.hero-media img,.slideshow,.svc-media img,.flow-media img,
.article-figure img,.blogcard img,.mapwrap,.lb-inner img{border-radius:var(--r-media)}
.hero-media img,.slideshow{overflow:hidden}

.btn,.quote input,.quote textarea,.consent,.head-call{border-radius:var(--r-ctl)}

/* ============================================================================
   MOBILE PASS â€” everything below 900px. Desktop is deliberately untouched:
   no rule in here applies at 900px and up.
   ========================================================================== */
@media (max-width:899px){

  /* --- tighter vertical rhythm: same content, far less scrolling --- */
  .band{padding:34px 0}
  .stack{gap:13px}
  .lead{font-size:15.5px;line-height:1.55;max-width:none}
  h1{font-size:clamp(26px,7.2vw,33px)}
  h2{font-size:clamp(22px,6vw,28px)}
  h3{font-size:16.5px}
  .shead{margin-bottom:9px;gap:10px}
  .microline{font-size:10.5px}

  /* --- buttons sit side by side, never stacked --- */
  .btnrow{flex-wrap:nowrap;gap:9px}
  .btnrow .btn{flex:1 1 0;min-width:0;padding:13px 8px;font-size:14.5px;
    text-align:center;line-height:1.2}
  .btn.wide{flex:none;width:100%}

  /* --- hero: compact, and the photo actually visible above the fold --- */
  .hero{padding:22px 0 26px}
  .hero .wrap{gap:16px}
  .slideshow{aspect-ratio:16/10}
  .dots{bottom:9px}
  .dots span{width:20px}

  /* --- recent work: 6 tiles, then send them to the gallery --- */
  #recent-work .masonry{columns:2;column-gap:9px}
  #recent-work .masonry figure{margin-bottom:9px}
  #recent-work .masonry figure:nth-child(n+7){display:none}
  .masonry figcaption{padding:18px 9px 8px;font-size:10.5px}

  /* --- swipe rows: photos and blog cards run left-to-right, not down --- */
  .swiperow{display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;
    margin-inline:calc(var(--gut) * -1);padding-inline:var(--gut);
    scrollbar-width:none;-webkit-overflow-scrolling:touch}
  .swiperow::-webkit-scrollbar{display:none}
  .swiperow > *{flex:0 0 76%;scroll-snap-align:start}
  .swiperow .tile img{aspect-ratio:4/3}

  /* --- testimonials --- */
  .revtrack .review{width:82vw}
  .review{padding:17px 17px 19px;gap:11px}
  .review blockquote{font-size:14.5px;line-height:1.55}
  .ratingbadge{transform:scale(.92)}

  /* --- numbered feature columns --- */
  .feats{gap:15px}
  .feat{padding-left:15px}
  .feat .big{font-size:29px}
  .feat p{font-size:14.5px;line-height:1.5}

  /* --- process timeline --- */
  .flow-step{--node:44px;padding-bottom:22px;row-gap:11px;column-gap:13px}
  .flow-body{padding-top:2px;gap:6px}
  .flow-body h3{font-size:17px}
  .flow-body p{font-size:14.5px}
  .flow-tag{font-size:10px}

  /* --- service rows and cards --- */
  .svclist{gap:26px}
  .svc{gap:14px}
  .svc-body{gap:10px}
  .card-body{padding:15px;gap:7px}
  .card p{font-size:14.5px}
  .ticks li{font-size:14.5px;margin-bottom:6px}

  /* --- contact page --- */
  .contact-grid{gap:18px}
  .formcard{padding:18px 16px}
  .formcard-h{font-size:18px;margin-bottom:12px}
  .quote{gap:11px}
  .quote label{font-size:12.5px;gap:5px}
  .quote input,.quote textarea{padding:10px 11px;font-size:16px}
  .quote textarea{min-height:92px}
  .infolist li{padding:11px 0}
  .infolist .k{font-size:10.5px}
  .mapwrap{aspect-ratio:4/3}
  .faq summary{padding:14px 32px 14px 0;font-size:15.5px}
  .faq .ans{font-size:14.5px;padding-bottom:15px}

  /* --- footer: was the longest thing on the site --- */
  .foot-in{padding:24px var(--gut) 20px;gap:16px 18px;
    grid-template-columns:repeat(2,1fr)}
  .foot-col:first-child{grid-column:1 / -1}
  .site-foot{font-size:13.5px}
  .foot-brand{font-size:15px}
  .foot-col:first-child p{font-size:13.5px}
  .foot-h{font-size:10px;margin-bottom:5px}
  .foot-col ul{display:flex;flex-direction:column;gap:1px}
  .site-foot li a{min-height:26px;font-size:13.5px}
  .site-foot .hours th,.site-foot .hours td{font-size:12.5px;padding:1px 0}
  .foot-area{font-size:12.5px;margin-top:6px}
  .foot-bar{padding:11px var(--gut);font-size:11.5px}
}

/* ============================================================================
   MOBILE PASS 2 â€” refinements. Still nothing applies at 900px and up.
   ========================================================================== */
@media (max-width:899px){

  /* --- header was the same charcoal as the hero, so the two merged into one
         slab. A hairline plus the photo moving to the top breaks them apart. --- */
  .site-head{box-shadow:0 1px 0 rgba(255,255,255,.14)}

  /* --- hero: photo first, copy under it --- */
  .hero{padding:0 0 26px}
  .hero .wrap{gap:0;padding-inline:0}
  .hero-media{order:-1;margin-bottom:18px}
  .hero-media .slideshow{border-radius:0;aspect-ratio:4/3}
  .hero .stack{padding-inline:var(--gut)}

  /* --- subtext was competing with the headings; drop it back --- */
  .lead{font-size:14px;line-height:1.5}
  h1{font-size:clamp(25px,6.6vw,30px)}
  h2{font-size:clamp(20px,5.4vw,25px)}
  h3{font-size:16px}
  .band{padding:28px 0}
  .stack{gap:11px}

  /* --- centre the section intros; reads calmer on a narrow screen --- */
  .band .wrap > .stack:first-child{text-align:center;align-items:center}
  .band .wrap > .stack:first-child .shead{justify-content:center}
  .band .wrap > .stack:first-child .lead{margin-inline:auto}
  .hero .stack{text-align:center;align-items:center}
  .hero .shead{justify-content:center}
  .hero .btnrow{width:100%}

  /* --- scroll-driven reveals are the "choppy" feeling on phones --- */
  .band .stack > *,.feat,.card,.pcard,.svc,.flow-step,
  .masonry figure,.review,.stat,.t{animation:none !important}

  /* --- services page --- */
  .svclist{gap:20px}
  .svc{gap:11px}
  .svc-body{gap:8px;align-items:center;text-align:center}
  .svc-body .ticks{text-align:left}
  .svc-n{font-size:11px}
  .svc-body h2{font-size:21px}

  /* --- footer: four stacked blocks became three tight lines --- */
  .foot-in{display:block;padding:20px var(--gut) 16px;text-align:center}
  .foot-col{margin-bottom:13px}
  .foot-col:last-child{margin-bottom:0}
  /* the blurb paragraph; phone and email are the 3rd and 4th and stay */
  .foot-col:first-child p:nth-of-type(2){display:none}
  .foot-brand{font-size:15px;margin-bottom:6px}
  .foot-h{display:none}
  .foot-col ul{display:flex;flex-direction:row;flex-wrap:wrap;
    justify-content:center;gap:0 14px}
  .site-foot li a{min-height:24px;font-size:13px}
  .foot-phone{font-size:17px;font-weight:800}
  .site-foot .hours{margin-inline:auto}
  .site-foot .hours th,.site-foot .hours td{font-size:12.5px;padding:0 5px}
  .foot-area{font-size:12.5px;margin-top:5px}
  .foot-bar{padding:9px var(--gut);font-size:11px}

  /* --- contact page --- */
  .contact-head{text-align:center}
  .contact-head .shead{justify-content:center}
  .formcard{padding:15px 14px}
  .quote{gap:9px}
  .quote label{font-size:12px}
  .quote input,.quote textarea{padding:9px 10px}
  .quote textarea{min-height:80px}
  .consent{font-size:12px}
  .infolist li{padding:9px 0}
  .mapwrap{aspect-ratio:16/11}
}

/* ============================================================================
   MOBILE PASS 3 â€” corrections. Still nothing applies at 900px and up.
   ========================================================================== */
@media (max-width:899px){

  /* --- hero photo: back inside the gutter so the rounded corners read --- */
  .hero{padding:18px 0 24px}
  .hero .wrap{padding-inline:var(--gut);gap:16px}
  .hero .stack{padding-inline:0}
  .hero-media{order:-1;margin-bottom:2px}
  .hero-media .slideshow,.hero-media img{border-radius:var(--r-media)}
  .hero-media .slideshow{aspect-ratio:4/3}

  /* --- CTA band: the micro-line was pure noise on a narrow screen --- */
  .microline{display:none}
  .band.tint2 .lead{font-size:13.5px}
  .band.tint2 h2{font-size:clamp(19px,5vw,23px)}

  /* --- why choose us / estimate columns --- */
  .feats{gap:13px}
  .feat{padding-left:13px}
  .feat .big{font-size:25px}
  .feat h3{font-size:15.5px}
  .feat p{font-size:13.5px;line-height:1.48}

  /* --- service rows read wrong centred; put them back left --- */
  .svc-body{align-items:flex-start;text-align:left}
  .svc-body h2{font-size:20px}
  .svc-body .lead{font-size:13.5px}
  .svc-body .btn{align-self:stretch;text-align:center}

  /* --- by the numbers: one row, not a 2x2 block --- */
  .stats{grid-template-columns:repeat(4,1fr);gap:8px}
  .stat b{font-size:clamp(17px,4.6vw,22px)}
  .stat span{font-size:8.5px;letter-spacing:.07em;line-height:1.25}

  /* --- contact details as a tile grid, like the reference --- */
  .infolist{display:grid;grid-template-columns:repeat(2,1fr);gap:0;
    border:1px solid var(--rule);border-radius:var(--r-ctl);overflow:hidden}
  .infolist li{padding:11px 12px;border-bottom:1px solid var(--rule);
    border-right:1px solid var(--rule)}
  .infolist li::before{display:none}
  .infolist li:nth-child(2n){border-right:0}
  .infolist li:nth-last-child(-n+2){border-bottom:0}
  .infolist .k{font-size:9.5px;margin-bottom:2px}
  .infolist .v{font-size:13.5px;line-height:1.4;word-break:break-word}
  .infolist .big{font-size:16px}
  .infolist .hours{font-size:12px}
  .infolist .hours th,.infolist .hours td{padding:0}

  /* --- footer: organised sections like the reference, not one long stack --- */
  .foot-in{display:block;text-align:left;padding:20px var(--gut) 14px}
  .foot-col{margin-bottom:0;padding:12px 0;border-top:1px solid rgba(255,255,255,.11)}
  .foot-col:first-child{border-top:0;padding-top:0}
  .foot-col:first-child p:nth-of-type(2){display:block;font-size:13px;margin-top:4px}
  .foot-h{display:block;font-size:10.5px;margin-bottom:7px;color:#fff}
  .foot-col ul{display:grid;grid-template-columns:repeat(2,1fr);
    gap:1px 14px;justify-content:start}
  .site-foot li a{min-height:25px;font-size:13px}
  .site-foot .hours{margin-inline:0}
  .foot-phone{font-size:19px}
}

/* ---- footer accordions: same checkbox pattern as the nav, so still no JS ---- */
.foot-acc .facc{position:absolute;opacity:0;pointer-events:none}
.foot-acc > ul{max-height:none;overflow:visible}
.foot-acc label.foot-h{display:block;margin-bottom:9px}

/* ============================================================================
   MOBILE PASS 4. Still nothing applies at 900px and up.
   ========================================================================== */
@media (max-width:899px){

  /* --- a lone button should not stretch the full width --- */
  .btnrow .btn:only-child{flex:0 1 auto;padding-inline:20px}
  .btnrow:has(.btn:only-child){justify-content:center}

  /* --- buttons: smaller overall, not just smaller text --- */
  .btn{min-height:42px;padding:10px 12px;font-size:14px}
  .btnrow{gap:8px}

  /* --- breathing room between an intro and the block it introduces --- */
  .band .wrap > .stack:first-child{margin-bottom:8px}
  .feats{gap:15px;margin-top:4px}

  /* --- the CTA band was the last thing still shouting --- */
  .band.tint2 h2{font-size:clamp(18px,4.8vw,22px)}
  .band.tint2 .lead{font-size:13px;line-height:1.5}
  .band.tint2 .stack{gap:9px}
  .band.tint2 .btnrow{margin-top:10px}

  /* --- contact tiles: keep the value inside its box --- */
  .infolist li{padding:10px 11px;min-width:0}
  .infolist .v{font-size:12.5px;line-height:1.35;overflow-wrap:anywhere;hyphens:auto}
  .infolist .big{font-size:15px;letter-spacing:-.01em}
  .infolist .hours{font-size:11px;width:100%}
  .infolist .hours th{text-align:left;white-space:nowrap}
  .infolist .hours td{text-align:right}

  /* --- FAQ --- */
  .faq{margin-top:6px}
  .faq summary{padding:12px 30px 12px 0;font-size:14.5px;min-height:0}
  .faq summary::after{font-size:19px}
  .faq .ans{font-size:13.5px;line-height:1.5;padding-bottom:13px}

  /* --- footer dropdowns --- */
  .foot-acc > ul{max-height:0;overflow:hidden;transition:max-height .3s ease}
  .foot-acc .facc:checked ~ ul{max-height:420px}
  .foot-acc label.foot-h{display:flex;align-items:center;justify-content:space-between;
    min-height:42px;margin:0;cursor:pointer;font-size:12px}
  .foot-acc label.foot-h::after{content:"+";font-size:17px;font-weight:400;
    color:#fff;line-height:1}
  .foot-acc .facc:checked ~ label.foot-h::after{content:"\2013"}
  .foot-acc{padding:0;border-top:1px solid rgba(255,255,255,.11)}
  .foot-acc > ul{grid-template-columns:1fr;padding-bottom:8px}
  .foot-acc .facc:checked ~ ul{padding-bottom:10px}
}

/* one line: prompt on the left, hours pushed to the right corner */
.formnote{display:flex;align-items:baseline;justify-content:space-between;
  gap:8px 14px;flex-wrap:wrap}
.formnote .fn-hrs{margin-left:auto;white-space:nowrap;color:var(--ink-60)}

/* ============================================================================
   MOBILE PASS 5. Still nothing applies at 900px and up.
   ========================================================================== */
@media (max-width:899px){

  /* --- body copy down another step across the board --- */
  .hero .lead{font-size:13.5px;line-height:1.5}
  .pcard p{font-size:13px;line-height:1.45}
  .pcard h3{font-size:17px}
  .pcard .go{font-size:11px}
  .card p{font-size:13.5px}

  /* --- CTA band: smallest it has been --- */
  .band.tint2{padding:24px 0}
  .band.tint2 h2{font-size:clamp(17px,4.4vw,20px)}
  .band.tint2 .lead{font-size:12.5px;line-height:1.45;max-width:34ch}

  /* --- buttons: never full-bleed unless they are the form submit --- */
  .svc-body .btn{align-self:auto;width:auto}
  .btn{min-height:40px;padding:9px 14px;font-size:13.5px;letter-spacing:-.005em}
  .btn.wide{width:100%;min-height:44px}

  /* --- process: separate the intro from step 01 --- */
  .flow{margin-top:10px}

  /* --- about: centre the body copy so it matches the centred heading --- */
  .band .wrap.narrow.stack > .lead,
  .band .wrap.narrow.stack > p{text-align:center;margin-inline:auto}

  /* --- contact page --- */
  .contact-head h1{font-size:clamp(21px,5.4vw,25px);margin-bottom:7px}
  .contact-head .lead{font-size:13px}
  .contact-head{margin-bottom:14px}
  .consent{font-size:11.5px;line-height:1.45;gap:9px}
  .consent input[type="checkbox"]{width:17px;height:17px;min-width:17px}
  .formnote{font-size:12px;line-height:1.45}

  /* --- footer: nothing peeking out of a closed dropdown --- */
  .foot-acc > ul{padding-bottom:0}
  .foot-acc .facc:checked ~ ul{padding-bottom:10px}
  .foot-in{text-align:left}
  .foot-col:first-child{text-align:left}
  .foot-area{font-size:12.5px;margin-top:4px;color:#8FA1B0}
  .foot-col:last-child .hours{width:100%}
  .foot-col:last-child .hours th{text-align:left;white-space:nowrap}
  .foot-col:last-child .hours td{text-align:right}
  .foot-bar{text-align:center}
}

/* ---- location pin before the footer address ---- */
.foot-area{display:flex;align-items:flex-start;gap:7px}
.foot-area svg{width:14px;height:14px;flex:none;fill:var(--blue-lt);margin-top:2px}

/* ---- hero: deep blue rather than the same charcoal as the header ----------
   The header is --dark #23282E. The hero used the identical value, so the two
   read as one slab. This runs --blue-deep into --dark, which separates them,
   adds depth, and stays entirely inside the locked palette. */
/* ---- header: the shop's own craft, rendered in CSS -----------------------
   Deep blue running to charcoal, a faint diamond-quilt tufting pattern, and a
   stitched seam as the divider instead of a plain rule. Every value is from the
   locked palette; no images, no extra requests. To drop it, delete ::before and
   ::after and set .site-head{background:var(--dark)}.

   Do NOT add `position:relative` here. This rule sits after the sticky-header
   declaration above and has the same specificity, so `relative` silently wins
   and the header stops sticking â€” which is exactly what happened when this
   block first shipped. The ::before and ::after below do not need it: the
   `position:sticky` set earlier already establishes a containing block for
   absolutely-positioned children. */
.site-head{
  background:linear-gradient(168deg,#16344F 0%,#1B3A52 55%,#23282E 100%)}
/* diamond quilt â€” deliberately near-invisible; it should register as texture,
   not as a pattern you can name */
.site-head::before{content:"";position:absolute;inset:0;pointer-events:none;
  background-image:
    repeating-linear-gradient(45deg,rgba(255,255,255,.030) 0 1px,transparent 1px 27px),
    repeating-linear-gradient(-45deg,rgba(255,255,255,.030) 0 1px,transparent 1px 27px)}
/* stitched seam */
.site-head::after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;
  pointer-events:none;
  background:repeating-linear-gradient(90deg,
    var(--blue-lt) 0 13px,rgba(94,155,217,.20) 13px 22px)}
.head-in{position:relative;z-index:1}

/* Every large dark surface gets the same quilting on a larger diamond, because
   these cover far more area than the header bar. Enough to stop the panels
   reading as flat, not enough to notice as a pattern.
   To undo, delete this block and the three position:relative rules.

   .016 is the MOBILE value and it is deliberate — do not raise it here. The
   desktop bump lives in the "quilt visibility, desktop only" block at the very
   end of this file. Phones were reported as fine; only the desktop grid was
   too faint to see. */
.hero{background:var(--dark)}
.hero,.band.dark,.site-foot{position:relative}
.hero::before,.band.dark::before,.site-foot::before{
  content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  background-image:
    repeating-linear-gradient(45deg,rgba(255,255,255,.016) 0 1px,transparent 1px 36px),
    repeating-linear-gradient(-45deg,rgba(255,255,255,.016) 0 1px,transparent 1px 36px)}
/* keep content above the overlay so it never intercepts a tap */
.hero > *,.band.dark > *,.site-foot > *{position:relative;z-index:1}

/* ---- service page shots: masonry on mobile, grid on desktop ----------------
   Desktop has the room for a clean 3-up grid; mobile does not, so it keeps the
   compact masonry. Both keep click-to-enlarge. */
@media (min-width:900px){
  .svc-shots{columns:auto;display:grid;grid-template-columns:repeat(3,1fr);
    gap:clamp(18px,2.4vw,30px)}
  .svc-shots figure{margin:0;break-inside:auto}
  .svc-shots figure img{aspect-ratio:4/3;object-fit:cover;width:100%}
}

/* ---- render performance ----------------------------------------------------
   Skip layout and paint for bands that are still off-screen. contain-intrinsic-size
   keeps the scrollbar honest so nothing jumps as they come into view. The call bar
   and the lightbox both sit outside .band, so neither is affected by the
   containment this introduces. */
.band{content-visibility:auto;contain-intrinsic-size:auto 640px}
/* the marquee animates forever; hint the compositor and stop it off-screen */
.revtrack{will-change:transform}
.revmarquee{contain:paint}

/* ---- photos a reviewer attached to their own Google review ---------------
   Sits inside the review card, under the quote. Fixed square tiles with
   object-fit:cover so two portrait phone photos and two landscape ones both
   read as a deliberate pair rather than a ragged pasted-in row â€” the cards sit
   side by side in a marquee, so uneven photo heights would stagger the whole
   band. Renders nothing unless a review actually carries photos. */
.rev-shots{display:grid;gap:8px;margin-top:14px;
  grid-template-columns:repeat(auto-fit,minmax(0,1fr))}
.rev-shots[data-n="1"]{grid-template-columns:minmax(0,62%)}
.rev-shots a{display:block;border-radius:var(--r-ctl);overflow:hidden;
  aspect-ratio:1/1;background:rgba(255,255,255,.06)}
.rev-shots img{width:100%;height:100%;object-fit:cover;display:block;
  border-radius:0;transition:transform .4s ease}
.rev-shots a:hover img{transform:scale(1.05)}
@media (max-width:899px){.rev-shots{gap:6px;margin-top:11px}}

/* ============================================================================
   SERVICES RESTRUCTURE (2026-08-07) â€” the photoless treatments.

   Three services (marine, aviation, motorcycle) and one more (sunroof shades)
   have no photograph this shop can honestly claim. Every rule below exists so
   that absence reads as a design decision rather than a broken image slot.
   Nothing here says "photos coming soon", and every one of these becomes an
   ordinary photo component again by deleting one class.
   ========================================================================== */

/* The photoless bento tile that lived here is gone: the sunroof card carries a
   real photograph as of 2026-08-07. */

/* ---- "We also work on": a row of photographs, NOT links -----------------
   No anchor, no hover lift, no lightbox and no cursor change: these tiles are
   there to show the range of the shop, and a tile that looks clickable but is
   not is worse than one that never suggested it. The three pages are still
   reachable from the footer. */
/* A FANNED DECK, CENTRED. Photo prints with white mounts, overlapping along a
   shallow arc — the cards toward each end sit lower and lean further, so the row
   curves. Every card is the same markup; the arc comes from nth-child transforms
   alone, so adding or removing a photo cannot break the layout.

   Centred, like every other band on the site. `justify-content:center` on a flex
   row plus negative margins between the cards is what makes the deck sit in the
   middle of the page however many cards it holds. */
.also{display:flex;justify-content:center;align-items:center;flex-wrap:nowrap;
  padding:clamp(12px,3vw,34px) 0 clamp(20px,4vw,44px)}
.also-col{margin:0;flex:0 0 auto;width:clamp(96px,15vw,208px);
  background:var(--white);padding:7px 7px 9px;border-radius:12px;
  box-shadow:0 14px 30px rgba(22,52,79,.18);
  transform-origin:center bottom;
  animation:alsofloat 10s ease-in-out infinite}
/* overlap: each card slides back over its neighbour */
.also-col + .also-col{margin-left:clamp(-46px,-4vw,-14px)}
/* the arc — outer cards drop and lean, the middle card sits highest and flattest */
.also-col:nth-child(1){transform:rotate(-9deg) translateY(20px);z-index:1}
.also-col:nth-child(2){transform:rotate(-6deg) translateY(9px);z-index:2;animation-delay:-1.4s}
.also-col:nth-child(3){transform:rotate(-2.5deg) translateY(1px);z-index:3;animation-delay:-2.8s}
.also-col:nth-child(4){transform:rotate(1deg) translateY(-2px);z-index:4;animation-delay:-4.2s}
.also-col:nth-child(5){transform:rotate(4.5deg) translateY(6px);z-index:5;animation-delay:-5.6s}
.also-col:nth-child(6){transform:rotate(8deg) translateY(18px);z-index:6;animation-delay:-7s}
.also-col:nth-child(7){transform:rotate(11deg) translateY(34px);z-index:7;animation-delay:-8.4s}
/* FIVE-CARD DECK. The arc above is tuned for six or seven; stop it at five and
   it ends on rotate(4.5deg) while the left edge is still at -9deg, so the whole
   fan visibly leans left. This retunes those five into a symmetric arc. It is
   scoped with :has so it only fires when the deck really is five cards long —
   add a sixth back to ALSO and the original arc takes over again untouched. */
.also:has(> .also-col:nth-child(5):last-child) .also-col:nth-child(1){transform:rotate(-9deg) translateY(20px)}
.also:has(> .also-col:nth-child(5):last-child) .also-col:nth-child(2){transform:rotate(-5deg) translateY(6px)}
.also:has(> .also-col:nth-child(5):last-child) .also-col:nth-child(3){transform:rotate(0deg) translateY(-2px)}
.also:has(> .also-col:nth-child(5):last-child) .also-col:nth-child(4){transform:rotate(5deg) translateY(6px)}
.also:has(> .also-col:nth-child(5):last-child) .also-col:nth-child(5){transform:rotate(9deg) translateY(20px)}
/* the drift is deliberately tiny — the deck should breathe, not move around the
   page while someone is trying to look at it */
@keyframes alsofloat{
  0%,100%{translate:0 0}
  50%{translate:0 -6px}
}
.also-col img{width:100%;aspect-ratio:3/4;object-fit:cover;border-radius:7px}
/* the deck is the message; per-card captions would fight the overlap */
.also-col figcaption{display:none}
.also-cat{font-size:11px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;
  color:var(--blue)}
@media (max-width:640px){
  .also-col{padding:4px 4px 6px;border-radius:8px;box-shadow:0 8px 18px rgba(22,52,79,.2)}
  .also-col img{border-radius:5px}
}
@media (prefers-reduced-motion:reduce){.also-col{animation:none}}

/* ---- before / after / during sequence ----------------------------------
   Unlike the masonry, these ARE cropped to one ratio. Three portrait photos at
   their natural heights read as three unrelated pictures; a common ratio is
   what makes the eye compare them, which is the entire point of the band. */
.ba{display:grid;gap:14px;grid-template-columns:1fr}
@media (min-width:700px){.ba{grid-template-columns:repeat(3,1fr);gap:clamp(14px,2vw,22px)}}
.ba figure{margin:0;position:relative;overflow:hidden;border-radius:var(--r-media);
  background:#EDF1F5}
.ba figure img{width:100%;height:100%;aspect-ratio:3/4;object-fit:cover;border-radius:0;
  transition:transform .5s ease}
.ba figure:hover img{transform:scale(1.04)}
.ba figcaption{position:absolute;left:0;right:0;bottom:0;padding:30px 13px 12px;
  font-size:12.5px;font-weight:600;letter-spacing:.02em;color:#fff;line-height:1.45;
  background:linear-gradient(to top,rgba(20,25,31,.90),rgba(20,25,31,.58) 58%,rgba(20,25,31,0))}
/* the stage chip is the label doing the work â€” BEFORE / STRIPPED / AFTER */
.ba-stage{position:absolute;top:12px;left:12px;z-index:2;padding:6px 11px;
  font-size:10.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase;
  color:#fff;background:rgba(20,25,31,.72);border-radius:var(--r-ctl)}
@media (max-width:699px){
  .ba figure img{aspect-ratio:4/3}
  .ba figcaption{padding:24px 11px 10px;font-size:11.5px}
}

/* ---- the reply-time promise, directly under the submit button ----------
   Sits between the button and .formnote. Deliberately heavier than .formnote:
   it answers the question every person hesitating over a submit button is
   actually asking, which is "and then what happens". The .quote flexbox already
   supplies the gap, so this only needs the negative top margin to sit close to
   the button it belongs to rather than floating between two notes. */
.replynote{display:flex;align-items:flex-start;gap:9px;margin-top:-4px;
  font-size:13.5px;font-weight:600;line-height:1.5;color:var(--ink-70)}
.replynote svg{flex:none;width:17px;height:17px;margin-top:1px;fill:var(--blue)}
@media (max-width:899px){.replynote{font-size:12.5px;line-height:1.45}}

/* ---- before / after pairs ----------------------------------------------
   Same photo-print treatment as the deck above, but a straight grid: a fan
   overlaps its neighbours, and you cannot overlap two photographs you are
   asking someone to compare. Two across on a phone, four on a desktop. */
.pairs{display:grid;grid-template-columns:1fr;gap:clamp(12px,2vw,22px);
  padding-top:clamp(14px,2.5vw,26px)}
@media (min-width:760px){.pairs{grid-template-columns:repeat(2,1fr)}}
.pair{margin:0;display:flex;flex-direction:column;gap:7px;
  background:var(--white);padding:8px 8px 10px;border-radius:14px;
  box-shadow:0 10px 26px rgba(22,52,79,.13)}
/* the two shots butt together as one image, split by a hairline */
.pair-shots{position:relative;display:grid;grid-template-columns:1fr 1fr;gap:3px;
  border-radius:9px;overflow:hidden;background:var(--rule)}
.pair-shot{position:relative;display:block;min-width:0}
.pair-shot img{width:100%;aspect-ratio:1/1;object-fit:cover;border-radius:0}
.pair-tag{position:absolute;top:7px;left:7px;z-index:2;padding:4px 8px;
  font-size:9.5px;font-weight:800;letter-spacing:.13em;text-transform:uppercase;
  color:#fff;background:rgba(20,25,31,.74);border-radius:5px}
.pair-tag.after{background:var(--blue-btn)}
/* the arrow sits on the join, so the eye travels left to right across it */
.pair-arrow{position:absolute;left:50%;top:50%;translate:-50% -50%;z-index:3;
  width:30px;height:30px;display:grid;place-items:center;border-radius:50%;
  background:var(--white);color:var(--blue-btn);font-size:15px;font-weight:800;
  box-shadow:0 3px 10px rgba(22,52,79,.28)}
.pair figcaption{padding:1px 4px 0;text-align:center;font-size:13px;font-weight:700;
  letter-spacing:.02em;color:var(--ink-70)}

/* ---- the animation ------------------------------------------------------
   Three things, all slow, all CSS, none of them moving the layout:

   1. the cards deal themselves in, staggered, once on load
   2. the AFTER photo breathes — a 4% zoom over 7s. Only the after side moves,
      so the eye is pulled from left to right across the join without anything
      being labelled twice
   3. the arrow on the join pulses in time with it

   Zoom lives on the img inside an overflow:hidden parent, so nothing reflows and
   nothing spills. Hover lifts the whole card and pushes the zoom a little
   further, which is the only part that is not automatic. */
.pair{animation:pairin .55s cubic-bezier(.22,.61,.36,1) both;
  transition:transform .3s ease,box-shadow .3s ease}
.pairs > .pair:nth-child(2){animation-delay:.09s}
.pairs > .pair:nth-child(3){animation-delay:.18s}
.pairs > .pair:nth-child(4){animation-delay:.27s}
.pairs > .pair:nth-child(5){animation-delay:.36s}
@keyframes pairin{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.pair:hover{transform:translateY(-4px);box-shadow:0 18px 36px rgba(22,52,79,.2)}

.pair-shot img{transition:transform .45s ease}
/* the after side only */
.pair-shot:nth-child(2) img{animation:afterbreathe 7s ease-in-out infinite}
.pairs > .pair:nth-child(2) .pair-shot:nth-child(2) img{animation-delay:-1.75s}
.pairs > .pair:nth-child(3) .pair-shot:nth-child(2) img{animation-delay:-3.5s}
.pairs > .pair:nth-child(4) .pair-shot:nth-child(2) img{animation-delay:-5.25s}
@keyframes afterbreathe{0%,100%{transform:scale(1)}50%{transform:scale(1.04)}}
.pair:hover .pair-shot:nth-child(2) img{transform:scale(1.06)}

.pair-arrow{animation:arrownudge 7s ease-in-out infinite}
@keyframes arrownudge{
  0%,100%{transform:translateX(0);box-shadow:0 3px 10px rgba(22,52,79,.28)}
  50%{transform:translateX(3px);box-shadow:0 5px 16px rgba(30,92,153,.42)}
}
@media (prefers-reduced-motion:reduce){
  .pair,.pair-shot img,.pair-arrow{animation:none}
}
@media (max-width:560px){
  .pair{padding:5px 5px 7px;border-radius:10px;gap:5px}
  .pair-shots{gap:2px;border-radius:7px}
  .pair-tag{font-size:8px;padding:3px 6px;letter-spacing:.08em;top:5px;left:5px}
  .pair-arrow{width:24px;height:24px;font-size:12px}
  .pair figcaption{font-size:11.5px}
}

/* ---- footer social row --------------------------------------------------
   One row under the address, sized to the 44px touch target on a phone. The
   icons inherit currentColor, so they take the footer's text colour and need no
   second set of assets if the footer ever changes background. */
/* SELECTORS ARE `.foot-col ul.socials`, not `.socials`, ON PURPOSE. The footer
   already styles `.foot-col ul` at three different widths — column, then wrapped
   row, then a two-column grid — and those rules are more specific than a lone
   class, which is what was throwing these icons around. Matching that
   specificity is what keeps them on one line everywhere. */
.foot-col ul.socials{list-style:none;display:flex;flex-direction:row;flex-wrap:nowrap;
  justify-content:flex-start;align-items:center;gap:8px;margin:14px 0 0;padding:0}
.foot-col ul.socials li{flex:0 0 auto}
.foot-col ul.socials a{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;min-height:36px;padding:0;border-radius:9px;
  background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.16);
  color:#E9EEF3;transition:background .2s ease,border-color .2s ease,transform .2s ease}
.foot-col ul.socials svg{width:17px;height:17px;fill:currentColor}
.foot-col ul.socials a:hover{background:var(--blue-btn);border-color:var(--blue-btn);
  color:#fff;transform:translateY(-2px)}
@media (max-width:899px){
  /* Left, not centred. The footer centres its text on a phone, but a row of
     four icon buttons floating in the middle of the column read as unmoored —
     against the left edge they line up with everything above them. */
  .foot-col ul.socials{justify-content:flex-start;gap:10px;margin-top:12px}
  .foot-col ul.socials a{width:40px;height:40px;min-height:40px;border-radius:10px}
  .foot-col ul.socials svg{width:18px;height:18px}
}
/* WHERE the row sits: under Hours once the footer is four columns wide, under
   the address while it is a single centred stack. Both copies are in the HTML
   and one is hidden per width — see footer() for why. */
.foot-col ul.socials.sc-desk{display:none}
@media (min-width:1000px){
  .foot-col ul.socials.sc-desk{display:flex;margin-top:16px}
  .foot-col ul.socials.sc-mob{display:none}
}

/* ---- careers: how to apply --------------------------------------------- */
.applyrow{display:grid;grid-template-columns:1fr;gap:12px;
  padding-top:clamp(14px,2.5vw,24px)}
@media (min-width:720px){.applyrow{grid-template-columns:repeat(3,1fr)}}
.applycard{display:flex;flex-direction:column;align-items:center;gap:5px;
  text-align:center;background:var(--white);border:1px solid var(--rule);
  border-radius:var(--r-card);padding:18px 16px}
.applycard .k{font-size:10.5px;font-weight:700;letter-spacing:.15em;
  text-transform:uppercase;color:var(--blue)}
/* the email address must sit on ONE line at every width — it is 27 characters,
   so it is sized to fit the card rather than allowed to break mid-word */
.applycard a{text-decoration:none;font-weight:700;max-width:100%;
  white-space:nowrap;overflow-wrap:normal;font-size:clamp(12.5px,2.6vw,15px)}
.applycard .big{font-size:clamp(19px,2.2vw,23px);letter-spacing:-.02em;white-space:nowrap}
.applycard .hrs{font-size:13px;color:var(--ink-60)}

/* ---- blog card with no photo ------------------------------------------- */
.card.nophoto{border-top:3px solid var(--blue-lt)}
.card.nophoto .card-body{padding-top:24px}

/* ---- LOGO TRIAL: header and footer marks --------------------------------
   Sized by height so the lockup stays put whatever the artwork's aspect ratio.
   width:auto lets the intrinsic ratio drive the width, and max-width stops a
   wide mark shoving the nav off the header on a narrow phone.
   TO REVERT: delete this block. */
/* background:none is REQUIRED. The global img rule sets background:#EDF1F5 as a
   loading placeholder so photos do not flash empty. The logo is transparent, so
   that placeholder shows straight through it as a pale box on the dark header. */
.brand img,.foot-brand img{background:none}
/* drop-shadow, not box-shadow: it follows the artwork's alpha outline rather
   than drawing a rectangle, so it separates the white linework from the header's
   quilted gradient without putting a plate behind the logo. Kept dark and tight
   â€” a light shadow would halo, which is the problem we just removed. */
.brand img{height:82px;width:auto;max-width:62vw;display:block;
  filter:drop-shadow(0 1px 2px rgba(0,0,0,.55))}
@media (max-width:899px){.brand img{height:66px}}
@media (max-width:380px){.brand img{height:58px}}

/* TRIAL 2 — mobile: logo left, phone button beside it, no sticky bottom bar.
   The call button was desktop-only and the phone lived in the fixed .callbar at
   the foot of the screen. This moves it up into the header next to the logo and
   removes the bottom bar entirely.

   Explicit `order` is required. In DOM order the header is brand, burger, nav,
   head-call — and .nav has flex-basis:100%, so without ordering the nav would
   wrap to row two and push the call button down to row three. Ordering puts
   brand / call / burger on row one and leaves the nav on its own row.

   The footer's bottom padding also has to come back down: it existed purely to
   stop the fixed call bar covering the last line, and there is no call bar now.

   Desktop is untouched — this is all below the 1000px breakpoint. */
@media (max-width:999px){
  .head-call{display:inline-block;order:2;padding:9px 13px;font-size:13.5px;
    border-radius:var(--r-ctl);margin-left:10px}
  .burger{order:3}
  .nav{order:4}
  .callbar{display:none}
  .site-foot{padding-bottom:clamp(24px,5vw,40px)}
}
@media (max-width:400px){
  .head-call{padding:8px 10px;font-size:12.5px;margin-left:6px}
  .brand img{height:48px}
}
.foot-brand img{height:110px;width:auto;max-width:100%;display:block;margin-bottom:2px}
@media (max-width:899px){.foot-brand img{height:92px}}

/* ============ TRIAL: white header ========================================
   One idea, not four. The previous version layered an inverted quilt, a dashed
   patch inset, a double topstitch seam and a drop shadow all at once, and it
   read as noise.

   What is left is the only element that was doing real work: the badge artwork
   is cream, so on plain white it disappears. A plain dark patch behind it fixes
   that and nothing else competes with it.

   Deliberately NOT here: the quilt texture, the dashed stitching on the patch,
   the double seam, the patch shadow.

   TO REVERT: delete this whole block. Everything is scoped to .site-head. */
.site-head{background:#fff;color:var(--ink)}

/* quilt back, inverted — faint blue on white instead of white on dark.
   .05 is the MOBILE value — leave it. The desktop bump is in the "quilt
   visibility, desktop only" block at the very end of this file. */
.site-head::before{
  background-image:
    repeating-linear-gradient(45deg,rgba(47,111,176,.05) 0 1px,transparent 1px 27px),
    repeating-linear-gradient(-45deg,rgba(47,111,176,.05) 0 1px,transparent 1px 27px)}
.site-head::after{height:1px;background:var(--rule)}

/* badge + wordmark side by side. The base .brand is a column (it used to stack
   the name over a strapline); this puts them on one row. */
.brand{flex-direction:row;align-items:center;gap:11px;
  background:none;padding:0}
/* The badge carries the shop name inside the artwork, so a text wordmark beside
   it said the same thing twice. Hidden at every width — desktop and mobile. */
.brand-name{display:none}
.brand-name em{color:var(--blue)}
.brand img{filter:none}

.nav a{color:var(--ink-70);border-bottom-color:var(--rule)}
.nav a:hover,.nav a.on{color:var(--ink)}
.nav a.on::before{background:var(--blue)}
.burger span{background:var(--ink)}
@media (min-width:1000px){
  .nav a.on{box-shadow:inset 0 -2px 0 var(--blue)}
  /* Whole header centred as one group. No auto margins at all — an auto margin
     shoves everything to one side, which is why this kept ending up hard left
     with a hole on the right. justify-content:center balances the slack evenly:
              badge   Home Services Gallery ...   ☎ (980) 385-8101              */
  .head-in{justify-content:center;padding-top:9px;padding-bottom:9px}
  .brand{margin-right:34px}
  .nav{margin-right:0}
  .nav ul{gap:26px}

  /* Solid blue button, as it was. The outlined version was tried and rejected. */
  .head-call{margin-left:28px;margin-right:0}
  .hc-ic,.hc-sub{display:none}
}

/* Mobile call button: a solid blue block is too loud beside the badge and the
   wordmark on a white bar. Tinted fill, blue text, so it still reads as the
   action without shouting over the brand. */
@media (max-width:999px){
  /* Glyph + number on ONE line, in a pill that hugs the text.
     It was stretching because it was display:flex with a wrapping second line —
     the box then sized to that content block rather than to the number.
     inline-flex + nowrap + flex:0 0 auto is what makes it wrap the number only.
     "Free estimate" is dropped here at the user's request. */
  .head-call{background:rgba(47,111,176,.10);color:var(--blue);
    box-shadow:inset 0 0 0 1px rgba(47,111,176,.28);
    display:inline-flex;align-items:center;gap:5px;flex:0 0 auto;
    padding:7px 11px;margin-left:8px;line-height:1;white-space:nowrap}
  .head-call:hover{background:rgba(47,111,176,.16)}
  .hc-ic{display:inline;font-size:11.5px;line-height:1}
  .hc-num{font-size:13px;font-weight:800;letter-spacing:-.02em}
  .hc-sub{display:none}
  .brand{gap:0;flex-shrink:0}
  .brand img{height:62px}
  .burger{flex-shrink:0}
}
@media (max-width:380px){
  .head-call{padding:6px 9px;margin-left:6px;gap:4px}
  .hc-num{font-size:12px}
  .brand img{height:54px}
}
/* ==================== end white header TRIAL ============================= */

/* ---- comparison tables in articles --------------------------------------
   Wide spec tables scroll inside their OWN container. The page body must never
   scroll sideways, and overflow must never go on html/body â€” at viewport level
   that breaks position:fixed on iOS and strands the sticky call bar. */
.tablewrap{overflow-x:auto;margin:1.5em 0;
  border:1px solid var(--rule);border-radius:var(--r-card)}
.spectable{width:100%;border-collapse:collapse;font-size:15px;min-width:520px}
.spectable th,.spectable td{text-align:left;padding:11px 14px;
  border-bottom:1px solid var(--rule);vertical-align:top}
.spectable thead th{background:var(--tint);font-weight:800;font-size:13px;
  letter-spacing:.04em;text-transform:uppercase;color:var(--blue-deep);
  white-space:nowrap}
.spectable tbody tr:last-child th,.spectable tbody tr:last-child td{border-bottom:0}
.spectable tbody th{font-weight:700;white-space:nowrap}
.spectable .yes{color:var(--blue);font-weight:700}
@media (max-width:899px){.spectable{font-size:14px}
  .spectable th,.spectable td{padding:9px 11px}}

/* ================= TRIAL: stitched mobile call bar =======================
   The sticky "Call ... Â· Free Estimate" bar, given the same craft treatment the
   header already carries. Mobile only â€” .callbar is display:none from 1000px up,
   so nothing on desktop is touched.

   Two parts, both from the locked palette, no images:
   1. a stitched seam along the TOP edge, using the exact same repeating gradient
      as .site-head::after â€” so the header is seamed at its bottom edge and the
      call bar at its top, and the page reads as one trimmed panel.
   2. a faint dashed topstitch set in from the edge.

   The topstitch deliberately stops above env(safe-area-inset-bottom): on a
   notched iPhone the bar extends into the home-indicator area, and stitching
   drawn through that strip looks like a rendering fault rather than a detail.

   TO REVERT: delete this entire block. Nothing else references it. */
/* No stitch lines here â€” just the diamond quilt, the same device the header and
   the dark bands already carry.

   Applied as a background-image on .callbar itself rather than as a pseudo
   element. A ::before with inset:0 paints above the anchor's text, and the bar's
   label is a bare text node that cannot be lifted back with z-index. A
   background layer always sits under content, so this cannot ever wash over the
   phone number.

   Geometry now matches the header exactly â€” 27px diamond â€” so the top and
   bottom of the page read as the same treatment rather than two similar ones.

   Opacity is LOWER than the header's .030, not higher. The header sits on a
   near-charcoal gradient; this bar sits on the much brighter button blue, where
   the same white line reads considerably stronger. Matching the header's number
   would look heavier than the header. .020 is what actually matches it by eye.

   The top edge is softened too: the old shadow was a hard dark line that drew
   the eye to the bar's edge instead of to the phone number.

   TO REVERT: delete this rule. */
.callbar{
  background-image:
    repeating-linear-gradient(45deg,rgba(255,255,255,.020) 0 1px,transparent 1px 27px),
    repeating-linear-gradient(-45deg,rgba(255,255,255,.020) 0 1px,transparent 1px 27px);
  box-shadow:0 -10px 26px rgba(0,0,0,.13)}
/* ========================= end TRIAL block ============================== */

/* ============ quilt visibility, DESKTOP ONLY ==============================
   Added 2026-08-09. The user reported the background grid was barely visible
   on a desktop monitor and asked for it back up; phones were explicitly fine,
   so every value here is inside min-width:900px and mobile is untouched.

   Why it looked reduced, since this will come up again: it was not. The dark
   surfaces have carried .016 since 6455f06 and were never lowered, and the
   header only went .055 -> .05. What changed is that the HEADER WENT FROM DARK
   TO WHITE, and the same motif reads far weaker as 5% blue on #fff than as 3%
   white on the old blue-charcoal gradient. So this compensates for the
   surface, not for a cut. Do not "restore" the base values to fix a desktop
   complaint - change these two.

   MUST STAY LAST IN THE FILE. The white-header TRIAL block above re-declares
   .site-head::before at the same specificity, so an earlier rule would lose.

   CURRENT STATE, after two rounds of the user looking at it on a monitor:
     header        .05   BASE, not overridden - a louder header was rejected
     dark surfaces .016  BASE, not overridden - footer and ordinary dark bands
     reviews band  .030  override below, explicitly kept
     hero          .022  override below
   The 27px and 36px diamonds never change. Only ever move the alpha, and keep
   the pair inside a rule equal or the two diagonals stop matching. */
@media (min-width:900px){
  /* REVERTED 2026-08-09, same day it went in. The user looked at the louder
     grid on desktop and did not like it, so the header and the general dark
     surfaces are back on their original .05 / .016. Mobile never moved in
     either direction and still does not. Two exceptions follow. */

  /* Reviews marquee only. `.band.dark.reviews` is emitted by reviews_block() in
     build_pages.py; every other dark band keeps the base .016. Specificity is
     0,3,0 against the base rule's 0,2,0, so this wins without !important. */
  .band.dark.reviews::before{
    background-image:
      repeating-linear-gradient(45deg,rgba(255,255,255,.030) 0 1px,transparent 1px 36px),
      repeating-linear-gradient(-45deg,rgba(255,255,255,.030) 0 1px,transparent 1px 36px)}

  /* Hero only. The user still found the hero grid hard to see on desktop and
     asked for "a little bit, nothing crazy".

     .022, NOT .030 — deliberately short of the reviews band. The hero was at
     .030 in 64ed559, the user saw exactly that and rejected it, so matching the
     reviews value here would walk straight back into the thing that was turned
     down. .022 is about a third of the way up from .016 rather than doubling
     it. If it is still too faint, .025 next; do not jump to .030.

     Hero only means hero only: .site-foot and ordinary .band.dark stay at base.
     Same specificity as the base rule, so this must stay after it in the file. */
  .hero::before{
    background-image:
      repeating-linear-gradient(45deg,rgba(255,255,255,.022) 0 1px,transparent 1px 36px),
      repeating-linear-gradient(-45deg,rgba(255,255,255,.022) 0 1px,transparent 1px 36px)}
}

/* The trust strip that briefly lived here (a four-cell proof bar, then four
   photo tiles under the home hero) was REMOVED on the user's instruction the
   same day it went in. Both versions are in git if it is ever wanted back:
   64ed559 for the flat bar, 1d9358f for the photo tiles.

   --star-gold stays in :root. It is not an orphan — `.stars` uses it for the
   review marquee, and tokenising that literal was a correctness fix worth
   keeping regardless of this strip. */

/* ================= SPLIT CALL / TEXT BAR + contact text link ==============
   Added 2026-08-09. The shop's number receives picture messages, and the whole
   site asks people to "send a photo of the job" - but the only route was an
   eight-field form. On a phone, next to the car, a text is a few seconds.

   `.callbar` keeps every base rule above: fixed position, z-index, the
   hide-from-1000px rule, safe-area padding, and the .site-foot clearance that
   depends on its height. `.split` changes ONLY the internal layout, so nothing
   here has to re-derive any of that.

   Call is the wider half deliberately - it is the one conversion Google can
   track, so it keeps the emphasis.

   TO REVERT: delete this block and the callbar markup in build_site.footer().
   ======================================================================== */
.callbar.split{gap:0;padding:0;padding-bottom:env(safe-area-inset-bottom);
  justify-content:stretch}
.callbar.split .cb{flex:1;display:flex;align-items:center;justify-content:center;
  gap:8px;min-height:46px;padding:7px 10px;color:#fff;text-decoration:none;
  font-weight:700;font-size:15px;letter-spacing:-.01em}
.callbar.split .cb-call{flex:1.32;background:var(--blue-btn)}
.callbar.split .cb-text{background:#16344F;box-shadow:inset 1px 0 0 rgba(255,255,255,.17)}
.callbar.split .cb:active{filter:brightness(1.14)}
@media (max-width:359px){
  .callbar.split .cb{font-size:13.5px;gap:6px}
}

/* contact page: the text option sits under the number it shares */
.textlink{display:inline-block;margin-top:7px;font-size:14.5px;font-weight:700;
  color:var(--blue);text-decoration:none}
.textlink:hover{text-decoration:underline}
