/* ============================================================
   GB ROOFING — DEMO 1 "ASCENT"
   Architectural / editorial. Light paper, ink type, brand blue
   used sparingly as a precision accent. Swiss grid, big rules,
   numbered service index, generous air.
   ============================================================ */

:root{
  --blue:#3498db;          /* brand — taken from the logo */
  --blue-deep:#1c6ea8;     /* accessible blue for text on paper */
  --blue-ink:#0f3f61;      /* darkest blue, for deep contrast */
  --grey:#737373;          /* brand grey — the wordmark colour */
  --ink:#14181d;
  --ink-2:#3d444d;
  --ink-3:#5f6672;   /* was #6b7280 — 4.48:1 on paper, just under AA */
  --paper:#f7f6f4;
  --paper-2:#efedea;
  --line:#dedbd6;
  --white:#fff;
  --ease:cubic-bezier(.16,1,.3,1);
  --ease-io:cubic-bezier(.65,0,.35,1);
  --shell:min(1360px, 92vw);
  --gut:clamp(18px,4vw,44px);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:"Inter",ui-sans-serif,system-ui,-apple-system,"Segoe UI",sans-serif;
  font-size:1.0625rem;line-height:1.68;-webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
h1,h2,h3,h4{margin:0;font-family:"Schibsted Grotesk",ui-sans-serif,system-ui,sans-serif;
  font-weight:400;line-height:1.06;letter-spacing:-.025em}
p{margin:0 0 1.1em}
ul{margin:0;padding:0;list-style:none}
button{font:inherit;cursor:pointer;border:0;background:none;color:inherit}
:focus-visible{outline:2.5px solid var(--blue);outline-offset:3px;border-radius:2px}

.shell{width:var(--shell);margin-inline:auto}
.serif{font-family:"Schibsted Grotesk",ui-sans-serif,system-ui,sans-serif;font-weight:400}
.nums{font-variant-numeric:lining-nums tabular-nums;font-feature-settings:"lnum" 1,"tnum" 1}

/* ---------- reveal ---------- */
html.js [data-reveal]{opacity:0;transform:translateY(26px);
  transition:opacity .95s var(--ease),transform .95s var(--ease);transition-delay:var(--rd,0ms)}
html.js [data-reveal].is-in{opacity:1;transform:none}
html.js [data-reveal="fade"]{transform:none}
html.js [data-reveal="left"]{transform:translateX(-30px)}
html.js [data-reveal="scale"]{transform:scale(.965);opacity:0}
html.js [data-reveal="scale"].is-in{transform:none}
html.reveal-off [data-reveal]{opacity:1!important;transform:none!important}

/* word-by-word headline mask reveal */
.wr{display:inline-block;overflow:hidden;vertical-align:bottom;padding-bottom:.06em}
.wr>i{display:inline-block;font-style:inherit;transform:translateY(105%);
  transition:transform 1.05s var(--ease);transition-delay:var(--wd,0ms)}
html:not(.js) .wr>i,html.reveal-off .wr>i{transform:none}
.is-in .wr>i,[data-reveal].is-in .wr>i{transform:none}

/* ---------- grain ---------- */
.grain{position:fixed;inset:0;z-index:1;pointer-events:none;opacity:.05;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E")}

/* ============================================================ HEADER */
.hdr{position:fixed;inset:0 0 auto;z-index:600;padding:18px 0;background:transparent;
  border-bottom:1px solid transparent;
  transition:padding .45s var(--ease),border-color .45s var(--ease),background .45s var(--ease)}
.hdr::before{content:"";position:absolute;inset:0 0 auto;height:140px;pointer-events:none;
  background:linear-gradient(180deg,rgba(10,13,17,.55),transparent);transition:opacity .45s var(--ease)}
.hdr.stuck{padding:11px 0;border-bottom-color:var(--line);background:rgba(247,246,244,.94);
  backdrop-filter:blur(20px) saturate(1.4);-webkit-backdrop-filter:blur(20px) saturate(1.4)}
.hdr.stuck::before{opacity:0}
.hdr .in{display:flex;align-items:center;gap:clamp(14px,3vw,40px);position:relative}
.hdr .logo{flex:0 0 auto}
.hdr .logo img{height:clamp(54px,5.6vw,78px);width:auto;transition:height .45s var(--ease)}
.hdr.stuck .logo img{height:clamp(46px,4.6vw,62px)}
.nav{display:flex;align-items:center;gap:clamp(10px,1.8vw,28px);margin-left:auto}
.nav>a,.nav .drop>button{
  position:relative;font-size:0.8438rem;font-weight:500;letter-spacing:.005em;color:rgba(255,255,255,.88);
  padding:8px 2px;transition:color .3s}
.hdr.stuck .nav>a,.hdr.stuck .nav .drop>button{color:var(--ink-2)}
.hdr.stuck .nav>a:hover,.hdr.stuck .nav .drop:hover>button{color:var(--ink)}
.nav>a::after,.nav .drop>button::after{content:"";position:absolute;left:0;right:0;bottom:2px;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:right;transition:transform .45s var(--ease)}
.nav>a:hover,.nav .drop:hover>button{color:#fff}
.nav>a:hover::after,.nav .drop:hover>button::after{transform:scaleX(1);transform-origin:left}
.nav .drop{position:relative}
.nav .drop>button{display:flex;align-items:center;gap:6px}
.nav .drop>button svg{width:9px;height:9px;transition:transform .35s var(--ease)}
.nav .drop:hover>button svg{transform:rotate(180deg)}
.dropm{position:absolute;top:calc(100% + 12px);left:50%;transform:translateX(-50%) translateY(-8px);
  min-width:262px;background:var(--white);border:1px solid var(--line);border-radius:2px;
  box-shadow:0 30px 70px -24px rgba(20,24,29,.24);padding:7px;
  opacity:0;visibility:hidden;transition:.35s var(--ease)}
.nav .drop:hover .dropm,.nav .drop:focus-within .dropm{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
.dropm a{display:block;padding:10px 13px;font-size:0.8438rem;color:var(--ink-2);border-radius:2px;transition:.25s}
.dropm a:hover{background:var(--paper-2);color:var(--ink);padding-left:19px}

.hcta{display:flex;align-items:center;gap:clamp(14px,2vw,26px);margin-left:clamp(8px,1.6vw,22px)}
.tel{display:flex;align-items:center;gap:8px;font-weight:400;font-size:0.8438rem;color:#fff;white-space:nowrap;transition:color .3s}
.hdr.stuck .tel{color:var(--ink)}
.tel svg{width:14px;height:14px;color:currentColor;opacity:.55}
.navlink{position:relative;font-size:0.8438rem;font-weight:500;color:#fff;white-space:nowrap;padding:8px 2px;transition:color .3s}
.hdr.stuck .navlink{color:var(--ink)}
.navlink::after{content:"";position:absolute;left:0;right:0;bottom:2px;height:1px;background:currentColor;
  opacity:.4;transform-origin:right;transition:transform .45s var(--ease)}
.navlink:hover::after{transform:scaleX(0)}

.btn{
  position:relative;display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:15px 28px;border-radius:2px;font-size:0.8438rem;font-weight:500;letter-spacing:.02em;
  background:var(--ink);color:var(--white);overflow:hidden;isolation:isolate;
  transition:color .4s var(--ease),transform .4s var(--ease)}
.btn::before{content:"";position:absolute;inset:0;z-index:-1;background:var(--blue);
  transform:translateY(101%);transition:transform .5s var(--ease)}
.btn:hover::before{transform:translateY(0)}
.btn:hover{transform:translateY(-2px)}
.btn.ghost{background:transparent;color:var(--ink);border:1px solid var(--line)}
.btn.ghost:hover{color:var(--white);border-color:var(--ink)}
.btn.blue{background:var(--blue);color:#08131d}
.btn.blue::before{background:#fff}
.btn.blue:hover{color:var(--ink)}
.btn svg{width:14px;height:14px;transition:transform .4s var(--ease)}
.btn:hover svg{transform:translateX(4px)}

.quiet{display:inline-flex;align-items:center;gap:8px;font-size:0.8438rem;font-weight:500;
  color:var(--ink-2);padding:15px 2px;position:relative;transition:color .3s}
.quiet::after{content:"";position:absolute;left:0;right:0;bottom:11px;height:1px;background:currentColor;
  opacity:.35;transform-origin:right;transition:transform .45s var(--ease)}
.quiet:hover{color:var(--ink)}
.quiet:hover::after{transform:scaleX(0)}
.quiet svg{width:13px;height:13px;transition:transform .4s var(--ease)}
.quiet:hover svg{transform:translateX(4px)}

/* burger */
.burger{display:none;width:44px;height:44px;place-items:center;margin-left:auto;flex:0 0 auto}
.burger span{display:block;width:22px;height:1.4px;background:#fff;position:relative;transition:.4s var(--ease)}
.burger span::before,.burger span::after{content:"";position:absolute;left:0;width:22px;height:1.4px;background:#fff;transition:.4s var(--ease)}
.hdr.stuck .burger span,.hdr.stuck .burger span::before,.hdr.stuck .burger span::after{background:var(--ink)}
.burger.open span,.hdr.stuck .burger.open span{background:transparent}
.burger.open span{background:transparent}
.burger span::before{top:-7px}.burger span::after{top:7px}
.burger.open span{background:transparent}
.burger.open span::before{top:0;transform:rotate(45deg)}
.burger.open span::after{top:0;transform:rotate(-45deg)}

/* The closed drawer was only translated off-screen, so its twelve links stayed
   visible to the accessibility tree and in the keyboard tab order on every page —
   a keyboard user tabbed through a menu they could not see. visibility:hidden
   removes them; the delayed transition lets the slide-out still animate. */
.drawer{position:fixed;inset:0;z-index:590;background:var(--paper);padding:96px var(--gut) 40px;
  transform:translateY(-100%);overflow-y:auto;
  visibility:hidden;
  transition:transform .6s var(--ease),visibility 0s linear .6s;
  display:flex;flex-direction:column;gap:4px}
.drawer.open{transform:none;visibility:visible;transition:transform .6s var(--ease),visibility 0s}
.drawer a{font-family:"Schibsted Grotesk",sans-serif;font-weight:400;font-size:clamp(1.5rem,6vw,2.125rem);letter-spacing:-.025em;padding:9px 0;border-bottom:1px solid var(--line);color:var(--ink)}
.drawer .sub{font-family:"Inter",sans-serif;font-size:0.9688rem;padding-left:18px;color:var(--ink-3);border-bottom:1px dashed var(--line)}
.drawer .dact{margin-top:24px;display:flex;flex-direction:column;gap:12px}
.drawer .dact .btn{width:100%}

/* ============================================================ HERO — cinematic banner
   Golden-hour frame, type anchored bottom-left on a corner-weighted scrim so the
   house and sky stay clean. */
.hero{position:relative;min-height:100svh;display:flex;align-items:flex-end;
  padding-top:calc(var(--hdr-h,72px) + 60px);padding-bottom:clamp(64px,10vh,124px);
  overflow:hidden;isolation:isolate;background:var(--ink)}
.hero-bg{position:absolute;inset:0;z-index:-2}
.hero-bg img{width:100%;height:100%;object-fit:cover;transform-origin:58% 46%;
  transform:scale(1.2);animation:heroZoom 26s cubic-bezier(.22,.61,.36,1) forwards}
@keyframes heroZoom{to{transform:scale(1.01)}}
@media (prefers-reduced-motion:reduce){.hero-bg img{animation:none;transform:none}}
/* The 75deg scrim fell to zero by the middle of the frame, but the headline runs
   further across than that, so its right-hand end sat on bright sky — measured
   1.61:1 against white at 1440px, where large text needs 3:1. Carry the gradient
   further before it releases. It still clears the right of the frame entirely, so
   the photograph is untouched where there is no type over it. */
.hero::after{content:"";position:absolute;inset:0;z-index:-1;
  background:
    linear-gradient(75deg,rgba(10,13,17,.76) 0%,rgba(10,13,17,.64) 26%,rgba(10,13,17,.47) 52%,rgba(10,13,17,0) 82%),
    linear-gradient(180deg,rgba(10,13,17,.38) 0%,rgba(10,13,17,0) 24%,rgba(10,13,17,0) 48%,rgba(10,13,17,.5) 100%)}
@media(max-width:900px){
  .hero::after{background:linear-gradient(180deg,rgba(10,13,17,.72) 0%,rgba(10,13,17,.42) 30%,rgba(10,13,17,.84) 64%,rgba(10,13,17,.96) 100%)}
}
/* A soft shadow does not count towards the WCAG ratio, but it is what actually
   keeps the type legible where the photograph is busy rather than merely bright. */
.hero h1,.hero .lead,.hero .kicker,.hero .eyebrow,.hero .hero-sub{
  text-shadow:0 1px 24px rgba(8,11,15,.5),0 1px 3px rgba(8,11,15,.3)}
.hero .shell{position:relative;z-index:3}

.eyebrow{display:flex;align-items:center;gap:13px;font-size:0.6875rem;font-weight:500;
  letter-spacing:.2em;text-transform:uppercase;color:rgba(255,255,255,.74);
  margin-bottom:clamp(20px,2.6vw,30px)}
.eyebrow::before{content:"";width:30px;height:1px;background:rgba(255,255,255,.5)}

.hero h1{font-size:clamp(2.375rem,4.6vw,4.5rem);letter-spacing:-.03em;line-height:1.03;
  color:#fff;margin-bottom:clamp(20px,2.4vw,28px);max-width:13ch}
.hero h1 .lt{color:rgba(255,255,255,.55)}
.hero-sub{max-width:44ch;font-size:clamp(1rem,1.15vw,1.0938rem);line-height:1.66;
  color:rgba(255,255,255,.8);margin-bottom:clamp(28px,3.2vw,40px)}
.hero-act{display:flex;flex-wrap:wrap;gap:clamp(14px,1.6vw,24px);align-items:center}

/* hairline credential index, set on the banner */
.hero-meta{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.6vw,28px);
  max-width:760px;margin-top:clamp(38px,5vw,64px);padding-top:clamp(20px,2.4vw,26px);
  border-top:1px solid rgba(255,255,255,.24)}
.hero-meta div span{display:block;font-size:0.625rem;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.6);margin-bottom:7px}
.hero-meta div b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(0.8438rem,1vw,0.9688rem);letter-spacing:-.01em;color:#fff;line-height:1.4}
@media(max-width:600px){.hero-meta{grid-template-columns:1fr;gap:14px}
  .hero-meta div{display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:baseline}
  .hero-meta div span{margin-bottom:0;min-width:104px}}

/* the header sits on photography again */
.hero .quiet{color:rgba(255,255,255,.86)}
.hero .quiet:hover{color:#fff}

/* ============================================================ SECTION FURNITURE */
.sec{position:relative;padding:clamp(74px,11vw,150px) 0;z-index:2}
.sec.pap2{background:var(--paper-2)}
.sec.white{background:var(--white)}
.shead{display:grid;grid-template-columns:1fr;gap:20px;margin-bottom:clamp(40px,6vw,72px)}
@media(min-width:900px){.shead{grid-template-columns:190px 1fr;align-items:start;gap:48px}}
.snum{font-family:"Inter",sans-serif;font-weight:500;font-size:0.6875rem;letter-spacing:.16em;color:var(--ink-3);
  text-transform:uppercase;display:flex;align-items:center;gap:11px;font-variant-numeric:lining-nums}
.snum::before{content:"";width:26px;height:1px;background:var(--blue)}
.shead h2{font-size:clamp(1.75rem,3.6vw,3.25rem);letter-spacing:-.028em;line-height:1.08;
  margin:0 0 clamp(14px,1.5vw,20px)}
.shead p{max-width:52ch;color:var(--ink-2);margin:0}
.rule{height:1px;background:var(--line);transform:scaleX(0);transform-origin:left;
  transition:transform 1.3s var(--ease)}
[data-reveal].is-in .rule,.is-in>.rule{transform:scaleX(1)}

/* ============================================================ ABOUT */
.about{display:grid;gap:clamp(34px,5vw,80px);align-items:start}
@media(min-width:960px){.about{grid-template-columns:1.05fr .95fr}}
.pull{font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.3125rem,2.5vw,2.0625rem);line-height:1.25;
  letter-spacing:-.022em;color:var(--ink);margin-bottom:28px}
.pull em{font-style:normal;color:var(--ink-3)}
.about-body p{color:var(--ink-2);max-width:60ch}
.about-fig{position:relative}
.about-fig img{width:100%;height:clamp(320px,44vw,480px);object-fit:cover;border-radius:2px}
.about-badge{position:absolute;right:-14px;bottom:-14px;background:var(--ink);color:#fff;
  padding:22px 26px;border-radius:2px;max-width:230px;box-shadow:0 30px 60px -24px rgba(0,0,0,.4)}
.about-badge b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-size:1.875rem;line-height:1;letter-spacing:-.02em;
  font-weight:400;font-variant-numeric:lining-nums tabular-nums}
.about-badge span{display:block;font-size:0.7812rem;letter-spacing:.1em;text-transform:uppercase;
  color:rgba(255,255,255,.62);margin-top:9px;line-height:1.5}
@media(max-width:600px){.about-badge{right:10px;bottom:-10px;padding:16px 18px;max-width:190px}
  .about-badge b{font-size:1.875rem}}

/* roof line-draw */
.roofline{width:100%;height:auto;margin-top:34px;overflow:visible}
.roofline path,.roofline line{fill:none;stroke:var(--blue);stroke-width:1.5;
  stroke-dasharray:var(--len,900);stroke-dashoffset:var(--len,900);
  transition:stroke-dashoffset 2.2s var(--ease-io)}
.is-in .roofline path,.is-in .roofline line{stroke-dashoffset:0}
.roofline .fade{stroke:var(--line)}

/* ============================================================ SERVICES INDEX */
.sindex{display:grid;grid-template-columns:1fr;border-top:1px solid var(--line)}
@media(min-width:900px){.sindex{grid-template-columns:1fr 1fr;column-gap:clamp(32px,4vw,72px)}}
.srow{position:relative;display:grid;grid-template-columns:auto 1fr auto;
  gap:clamp(14px,1.8vw,26px);align-items:baseline;
  padding:clamp(22px,2.6vw,30px) 0;border-bottom:1px solid var(--line);
  transition:padding-left .5s var(--ease)}
.srow:hover{padding-left:10px}
.srow::before{content:"";position:absolute;left:0;bottom:-1px;height:1px;width:100%;background:var(--blue);
  transform:scaleX(0);transform-origin:left;transition:transform .6s var(--ease)}
.srow:hover::before{transform:scaleX(1)}
.srow .n{font-family:"Inter",sans-serif;font-weight:500;font-size:0.6875rem;letter-spacing:.1em;
  color:var(--ink-3);font-variant-numeric:lining-nums tabular-nums;min-width:26px}
.srow h3{font-size:clamp(1.0625rem,1.55vw,1.375rem);letter-spacing:-.02em;line-height:1.25;
  margin-bottom:7px;transition:color .4s var(--ease)}
.srow .d{display:block;font-size:0.9688rem;line-height:1.6;color:var(--ink-3);max-width:44ch}
.srow .go{width:34px;height:34px;border:1px solid var(--line);border-radius:50%;
  display:grid;place-items:center;flex:0 0 auto;align-self:center;
  transition:.5s var(--ease);opacity:.5}
.srow .go svg{width:13px;height:13px}
.srow:hover .go{opacity:1;transform:rotate(-45deg)}
/* hover image follower (fine pointers only) */
.speek{position:fixed;top:0;left:0;width:270px;height:200px;z-index:520;pointer-events:none;
  border-radius:2px;overflow:hidden;opacity:0;transform:translate(-50%,-50%) scale(.9);
  transition:opacity .35s var(--ease),transform .45s var(--ease);
  box-shadow:0 30px 70px -22px rgba(0,0,0,.45)}
.speek.on{opacity:1;transform:translate(-50%,-50%) scale(1)}
.speek img{width:100%;height:100%;object-fit:cover}
@media(hover:none),(pointer:coarse){.speek{display:none}}

/* ============================================================ RESTEC BAND */
.restec{background:var(--ink);color:#fff;position:relative;overflow:hidden}
.restec::before{content:"";position:absolute;top:-30%;right:-10%;width:60vw;height:60vw;border-radius:50%;
  background:radial-gradient(circle,rgba(52,152,219,.22),transparent 66%);pointer-events:none}
.restec .shead h2{color:#fff}
.restec .shead p{color:rgba(255,255,255,.72)}
.restec .snum{color:#7fc4ee}
.rest-grid{display:grid;gap:clamp(30px,4.6vw,70px);align-items:center}
@media(min-width:960px){.rest-grid{grid-template-columns:1fr 1fr}}
.rest-logo{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.14);border-radius:2px;
  padding:clamp(28px,4.6vw,54px);display:grid;place-items:center;gap:26px}
.rest-logo img{width:min(330px,80%);height:auto}
.rest-logo .cap{font-size:0.7812rem;letter-spacing:.18em;text-transform:uppercase;color:rgba(255,255,255,.55);text-align:center}
.rest-pts{display:grid;gap:2px;margin-top:8px}
.rest-pts li{display:grid;grid-template-columns:auto 1fr;gap:16px;padding:17px 0;
  border-bottom:1px solid rgba(255,255,255,.12);align-items:start}
.rest-pts li:first-child{border-top:1px solid rgba(255,255,255,.12)}
.rest-pts .ic{width:var(--ic);height:var(--ic);color:var(--blue);flex:0 0 auto;margin-top:3px}
.rest-pts b{display:block;font-size:0.9688rem;font-weight:600;margin-bottom:3px}
.rest-pts span{font-size:0.9688rem;color:rgba(255,255,255,.66);line-height:1.6}
.restec img.sysimg{width:100%;height:clamp(240px,34vw,380px);object-fit:cover;border-radius:2px}

/* ============================================================ WORK MOSAIC */
/* lightbox */
.lb{position:fixed;inset:0;z-index:9600;background:rgba(12,16,20,.95);display:grid;place-items:center;
  padding:5vh 5vw;opacity:0;visibility:hidden;transition:.4s var(--ease);backdrop-filter:blur(6px)}
.lb.open{opacity:1;visibility:visible}
.lb img{max-width:100%;max-height:88vh;object-fit:contain;border-radius:2px;
  transform:scale(.95);transition:transform .5s var(--ease)}
.lb.open img{transform:none}
.lb button{position:absolute;color:#fff;width:52px;height:52px;display:grid;place-items:center;
  border:1px solid rgba(255,255,255,.28);border-radius:50%;transition:.3s;background:rgba(0,0,0,.3)}
.lb button:hover{background:var(--blue);border-color:var(--blue)}
.lb .x{top:18px;right:18px}.lb .pv{left:14px;top:50%;transform:translateY(-50%)}
.lb .nx{right:14px;top:50%;transform:translateY(-50%)}
.lb svg{width:19px;height:19px}
@media(max-width:600px){.lb .pv{left:8px}.lb .nx{right:8px}.lb button{width:44px;height:44px}}

/* ============================================================ BEFORE / AFTER */
.ba{position:relative;overflow:hidden;border-radius:2px;user-select:none;touch-action:pan-y;
  aspect-ratio:4/3;max-width:620px;margin-inline:auto;cursor:ew-resize;background:var(--paper-2)}
.ba img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.ba .aft{clip-path:inset(0 0 0 var(--sp,50%))}
.ba .hdl{position:absolute;top:0;bottom:0;left:var(--sp,50%);width:2px;background:#fff;z-index:3;
  box-shadow:0 0 0 1px rgba(0,0,0,.16)}
.ba .hdl::after{content:"";position:absolute;left:50%;top:50%;width:52px;height:52px;margin:-26px 0 0 -26px;
  border-radius:50%;background:#fff;box-shadow:0 8px 24px -6px rgba(0,0,0,.4)}
.ba .hdl::before{content:"";position:absolute;left:50%;top:50%;z-index:2;width:18px;height:10px;margin:-5px 0 0 -9px;
  background:var(--ink);
  clip-path:polygon(0 50%,6px 0,6px 35%,12px 35%,12px 0,18px 50%,12px 100%,12px 65%,6px 65%,6px 100%)}
.ba .tag{position:absolute;top:16px;z-index:4;padding:9px 18px;border-radius:2px;font-size:0.6875rem;
  font-weight:600;letter-spacing:.16em;text-transform:uppercase;background:rgba(12,16,20,.72);color:#fff;
  backdrop-filter:blur(6px)}
.ba .tag.b{left:14px}.ba .tag.a{right:14px}

/* ============================================================ TESTIMONIALS */
.tst{display:grid;gap:clamp(16px,2.2vw,26px)}
@media(min-width:820px){.tst{grid-template-columns:repeat(3,1fr)}}
.tcard{background:var(--white);border:1px solid var(--line);border-radius:2px;padding:clamp(24px,3vw,34px);
  display:flex;flex-direction:column;gap:15px;transition:transform .6s var(--ease),box-shadow .6s var(--ease),border-color .6s}
.tcard:hover{transform:translateY(-6px);box-shadow:0 34px 70px -30px rgba(20,24,29,.28);border-color:#cfcbc4}
.stars{display:flex;gap:3px;color:var(--blue)}
.stars svg{width:15px;height:15px}
.tcard h3{font-size:0.9688rem;font-weight:600;letter-spacing:-.005em;color:var(--ink)}
.tcard blockquote{margin:0;font-size:0.9688rem;line-height:1.68;color:var(--ink-2)}
.tcard cite{margin-top:auto;font-style:normal;font-size:0.8125rem;font-weight:600;color:var(--ink);
  padding-top:14px;border-top:1px solid var(--line)}

/* ============================================================ AREAS */
.areas{display:grid;gap:clamp(30px,4vw,64px)}
@media(min-width:960px){.areas{grid-template-columns:1fr 1.08fr;align-items:start}}
.alist{display:grid;grid-template-columns:1fr;gap:0 clamp(24px,4vw,54px)}
@media(min-width:560px){.alist{grid-template-columns:repeat(2,1fr)}}
.alist a{position:relative;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:15px 4px;border-bottom:1px solid var(--line);font-size:clamp(0.9375rem,1.9vw,1.1875rem);
  font-weight:500;transition:padding-left .45s var(--ease),color .35s}
.alist a:hover{padding-left:12px;color:var(--blue-deep)}
.alist a .pc{font-size:0.6875rem;letter-spacing:.1em;color:var(--ink-3);font-variant-numeric:lining-nums}

.amap{position:relative;border-radius:2px;overflow:hidden;min-height:320px;background:var(--paper-2);
  border:1px solid var(--line)}
.amap img{width:100%;height:100%;object-fit:cover;min-height:320px}
.amap .ov{position:absolute;inset:auto 0 0;padding:40px 24px 22px;color:#fff;
  background:linear-gradient(transparent,rgba(10,14,18,.86))}
.amap .ov b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-size:1.3125rem;font-weight:400;letter-spacing:-.02em;margin-bottom:5px}
.amap .ov span{font-size:0.9688rem;color:rgba(255,255,255,.78)}

/* ============================================================ FAQ */
.faq{max-width:920px;margin-inline:auto;border-top:1px solid var(--line)}
.fq{border-bottom:1px solid var(--line)}
.fq>button{width:100%;display:flex;align-items:center;justify-content:space-between;gap:22px;
  padding:24px 0;text-align:left;font-size:clamp(1rem,2.1vw,1.3125rem);font-weight:500;
  letter-spacing:-.015em;color:var(--ink);transition:color .3s}
.fq>button:hover{color:var(--blue-deep)}
.fq .pm{position:relative;width:22px;height:22px;flex:0 0 auto}
.fq .pm::before,.fq .pm::after{content:"";position:absolute;background:var(--blue);transition:.45s var(--ease)}
.fq .pm::before{left:0;top:10px;width:22px;height:1.6px}
.fq .pm::after{left:10px;top:0;width:1.6px;height:22px}
.fq[open] .pm::after,.fq.open .pm::after{transform:rotate(90deg);opacity:0}
.fq .ans{overflow:hidden;height:0;transition:height .5s var(--ease)}
.fq .ans>div{padding:0 0 26px;color:var(--ink-2);max-width:74ch;font-size:0.9688rem}

/* ============================================================ CONTACT */
.ctc{display:grid;gap:clamp(32px,4.6vw,72px)}
@media(min-width:960px){.ctc{grid-template-columns:.92fr 1.08fr}}
.cinfo li{display:grid;grid-template-columns:auto minmax(0,1fr);gap:18px;padding:22px 0;border-bottom:1px solid var(--line);align-items:start}
.cinfo li>span:last-child{min-width:0}
.cinfo li:first-child{border-top:1px solid var(--line)}
.cinfo .ic{width:40px;height:40px;border-radius:50%;display:grid;place-items:center;
  background:var(--paper-2);color:var(--blue-deep);flex:0 0 auto}
.cinfo .ic svg{width:17px;height:17px}
.cinfo b{display:block;font-size:0.6875rem;letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3);margin-bottom:5px;font-weight:600}
.cinfo a,.cinfo p{font-size:clamp(0.9375rem,2vw,1.25rem);font-weight:500;color:var(--ink);margin:0;transition:color .3s;
  overflow-wrap:anywhere;word-break:break-word}
.cinfo a:hover{color:var(--blue-deep)}
.cinfo small{display:block;font-size:0.8125rem;color:var(--ink-3);font-weight:400;margin-top:3px}

.form{background:var(--white);border:1px solid var(--line);border-radius:2px;padding:clamp(24px,3.4vw,42px)}
.fg{position:relative;margin-bottom:20px}
.fg label{position:absolute;left:15px;top:16px;font-size:0.9688rem;color:var(--ink-3);pointer-events:none;
  transition:.32s var(--ease);background:var(--white);padding:0 5px}
.fg input,.fg select,.fg textarea{width:100%;padding:16px 15px;border:1px solid var(--line);border-radius:2px;
  background:var(--white);font:inherit;font-size:0.9688rem;color:var(--ink);transition:border-color .3s,box-shadow .3s}
.fg textarea{min-height:130px;resize:vertical}
.fg select{appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none' stroke='%23737373' stroke-width='1.6'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 16px center;background-size:12px;cursor:pointer}
.fg input:focus,.fg select:focus,.fg textarea:focus{outline:none;border-color:var(--blue);box-shadow:0 0 0 3px rgba(52,152,219,.14)}
.fg input:focus+label,.fg input:not(:placeholder-shown)+label,
.fg textarea:focus+label,.fg textarea:not(:placeholder-shown)+label{top:-9px;font-size:0.6875rem;color:var(--blue-deep);letter-spacing:.06em}
.fg.sel label{top:-9px;font-size:0.6875rem;color:var(--ink-3);letter-spacing:.06em}
.form .btn{width:100%;padding:17px}
.fnote{font-size:0.7812rem;color:var(--ink-3);margin:14px 0 0;text-align:center}

/* ============================================================ FOOTER */
.ft{background:var(--ink);color:rgba(255,255,255,.68);padding:clamp(60px,8vw,96px) 0 0;position:relative;z-index:2}
.ft-top{display:grid;gap:clamp(30px,4vw,54px);padding-bottom:clamp(40px,5vw,64px)}
@media(min-width:820px){.ft-top{grid-template-columns:1.5fr 1fr 1fr 1.1fr}}
.ft-top h3{font-size:0.6875rem;letter-spacing:.19em;text-transform:uppercase;color:#fff;margin-bottom:20px;font-weight:600}
.ft a{color:rgba(255,255,255,.68);font-size:0.9688rem;transition:color .3s,padding-left .35s var(--ease)}
.ft a:hover{color:#fff;padding-left:5px}
.ft li{margin-bottom:11px}
.ft-brand img{height:52px;width:auto;margin-bottom:20px}
.ft-brand p{font-size:0.9688rem;max-width:36ch;line-height:1.7}
.ft-soc{display:flex;gap:10px;margin-top:20px}
.ft-soc a{width:44px;height:44px;border:1px solid rgba(255,255,255,.18);border-radius:50%;
  display:grid;place-items:center;transition:.35s var(--ease)}
.ft-soc a:hover{background:var(--blue);border-color:var(--blue);color:#fff;padding-left:0;transform:translateY(-3px)}
.ft-soc svg{width:16px;height:16px}
.ft-kw{padding:26px 0;border-top:1px solid rgba(255,255,255,.12);
  font-size:0.7812rem;line-height:2.1;color:rgba(255,255,255,.5)}
.ft-kw a{font-size:0.7812rem}
.ft-kw a:hover{padding-left:0;color:var(--blue)}
.ft-bot{padding:20px 0 26px;border-top:1px solid rgba(255,255,255,.12);
  display:flex;flex-wrap:wrap;gap:12px;justify-content:space-between;font-size:0.7812rem;color:rgba(255,255,255,.45)}
.ft-bot a:hover{padding-left:0}

/* floating call button (mobile) */
.fabcall{position:fixed;right:16px;bottom:74px;z-index:8800;width:56px;height:56px;border-radius:50%;
  background:var(--blue);color:#fff;display:none;place-items:center;
  box-shadow:0 14px 34px -10px rgba(52,152,219,.7);transition:transform .35s var(--ease)}
.fabcall:hover{transform:scale(1.07)}
.fabcall svg{width:24px;height:24px}
@media(max-width:900px){.fabcall{display:grid}}

/* ============================================================ RESPONSIVE */
@media(max-width:1080px){
  .nav{display:none}
  /* The homepage nests .tel inside .hcta with the Enquire link; inner pages
     have .tel as a direct child. Hiding .hcta wholesale took the phone number
     off the homepage header on every phone. Keep the number, drop the button. */
  .hcta{display:flex;margin-left:0}
  .hcta .navlink{display:none}
  .burger{display:grid}
}
@media(max-width:900px){
  body{font-size:0.9688rem}
  .hero{min-height:92svh;padding-top:130px}
  .ft{padding-bottom:80px}
}
@media(max-width:600px){
  .alist{grid-template-columns:1fr}
}

/* ---------- local number callout (areas section) ---------- */
.localnum{display:grid;grid-template-columns:auto 1fr;gap:16px;align-items:start;
  margin-top:30px;padding:22px 0 0;border-top:1px solid var(--line);border-radius:0;background:none}
.localnum .ic{width:32px;height:32px;border-radius:50%;display:grid;place-items:center;
  background:var(--paper-2);color:var(--ink-2);flex:0 0 auto}
.localnum .ic svg{width:18px;height:18px}
.localnum b{display:block;font-size:0.6875rem;letter-spacing:.15em;text-transform:uppercase;
  color:var(--blue-deep);margin-bottom:6px;font-weight:700}
.localnum p{margin:0;font-size:0.9688rem;color:var(--ink-2)}
.localnum a{font-weight:600;color:var(--ink);border-bottom:1px solid var(--blue);transition:color .3s}
.localnum a:hover{color:var(--blue-deep)}

/* ---------- quiet credentials strip (replaces the banner stat bar + marquee) ---------- */
.creds{background:var(--paper);border-bottom:1px solid var(--line);position:relative;z-index:2}
.creds ul{display:grid;grid-template-columns:1fr;gap:0}
@media(min-width:820px){.creds ul{grid-template-columns:repeat(3,1fr)}}
.creds li{padding:clamp(22px,2.6vw,34px) clamp(14px,2vw,28px) clamp(22px,2.6vw,34px) 0;
  border-right:1px solid var(--line)}
.creds li:last-child{border-right:0}
@media(max-width:819px){
  .creds li{border-right:0;border-bottom:1px solid var(--line)}
  .creds li:last-child{border-bottom:0}
}
.creds b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.25rem,2.1vw,1.6875rem);letter-spacing:-.022em;color:var(--ink);line-height:1;margin-bottom:9px}
.creds span{display:block;font-size:0.8125rem;line-height:1.5;color:var(--ink-3)}


/* ============================================================ CAROUSEL — "film"
   Demo 1's language: an editorial filmstrip. Snap to start, hairline arrows,
   a numeric counter. Deliberately plain so the photographs do the talking. */
.car{position:relative}
.car-track{display:flex;gap:clamp(10px,1.2vw,18px);overflow-x:auto;scroll-snap-type:x mandatory;
  scroll-behavior:smooth;padding-bottom:4px;
  scrollbar-width:none;-ms-overflow-style:none;cursor:grab}
.car-track::-webkit-scrollbar{display:none}
.car-track.dragging{cursor:grabbing;scroll-behavior:auto;scroll-snap-type:none}
.car-track:focus-visible{outline:2.5px solid var(--blue);outline-offset:6px}
.car-film .car-track > *{flex:0 0 auto;scroll-snap-align:start}
.car-film .mfig{width:clamp(240px,30vw,430px);aspect-ratio:4/3;margin:0;position:relative;
  overflow:hidden;border-radius:2px;background:var(--paper-2);cursor:pointer}
.car-film .mfig img{width:100%;height:100%;object-fit:cover;
  transition:transform 1.1s var(--ease),filter .6s var(--ease)}
.car-film .mfig:hover img{transform:scale(1.05)}
.car-film .mfig figcaption{position:absolute;inset:auto 0 0;padding:34px 16px 14px;color:#fff;
  font-size:0.7812rem;letter-spacing:.02em;background:linear-gradient(transparent,rgba(10,14,18,.86));
  opacity:0;transform:translateY(8px);transition:.5s var(--ease)}
.car-film .mfig:hover figcaption{opacity:1;transform:none}
.car-quotes .car-track > *{width:clamp(280px,32vw,420px);scroll-snap-align:start}

.car-nav{display:flex;align-items:center;gap:10px;margin-top:clamp(22px,2.6vw,32px)}
.car-nav .car-prev,.car-nav .car-next{width:46px;height:46px;border-radius:50%;border:1px solid var(--line);
  display:grid;place-items:center;background:transparent;color:var(--ink);
  transition:.35s var(--ease)}
.car-nav .car-prev:hover:not(:disabled),.car-nav .car-next:hover:not(:disabled){background:var(--ink);border-color:var(--ink);color:var(--paper)}
.car-nav .car-prev:disabled,.car-nav .car-next:disabled{opacity:.3;cursor:default}
.car-nav .car-prev svg,.car-nav .car-next svg{width:16px;height:16px}
.car-count{margin-left:auto;font-size:0.7812rem;letter-spacing:.14em;color:var(--ink-3);
  font-variant-numeric:lining-nums tabular-nums}
@media(max-width:600px){.car-film .mfig{width:78vw}.car-quotes .car-track > *{width:82vw}}

/* ============================================================ DEMO 1 — blue on hover
   Every clickable thing resolves to brand blue. One rule, applied everywhere,
   so the page has a single consistent interactive signal. */
.hdr .nav > a:hover,
.hdr .nav .drop:hover > button,
.hdr .navlink:hover,
.hdr .tel:hover,
.dropm a:hover,
.drawer a:hover,
.srow:hover h3,
.alist a:hover,
.cinfo a:hover,
.faq .fq > button:hover,
.ft a:hover,
.ft-kw a:hover,
.quiet:hover,
.car-count:hover{color:var(--blue)!important}

.hdr.stuck .nav > a:hover,
.hdr.stuck .nav .drop:hover > button,
.hdr.stuck .navlink:hover,
.hdr.stuck .tel:hover{color:var(--blue)!important}

/* underlines and rules follow the same signal */
.nav > a:hover::after,.nav .drop:hover > button::after{background:var(--blue)}
.navlink:hover::after,.quiet:hover::after{background:var(--blue)}
.srow:hover .go{background:var(--blue);border-color:var(--blue);color:#fff}
.car-nav .car-prev:hover:not(:disabled),.car-nav .car-next:hover:not(:disabled){background:var(--blue);border-color:var(--blue);color:#fff}
.mfig:hover figcaption{color:#fff}
.ft-soc a:hover{background:var(--blue);border-color:var(--blue);color:#fff}
.btn.ghost:hover{border-color:var(--blue)}
.tcard:hover{border-color:var(--blue)}
.alist a:hover .pc{color:var(--blue)}

/* ---------- about: a hairline fact index under the copy ---------- */
.about-facts{display:grid;grid-template-columns:1fr;gap:0;
  margin-top:clamp(44px,5.6vw,76px);border-top:1px solid var(--line)}
@media(min-width:820px){.about-facts{grid-template-columns:repeat(3,1fr)}}
.about-facts li{padding:clamp(22px,2.6vw,30px) clamp(18px,2.4vw,34px) clamp(22px,2.6vw,30px) 0;
  border-right:1px solid var(--line)}
.about-facts li:last-child{border-right:0}
@media(max-width:819px){.about-facts li{border-right:0;border-bottom:1px solid var(--line)}
  .about-facts li:last-child{border-bottom:0}}
.about-facts b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.0625rem,1.5vw,1.3125rem);letter-spacing:-.018em;color:var(--ink);margin-bottom:9px}
.about-facts span{display:block;font-size:0.9688rem;line-height:1.6;color:var(--ink-3);max-width:34ch}

/* ---------- footer: an editorial masthead ---------- */
.ft-say{display:grid;gap:clamp(20px,3vw,44px);align-items:center;
  padding-bottom:clamp(44px,5.4vw,72px);border-bottom:1px solid rgba(255,255,255,.14)}
@media(min-width:860px){.ft-say{grid-template-columns:1fr auto}}
.ft-say p{margin:0;font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.5rem,3.1vw,2.625rem);line-height:1.14;letter-spacing:-.028em;color:#fff;max-width:20ch}
.ft-say .btn{background:var(--paper);color:var(--ink)}
.ft-say .btn::before{background:var(--blue)}
.ft-say .btn:hover{color:#fff}
.ft-top{padding-top:clamp(40px,5vw,64px)}

/* ---------- carousel cards size to their content ---------- */
.car-track{align-items:flex-start}
.tcard cite{margin-top:0}

/* ============================================================ AREAS — town grid
   Was a two-column list whose hairlines stopped at the column gap and restarted,
   which read as broken. A plain grid of towns needs no rules at all. */
.areas-in{display:block}
.towns{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;
  background:var(--town-line);border:1px solid var(--town-line)}
@media(min-width:620px){.towns{grid-template-columns:repeat(3,1fr)}}
@media(min-width:960px){.towns{grid-template-columns:repeat(5,1fr)}}
.town{display:block;padding:clamp(20px,2.2vw,28px) clamp(16px,1.8vw,22px);
  background:var(--town-bg);transition:background .35s var(--ease),color .35s var(--ease)}
.town b{display:block;font-size:clamp(0.9375rem,1.25vw,1.0625rem);font-weight:500;letter-spacing:-.012em;
  color:var(--town-ink);margin-bottom:6px;transition:color .35s var(--ease)}
.town span{display:block;font-size:0.6875rem;letter-spacing:.13em;color:var(--town-sub);
  font-variant-numeric:lining-nums tabular-nums}
.town:hover{background:var(--town-hover)}

.area-note{display:grid;grid-template-columns:1fr;gap:clamp(22px,3vw,48px);
  margin-top:clamp(30px,3.6vw,48px)}
@media(min-width:820px){.area-note{grid-template-columns:1fr 1.35fr}}
.area-note b{display:block;font-size:0.6875rem;font-weight:600;letter-spacing:.17em;
  text-transform:uppercase;color:var(--town-sub);margin-bottom:10px}
.area-note p{margin:0;font-size:0.9688rem;line-height:1.7;color:var(--town-note)}
.area-note a{font-weight:600;color:var(--town-ink);border-bottom:1px solid currentColor}

:root{--town-line:var(--line);--town-bg:var(--paper);--town-hover:var(--paper-2);
  --town-ink:var(--ink);--town-sub:var(--ink-3);--town-note:var(--ink-2)}
.town:hover b{color:var(--blue)}

/* ---------- carousel: fade the peek edge, group the controls ---------- */
.car{--car-fade:56px}
.car-track{-webkit-mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - var(--car-fade)),transparent 100%);
  mask-image:linear-gradient(90deg,#000 0,#000 calc(100% - var(--car-fade)),transparent 100%)}
.car-track:focus-visible{-webkit-mask-image:none;mask-image:none}
@media(max-width:700px){.car{--car-fade:28px}}

.car-nav{justify-content:flex-start}
.car-count{margin-left:14px}

/* ============================================================ UNIFORM SCALE
   Six rounds of edits left each page with several competing values for the same
   decision. One token per decision, applied everywhere. */
:root{
  --sec-y:clamp(72px,9vw,132px);   /* every section, top and bottom */
  --head-gap:clamp(38px,5vw,64px); /* section heading to its content */
  --card-p:clamp(24px,2.6vw,32px); /* every card */
  --ic-sm:14px; --ic:16px; --ic-lg:19px;
}

/* section rhythm */
.sec{padding-top:var(--sec-y);padding-bottom:var(--sec-y)}
.shead{margin-bottom:var(--head-gap)}

/* icon scale — three sizes, no more */
.cinfo .ic svg,.rest-pts .ic svg,.rpts .ic svg,.localnum .ic svg{width:var(--ic);height:var(--ic)}
.btn svg,.quiet svg,.car-nav svg,.ft-soc svg,.tel svg,.nav .drop > button svg{width:var(--ic-sm);height:var(--ic-sm)}
.stars svg{width:var(--ic-sm);height:var(--ic-sm)}
.feat .ic svg,.step .ic svg{width:var(--ic-lg);height:var(--ic-lg)}

/* card padding */
.tcard,.scard .body,.rcard .body,.fq > button{padding:var(--card-p)}
.fq .ans > div{padding:0 var(--card-p) var(--card-p)}

/* the Restec panel was vertically centred against a much taller list, so it floated */
.rest-grid,.rest,.rband{align-items:start}

/* ---------- testimonials: one review at a time ---------- */
.car-quotes .car-track{gap:0;-webkit-mask-image:none;mask-image:none;
  padding-inline:0;align-items:stretch}
.car-quotes .car-track > *{width:100%;flex:0 0 100%;scroll-snap-align:center;
  transform:none;opacity:1}
.car-quotes .tcard{width:100%;max-width:920px;margin-inline:auto}
.car-quotes .car-nav{justify-content:center}

/* ============================================================ BREATHING ROOM
   Text was sitting tight against the rules on the celled blocks. Every cell that
   has a line beside it now keeps a generous, equal gutter from it. */
:root{--cell-p:clamp(26px,2.6vw,36px)}

/* town grid — each cell is bounded by a rule on every side */
.town{padding:var(--cell-p) var(--cell-p)}
.town b{margin-bottom:8px}

/* hairline column blocks: pad the side that meets the rule, not just the text side */
.creds li,.about-facts li,.about-cols li{
  padding:var(--cell-p) var(--cell-p) var(--cell-p) 0}
.creds li:not(:last-child),.about-facts li:not(:last-child),.about-cols li:not(:last-child){
  padding-right:var(--cell-p)}
@media(max-width:819px){
  .creds li,.about-facts li,.about-cols li{padding-right:0}
}

/* stacked rule lists */
.cinfo li{padding:calc(var(--cell-p) * .74) var(--cell-p)}
.rest-pts li,.rpts li{padding:calc(var(--cell-p) * .68) 0}
.rest-list li{padding:calc(var(--cell-p) * .62) var(--cell-p)}
.srow{padding-top:calc(var(--cell-p) * .86);padding-bottom:calc(var(--cell-p) * .86)}
.atile{padding:calc(var(--cell-p) * .56) 4px}

/* boxed cards and the accordion */
.tcard,.scard .body,.rcard .body{padding:var(--cell-p)}
.fq > button{padding:calc(var(--cell-p) * .72) var(--cell-p)}
.fq .ans > div{padding:0 var(--cell-p) var(--cell-p)}
.form{padding:clamp(28px,3.2vw,44px)}
.rest-card,.rlogo,.rest-logo{padding:clamp(34px,4.4vw,56px)}
.area-note{gap:clamp(26px,3.2vw,54px)}

/* ============================================================ MOTION & FINISH
   A slower, more expensive feel: staggered entrances, images that settle rather
   than pop, lift on hover, and a hairline that draws itself under each heading.
   Everything degrades to a static page without JS and honours reduced-motion. */

/* images settle out of a slight scale as their block reveals */
html.js [data-reveal] img{transform:scale(1.035);transition:transform 1.4s var(--ease)}
html.js [data-reveal].is-in img{transform:scale(1)}
html.js .car-track img{transform:none!important}
/* The hero has its own zoom keyframe. It only needs to opt out of the generic
   settle scale above, and an !important here would beat the animation and
   leave the banner dead still — which is exactly what it did. */
html.js .hero-bg img{transform:scale(1.2)}

/* the rule under a section label draws itself in */
.snum::before,.tag::before,.eyebrow::before{transform-origin:left;transform:scaleX(0);
  transition:transform 1s var(--ease) .1s}
[data-reveal].is-in .snum::before,[data-reveal].is-in .tag::before,
[data-reveal].is-in .eyebrow::before,.shead.is-in .eyebrow::before{transform:scaleX(1)}
html:not(.js) .snum::before,html:not(.js) .tag::before,html:not(.js) .eyebrow::before,
html.reveal-off .snum::before,html.reveal-off .tag::before,html.reveal-off .eyebrow::before{transform:scaleX(1)}

/* grid children stagger themselves — no per-element delay attributes to maintain */
.towns .town,.sgrid .scard,.about-facts li,.about-cols li,.creds li,
.rest-pts li,.rpts li,.rest-list li,.cinfo li,.faq .fq,.sindex .srow{
  --stagger:0ms}
html.js [data-reveal] .town,html.js [data-reveal] .scard{opacity:0;transform:translateY(14px);
  transition:opacity .8s var(--ease),transform .8s var(--ease);transition-delay:var(--stagger)}
html.js [data-reveal].is-in .town,html.js [data-reveal].is-in .scard{opacity:1;transform:none}
html.reveal-off .town,html.reveal-off .scard{opacity:1!important;transform:none!important}
.towns .town:nth-child(2){--stagger:60ms}   .towns .town:nth-child(3){--stagger:120ms}
.towns .town:nth-child(4){--stagger:180ms}  .towns .town:nth-child(5){--stagger:240ms}
.towns .town:nth-child(6){--stagger:80ms}   .towns .town:nth-child(7){--stagger:140ms}
.towns .town:nth-child(8){--stagger:200ms}  .towns .town:nth-child(9){--stagger:260ms}
.towns .town:nth-child(10){--stagger:320ms}
.sgrid .scard:nth-child(2){--stagger:80ms}  .sgrid .scard:nth-child(3){--stagger:160ms}
.sgrid .scard:nth-child(4){--stagger:240ms} .sgrid .scard:nth-child(6){--stagger:80ms}
.sgrid .scard:nth-child(7){--stagger:160ms} .sgrid .scard:nth-child(8){--stagger:240ms}

/* considered lift on the things you can click */
.tcard,.scard,.rcard,.town,.wfig,.mfig{will-change:transform}
.wfig,.mfig{transition:transform .7s var(--ease),box-shadow .7s var(--ease)}
.wfig:hover,.mfig:hover{transform:translateY(-4px)}

/* buttons get a soft sheen rather than a colour flip */
.btn::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.22) 50%,transparent 62%);
  transform:translateX(-120%);transition:transform .9s var(--ease)}
.btn:hover::after{transform:translateX(120%)}

/* the carousel arrows breathe when they can still move */
.car-nav .car-prev:not(:disabled),.car-nav .car-next:not(:disabled){cursor:pointer}
.car-nav .car-prev:active,.car-nav .car-next:active{transform:scale(.94)}

@media (prefers-reduced-motion:reduce){
  html.js [data-reveal] img,html.js [data-reveal].is-in img{transform:none}
  html.js [data-reveal] .town,html.js [data-reveal] .scard{opacity:1;transform:none}
  .snum::before,.tag::before,.eyebrow::before{transform:scaleX(1)}
  .btn::after{display:none}
}

/* the .tcard IS the slide, so capping its width left the next one peeking.
   Full-width slide; the reading measure is set on the content instead. */
.car-quotes .car-track > *{flex:0 0 100%!important;width:100%!important;max-width:none!important}
.car-quotes .tcard{display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:16px;padding-block:clamp(34px,4vw,52px)}
.car-quotes .tcard h3{font-size:0.7812rem;letter-spacing:.16em;text-transform:uppercase;opacity:.62;font-weight:600}
.car-quotes .tcard blockquote{max-width:60ch;font-size:clamp(1.0625rem,1.7vw,1.375rem);line-height:1.62}
.car-quotes .tcard cite{border-top:0;padding-top:4px;letter-spacing:.04em}
.car-quotes .stars{justify-content:center}

/* ============================================================ GUTTERS ON RULED COLUMNS
   These blocks divide with `border-right`, so the NEXT column's text was starting
   flush against that line — the earlier rule set padding-left to 0. Every cell now
   keeps a full gutter on both sides; only the first cell in a row sits flush left so
   its text still lines up with the section heading above it. */
.creds li,.about-facts li,.about-cols li{
  padding:var(--cell-p) var(--cell-p) var(--cell-p) var(--cell-p)}

@media(min-width:820px){
  .creds ul{grid-template-columns:repeat(3,1fr)}
  .creds li:nth-child(3n+1),
  .about-facts li:nth-child(3n+1),
  .about-cols li:nth-child(3n+1){padding-left:0}
}
@media(max-width:819px){
  .creds li,.about-facts li,.about-cols li{padding-left:0;padding-right:0}
}

/* the same trap on the two-column note under the town grid */
.area-note > div + div{padding-left:0}
@media(min-width:820px){.area-note{column-gap:clamp(40px,5vw,80px)}}

/* ============================================================ FORM LABELS
   The floating labels were notched into the field's top border, so the rule ran
   through the text. Labels now sit above the field as a small caps caption — no
   line to collide with, easier to read, and it survives autofill. */
.fg{position:relative;display:flex;flex-direction:column;margin-bottom:clamp(20px,2vw,26px)}
.fg label{position:static !important;order:-1;top:auto !important;left:auto !important;
  margin:0 0 9px;padding:0 !important;background:none !important;
  font-size:0.6875rem;font-weight:600;letter-spacing:.15em;text-transform:uppercase;
  line-height:1.4;pointer-events:auto}
.fg input,.fg select,.fg textarea{order:1}
/* the old floating states no longer apply */
.fg input:focus + label,.fg input:not(:placeholder-shown) + label,
.fg textarea:focus + label,.fg textarea:not(:placeholder-shown) + label,
.fg.sel label{position:static !important;top:auto !important;left:auto !important;
  font-size:0.6875rem;letter-spacing:.15em;background:none !important}
.form .btn{margin-top:6px}
.fg label{color:var(--ink-3)}
.fg input:focus ~ label,.fg select:focus ~ label,.fg textarea:focus ~ label{color:var(--blue)}

/* Slides are equal height so the carousel does not jump as it rotates; centre the
   quote within that height so a short review does not leave a hole underneath. */
.car-quotes .tcard{justify-content:center;min-height:clamp(240px,26vw,320px)}

/* ---------- gallery: a continuously flowing strip ---------- */
.car-flow .car-track{scroll-snap-type:none;overflow:hidden;cursor:default;
  will-change:transform;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 4%,#000 96%,transparent 100%);
  mask-image:linear-gradient(90deg,transparent 0,#000 4%,#000 96%,transparent 100%)}
.car-flow .mfig{cursor:pointer}
/* without JS it stays a normal scrollable rail */
html:not(.js) .car-flow .car-track{overflow-x:auto;scroll-snap-type:x mandatory}
@media (prefers-reduced-motion:reduce){
  .car-flow .car-track{overflow-x:auto;scroll-snap-type:x mandatory;transform:none!important}
}

/* ── Text link tap targets ────────────────────────────────────────────────────
   Footer and contact links are single lines of ~18px text with dead space
   between them, so on a phone a near miss does nothing at all. Padding turns
   that dead space into part of the link; the matching negative margin means the
   spacing you see is untouched. padding-block only, so the hover slide on
   padding-left still works. */
.ft-top li a,.ft-bot a{display:inline-block;padding-block:6px;margin-block:-6px}
.cinfo a{display:inline-block;padding-block:5px;margin-block:-5px}
/* The header number is its own row in the bar, so it can take a little height
   without disturbing anything around it. */
.tel{padding-block:5px}

/* ============================================================
   INNER PAGES — "ASCENT"
   Same language as the homepage: paper ground, ink type, thin
   rules, blue as a precision accent. Nothing new invented here;
   every inner page is assembled from this vocabulary so the
   whole site reads as one hand.
   ============================================================ */

/* ── Page banner ───────────────────────────────────────────── */
.pb{position:relative;isolation:isolate;background:var(--ink);overflow:hidden;
  padding:calc(var(--hdr-h,86px) + clamp(72px,9vw,128px)) 0 clamp(56px,7vw,96px)}
.pb-bg{position:absolute;inset:0;z-index:-2}
.pb-bg img{width:100%;height:100%;object-fit:cover;object-position:center 42%}
/* Kept light: a flat scrim flattens the photography, so this is a directional
   wash that holds the type and leaves the roof itself readable. */
.pb::after{content:"";position:absolute;inset:0;z-index:-1;
  background:linear-gradient(100deg,rgba(12,16,20,.86) 0%,rgba(12,16,20,.64) 46%,rgba(12,16,20,.22) 100%)}
.pb .shell{position:relative;z-index:1}
.pb h1{color:var(--white);font-size:clamp(2rem,5vw,4.25rem);letter-spacing:-.03em;
  max-width:19ch;margin:0 0 clamp(16px,2vw,22px)}
.pb .pb-sub{color:rgba(255,255,255,.82);max-width:60ch;font-size:clamp(0.9688rem,1.5vw,1.1875rem);margin:0}
.pb .eyebrow{color:rgba(255,255,255,.72);margin-bottom:18px}
.pb-act{display:flex;flex-wrap:wrap;gap:12px;margin-top:clamp(26px,3vw,36px)}

/* ── Breadcrumbs ───────────────────────────────────────────── */
.crumb{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:clamp(18px,2.4vw,26px);
  font-size:0.7812rem;letter-spacing:.02em;color:rgba(255,255,255,.62)}
.crumb a{color:rgba(255,255,255,.72);transition:color .3s}
.crumb a:hover{color:var(--blue)}
.crumb svg{width:11px;height:11px;opacity:.5;flex:0 0 auto}
.crumb [aria-current]{color:rgba(255,255,255,.92)}

/* ── Prose ─────────────────────────────────────────────────── */
.prose{max-width:74ch}
.prose h2{font-size:clamp(1.5rem,2.9vw,2.375rem);letter-spacing:-.025em;line-height:1.12;
  margin:clamp(40px,4.4vw,60px) 0 clamp(14px,1.5vw,20px)}
.prose h2:first-child{margin-top:0}
.prose h3{font-size:clamp(1.1562rem,1.85vw,1.5rem);letter-spacing:-.018em;line-height:1.2;
  margin:clamp(36px,3.8vw,52px) 0 clamp(12px,1.3vw,16px)}
.prose p{color:var(--ink-2)}
.prose p.lede{font-size:clamp(1.0938rem,1.75vw,1.3125rem);color:var(--ink);line-height:1.6}
.prose a:not(.btn){color:var(--blue-deep);text-decoration:underline;
  text-underline-offset:3px;text-decoration-thickness:1px;
  text-decoration-color:rgba(28,110,168,.35);transition:text-decoration-color .3s}
.prose a:not(.btn):hover{text-decoration-color:var(--blue-deep)}
.prose > :last-child{margin-bottom:0}

/* ── Tick list ─────────────────────────────────────────────── */
.tick{display:grid;gap:11px;margin:0 0 1.1em}
.tick li{position:relative;padding-left:30px;color:var(--ink-2)}
.tick li::before{content:"";position:absolute;left:0;top:.62em;width:15px;height:8px;
  border-left:1.5px solid var(--blue);border-bottom:1.5px solid var(--blue);
  transform:rotate(-45deg) translateY(-1px)}
.tick.two{grid-template-columns:repeat(auto-fit,minmax(240px,1fr));column-gap:32px}

/* ── Alternating image + text ──────────────────────────────── */
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(34px,5vw,80px);align-items:center}
.split + .split{margin-top:clamp(60px,7vw,110px)}
.split .sp-fig{position:relative;overflow:hidden;border-radius:2px;background:var(--paper-2)}
.split .sp-fig img{width:100%;height:100%;object-fit:cover;aspect-ratio:4/3}
.split.flip .sp-fig{order:2}
.split .sp-body h2{font-size:clamp(1.4375rem,2.7vw,2.25rem);letter-spacing:-.024em;line-height:1.14;
  margin:0 0 clamp(15px,1.6vw,22px)}
.split .sp-body p{color:var(--ink-2)}
.split .sp-body > :last-child{margin-bottom:0}
.sp-num{display:block;font-size:0.6875rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--blue-deep);font-weight:600;margin-bottom:14px}

/* ── Callout panel ─────────────────────────────────────────── */
.callout{border:1px solid var(--line);border-left:2px solid var(--blue);
  background:var(--white);padding:var(--cell-p);border-radius:2px}
.callout h3{font-size:clamp(1.125rem,1.8vw,1.4375rem);letter-spacing:-.018em;
  margin:0 0 clamp(12px,1.3vw,16px)}
.callout p{color:var(--ink-2)}
.callout > :last-child{margin-bottom:0}
.sec.pap2 .callout{background:var(--paper)}

/* ── Postcode / village chips ──────────────────────────────── */
.chips{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 1.1em}
.chips li{font-size:0.8125rem;letter-spacing:.03em;color:var(--ink-2);
  border:1px solid var(--line);border-radius:2px;padding:7px 13px;background:var(--white)}
.sec.pap2 .chips li,.sec.white .chips li{background:var(--paper-2)}
.chips li.k{border-color:rgba(52,152,219,.42);color:var(--blue-deep);font-weight:500}

/* ── Card grid (services / towns) ──────────────────────────── */
.cgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:2px;overflow:hidden}
.cgrid > a{background:var(--paper);padding:var(--cell-p);display:flex;flex-direction:column;gap:9px;
  transition:background .4s var(--ease),color .4s var(--ease)}
.sec.pap2 .cgrid > a{background:var(--paper-2)}
.sec.white .cgrid > a{background:var(--white)}
.cgrid > a:hover{background:var(--white)}
.sec.white .cgrid > a:hover{background:var(--paper-2)}
.cgrid h3{font-size:clamp(1.0625rem,1.6vw,1.3125rem);letter-spacing:-.018em;transition:color .35s}
.cgrid > a:hover h3{color:var(--blue-deep)}
.cgrid p{font-size:0.9688rem;color:var(--ink-3);margin:0;line-height:1.6}
.cgrid .go{margin-top:auto;padding-top:14px;font-size:0.7812rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--blue-deep);display:flex;align-items:center;gap:8px;font-weight:600}
.cgrid .go svg{width:13px;height:13px;transition:transform .4s var(--ease)}
.cgrid > a:hover .go svg{transform:translateX(5px)}

/* ── Stat strip ────────────────────────────────────────────── */
.strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.strip > div{padding:clamp(24px,2.8vw,36px) clamp(22px,2.4vw,32px);border-right:1px solid var(--line)}
.strip > div:last-child{border-right:0}
.strip b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.625rem,3vw,2.5rem);letter-spacing:-.03em;line-height:1;margin-bottom:9px}
.strip span{font-size:0.7812rem;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-3);font-weight:500}

/* ── Related links ─────────────────────────────────────────── */
.rel{display:flex;flex-wrap:wrap;gap:9px}
.rel a{font-size:0.9688rem;border:1px solid var(--line);border-radius:2px;padding:10px 16px;
  color:var(--ink-2);background:var(--white);transition:.35s var(--ease)}
.sec.white .rel a{background:var(--paper-2)}
.rel a:hover{border-color:var(--blue);color:var(--blue-deep);transform:translateY(-2px)}

/* ── Two column page layout (body + aside) ─────────────────── */
.pcols{display:grid;grid-template-columns:minmax(0,1fr) 336px;gap:clamp(40px,5.5vw,88px);align-items:start}
.aside{position:sticky;top:calc(var(--hdr-h,86px) + 24px);display:grid;gap:20px}
.aside .callout{background:var(--white)}
.sec.white .aside .callout{background:var(--paper-2)}
.aside .btn{width:100%;justify-content:center}

/* 960, not 1080: a 1024px iPad in landscape has ample room for the contact
   card alongside the text, and stacking it there wastes half the screen. */
@media (max-width:960px){
  .pcols{grid-template-columns:1fr;gap:clamp(36px,5vw,56px)}
  .aside{position:static;grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
}
/* Slightly narrower sidebar between 961 and 1120 so the text keeps a decent measure. */
@media (min-width:961px) and (max-width:1120px){
  .pcols{grid-template-columns:minmax(0,1fr) 296px;gap:clamp(32px,3.4vw,44px)}
}
/* 700, not 820. Real phones stop at 430 CSS px, so everything from 700 up is a
   tablet and should get the two-column block. iPad mini is 744 and would
   otherwise take the phone build. The image is given the narrower share at
   tablet sizes so the text keeps a readable measure. */
@media (min-width:701px) and (max-width:1080px){
  .split{grid-template-columns:.88fr 1fr;gap:clamp(26px,3.4vw,44px)}
}
@media (max-width:700px){
  .split{grid-template-columns:1fr;gap:clamp(22px,4vw,32px)}
  .split.flip .sp-fig{order:0}
}
@media (max-width:819.98px){
  .strip > div{border-right:0;border-bottom:1px solid var(--line)}
  .strip > div:last-child{border-bottom:0}
}
@media (max-width:560px){
  .pb h1{max-width:none}
  .crumb{font-size:0.6875rem}
}

/* ── Skip link + visually hidden ───────────────────────────── */
/* Kept in the document rather than thrown to -9999px: some assistive tech and
   some browsers treat a far-offscreen element inconsistently. */
.skip{position:absolute;left:12px;top:12px;z-index:900;background:var(--ink);color:var(--white);
  transform:translateY(-160%);transition:transform .2s ease;
  padding:14px 22px;border-radius:0 0 2px 0;font-size:0.9688rem}
.skip:focus{transform:translateY(0)}
.vh{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ── Type-led banner ───────────────────────────────────────────
   Town, testimonial and contact pages get an ink ground instead of a
   photograph. A generic stock roof says nothing about Cobham, and the
   whole area set reads as one deliberate family this way. */
.pb.ink{background:var(--ink)}
.pb.ink::after{background:
  radial-gradient(120% 90% at 82% 8%,rgba(52,152,219,.16) 0%,transparent 58%),
  linear-gradient(180deg,rgba(255,255,255,.03) 0%,transparent 40%)}
.pb.ink .pb-rule{position:absolute;inset:0;z-index:-1;opacity:.10;pointer-events:none;
  background-image:linear-gradient(90deg,#fff 1px,transparent 1px);
  background-size:clamp(64px,7vw,116px) 100%}
.pb.ink .pb-mark{position:absolute;right:-2%;top:50%;transform:translateY(-50%);z-index:-1;
  font-family:"Schibsted Grotesk",sans-serif;font-weight:400;letter-spacing:-.06em;
  font-size:clamp(9.375rem,26vw,26.25rem);line-height:.8;color:rgba(255,255,255,.045);
  white-space:nowrap;user-select:none;pointer-events:none}
@media (max-width:700px){.pb.ink .pb-mark{display:none}}

/* ── Full gallery grid (gallery page) ──────────────────────── */
.ggrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:clamp(14px,1.6vw,22px)}
.ggrid .mfig{margin:0;position:relative;overflow:hidden;border-radius:2px;cursor:pointer;background:var(--paper-2)}
.ggrid .mfig img{width:100%;aspect-ratio:4/3;height:auto;object-fit:cover;
  transition:transform 1.1s var(--ease)}
.ggrid .mfig:hover img{transform:scale(1.045)}
.ggrid figcaption{position:absolute;left:0;right:0;bottom:0;padding:26px 20px 16px;
  font-size:0.8438rem;letter-spacing:.01em;color:#fff;
  background:linear-gradient(0deg,rgba(10,14,18,.82),transparent);
  opacity:0;transform:translateY(6px);transition:.45s var(--ease)}
.ggrid .mfig:hover figcaption,.ggrid .mfig:focus-within figcaption{opacity:1;transform:none}

/* ── Testimonial wall (testimonials page) ──────────────────── */
.twall{display:grid;grid-template-columns:repeat(auto-fit,minmax(320px,1fr));gap:1px;
  background:var(--line);border:1px solid var(--line);border-radius:2px;overflow:hidden}
.twall .tcard{background:var(--paper);padding:var(--cell-p);display:flex;flex-direction:column;
  gap:13px;transition:background .45s var(--ease)}
.twall .tcard:hover{background:var(--white)}
.twall .tcard h3{font-size:0.7812rem;letter-spacing:.16em;text-transform:uppercase;
  opacity:.62;font-weight:600;line-height:1.5}
.twall .tcard blockquote{margin:0}
.twall .tcard blockquote p{margin:0;color:var(--ink-2);font-size:0.9688rem;line-height:1.68}
.twall .tcard cite{font-style:normal;font-size:0.8125rem;letter-spacing:.05em;color:var(--ink);
  font-weight:500;margin-top:auto;padding-top:4px}
@media (max-width:560px){
  .ggrid{grid-template-columns:1fr}
  .ggrid figcaption{opacity:1;transform:none}
}

/* ── Sitemap columns ───────────────────────────────────────── */
.smap{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:clamp(32px,4vw,64px)}
.smap h2{font-size:clamp(1.0625rem,1.6vw,1.3125rem);letter-spacing:-.015em;margin:0 0 18px;
  padding-bottom:14px;border-bottom:1px solid var(--line)}
.smap .tick li{padding-left:26px}
.smap a{color:var(--ink-2);transition:color .3s}
.smap a:hover{color:var(--blue-deep)}

/* The ghost button's ink text disappears against a dark banner. */
.pb .btn.ghost{color:#fff;border-color:rgba(255,255,255,.38)}
.pb .btn.ghost:hover{color:var(--ink);border-color:#fff}
.pb .btn.ghost::before{background:#fff}

/* ── Inner page closing CTA ────────────────────────────────── */
.pcta{display:grid;grid-template-columns:minmax(0,54ch) auto;
  justify-content:space-between;gap:clamp(24px,3vw,48px);
  align-items:center;border-top:1px solid var(--line);padding-top:clamp(32px,4vw,52px)}
/* This block was built for a short display line, but the closing copy runs to
   40-odd words. At 34px in a 22ch column that became eleven lines of huge type.
   Set it as the paragraph it actually is. */
.pcta p{margin:0;font-family:"Inter",ui-sans-serif,system-ui,sans-serif;font-weight:400;
  font-size:clamp(1.0312rem,1.5vw,1.1875rem);line-height:1.66;letter-spacing:0;
  color:var(--ink-2);max-width:none}
.pcta-act{display:flex;flex-wrap:wrap;gap:12px}
@media (max-width:700px){
  .pcta{grid-template-columns:1fr;gap:26px}
  .pcta p{max-width:none}
}

/* ── Inner page tap targets ────────────────────────────────────
   Breadcrumbs and the links in the contact card are single lines of small
   text. Padding gives a finger something to hit; the negative margin keeps
   the layout exactly where it was. */
.crumb a{display:inline-block;padding-block:6px;margin-block:-6px}
/* Every standalone small-text link in the inner-page kit, done in one place so
   the next component added here does not reintroduce a 20px tap target. */
.callout a,.strip a,.smap a,.aside a:not(.btn),.chips a{
  display:inline-block;padding-block:5px;margin-block:-5px}

/* ============================================================
   MOTION — inner pages
   Everything below is keyed to .is-in, which reveal.js guarantees
   within 6 seconds whatever happens, or sits on top of content
   that is already visible. Nothing here can hide the page.
   ============================================================ */

/* ── Reading progress hairline ─────────────────────────────── */
#gb-prog{position:fixed;top:0;left:0;right:0;height:2px;z-index:700;
  background:linear-gradient(90deg,var(--blue),var(--blue-ink));
  transform:scaleX(0);transform-origin:0 50%;will-change:transform;pointer-events:none}
@media print{#gb-prog{display:none}}

/* ── Stagger ───────────────────────────────────────────────── */
.js [data-stagger] > *{opacity:0;transform:translateY(14px);
  transition:opacity .7s var(--ease) var(--stagger,0ms),transform .7s var(--ease) var(--stagger,0ms)}
.js [data-stagger].is-in > *,
.js [data-reveal].is-in [data-stagger] > *{opacity:1;transform:none}
.reveal-off [data-stagger] > *{opacity:1!important;transform:none!important;transition:none!important}

/* ── Block image: curtain wipe + slow drift ────────────────── */
.split .sp-fig{position:relative;overflow:hidden;isolation:isolate}
.split .sp-fig img{will-change:transform;transform:scale(1.08);
  transition:transform 1.4s var(--ease)}
.js .split .sp-fig::after{content:"";position:absolute;inset:0;z-index:2;
  background:var(--paper);transform:translateY(0);
  transition:transform 1.05s cubic-bezier(.76,0,.24,1)}
.sec.white .split .sp-fig::after{background:var(--white)}
.sec.pap2 .split .sp-fig::after{background:var(--paper-2)}
.js .split.is-in .sp-fig::after{transform:translateY(-101%)}
.reveal-off .split .sp-fig::after{display:none}
.reveal-off .split .sp-fig img{transform:none}

/* ── Numbers ───────────────────────────────────────────────── */
.figs{display:grid;grid-template-columns:repeat(4,1fr);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.figs > div{padding:clamp(24px,3vw,40px) clamp(18px,2vw,30px);border-right:1px solid var(--line);
  position:relative;overflow:hidden}
.figs > div:last-child{border-right:0}
.figs b{display:block;font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.875rem,4.2vw,3.625rem);letter-spacing:-.038em;line-height:1;
  color:var(--ink);font-variant-numeric:lining-nums tabular-nums}
.figs span{display:block;margin-top:10px;font-size:0.6875rem;letter-spacing:.15em;
  text-transform:uppercase;color:var(--ink-3);font-weight:600;line-height:1.5}
.figs > div::before{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;
  background:var(--blue);transform:scaleX(0);transform-origin:0 50%;
  transition:transform 1s var(--ease) var(--stagger,0ms)}
.figs.is-in > div::before,[data-reveal].is-in .figs > div::before{transform:scaleX(1)}
@media (max-width:819.98px){
  .figs{grid-template-columns:repeat(2,1fr)}
  .figs > div:nth-child(2n){border-right:0}
  .figs > div:nth-child(-n+2){border-bottom:1px solid var(--line)}
}
@media (max-width:420px){.figs{grid-template-columns:1fr}
  .figs > div{border-right:0;border-bottom:1px solid var(--line)}
  .figs > div:last-child{border-bottom:0}}

/* ── Process steps ─────────────────────────────────────────── */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:clamp(22px,2.6vw,38px);counter-reset:step}
.steps > div{position:relative;padding-top:clamp(26px,3vw,38px);border-top:1px solid var(--line)}
.steps > div::before{counter-increment:step;content:counter(step,decimal-leading-zero);
  position:absolute;top:0;left:0;transform:translateY(-50%);
  font-family:"Schibsted Grotesk",sans-serif;font-size:0.7812rem;font-weight:600;
  letter-spacing:.16em;color:var(--blue-deep);background:var(--paper);padding-right:14px}
.sec.white .steps > div::before{background:var(--white)}
.sec.pap2 .steps > div::before{background:var(--paper-2)}
.steps h3{font-size:clamp(1.0625rem,1.7vw,1.375rem);letter-spacing:-.018em;line-height:1.25;
  margin:0 0 clamp(11px,1.2vw,15px)}
.steps p{margin:0;color:var(--ink-2);font-size:0.9688rem;line-height:1.66}
.steps > div::after{content:"";position:absolute;top:-1px;left:0;width:100%;height:1px;
  background:var(--blue);transform:scaleX(0);transform-origin:0 50%;
  transition:transform .9s var(--ease) var(--stagger,0ms)}
[data-reveal].is-in .steps > div::after{transform:scaleX(1)}

/* ── Marquee ───────────────────────────────────────────────── */
.mq{position:relative;overflow:hidden;border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);padding:clamp(16px,1.8vw,24px) 0;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.mq-track{display:flex;align-items:center;width:max-content;will-change:transform}
/* trailing margin, never a flex gap — a gap is not duplicated with the items
   and the loop visibly jumps every cycle */
.mq-track > *{margin-right:clamp(26px,3.4vw,54px);flex:0 0 auto;
  font-family:"Schibsted Grotesk",sans-serif;font-size:clamp(1.0625rem,2vw,1.625rem);
  letter-spacing:-.02em;color:var(--ink-3);white-space:nowrap;transition:color .35s}
.mq-track > a:hover{color:var(--blue-deep)}
.mq-track .dot{color:var(--blue);opacity:.55;font-size:.7em}

/* ── Prose link underline sweep ────────────────────────────── */
.prose a:not(.btn){background-image:linear-gradient(var(--blue-deep),var(--blue-deep));
  background-size:0% 1px;background-repeat:no-repeat;background-position:0 100%;
  transition:background-size .45s var(--ease)}
.prose a:not(.btn):hover{background-size:100% 1px}

/* ── Section heading rule that draws itself ────────────────── */
.js .shead{position:relative}
.js .shead::after{content:"";position:absolute;left:0;bottom:calc(-1 * clamp(16px,2vw,26px));
  width:100%;height:1px;background:var(--line);transform:scaleX(0);transform-origin:0 50%;
  transition:transform 1.1s var(--ease)}
.js .shead.is-in::after{transform:scaleX(1)}
.reveal-off .shead::after{transform:scaleX(1)}

/* ── Service cards get a photograph ────────────────────────────
   Text-only cards were the blandest thing on the town pages. */
.cgrid > a{padding:0;gap:0;overflow:hidden}
.cg-fig{display:block;position:relative;overflow:hidden;background:var(--paper-2);
  aspect-ratio:16/10}
.cg-fig img{width:100%;height:100%;object-fit:cover;
  transform:scale(1.02);transition:transform 1.1s var(--ease),filter .6s var(--ease);
  filter:saturate(.92)}
.cgrid > a:hover .cg-fig img{transform:scale(1.075);filter:saturate(1)}
.cg-fig::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,transparent 55%,rgba(12,16,20,.14));pointer-events:none}
.cgrid > a > h3,.cgrid > a > p,.cgrid > a > .go{padding-inline:var(--cell-p)}
.cgrid > a > h3{padding-top:clamp(20px,2.2vw,26px)}
.cgrid > a > p{padding-top:8px}
.cgrid > a > .go{padding-block:clamp(16px,1.8vw,22px) clamp(20px,2.2vw,26px);margin-top:auto}

/* ── Inner page banner: a very slow drift ──────────────────────
   Same idea as the homepage, on its own selector so the site-wide
   transform reset for carousels cannot switch it off. */
.pb-bg img{transform-origin:56% 48%;animation:pbDrift 30s cubic-bezier(.22,.61,.36,1) forwards}
@keyframes pbDrift{from{transform:scale(1.13)}to{transform:scale(1)}}
@media (prefers-reduced-motion:reduce){.pb-bg img{animation:none;transform:none}}

/* ============================================================
   TIDY PASS
   Every grid gets an explicit column count that divides its item
   count at every breakpoint. auto-fit decides the column count
   from available width, which is exactly how you end up with a
   last row holding one card and a 646px hole beside it.
   ============================================================ */

/* 8 service cards */
.cgrid{grid-template-columns:repeat(4,1fr)}
/* 10 town cards on the areas hub */
.cgrid.cg-5{grid-template-columns:repeat(5,1fr)}
@media (max-width:1199px){.cgrid,.cgrid.cg-5{grid-template-columns:repeat(2,1fr)}}
@media (max-width:640px){.cgrid,.cgrid.cg-5{grid-template-columns:1fr}}

/* 4 steps */
.steps{grid-template-columns:repeat(4,1fr)}
@media (max-width:1080px){.steps{grid-template-columns:repeat(2,1fr)}}
@media (max-width:600px){.steps{grid-template-columns:1fr}}

/* 4 contact details */
.strip{grid-template-columns:repeat(4,1fr)}
@media (max-width:900px){.strip{grid-template-columns:repeat(2,1fr)}
  .strip > div:nth-child(2n){border-right:0}
  .strip > div:nth-child(-n+2){border-bottom:1px solid var(--line)}}
@media (max-width:520px){.strip{grid-template-columns:1fr}
  .strip > div{border-right:0;border-bottom:1px solid var(--line)}
  .strip > div:last-child{border-bottom:0}}

/* 16 reviews */
.twall{grid-template-columns:repeat(4,1fr)}
@media (max-width:1199px){.twall{grid-template-columns:repeat(2,1fr)}}
@media (max-width:640px){.twall{grid-template-columns:1fr}}

/* 12 gallery frames */
.ggrid{grid-template-columns:repeat(4,1fr)}
@media (max-width:1199px){.ggrid{grid-template-columns:repeat(3,1fr)}}
@media (max-width:860px){.ggrid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:520px){.ggrid{grid-template-columns:1fr}}

/* 3 sitemap columns */
.smap{grid-template-columns:repeat(3,1fr)}
@media (max-width:819.98px){.smap{grid-template-columns:1fr}}

/* two-up tick lists */
.tick.two{grid-template-columns:repeat(2,1fr)}
@media (max-width:640px){.tick.two{grid-template-columns:1fr}}

/* A rule under every section header is what makes each section read as the
   same template stamped again. The heading is its own separation. */
.js .shead::after,.reveal-off .shead::after{content:none}

/* ── Reviews wall: space, not a lattice ────────────────────────
   Sixteen bordered cards sitting inside a bordered grid drew 48 rules on
   their own and put a box inside a box on every one. Space separates them
   now; the tint is the only edge. */
.twall{background:none;border:0;border-radius:0;overflow:visible;
  gap:clamp(16px,1.8vw,26px)}
.twall .tcard{border:0;border-radius:2px;background:var(--paper-2);
  transition:background .5s var(--ease)}
.sec.pap2 .twall .tcard,.sec.white .twall .tcard{background:var(--paper-2)}
.twall .tcard:hover{transform:none;box-shadow:none;background:var(--white)}
.twall .tcard cite{border-top:0;padding-top:2px;color:var(--ink-3);font-weight:500}
.twall .tcard h3{color:var(--blue-deep);opacity:1}

/* ── Two column pages: close the dead gutter ───────────────────
   The text column was 1fr (910px at 1440) while .prose capped the words at
   74ch (794px), so 115px sat empty inside the column and another 79px in the
   gap. Size the column to the measure instead and let the slack be a single,
   deliberate gutter. */
.pcols{grid-template-columns:minmax(0,66ch) minmax(300px,500px);
  justify-content:space-between;column-gap:clamp(32px,3.4vw,64px)}
.pcols > .prose{max-width:none}
@media (max-width:1120px) and (min-width:961px){
  .pcols{grid-template-columns:minmax(0,1fr) 300px;column-gap:clamp(30px,3.2vw,44px)}
}

/* ── Sidebar links card ────────────────────────────────────── */
.aside-links h3{font-size:0.7812rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-3);font-weight:600;margin-bottom:16px}
.aside-links ul{display:grid;gap:2px}
.aside-links li{border-top:1px solid var(--line)}
.aside-links li:first-child{border-top:0}
.aside-links a{display:block;padding-block:11px;font-size:0.9688rem;color:var(--ink-2);
  transition:color .3s var(--ease),padding-left .35s var(--ease)}
.aside-links a:hover{color:var(--blue-deep);padding-left:6px}

/* ── One grade over every content photograph ───────────────────
   The job photos come from a dozen phone cameras with a dozen white balances,
   and that inconsistency is what reads as amateur. A single grade across the
   set makes it look commissioned. Brand marks and the page banner are
   excluded by name, not by luck. */
.sp-fig img,.cg-fig img,.mfig img,.wfig img,.ggrid img{
  filter:saturate(.84) contrast(1.045) brightness(1.005)}
.logo img,.ft-brand img,.rest-logo img,.pb-bg img{filter:none}
/* the wash is what separates graded from merely desaturated */
.sp-fig,.cg-fig,.mfig,.ggrid .mfig{position:relative}
.sp-fig::before,.cg-fig::before{content:"";position:absolute;inset:0;z-index:1;
  pointer-events:none;background:#8fa4b4;mix-blend-mode:soft-light;opacity:.14}
.ggrid .mfig::before{content:"";position:absolute;inset:0;z-index:1;
  pointer-events:none;background:#8fa4b4;mix-blend-mode:soft-light;opacity:.14}
/* The name sat at the bottom of a stretched card, which opened a hole between
   the quote and the name on every short review. Let it follow the quote. */
.twall .tcard cite{margin-top:14px}
.twall .tcard{justify-content:flex-start}

/* ── Contact page form ─────────────────────────────────────────
   .ctc is the homepage's two-up wrapper (details beside the form). Reusing it
   here, where it holds only the form, dropped the form into a 0.92fr track and
   squeezed the inputs to 117px. This wrapper is a single column by design. */
/* .form is already a complete panel with its own ground, border and padding,
   so this wrapper is a pass-through. Boxing it again put a box inside a box. */
.cform{display:block}
.cform .form{width:100%;margin:0}
/* The contact page's form is the point of the page, not a sidebar note. */
.pcols.pcols-form{grid-template-columns:minmax(0,1fr) minmax(380px,520px)}
@media (max-width:1120px) and (min-width:961px){
  .pcols.pcols-form{grid-template-columns:minmax(0,1fr) minmax(340px,420px)}
}

/* Must come last and match the modifier's specificity: a media query adds none,
   so .pcols.pcols-form was beating the stacking rule at every width. */
@media (max-width:960px){
  .pcols,.pcols.pcols-form{grid-template-columns:1fr;column-gap:0}
}
/* Stacked, the form would otherwise run to 766px and a single-line name field
   that wide looks wrong. */
@media (max-width:960px){.cform{max-width:640px}}

/* ── Tidy pass 2: measured defects ─────────────────────────────────────── */

/* Text was running 80-99 characters a line at 1440 and 744. 66ch lands it at
   about 72-78, which is where it should be. Measured with Range rects, not a
   character-width estimate — the estimate was out by 20%. */
.prose{max-width:66ch}
.pcols > .prose{max-width:none}
.callout p,.fq .ans p,.fq .ans div{max-width:64ch}

/* .faq was centred with margin-inline:auto while every one of its siblings sits
   on the shell's left edge, so it started 202px in from the heading above it. */
.faq{margin-inline:0}

/* Two numbers side by side reads better than four stacked on a phone. */
@media (max-width:420px){
  .figs{grid-template-columns:repeat(2,1fr)}
  .figs > div{border-right:1px solid var(--line);border-bottom:1px solid var(--line)}
  .figs > div:nth-child(2n){border-right:0}
  .figs > div:nth-child(n+3){border-bottom:0}
}

/* The sitemap ran one column from 820 down, leaving 70% of every row empty. */
/* 3 columns or 1 — never 2, because 3 items do not divide 2. */
@media (max-width:819.98px){.smap{grid-template-columns:repeat(3,1fr);gap:clamp(20px,3vw,36px)}}
@media (max-width:620px){.smap{grid-template-columns:1fr}}

/* A long email address inflated its own track, so "four equal columns" was not.
   minmax(0,1fr) lets a track shrink below its content; min-width:0 lets the
   content wrap instead of pushing. */
.strip{grid-template-columns:repeat(4,minmax(0,1fr))}
.strip > div{min-width:0}
.strip b,.strip a{overflow-wrap:anywhere}
.ft-top > *{min-width:0}
.ft-top a{overflow-wrap:anywhere}

/* Pill rows were leaving a single orphan on the last line. A grid with a
   dividing column count cannot. */
@media (min-width:901px){
  .rel,.chips{display:grid;grid-template-columns:repeat(4,1fr);gap:9px;align-items:stretch}
  .rel a,.chips li{display:flex;align-items:center;justify-content:center;text-align:center}
}
@media (min-width:641px) and (max-width:900px){
  .rel,.chips{display:grid;grid-template-columns:repeat(3,1fr);gap:9px}
  .rel a,.chips li{display:flex;align-items:center;justify-content:center;text-align:center}
}
@media (max-width:640px){
  .rel,.chips{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}
  .rel a,.chips li{display:flex;align-items:center;justify-content:center;text-align:center}
}

/* The section label's rule was 50% white — invisible on a white section. The
   homepage uses a blue one for the same slot. */
.shead .eyebrow::before,.pb .eyebrow::before{background:var(--blue);width:26px}
.pb .eyebrow::before{background:rgba(255,255,255,.6)}

/* An iPad Air is exactly 820 wide and was getting both sides of the boundary:
   the phone rules fired at max-width:820 while the tablet rules fired at
   min-width:820. */
@media (max-width:819.98px){.figs{grid-template-columns:repeat(2,1fr)}}

/* ── Type: one size per role ───────────────────────────────────────────── */
/* A body-level h2 was rendering at 38px in .prose and 36px in a .split block,
   and a card h3 at 23px in .callout and 22px in .steps. Two sizes 2px apart
   doing the same job reads as a mistake rather than a decision. */
.prose h2,.split .sp-body h2{font-size:clamp(1.5rem,2.9vw,2.375rem);letter-spacing:-.025em;line-height:1.12}
.callout h3,.steps h3,.cgrid h3{font-size:clamp(1.0625rem,1.75vw,1.375rem);letter-spacing:-.018em;line-height:1.25}

/* Five of every six wrapping headings ended with one word alone on the last
   line. Balancing costs nothing and it is the difference between a heading
   that looks set and one that looks like it fell there. */
h1,h2,h3,.pcta p,.pb-sub{text-wrap:balance}
.prose p,.fq .ans p{text-wrap:pretty}

/* Two cells in the contact strip were 40px while the third was 19px. */
.strip b{font-size:clamp(1.25rem,2.4vw,1.875rem)!important;letter-spacing:-.03em;line-height:1.15}
.strip b a{font-size:inherit;letter-spacing:inherit}

/* The block image and its text now start on the same line. Centring them made
   every stacked block start at a different height. */
.split{align-items:start}
.split .sp-body{padding-top:clamp(2px,0.6vw,10px)}

/* ── Tidy pass 3: doubled rules and a component with four fills ─────────── */

/* The blue underline sat directly on top of the strip's own border-bottom —
   two painted rules with a 0px gap between them. Let the blue replace it. */
.figs > div::before{bottom:-1px;height:1px}

/* Same doubling in the contact strip once it goes two-up: the last row's cell
   borders landed on the component's own bottom rule. */
@media (max-width:900px){
  .strip > div:nth-last-child(-n+2){border-bottom:0}
}
@media (max-width:520px){
  .strip > div:nth-last-child(-n+2){border-bottom:0}
  .strip > div:not(:last-child){border-bottom:1px solid var(--line)}
}

/* .callout was white on white in one context, tinted in another, and outlined
   in a third — one component with four different relationships to its ground.
   One rule now: a tint with no outline, and the blue edge as the only accent. */
.callout,.sec.white .callout,.sec.pap2 .callout,.aside .callout,.sec.white .aside .callout{
  background:var(--paper-2);border:0;border-left:2px solid var(--blue);border-radius:2px}
.sec.pap2 .callout,.sec.pap2 .aside .callout{background:var(--white)}

/* The form was a bordered box holding six bordered boxes. The tint separates it
   from the page and lets the white fields read as the only outlined things. */
.form{background:var(--paper-2);border:0}
.sec.pap2 .form,.sec.white .form{background:var(--paper-2)}

/* ── Tidy pass 4: the last confirmed defects ───────────────────────────── */

/* The homepage town grid ran 3 columns from 620px with 10 towns, so 744 and
   820 printed two empty lattice cells as a solid grey slab beside Bagshot.
   10 divides by 2 and by 5, never by 3. */
@media (min-width:620px) and (max-width:959.98px){
  .towns{grid-template-columns:repeat(2,1fr)}
}

/* The reviews wall ran four across from 1200px, which wrapped every quote
   every four words on the one page whose job is reading quotes. Two columns
   still divides 16 and gives each quote a proper measure. */
.twall{grid-template-columns:repeat(2,1fr)}
@media (max-width:640px){.twall{grid-template-columns:1fr}}

/* Ten town cards at five across left 23 characters a line. */
.cgrid.cg-5{grid-template-columns:repeat(2,1fr)}
@media (min-width:1600px){.cgrid.cg-5{grid-template-columns:repeat(5,1fr)}}

/* Three cards in a two-column sidebar leaves one alone on the last row. */
@media (max-width:960px){.aside{grid-template-columns:1fr}}

/* The about figure changed crop ratio by 87% between breakpoints. */
.about-fig img{aspect-ratio:3/2;height:auto;object-fit:cover}

/* Uncapped copy on the homepage area note ran to 108 characters. */
.area-note p,.about-body p{max-width:600px}

/* ── Form status ───────────────────────────────────────────── */
.fmsg{margin:14px 0 0;font-size:0.9688rem;line-height:1.55;min-height:0}
.fmsg:empty{display:none}
.fmsg.is-good{color:var(--blue-ink);font-weight:500}
.fmsg.is-bad{color:#9a2c2c}
.form button[disabled]{opacity:.6;cursor:progress}
.smap-note{font-size:0.9062rem;line-height:1.6;color:var(--ink-3);margin:-6px 0 18px;max-width:44ch}

/* ── Breadcrumbs removed ───────────────────────────────────────
   The trail is gone from the page; the BreadcrumbList JSON-LD still carries it
   for Google. The banner keeps its eyebrow, which gives the reader their
   bearings without navigation furniture. */
.crumb{display:none}

/* ============================================================
   SERVICE PAGE COMPONENTS
   One design language, several shapes. Each service page draws a
   different subset in a different order, so the nine pages read as
   nine pages rather than one template run nine times.
   ============================================================ */

/* ── Timeline: a numbered sequence, each step with its own photo ── */
.tline{display:grid;gap:clamp(30px,4vw,58px);position:relative}
.tline > div{display:grid;grid-template-columns:clamp(180px,22vw,300px) minmax(0,1fr);
  gap:clamp(22px,3vw,44px);align-items:center;position:relative}
.tline figure{margin:0;overflow:hidden;border-radius:2px;background:var(--paper-2);
  aspect-ratio:4/3;position:relative}
.tline figure img{width:100%;height:100%;object-fit:cover;
  filter:saturate(.84) contrast(1.045);transform:scale(1.06);
  transition:transform 1.3s var(--ease)}
.tline > div:hover figure img{transform:scale(1)}
.tline .tl-n{display:block;font-size:0.6875rem;letter-spacing:.2em;font-weight:600;
  color:var(--blue-deep);margin-bottom:11px}
.tline h3{font-size:clamp(1.1875rem,2vw,1.625rem);letter-spacing:-.02em;line-height:1.2;
  margin:0 0 clamp(12px,1.3vw,16px)}
.tline p{margin:0;color:var(--ink-2);max-width:56ch}
/* the rule that joins the steps, drawn on reveal */
.tline::before{content:"";position:absolute;left:clamp(90px,11vw,150px);top:0;bottom:0;width:1px;
  background:var(--line);transform:scaleY(0);transform-origin:50% 0;
  transition:transform 1.6s var(--ease)}
[data-reveal].is-in .tline::before,.tline.is-in::before{transform:scaleY(1)}
@media (max-width:760px){
  .tline > div{grid-template-columns:1fr;gap:16px}
  .tline::before{display:none}
}

/* ── Compare: two or three options side by side ─────────────── */
.compare{display:grid;gap:1px;background:var(--line);border:1px solid var(--line);border-radius:2px;
  overflow:hidden;grid-template-columns:repeat(3,1fr)}
.compare.two{grid-template-columns:repeat(2,1fr)}
.compare > div{background:var(--paper);padding:var(--cell-p);display:flex;flex-direction:column;
  gap:13px;transition:background .45s var(--ease)}
.sec.white .compare > div{background:var(--white)}
.sec.pap2 .compare > div{background:var(--paper-2)}
.compare > div:hover{background:var(--white)}
.sec.white .compare > div:hover{background:var(--paper-2)}
.compare h3{font-size:clamp(1.125rem,1.8vw,1.4375rem);letter-spacing:-.02em;line-height:1.2;margin:0}
.compare .cmp-lead{margin:0;color:var(--ink-2);font-size:0.9688rem;line-height:1.6}
.compare ul{display:grid;gap:9px;margin:4px 0 0;list-style:none;padding:0}
.compare li{position:relative;padding-left:20px;font-size:0.9062rem;color:var(--ink-3);line-height:1.55}
.compare li::before{content:"";position:absolute;left:0;top:.66em;width:7px;height:7px;
  border-radius:50%;background:var(--blue);opacity:.5}
.compare .cmp-tag{margin-top:auto;padding-top:12px;font-size:0.6875rem;letter-spacing:.15em;
  text-transform:uppercase;font-weight:600;color:var(--blue-deep)}
@media (max-width:900px){.compare,.compare.two{grid-template-columns:1fr}}

/* ── Symptom rows: what you can see, what it usually means ──── */
.symp{border-top:1px solid var(--line)}
.symp > div{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(20px,3vw,52px);padding:clamp(20px,2.4vw,30px) 0;border-bottom:1px solid var(--line);
  align-items:baseline}
.symp b{font-family:"Schibsted Grotesk",sans-serif;font-weight:400;
  font-size:clamp(1.0625rem,1.7vw,1.3125rem);letter-spacing:-.018em;line-height:1.3;color:var(--ink)}
.symp p{margin:0;color:var(--ink-2);font-size:0.9688rem;line-height:1.66}
.symp .symp-head{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:clamp(20px,3vw,52px);padding-bottom:12px;border-bottom:0}
.symp .symp-head span{font-size:0.6875rem;letter-spacing:.16em;text-transform:uppercase;
  font-weight:600;color:var(--ink-3)}
@media (max-width:760px){
  .symp > div,.symp .symp-head{grid-template-columns:1fr;gap:8px}
  .symp .symp-head{display:none}
}

/* ── Duo: two columns of prose, for breaking up a long run ──── */
.duo{columns:2;column-gap:clamp(34px,4.5vw,72px);column-rule:1px solid var(--line)}
.duo p{margin:0 0 1.05em;break-inside:avoid;color:var(--ink-2)}
.duo p:last-child{margin-bottom:0}
@media (max-width:820px){.duo{columns:1;column-rule:0}}

/* ── Feature panel: a single statement on the ink ground ────── */
.feat{position:relative;isolation:isolate;background:var(--ink);color:var(--white);
  border-radius:2px;overflow:hidden;padding:clamp(34px,5vw,72px)}
.feat::before{content:"";position:absolute;inset:0;z-index:-1;opacity:.10;
  background-image:linear-gradient(90deg,#fff 1px,transparent 1px);
  background-size:clamp(56px,6vw,96px) 100%}
.feat h3{font-size:clamp(1.375rem,2.8vw,2.375rem);letter-spacing:-.026em;line-height:1.15;
  margin:0 0 16px;max-width:22ch;color:var(--white)}
.feat p{margin:0;color:rgba(255,255,255,.78);max-width:60ch}
.feat .tick li{color:rgba(255,255,255,.78)}
.feat .tick li::before{border-color:var(--blue)}

/* ── Two column prose heading ──────────────────────────────── */
.duo-h{font-size:clamp(1.5rem,2.9vw,2.375rem);letter-spacing:-.025em;line-height:1.12;
  margin:0 0 clamp(18px,2vw,28px);max-width:24ch;text-wrap:balance}
.duo + .tick{margin-top:clamp(20px,2.2vw,30px)}

/* Rows inside a rebuilt band keep the same rhythm as a .split pair. */
section > .shell > div + div{margin-top:clamp(44px,5vw,76px)}
.split + .duo-h{margin-top:0}
section > .shell > .split + div,
section > .shell > div + .split{margin-top:clamp(56px,6.5vw,104px)}
/* The heading that introduces the opening paragraph. */
.intro-h{font-size:clamp(1.5rem,2.9vw,2.375rem);letter-spacing:-.025em;line-height:1.12;
  margin:0 0 clamp(16px,1.8vw,24px);text-wrap:balance}
.prose .intro-h + .lede{margin-top:0}

/* Text-only timeline: the number column carries the sequence. */
.tline > div{grid-template-columns:clamp(64px,7vw,104px) minmax(0,1fr);align-items:start}
.tline .tl-n{font-size:clamp(1.25rem,2.4vw,2rem);letter-spacing:-.03em;font-weight:400;
  font-family:"Schibsted Grotesk",sans-serif;color:var(--blue-deep);margin:0}
.tline::before{left:clamp(30px,3.4vw,50px)}
@media (max-width:760px){.tline > div{grid-template-columns:1fr;gap:10px}}

/* ---- the action rail needs its own lane -------------------------------------
   #gb-rail is fixed against the right edge and ships live, so it is part of the
   layout whether the grid knows it or not. The shell was min(1360px, 92vw),
   which leaves a 4vw margin — narrower than the rail at every width below about
   1490px, so prose ran underneath it and lines lost their last few characters
   mid-word on iPad. Reserve the rail's width symmetrically: both margins stay
   equal, so centred headings stay centred, and the rail floats in the gutter
   instead of over the text. Phones are handled separately below — 84px of
   margin each side is not affordable at 390px. */
@media (min-width:700px){
  :root{ --shell:min(1360px, 92vw, calc(100vw - 168px)) }
}

/* A tick list closing a split's text column, after the relocation above. */
.split .sp-body .tick{margin-top:clamp(18px,2vw,26px);margin-bottom:0}

/* ---- timeline band ----------------------------------------------------------
   .tline paragraphs cap at 56ch for readability, which in a full-width shell
   left roughly 530px — about 40% of the row — blank down the whole sequence.
   Give the band two columns instead: the section head holds the left column and
   sticks while the steps run past it on the right. The measure stays 56ch, the
   width gets used, and it works for any number of steps rather than needing an
   even count the way a multi-column grid would. */
@media (min-width:1000px){
  .tl-band > .shell{display:grid;
    grid-template-columns:minmax(300px,392px) minmax(0,1fr);
    gap:clamp(44px,5.5vw,88px);align-items:start}
  .tl-band .shead{grid-template-columns:1fr;gap:16px;margin-bottom:0;
    position:sticky;top:calc(var(--hdr-h,86px) + 34px)}
  /* The section h2 runs to 52px full width; in a 390px column that broke into
     five stub lines. Size it to the column it now lives in. */
  .tl-band .shead h2{font-size:clamp(1.625rem,2.5vw,2.125rem);line-height:1.14}
  .tl-band .shead p{max-width:none}
  .tl-band .tline{margin-top:4px}
}

/* A split's photo keeps its 4:3 shape, so when the text column runs longer —
   which it now does wherever a tick list sits in it — the photo left a tall
   blank below itself. Let the figure fill the row instead; the image already
   covers, so it crops rather than distorts. Only the figure stretches: the copy
   stays centred, so rows where the text is the shorter side are unaffected. */
@media (min-width:861px){
  .split .sp-fig{align-self:stretch}
  .split .sp-fig img{aspect-ratio:auto;min-height:100%}
}

/* Only .duo-h and .intro-h balanced their lines, so other headings broke wherever
   the line ran out — "What a full strip and re- / cover actually involves" split
   across its own hyphen. Balance them all; pretty keeps single-word last lines
   off the body copy. */
.prose h2,.prose h3,.split .sp-body h2,.shead h2,
.tline h3,.steps h3,.callout h3,.feat h3{text-wrap:balance}

/* ---- contact details strip --------------------------------------------------
   Two separate faults. A later rule pinned this to four columns at EVERY width,
   overriding the responsive breakpoints above it, so on a 390px phone each cell
   was 46px wide and all four values wrapped to shreds. And four columns are too
   narrow for the content even on a desktop: at 1440 a cell has 254px of room and
   "grant@gbroofingservices.co.uk" needs 405px at the display size, so the email
   and the opening hours always broke across two lines.

   Two columns give a cell 572px at 1440 and 315px on a phone — enough for every
   value to sit on one line at every width, which is the point of the band. Below
   640px there is not room for two, so it stacks. Measured, not guessed. */
.strip{grid-template-columns:repeat(2,minmax(0,1fr))}
.strip > div{border-right:1px solid var(--line);border-bottom:1px solid var(--line)}
.strip > div:nth-child(2n){border-right:0}
.strip > div:nth-last-child(-n+2){border-bottom:0}
/* Each value now fits, so stop breaking words mid-address as a fallback. */
.strip b,.strip a{overflow-wrap:normal}
.strip b{white-space:nowrap}

/* Two columns need about 800px of viewport before the cell can hold the email on
   one line — below that the reserved rail lane eats the width faster than the
   type shrinks (at 700px the cell is 222px and the address needs 270px). Stack
   below 900px, which leaves real headroom rather than a marginal fit. */
@media (max-width:899.98px){
  .strip{grid-template-columns:minmax(0,1fr)}
  .strip > div{border-right:0;border-bottom:1px solid var(--line)}
  .strip > div:last-child{border-bottom:0}
  .strip b{font-size:clamp(1.0625rem,5.2vw,1.625rem)!important}
}

/* A short lead-in, not a chapter: these three pages exist to show the pictures,
   the towns and the reviews, so the writing above them is one paragraph and the
   band is padded to match. Anything longer sits below the thing people came for. */
.intro-brief{padding-top:clamp(40px,4.6vw,64px);padding-bottom:clamp(34px,3.6vw,54px)}
.intro-brief .prose{max-width:72ch}
.intro-brief .prose .lede{margin-bottom:0}

/* ---- open drawer vs the fixed header ---------------------------------------
   The header is transparent and sits above the drawer (z 600 vs 590), which is
   correct — the burger is the close control and has to stay reachable. But the
   drawer scrolls, so once it did, its links passed under the transparent header
   and overprinted the logo and the number. Give the header a solid ground for as
   long as the menu is open; raising the drawer's z-index instead would bury the
   only way to close it. */
/* The drawer scrolls under the header, so the header needs a solid ground while
   the menu is open. The site already has that treatment for the scrolled state,
   so the open menu simply adopts it — background, link colours, burger colour and
   the dark logo — rather than half-inventing a second one. */
.hdr.menu-open{padding:11px 0;border-bottom:1px solid var(--line);background:var(--paper)}
.hdr.menu-open::before{opacity:0}
.hdr.menu-open .logo img{height:clamp(46px,4.6vw,62px)}
.hdr.menu-open .tel,.hdr.menu-open .navlink{color:var(--ink)}
.hdr.menu-open .burger span,
.hdr.menu-open .burger span::before,
.hdr.menu-open .burger span::after{background:var(--ink)}
.hdr.menu-open .burger.open span{background:transparent}
/* and room at the bottom so the last link clears the docked action bar */
@media (max-width:699px){ .drawer{padding-bottom:120px} }

/* The dropdown opened on hover and on :focus-within, but the button's
   aria-expanded never moved, so a screen reader was told it was closed while it
   was open. It is now driven by a class the script controls as well. */
.nav .drop.open .dropm{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}

/* ---- touch targets on coarse pointers --------------------------------------
   Keyed to the input device, not the viewport width: a 12.9in iPad is 1366px wide
   and entirely a touch screen. Stacked footer link lists are left alone — their
   pitch is already ~38px, and padding them would balloon the footer for no gain.
   The two raised here are the ones people actually reach for. */
@media (pointer:coarse){
  .hdr .tel{min-height:44px;display:inline-flex;align-items:center}
  .ft a[href^="mailto:"],.ft a[href^="tel:"]{min-height:44px;display:inline-flex;align-items:center}
}
