/* =====================================================================
   ShowerDoorKing — 2026 site system
   Palette + type per the SDK 2026 Brand Guide.
   Garet → Outfit  ·  Garamond → EB Garamond  (nearest web-licensed match)
   ===================================================================== */

:root{
  /* --- brand --- */
  --navy:#22405d;
  --navy-900:#12233a;
  --navy-800:#1a3149;
  --navy-700:#22405d;
  --navy-600:#2d5175;
  --gold:#eab76d;
  --gold-100:#f6e0bd;
  --gold-600:#c8934a;
  --gold-700:#a1701f;
  --glass:#ddebe8;
  --tile:#f8f7f3;
  --stone:#dbd7cd;
  --azure:#82a6c9;
  --azure-light:#a6c0d9;   /* --azure, lifted to read as text over a photograph */

  /* --- derived neutrals (navy-biased, never pure grey) --- */
  --ink:#16293c;
  --ink-soft:#3d566d;
  --mute:#5c7285;
  --mute-light:#93a8b8;
  --line:rgba(34,64,93,.14);
  --line-dark:rgba(255,255,255,.13);

  /* --- type --- */
  --serif:'EB Garamond',Garamond,Georgia,'Times New Roman',serif;
  --script:'Mrs Saint Delafield',cursive;
  --sans:'Outfit','Helvetica Neue',-apple-system,BlinkMacSystemFont,Arial,sans-serif;

  --t-display:clamp(44px,5.6vw,84px);
  --t-h1:clamp(36px,5.4vw,78px);
  --t-h2:clamp(28px,3.9vw,54px);
  --t-h3:clamp(21px,1.9vw,28px);
  --t-lede:clamp(17px,1.35vw,20.5px);
  --t-body:16.5px;
  --t-small:14px;
  --t-label:11px;

  /* --- layout --- */
  --wrap:1240px;
  --wrap-wide:1500px;
  --gut:clamp(20px,5vw,64px);
  --sect:clamp(48px,5.6vw,92px);
  --r:4px;
  --r-lg:18px;

  --ease:cubic-bezier(.22,.61,.28,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}

/* The browser hides [hidden] with display:none, but that is a UA rule and any
   author rule that sets display beats it. So .btn{display:inline-flex} left the
   portfolio's "Load more" button on screen after the script had hidden it, and
   the same trap waits for every component that sets display and is ever hidden
   from script. One rule settles it for all of them. */
[hidden]{display:none !important}
html:focus-within{scroll-behavior:smooth}

body{
  margin:0;
  background:var(--tile);
  color:var(--ink);
  font-family:var(--sans);
  font-size:var(--t-body);
  font-weight:300;
  line-height:1.68;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  overflow-x:hidden;
}

img,svg,video{display:block;max-width:100%}
a{color:inherit}
button{font:inherit}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:2px}

/* =====================  primitives  ===================== */

.wrap{max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gut)}
.wrap-wide{max-width:var(--wrap-wide);margin-inline:auto;padding-inline:var(--gut)}
.section{padding-block:var(--sect)}

.eyebrow{
  font-size:var(--t-label);letter-spacing:.22em;text-transform:uppercase;
  font-weight:600;color:var(--gold-600);margin:0 0 22px;display:block;
}
.on-dark .eyebrow,.dark .eyebrow{color:var(--gold)}

h1,h2,h3,h4{margin:0;font-weight:400;text-wrap:balance;letter-spacing:-.02em;line-height:1.06}
.display{font-family:var(--serif);font-size:var(--t-display);line-height:1.0;letter-spacing:-.028em}
.h1{font-family:var(--serif);font-size:var(--t-h1);line-height:1.05}
.h2{font-family:var(--serif);font-size:var(--t-h2);line-height:1.1}
.h3{font-family:var(--sans);font-size:var(--t-h3);font-weight:500;line-height:1.25;letter-spacing:-.015em}
.serif-it{font-style:italic;color:var(--gold)}
.dark .serif-it{color:var(--gold)}

/* The second line of the home page headline. Upright rather than the serif
   italic the other heroes use, because that headline is one continuous
   sentence and an italic break in the middle reads as two separate thoughts.
   --azure itself is too dark to sit on a photograph; this is the same hue
   lifted until it clears the scrim as reliably as the gold does. */
.hero-sub{color:var(--azure-light);font-size:60%;display:inline-block;
  line-height:1;letter-spacing:-.02em}

p{margin:0 0 1.1em}
p:last-child{margin-bottom:0}
.lede{font-size:var(--t-lede);line-height:1.72;color:var(--mute);font-weight:300;max-width:62ch}
/* A quieter lede for long runs of body copy, where the full size is more
   presence than the text needs and costs a lot of vertical space. */
.lede--sm{font-size:clamp(15.5px,1.12vw,17px);line-height:1.75}
.dark .lede{color:#b7cadb}
.measure{max-width:66ch}

.rule{height:1px;background:var(--line);border:0;margin:0;transform-origin:left;}
.dark .rule{background:var(--line-dark)}

/* =====================  buttons / links  ===================== */

.btn{
  --bg:var(--gold);--fg:#16293c;
  display:inline-flex;align-items:center;gap:10px;
  background:var(--bg);color:var(--fg);
  font-family:var(--sans);font-size:14.5px;font-weight:600;letter-spacing:.012em;
  padding:15px 28px;border-radius:999px;text-decoration:none;border:1px solid transparent;
  transition:transform .34s var(--ease-out),box-shadow .34s var(--ease-out),background .25s;
  box-shadow:0 1px 0 rgba(255,255,255,.4) inset,0 8px 22px -10px rgba(200,147,74,.75);
  white-space:nowrap;
}
.btn:hover{transform:translateY(-2px);box-shadow:0 1px 0 rgba(255,255,255,.5) inset,0 16px 34px -12px rgba(200,147,74,.8)}
.btn:active{transform:translateY(0)}
.btn--ghost{
  background:transparent;color:var(--navy);border-color:var(--line);box-shadow:none;
}
.btn--ghost:hover{background:rgba(34,64,93,.05);box-shadow:none;border-color:rgba(34,64,93,.3)}

/* A long call to action that has to wrap on a narrow screen. The base .btn is
   nowrap, which is right for short labels and wrong for a full sentence. */
.btn--wrap{ white-space:normal; text-align:center }
.dark .btn--ghost{color:#fff;border-color:rgba(255,255,255,.28)}
.dark .btn--ghost:hover{background:rgba(255,255,255,.08);border-color:rgba(255,255,255,.5)}

.arrowlink{
  display:inline-flex;align-items:center;gap:9px;text-decoration:none;
  font-size:14.5px;font-weight:600;letter-spacing:.01em;color:var(--navy);
  padding-bottom:5px;border-bottom:1.5px solid var(--gold);
}
.dark .arrowlink,.hero .arrowlink,.seq .arrowlink,.cta .arrowlink,
.phead .arrowlink,.drawer .arrowlink{color:#fff}
.arrowlink .ar{transition:transform .34s var(--ease-out);display:inline-block}
.arrowlink:hover .ar{transform:translateX(5px)}

/* =====================  glass  ===================== */

.glass{
  position:relative;
  background:rgba(255,255,255,.09);
  border:1px solid rgba(255,255,255,.18);
  border-radius:var(--r-lg);
  -webkit-backdrop-filter:blur(26px) saturate(150%);
  backdrop-filter:blur(26px) saturate(150%);
  box-shadow:0 1px 0 rgba(255,255,255,.22) inset,0 24px 60px -28px rgba(6,18,32,.7);
  overflow:hidden;
}
.glass::after{ /* pointer sheen */
  content:'';position:absolute;inset:0;pointer-events:none;opacity:0;
  transition:opacity .45s var(--ease);
  background:radial-gradient(340px circle at var(--mx,50%) var(--my,50%),
             rgba(255,255,255,.20),rgba(255,255,255,0) 62%);
}
.glass:hover::after{opacity:1}
.glass--light{
  background:rgba(255,255,255,.62);
  border-color:rgba(34,64,93,.12);
  box-shadow:0 1px 0 rgba(255,255,255,.9) inset,0 22px 50px -30px rgba(22,41,60,.35);
}
.glass--light::after{background:radial-gradient(340px circle at var(--mx,50%) var(--my,50%),rgba(255,255,255,.9),rgba(255,255,255,0) 62%)}

/* =====================  header / nav  ===================== */

.hdr{
  position:fixed;inset:0 0 auto 0;z-index:100;
  padding:14px var(--gut);
  transition:padding .5s var(--ease-out);
}
.hdr__inner{
  max-width:var(--wrap-wide);margin-inline:auto;
  display:flex;align-items:center;justify-content:space-between;gap:24px;
  padding:12px 14px 12px 20px;border-radius:999px;
  border:1px solid transparent;background:transparent;
  transition:background .5s var(--ease-out),border-color .5s var(--ease-out),
             box-shadow .5s var(--ease-out),padding .5s var(--ease-out),max-width .5s var(--ease-out);
}
.hdr.is-stuck{padding-top:10px}
.hdr.is-stuck .hdr__inner{
  max-width:1180px;
  background:rgba(18,35,58,.66);
  border-color:rgba(255,255,255,.14);
  -webkit-backdrop-filter:blur(22px) saturate(160%);
  backdrop-filter:blur(22px) saturate(160%);
  box-shadow:0 1px 0 rgba(255,255,255,.16) inset,0 18px 44px -22px rgba(6,18,32,.72);
}
.hdr--solid .hdr__inner{
  background:rgba(18,35,58,.62);border-color:rgba(255,255,255,.13);
  -webkit-backdrop-filter:blur(22px) saturate(160%);backdrop-filter:blur(22px) saturate(160%);
}

.brand{display:flex;align-items:center;gap:11px;text-decoration:none;flex:0 0 auto}
/* The pill's height is set by its tallest child, which is the Free Estimate
   button on desktop and the menu button on a phone, not the logo. That left
   headroom above the mark, so the logo takes it: bigger wordmark, same pill.
   The sizes below sit just inside each breakpoint's content box, and
   checkheader.py measures the pill to make sure it has not grown. */
.brand img{height:46px;width:auto}
@media (max-width:1024px){ .brand img{height:42px} }
.brand__crown{height:19px;width:auto;display:none}

.nav{display:flex;align-items:center;gap:4px}
.nav a,.nav button{
  color:rgba(255,255,255,.86);text-decoration:none;font-size:14px;font-weight:400;letter-spacing:.005em;
  padding:9px 15px;border-radius:999px;background:none;border:0;cursor:pointer;
  transition:background .28s var(--ease),color .28s var(--ease);display:inline-flex;align-items:center;gap:6px;
}
.nav a:hover,.nav button:hover,.nav [aria-expanded="true"]{background:rgba(255,255,255,.11);color:#fff}
.nav .chev{width:9px;height:9px;transition:transform .32s var(--ease)}
.nav [aria-expanded="true"] .chev{transform:rotate(180deg)}

.hdr__cta{display:flex;align-items:center;gap:12px;flex:0 0 auto}
.tel{
  color:#fff;text-decoration:none;font-size:14px;font-weight:500;letter-spacing:.01em;
  padding:9px 14px;border-radius:999px;transition:background .28s;white-space:nowrap;
}
.tel:hover{background:rgba(255,255,255,.11)}
.hdr .btn{padding:11px 22px;font-size:13.5px}

/* mega menu */
.mega{
  position:absolute;left:var(--gut);right:var(--gut);top:calc(100% + 8px);
  max-width:1180px;margin-inline:auto;
  background:rgba(18,35,58,.86);
  -webkit-backdrop-filter:blur(30px) saturate(170%);backdrop-filter:blur(30px) saturate(170%);
  border:1px solid rgba(255,255,255,.14);border-radius:22px;
  box-shadow:0 1px 0 rgba(255,255,255,.14) inset,0 34px 80px -34px rgba(6,18,32,.85);
  padding:26px;
  display:grid;grid-template-columns:repeat(3,1fr);gap:8px;
  opacity:0;visibility:hidden;transform:translateY(-10px) scale(.985);transform-origin:top center;
  transition:opacity .38s var(--ease-out),transform .38s var(--ease-out),visibility .38s;
}
.mega.is-open{opacity:1;visibility:visible;transform:none}
.mega a{
  display:flex;gap:14px;align-items:center;padding:12px;border-radius:14px;
  text-decoration:none;color:#fff;transition:background .28s var(--ease)
}
.mega a:hover{background:rgba(255,255,255,.09)}
.mega img{width:64px;height:64px;object-fit:cover;border-radius:10px;flex:0 0 auto}
.mega .t{font-size:14.5px;font-weight:500;letter-spacing:-.008em;line-height:1.3}
.mega .d{font-size:12.5px;color:#a7bccf;line-height:1.45;margin-top:3px;font-weight:300}

/* A short dropdown with no pictures: About Us and Service Areas. Same panel
   as the services menu, sized to its contents and hung under its own button
   rather than spanning the header. */
.navdrop{ position:relative; display:inline-flex }
.mega--sm{ left:0; right:auto; width:max-content; min-width:206px;
           margin-inline:0; display:block; padding:10px;
           top:calc(100% + 10px); transform-origin:top left }
.mega--sm a{ padding:11px 14px }
.mega--sm .t{ font-size:15px }

/* mobile */
.burger{display:none;width:42px;height:42px;border-radius:999px;border:1px solid rgba(255,255,255,.2);
  background:rgba(255,255,255,.07);cursor:pointer;align-items:center;justify-content:center;flex-direction:column;gap:5px}
.burger i{display:block;width:16px;height:1.5px;background:#fff;transition:transform .34s var(--ease),opacity .2s}
/* the bars are 1.5px tall with a 5px gap, so each outer bar sits 6.5px from
   the middle one and has to travel all of it to cross in the centre */
.burger[aria-expanded="true"] i:nth-child(1){transform:translateY(6.5px) rotate(45deg)}
.burger[aria-expanded="true"] i:nth-child(2){opacity:0}
.burger[aria-expanded="true"] i:nth-child(3){transform:translateY(-6.5px) rotate(-45deg)}

.drawer{
  position:fixed;inset:0;z-index:99;background:rgba(15,30,48,.9);
  -webkit-backdrop-filter:blur(30px) saturate(150%);backdrop-filter:blur(30px) saturate(150%);
  padding:100px var(--gut) 40px;overflow-y:auto;
  opacity:0;visibility:hidden;transition:opacity .42s var(--ease-out),visibility .42s;
}
.drawer.is-open{opacity:1;visibility:visible}
.drawer a{display:block;color:#fff;text-decoration:none;font-family:var(--serif);
  font-size:clamp(26px,6vw,38px);padding:13px 0;border-bottom:1px solid rgba(255,255,255,.1);letter-spacing:-.02em}
.drawer .sub{font-family:var(--sans);font-size:16px;color:#a7bccf;padding-left:16px;font-weight:300}
/* The quote button and the phone number on one row, the way the header carries
   them: button on the left, number on the right. Stacked, the number sat as an
   orphan under the button with nothing beside it. */
.drawer .foot{margin-top:34px;display:flex;align-items:center;
  justify-content:space-between;gap:18px;flex-wrap:wrap}
/* A group heading in the drawer. The desktop menu opens About Us as a panel
   listing both pages, so the drawer names the group and lists both under it
   rather than making the group itself the link to one of them. */
.drawer .grp{display:block;color:#fff;font-family:var(--serif);
  font-size:clamp(26px,6vw,38px);padding:13px 0;letter-spacing:-.02em;
  border-bottom:1px solid rgba(255,255,255,.1)}

/* =====================  hero  ===================== */

.hero{
  position:relative;min-height:min(92vh,860px);display:flex;align-items:flex-end;
  background:var(--navy-900);color:#fff;overflow:hidden;isolation:isolate;
}
.hero__media{position:absolute;inset:-6% 0 0;z-index:-2;will-change:transform}
/* The home hero photo is a tall 2:3.3 corner shot, so a wide band only shows a
   third of its height. 16% puts that band across the top of the enclosure: the
   rain head, the clamp and the top corner of the glass, which is the part that
   reads as frameless. Only the home page uses .hero__media. */
.hero__media img{width:100%;height:112%;object-fit:cover;object-position:center 16%}
.hero__scrim{
  position:absolute;inset:0;z-index:-1;
  background:
    linear-gradient(to top,rgba(12,28,46,.94) 0%,rgba(12,28,46,.62) 34%,rgba(12,28,46,.24) 62%,rgba(12,28,46,.55) 100%),
    linear-gradient(to right,rgba(12,28,46,.62) 0%,rgba(12,28,46,.05) 62%);
}
.hero__inner{width:100%;max-width:var(--wrap-wide);margin-inline:auto;padding:0 var(--gut) clamp(52px,7vw,92px);}
.hero__grid{display:grid;grid-template-columns:minmax(0,1.15fr) minmax(300px,.85fr);gap:clamp(28px,4vw,64px);align-items:end}
.hero h1{font-family:var(--serif);font-size:var(--t-display);line-height:.98;letter-spacing:-.03em;margin:0 0 24px}
.hero .lede{color:#c6d8e6;max-width:44ch;margin-bottom:32px}
/* The gap above the sub-line comes from the type's own leading and grows with
   the font; the gap below it was a fixed 24px that never moved, so the wider
   the screen the more lopsided it looked. Both sides are em-based here, which
   holds the sub-line centred between the line above and the lede below from
   390px to 1440px. Scoped to the home hero so the other 51 pages are untouched. */
/* The home headline is set in the body sans at 600, the same weight the quote
   button uses, rather than the serif the other 43 heroes use. It reads as more
   direct and leaves the serif logo as the one refined thing in the header.
   Tracking is eased from the serif's -.03em because a geometric sans needs
   less of it at display size. Home page only: the other heroes are untouched. */
.hero--home h1{font-family:var(--sans);font-weight:600;letter-spacing:-.025em}
/* Outfit's metrics are not the serif's, so the centring was re-solved after the
   font changed. The gap above comes from the type's leading and scales with it;
   the gap below carries a roughly fixed amount from the lede's own leading that
   does not scale, which is why the bottom margin needs the -8px term. Measured
   at 1440, 1200, 900, 600 and 390: even to within 3px at every one. */
.hero--home h1{margin-bottom:calc(.30em - 8px)}
.hero--home .ln--sub{margin-top:10px}
.hero__acts{display:flex;gap:14px;flex-wrap:wrap;align-items:center}

/* hero glass card */
.hcard{padding:26px 26px 22px;border-radius:20px}
.hcard .k{font-size:var(--t-label);letter-spacing:.2em;text-transform:uppercase;color:var(--gold);font-weight:600;margin:0 0 16px}
.hcard ul{list-style:none;margin:0;padding:0;display:grid;gap:0}
.hcard li{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:11px 0;border-top:1px solid rgba(255,255,255,.13);font-size:14px;color:#cfe0ec;font-weight:300}
.hcard li:first-child{border-top:0}
.hcard li b{font-family:var(--serif);font-size:19px;font-weight:500;color:#fff;letter-spacing:-.01em;
  font-variant-numeric:tabular-nums}

/* line-mask reveal */
.lines{display:block}
.lines .ln{display:block;overflow:hidden}
.lines .ln > span{display:block;transform:translateY(105%);will-change:transform}
.js .lines.go .ln > span{animation:lineUp 1.05s var(--ease-out) forwards}
.js .lines.go .ln:nth-child(2) > span{animation-delay:.09s}
.js .lines.go .ln:nth-child(3) > span{animation-delay:.18s}
.js .lines.go .ln:nth-child(4) > span{animation-delay:.27s}
@keyframes lineUp{to{transform:translateY(0)}}

/* fade-rise for hero support content */
.js .rise{opacity:0;transform:translateY(26px)}
.js .rise.go{animation:riseIn .95s var(--ease-out) forwards}
@keyframes riseIn{to{opacity:1;transform:none}}
.js .d1{animation-delay:.34s}.js .d2{animation-delay:.44s}.js .d3{animation-delay:.54s}

/* hero image zoom-settle on load */
.js .hero__media img{transform:scale(1.09);will-change:transform}
.js .hero.go .hero__media img{animation:settle 1.9s var(--ease-out) forwards}
@keyframes settle{to{transform:scale(1)}}

/* =====================  scroll reveal (below fold)  ===================== */

.js .rv{opacity:0;transform:translateY(30px);transition:opacity .95s var(--ease-out),transform .95s var(--ease-out)}
.js .rv.in{opacity:1;transform:none}
.js .rv-2{transition-delay:.09s}.js .rv-3{transition-delay:.18s}.js .rv-4{transition-delay:.27s}

/* A card that both reveals on scroll and lifts on hover has two rules wanting
   its transform, and .rv.in (transform:none) outranks a plain :hover, so the
   lift silently never happened. Repeating the class matches that specificity
   and, coming later, wins, without reaching for !important. Any new card that
   carries .rv and lifts belongs in this list. */
.config.config:hover,
.swatch.swatch:hover,
.tilecard.tilecard:hover,
.fcard--link.fcard--link:hover,
.svc.svc:hover,
.person.person:hover{ transform:translateY(-4px) }
.js .rvl{transform:scaleX(0);transition:transform 1.1s var(--ease-out)}
.js .rvl.in{transform:scaleX(1)}
.js .rvi{clip-path:inset(0 0 100% 0);transform:scale(1.06);
  transition:clip-path 1.25s var(--ease-out),transform 1.5s var(--ease-out)}
.js .rvi.in{clip-path:inset(0 0 0 0);transform:none}

/* word reveal */
.wr{display:inline}
.wr .w{display:inline-block;overflow:hidden;vertical-align:bottom}
.wr .w > i{display:inline-block;font-style:inherit;transform:translateY(100%);
  transition:transform .8s var(--ease-out)}
.js .wr.in .w > i{transform:none}

/* =====================  dark section  ===================== */

.dark{background:var(--navy-900);color:#fff}
.dark h1,.dark h2,.dark h3{color:#fff}
.navy{background:var(--navy)}
.tile{background:var(--tile)}
.glasstone{background:var(--glass)}
.stone{background:var(--stone)}

/* =====================  pinned sequence (Apple-style)  ===================== */

.seq{position:relative;background:var(--navy-900);color:#fff}
.seq__rail{height:520vh}
.seq__stick{position:sticky;top:0;height:100vh;display:flex;align-items:center;overflow:hidden}
.seq__bg{position:absolute;inset:0}
.seq__bg figure{position:absolute;inset:0;margin:0;opacity:0;transform:scale(1.09);
  transition:opacity 1s var(--ease-out),transform 1.6s var(--ease-out)}
.seq__bg figure.on{opacity:1;transform:scale(1)}
.seq__bg img{width:100%;height:100%;object-fit:cover}
.seq__veil{position:absolute;inset:0;background:
  linear-gradient(to right,rgba(12,28,46,.95) 0%,rgba(12,28,46,.86) 32%,rgba(12,28,46,.52) 68%,rgba(12,28,46,.3) 100%)}
.seq__inner{position:relative;width:100%;max-width:var(--wrap-wide);margin-inline:auto;padding-inline:var(--gut)}
.seq__panels{position:relative;max-width:600px;min-height:330px}
.seq__panel{position:absolute;inset:0;opacity:0;transform:translateY(24px);pointer-events:none;
  transition:opacity .7s var(--ease-out),transform .7s var(--ease-out)}
.seq__panel.on{opacity:1;transform:none;pointer-events:auto}
.seq__panel .n{font-family:var(--serif);font-style:italic;font-size:15px;color:var(--gold);margin:0 0 14px}
.seq__panel h3{font-family:var(--serif);font-size:clamp(30px,4.4vw,58px);font-weight:400;
  letter-spacing:-.025em;line-height:1.02;margin:0 0 18px}
.seq__panel p{color:#bed2e2;font-size:var(--t-lede);max-width:40ch;margin-bottom:26px;line-height:1.7}
.seq__prog{display:flex;gap:8px;margin-top:34px}
.seq__prog i{height:2px;width:52px;background:rgba(255,255,255,.22);border-radius:2px;overflow:hidden;position:relative}
.seq__prog i::after{content:'';position:absolute;inset:0;background:var(--gold);transform:scaleX(var(--f,0));
  transform-origin:left;transition:transform .3s linear}

/* =====================  drift gallery  ===================== */

.drift{overflow:hidden;padding-block:clamp(20px,3vw,40px)}
.drift__track{display:flex;gap:18px;will-change:transform;padding-inline:var(--gut)}
.drift__track figure{margin:0;flex:0 0 auto;width:clamp(230px,26vw,380px)}
.drift__track img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;border-radius:12px}
.drift__track figcaption{font-family:var(--serif);font-style:italic;font-size:13.5px;
  color:var(--mute);padding-top:11px}
.dark .drift__track figcaption{color:#a3b9cc}

/* =====================  marquee  ===================== */

.mq{overflow:hidden;border-block:1px solid var(--line);padding-block:20px;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.dark .mq{border-color:var(--line-dark)}
.mq__t{display:flex;gap:0;width:max-content;animation:mq 58s linear infinite}
.mq__t span{font-family:var(--serif);font-size:clamp(17px,2vw,25px);color:var(--mute);
  padding-inline:22px;white-space:nowrap;letter-spacing:-.01em}
.dark .mq__t span{color:#8fa8bd}
.mq__t span::after{content:'·';color:var(--gold);margin-left:44px}
@keyframes mq{to{transform:translateX(-50%)}}
.mq:hover .mq__t{animation-play-state:paused}

/* =====================  cards / grids  ===================== */

.grid{display:grid;gap:clamp(18px,2.2vw,30px)}
.g2{grid-template-columns:repeat(auto-fit,minmax(300px,1fr))}
.g3{grid-template-columns:repeat(auto-fit,minmax(272px,1fr))}
.g4{grid-template-columns:repeat(auto-fit,minmax(215px,1fr))}
/* Five equal cards across, rather than auto-fit, so the row never breaks into
   an orphan. minmax(0,…) keeps a long card title from widening its track. */
.g5{grid-template-columns:repeat(5,minmax(0,1fr))}
/* A card that is itself a link: the call to action sits on the bottom edge, so
   a row of them lines up however unevenly the titles wrap. */
.fcard--link{ display:flex; flex-direction:column;
              transition:transform .4s var(--ease-out), box-shadow .4s var(--ease-out) }
.fcard--link:hover{ transform:translateY(-4px);
                    box-shadow:0 26px 50px -30px rgba(22,41,60,.45) }
.fcard--link .arrowlink{ margin-top:auto; padding-top:18px }
@media (max-width:1100px){ .g5{grid-template-columns:repeat(3,minmax(0,1fr))} }
@media (max-width:760px) { .g5{grid-template-columns:repeat(2,minmax(0,1fr))} }
@media (max-width:600px) { .g5{grid-template-columns:minmax(0,1fr)} }
/* On a phone these cards go to one column and lie down: the name on the left,
   the link on the right. Side by side there was only about 105px inside the
   padding, which broke "See the work" onto three lines and stretched every
   card to the height of the tallest title. */
@media (max-width:600px){
  .g5 .fcard--link{ flex-direction:row; align-items:center;
                    justify-content:space-between; gap:18px; padding:18px 22px }
  .g5 .fcard--link h3{ margin:0; font-size:18px }
  .g5 .fcard--link .arrowlink{ margin-top:0; padding-top:0;
                               white-space:nowrap; flex:none }
}
/* Five cards read better as three then two than as four and a lone straggler. */
.g3--wide{grid-template-columns:repeat(auto-fit,minmax(330px,1fr))}

.tilecard{
  display:flex;flex-direction:column;text-decoration:none;color:inherit;
  border-radius:14px;overflow:hidden;background:#fff;border:1px solid var(--line);
  transition:transform .5s var(--ease-out),box-shadow .5s var(--ease-out),border-color .4s;
}
.tilecard:hover{transform:translateY(-4px);box-shadow:0 26px 50px -30px rgba(22,41,60,.5);border-color:rgba(34,64,93,.24)}
.tilecard__pic{position:relative;overflow:hidden;aspect-ratio:4/3}
.tilecard__pic img{width:100%;height:100%;object-fit:cover;transition:transform 1.1s var(--ease-out)}
.tilecard:hover .tilecard__pic img{transform:scale(1.055)}
.tilecard__b{padding:22px 22px 24px;display:flex;flex-direction:column;gap:7px;flex:1}
.tilecard h3{font-family:var(--sans);font-size:18.5px;font-weight:500;letter-spacing:-.014em;line-height:1.3;color:var(--navy)}
.tilecard p{font-size:14.5px;color:var(--mute);margin:0;line-height:1.6}
.tilecard .go{margin-top:auto;padding-top:14px;font-size:13px;font-weight:600;color:var(--navy);
  letter-spacing:.05em;text-transform:uppercase;display:inline-flex;gap:8px;align-items:center}
.tilecard .go span{transition:transform .34s var(--ease-out)}
.tilecard:hover .go span{transform:translateX(5px)}

/* editorial index rows */
.idx{border-top:1px solid var(--line)}
.dark .idx{border-color:var(--line-dark)}
.idxrow{display:grid;grid-template-columns:64px 1fr auto;gap:clamp(16px,3vw,44px);
  align-items:baseline;padding:26px 0;border-bottom:1px solid var(--line);
  text-decoration:none;color:inherit;position:relative;transition:padding-left .45s var(--ease-out)}
.dark .idxrow{border-color:var(--line-dark)}
.idxrow:hover{padding-left:14px}
.idxrow .num{font-family:var(--serif);font-style:italic;font-size:15px;color:var(--gold)}
.idxrow h3{font-family:var(--serif);font-size:clamp(21px,2.6vw,30px);font-weight:400;
  letter-spacing:-.018em;margin:0 0 6px;color:var(--navy)}
.dark .idxrow h3{color:#fff}
.idxrow p{margin:0;font-size:15px;color:var(--mute);max-width:60ch;line-height:1.62}
.dark .idxrow p{color:#a9c0d3}
.idxrow .to{font-size:19px;color:var(--gold);transition:transform .38s var(--ease-out)}
.idxrow:hover .to{transform:translateX(6px)}

/* stat band */
.stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:clamp(24px,4vw,52px)}
.stat .n{font-family:var(--sans);font-size:clamp(36px,4.5vw,62px);font-weight:600;line-height:1;
  letter-spacing:-.035em;color:var(--gold-700);font-variant-numeric:tabular-nums}
/* On a dark band the brand gold carries itself; on a light one it needs the
   deeper tone to clear 3:1 against stone at display size. */
.dark .stat .n{color:var(--gold)}
.stat .n em{font-style:normal;color:var(--gold)}
.stat .l{font-size:13.5px;color:var(--mute);margin-top:12px;line-height:1.5;max-width:22ch}
.dark .stat .l{color:#a3b9cc}
@media (max-width:680px){
  /* Equal thirds. An uneven set of tracks made "10,000+" start left of where
     the eye expects it and left a gap before "100+"; three figures read as a
     row and want one rhythm. They fit in a third at this size. */
  .stats{gap:10px;grid-template-columns:repeat(3,minmax(0,1fr))}
  .stat .n{font-size:clamp(16px,5.2vw,28px)}
  .stat .l{font-size:11px;margin-top:8px;line-height:1.4}
}


/* split feature */
.split{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:clamp(30px,5vw,80px);align-items:center}
.split--rev > *:first-child{order:2}
/* long-form service layouts hang from the top rather than centring a tall
   prose column against a short spec column */
.split:has(.prose),.split:has(.specs){align-items:start}
.split figure{margin:0;position:relative}
.split figure img{width:100%;height:auto;aspect-ratio:5/6;object-fit:cover;border-radius:16px}
.split figcaption{font-family:var(--serif);font-style:italic;font-size:13.5px;color:var(--mute);padding-top:12px}
.dark .split figcaption{color:#a3b9cc}
/* A product shot with its own transparent background sits directly on the band:
   no crop to a card shape, no rounded edge. */
.split figure.cutout img{ aspect-ratio:auto; object-fit:contain; border-radius:0 }

/* pull quote */
.pull{text-align:center;max-width:960px;margin-inline:auto}
.pull blockquote{margin:0;font-family:var(--serif);font-size:clamp(23px,3.3vw,42px);line-height:1.32;
  letter-spacing:-.02em;color:var(--navy)}
.dark .pull blockquote{color:#fff}
.pull cite{display:block;font-family:var(--sans);font-style:normal;font-size:12px;letter-spacing:.19em;
  text-transform:uppercase;color:var(--mute);margin-top:26px;font-weight:600}
.dark .pull cite{color:var(--gold)}
.stars{color:var(--gold);letter-spacing:.28em;font-size:14px;margin-bottom:22px}

/* spec list */
.specs{list-style:none;margin:0;padding:0;border-top:1px solid var(--line)}
.dark .specs{border-color:var(--line-dark)}
.specs li{display:grid;grid-template-columns:minmax(130px,.34fr) 1fr;gap:20px;padding:15px 0;
  border-bottom:1px solid var(--line);font-size:15px}
.dark .specs li{border-color:var(--line-dark)}
.specs b{font-weight:500;color:var(--navy);font-size:13px;letter-spacing:.06em;text-transform:uppercase}
.dark .specs b{color:var(--gold)}
.specs span{color:var(--mute)}
.dark .specs span{color:#b7cadb}

/* FAQ */
.faq{border-top:1px solid var(--line)}
.dark .faq{border-color:var(--line-dark)}
.faq details{border-bottom:1px solid var(--line);padding:0}
.dark .faq details{border-color:var(--line-dark)}
.faq summary{list-style:none;cursor:pointer;padding:24px 44px 24px 0;position:relative;
  font-family:var(--serif);font-size:clamp(18px,2.1vw,24px);letter-spacing:-.015em;color:var(--navy);line-height:1.34}
.dark .faq summary{color:#fff}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:'';position:absolute;right:6px;top:50%;width:13px;height:13px;
  border-right:1.5px solid var(--gold);border-bottom:1.5px solid var(--gold);
  transform:translateY(-70%) rotate(45deg);transition:transform .38s var(--ease-out)}
.faq details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq .a{padding:0 12% 26px 0;color:var(--mute);font-size:16px;line-height:1.75;max-width:72ch}
.dark .faq .a{color:#b7cadb}
.faq details[open] .a{animation:riseIn .6s var(--ease-out) both}

/* steps */
.steps{counter-reset:s;display:grid;gap:0}
.step{display:grid;grid-template-columns:minmax(86px,.16fr) 1fr;gap:clamp(16px,3vw,46px);
  padding:30px 0;border-top:1px solid var(--line);align-items:start}
.dark .step{border-color:var(--line-dark)}
.step .sn{font-family:var(--serif);font-style:italic;color:var(--gold);font-size:17px}
.step h3{font-family:var(--sans);font-size:19px;font-weight:500;letter-spacing:-.012em;margin:0 0 8px;color:var(--navy)}
.dark .step h3{color:#fff}
.step p{margin:0;color:var(--mute);font-size:15.5px;max-width:62ch}
.dark .step p{color:#b7cadb}

/* page header (interior) */
.phead{position:relative;background:var(--navy-900);color:#fff;padding:clamp(140px,17vw,210px) 0 clamp(56px,7vw,90px);overflow:hidden}
.phead__media{position:absolute;inset:0;z-index:0}
.phead__media img{width:100%;height:100%;object-fit:cover}
.phead::after{content:'';position:absolute;inset:0;
  background:linear-gradient(to top,rgba(12,28,46,.96),rgba(12,28,46,.72) 55%,rgba(12,28,46,.6));z-index:1}
.phead .wrap{position:relative;z-index:2}
/* Outfit at 600 sets much wider than EB Garamond at the same point size, so
   keeping --t-h1 pushed 39 headlines onto an extra row, including every city
   page on a phone. This scale is about 10% smaller in points and optically the
   same size on screen, because the sans has far more x-height per point. */
.phead h1{font-family:var(--sans);font-weight:600;font-size:clamp(31px,4.8vw,70px);
  letter-spacing:-.025em;margin:0 0 20px}
/* Line two of an interior headline. It was gold serif italic; now it is upright
   in the lifted azure, matching the home page. The gold is left to the buttons,
   where it means "do this", and the sans keeps all 53 headlines in one voice.
   .serif-it sets both the italic and the gold, so both are overridden here. */
.phead h1 .serif-it{font-style:normal;color:var(--azure-light)}
.phead .lede{color:#c6d8e6}
.crumbs{font-size:12.5px;color:#9fb7cb;margin:0 0 20px;letter-spacing:.03em}
.crumbs a{text-decoration:none;color:#9fb7cb}
.crumbs a:hover{color:#fff}
.crumbs span{color:var(--gold);padding-inline:8px}

/* gallery
   A grid, not CSS columns. Columns fill top-to-bottom and re-balance every time
   the content changes, so "Load more" reshuffled every photograph already on
   screen and the reading order ran down the page rather than across it. A grid
   flows left to right and only ever appends, so nothing a visitor has already
   looked at moves.
   Every tile is 3:4 because that is what 73% of the library already is, and the
   median is exactly 3:4, so the uniform shape costs almost nothing in cropping
   and buys a gallery that never jumps. */
.gal{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px}
.gal figure{margin:0;position:relative;border-radius:12px;overflow:hidden;
  aspect-ratio:3/4;background:rgba(34,64,93,.06);cursor:zoom-in}
.gal img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 1.1s var(--ease-out)}
.gal figure:hover img{transform:scale(1.045)}
.gal figure:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
.gal figcaption{position:absolute;left:0;right:0;bottom:0;padding:34px 16px 14px;color:#fff;
  font-family:var(--serif);font-style:italic;font-size:13.5px;
  background:linear-gradient(to top,rgba(12,28,46,.86),transparent);
  opacity:0;transform:translateY(8px);transition:opacity .4s var(--ease),transform .4s var(--ease)}
.gal figure:hover figcaption{opacity:1;transform:none}
.filters{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:34px}
.filters button{border:1px solid var(--line);background:transparent;color:var(--mute);
  padding:9px 17px;border-radius:999px;font-size:13.5px;cursor:pointer;transition:all .3s var(--ease)}
.filters button:hover{border-color:rgba(34,64,93,.35);color:var(--navy)}
.filters button[aria-pressed="true"]{background:var(--navy);border-color:var(--navy);color:#fff}

/* form */
.form{display:grid;gap:18px}
.field{display:flex;flex-direction:column;gap:8px}
.field label{font-size:12px;letter-spacing:.14em;text-transform:uppercase;font-weight:600;color:var(--gold)}
.field input,.field select,.field textarea{
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.17);border-radius:10px;
  padding:14px 15px;color:#fff;font-family:var(--sans);font-size:15.5px;font-weight:300;
  transition:border-color .3s,background .3s}
.field textarea{min-height:130px;resize:vertical}
.field select option{background:var(--navy-900);color:#fff}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--gold);background:rgba(255,255,255,.1)}
.field input::placeholder,.field textarea::placeholder{color:#7f97ab}
.f2{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:18px}
.formnote{font-size:13px;color:#93aabe;margin:0}

/* contact tiles */
.ctile{padding:26px;border-radius:16px}
.ctile .k{font-size:var(--t-label);letter-spacing:.2em;text-transform:uppercase;color:var(--gold);font-weight:600;margin:0 0 12px}
.ctile p{margin:0;font-size:16px;line-height:1.65;color:#cfe0ec}
.ctile a{color:#fff;text-decoration:none;border-bottom:1px solid rgba(234,183,109,.6)}

/* CTA band */
.cta{position:relative;overflow:hidden;background:var(--navy);color:#fff;
  padding-block:clamp(64px,9vw,120px);isolation:isolate}
.cta__media{position:absolute;inset:0;z-index:-2}
.cta__media img{width:100%;height:100%;object-fit:cover}
.cta::before{content:'';position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to right,rgba(18,35,58,.95),rgba(18,35,58,.7))}
.cta h2{font-family:var(--serif);font-size:var(--t-h2);margin:0 0 18px;max-width:16ch}
.cta .lede{color:#c6d8e6;margin-bottom:32px}

/* footer */
.ftr{background:var(--navy-900);color:#c6d8e6;padding-block:clamp(52px,7vw,84px) 30px;font-size:14.5px}
.ftr__top{display:grid;grid-template-columns:minmax(240px,1.3fr) repeat(auto-fit,minmax(150px,1fr));
  gap:clamp(28px,4vw,56px);padding-bottom:44px}
.ftr img.mark{height:28px;width:auto;margin-bottom:20px}
.ftr h4{font-size:var(--t-label);letter-spacing:.2em;text-transform:uppercase;color:var(--gold);
  font-weight:600;margin:0 0 16px}
.ftr ul{list-style:none;margin:0;padding:0;display:grid;gap:10px}
.ftr a{color:#c6d8e6;text-decoration:none;transition:color .25s}
.ftr a:hover{color:#fff}
.ftr__bot{border-top:1px solid rgba(255,255,255,.11);padding-top:24px;display:flex;
  justify-content:space-between;gap:20px;flex-wrap:wrap;font-size:13px;color:#8ba3b8}
.ftr p{color:#a9c0d3;line-height:1.7;max-width:38ch}

/* ---- the shop map -----------------------------------------------------------
   A fixed aspect ratio so the page does not jump when the lazy iframe arrives,
   and the frame carries the rounding and the shadow rather than the iframe,
   which cannot be clipped reliably on its own. */
.mapwrap{position:relative;margin-top:clamp(26px,3vw,40px);border-radius:var(--r-lg);
  overflow:hidden;border:1px solid rgba(34,64,93,.14);
  box-shadow:0 24px 54px -34px rgba(22,41,60,.5);aspect-ratio:16/9;background:var(--tile)}
@media(max-width:700px){ .mapwrap{aspect-ratio:4/3} }
.mapwrap iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.mapacts{display:flex;align-items:center;gap:clamp(16px,2.4vw,30px);flex-wrap:wrap;
  margin-top:clamp(18px,2vw,26px)}
.mapaddr{margin:0;font-size:14.5px;line-height:1.6;color:var(--mute)}
.mapaddr a{color:var(--navy);text-decoration:none;border-bottom:1px solid rgba(234,183,109,.6)}

/* ---- reviews ---------------------------------------------------------------
   Frosted panels on the pale glass tint, which is the one background on the site
   with enough tone behind it for frosted glass to read as glass rather than as a
   white box. Nothing moves: a review is read, not glanced at, and content that
   scrolls under the reader gets skipped. */
.reviews .fcard,.reviews .rbar{
  background:rgba(255,255,255,.62);
  border:1px solid rgba(255,255,255,.85);
  -webkit-backdrop-filter:blur(22px) saturate(150%);
  backdrop-filter:blur(22px) saturate(150%);
  box-shadow:0 1px 0 rgba(255,255,255,.95) inset,0 24px 54px -32px rgba(22,41,60,.45)}
.reviews .fcard{border-radius:var(--r-lg);padding:clamp(24px,2.4vw,34px);display:flex;
  flex-direction:column}
.reviews .fcard p{color:var(--ink-soft);margin:0}

.gmark{width:15px;height:15px;flex:0 0 auto}

/* who wrote it. A name and a source are what make a quote read as real; an
   unattributed five-star line is the shape of an invented testimonial. */
.rwho{display:flex;align-items:center;gap:12px;margin-top:auto;padding-top:18px;
  border-top:1px solid rgba(34,64,93,.13)}
.rwho>span:last-child{display:block}
.ravatar{width:38px;height:38px;border-radius:50%;flex:0 0 auto;display:grid;place-items:center;
  background:var(--navy);color:#fff;font-weight:600;font-size:15px;font-family:var(--sans)}
.rwho__n{display:block;font-size:14.5px;font-weight:600;color:var(--ink);line-height:1.3}
.rwho__m{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--mute);margin-top:2px}

/* four reviews: an explicit two-up. The shared auto-fit grids land on three
   columns at desktop width, which leaves the fourth card alone on its own row. */
.reviews .revpair{grid-template-columns:1fr}
@media(min-width:780px){ .reviews .revpair{grid-template-columns:1fr 1fr} }

/* the summary, and the link that lets anyone go and check */
.rbar{display:flex;align-items:center;justify-content:center;gap:clamp(14px,2.6vw,34px);
  flex-wrap:wrap;border-radius:999px;padding:16px clamp(20px,2.4vw,36px);
  margin:clamp(26px,3vw,34px) auto 0;width:fit-content;max-width:100%}
.rbar__score{font-family:var(--serif);font-size:38px;line-height:1;color:var(--ink)}
.rbar__mid{text-align:left}
.rbar__stars{display:block;color:var(--gold);letter-spacing:.2em;font-size:15px}
.rbar__sub{display:flex;align-items:center;gap:7px;font-size:13px;color:var(--mute);margin-top:4px}
.rbar__link{font-size:13.5px;font-weight:600;color:var(--navy);text-decoration:none;
  border-bottom:1.5px solid var(--gold);padding-bottom:4px;white-space:nowrap;
  transition:color .25s}
.rbar__link:hover{color:var(--gold-700)}
@media(max-width:600px){
  .rbar{border-radius:var(--r-lg);flex-direction:column;gap:14px;text-align:center}
  .rbar__mid{text-align:center}
  .rbar__sub{justify-content:center}
}

/* ---- catalog download card ------------------------------------------------
   Stacked on a phone, cover full width on top, because the thumbnail-beside-text
   version left the cover stranded in a narrow column with the text crushed into
   the rest. Two columns only once there is room for them. */
.catcard{
  display:grid;gap:clamp(22px,3vw,44px);align-items:center;
  background:#fff;border:1px solid rgba(34,64,93,.14);border-radius:18px;
  padding:clamp(20px,3vw,44px);box-shadow:0 20px 50px -34px rgba(34,64,93,.5);
  grid-template-columns:1fr}
.catcard__shot{display:block;border-radius:8px;overflow:hidden;align-self:start}
.catcard__shot img{display:block;width:100%;height:auto;
  box-shadow:0 14px 34px -20px rgba(34,64,93,.65);border:1px solid rgba(34,64,93,.1);
  border-radius:8px;transition:transform .35s var(--ease-out)}
.catcard__shot:hover img{transform:translateY(-3px)}
.catcard__body .h2{margin:7px 0 14px}
.catcard__body p{color:var(--ink-soft);max-width:54ch;margin:0 0 20px}
.catcard__meta{display:flex;flex-wrap:wrap;gap:9px;list-style:none;padding:0;margin:0 0 26px}
.catcard__meta li{font-size:12.5px;letter-spacing:.03em;color:var(--mute);
  border:1px solid rgba(34,64,93,.16);border-radius:999px;padding:6px 14px}
.catcard__acts{display:flex;gap:18px;align-items:center;flex-wrap:wrap}
@media(min-width:760px){ .catcard{grid-template-columns:230px 1fr} }
/* the heading is a display serif and runs to three lines on a narrow screen,
   which pushes the button below the fold for no good reason */
@media(max-width:759px){
  .catcard__body .h2{font-size:clamp(26px,7.4vw,34px)}
  .catcard__body p{margin-bottom:18px}
  .catcard__meta{margin-bottom:22px}
}
/* the contractors' version, where the card carries a short form instead of a
   download button. Three fields, because every extra one costs a lead. */
.catform{margin-top:4px}
/* grid children default to min-width:auto, and a text input's default size
   attribute is wider than a third of this card, so the last field pushed out
   past the edge. min-width:0 lets the columns actually share the row. */
.catform__row{display:grid;gap:14px;grid-template-columns:1fr}
.catform__row>.field{min-width:0}
.catform__row>.field input{width:100%;min-width:0}
@media(min-width:620px){.catform__row{grid-template-columns:repeat(3,1fr)}}
.catform .field label{color:var(--mute)}
.catform .field input{background:rgba(34,64,93,.04);border-color:rgba(34,64,93,.18);color:var(--ink)}
.catform .field input:focus{border-color:var(--gold-600);background:#fff}
.catform .field input::placeholder{color:var(--mute-light)}
.catform__act{display:flex;gap:18px;align-items:center;flex-wrap:wrap;margin-top:20px}
.tile .catform .field input{background:#fff}
.dark .catcard,.navy .catcard{background:rgba(255,255,255,.055);
  border-color:rgba(255,255,255,.15);box-shadow:none}
.dark .catcard__body p,.navy .catcard__body p{color:#b9cdde}
.dark .catcard__meta li,.navy .catcard__meta li{color:#a9c0d2;border-color:rgba(255,255,255,.2)}

/* social links. Round, quiet by default, gold on hover, sized so a thumb can
   hit them on a phone without the footer turning into a row of buttons. */
.ftr ul.ftr__social{display:flex;gap:10px;margin-top:22px;list-style:none;padding:0}
.ftr ul.ftr__social a{
  display:grid;place-items:center;width:40px;height:40px;border-radius:50%;
  color:#c6d8e6;border:1px solid rgba(255,255,255,.16);
  transition:color .25s,border-color .25s,background .25s,transform .25s var(--ease-out)}
.ftr ul.ftr__social a:hover{
  color:var(--gold);border-color:rgba(234,183,109,.55);
  background:rgba(234,183,109,.09);transform:translateY(-2px)}
.ftr ul.ftr__social a:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

/* scroll progress */
.skip{position:absolute;left:-9999px;top:8px;z-index:999;width:1px;height:1px;overflow:hidden}
.skip:focus{left:8px;width:auto;height:auto;overflow:visible}
.prog{position:fixed;top:0;left:0;height:2px;background:var(--gold);z-index:200;
  transform-origin:left;transform:scaleX(0);width:100%}

/* =====================  responsive  ===================== */

@media (max-width:1080px){
  .nav{display:none}
  .burger{display:flex}
  .hdr .btn{display:none}
  .mega{display:none!important}
  .gal{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:820px){
  .hero__grid{grid-template-columns:1fr}
  .hcard{max-width:520px}
  .tel{display:none}
  .split--rev > *:first-child{order:0}
  .idxrow{grid-template-columns:1fr;gap:6px}
  .idxrow .to,.idxrow .num{display:none}
  .step{grid-template-columns:1fr;gap:8px}
  .specs li{grid-template-columns:1fr;gap:4px}
  .seq__rail{height:400vh}
  .seq__panels{min-height:420px}
}
@media (max-width:760px){
  .ftr__top{grid-template-columns:1fr;gap:32px}
}
@media (max-width:520px){
  .gal{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
  .brand img{height:40px}
}

@media (prefers-reduced-motion:reduce){
  html:focus-within{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important;scroll-behavior:auto!important}
  .js .rv,.js .rise,.js .rvi,.js .rvl{opacity:1!important;transform:none!important;clip-path:none!important}
  .js .lines .ln > span{transform:none!important}
  .js .hero__media img{transform:none!important}
  .wr .w > i{transform:none!important}
  .mq__t{animation:none}
  .seq__rail{height:auto}
  .seq__stick{position:static;height:auto;padding-block:60px}
  .seq__panels{position:static;min-height:0;display:grid;gap:40px}
  .seq__panel{position:static;opacity:1;transform:none}
}

/* no-JS safety: everything visible */
.no-js .rv,.no-js .rise,.no-js .rvi,.no-js .rvl{opacity:1;transform:none;clip-path:none}

/* =====================  AEO answer blocks + utilities  ===================== */
.answer{border-left:2px solid var(--gold);padding:2px 0 2px clamp(18px,2.4vw,26px);margin:0 0 34px;max-width:70ch}
.answer .k{font-size:var(--t-label);letter-spacing:.2em;text-transform:uppercase;font-weight:600;
  color:var(--gold-600);margin:0 0 10px;display:block}
.dark .answer .k{color:var(--gold)}
.answer p{font-size:var(--t-lede);line-height:1.68;color:var(--ink-soft);margin:0}
.dark .answer p{color:#cfe0ec}

.prose{max-width:70ch}
.prose h2{font-family:var(--serif);font-size:clamp(24px,2.9vw,36px);margin:52px 0 16px;color:var(--navy)}
.dark .prose h2{color:#fff}
.prose h3{font-family:var(--sans);font-weight:500;font-size:19px;letter-spacing:-.012em;margin:34px 0 10px;color:var(--navy)}
.dark .prose h3{color:#fff}
.prose p{color:var(--mute);line-height:1.72;font-size:16.5px;margin:0 0 14px }
.dark .prose p{color:#b7cadb}
.prose ul{color:var(--mute);padding-left:20px;line-height:1.8;margin:0 0 1.2em}
.dark .prose ul{color:#b7cadb}
.prose li{margin-bottom:7px}
.prose li::marker{color:var(--gold)}
.prose a{color:var(--navy);text-decoration:none;border-bottom:1px solid var(--gold)}
.dark .prose a{color:#fff}

.pills{display:flex;flex-wrap:wrap;gap:8px;list-style:none;margin:0;padding:0}
.pills li{border:1px solid var(--line);border-radius:999px;padding:8px 16px;font-size:13.5px;color:var(--mute)}
.dark .pills li{border-color:var(--line-dark);color:#b7cadb}
.pills li b{color:var(--navy);font-weight:500}
.dark .pills li b{color:#fff}

.areas{columns:4;column-gap:28px;list-style:none;margin:0;padding:0;font-size:15px}
.areas li{padding:7px 0;color:var(--mute);break-inside:avoid;border-bottom:1px solid var(--line)}
.dark .areas li{color:#b7cadb;border-color:var(--line-dark)}
@media (max-width:900px){.areas{columns:2}}
@media (max-width:480px){.areas{columns:1}}

.headrow{display:flex;justify-content:space-between;align-items:flex-end;gap:26px;flex-wrap:wrap;margin-bottom:clamp(30px,4vw,52px)}
.headrow h2{max-width:19ch}

.status{background:rgba(234,183,109,.14);border:1px solid rgba(234,183,109,.42);border-radius:12px;
  padding:16px 18px;color:#f2e2c8;font-size:14.5px;line-height:1.6;margin-top:6px}


/* ---------- content-page heading rhythm ---------- */
.headrow{ align-items:flex-start }
.measure .h2 + .lede,
.headrow .h2 + .lede,
.prose .h2--sm + p{ margin-top:20px }
.h2--sm{ font-family:var(--serif); font-size:clamp(25px,2.9vw,37px);
         line-height:1.16; letter-spacing:-.02em; color:var(--navy) }
.dark .h2--sm{ color:#fff }

/* ---------- feature / review card ---------- */
.fcard{ padding:30px 28px; border-radius:var(--r-lg);
        background:rgba(255,255,255,.62); border:1px solid rgba(34,64,93,.12);
        box-shadow:0 1px 0 rgba(255,255,255,.9) inset, 0 22px 50px -30px rgba(22,41,60,.35) }
/* a review card is often a <blockquote> or a <figure>, and both carry the
   browser's default 1em 40px margin, which eats 80px out of the card's track */
.fcard{ margin:0 }
.fcard h3{ margin:0 0 12px }
.fcard p{ margin:0; color:var(--mute); font-size:16px; line-height:1.7 }
.fcard .stars{ margin-bottom:14px }
.dark .fcard{ background:rgba(255,255,255,.09); border-color:rgba(255,255,255,.18);
              box-shadow:0 1px 0 rgba(255,255,255,.14) inset, 0 24px 54px -30px rgba(6,18,32,.6) }
.dark .fcard p{ color:#b7cadb }
.dark .fcard h3{ color:#fff }

/* portfolio grid stays two-up on phones so it isn't endless */
@media (max-width:640px){ .gal{ grid-template-columns:repeat(2,minmax(0,1fr)); gap:10px } }
.gal figure[hidden]{ display:none !important }

/* =========================================================================
   Page-composition modifiers
   Named variants of existing components — no inline styles, no overrides.
   ========================================================================= */

/* A band that holds one line of text: normal section padding leaves it
   floating in empty space, so it gets its own, shorter measure. */
.section--tight{ padding-block:clamp(30px,3.4vw,50px) }
.section--tight .headrow{ margin-bottom:0; align-items:center }
/* a heading with a button beside it: centre the two against each other so the
   button sits on the heading rather than floating up by the eyebrow */
.headrow--mid{ align-items:center }

/* Seven service tiles in a single row. At this width a tile is about 160px, so
   the picture squares up and the type steps down; below a laptop it breaks to
   four and then two rather than trying to hold seven. */
.g7{ grid-template-columns:repeat(7,minmax(0,1fr)); gap:clamp(10px,1vw,16px) }
@media (max-width:1180px){ .g7{ grid-template-columns:repeat(4,minmax(0,1fr)) } }
@media (max-width:720px) { .g7{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
.g7 .tilecard__pic{ aspect-ratio:1 }
.g7 .tilecard__b{ padding:13px 13px 15px; gap:4px }
.g7 .tilecard h3{ font-size:14.5px; line-height:1.25 }
.g7 .tilecard .go{ padding-top:9px; font-size:10.5px; letter-spacing:.04em }
@media (max-width:1180px){
  .g7 .tilecard__b{ padding:16px 16px 18px }
  .g7 .tilecard h3{ font-size:16.5px }
  .g7 .tilecard .go{ font-size:12px }
}

/* A band with a photograph behind it, washed right back so the type stays the
   subject. Same construction as the closing CTA's media layer, but light. */
.section--photo{ position:relative; overflow:hidden }
.section--photo > .wrap{ position:relative; z-index:2 }
.section--photo .bandbg{ position:absolute; inset:0; z-index:0 }
.section--photo .bandbg img{ width:100%; height:100%; object-fit:cover }
.section--photo::after{ content:''; position:absolute; inset:0; z-index:1;
  background:linear-gradient(105deg, rgba(219,215,205,.95) 0%,
                             rgba(219,215,205,.9) 45%, rgba(219,215,205,.72) 100%) }

/* Cards sit narrower in a five-up row, so their insides scale down too. */
.g5 .tilecard__b{ padding:16px 16px 18px; gap:5px }
.g5 .tilecard h3{ font-size:16.5px }
.g5 .tilecard .go{ padding-top:10px; font-size:12px }
@media (max-width:1040px){
  .g5 .tilecard__b{ padding:13px 13px 15px }
  .g5 .tilecard h3{ font-size:14.5px }
  .g5 .tilecard .go{ font-size:11px; letter-spacing:.04em }
}

/* A section whose content is short — less air above and below. */
.section--snug{ padding-block:clamp(34px,3.8vw,60px) }

/* Text-led split: a smaller, landscape photo and tighter copy. */
.split--compact{ gap:clamp(24px,3.2vw,56px); align-items:center }
.split--compact figure{ max-width:440px; width:100% }
.split--compact figure img{ aspect-ratio:4/3 }
.split--compact .prose p:last-child{ margin-bottom:0 }

/* Owner's signature line. */
.byline{ display:flex; flex-direction:column; gap:2px; margin-top:38px }
/* Counters between a paragraph and a signature: equal air above and below,
   rather than pinned to the paragraph. */
.measure + .stats{ margin-top:clamp(28px,3.2vw,46px) }
.stats + .byline{ margin-top:clamp(28px,3.2vw,46px) }
.signature{ font-family:var(--script); font-size:clamp(34px,3.4vw,46px);
            line-height:1; color:var(--navy) }
.dark .signature{ color:#fff }
.byline__role{ font-family:var(--sans); font-size:14px; letter-spacing:.04em;
               color:var(--mute) }
.dark .byline__role{ color:#b7cadb }

/* =========================================================================
   Glass sample board — the swatch grid on the Glass Options page
   ========================================================================= */
.swatches{ display:grid; gap:clamp(18px,2.2vw,28px);
           grid-template-columns:repeat(4,1fr) }
@media (max-width:1180px){ .swatches{ grid-template-columns:repeat(3,1fr) } }
@media (max-width:820px) { .swatches{ grid-template-columns:repeat(2,1fr) } }

.swatch{ display:flex; flex-direction:column; background:#fff;
         border:1px solid var(--line); border-radius:14px; overflow:hidden;
         transition:transform .4s var(--ease-out), box-shadow .4s var(--ease-out),
                    border-color .4s var(--ease-out) }
.swatch:hover{ transform:translateY(-4px);
               box-shadow:0 26px 50px -30px rgba(22,41,60,.45);
               border-color:rgba(34,64,93,.24) }
.swatch__pic{ aspect-ratio:1; overflow:hidden; background:var(--tile) }
.swatch__pic img{ width:100%; height:100%; object-fit:cover; display:block;
                  transition:transform 1.1s var(--ease-out) }
.swatch:hover .swatch__pic img{ transform:scale(1.04) }
.swatch__b{ padding:20px 20px 24px; display:flex; flex-direction:column; gap:9px }
.swatch__b h3{ font-family:var(--sans); font-size:17px; font-weight:500;
               letter-spacing:-.014em; line-height:1.3; color:var(--navy) }
.swatch__b p{ margin:0; font-size:14.5px; line-height:1.68; color:var(--mute) }

/* Family label above each run of swatches. */
.family{ display:flex; align-items:baseline; gap:16px; margin-bottom:24px }
.family h2{ font-family:var(--serif); font-size:clamp(25px,2.7vw,36px);
            color:var(--navy); letter-spacing:-.02em }
.family__rule{ flex:1; height:1px; background:var(--line) }
.family__n{ font-size:13px; letter-spacing:.14em; text-transform:uppercase;
            color:var(--gold-600); font-weight:600 }

/* Specification note — small, factual, sits under the intro. */
.specnote{ display:flex; flex-wrap:wrap; gap:10px 28px; align-items:baseline;
           margin-top:30px; padding-top:22px; border-top:1px solid var(--line) }
.specnote dt{ font-size:12px; letter-spacing:.16em; text-transform:uppercase;
              color:var(--gold-600); font-weight:600; margin:0 }
.specnote dd{ margin:0; font-size:15.5px; color:var(--mute); line-height:1.6 }
.specnote b{ color:var(--navy); font-weight:500 }

/* -------------------------------------------------------------------------
   Glass Options additions
   ------------------------------------------------------------------------- */

/* Intro copy runs the full width in two columns rather than one narrow
   column with dead space beside it. */
.intro-wide{ max-width:none }
@media (min-width:900px){
  .intro-wide > .lede{ max-width:none }
  /* One paragraph flows into two columns. */
  .intro-wide:not(:has(> .lede ~ .lede)) > .lede{ columns:2; column-gap:clamp(40px,4vw,72px) }
  /* Two or more sit side by side rather than flowing across each other. */
  .intro-wide:has(> .lede ~ .lede){
    display:grid; grid-template-columns:1fr 1fr; gap:clamp(30px,3.4vw,64px);
  }
}

/* Swatch descriptions are clamped so every card in a row is the same height;
   the toggle drops the full text down. */
.swatch__b p{
  display:-webkit-box; -webkit-box-orient:vertical;
  -webkit-line-clamp:6; overflow:hidden;
}
.swatch.is-open .swatch__b p{ -webkit-line-clamp:none; overflow:visible }

.swatch__more{
  align-self:flex-start; margin-top:2px; padding:0; border:0; background:none;
  font-family:var(--sans); font-size:12.5px; font-weight:600; letter-spacing:.06em;
  text-transform:uppercase; color:var(--navy); cursor:pointer;
  display:inline-flex; align-items:center; gap:7px;
}
.swatch__more:hover{ color:var(--gold-600) }
.swatch__more i{ font-style:normal; transition:transform .3s var(--ease-out) }
.swatch.is-open .swatch__more i{ transform:rotate(180deg) }
/* No toggle needed when the copy already fits. */
.swatch__more[hidden]{ display:none }

/* The "ask us" tile that closes a family row. */
.swatch--ask{ text-decoration:none; color:inherit; justify-content:center;
              align-items:center; text-align:center; padding:34px 26px;
              background:var(--tile); border-style:dashed;
              border-color:rgba(34,64,93,.26) }
.swatch--ask:hover{ background:#fff; border-color:var(--gold) }
.swatch--ask h3{ font-family:var(--serif); font-size:22px; line-height:1.25;
                 color:var(--navy); margin:0 0 14px; max-width:15ch }
.swatch--ask .plus{ font-family:var(--serif); font-size:40px; line-height:1;
                    color:var(--gold); display:block; margin-bottom:16px }
.swatch--ask .go{ font-size:12.5px; font-weight:600; letter-spacing:.06em;
                  text-transform:uppercase; color:var(--navy);
                  display:inline-flex; gap:8px; align-items:center }
.swatch--ask .go span{ transition:transform .34s var(--ease-out) }
.swatch--ask:hover .go span{ transform:translateX(5px) }

/* =========================================================================
   "Why choose" feature band
   A dark section so the glass cards read as glass, with a numbered sequence.
   ========================================================================= */
.why__head{ display:grid; gap:clamp(18px,3vw,56px); align-items:end;
            margin-bottom:clamp(34px,4vw,58px) }
/* Two columns only when the section actually carries an intro paragraph. */
@media (min-width:920px){
  .why__head:has(.lede){ grid-template-columns:minmax(0,1fr) minmax(0,1.15fr) }
}
.why__head h2{ max-width:20ch }
.why__head .lede{ max-width:60ch; margin:0 }

.why__grid{ display:grid; gap:clamp(14px,1.6vw,22px);
            grid-template-columns:repeat(4,1fr) }
@media (max-width:1100px){ .why__grid{ grid-template-columns:repeat(2,1fr) } }
@media (max-width:560px) { .why__grid{ grid-template-columns:1fr } }

.why__item{ padding:clamp(24px,2.2vw,32px) clamp(20px,1.9vw,28px);
            border-radius:var(--r-lg); display:flex; flex-direction:column }
.why__crown{ width:clamp(34px,3.2vw,44px); height:auto; display:block;
             margin-bottom:clamp(16px,1.6vw,22px) }
.why__item h3{ font-family:var(--sans); font-size:17.5px; font-weight:500;
               letter-spacing:-.014em; line-height:1.3; color:#fff; margin:0 0 10px }
.why__item p{ font-size:15px; line-height:1.7; color:#b7cadb; margin:0 }

/* =========================================================================
   Descender fix
   The reveal animations mask each line (.lines) and each word (.wr) with
   overflow:hidden, which cropped the tails of g, y, p and j. Each mask now
   carries room below the baseline, pulled back by an equal negative margin so
   nothing moves, and the hidden start position is pushed past the taller mask.
   ========================================================================= */
.lines .ln{ padding-bottom:.18em; margin-bottom:-.18em }
.lines .ln > span{ transform:translateY(132%) }
.wr .w{ padding-bottom:.2em; margin-bottom:-.2em }
.wr .w > i{ transform:translateY(132%) }

/* A "why choose" band with no intro paragraph centres on its heading. */
.why__head:not(:has(.lede)){ justify-items:center; text-align:center }
.why__head:not(:has(.lede)) h2{ max-width:none }

/* =========================================================================
   Shower door configurations
   Same square format as the glass swatches, so the two read as one system.
   The renderings carry their own transparency and sit on the tile ground.
   ========================================================================= */
.configs{ display:grid; gap:clamp(16px,1.8vw,26px);
          grid-template-columns:repeat(3,1fr) }
@media (max-width:980px){ .configs{ grid-template-columns:repeat(2,1fr) } }
@media (max-width:560px){ .configs{ grid-template-columns:1fr } }
/* A row of four: three layouts plus the closing & More tile. */
@media (min-width:981px){ .configs--4{ grid-template-columns:repeat(4,1fr) } }

.config{ display:flex; flex-direction:column; background:#fff;
         border:1px solid var(--line); border-radius:14px; overflow:hidden;
         transition:transform .4s var(--ease-out), box-shadow .4s var(--ease-out),
                    border-color .4s var(--ease-out) }
.config:hover{ transform:translateY(-4px);
               box-shadow:0 26px 50px -30px rgba(22,41,60,.45);
               border-color:rgba(34,64,93,.24) }
/* The square is carried by the image itself. A percentage height here cannot
   resolve against an auto-sized row, so each rendering used to stretch its own
   card to its own aspect ratio and the titles fell out of line. */
.config__pic{ background:var(--tile); padding:14px }
.config__pic img{ display:block; width:100%; height:auto; aspect-ratio:1; object-fit:contain;
                  transition:transform 1s var(--ease-out) }
.config:hover .config__pic img{ transform:scale(1.04) }
.config__b{ padding:20px 22px 24px }
.config__b h3{ font-family:var(--sans); font-size:17px; font-weight:500;
               letter-spacing:-.014em; color:var(--navy); margin:0 0 8px }
.config__b p{ margin:0; font-size:14.5px; line-height:1.68; color:var(--mute) }

/* The card that closes the grid: no rendering, an invitation instead. */
.config--more{ background:var(--tile); border-style:dashed;
               border-color:rgba(34,64,93,.26); justify-content:center;
               text-align:center; padding:34px 28px; text-decoration:none; color:inherit }
.config--more:hover{ background:#fff; border-color:var(--gold) }
.config--more h3{ font-family:var(--serif); font-size:23px; color:var(--navy);
                  margin:0 0 12px }
.config--more p{ font-size:15px; line-height:1.7; color:var(--mute); margin:0 0 16px }
.config--more .go{ font-size:12.5px; font-weight:600; letter-spacing:.06em;
                   text-transform:uppercase; color:var(--navy);
                   display:inline-flex; gap:8px; align-items:center }
.config--more .go span{ transition:transform .34s var(--ease-out) }
.config--more:hover .go span{ transform:translateX(5px) }

/* ---------- photo rail ----------
   A real horizontal scroller that also drifts on its own. Making it a genuine
   scroller rather than an animated track is what buys the swipe on a phone,
   the wheel and the draggable bar on a desktop: all of that is the browser's,
   not ours. The script adds the drift on top and gets out of the way the
   moment anyone touches it. The photographs are carried twice so the drift can
   wrap without a seam, and the second set is hidden from screen readers. */
.marquee{ overflow-x:auto; overflow-y:hidden; touch-action:pan-x;
          overscroll-behavior-x:contain;
          --rail-gap:clamp(14px,1.6vw,22px);
          /* the native bar is hidden: on a Mac it is an overlay that fades out,
             which is no use as a handle, so the script draws its own below */
          scrollbar-width:none }
.marquee::-webkit-scrollbar{ display:none }
.marquee__track{ display:flex; align-items:start; gap:var(--rail-gap); width:max-content }
.marquee figure{ margin:0; flex:0 0 clamp(195px,18vw,265px) }

/* The position bar. Built by script, so it only appears where it works, and it
   is placed outside the scroller so it stays put while the strip moves under
   it. Click anywhere on it to jump, or drag the thumb. */
.marquee__bar{ position:relative; height:6px; border-radius:99px; cursor:pointer;
               background:rgba(34,64,93,.13); margin-top:clamp(16px,1.6vw,22px);
               touch-action:none }
.marquee__bar i{ position:absolute; top:0; bottom:0; left:0; width:24%;
                 border-radius:99px; background:var(--gold);
                 transition:background .3s var(--ease) }
.marquee__bar:hover i, .marquee__bar.is-held i{ background:var(--gold-600) }
.dark .marquee__bar{ background:rgba(255,255,255,.17) }

/* drag anywhere on the strip with a mouse; touch keeps the native swipe */
.js .marquee{ cursor:grab }
.js .marquee.is-dragging{ cursor:grabbing; scroll-behavior:auto }
.js .marquee.is-dragging img{ pointer-events:none }
.marquee img{ display:block; width:100%; height:auto; aspect-ratio:3/4; object-fit:cover;
              border-radius:13px }
.marquee figcaption{ font-family:var(--serif); font-style:italic; font-size:14px;
                     line-height:1.56; color:var(--mute); margin-top:12px; padding-top:11px;
                     border-top:1px solid var(--line) }
/* A photograph opened full size. Built by script, so the zoom cursor only
   appears where the script is running. */
.lightbox{ position:fixed; inset:0; z-index:200; display:grid; place-items:center;
           padding:clamp(14px,4vw,52px); background:rgba(12,28,46,.93);
           opacity:0; visibility:hidden; cursor:zoom-out;
           transition:opacity .28s var(--ease-out), visibility .28s }
.lightbox.is-open{ opacity:1; visibility:visible }
.lightbox img{ max-width:100%; max-height:100%; width:auto; height:auto; border-radius:10px;
               box-shadow:0 40px 90px -30px rgba(0,0,0,.7) }
.js .marquee img{ cursor:zoom-in }

@media (max-width:720px){
  .marquee figure{ flex-basis:clamp(210px,62vw,260px) }
}

/* ---------- mirrors page ---------- */
/* A wide photograph carried across a section, above the copy it introduces. */
.banner{ margin:clamp(26px,3vw,40px) 0 0 }
.banner img{ display:block; width:100%; height:auto; aspect-ratio:2/1; object-fit:cover;
             border-radius:var(--r-lg) }
@media (max-width:640px){ .banner img{ aspect-ratio:3/2 } }

/* Manufacturer specification, set below the body copy it follows. */
.fine{ margin:0; font-size:14px; line-height:1.7; color:var(--mute);
       padding-top:16px; border-top:1px solid var(--line) }
.dark .fine{ color:#a3b9cc }

/* An application card carries a photograph rather than a rendering, so the
   picture fills its box instead of sitting contained on the tile ground. */
.config--photo .config__pic{ padding:0 }
.config--photo .config__pic img{ aspect-ratio:3/2; object-fit:cover }

/* Square swatch rail: the antique mirror finishes. Same mechanism as the photo
   rail, with a square crop and a named caption so a finish can be read by name. */
.marquee--sw figure{ flex:0 0 clamp(186px,16.5vw,238px) }
.marquee--sw img{ aspect-ratio:1 }
.marquee--sw figcaption b{ display:block; font-family:var(--sans); font-style:normal;
                           font-weight:500; font-size:14.5px; letter-spacing:-.012em;
                           color:var(--navy); margin-bottom:5px }

/* Three reasons rather than four. */
@media (min-width:1101px){ .why__grid--3{ grid-template-columns:repeat(3,1fr) } }

/* =========================================================================
   Meet the team
   The cards sit on the navy band and reuse .glass, so they pick up the same
   translucency and the pointer sheen the rest of the site already wires up.
   They hold still until the pointer reaches one, and then lift. The lift lives
   on the card and the reveal lives on a wrapper around it, so the two
   transforms never fight over the same element.
   ========================================================================= */
.people{ display:grid; gap:clamp(18px,2.2vw,30px);
         grid-template-columns:repeat(3,minmax(0,1fr)) }
@media (max-width:1000px){ .people{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
@media (max-width:620px) { .people{ grid-template-columns:minmax(0,1fr) } }

.person{ height:100%; padding:clamp(22px,2.1vw,30px); display:flex; flex-direction:column;
         transition:transform .45s var(--ease-out), box-shadow .45s var(--ease-out) }
.person:hover{ transform:translateY(-4px);
               box-shadow:0 1px 0 rgba(255,255,255,.3) inset, 0 40px 70px -32px rgba(6,18,32,.85) }
@media (prefers-reduced-motion:reduce){ .person{ transition:none } }

.person__pic{ width:92px; height:92px; border-radius:16px; overflow:hidden; margin-bottom:18px;
              background:rgba(255,255,255,.1); border:1px solid rgba(255,255,255,.22);
              flex:0 0 auto }
.person__pic img{ display:block; width:100%; height:100%; object-fit:cover }
/* no headshot yet: the crown stands in, sized to sit inside the same frame */
.person__pic--crown{ display:grid; place-items:center }
.person__pic--crown img{ width:54%; height:auto; object-fit:contain }
.person h3{ font-family:var(--sans); font-size:17.5px; font-weight:500; letter-spacing:-.014em;
            color:#fff; margin:0 }
.person__role{ font-family:var(--serif); font-style:italic; font-size:14.5px; color:var(--gold);
               margin:5px 0 14px }
.person p:not(.person__role){ margin:0; font-size:14.5px; line-height:1.72; color:#b7cadb }
/* matches the specificity of the rule above, which otherwise wins and closes the gap */
.person p:not(.person__role) + p{ margin-top:12px }

/* Body copy set across the full page rather than in a narrow left column. Two
   columns on a wide screen keeps the line length readable while the text still
   reaches the right edge; a paragraph is never split between them. */
.cols2{ columns:2; column-gap:clamp(34px,4.5vw,72px) }
.cols2 > p{ margin-top:0; break-inside:avoid }
.cols2 > p + p{ margin-top:1.15em }
@media (max-width:860px){ .cols2{ columns:1 } }

/* =========================================================================
   Hardware finishes
   Every chip is the same knob photographed in a different finish, so they are
   set small and tight and read as a palette rather than a product grid: eight
   across a desktop, four across a phone.
   ========================================================================= */
/* minmax(0,…) rather than 1fr: a grid track's automatic minimum is the intrinsic
   width of what sits in it, so the 320px chip images would otherwise hold every
   column open and push the whole row off a phone screen. */
.finishes{ display:grid; gap:clamp(11px,1.3vw,19px);
           grid-template-columns:repeat(8,minmax(0,1fr)) }
@media (max-width:1100px){ .finishes{ grid-template-columns:repeat(6,minmax(0,1fr)) } }
@media (max-width:760px) { .finishes{ grid-template-columns:repeat(4,minmax(0,1fr)) } }
.finish{ margin:0; text-align:center; min-width:0 }   /* figure carries a 40px UA margin */
.finish img{ display:block; width:100%; height:auto; aspect-ratio:1; object-fit:contain;
             background:#fff; border:1px solid var(--line); border-radius:12px; padding:6%;
             transition:transform .4s var(--ease-out), border-color .4s var(--ease-out),
                        box-shadow .4s var(--ease-out) }
.finish:hover img{ transform:translateY(-4px); border-color:var(--gold);
                   box-shadow:0 16px 30px -20px rgba(22,41,60,.5) }
.finish b{ display:block; font-family:var(--sans); font-weight:500; font-size:13px;
           line-height:1.4; letter-spacing:-.008em; color:var(--navy); margin-top:10px }
@media (max-width:560px){ .finish b{ font-size:11.5px } }

/* The rest of the range, behind a native disclosure. No script is involved, so
   it opens the same way with JavaScript off and the label swaps on [open]. */
.more{ margin-top:clamp(24px,2.6vw,34px) }
.more > summary{ list-style:none; cursor:pointer; display:inline-flex; align-items:center; gap:10px;
                 font-size:12.5px; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
                 color:var(--navy); background:transparent;
                 border:1px solid var(--line); border-radius:999px; padding:11px 22px;
                 transition:border-color .3s var(--ease), color .3s var(--ease) }
.more > summary::-webkit-details-marker{ display:none }
.more > summary::marker{ content:"" }
.more > summary:hover{ border-color:var(--gold); color:var(--gold-600) }
.more > summary i{ font-style:normal; font-size:10px; transition:transform .3s var(--ease-out) }
.more[open] > summary i{ transform:rotate(180deg) }
.more .lbl-open{ display:none }
.more[open] .lbl-open{ display:inline }
.more[open] .lbl-shut{ display:none }
.more__b{ margin-top:clamp(22px,2.4vw,32px) }


/* ---------- numbered process steps ---------- */
.steps2{ display:grid; gap:clamp(18px,2vw,32px); counter-reset:step;
         grid-template-columns:repeat(auto-fit,minmax(230px,1fr)) }
.step2{ border-top:2px solid var(--gold); padding-top:20px; counter-increment:step }
.step2 h3{ font-family:var(--sans); font-size:17px; font-weight:500; color:var(--navy);
           margin:0 0 9px }
.step2 h3::before{ content:counter(step,decimal-leading-zero);
                   font-family:var(--serif); font-size:15px; color:var(--gold-600);
                   display:block; margin-bottom:8px; letter-spacing:.08em }
.step2 p{ margin:0; font-size:15px; line-height:1.7; color:var(--mute) }
/* Beside a photograph the steps run down the column rather than across it:
   auto-fit would otherwise break three steps into two uneven rows. */
.split .steps2{ grid-template-columns:minmax(0,1fr); gap:clamp(16px,1.8vw,24px) }
.dark .step2 h3{ color:#fff } .dark .step2 p{ color:#b7cadb }
/* Five steps: one row on a wide screen, rather than four and an orphan. */
@media (min-width:1100px){ .steps2--5{ grid-template-columns:repeat(5,minmax(0,1fr)) } }
/* A step already completed (the thank-you page ticks off step one). */
.step2--done{ border-top-color:var(--azure) }
.step2--done h3::before{ content:"\2713  Done"; font-family:var(--sans); font-size:13px;
                         font-weight:600; color:var(--azure); letter-spacing:.12em; text-transform:uppercase }

/* ---------- price band ---------- */
.price{ display:grid; gap:clamp(24px,3.4vw,58px); align-items:start }
@media (min-width:900px){ .price{ grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr) } }
.price__fig{ font-family:var(--serif); font-size:clamp(38px,5vw,70px); line-height:1;
             color:var(--navy); margin:0 0 10px }
.price__note{ font-size:14px; letter-spacing:.06em; text-transform:uppercase;
              color:var(--gold-600); font-weight:600; margin:0 }

/* ---------- questions ---------- */
.qa{ border-top:1px solid var(--line) }
.qa__item{ border-bottom:1px solid var(--line); padding:clamp(20px,2.2vw,28px) 0;
           display:grid; gap:10px clamp(28px,4vw,64px) }
@media (min-width:860px){ .qa__item{ grid-template-columns:minmax(0,1fr) minmax(0,1.5fr) } }
.qa__item h3{ font-family:var(--sans); font-size:17.5px; font-weight:500;
              letter-spacing:-.014em; line-height:1.4; color:var(--navy); margin:0 }
.qa__item p{ margin:0; font-size:16px; line-height:1.75; color:var(--mute) }
/* The same two-column rows, numbered, for a short run of reasons where the
   order is part of the point. Distinguishes them from the questions list on
   the same page without inventing a second layout. */
.qa--num{ counter-reset:reason }
.qa--num .qa__item{ counter-increment:reason }
.qa--num .qa__item h3::before{ content:counter(reason,decimal-leading-zero);
                               font-family:var(--serif); font-size:15px; color:var(--gold-600);
                               display:block; margin-bottom:9px; letter-spacing:.08em }

/* =========================================================================
   Services directory
   A card per service: photograph, summary, the sub-types as pills, and a
   button on the bottom edge so a row lines up however unevenly copy wraps.
   The card is not itself a link — the button is — so nothing nests.
   ========================================================================= */
.svcs{ display:grid; gap:clamp(18px,2.2vw,30px);
       grid-template-columns:repeat(3,minmax(0,1fr)) }
.svcs--4{ grid-template-columns:repeat(4,minmax(0,1fr)) }
.svcs--2{ grid-template-columns:repeat(2,minmax(0,1fr)) }
/* One card per row, read left to right: photograph, then the words. A row of
   upright cards makes the reader scan down nine columns of text; stacked rows
   put every title in the same place down the left edge. */
.svcs--1{ grid-template-columns:minmax(0,1fr); gap:clamp(14px,1.5vw,20px) }
@media (max-width:1040px){
  .svcs, .svcs--4{ grid-template-columns:repeat(2,minmax(0,1fr)) }
  /* re-asserted after the line above, which also matches a stacked row */
  .svcs--1{ grid-template-columns:minmax(0,1fr) }
}
@media (max-width:660px){
  .svcs, .svcs--4, .svcs--2{ grid-template-columns:minmax(0,1fr) }
}

.svc{ display:flex; flex-direction:column; margin:0; background:#fff;
      border:1px solid var(--line); border-radius:14px; overflow:hidden;
      transition:transform .45s var(--ease-out), box-shadow .45s var(--ease-out),
                 border-color .4s var(--ease-out) }
.svc:hover{ transform:translateY(-4px);
            box-shadow:0 26px 50px -30px rgba(22,41,60,.45);
            border-color:rgba(34,64,93,.24) }
.svc__pic{ aspect-ratio:4/3; overflow:hidden; background:var(--tile) }
.svc__pic img{ width:100%; height:100%; object-fit:cover;
               transition:transform 1.1s var(--ease-out) }
.svc:hover .svc__pic img{ transform:scale(1.05) }
/* A wide card turns on its side: the photograph fills the card's height on the
   left rather than being cropped to a thin band across the top. The min-height
   keeps a short card from squeezing its photograph into a letterbox. */
@media (min-width:860px){
  .svcs--2 .svc, .svcs--1 .svc{ display:grid; align-items:stretch }
  .svcs--2 .svc{ grid-template-columns:minmax(0,.44fr) minmax(0,.56fr) }
  .svcs--1 .svc{ grid-template-columns:minmax(0,.3fr) minmax(0,.7fr); min-height:216px }
  /* The photograph must not set the row's height: a 540x720 source stretched
     the card to 414px and left the body half empty. Taking the image out of
     the flow leaves the words in charge of how tall the card is. */
  .svcs--2 .svc__pic, .svcs--1 .svc__pic{ aspect-ratio:auto; height:auto; position:relative }
  .svcs--2 .svc__pic img, .svcs--1 .svc__pic img{ position:absolute; inset:0 }
  /* a paragraph set across 800px is a tiring line length */
  .svcs--1 .svc__b{ padding:clamp(22px,2.1vw,30px) }
  .svcs--1 .svc__b p{ max-width:72ch }
}
.svc__b{ padding:clamp(20px,1.9vw,27px); display:flex; flex-direction:column;
         flex:1; gap:13px }
.svc__b h3{ font-family:var(--sans); font-size:19px; font-weight:500;
            letter-spacing:-.015em; line-height:1.3; color:var(--navy); margin:0 }
.svc__b p{ margin:0; font-size:15px; line-height:1.7; color:var(--mute) }
.svc__list{ list-style:none; margin:0; padding:0; display:flex;
            flex-wrap:wrap; gap:6px }
.svc__list li{ font-size:12.5px; line-height:1.4; color:var(--mute);
               border:1px solid var(--line); border-radius:999px; padding:5px 11px }
.svc .btn{ align-self:flex-start; margin-top:auto; padding:12px 22px; font-size:13.5px }
/* Stacked below the side-by-side breakpoint: the photograph sits on top, and a
   4:3 crop on ten full-width cards is a very long scroll, so it runs shallower. */
@media (max-width:859px){
  .svcs--1 .svc__pic{ aspect-ratio:16/9 }
}

/* =========================================================================
   Contact
   The form is the page, so it gets the wider column and the dark ground the
   field styles were written for. On a light band the inputs are white text on
   white, which is how the first pass of this page was quietly broken.
   ========================================================================= */
/* stretch, not start: the panel beside the form runs the full height of it, so
   the two columns finish on the same line instead of leaving a dead corner. The
   heading sits above the grid rather than inside the left column, which is what
   lets both columns begin level without guessing how tall the heading is. */
.contactgrid{ display:grid; gap:clamp(30px,3.6vw,60px); align-items:stretch;
              grid-template-columns:minmax(0,1.55fr) minmax(0,1fr);
              margin-top:clamp(22px,2.4vw,34px) }
@media (max-width:900px){ .contactgrid{ grid-template-columns:minmax(0,1fr) } }

.field input[type=file]{ padding:11px 13px; font-size:14px; color:#cfe0ec; cursor:pointer }
.field input[type=file]::file-selector-button{
  margin-right:13px; padding:8px 15px; border-radius:999px; cursor:pointer;
  border:1px solid rgba(255,255,255,.22); background:rgba(255,255,255,.08);
  color:#fff; font-family:var(--sans); font-size:13px; font-weight:500;
  transition:background .25s }
.field input[type=file]::file-selector-button:hover{ background:rgba(255,255,255,.16) }
.field .hint{ font-size:12.5px; color:#8ba3b8; letter-spacing:0; text-transform:none;
              font-weight:300; margin:0 }

/* the ways to reach a person, beside the form. One panel split by hairlines
   rather than four separate boxes, and the four blocks share whatever height is
   left over, so the panel always finishes level with the form. space-between
   would bunch the content at the two ends on a short form; giving each block an
   equal share of the slack keeps the rhythm even at any height. */
.reach{ display:flex; flex-direction:column; padding:0; overflow:hidden;
        border-radius:var(--r-lg) }
.reach__item{ flex:1 1 0; display:flex; flex-direction:column; justify-content:center;
              padding:clamp(20px,2vw,26px) clamp(22px,2.2vw,28px);
              border-bottom:1px solid rgba(255,255,255,.12) }
.reach__item:last-child{ border-bottom:0 }
.reach__item .k{ font-size:var(--t-label); letter-spacing:.2em; text-transform:uppercase;
                 color:var(--gold); font-weight:600; margin:0 0 9px }
.reach__item p{ margin:0; font-size:16px; line-height:1.6; color:#cfe0ec }
.reach__item a{ color:#fff; text-decoration:none; border-bottom:1px solid rgba(234,183,109,.55) }
.reach__item a:hover{ border-bottom-color:var(--gold) }
.reach__big{ font-family:var(--serif); font-size:clamp(25px,2.6vw,33px); line-height:1.1 }
.reach__big a{ border:0 }
.reach__sub{ font-size:13.5px!important; color:#93aabe!important; margin-top:7px!important }
/* stacked below the form on a phone, where equal-height blocks would only add
   empty space to a column that is already as tall as it needs to be */
@media (max-width:900px){ .reach__item{ flex:0 0 auto } }

/* =========================================================================
   Service areas
   Towns we cover are listed as pills. A town with a page of its own is a
   linked pill; the rest are plain text, because naming a town we serve is
   useful to a reader whether or not it has somewhere to click through to.
   ========================================================================= */
.pills li a{ text-decoration:none; color:var(--navy); font-weight:500;
             display:inline-flex; align-items:center; gap:7px }
.pills li:has(a){ border-color:rgba(34,64,93,.3); background:#fff;
                  transition:transform .3s var(--ease-out), box-shadow .3s var(--ease-out),
                             border-color .3s var(--ease-out) }
.pills li:has(a):hover{ transform:translateY(-2px); border-color:var(--gold);
                        box-shadow:0 12px 24px -16px rgba(22,41,60,.5) }
.pills li a::after{ content:'\2192'; color:var(--gold-600); font-size:12px;
                    transition:transform .3s var(--ease-out) }
.pills li:has(a):hover a::after{ transform:translateX(3px) }

.areaset + .areaset{ margin-top:clamp(40px,4.4vw,68px) }
.areaset .family{ margin-bottom:18px }
.areaset p{ max-width:68ch; margin:0 0 20px; color:var(--mute);
            font-size:clamp(15.5px,1.12vw,17px); line-height:1.75 }

/* =========================================================================
   City pages
   One or two photographs from the town itself, shown large rather than hidden
   in a scroller: when a page only has two pieces of genuinely local proof,
   the proof should be the biggest thing on it.
   ========================================================================= */
.local{ display:grid; gap:clamp(16px,1.8vw,26px);
        grid-template-columns:repeat(auto-fit,minmax(min(100%,290px),1fr)) }
.local figure{ margin:0 }
.local img{ width:100%; height:auto; aspect-ratio:3/4; object-fit:cover;
            border-radius:var(--r-lg) }
/* A single photograph runs beside the words rather than alone across the page. */
.local--one{ grid-template-columns:minmax(0,1fr) }
@media (min-width:860px){ .local--one{ max-width:440px } }
/* four stills auto-fit into a row of three and a lone orphan, which reads as a
   mistake. Two columns gives a square block instead */
.local--4{ max-width:780px }
@media (min-width:860px){ .local--4{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
.local figcaption{ font-family:var(--serif); font-style:italic; font-size:14px;
                   color:var(--mute); padding-top:12px 
}
.dark .local figcaption{ color:#a3b9cc }

/* =========================================================================
   Blog articles
   The shared .prose styles carry headings, paragraphs and lists. What a long
   article adds is a data table, in-body photographs, and the configuration
   strip under the price table.
   ========================================================================= */
/* a long read sits centred in the column rather than hard against its left
   edge, which looks lopsided in a 1240px wrap */
.article{ max-width:76ch; margin-inline:auto }
.article > h2:first-child,
.article > p:first-child{ margin-top:0 }
/* the opening paragraph is the answer to the question in the title, so it is
   given the weight of a lede rather than of body copy */
.article > p:first-of-type{ font-size:var(--t-lede); line-height:1.7; color:var(--ink-soft) }
.article strong{ color:var(--navy); font-weight:600 }

/* a table of numbers people scan down */
.tablewrap{ margin:clamp(26px,3vw,38px) 0; overflow-x:auto;
            border:1px solid var(--line); border-radius:var(--r-lg); background:#fff }
.dtable{ width:100%; border-collapse:collapse; font-size:15.5px; min-width:560px }
.dtable th, .dtable td{ text-align:left; padding:14px clamp(14px,1.5vw,20px);
                        border-bottom:1px solid var(--line); vertical-align:top }
.dtable thead th{ font-family:var(--sans); font-size:12px; font-weight:600;
                  letter-spacing:.12em; text-transform:uppercase; color:var(--gold-700);
                  background:var(--tile); border-bottom:1px solid rgba(34,64,93,.2) }
.dtable tbody tr:last-child td{ border-bottom:0 }
.dtable tbody td:first-child{ color:var(--navy); font-weight:500 }
/* the money column: tabular figures so the ranges line up down the page */
.dtable tbody td:nth-child(2){ color:var(--navy); font-weight:500; white-space:nowrap;
                               font-variant-numeric:tabular-nums }
@media (max-width:620px){ .dtable{ font-size:14.5px } }

/* a photograph inside the article */
.artfig{ margin:clamp(26px,3vw,38px) 0 }
/* nearly every project photograph is portrait, and a full-width portrait in a
   76ch column is taller than the screen. Cap the height and let the width
   follow, so the picture illustrates the section instead of interrupting it. */
.artfig img{ width:auto; max-width:100%; max-height:560px; height:auto;
             border-radius:var(--r-lg); display:block; margin-inline:auto }
.artfig figcaption{ text-align:center }
/* a hardware knob or a glass sample is a small subject photographed close up;
   at the same size as a room shot it dominates a section it only illustrates */
.artfig--sm img{ max-height:300px; border-radius:12px }
.artfig figcaption{ font-family:var(--serif); font-style:italic; font-size:14px;
                    color:var(--mute); padding-top:11px }

/* the configuration drawings, as a key to the table above them */
.configstrip{ display:grid; gap:clamp(12px,1.4vw,20px); margin:clamp(24px,2.8vw,34px) 0;
              grid-template-columns:repeat(3,minmax(0,1fr)) }
@media (max-width:640px){ .configstrip{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
.configstrip figure{ margin:0 }
/* the drawings differ in aspect ratio, so a fixed box keeps the captions on
   one line across the row */
.configstrip img{ width:100%; height:auto; aspect-ratio:4/3; object-fit:contain;
                  display:block; background:var(--tile); padding:6px;
                  border:1px solid var(--line); border-radius:12px }
.configstrip figcaption{ font-size:13px; color:var(--mute); padding-top:9px; line-height:1.4 }

/* =========================================================================
   Portfolio filters
   Two rows: the category, then that category's own options. The second row is
   deliberately quieter than the first so the hierarchy reads at a glance
   rather than looking like sixteen equal choices.
   ========================================================================= */
.filters button i{ font-style:normal; font-size:11.5px; opacity:.6;
                   font-variant-numeric:tabular-nums; margin-left:3px }
.filters button[aria-pressed="true"] i{ opacity:.75 }

.subwrap{ margin:-18px 0 30px }
.subfilters{ display:flex; gap:7px; flex-wrap:wrap; align-items:center;
             padding:14px 0 2px; border-top:1px solid var(--line) }
.subfilters[hidden]{ display:none }
.subfilters button{ border:1px solid transparent; background:transparent;
                    color:var(--mute); padding:6px 13px; border-radius:999px;
                    font-size:13px; cursor:pointer;
                    transition:color .25s var(--ease), background .25s var(--ease) }
.subfilters button:hover{ color:var(--navy); background:rgba(34,64,93,.05) }
.subfilters button[aria-pressed="true"]{ background:rgba(34,64,93,.08);
                                         color:var(--navy); font-weight:500 }
.subfilters button i{ font-style:normal; font-size:11px; opacity:.55;
                      font-variant-numeric:tabular-nums; margin-left:3px }

.galcount{ margin:0 0 20px; font-size:13.5px; color:var(--mute);
           letter-spacing:.02em }
.galcount[hidden]{ display:none }

/* the spam trap on the quote form: off-screen rather than display:none, since
   some bots skip anything that is hidden outright */
.hpot{ position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden }

/* ---------------------------------------------------------------------------
   Lightbox
   Deliberately not edge-to-edge: the photograph opens a good deal larger than
   its tile and stops there, so it reads as a closer look rather than a mode
   change. It walks whatever the filter is currently showing, not the whole
   library, so narrowing to "Over a Tub" and swiping stays inside those.
   --------------------------------------------------------------------------- */
.lb{position:fixed;inset:0;z-index:300;display:grid;place-items:center;
    padding:clamp(14px,3vw,40px);
    background:rgba(9,20,33,.86);-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);
    opacity:0;pointer-events:none;transition:opacity .28s var(--ease)}
.lb.open{opacity:1;pointer-events:auto}
.lb[hidden]{display:none!important}
.lb__fig{margin:0;display:flex;flex-direction:column;align-items:center;gap:14px;
         max-width:100%;max-height:100%;min-width:0}
.lb__img{display:block;max-width:min(88vw,760px);max-height:78vh;width:auto;height:auto;
  border-radius:10px;box-shadow:0 40px 90px -30px rgba(0,0,0,.8);background:#0d1b2a;
  transition:opacity .2s var(--ease)}
.lb.swapping .lb__img{opacity:.35}
.lb__cap{color:#dce8f2;font-family:var(--sans);font-weight:300;font-size:14.5px;
  text-align:center;max-width:min(88vw,620px);line-height:1.5;margin:0}
.lb__n{display:block;color:#8aa4ba;font-size:12px;letter-spacing:.1em;margin-top:5px;
  font-variant-numeric:tabular-nums}
.lb button{position:absolute;border:1px solid rgba(255,255,255,.22);
  background:rgba(12,28,46,.55);color:#fff;border-radius:999px;cursor:pointer;
  display:grid;place-items:center;transition:background .25s var(--ease),border-color .25s var(--ease)}
.lb button:hover{background:rgba(12,28,46,.9);border-color:rgba(255,255,255,.5)}
.lb button:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.lb__close{top:clamp(10px,2vw,22px);right:clamp(10px,2vw,22px);width:42px;height:42px;font-size:19px;line-height:1}
.lb__prev,.lb__next{top:50%;transform:translateY(-50%);width:46px;height:46px;font-size:20px;line-height:1}
.lb__prev{left:clamp(8px,2vw,26px)} .lb__next{right:clamp(8px,2vw,26px)}
@media (max-width:620px){
  .lb__img{max-width:92vw;max-height:70vh}
  .lb__prev,.lb__next{top:auto;bottom:calc(14px + env(safe-area-inset-bottom,0px));transform:none;
    width:44px;height:44px}
  .lb__cap{font-size:13.5px}
}
@media (prefers-reduced-motion:reduce){
  .lb,.lb__img{transition:none}
}
body.lb-open{overflow:hidden}

/* ---------------------------------------------------------------- sticky quote bar
   Phones and small tablets only. Above 1080px the header carries its own
   Free Estimate button and the phone number, so the bar would be redundant;
   below 1080px both are hidden behind the burger (see .hdr .btn and .tel),
   which leaves long stretches of scrolling with nothing to tap.

   Hidden until JS adds .is-on, which happens once the visitor is past the
   first screenful. visibility rather than opacity, so the links are not
   focusable by keyboard while the bar is parked off-screen.

   z-index sits under the drawer (99), the header (100) and the lightbox (300),
   all of which cover the whole screen when open, so each of those hides the
   bar without a rule of its own. */
.qbar{
  position:fixed;left:0;right:0;bottom:0;z-index:70;
  display:none;align-items:center;gap:10px;
  padding:10px 14px;
  padding-bottom:calc(10px + env(safe-area-inset-bottom,0px));
  background:rgba(18,35,58,.93);
  -webkit-backdrop-filter:saturate(1.3) blur(12px);
          backdrop-filter:saturate(1.3) blur(12px);
  border-top:1px solid rgba(255,255,255,.12);
  transform:translateY(115%);visibility:hidden;
  transition:transform .3s var(--ease-out),visibility .3s;
}
@media (max-width:1080px){
  .qbar{display:flex}
  /* so the bar never sits on top of the last line of the footer */
  .ftr{padding-bottom:calc(30px + 74px + env(safe-area-inset-bottom,0px))}
}
.qbar.is-on{transform:none;visibility:visible}
.qbar .btn{
  flex:1 1 auto;justify-content:center;
  padding:14px 20px;font-size:15px;
  box-shadow:0 1px 0 rgba(255,255,255,.35) inset;
}
.qbar .btn:hover{transform:none}
.qbar__tel{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:7px;
  padding:13px 17px;border-radius:999px;
  border:1px solid rgba(255,255,255,.26);
  color:#eaf1f7;text-decoration:none;
  font-family:var(--sans);font-size:14.5px;font-weight:500;
}
.qbar__tel:focus-visible,.qbar .btn:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
@media (prefers-reduced-motion:reduce){ .qbar{transition:none} }
