/* Cedarline Heating & Cooling — generated by TradeKit. Theme: pine · Fonts: Barlow Condensed + Barlow */
:root{--bg:#151a17;--surface:#1d2420;--dark2:#0f1311;--footer-bg:#191f1b;
--accent:#6cb389;--accent-lt:#8fc9a5;--accent-rgb:108,179,137;
--cta:#c4643c;--cta-hover:#a95634;--on-cta:#ffffff;
--text:#eef3ef;--off:#cbd6ce;--muted:#8a958c;--placeholder:#828b85;--ok:#6cb389;
--label:#adb2ae;
/* Two values that used to be baked straight into the rules that needed
   them, which was fine until the demo swatch row could cross from a dark
   palette to a light one. Variables now, so the switcher can move them
   with the rest.
   --hero-acc  the accent lifted until it reads on the hero scrim.
   --ink-rgb   black or white, for hairlines and empty stars. */
--hero-acc:#6cb389;--ink-rgb:255,255,255;
/* 58.53 the hero headline's coloured line - a theme may set a deeper shade (Harbour) */
--hero-hl:#86c7a1;
--qband-l:#31513e;--qband-r:#416b52;--qband-ink:#f4f7fa;--qband-accent:#6cb389;
/* --accent-ink is the accent as TEXT. The accent is chosen to carry
   white on a button, which is a different job: on a light build his
   orange measures about 3.2:1 against the footer, so the phone, the
   email and the review link all read as washed out rather than as
   links. Mixed toward the text colour until it clears 4.5:1 on the
   footer, which keeps his hue and only takes the lightness. Dark
   builds already pass, so nothing there changes. */
--accent-ink:#6cb389;
--hdr-ink:#ffffff;

--border:rgba(108,179,137,0.16);--border-soft:rgba(108,179,137,0.08);
--font-display:'Barlow Condensed', sans-serif;--font-body:'Barlow', sans-serif;--col:1100px;--tight:760px}

*,*::before,*::after{box-sizing:border-box}html{scroll-behavior:smooth}
body{margin:0;overflow-x:clip;background:var(--bg);color:var(--off);font-family:var(--font-body);font-stretch:normal;
font-size:calc(16px * 0.88);line-height:1.65;-webkit-font-smoothing:antialiased}
/* Headings had margin:0, so anything following sat right against
   them and every case needed patching inline. A default gap here,
   and adjacent margins collapse where a following element sets its
   own — so nothing doubles up. */
/* h2 had no font-size at all. h1,h2,h3 above sets family, weight and
   colour, and this rule set the margin - so every section heading on
   every page rendered at the browser's default 1.5em, unrelated to the
   h1 and unmoved by the type scale. It looked right only because 24px
   happens to sit under this pairing's h1 at Standard. */
h2{margin:0 0 18px;font-size:calc(28px * 0.88);line-height:1.15}
h3{margin:0 0 8px}
h1,h2,h3{font-family:var(--font-display);font-stretch:normal;color:var(--text);font-weight:400;
line-height:1.05;letter-spacing:.01em;text-wrap:balance}
h1{margin:0}
h1{font-size:calc(clamp(42px,6.4vw,74px) * 0.88)}h2{font-size:calc(clamp(32px,4.2vw,48px) * 0.88)}h3{font-size:calc(22px * 0.88)}

p{margin:0 0 1.1em}
/* Same as everycall.css: no underline anywhere, and a hover answered by
   colour rather than a rule. Underlines on phone numbers and inline links
   made body copy look littered. Buttons and the nav/footer lists set
   their own hover colours, which outrank this. */
a{color:var(--accent);text-decoration:none}
a:hover{color:var(--accent-lt)}
/* Every phone link, not just the ones given a class.

   .tel covered the inline ones in a sentence. The buttons never had it -
   "Call (250) 609-1875" is an anchor with no class, and on a narrow
   phone it splits after "Call (250)" and leaves the rest on the line
   below. A number somebody has to reassemble before dialling it is the
   worst place on the page for a line break, since ringing is the thing
   the button exists to cause.

   Attribute selector so it catches anything added later without
   anybody having to remember. */
a[href^="tel:"]{white-space:nowrap}
.tel{white-space:nowrap}strong,b{color:var(--text);font-weight:500}
.eyebrow{font-size:calc(14px * 0.88);font-weight:500;letter-spacing:.22em;text-transform:uppercase;color:var(--accent);
margin:0 0 22px;display:flex;align-items:center;gap:12px;line-height:1}   /* 58.210 line-height 1: at the body's 1.65 the capitals sat about 5px down inside their own line, so a section read 55px to the eyebrow, not 50. 4px more under it keeps the gap to the heading as it was. */
/* Ported verbatim from everycall.css, reasoning included. Thinner and
   knocked back on purpose: at 2px solid accent this read as a second
   coloured element next to the label rather than a rule mark — and on
   --dark2 the extra contrast made it look heavier than the identical
   mark on --surface. 1px at half opacity evens that out. Slightly wider
   than before, because a thin line reads shorter than it measures.
   rgba off --accent-rgb, not a literal, so all six themes and a custom
   accent get their own colour. */
.eyebrow::before{content:"";width:30px;height:1px;background:rgba(var(--accent-rgb),.5);flex:none}
.lede{font-size:calc(18px * 0.88);color:var(--off);max-width:58ch;text-wrap:pretty}
.small{font-size:calc(16px * 0.88);color:var(--muted)}
.wrap{max-width:var(--col);margin:0 auto}.tight>*{max-width:var(--tight)}
.band{padding:50px 24px}.band--surface{background:var(--surface)}.band--top{padding-top:50px}
.band--cta{background:var(--dark2)}
/* 57.90 Exactly 50px at the top and bottom of every section, as seen.
   The band's own padding was always 50px, but whatever sat first or last
   inside it added its own margin on top - a closing paragraph's 16-21px,
   the review wall's 8px - so the gap you saw was 58, 66, 71. Nothing at
   the very top or bottom of a section adds space of its own now: the
   first thing, the last thing, and the first and last thing inside it
   (a column of the two-up layouts included). The review wall is CSS
   columns and every card carries 16px below, so as the last thing in a
   section it pulls that back. */
.band>.wrap>:first-child,.band>.wrap>:first-child>:first-child{margin-top:0}
.band>.wrap>:last-child,.band>.wrap>:last-child>:last-child,.band>.wrap>.hero-grid>*>:last-child{margin-bottom:0}
.band>.wrap>.rev-wall:last-child{margin-bottom:-16px}
/* --header-bg, not a literal. It was rgba(0,0,0,.55) here and
   overridden with a baked rgba(surface) for light builds - both fine
   until the swatches could cross families, at which point the header
   was the one band on the page a variable swap could not reach. It
   stayed pale on a dark theme, with pale nav links on it. */
/* 56.3 Promo strip, above the sticky header. Tinted with the accent over
   the card colour so it reads as the theme's own rather than an ad. */
.promo-bar{background:linear-gradient(rgba(var(--accent-rgb),.16),rgba(var(--accent-rgb),.16)),var(--surface);
border-bottom:1px solid var(--border);color:var(--text);font-size:calc(14px * 0.88);line-height:1.4}
.promo-track{display:grid;max-width:var(--col);margin:0 auto;padding:9px 52px}
/* 57.4 Close, in the far right corner, in the strip's own text colour. */
.promo-bar{position:relative}
.promo-bar[hidden]{display:none}
.promo-x{position:absolute;top:50%;right:10px;transform:translateY(-50%);width:34px;height:34px;padding:0;border:0;
border-radius:50%;background:none;color:inherit;font:400 24px/1 sans-serif;cursor:pointer;opacity:.75;transition:opacity .15s,background .15s}
.promo-x:hover,.promo-x:focus-visible{opacity:1;background:rgba(127,127,127,.18)}
.promo-i{grid-area:1/1;margin:0;display:flex;align-items:center;justify-content:center;gap:14px;flex-wrap:wrap;
text-align:center;opacity:0;visibility:hidden;transition:opacity .6s,visibility .6s}
.promo-i.is-on{opacity:1;visibility:visible}
.promo-i b{color:var(--accent-ink);font-weight:700;letter-spacing:.02em}
/* 63.4 About heading: the part after | in his accent, on the same line (63.5). */
.about-acc{color:var(--accent-ink)}
.promo-btn{display:inline-block;padding:5px 13px;border-radius:4px;background:var(--cta);color:var(--on-cta);
font-weight:600;font-size:calc(12.5px * 0.88);letter-spacing:.08em;text-transform:uppercase;text-decoration:none;white-space:nowrap}
.promo-btn:hover,.promo-btn:focus-visible{background:var(--cta-hover)}
/* 58.366 Whole banner clickable, and white text. */
.promo-i--link{position:relative}
.promo-link{color:inherit;text-decoration:none}
.promo-link::after{content:"";position:absolute;inset:-9px -52px}
/* 58.368 Hover: no underline, keep the colour, a shade lighter. */
.promo-bar .promo-i--link a.promo-link,.promo-bar .promo-i--link a.promo-link:hover,.promo-bar .promo-i--link a.promo-link:focus-visible{text-decoration:none;text-decoration-color:transparent}
.promo-bar .promo-i--link a.promo-link:hover,.promo-bar .promo-i--link a.promo-link:focus-visible{color:inherit;color:color-mix(in srgb,currentColor 78%,#fff)}
.promo-bar--white .promo-i--link a.promo-link:hover,.promo-bar--white .promo-i--link a.promo-link:focus-visible{color:#fff;opacity:.85}
.promo-i--link .promo-btn{position:relative;z-index:1}
.promo-i--link:not(.is-on) .promo-link::after{display:none}
.promo-bar--white,.promo-bar--white .promo-i b{color:#fff}
@media(max-width:620px){.promo-track{padding:8px 44px 8px 14px}.promo-i{gap:8px;font-size:calc(12.5px * 0.88)}.promo-x{right:4px}}
@media(prefers-reduced-motion:reduce){.promo-i{transition:none}}
/* 56.4 Solid looks. The tint read as part of the header and got lost.
   Accent fill with the PAGE colour as the ink: dark text on a bright
   accent on a dark theme, light on a deep one on a light theme - the
   pair every theme is already built around, so it reads on all of them
   and follows the demo's colour swatches with no script. The label goes
   bold capitals rather than a second colour, and the button inverts. */
.promo-bar--solid{background:var(--accent);color:var(--bg);border-bottom:0;font-size:calc(16px * 0.88);font-weight:500}
.promo-bar--solid .promo-track{padding:11px 52px}
.promo-bar--solid .promo-i b{color:inherit;font-weight:800;text-transform:uppercase;letter-spacing:.09em}
.promo-bar--solid .promo-btn{background:var(--bg);color:var(--accent)}
.promo-bar--solid .promo-btn:hover,.promo-bar--solid .promo-btn:focus-visible{background:var(--bg);opacity:.85}
.promo-bar--cta{background:var(--cta);color:var(--on-cta)}
.promo-bar--cta .promo-btn{background:var(--on-cta);color:var(--cta)}
.promo-bar--cta .promo-btn:hover,.promo-bar--cta .promo-btn:focus-visible{background:var(--on-cta)}
@media(max-width:620px){.promo-bar--solid .promo-track{padding:9px 44px 9px 14px}.promo-bar--solid{font-size:calc(14px * 0.88)}}
/* 56.3 Badge images. White tiles because the badges themselves are drawn
   for white - a BBB seal on a dark page loses its edge - and one fixed
   tile size so a tall seal and a wide wordmark sit as equals. */
.badge-row{display:flex;flex-wrap:wrap;gap:16px;margin-top:28px}
/* 56.9 Fixed height, width from the badge: a tall shield gets a narrow
   tile and a wide wordmark a wide one, so neither sits in white space. */
.badge-tile{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:auto;height:100px;padding:12px 16px;
background:#fff;border:1px solid var(--border-soft);border-radius:10px;transition:transform .15s,box-shadow .2s}
a.badge-tile:hover,a.badge-tile:focus-visible{transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.2)}
.badge-tile img{height:100%;width:auto;max-width:240px;object-fit:contain;display:block}
@media(max-width:620px){.badge-row{gap:12px}.badge-tile{height:84px;padding:10px 12px}.badge-tile img{max-width:150px}}
/* 58.360 The Credentials section's own tiles: shorter and all one width.
   At 100px tall they were the loudest thing on that part of the page, and
   width-from-the-badge made a ragged row (a square BBB seal beside a long
   WorkSafeBC wordmark). 76px tall, 200px wide, each badge centred in its
   tile. Only this section - Backed by and the footer keep their own. */
.badges-band .badge-tile{height:76px;width:176px;padding:8px 10px}   /* 58.361 tighter: the badge fills more of its tile */
.badges-band .badge-tile img{max-width:100%}
@media(max-width:620px){.badges-band .badge-tile{height:64px;width:auto;flex:1 1 130px;max-width:176px;padding:6px 8px}}
/* 56.6 Compact strip and the Backed by row under the reviews. A named
   badge is a tile and its name side by side, so one badge reads as a
   line of proof rather than a lone box. */
.badge-backed .badge-row{margin-top:0;gap:14px 30px}
.badge-backed{margin-top:40px;padding-top:28px;border-top:1px solid var(--border-soft);
display:flex;align-items:center;flex-wrap:wrap;gap:16px 32px}
.badge-backed-l{margin:0;font-size:calc(14px * 0.88);letter-spacing:.18em;text-transform:uppercase;color:var(--muted)}
.badge-item{display:flex;align-items:center;gap:14px;text-decoration:none;color:var(--text)}
.badge-item .badge-tile{height:76px;padding:8px 10px}
a.badge-item:hover .badge-tile,a.badge-item:focus-visible .badge-tile{transform:translateY(-2px);box-shadow:0 8px 20px rgba(0,0,0,.2)}
.badge-item-n{font-size:calc(16px * 0.88);font-weight:600;line-height:1.3;max-width:20ch}
a.badge-item:hover .badge-item-n{color:var(--accent-ink)}
@media(max-width:620px){.badge-item{width:100%}.badge-item .badge-tile{height:66px}}
/* 57.0 Brands we use. White tiles for the same reason as the badges -
   makers' logos are drawn for white. Greyscale by default so four
   brands' colours do not fight his; colour comes back on hover. */
.brand-strip{padding:34px 24px;background:var(--surface);border-top:1px solid var(--border-soft)}
/* 57.3 Its own band colour - a light tint of his accent over the page -
   so the row never runs into the band above or below it, whatever the
   section order or theme. The plain surface stays as the fallback for a
   browser without color-mix. */
.brand-strip,.brands-band{background:var(--surface);background:color-mix(in srgb,var(--accent) 11%,var(--bg));
border-top:1px solid var(--border-soft);border-bottom:1px solid var(--border-soft)}
.brand-strip .wrap{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:18px 40px}
.brand-row{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:12px 14px}
.brands-band .brand-row{gap:16px}
.brand-tile{display:flex;align-items:center;justify-content:center;box-sizing:border-box;height:64px;padding:10px 16px;
background:#fff;border:1px solid var(--border-soft);border-radius:8px}
.brands-band .brand-tile{height:88px;padding:14px 20px}
.brand-tile img{height:100%;width:auto;max-width:170px;object-fit:contain;display:block;transition:filter .25s,opacity .25s}
.brands-band .brand-tile img{max-width:210px}
.brand-row--grey .brand-tile img{filter:grayscale(1);opacity:.72}
.brand-row--grey .brand-tile:hover img{filter:none;opacity:1}
.brand-tile--grey img{filter:grayscale(1);opacity:.72}
/* 57.1 One colour. No white tile: the logo is the colour itself. */
.brand-tile--one{background:none;border:0;padding:6px 10px}
.brand-mask{display:block;height:100%;background:var(--accent);-webkit-mask-size:contain;mask-size:contain;
-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-position:center;mask-position:center;transition:opacity .2s}
.brand-row--mono .brand-mask{background:var(--text);opacity:.82}
.brand-mask img{height:100%;width:auto;max-width:170px;display:block;opacity:0}
.brands-band .brand-mask img{max-width:210px}
.brand-tile--one:hover .brand-mask{opacity:1}
.brand-row--accent .brand-tile--one:hover .brand-mask{opacity:.85}
@media(max-width:620px){.brand-strip{padding:26px 16px}.brand-mask img{max-width:120px}.brand-tile,.brands-band .brand-tile{height:52px;padding:8px 12px}.brand-tile img,.brands-band .brand-tile img{max-width:120px}}
/* 56.9 In the footer: small white tiles under the email. */
.footer-badges{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}
.fb-tile{display:flex;align-items:center;justify-content:center;box-sizing:border-box;height:56px;padding:4px 5px;   /* 58.295 was 6px 8px - the badge fills more of its tile */
background:#fff;border-radius:6px;transition:transform .15s}
a.fb-tile:hover,a.fb-tile:focus-visible{transform:translateY(-2px)}
.fb-tile img{height:100%;width:auto;max-width:140px;object-fit:contain;display:block}

.site-header{position:sticky;top:0;z-index:50;background:var(--header-bg,rgba(0,0,0,.55));backdrop-filter:blur(10px);
border-bottom:1px solid var(--border);padding:0 24px}
/* Padding shrinks as the logo grows, so a bigger mark makes the header
   taller by less than its own increase rather than by all of it. */
.site-header .wrap{display:flex;align-items:center;justify-content:space-between;gap:20px;
padding:14px 0;min-height:76px}   /* 58.245 capped at 14: a smaller logo was getting more padding, so the header grew as the logo shrank */
/* min-height rather than more padding. The header is sized by whatever
   is inside it, so a text wordmark came out around 60px tall while a
   badge or an uploaded logo made the same bar 73 - the thin ones looked
   cramped against a full nav row. A floor lifts the short ones to 76 and
   leaves a tall logo alone, so every build lands in the same range
   without capping anything. */
/* flex-shrink:0 on both, and it is load-bearing. The header row is a
   flex container and so is this, which makes the <img> a flex item —
   and flex items shrink. With height pinned at 40px and the width
   allowed to give way, a tight header (long nav, narrow window, a wide
   logo) squeezes the image horizontally and the logo comes out
   squashed. width:auto does not prevent it; only refusing to shrink
   does. object-fit is the backstop for anything that still gets a
   width forced on it. */
/* A BOX, not a height. Logos arrive in every shape: a 200x40 wordmark,
   a square badge, a tall crest. Pinning them all to height:40px makes
   the wordmark 200px wide and correct, and the square one 40px wide and
   apologetic — same height, nothing like the same presence. So both
   edges are capped and each logo hits whichever it reaches first: a
   wordmark runs out of width and settles around 38px tall, a square runs
   out of height and comes out about 56px across. No measuring, no
   setting, works on a file it has never seen.

   flex-shrink:0 is load-bearing on both. The header row is a flex
   container and so is this, which makes the <img> a flex item, and flex
   items shrink — with the height pinned and the width free to give way,
   a tight header squeezes the logo sideways. width:auto does not stop
   that; only refusing to shrink does. */
.logo--img{display:flex;align-items:center;padding:2px 0;flex:0 0 auto;min-width:0}
.logo--img img{height:56px;max-width:210px;width:auto;
flex:0 0 auto;object-fit:contain;display:block}   /* 58.244 height, not max-height: a small file sat at its own pixel height whatever Logo size said */
/* 57.44 The panel follows the swatches. A dark panel is there to lift
   pale lettering off a LIGHT header, so it appears only on the light
   themes and goes when the prospect presses a dark swatch - where the
   same lettering reads on its own and a panel would be a box round his
   logo. The white panel is the same the other way. html.tk-light is set
   at build time and toggled by the swatch switcher, so both follow a
   click with no script of their own. */
html.tk-light .logo--plate-dark{padding:7px 12px;border-radius:8px;background:#151c25}
html:not(.tk-light) .logo--plate-light{padding:7px 12px;border-radius:8px;background:#ffffff}
.logo--mark{display:flex;align-items:center;gap:11px}
.logo-badge{display:inline-flex;align-items:center;justify-content:center;
width:40px;height:40px;border-radius:6px;background:var(--accent);color:var(--bg);
font-size:19px;letter-spacing:.02em;flex:none;line-height:1;padding-top:2px}
.logo{font-family:var(--font-display);font-weight:400;font-size:calc(30px * 0.88);color:var(--text);text-decoration:none;letter-spacing:.02em;line-height:1;white-space:nowrap}
.logo-short{display:none}
.logo{font-size:calc(calc(30px * 0.963) * 0.88)}@media(max-width:1500px){.logo-full{display:none}.logo-short{display:inline}}
.lg-a{color:var(--accent)}
:root{--tk-text:var(--text);--tk-off:var(--off);--tk-accent:var(--accent);--tk-accent-lt:var(--accent-lt);--tk-border:var(--border);--tk-cta:var(--cta);--tk-on-cta:var(--on-cta)}:root .site-header.site-header{background:color-mix(in srgb,var(--bg) 45%,#000);backdrop-filter:none;border-bottom-color:rgba(255,255,255,.08)}.site-header>.wrap{--text:#f3f1ee;--off:#d9dde2;--border:rgba(255,255,255,.18)}:root .site-header .logo--plate-light{padding:7px 12px;border-radius:8px;background:#ffffff}:root .site-header .logo--plate-dark{padding:0;background:none}.site-header .nav-menu{--text:var(--tk-text);--off:var(--tk-off);--accent:var(--tk-accent);--accent-lt:var(--tk-accent-lt);--border:var(--tk-border)}
/* Three parts across the header: logo, links, then the phone and the
   quote button. The links take the middle and centre in it, so they read
   as a row rather than as a queue pushed up against the button. flex:1
   with min-width:0 rather than a fixed share, so a long service list
   still gives way instead of shoving the button off the end. */
.nav{display:flex;align-items:center;gap:26px;flex:1 1 auto;justify-content:center;min-width:0}
.nav-act{display:flex;align-items:center;gap:26px;flex:0 0 auto}
/* 58.145 */
.hdr-phone{display:inline-flex;align-items:center;gap:8px;font-weight:400;font-size:calc(16px * 0.88);letter-spacing:.08em;text-decoration:none;white-space:nowrap}
.hdr-ph-ico{color:var(--accent);flex:none}
/* 58.146 The pair sits in the header as if it were not there, unless the
   phone is outlined - then the two are one grid, equal columns, so the
   number's box and Get a quote are the same width and height. The shape
   follows Button shape, since the number carries .btn too. */
.hdr-pair{display:contents}
.hdr-pair--btn{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:12px;align-items:stretch}
.site-header .hdr-pair--btn>*{display:inline-flex;align-items:center;justify-content:center;text-align:center}
.site-header .hdr-phone--btn{gap:8px;background:transparent;border:1px solid var(--accent-ink);   /* 58.178 the ghost-button blue */text-transform:none;letter-spacing:.08em;font-weight:400;font-size:calc(16px * 0.88);   /* 58.155 16px - the 18px button size made the number shout */
margin-right:0!important;padding-left:16px;padding-right:16px}
/* 58.147 border and icon in the number's own colour - the same as the menu links - rather than the accent */
html .site-header .hdr-phone.hdr-phone--btn{color:var(--accent-ink)!important}   /* 58.178 over the light-header number colour */
.site-header .hdr-phone--btn .hdr-ph-ico{color:currentColor}
.site-header .hdr-phone--btn:hover,.site-header .hdr-phone--btn:focus-visible{background:rgba(var(--accent-rgb),.10);border-color:var(--accent-ink);transform:translateY(-1px)}
/* 58.233 Phone as the main button: the number in his button colour, on
   the right; Get a quote outlined beside it in the ghost-button blue. */
.site-header .hdr-phone--main{gap:8px;text-transform:none;letter-spacing:.08em;font-weight:400;font-size:calc(16px * 0.88);margin-right:0!important;padding-left:16px;padding-right:16px}
.site-header .hdr-phone--main .hdr-ph-ico{color:currentColor}
html .site-header .wrap .hdr-phone.hdr-phone--main,html.tk-light .site-header>.wrap .hdr-phone.hdr-phone--main{color:var(--on-cta)!important}
.site-header .hdr-ghost{background:transparent;border:1px solid var(--accent-ink);margin-right:0!important}
html .site-header .wrap a.hdr-ghost,html.tk-light .site-header>.wrap .nav a.hdr-ghost{color:var(--accent-ink)!important}
.site-header .hdr-ghost:hover,.site-header .hdr-ghost:focus-visible{background:rgba(var(--accent-rgb),.10);border-color:var(--accent-ink);transform:translateY(-1px)}
/* 58.236 On a dark header the outlined button goes quiet: the menu's own
   light text and a soft white outline, the accent left on the phone icon
   only. In the accent blue, text and border together, it was the loudest
   thing in the header and fought the solid button it is meant to sit
   behind. A light or white header keeps the blue - there it reads as
   calm. Auto follows the page, so a swatch to a light palette brings the
   blue back. */
html body .site-header .wrap .hdr-phone.hdr-phone--btn,html body .site-header .wrap a.hdr-ghost{color:var(--text)!important;border-color:rgba(255,255,255,.28)}html body .site-header .hdr-phone--btn .hdr-ph-ico{color:var(--accent)}html body .site-header .wrap .hdr-phone.hdr-phone--btn:hover,html body .site-header .wrap .hdr-phone.hdr-phone--btn:focus-visible,html body .site-header .wrap a.hdr-ghost:hover,html body .site-header .wrap a.hdr-ghost:focus-visible{background:rgba(255,255,255,.07);border-color:rgba(255,255,255,.5)}
/* 55.30 Phone menu - see the header. Hidden on anything wide enough to
   show the real nav. */
.nav-burger{display:none;width:42px;height:42px;padding:0;border:1px solid var(--border);border-radius:6px;
background:transparent;cursor:pointer;flex-direction:column;align-items:center;justify-content:center;gap:5px}
.nav-burger span{display:block;width:20px;height:2px;background:var(--text);border-radius:2px;transition:transform .18s,opacity .18s}
.nav-burger.is-open span:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav-burger.is-open span:nth-child(2){opacity:0}
.nav-burger.is-open span:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.mnav{background:var(--surface);border-top:1px solid var(--border);max-height:calc(100vh - 140px);overflow-y:auto}
.mnav[hidden]{display:none}
.mnav .wrap{display:block;padding:10px 0 22px}
.mnav a{display:block;padding:11px 2px;color:var(--text);text-decoration:none;font-size:calc(18px * 0.88);
border-bottom:1px solid var(--border)}
.mnav a:hover{color:var(--accent-lt)}
.mnav-h{margin:18px 0 2px;font-size:calc(12.5px * 0.88);letter-spacing:.12em;text-transform:uppercase;color:var(--accent)}
.mnav .mnav-call{margin-top:16px;border:0;text-align:center;background:var(--cta);color:var(--on-cta);border-radius:4px;
font-weight:600;letter-spacing:.04em}
@media(min-width:901px){.mnav{display:none!important}}
.nav a{color:var(--off);text-decoration:none;font-size:15px;letter-spacing:.04em;text-transform:uppercase}
/* The caret below is an 8px inline-block sitting in the link's line box.
   At the default line-height it makes the dropdown links taller than the
   plain ones, and align-items:center then pushes their text down by the
   difference. One explicit line-height, tall enough to contain the caret,
   makes every nav item the same height. Buttons excluded — .btn sets its
   own line-height:1 and would grow. */
.nav>a:not(.btn),.nav-drop>a{display:block;line-height:1.6;white-space:nowrap}
.nav a:hover{color:var(--accent-lt)}
/* Areas dropdown. Opens on hover and on keyboard focus, so the area
   pages are reachable from every page rather than only the homepage. */
.nav-drop{position:relative;display:inline-block}
.nav-drop>a::after{content:"";display:inline-block;margin-left:6px;vertical-align:middle;
border:4px solid transparent;border-top-color:currentColor;transform:translateY(2px)}
.nav-menu{position:absolute;top:100%;left:50%;transform:translateX(-50%);margin:0;padding:8px 0;
list-style:none;min-width:190px;background:var(--surface);border:1px solid var(--border);
border-radius:8px;box-shadow:0 12px 32px rgba(0,0,0,.45);
opacity:0;visibility:hidden;pointer-events:none;translate:0 6px;
transition:opacity .18s ease,translate .18s ease,visibility .18s;z-index:60}
.nav-drop:hover .nav-menu,.nav-drop:focus-within .nav-menu{
opacity:1;visibility:visible;pointer-events:auto;translate:0 0}
.nav-menu li{margin:0}
.nav-menu a{display:block;padding:8px 18px;font-size:calc(14px * 0.88);letter-spacing:.03em;
text-transform:none;color:var(--off);white-space:nowrap}
.nav-menu a:hover{background:var(--dark2);color:var(--accent-lt)}
/* A gap between the link and the menu would close it mid-move. */
.nav-drop::after{content:"";position:absolute;top:100%;left:0;right:0;height:14px}.nav-phone{color:var(--text)!important;white-space:nowrap}
.btn{display:inline-block;font-family:var(--font-body);font-stretch:normal;font-size:calc(18px * 0.88);
letter-spacing:.08em;text-transform:uppercase;text-decoration:none;padding:15px 28px;   /* 58.150 every standard button is the hero size: 18px, 15px padding - one height across the site */border-radius:4px;
line-height:1;border:1px solid transparent;cursor:pointer;transition:background .2s,color .2s,border-color .2s,transform .15s}
.btn--cta{background:var(--cta);color:var(--on-cta);border-color:var(--cta)}


/* 58.234 The header reads as one line of type: the menu links, the phone
   and Get a quote all at the same letter spacing (they were .04em, .08em
   and .08em at three different sizes), and the two header buttons at the
   same size as each other. Normal lettering keeps the buttons' own tight
   spacing - mixed case does not want the caps tracking. */
.site-header .nav a:not(.btn),.site-header .hdr-pair .btn,.site-header .hdr-phone{letter-spacing:.06em}
.site-header .hdr-pair .btn{font-size:calc(16px * 0.88)}
/* color restated deliberately. These are <a> elements, so a hover rule
   that omits it lets whichever link rule wins repaint the label — the
   solid red button flipping to accent blue on hover. :focus-visible gets
   the same treatment, or keyboard users hit the bug with no fix. */
.btn--cta:hover,.btn--cta:focus-visible{background:var(--cta-hover);border-color:var(--cta-hover);
color:var(--on-cta);transform:translateY(-2px)}
.btn--ghost{background:transparent;color:var(--accent-lt);border-color:rgba(var(--accent-rgb),.5)}
.btn--ghost:hover,.btn--ghost:focus-visible{border-color:var(--accent);color:var(--accent);transform:translateY(-1px)}
/* 58.42 On a photo the outline button had nothing behind it - accent
   text and a half-see-through border over a busy picture. It gets a
   smoked-glass backing and white lettering there, so it reads on any
   photo; still clearly the second button next to the solid one. */
/* 58.130 Solid now, not see-through: the photo showing through it made it
   look faded beside the solid Call button and the solid rating badge. A
   near-black charcoal on every theme, since the backing is always a photo. */
.hero--scrim .btn--ghost,.band--shot .btn--ghost{background:#343a42;color:#fff;border-color:rgba(255,255,255,.3)}
.hero--scrim .btn--ghost:hover,.hero--scrim .btn--ghost:focus-visible,.band--shot .btn--ghost:hover,.band--shot .btn--ghost:focus-visible{background:#3f464f;color:#fff;border-color:rgba(255,255,255,.5)}
/* 58.43 A barely-there edge, not a white outline: the bright outline made
   the second button the loudest thing in the hero, louder than Call. */
html.tk-light .hero--scrim .btn--ghost,html.tk-light .band--shot .btn--ghost{background:#343a42;color:#fff;border-color:rgba(255,255,255,.3)}
.btn--lg{font-size:calc(18px * 0.88);padding:15px 28px}.btn--sm{font-size:calc(14px * 0.88);padding:9px 16px}
.btn--full{width:100%;text-align:center}
/* Equal columns, not flex.

   The homepage hero already did this through .hero-btns, but every
   other pair - the service and area page heroes, the closing call to
   action - was flex, so each button sized to its own label. "Call (250)
   609-1875" beside "Get a quote" then reads as two unrelated buttons
   rather than one choice, and on a phone they wrap to two different
   widths, which reads as a mistake rather than a stack.

   auto-columns:1fr on a max-content track sizes every column to the
   widest label, so the pair matches without either being stretched
   across the band. minmax is not needed here because auto-columns
   already sets the track; what IS needed is min-width:0 on the items,
   since a grid item defaults to min-content and the longer label would
   push its own track wider and undo the whole thing. */
.btn-row{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
gap:12px;margin-top:28px;width:max-content;max-width:100%}
.btn-row .btn{min-width:0;text-align:center}
/* Stacked and full width on a phone, where two header-width buttons
   side by side do not fit. */
@media(max-width:560px){.btn-row{grid-auto-flow:row;width:100%}}
/* Where a row carries three or more buttons, flex-wrap leaves each one at
   its own content width — so a wrapped row reads as a mistake. An auto-fit
   grid gives equal columns at every width: three across on desktop, one
   full-width column on a phone, and never a ragged pair. */
.btn-row--even{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
gap:12px;margin-top:28px}
.btn-row--even .btn{text-align:center}
/* The hero pair only. Two equal tracks rather than letting each button size
   itself: "Call (604) 555-0188" is far wider than "Get a quote", and the
   mismatch reads as two unrelated buttons rather than one choice. Capped so
   the ghost one is not stretched halfway across the hero. minmax(0,1fr)
   because grid items default to min-content, and the longer label would
   otherwise push its own track wider and defeat the point. Full width and
   stacked on a phone, where the short one looked stranded. */
/* 58.149 Sized to the longer label, both the same: width:max-content on the
   grid with 1fr columns makes every column as wide as the widest button.
   The fixed 290px was set for "Call (604) 555-0188"; with the phone-icon
   label it left both buttons half empty. min-width keeps a short pair
   from looking stubby. */
.hero-btns{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;width:max-content;max-width:100%;gap:12px}
.hero-btns .btn{min-width:200px}
/* nowrap is not cosmetic. At 250px the track was a hair narrower than
   "Call (604) 774-8949" renders at 18px with the letter-spacing, so the
   label broke onto a second line — and the break landed inside the phone
   number, giving "Call (604) 774-" over "8949". A two-line button beside a
   one-line one also reads as bigger text even though both are 18px. 290px
   clears a North American number comfortably; nowrap means a longer one
   still never splits. */
.hero-btns .btn{text-align:center;white-space:nowrap}
.hero--centred .hero-btns{margin-left:auto;margin-right:auto}
.hero{position:relative;padding:50px 24px;
background-image:linear-gradient(
  rgba(0,0,0,calc(0.42 + var(--hero-extra,0))),
  rgba(0,0,0,calc(0.5 + var(--hero-extra,0)))),var(--hero-img);
background-size:cover;background-position:center 50%}

.hero-grid{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);gap:clamp(32px,5vw,64px);align-items:start}
.hero-grid>*{min-width:0}
/* Hero service list. It fills the space beside a tall form and answers the
   question a visitor has second - do you do my thing. Two columns rather
   than one wrapped row: the gap being filled is vertical, so a row of six
   names solves nothing and reads cramped. Ticks reuse the same check icon
   as the services section, so it looks like part of the same site.
   Capped at eight - a business with a dozen services would otherwise push
   the hero taller than the form it is balancing. */
.hero-svc{margin-top:28px;padding-top:24px;border-top:1px solid rgba(var(--ink-rgb),.12);width:fit-content;max-width:100%}   /* 58.237 the line stops with the list, as the promises' does (58.231) */
@media(max-width:600px){.hero-svc{width:auto}}
/* A small heading, not an eyebrow. It introduces the list, so it sits above
   it in the hierarchy - sentence case, a little larger than the items, in
   full-strength text colour. */
.hero-svc-h{font-size:calc(18px * 0.88);color:var(--text);margin:0 0 18px}
.hero-svc-h.sr-only{margin:0}
/* 58.166 Four promises, one row, under the hero buttons.
   58.231 The line above them stops where the row stops (it ran the full
   width of the hero, well past the last promise). Phones keep it full
   width, where the two-by-two grid fills the screen anyway. */
.hero-prom{list-style:none;margin:28px 0 0;padding:26px 0 0;border-top:1px solid rgba(var(--ink-rgb),.12);width:fit-content;max-width:100%;display:flex;flex-wrap:wrap;justify-content:flex-start;gap:16px clamp(28px,3vw,44px)}   /* 58.201 side by side at a fixed gap, not spread to the full width */
.hero-prom li{display:flex;align-items:center;gap:9px;flex:0 1 auto}
.hero-prom.hero-prom--two{display:grid;grid-template-columns:repeat(2,max-content);gap:16px clamp(28px,3vw,44px)}   /* 58.338 two rows of two when four won't fit on one */
.hero-prom svg{width:26px;height:26px;flex:0 0 26px;color:var(--off)}   /* 58.175 the text's colour unless set to the accent */
.hero-prom span{font-size:calc(16px * 0.88);line-height:1.35;font-weight:400;color:var(--off)}   /* 58.173 the step text's size; 58.174 the colour of the line under the headline - between the step grey and white */
@media(max-width:600px){.hero-prom{width:auto;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 18px}.hero-prom li{max-width:none}}
html.tk-light .hero--scrim .hero-prom span{color:rgba(244,247,250,.86)}
html.tk-light .hero--scrim .hero-prom{border-top-color:rgba(255,255,255,.16)}
/* 58.179 The hero label: a quiet pill above the headline - no new colour. */
.hero-pill{display:inline-block;margin:0 0 18px;padding:6px 15px;border-radius:999px;background:rgba(var(--ink-rgb),.08);border:1px solid rgba(var(--ink-rgb),.14);color:var(--off);font-size:calc(14px * 0.88);font-weight:500;letter-spacing:.02em;line-height:1.35}
html.tk-light .hero--scrim .hero-pill{background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.24);color:rgba(244,247,250,.92)}
/* 58.188 With the pill on, the hero wins its height back so the promises
   stay above the fold: less space above the pill, and a tighter stack
   under the buttons. A hero without the pill is untouched. */
   /* 58.189 not needed on Wide - the headline gives back more than the pill takes */
/* 58.189 Wide headline where no form sits beside it. */
.hero--noform .hero-grid{grid-template-columns:minmax(0,1fr)}   /* 58.338 the full width of the page, the same as the header and every section (was 1000px) */
.hero--centred .hero-mid{max-width:var(--col)}
.hero--noform .lede,.hero--centred .lede{max-width:none}
html.tk-light .hero--scrim .hero-prom svg{color:rgba(244,247,250,.86)}
.hero-svc-list{list-style:none;margin:0;padding:0;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:11px 26px;max-width:52ch}
.hero-svc-list li{display:flex;align-items:flex-start;gap:9px;min-width:0}
/* align-items:center centred the tick against the whole label, so a
   two-line service sat its icon halfway down. flex-start plus a nudge
   puts it on the first line's cap height whatever the label does. */
.hero-svc-list svg{width:18px;height:18px;flex:0 0 18px;color:var(--accent);margin-top:2px}
.hero-svc-list a,.hero-svc-list span{font-size:calc(16px * 0.88);line-height:1.25;
  color:var(--text);text-decoration:none}
.hero-svc-list a:hover{color:var(--accent);text-decoration:underline}
/* Was .hero only, so the home page looked right and every area, service
   and reviews page had its lede jammed under the headline — those use
   .band--top rather than .hero. Keyed off the pair instead of the
   container, so it holds wherever a lede follows a headline. */
.hero h1 span{color:var(--hero-hl,var(--accent))}
h1 + .lede{margin-top:22px}
/* no image: a tinted gradient instead of a photo */
.hero--flat{background-image:linear-gradient(160deg,var(--surface) 0%,var(--bg) 55%,var(--dark2) 100%)!important}
.hero-panel-img.hero--flat{background-image:linear-gradient(150deg,var(--accent) 0%,var(--dark2) 90%)!important;opacity:.55}

.about-grid--nophoto{grid-template-columns:1fr;max-width:760px}
/* hero: centred */
.hero--centred{text-align:center;padding:50px 24px}
.hero--centred .hero-mid{max-width:820px;margin:0 auto}
.hero--centred .lede{margin:22px auto 0;max-width:60ch}
.hero--centred .btn-row{margin-left:auto;margin-right:auto}
/* hero: panel */
.hero--panel{display:grid;grid-template-columns:1fr 1fr;padding:0;min-height:520px}
.hero-panel-img{background-size:cover;background-position:center 50%;min-height:320px;opacity:0.88;transition:opacity .3s,filter .3s}
.hero--panel:hover .hero-panel-img{opacity:1;}
.hero-panel-copy{background:var(--surface);display:flex;align-items:center;padding:50px 48px}
.hero-panel-inner{max-width:520px}
.hero--panel h1 span{color:var(--hero-hl,var(--accent))}
/* services: icon list */
.svc-list{display:grid;grid-template-columns:1fr 1fr;gap:4px 40px;margin-top:40px}
.svcl{display:grid;grid-template-columns:34px 1fr;gap:14px;padding:20px 0;
border-bottom:1px solid var(--border-soft);align-items:start}
.svcl-i{color:var(--accent);padding-top:2px}
.svcl-i svg{width:24px;height:24px;display:block}
.svcl h3{margin-bottom:6px}
.svcl p{margin:0;font-size:calc(16px * 0.88);color:var(--muted)}
/* 22px of padding, not 26, and it is the second-loudest thing in the
   hero rather than the first. The card is opaque and sits on a darkened
   photograph, so on a light build it was the brightest object on the
   page and the eye reached it before the headline - which is the wrong
   order, since the headline sells and the form converts. Trimming the
   padding takes about 50px off the height, which is what was pushing
   the trade list below the fold. */
/* The border is back, and the band covers it.

   It was removed outright because it drew a 1px line of the card's own
   colour around the top and sides of the heading band - a white frame
   round a dark strip on a light theme. That fixed the hero, where the
   card sits on a darkened photograph and needs no edge of its own, and
   broke every other page: on the reviews page and the area pages the
   card is white on near-white and simply dissolved.

   Both at once is a matter of one pixel. The band's negative margins go
   to -23 rather than -22 - the card's padding PLUS its border - so the
   strip covers the border instead of sitting inside it, and its radius
   matches the card's outer 10px rather than the 9px inner. The border
   then shows exactly where it is wanted: down the sides below the band,
   and across the bottom.

   Anything that changes the padding or the radius has to move both. */
.quote-card{overflow-wrap:anywhere;background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:22px 22px 20px}
.quote-card{transition:border-color .3s,box-shadow .3s}
.quote-card.is-lit{box-shadow:0 0 0 2px var(--accent),0 0 0 5px rgba(var(--accent-rgb),.18)}
/* 58.162 The Get a quote pop-up. */
.qmodal{position:fixed;inset:0;z-index:2147483000;background:rgba(10,14,20,.62);overflow-y:auto;display:flex;align-items:flex-start;justify-content:center;padding:6vh 16px 24px}
.qmodal[hidden]{display:none}
.qm-in{position:relative;width:100%;max-width:600px;margin:auto 0}
.qm-in .quote-card{box-shadow:0 24px 60px rgba(0,0,0,.35);max-width:none}
.qm-x{position:absolute;top:-14px;right:-14px;z-index:2;width:38px;height:38px;border-radius:50%;border:0;background:#fff;color:#1b1f24;font-size:24px;line-height:38px;padding:0;cursor:pointer;box-shadow:0 4px 14px rgba(0,0,0,.3)}
.qm-x:hover{background:#f1f3f5}
html.qm-open{overflow:hidden}
@media(max-width:600px){.qmodal{padding:22px 10px 16px}.qm-x{top:-12px;right:-6px}}
/* The quote card's heading, as a band across the top of the card.

   Four things were wrong with it as a plain line of type.

   It was the only block on the page with no eyebrow over it. Every
   section leads with the small tracked accent line and a dash; the card
   started cold, so it read as a stray paragraph rather than the start of
   something.

   It was the only sentence-case thing inside its own card. The field
   labels are uppercase and tracked and the button is uppercase, so the
   heading matched neither and looked like it had been dropped in.

   It was hardcoded at 32px while every other heading goes through sz(),
   so turning the type scale up grew the whole site around a card heading
   that stayed put.

   And a display face at 32px is visibly lighter than the same face at
   64px in the h1 above it - same font, half the density.

   The band answers the first two at once: it gives the heading a top to
   sit on without adding an eyebrow the card has no room for, and it
   separates the promise from the fields underneath it.

   The accent, not a grey. Two greys were tried - --dark2, which is also
   the input fill and merged with the first field, and a tenth-step off
   it, which separated cleanly and still read as a dead strip. The band's
   job is to catch someone who has just landed on the page, and the
   argument for keeping the card quiet applies to the card, not to the
   50px of it that is meant to be seen first.

   Sentence case and 21px, not caps at 30. The heading is a sentence now
   rather than three words, and a sentence in caps at that size is a
   shout across two lines. Letter-spacing is left to the h2 rule, since
   the extra air caps need is wrong for lowercase.

   Negative margins equal to the card's padding, and a 9px radius because
   the card's 10px is measured outside a 1px border. Both have to move
   together with .quote-card above if that padding ever changes.

   Weight is deliberately untouched, still. F.dispWeight already resolves to the
   heaviest weight a custom family publishes, and a preset face like
   Bebas has one weight only - asking for 600 there gets a synthesised
   bold, which at this size looks smeared rather than strong. The density
   comes from the caps and the fill instead. Tracking goes slightly
   positive, not negative: caps need a little air to stay legible, which
   is the opposite of what tightening a lowercase headline wants. */
.quote-h{font-size:calc(21px * 0.88);line-height:1.3;margin:-23px -23px 16px;
  padding:14px 23px 13px;border-radius:10px 10px 0 0;color:var(--qband-ink);
  background:linear-gradient(100deg,var(--qband-l) 0%,var(--qband-r) 100%);
  display:flex;align-items:center;gap:12px}
/* Homepage hero card: the business name on desktop, Contact Us on a phone. */
.quote-h .qh-short{display:none}
@media(max-width:620px){.quote-h .qh-long{display:none}.quote-h .qh-short{display:inline}}
/* Centred, not flex-start. flex-start aligns the TOP of a 38px chip with
   the top of a 21px line, which hangs the chip most of a line below the
   text and reads as misaligned - the taller the mark, the worse it gets.
   Centring is right for the single line this heading is written to fit.

   The cost is the phone, where the line wraps to three and the chip
   centres against the block rather than the first line. That is a real
   trade and the fix for it is a shorter line, not a different alignment
   - at 27 characters it does not wrap at all. */
/* The chip is the launcher: same accent fill, same white glyph, same 2px
   stroke. Rounded square rather than a circle only so it is not mistaken
   for a second button - this one does not click. */
.qh-chip{flex:none;width:38px;height:38px;border-radius:9px;
  background:var(--qband-accent);color:#ffffff;
  /* Hairline so the chip keeps an edge against the band. The band is the
     chip's own colour darkened, so the two are never far apart by
     construction: about 2.6:1 on the six themes with a light accent and
     down to 1.7 on frost, whose accent is a navy to begin with. The
     lighter the band gets the truer that becomes, so the line matters
     more here than it did when the band was near-black. */
  box-shadow:0 0 0 1px rgba(255,255,255,.34);
  display:flex;align-items:center;justify-content:center}
/* 24 in a 38 chip, not 21. The clipboard's drawing sits inside its own
   viewBox padding, so at 21 it floated in the middle of the square with
   too much air round it and read as a small mark in a big box. */
.qh-chip svg{width:24px;height:24px}
/* --text, not --muted. This line carries the callback promise, which is
   the whole offer, and --muted is the grey the site uses for footnotes -
   it read as small print sitting under the thing it was meant to sell.
   The genuine footnote in this card is the "Or call us on ..." line
   under the button, and that keeps --muted. */
.quote-sub{font-size:calc(16px * 0.88);color:var(--text);margin-bottom:18px}
.qform{display:grid;gap:14px}
.qform .lbl-opt{color:var(--placeholder);letter-spacing:.1em}
/* --label, not --muted. At 12.5px with .16em tracking a field label is
   thin and spread out, and it sits on --surface, while the placeholder
   beside it is 16px on the darker --dark2 fill. That makes the two read
   as the same weight even though --muted measures about 4.4:1 here and
   --placeholder about 2.7:1. Measured across all six themes and the
   spread is under 0.3 either way, so this is not a one-theme quirk.
   --label is derived (text mixed 30% toward bg) rather than a fixed hex
   so a custom theme gets it for free and each preset keeps its own hue.
   Placeholder deliberately left alone — it is already at 2.7:1 and some
   of these placeholders carry real instruction. */
.qform label{display:block;font-size:calc(12.5px * 0.88);letter-spacing:.16em;text-transform:uppercase;
font-weight:500;color:var(--label);margin-bottom:6px}
.qform input[type=text],.qform input[type=tel],.qform input[type=email],.qform textarea{width:100%;background:var(--dark2);
border:1px solid var(--border);border-radius:5px;color:var(--text);font-family:var(--font-body);
/* 16px, fixed, and NOT on the scale. Safari on iOS zooms the page when
   a focused input is under 16px, and Compact would take this to 14.08 -
   so a man tapping Name on his phone would get the whole page lurching
   in on him, which is the one moment in the funnel where nothing should
   move. The label above it scales; the input does not. */
font-stretch:normal;font-size:16px;padding:12px 14px}
.qform textarea{min-height:96px;resize:vertical}
.qform input:focus,.qform textarea:focus{outline:none;border-color:var(--accent)}
.qform ::placeholder{color:var(--placeholder);opacity:.42}   /* 58.227 lighter, 58.230 lighter again */
/* This is a <label>, so it inherits the uppercase and wide tracking
   meant for field labels — which turns required legal wording into
   the loudest thing on the form. Reset it to quiet body text. */
/* This is a <label> inside .qform, so .qform label — a class plus an
   element — outranks a plain .consent-row. Matching that specificity
   is what makes the two-column layout and the quiet type stick. */
.qform label.consent-row{display:grid;grid-template-columns:16px minmax(0,1fr);
gap:10px;align-items:start;margin:0;
text-transform:none;letter-spacing:normal;font-weight:400}
/* The label is one short line the person is meant to READ, so it takes
   body size and body colour. Every disclosure lives in .consent-note
   below it, which is the quiet type. Same split as everycall.co's own
   forms — the ask above, the small print under it. */
.qform label.consent-row span{font-size:calc(14px * 0.88);line-height:1.5;color:var(--off);
text-transform:none;letter-spacing:normal}
.qform label.consent-row input{margin:2px 0 0;width:15px;height:15px;flex:none;
accent-color:var(--accent)}
/* The checkbox and its small print are ONE grid item, not two. .qform is
   display:grid with gap:14px, and a grid gap does not collapse with the
   children's margins — so however small a margin the note carried, the
   gap set the distance and the print floated between the box and the
   button. Wrapping them makes the spacing below a margin we control.
   Worth remembering: in .qform, any two elements that belong together
   need a wrapper, not a smaller margin. */
.consent-block{margin:4px 0 0}
/* 11px at 1.45. Five lines of message-frequency-and-data-rates is the
   least persuasive content on the screen and it was setting the height
   of the whole card. A2P requires the words, not the size. */
.qform p.consent-note{margin:2px 0 0 26px;font-size:calc(12.5px * 0.88);line-height:1.45;
  color:var(--placeholder);opacity:.85}
/* Typo suggestion and the one error line. Both start hidden; the script
   adds .show. Amber for a question, red for a problem - neither uses the
   theme accent, because this is the form talking, not the brand. */
.qform .qsug{margin:6px 0 0;font-size:calc(14px * 0.88);line-height:1.5;color:#e0b25f;
text-transform:none;letter-spacing:normal;display:none}
.qform .qsug.show{display:block}
.qform .qsug b{color:var(--accent);cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.qform .qerr{margin:0;font-size:calc(14px * 0.88);line-height:1.5;color:#e08a80;
text-transform:none;letter-spacing:normal;display:none}
.qform .qerr.show{display:block}
.quote-alt{margin:16px 0 0;font-size:calc(14px * 0.88);color:var(--muted)}
.stats-bar{background:var(--dark2);border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:28px 24px}
.stats-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:28px 24px;text-align:center;align-items:start}
.stat-n{font-family:var(--font-display);font-weight:400;font-size:clamp(30px,3.2vw,42px);line-height:1.05;color:var(--accent-ink);min-height:1.05em;display:flex;align-items:center;justify-content:center}
.stat-n svg{width:1.15em;height:1.15em;margin:-.05em 0}   /* 58.315 bigger, so it carries the same weight as the numbers */
.stat-l{margin-top:6px;font-size:calc(14px * 0.88);letter-spacing:.08em;text-transform:uppercase;color:var(--off);line-height:1.4}
@media(max-width:620px){.stats-grid{grid-template-columns:1fr 1fr}.stats-bar{padding:24px 18px}}
.trust-bar{background:var(--dark2);border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:16px 0;overflow:hidden;max-width:100vw}
/* The track is width:max-content by design. Clipping has to happen on
   an element that is itself viewport-width — an inner .wrap can still
   report its children past the edge on mobile. */
.trust-bar .wrap{max-width:100%;width:100%;overflow:hidden;
-webkit-mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent);
        mask-image:linear-gradient(90deg,transparent,#000 4%,#000 96%,transparent)}
.trust-track{display:flex;width:max-content;animation:trustscroll 44s linear infinite}
.trust-bar:hover .trust-track{animation-play-state:paused}
@keyframes trustscroll{from{transform:translateX(0)}to{transform:translateX(-50%)}}
.trust-item{font-size:calc(14px * 0.88);letter-spacing:.08em;text-transform:uppercase;color:var(--off);
position:relative;padding:0 30px;white-space:nowrap;flex:none}
.trust-item::before{content:"";position:absolute;left:0;top:50%;width:1px;height:1.3em;transform:translateY(-50%);background:var(--accent);opacity:.55}   /* 58.312 a thin rule between items, not a dot */
/* 58.310 the icon version */
.trust-item--i{display:inline-flex;align-items:center;gap:10px;padding:0 28px}
.trust-item--i::before{display:none}
.trust-ico{flex:none;color:var(--accent);width:1.5em;height:1.5em}
.svc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;margin-top:40px}
.svc-grid--two{grid-template-columns:repeat(2,1fr)}   /* 58.337 four cards: two rows of two */
/* A column, so the parts inside can be made to line up across cards.
   Grid alignes the CARDS; it does nothing for what is inside them, which
   is why a two-line title pushed its own description and button down while
   the cards beside it stayed put. */
.svc{background:var(--surface);border:1px solid var(--border-soft);border-radius:8px;
overflow:hidden;padding-bottom:20px;display:flex;flex-direction:column}
/* A ratio, not a fixed height. 158px on a card about 380px wide is 2.4:1,
   and a stock landscape is 3:2 - so more than a third of the picture was
   being cut off top and bottom, which is how a man on a ladder ends up
   cropped to his waist.

   16:9 keeps the card compact while losing far less, and being a ratio it
   holds on tablet and phone where the cards get wider - a fixed height
   there was cropping harder still. min-height stops it collapsing on very
   narrow columns. */
.svc-img{aspect-ratio:16/9;min-height:150px;background-size:cover;background-position:center;background-color:var(--dark2);opacity:0.88;transition:opacity .25s,filter .25s}
.svc:hover .svc-img{opacity:1;}
.svc-img,.about-photo{position:relative;isolation:isolate}
.svc-img::before,.about-photo::before{content:"";position:absolute;inset:0;-webkit-backdrop-filter:saturate(.72) contrast(1.04);backdrop-filter:saturate(.72) contrast(1.04);transition:opacity .25s;pointer-events:none}
.about-photo::before,.about-photo::after{border-radius:8px}
.svc:hover .svc-img::before,.about-photo:hover::before{opacity:0}
.hero--scrim,.band--shot,.hero-panel-img{isolation:isolate}
.band--shot{position:relative}   /* 58.177 the frame for its tone layers - without it they sized to the window and tinted the section below */
.hero-panel-img{position:relative}
.hero--scrim::before,.band--shot::before,.hero-panel-img::before{content:"";position:absolute;inset:0;z-index:0;-webkit-backdrop-filter:saturate(.72) contrast(1.04);backdrop-filter:saturate(.72) contrast(1.04);pointer-events:none}
.hero--scrim>*,.band--shot>*{position:relative;z-index:1}
/* 56.2 flex, not block. .svc makes the card a column so the button can
   sit on the bottom, and this rule came later and turned it back into a
   block - on exactly the cards that have a button, since only linked
   cards get one. So margin-top:auto on .svc-more did nothing and each
   Read more sat wherever its blurb ended. */
.svc--link{text-decoration:none;display:flex;transition:border-color .2s,transform .15s}
.svc--link:hover{border-color:rgba(var(--accent-rgb),.45);transform:translateY(-3px)}
.svc--link:hover h3{color:var(--accent-lt)}
/* The same secondary button as "Leave us a review", so the site has one
   button that means "this is optional, press it if you want" rather than
   two that look alike but not quite. btn--ghost carries the whole look;
   only the positioning belongs here.

   margin-top:auto pins it to the bottom of the card, so the buttons line
   up across the row however long the titles and descriptions run. */
/* margin-top:auto pushes it to the bottom of the card so the buttons line
   up across the row. It also means any margin-top set here is ignored -
   the gap above comes from the paragraph's own margin-bottom instead,
   which is a floor rather than whatever slack the card happens to have. */
/* -10px on the top. The button sat hard against the bottom padding and
   read as an afterthought rather than part of the card. */
.call-ico{display:inline-block;vertical-align:-0.125em;margin-right:.55em;width:1em;height:1em;margin-top:-.2em;margin-bottom:-.2em}   /* 58.149 no taller than the text, so an icon button is the same height as its neighbour */
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.svc-more{align-self:flex-start;margin:0 20px;margin-top:auto;position:relative;top:-10px}
/* 58.133 The text-link choice: "Read more →" in the accent colour, normal
   lettering whatever the button lettering is, and the arrow nudges right
   when the card is hovered. Same place on the card as the button. */
.svc-more--link{font-family:var(--font-body);font-size:calc(16px * 0.88);font-weight:600;color:var(--accent);line-height:1.4;padding:6px 0;text-transform:none;letter-spacing:0}
.svc-more--link .svc-arrow{display:inline-block;margin-left:4px;transition:transform .2s}
/* 58.166 The text link sits 24px off the bottom, like the sides - no nudge, no padding under it. */
.svc .svc-more--link{top:0;padding:0;margin-bottom:4px!important}   /* 67.2 !important: the last-child rule for bands was taking it off the last card only, so its link sat 4px lower */
.svc:has(.svc-more--link) p{margin-bottom:12px}   /* 58.204 a text link needs less air above it than a button: 12px, was 24 */
.svc-more--link,.svc-more--link .svc-arrow{font-weight:400}   /* 58.168 regular, words and arrow alike */
/* 58.183 The ask under the reviews: a line of text and a link in the accent, like Read more. */
.rev-ask{margin:24px 0 0;font-size:calc(16px * 0.88);color:var(--off)}
.rev-ask--c{text-align:center}
.rev-ask a{color:var(--accent-ink);text-decoration:none;white-space:nowrap}
.rev-ask a .svc-arrow{display:inline-block;margin-left:4px;transition:transform .2s}
.rev-ask a:hover .svc-arrow{transform:translateX(4px)}
.svc--link:hover .svc-more--link .svc-arrow{transform:translateX(4px)}
.svcl--link{text-decoration:none}
.svcl--link:hover h3{color:var(--accent-lt)}
.svc-points{list-style:none;margin:22px 0 0;padding:0;display:grid;gap:11px}
.svc-points li{position:relative;padding-left:24px;font-size:calc(16px * 0.88);line-height:1.6;color:var(--off)}
.svc-points li::before{content:"";position:absolute;left:0;top:9px;width:7px;height:7px;
border-radius:50%;background:var(--accent)}
/* Follows the Hero darkening slider, plus 10.

   It was hardcoded at .82 to .9 while the homepage hero used the
   slider, so a build set to a light 42% still had near-black service
   pages - the photo was a texture and the heading had gone. One number
   for the whole site now, with a small offset because these pages are
   the harder case: the homepage hero has the quote card beside it to
   carry the eye, and here the copy sits directly on the photograph with
   nothing else to hold it.

   Capped at .92 so the top of the slider cannot produce a black band. */
.band--shot{background-image:linear-gradient(
  rgba(0,0,0,0.52),
  rgba(0,0,0,0.58)),var(--hero-img);
background-size:cover;background-position:center}
/* Two lines of room whether the title needs them or not, so every
   description starts at the same height across the row. Reserving the
   space is what aligns them - a one-line title in a fixed box beats
   three ragged cards. */
.svc h3{margin:18px 20px 8px;line-height:1.2;min-height:0;
display:flex;align-items:flex-end}
/* 58.322 Where the browser can, line the cards up with subgrid instead of
   reserving two lines for every title: each row of cards shares its title
   height, so a row of one-line titles has no empty line above them, and a
   row with a two-line title still starts its descriptions level. The
   fixed two-line room (above) is only the fallback now. A title of 23
   letters was tipping a whole grid into the two-line room it did not need. */
@supports (grid-template-rows: subgrid){
  .svc-grid > .svc{display:grid;grid-template-rows:subgrid;grid-row:span 4;row-gap:0}
  .svc-grid > .svc h3{min-height:0}
  .svc-grid > .svc .svc-more{align-self:end}
}
.svc p{margin:0 20px 24px;font-size:calc(16px * 0.88);color:var(--muted)}
/* Extra pages. A person is photo-beside-text and stacks on a phone; a row
   of pictures is a grid that fits however many were on the line; one on
   its own runs the width of the column. */
.xp-person{display:grid;grid-template-columns:180px minmax(0,1fr);gap:26px;
align-items:start;margin:0 0 34px}
.xp-person-img img{width:100%;height:auto;border-radius:8px;display:block;
border:1px solid var(--border);opacity:0.88;transition:opacity .25s,filter .25s}
.xp-person:hover .xp-person-img img{opacity:1;}
.xp-person h3{margin:0 0 8px}
.xp-person p{margin:0;color:var(--muted)}
/* 57.82 People as a grid: big photos, name and role under. */
.xp-team{display:grid;gap:30px 22px;margin:0 0 34px}
.xp-team--2{grid-template-columns:repeat(2,minmax(0,1fr))}
.xp-team--3{grid-template-columns:repeat(3,minmax(0,1fr))}
.xp-team--4{grid-template-columns:repeat(4,minmax(0,1fr))}
.xp-card-img img{width:100%;aspect-ratio:4/5;object-fit:cover;object-position:center 25%;border-radius:8px;display:block;
border:1px solid var(--border);opacity:0.88;transition:opacity .25s,filter .25s}
.xp-card:hover .xp-card-img img{opacity:1;}
.xp-card h3{margin:14px 0 4px}
.xp-card p{margin:0 0 10px;color:var(--muted);font-size:calc(16px * 0.88)}
.xp-card p:last-child{margin-bottom:0}
/* 64.1 Photos capped - a portrait, not a poster, in a wide column */
.xp-card-img img{max-width:240px}
.xp-team--2{gap:44px 48px}
@media(max-width:860px){.xp-team--3,.xp-team--4{grid-template-columns:repeat(2,minmax(0,1fr))}}
/* 63.8 Cards with round photos */
.xp-team--c{gap:26px;align-items:stretch}
/* 64.2 cards in a row share one height */
.xp-rcard{height:100%;box-sizing:border-box}
.xp-rcard{background:var(--surface);border:1px solid var(--border-soft);border-radius:14px;padding:30px 28px;box-shadow:0 8px 28px rgba(var(--ink-rgb),.07)}
.xp-rimg img{width:150px;height:150px;border-radius:50%;object-fit:cover;object-position:center 25%;display:block;margin:0 0 18px}
.xp-rcard h3{margin:0 0 7px;color:var(--accent-ink)}
/* 64.3 role lighter; centred option */
.xp-rcard .xp-role{font-weight:500!important;color:var(--off)!important;margin:0 0 14px!important}
.xp-team--mid .xp-rcard>.xp-rimg img{margin-left:auto;margin-right:auto}
.xp-team--mid .xp-rcard>h3,.xp-team--mid .xp-rcard>.xp-role{text-align:center}
.xp-role{margin:0 0 12px!important;font-weight:600;color:var(--text)!important}
.xp-rcard p{margin:0 0 10px;color:var(--muted)}
.xp-rcard p:last-child{margin-bottom:0}
.xp-person .xp-role,.xp-card .xp-role{margin:0 0 8px!important}
@media(max-width:860px){.xp-team--c.xp-team--3{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:700px){.xp-team--c.xp-team--2,.xp-team--c.xp-team--3{grid-template-columns:minmax(0,1fr)}.xp-rimg img{width:120px;height:120px}}
@media(max-width:480px){.xp-team--2,.xp-team--3,.xp-team--4{gap:22px 14px}}
.xp-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
gap:16px;margin:0 0 30px}
/* One shape for every gallery photo, 4:3, cropped to fill.

   height:auto let each tile take its own proportions, so a row came out
   as three different heights and a photo on its own line ran the full
   width of the page - about 700px tall next to a 240px row, which read
   as one huge picture with thumbnails above it rather than as a
   gallery. A fixed ratio is what makes a grid look like a grid; the
   whole photo is still one click away. */
.xp-grid img,.xp-figure img{width:100%;aspect-ratio:4/3;object-fit:cover;
border-radius:8px;display:block;cursor:zoom-in;
border:1px solid var(--border-soft);opacity:0.88;transition:opacity .25s,filter .25s}
/* A photo on its own line is wider than one in a row, but not taller -
   16:9 keeps it from becoming a wall. */
.xp-figure img{aspect-ratio:16/9}
.xp-grid img:hover,.xp-figure img:hover{opacity:1;}

/* ── LIGHTBOX ────────────────────────────────────────────────────
   The crop above means a tile shows part of a photo, so there has to
   be a way to see the rest of it. Click any gallery image and it opens
   at full size. */
.lb{position:fixed;inset:0;z-index:200;background:rgba(8,10,14,.92);
display:none;align-items:center;justify-content:center;padding:24px;cursor:zoom-out}
.lb.on{display:flex}
.lb img{max-width:100%;max-height:100%;border-radius:6px;display:block}
.lb-x{position:absolute;top:14px;right:18px;background:none;border:0;cursor:pointer;
color:#e8eef4;font-size:34px;line-height:1;padding:4px 10px}
.xp-figure{margin:0 0 30px}
/* The gap the two bands used to make, now set on purpose and once. */
.xp-body{margin-top:34px}
.xp-body>*:last-child{margin-bottom:0}
@media(max-width:640px){.xp-person{grid-template-columns:minmax(0,1fr);gap:16px}
.xp-person-img{max-width:200px}}
/* 300 wide and square, from 380 wide at 4:5.

   Narrowing it alone was the wrong fix and did not work: 4:5 is a
   portrait, so the height is always a quarter more again than whatever
   width it is given - 380 made a 475-tall slab, 280 made a 350-tall
   one, same shape either way. What was wrong was the shape, not the
   size. Square at 300 sits against the five or so lines of copy beside
   it instead of running past them, and the eye reaches the heading
   first. The focus control still does its job - object-position works
   on any crop. */
.about-grid{display:grid;grid-template-columns:300px minmax(0,1fr);gap:clamp(28px,4vw,52px);align-items:start}
/* A 4:5 box, whatever shape the photo arrives in.

   height:auto let a 2:3 phone portrait run to one and a half times its
   own width and tower over the paragraph beside it. Capping the height
   was worse: it cropped in tight and pressed him against both edges,
   because the column is wider than the cap assumed.

   A fixed proportion solves both, and it holds whatever the camera did.
   Square, not the 4:5 portrait this used to be: at 4:5 the height is
   always a quarter more again than the width, so the photo ran past the
   copy beside it however narrow the column got - narrowing it was the
   wrong fix and did not work. object-position at 28% keeps the head in
   frame; centre is how you end up with a photograph of a chest. */
/* height:auto is load-bearing. The <img> carries width and height
   attributes so the browser can reserve the right box before the file
   lands, and those attributes act as a real CSS height. With both a
   width and a height set, aspect-ratio is ignored outright - so this
   rule was doing nothing at all and the photo was simply whatever the
   two attributes said: 380x480 before, 300x420 after narrowing it.
   Releasing the height is what lets the crop below take effect. */
.about-photo img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;object-position:center 28%;
border-radius:8px;border:1px solid var(--border);display:block;opacity:0.88;transition:opacity .25s,filter .25s}
.about-photo:hover img{opacity:1;}
/* 66.2 Landscape photo shapes, shown at their own proportions so nobody
   at the edge of a group shot is cut off. Beside: half the width. Across
   the top: the full width (no taller than 560px), the words underneath
   at a readable width. */
.about-grid--wide{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center}
.about-grid--wide .about-photo img{aspect-ratio:auto}   /* its own shape - a crop lost the man on the end */
.about-grid--top{grid-template-columns:1fr;gap:34px}
.about-grid--top .about-photo img{aspect-ratio:auto;max-height:560px}
.about-grid--top>div:last-child{max-width:820px}
.about-top-head{max-width:820px;margin:0 0 26px}
.about-top-head h2{margin-bottom:0}
.process{display:grid;grid-template-columns:repeat(4,1fr);gap:20px;margin-top:40px}
/* Stacked steps beside the quote form. Deliberately its own class
   rather than a .process modifier — the responsive rules for .process
   kept overriding it and collapsing the column to a few characters. */
.pflow{display:block;margin-top:40px}
/* 58.164 The eyebrow runs across the top of the Get in touch band, so the form lines up with the heading beside it, not with the eyebrow. */
.band--ask .hero-grid{align-items:start}
/* 58.166 30px under every section heading, whatever comes next. The
   next thing drops its own top margin so the two do not stack. Not the
   form's header strip, and not the privacy and terms pages. */
.band .wrap:not(.legal) h2:not(.quote-h){margin-bottom:30px}
/* 58.206 Exactly 50px at the top and bottom of every section: the band's
   own padding, with nothing inside adding to it - the first thing drops
   its top margin and the last thing (and the last thing inside it) its
   bottom margin. */
.band > .wrap > :first-child,.band > .wrap > :first-child > :first-child{margin-top:0}
.band > .wrap > .eyebrow:first-child{margin-top:-2px}   /* 58.210 the capitals' own top edge on the 50px line */
.band > .wrap > :last-child,.band > .wrap > :last-child > :last-child,.band > .wrap > :last-child > :last-child > :last-child{margin-bottom:0}
.band .wrap:not(.legal) h2:not(.quote-h) + *{margin-top:0}
.band .wrap:not(.legal) h2:not(.quote-h) + * > :first-child,.band .rev-head + * > :first-child{margin-top:0}
.band .wrap:not(.legal) h2:not(.quote-h) + .areas-split > *{margin-top:0}
.band .wrap:not(.legal) h2:not(.quote-h) + .faq:not(.faq--box) > details:first-child{padding-top:0}
.band .wrap:not(.legal) .rev-head h2:not(.quote-h){margin-bottom:0}
.band .rev-head{margin-bottom:30px}
.band .rev-head + *{margin-top:0}
/* 58.211 The line under a heading: 30px under it, 30px to what follows, and
   it takes over the job of the heading's + * rules for whatever comes next. */
.band .wrap .sec-intro{margin:0 0 30px;max-width:720px;font-size:calc(16px * 0.88);line-height:1.55;color:var(--muted)}
/* 58.213 The line under Tell us what you need is a section intro too, so it matches the others: same size and colour (it was the hero's larger lead-in size). */
.band--ask .lede{font-size:calc(16px * 0.88);line-height:1.55;color:var(--muted)}
/* 58.213 The line under a heading belongs to it: 12px between them, not the
   30px that separates a heading from the section's content. The 30px stays
   between that line and what follows. */
.band .wrap:not(.legal) h2:not(.quote-h):has(+ .sec-intro),.band .wrap:not(.legal) h2:not(.quote-h):has(+ .lede),.band .rev-head:has(+ .sec-intro){margin-bottom:12px}
.band .wrap .sec-intro + *{margin-top:0}
.band .wrap .sec-intro + * > :first-child{margin-top:0}
.band .wrap .sec-intro + .areas-split > *{margin-top:0}
.band .wrap .sec-intro + .faq:not(.faq--box) > details:first-child{padding-top:0}
/* 58.165 Open: the form sits on the band, no card, with a thin line
   between the columns. Scoped to the band, so a form moved into the
   pop-up is a card again. */
.band--ask .quote-card{background:transparent;border:0;border-left:1px solid var(--border);border-radius:0;box-shadow:none;
padding:0 0 0 clamp(28px,4vw,56px);-webkit-backdrop-filter:none;backdrop-filter:none}
.band--ask .quote-card .quote-h,.band--ask .quote-card .quote-sub{display:none}
.band--ask .quote-card.is-lit{box-shadow:none;border-left-color:var(--accent)}
@media(max-width:900px){.band--ask .quote-card{border-left:0;border-top:1px solid var(--border);padding:32px 0 0}}
/* Three children, two columns: the number and the heading fill row
   one, and the paragraph lands in row two — which is the 32px column
   unless it is told otherwise. That was the one-word-per-line bug. */
.pflow .pstep{display:grid;grid-template-columns:32px minmax(0,1fr);gap:4px 12px;
border-top:1px solid var(--border-soft);padding:14px 0 0;margin-top:14px;align-items:start}
.pflow .pstep h3{grid-column:2}
.pflow .pstep p{grid-column:2;min-width:0}
.pflow .pstep:first-child{border-top:0;margin-top:0;padding-top:0}
.pflow .pnum{font-family:var(--font-display);font-size:calc(26px * 0.88);color:var(--accent);line-height:1.1;display:block;margin:0}
.pflow h3{margin:0 0 4px}   /* 58.168 the card-title size, like every other step and card */
.pflow p{font-size:calc(16px * 0.88);color:var(--muted);margin:0}
.pstep{border-top:2px solid var(--border);padding-top:18px}
.pnum{font-family:var(--font-display);font-size:calc(34px * 0.88);color:var(--accent);line-height:1;display:block;margin-bottom:8px}
.pstep h3{margin-bottom:7px}.pstep p{font-size:calc(16px * 0.88);color:var(--muted);margin:0}
/* 58.180 Circled markers - the number or icon in white on the accent (or its darker shade). */
.pnum.pnum--c{display:flex;align-items:center;justify-content:center;width:52px;height:52px;border-radius:50%;background:var(--accent);color:#fff;font-size:calc(22px * 0.88);line-height:1;margin-bottom:16px}
.pnum.pnum--i svg{width:24px;height:24px}
.pflow .pnum.pnum--c{width:40px;height:40px;font-size:calc(18px * 0.88);margin:0;grid-row:1 / span 2}
.pflow .pnum.pnum--i svg{width:19px;height:19px}
.pflow .pstep:has(.pnum--c){grid-template-columns:40px minmax(0,1fr);gap:4px 16px}
/* rating badge + reviews */
/* 23px, up from 19. On a review card the stars are the thing the eye
   lands on before it reads a word, and at 19 they were smaller than the
   review text sitting under them — which read as a footnote rather
   than a rating. The rating badge in the section heading uses the same
   class and takes the increase with it, which is wanted: it carries the
   4.9 and the count. */
/* Meant to be mistaken for Google's, because that is where the rating
   came from and a star that looks like something else invites the
   question of where the number came from.

   Two things were off against a real review card. The colour was
   #f0b429, a duller mustard that reads brown-gold next to Google's;
   theirs is #fbbc04, their own amber, and it is noticeably more
   saturated. And the glyph carries its own side bearing, so a 2px gap
   on top of that left them visibly spaced out where Google's very
   nearly touch. The gap is gone and a small negative letter-spacing
   pulls in the built-in padding the glyph brings with it.

   Closed with a negative margin between the stars, NOT with
   letter-spacing on .star — which was the first attempt and quietly
   broke the ratings. The space is inside the glyph, so letter-spacing
   does reach it, but it also narrows the .star box, and .star-f is a
   percentage width clipped against that box. At 100% the fill was
   clipping 1.3px short of the glyph and shaving the point off every
   full star, on cards that are hardcoded to five of them. A margin
   moves the boxes without resizing them, so the fill still measures
   against the whole glyph. */
.star{position:relative;display:inline-block;color:rgba(var(--ink-rgb),.18);
font-size:calc(23px * 0.88);line-height:1}
.star + .star{margin-left:-2.5px}
.star-f{position:absolute;left:0;top:0;overflow:hidden;color:#fbbc04;white-space:nowrap}
.ratingbadge{display:inline-flex;align-items:center;gap:10px;text-decoration:none;
background:var(--dark2);border:1px solid var(--border);border-radius:100px;padding:9px 18px;
transition:border-color .2s}
a.ratingbadge:hover{border-color:rgba(var(--accent-rgb),.5)}
/* 19, not 22, and scaled with the rest of the site.

   22 against the 14px count is a ratio of 1.57, which reads right in a
   condensed display face like Bebas - the digits are narrow, so a big
   number still sits quietly. In a wide face like Poppins the same ratio
   is a slab: the 5.0 arrives before the stars and the count, which are
   the parts carrying the proof. 19 keeps it the largest thing in the
   badge without it being the loudest.

   sz() so it follows the Text size control, like everything else in the
   generated stylesheet - a fixed pixel size is what made the nav and
   this both need fixing by hand. */
.rb-score{font-family:var(--font-display);font-size:calc(21px * 0.88);color:var(--text);line-height:1}
.rb-stars{display:inline-flex;gap:0}
.rb-count{font-size:calc(14px * 0.88);color:var(--muted);white-space:nowrap}
.hero-rating{margin-top:34px}
.rev-head{display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.rev-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-top:36px}
/* VIDEO TESTIMONIALS. 16:9 is locked with aspect-ratio rather than left
   to the file, so the grid does not jump about as posters arrive at
   different sizes. Two columns, one under 700px — three would put them
   at a size nobody can read a face in. */
.vt-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:20px;margin-top:8px}
.vt-item{margin:0}
.vt-media{width:100%;aspect-ratio:16/9;display:block;border-radius:8px;overflow:hidden;
background:var(--deep);border:1px solid var(--border)}
.vt-yt{position:relative;padding:0;cursor:pointer}
.vt-yt img{width:100%;height:100%;object-fit:cover;display:block}
/* YouTube's hqdefault is 4:3 with black bars top and bottom; scaling it
   slightly and cropping gets rid of them without a second request. */
.vt-yt img{transform:scale(1.35)}
.vt-play{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
width:64px;height:64px;border-radius:50%;background:var(--cta);
box-shadow:0 4px 18px rgba(0,0,0,.45);transition:transform .16s}
.vt-play::after{content:'';position:absolute;left:54%;top:50%;transform:translate(-50%,-50%);
border-style:solid;border-width:11px 0 11px 18px;border-color:transparent transparent transparent #fff}
.vt-yt:hover .vt-play,.vt-yt:focus-visible .vt-play{transform:translate(-50%,-50%) scale(1.09)}
.vt-media iframe{width:100%;height:100%;border:0;display:block}
.vt-cap{margin-top:9px;font-size:calc(16px * 0.88);color:var(--muted)}
/* 58.185 Rows, not newspaper columns, so newest first reads left to right, row by row. */
.rev-wall{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;align-items:start;margin-top:8px}
.rev-wall .rev{margin:0;display:block;width:auto}
.rev{margin:0;background:var(--surface);border:1px solid var(--border-soft);
border-radius:8px;padding:22px}
/* Name, then stars and when, then the words — the order Google itself
   uses, and the order somebody reads a review in. Who said it decides
   whether the rest is worth reading, so it goes first; the stars and
   the date qualify it; the words follow.

   It used to open on five stars and finish on the name, which put the
   least specific thing at the top of every card and the one piece of
   evidence that it is a real person at the bottom. Five identical rows
   of gold stars down a page is decoration; a name is not. */
/* 58.168 Reviewer names as card titles - the heading face at the h3 size, like the service and area names. */
.rev-who,.rev figcaption.rev-who{font-family:var(--font-display);font-stretch:normal;font-size:calc(22px * 0.88);font-weight:400;letter-spacing:.01em;line-height:1.15;color:var(--text);margin:0 0 8px}
.rev-meta{display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap}
/* inline-flex, not flex: it sits beside the date now rather than owning
   its own row, and a block-level flex would push the date underneath. */
.rev-stars{display:inline-flex;gap:0}
.rev-when{font-size:calc(14px * 0.88);color:var(--muted)}
/* 15.5, matching the service cards, and run through the type scale.

   It was a flat 16px next to service cards at 15.5 and area cards at
   15 - bigger than either, on the same page, in the same shape of box.
   Half a pixel is not much on its own; three card types disagreeing by
   half a pixel each is what makes a page look assembled rather than
   designed.

   The scale is the other half. Body copy is sz('17px'), so the whole
   page grows and shrinks with the Type scale setting - and the reviews
   did not, being hardcoded. Turn the scale up and they were the only
   text that stayed put; turn it down and they were the only text that
   stayed large, which is what makes them look oversized. */
.rev blockquote{margin:0;font-size:calc(16px * 0.88);line-height:1.6;color:var(--off)}
/* Reads as part of the sentence it interrupts, because it is. A button
   styled like a button would pull the eye away from the review, which
   is the thing worth reading. */
.rev-more{background:none;border:0;padding:0;margin:0;font:inherit;color:var(--accent);
cursor:pointer;white-space:nowrap}
.rev-more:hover{text-decoration:underline;text-underline-offset:2px}
.rev figcaption{font-size:calc(14px * 0.88);color:var(--text)}
.rev figcaption span{color:var(--muted)}
.mapwrap{border:1px solid var(--border);border-radius:8px;overflow:hidden;
background:var(--dark2);margin-top:40px;line-height:0}
.mapwrap iframe{width:100%;height:340px;border:0;display:block;filter:grayscale(.12) contrast(1.02)}
.areas-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:clamp(24px,3.5vw,44px);align-items:start}
.areas-split .mapwrap{margin-top:40px}
.area-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:40px}
.area-grid--tight{grid-template-columns:repeat(2,1fr)}
/* 58.209 More than six towns: the list ran far below the map and left a
   column of empty space beside it. The map goes full width across the top
   (a little shorter, since it is wide) and the cards sit three across
   underneath. Six or fewer keep the side-by-side layout. */
.areas-split--wide{grid-template-columns:1fr;gap:30px}   /* 58.210 30px under the map, like under a heading (was 14) */
.areas-split--wide .mapwrap iframe{height:300px}
.areas-split--wide .area-grid--tight{grid-template-columns:repeat(3,1fr);margin-top:0}
@media(max-width:900px){.areas-split--wide .area-grid--tight{grid-template-columns:repeat(2,1fr)}.areas-split--wide .mapwrap iframe{height:260px}}
@media(max-width:600px){.areas-split--wide .area-grid--tight{grid-template-columns:1fr}.areas-split--wide .mapwrap iframe{height:240px}}
.area{display:block;background:var(--dark2);border:1px solid var(--border-soft);border-radius:8px;
padding:20px;text-decoration:none;transition:border-color .2s,transform .15s}
.area:hover{border-color:rgba(var(--accent-rgb),.45);transform:translateY(-2px)}
.area h3{margin-bottom:7px}.area:hover h3{color:var(--accent-lt)}
.area p{margin:0;font-size:calc(16px * 0.88);color:var(--muted)}
/* The iframe arrives with no height of its own; form_embed.js sets one
   once the calendar has drawn. min-height stops the collapse in between,
   and on a phone the month grid needs the room anyway. */
/* No border, no background, no radius. The GHL widget draws its own dark
   panel with its own border, so framing it here produced a card inside a
   card. The widget's panel is narrower than the band, so expect dark space
   either side — that is the widget's own width, not a gap we can close
   from out here. Put the frame back if the widget is ever set to render
   transparent. */
.calwrap{margin-top:36px}
/* On /book the page heading sits directly above, so the band's own top
   padding stacked on the wrap's margin AND the section above it — three
   gaps in a row. Nothing between the lede and the calendar needs them. */
.band--calflush{padding-top:0}
.band--calflush .calwrap{margin-top:0}
.calwrap iframe{display:block;width:100%;min-height:720px;border:0}
@media(max-width:620px){.calwrap iframe{min-height:820px}}
.faq{margin-top:40px}
.faq details{border-bottom:1px solid var(--border-soft);padding:18px 0}
.faq summary{cursor:pointer;list-style:none;font-size:calc(18px * 0.88);font-weight:400;color:var(--text);   /* 58.50 regular - the size and brighter colour already mark it as the question */
display:flex;justify-content:space-between;gap:18px;align-items:center}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";color:var(--accent);font-size:calc(26px * 0.88);line-height:1;flex:none}
.faq details[open] summary::after{content:"\2013"}
.faq details p{margin:14px 0 0;max-width:72ch;color:var(--muted)}
/* 58.134 The boxed choice: every question in one rounded card, a line
   between each, and a down arrow that turns up when it is open - in
   place of the open rows with a plus. */
.faq--box{background:var(--surface);border:1px solid var(--border);border-radius:12px;overflow:hidden}
.faq--box details{padding:15px 24px;border-bottom:1px solid var(--border-soft)}   /* 58.138 15, down from 20 */
.faq--box details:last-child{border-bottom:0}
.faq--box summary::after,.faq--box details[open] summary::after{content:"";width:9px;height:9px;flex:none;
border-right:2px solid var(--off);border-bottom:2px solid var(--off);transform:translateY(-3px) rotate(45deg);transition:transform .2s}
.faq--box details[open] summary::after{transform:translateY(2px) rotate(-135deg)}
@media(max-width:560px){.faq--box details{padding:14px 16px}}
.site-footer{background:var(--footer-bg);border-top:1px solid var(--border);padding:49px 24px 0}
/* 58.255 A dark footer whatever the theme: its own background, and the colours inside it re-pointed so every link, heading, icon and button follows. Fixed darks rather than mixes of the theme's text, so a swatch to a dark palette cannot turn it pale. */
.site-footer{background:color-mix(in srgb,var(--accent) 24%,#101214);border-top-color:transparent}
/* 58.288 On the footer's own contents only - the Before you go dialog and the tour sit inside the footer in the page, and took the pale footer colours onto their light cards. */
.site-footer > :not(.tk-exit):not([class^="tk-tour"]){
--text:#f3f1ee;--off:#d6dbe0;--muted:#a3acb6;--label:#c5ccd3;--border:rgba(255,255,255,.16);--border-soft:rgba(255,255,255,.08);
--accent-ink:color-mix(in srgb,var(--accent) 40%,#ffffff);--accent-lt:color-mix(in srgb,var(--accent) 40%,#ffffff)}
/* 57.91 50px to the top of the letters, not to the top of the line. The
   border is 1px of it, and the headings trim the space a line of text
   carries above its capitals (text-box, in current Chrome, Edge and
   Safari; a browser without it shows a few px more, as before). */
/* auto-fit, not four fixed tracks. The columns were 1.4fr 1.3fr .95fr
   1.05fr, which is right for exactly four - and an extra-pages column
   makes five, so Hours wrapped underneath the business details and the
   footer looked broken. This takes however many there are: four across
   on a wide screen, two on a tablet, one on a phone, and it cannot be
   thrown out by adding a column again. The first column is wider
   because it carries the address, the phone, the email and the buttons. */
.footer-inner{max-width:var(--col);margin:0 auto;display:grid;
grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
gap:26px 40px;padding-bottom:20px}
.footer-inner>.footer-col:first-child{min-width:230px}
/* 17, down from 19. With the links smaller the headings were carrying
   too much weight for what they are - column labels, not headlines. */
/* .07em was set for Bebas, which is condensed enough that generous
   tracking reads as deliberate. On a wide face it just looks stretched -
   same trap as the nav and the rating badge. */
.footer-heading{font-family:var(--font-display);font-size:calc(16px * 0.88);   /* 58.127 16, down from 18 - a column label, two steps over the 14px links rather than three */letter-spacing:.02em;color:var(--text);margin-bottom:12px;text-box:trim-start cap alphabetic}
/* Social icons. 36px targets on an 18px glyph, so they clear the 44px
   guidance once the row gap is counted, and laid out as a wrapping flex
   row so six of them still behave in a narrow column. */
.soc-row{display:flex;flex-wrap:wrap;gap:6px}
/* Outlined and muted, not filled in the CTA colour.

   They were solid --cta circles, the same red as Book a visit and the
   chat launcher - so the brightest thing in the bottom bar was a link
   OFF the site, sitting a few lines under the two buttons that are the
   whole point of the footer. Three red objects in the last stretch of
   the page, and the one that leads away was as loud as the two that
   lead in.

   A thin border and muted glyph now, brightening to the CTA on hover.
   They are still findable by anyone looking for them, which is all a
   social link in a footer has to be, and they no longer compete.

   Kept for reference, since it explains the colour they brighten TO:
   --cta and --on-cta, not the derived accent ink.

   The circles were built from accent-ink, which is the accent mixed
   toward the text until it clears 4.5:1 against the footer. On the six
   presets that lands close to the accent, so the circles matched the
   chat bubble by accident. On a custom palette whose accent fails that
   test - his orange did - it darkens several steps and the two stop
   matching, on the one build where the colour is actually his.

   The button colour has none of that problem: it is what the chat
   bubble and every button on the site already use, and --on-cta is
   designed to be readable on it, so the glyph needs no contrast
   working-out at all. */
.soc-row a{display:inline-flex;align-items:center;justify-content:center;
width:36px;height:36px;border-radius:50%;
border:1px solid var(--border);background:transparent;color:var(--muted);
transition:background .18s,color .18s,border-color .18s,transform .15s}
.soc-row a:hover{background:var(--cta);border-color:var(--cta);
color:var(--on-cta);transform:translateY(-2px)}
/* 14.5, down from 15.5. Body is 17px, so at 15.5 the footer read as a
   continuation of the page rather than as the quiet end of it - the
   convention is nearer 14. Not lower than this, though: these are real
   links people tap on a phone, and below about 14px they get hard to
   hit on a site whose whole argument is that it works on a phone. */
.footer-link,.footer-line{display:block;font-size:calc(14px * 0.88);   /* 58.47 up from 13px; 58.49 14, on the scale */line-height:1.5;color:var(--muted);
text-decoration:none;padding:3px 0;margin:0}
.footer-line.fi{display:flex;align-items:flex-start;gap:9px}
.footer-line.fi .fi-i{flex:none;margin-top:.22em;opacity:.8}
.footer-line.fi a{color:inherit;text-decoration:none}.footer-line.fi a:hover{color:var(--accent-ink)}
.footer-link:hover{color:var(--accent-ink)}
/* The links sitting INSIDE a .footer-line — the phone and the email — are
   not the .footer-line itself, so the text-decoration:none above never
   reached them and the global a rule underlined them. */
.footer-line a{text-decoration:none;color:var(--accent-ink)}
.footer-line a:hover{color:var(--text)}
/* Leave us a review is an outlined button in the same colour, and it
   was failing the same way. */
.site-footer .btn--ghost{color:var(--accent-ink);border-color:var(--accent-ink)}
.site-footer .btn--ghost:hover{color:var(--text);border-color:var(--text)}
/* Hours were a fixed 122px first column, so a long day ran straight into
   its own time with no gap while a short one left a hole. Two real columns
   instead: the day takes what it needs and wraps inside its own column,
   the time is auto-width and right-aligned so every row lines up. */
.footer-hours{display:grid;grid-template-columns:1fr auto;gap:2px 14px;align-items:baseline;
padding:1px 0;font-size:calc(14px * 0.88)}
.footer-hours span:last-child{white-space:nowrap;text-align:right;color:inherit}   /* 58.48 same as the rest of the footer */
/* 58.129 One grid for all the rows, so the times sit a set gap after the
   longest day and still line up - rather than pushed to the far edge of
   the column with a hole after every short day. */
.footer-hours-grid{display:grid;grid-template-columns:auto auto;justify-content:start;column-gap:22px;row-gap:3px;font-size:calc(14px * 0.88)}
.footer-hours-grid .footer-hours{display:contents}
.footer-hours-grid .footer-hours span:last-child{text-align:left}
/* Stacked in a narrow footer column, two buttons at their own content
   widths read as a mistake — so they share a width. Capped well short of
   the column, though: filling it puts a solid block right up against the
   Services list next door. */
/* 26px under the row, not nothing. The bottom bar's rule sat straight
   under the buttons with only its own padding below it, so the line read
   as an underline on the pair rather than as the start of the bar. */
.footer-btns{max-width:var(--col);margin:10px auto 26px;display:grid;
grid-template-columns:repeat(2,minmax(0,250px));gap:12px;justify-content:center}   /* 58.150 250, room for the larger lettering */
/* One row of the grid means one width, whatever the labels are. Flex
   sized each button to its own text, so "Book a visit" came out narrower
   than "Leave us a review" and the pair read as two unrelated buttons
   that happened to be next to each other. */
@media(max-width:420px){.footer-btns{grid-template-columns:minmax(0,260px)}}
/* Height stated rather than left to the padding, so "Leave us a review"
   and "Book online" are the same button whatever their labels do. The
   grid is a fixed width and the longer label was wrapping inside it,
   which made one taller than the other. */
.footer-btns .btn{height:50px;font-size:calc(18px * 0.88);padding-left:28px;padding-right:28px;display:inline-flex;align-items:center;   /* 58.150 same height as every other button */

justify-content:center;padding:0 22px;white-space:nowrap;text-align:center}
.footer-bottom{max-width:var(--col);margin:0 auto;border-top:1px solid var(--border-soft);
padding:18px 0 26px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:10px 24px;
font-size:calc(14px * 0.88);color:var(--muted)}   /* 58.169 the same size and grey as the footer links (was 12.5px, dimmer) */
/* No underline, deliberately. PageSpeed flags this as "links rely on colour
   to be distinguishable", and the only fix that clears it without an
   underline is making the link near-white - which puts EveryCall's byline
   brighter than the client's own copyright line beside it. One flag on our
   own credit is the cheaper trade. */
.footer-bottom a{color:var(--muted);text-decoration:none}
/* 58.126 Why choose us cards, and the footer at five columns on a wide screen. */
.why-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:18px}
/* 70.5 Before & after. */
/* 71.1 The Compare button in the demo bar, and the full-screen view it opens. */
.demo-compare{appearance:none;cursor:pointer;background:transparent;border:1px solid #3d5169;border-radius:4px;color:#e8eef4;
font-family:var(--font-body);font-stretch:normal;font-size:calc(16px * 0.88);letter-spacing:.06em;text-transform:uppercase;line-height:1;padding:12px 14px;white-space:nowrap}
.demo-compare:hover{border-color:#4fa8e0;color:#fff}
.demo-compare .dc-short{display:none}
@media(max-width:1599px){.demo-compare .dc-long{display:none}.demo-compare .dc-short{display:inline}}
@media(max-width:700px){.demo-compare{padding:11px 10px;font-size:calc(14px * 0.88)}}
.is-shot .demo-compare,.is-shot .ba-modal{display:none!important}
.ba-modal{position:fixed;inset:0;z-index:300;background:rgba(6,10,14,.9);display:flex;align-items:center;justify-content:center;padding:20px}
.ba-modal[hidden]{display:none}
.ba-box{width:min(1240px,calc((100vh - 150px) * 1.6),100%)}
.ba-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px;margin-bottom:14px;color:#e8eef4}
.ba-title{margin:0;font-family:var(--font-display,inherit);font-size:calc(24px * 0.88);line-height:1.2;color:#fff}
.ba-sub{margin:4px 0 0;color:#9fb0c0;font-size:calc(14px * 0.88)}
.ba-x{appearance:none;background:none;border:0;color:#cbd5e1;font-size:34px;line-height:1;cursor:pointer;padding:0 4px}
.ba-x:hover{color:#fff}
.ba-stage{position:relative;aspect-ratio:16/10;overflow:hidden;border-radius:12px;border:1px solid var(--border);background:#fff;box-shadow:0 18px 50px rgba(0,0,0,.28)}
.ba-after{position:absolute;inset:0;overflow:hidden}
.ba-after iframe{position:absolute;left:0;top:0;width:1400px;height:875px;border:0;transform-origin:0 0;pointer-events:none;background:#fff}
.ba-before{position:absolute;inset:0;clip-path:inset(0 50% 0 0)}
.ba-before img{width:100%;height:100%;object-fit:cover;object-position:top center;display:block}
.ba-line{position:absolute;top:0;bottom:0;left:50%;width:3px;margin-left:-1.5px;background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.25);pointer-events:none}
.ba-knob{position:absolute;top:50%;left:50%;width:46px;height:46px;margin:-23px 0 0 -23px;border-radius:50%;background:var(--accent);color:#fff;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 14px rgba(0,0,0,.35)}
.ba-tag{position:absolute;bottom:14px;padding:6px 12px;border-radius:4px;background:rgba(0,0,0,.66);color:#fff;font-size:calc(13px * 0.88);letter-spacing:.04em;pointer-events:none}
.ba-tag--l{left:14px}.ba-tag--r{right:14px}
.ba-range{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:ew-resize;-webkit-appearance:none;appearance:none}
@media(max-width:620px){.ba-tag{font-size:calc(11px * 0.88);bottom:8px}.ba-tag--l{left:8px}.ba-tag--r{right:8px}.ba-knob{width:38px;height:38px;margin:-19px 0 0 -19px}}
/* 70.4 Advice: the list of articles and the article page. */
.adv-list{display:grid;gap:14px;margin-top:28px}
.adv-card{display:flex;flex-direction:column;gap:6px;background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:20px 22px;text-decoration:none;color:inherit;transition:border-color .2s}
.adv-card:hover{border-color:var(--accent)}
.adv-t{font-family:var(--font-display,inherit);font-size:calc(20px * 0.88);line-height:1.25;color:var(--text,inherit)}
.adv-x{color:var(--off)}
.adv-d,.adv-when{font-size:calc(14px * 0.88);color:var(--muted,var(--off))}
.adv-when{margin:-4px 0 26px}
.adv-body h2,.adv-body h3{margin-top:34px}
.adv-body ul{margin-bottom:20px}
.adv-body p{max-width:70ch}
.eyebrow a{color:inherit;text-decoration:none}
.why-card{background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:24px 24px 22px}
.why-card .pnum{margin-bottom:12px}
.why-card .pnum.pnum--c{width:44px;height:44px;font-size:calc(19px * 0.88);margin-bottom:16px}   /* 58.218 numbers in the accent circle, as on the homepage steps */
.why-card h3{margin:0 0 8px}
.why-card p{margin:0;color:var(--off)}
@media(min-width:1100px){.footer-inner{grid-template-columns:minmax(220px,1.25fr) repeat(3,minmax(0,1fr)) minmax(230px,1.25fr)}}
/* 58.125 Privacy and terms, after the copyright line. */
.legal-links{white-space:nowrap}
/* 70.3 EN / FR, above privacy and terms. Google's translate bar, popups and highlights hidden. */
/* 73.5 The language button and its menu. The button reads like the links
   beside it - same colour, no border, a small arrow; the menu opens above
   it in the site's own card colour, text and accent. */
.foot-row{display:inline-flex;align-items:center;gap:18px;flex-wrap:wrap;justify-content:inherit}
.lang-pick{position:relative;display:inline-flex}
.lang-btn{appearance:none;background:none;border:0;padding:2px 0;margin:0;cursor:pointer;
color:var(--muted);font:inherit;display:inline-flex;align-items:center;gap:5px}
.lang-btn:hover,.lang-btn[aria-expanded="true"]{color:var(--text)}
.lang-btn svg{transition:transform .15s}
.lang-btn[aria-expanded="true"] svg{transform:rotate(180deg)}
.lang-menu{position:absolute;bottom:calc(100% + 10px);right:0;z-index:60;min-width:170px;
display:flex;flex-direction:column;padding:6px;background:var(--surface);border:1px solid var(--border);
border-radius:var(--radius,8px);box-shadow:0 12px 32px rgba(0,0,0,.28);text-align:left}
.lang-menu[hidden]{display:none}
.footer-bottom .lang-menu a,.lang-menu a{color:var(--text);text-decoration:none;padding:8px 12px;border-radius:5px;white-space:nowrap;line-height:1.3}
.footer-bottom .lang-menu a:hover,.lang-menu a:hover,.lang-menu a:focus-visible{background:color-mix(in srgb,var(--accent) 16%,transparent);color:var(--text);outline:none}
.footer-bottom .lang-menu a.on,.lang-menu a.on{color:var(--accent);font-weight:600}
.lang-menu a{display:flex;align-items:baseline;gap:14px;justify-content:space-between}
.lang-menu .lm-en{color:var(--muted);font-size:.85em;font-weight:400}
.lang-menu{min-width:230px}
@media(max-width:620px){.lang-menu{right:auto;left:50%;transform:translateX(-50%)}}
/* 73.4 The languages he speaks, in his About section. */
.about-langs{display:flex;align-items:center;gap:9px;font-weight:600;margin:4px 0 0}
.about-langs svg{color:var(--accent);flex:0 0 auto}
.goog-te-banner-frame,iframe.skiptranslate,.skiptranslate iframe,#goog-gt-tt,.goog-te-balloon-frame,.goog-tooltip,.VIpgJd-ZVi9od-ORHb-OEVmcd,.VIpgJd-ZVi9od-aZ2wEe-wOHMyf,.VIpgJd-ZVi9od-l4eHX-hSRGPd{display:none!important}
body{top:0!important}
.goog-text-highlight{background:none!important;box-shadow:none!important}
.consent-note a{color:inherit;text-decoration:underline}
.legal h2{font-size:clamp(20px,2.2vw,26px);margin:40px 0 12px}
.legal p,.legal li{max-width:70ch}
.legal-date{color:var(--muted);margin-top:-6px}
/* Phones: the social icons get a row of their own above the copyright.
   Beside it they wrapped under the second line of the name and sat in
   the lower corner, where the call bar and the chat launcher cover them. */
@media(max-width:620px){.footer-bottom .soc-row{order:-1;flex-basis:100%}}
/* 58.128 Copyright left, social icons in the middle, privacy and terms on
   the right. Three columns on anything wider than a phone; on a phone they
   stack and centre, icons first. */
@media(min-width:621px){
  .footer-bottom{display:grid;grid-template-columns:1fr auto 1fr;align-items:center}
  .footer-bottom .soc-row{justify-content:center}
  .foot-right{text-align:right;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
}
@media(max-width:620px){
  .footer-bottom{justify-content:center;text-align:center}
  .footer-bottom .soc-row{justify-content:center}
  .foot-right{display:flex;flex-direction:column;align-items:center;gap:4px;flex-basis:100%}
}
.soc-row:empty{display:none}
@media(min-width:621px){.soc-row:empty{display:block}}
/* ── demo chat bubble ──────────────────────────────────────────────────
   A <details>, so open/close costs no script. summary is the launcher,
   the panel sits above it. Accent-coloured so it reads as part of the
   client's site rather than as EveryCall chrome — unlike the demo flag
   and preview band, this is standing in for one of THEIR features. */
.dchat{position:fixed;right:20px;bottom:20px;z-index:120}
.dchat>summary{list-style:none;cursor:pointer;width:56px;height:56px;border-radius:50%;
background:var(--accent);color:var(--bg);display:flex;align-items:center;justify-content:center;
box-shadow:0 6px 20px rgba(0,0,0,.38);transition:transform .15s,box-shadow .15s}
.dchat>summary::-webkit-details-marker{display:none}
.dchat>summary:hover{transform:translateY(-2px);box-shadow:0 9px 26px rgba(0,0,0,.46)}
.dchat>summary svg{width:28px;height:28px;fill:currentColor}
/* The dots have to knock THROUGH the speech bubble, not sit on it —
   inheriting currentColor painted them the same colour as the shape
   underneath and they vanished. Accent = the launcher circle behind. */
.dchat>summary svg circle{fill:var(--accent)}
.dchat[open]>summary{transform:none}
.dchat-panel{position:absolute;right:0;bottom:70px;width:288px;max-width:calc(100vw - 40px);
background:var(--surface);border:1px solid var(--border);border-radius:10px;padding:18px;
box-shadow:0 14px 40px rgba(0,0,0,.45)}
.dchat-h{margin:0 0 8px;font-family:var(--font-display);font-size:19px;letter-spacing:.05em;
color:var(--text)}
.dchat-b{margin:0 0 10px;font-size:14.5px;line-height:1.55;color:var(--off)}
.dchat-n{margin:0;font-size:12.5px;line-height:1.5;color:var(--placeholder)}
.dchat-cta{display:block;text-align:center;margin-top:14px}
/* Screenshots and the tablet/phone preview frames are of the CLIENT's site,
   so EveryCall's own furniture comes off — same as the flag and the band. */
.is-shot .dchat{display:none!important}
/* 57.53 ?shot=1 hides the REAL chat bubble too, not just the builder's
   stand-in. GoHighLevel's widget mounts as a custom element on some
   versions and a plain div with a generated id on others, with the
   button itself inside a shadow root - so the host element is hidden by
   every name it goes by. Without this every capture for the homepage
   rail had an orange bubble sitting in the corner of the phone. */
.is-shot chat-widget,.is-shot .chat-widget,.is-shot #lc_text-widget,
.is-shot [id^="lc_text-widget"],.is-shot [class*="leadconnector"],
.is-shot iframe[src*="leadconnector"],.is-shot iframe[src*="chat-widget"]{display:none!important}
/* EveryCall's navy and blue, not var(--dark2) and var(--accent).

   This ribbon is EveryCall's name on someone else's website, and it was
   taking the client's palette to say so - which made it read as part of
   the site rather than as a mark on it. It matches the bar along the top
   now, which is the same voice.

   Deliberately the quietest of the four EveryCall things on the page.
   It is a label, not a call to action, and the page has exactly one
   thing that should be pressed. Grey text, and only the wordmark in
   blue. */
.demo-flag{position:fixed;left:0;bottom:0;z-index:120;background:#161d26;
border-top:1px solid #223044;border-right:1px solid #223044;border-radius:0 6px 0 0;
padding:8px 16px;font-size:12.5px;letter-spacing:.1em;text-transform:uppercase;color:#8a97a6}
.demo-flag a{color:#4fa8e0;text-decoration:none}
.demo-flag a:hover{color:#7cc4f0}
/* Orange, and fixed rather than taken from the theme. It sits on EveryCall's
   own dark band rather than on the page, which is what keeps it from reading
   as one of the client's buttons - the separation comes from the band, not
   from the colour. Metrics match the site's .btn so the whole strip reads as
   one considered thing. */
/* A card, centred in its own right rather than relying on whatever
   column it happens to sit in - which is what left it drifting off
   centre on the booked page. Used by both confirmation pages, so both
   get the same treatment: the message is a distinct thing being said
   after the event, and a panel says that better than loose text on a
   band. */
.claim-done{text-align:center;max-width:640px;margin:0 auto;
background:var(--bg);border:1px solid var(--border-soft);
border-radius:12px;padding:38px 34px}
@media(max-width:560px){.claim-done{padding:28px 20px}}
.claim-done-h{margin:0 0 10px;font-family:var(--font-display);font-size:calc(26px * 0.88);
letter-spacing:.02em;color:var(--text)}
.claim-done-b{margin:0 auto;max-width:52ch;font-size:16px;line-height:1.6;color:var(--off)}
.claim-done-cta{margin-top:22px;font-size:17px;padding:14px 26px}
/* Filled brand blue: the one thing on the page that should be pressed.

   Same two colours as the tour button, different weight, on purpose.
   Claim is the conversion and the tour is optional help - make them
   identical and the thing you want pressed looks exactly like the thing
   you do not mind him ignoring. Filled beats outlined; the tour button
   is navy with a blue keyline, this one is the blue itself. */
.claim-btn{display:inline-block;background:#4fa8e0;color:#0f1720;text-decoration:none;
font-family:var(--font-body);font-stretch:normal;font-size:calc(16px * 0.88);letter-spacing:.08em;
text-transform:uppercase;line-height:1;border-radius:4px;padding:12px 22px;
white-space:nowrap;transition:background .2s,transform .15s}
.claim-btn:hover{background:#7cc4f0;color:#0f1720;transform:translateY(-2px)}
/* One of the two shows at any width, never both. The preview band is
   hidden under 700px — which is where the demo actually gets opened, so
   below that the ribbon carries the button instead. */
.claim-flag{display:none;margin-left:12px}
.demo-flag{display:flex;align-items:center}
/* A flex container drops the whitespace-only edges of its text nodes, so
   "built by " lost its trailing space and ran into the link. Put it back as
   a margin rather than an &nbsp;, and only on the EveryCall link - the claim
   button after it carries its own spacing already. */
.demo-flag>a:not(.claim-flag){margin-left:.32em}
/* Device preview band — same shape as the builder's preview: a bar across the
   top, the page below it in an iframe whose WIDTH changes. Width alone is
   enough; media queries key off the iframe's viewport. A narrowed div would
   not work, because a container is not a viewport. */
/* Hardcoded EveryCall colours, deliberately NOT the theme variables. The
   band has to read as something wrapped around the site rather than part
   of it, and a band that recolours itself to match each demo reads as
   part of it. Same reasoning as the claim button below. */
.demo-bar{position:fixed;top:0;left:0;right:0;z-index:150;height:64px;
display:flex;align-items:center;justify-content:space-between;gap:16px;padding:0 18px;
/* #161d26 exactly, which is everycall.co's own background. It was
   #0f1720 - close enough to look right on its own, and visibly not the
   same colour once the ribbon below it was corrected. */
background:#161d26;border-bottom:1px solid #223044}
/* 124px, not 110. DESKTOP is the longest of the three and at 16px
   uppercase with .08em tracking it needs about 106px including padding —
   so it was overflowing its track and sitting off-centre while TABLET and
   PHONE, which fit, looked fine. The text-indent below corrects for
   letter-spacing adding its gap after the last character too. */
.demo-devices{display:grid;grid-template-columns:repeat(3,124px);gap:6px}
/* Same metrics as the site's own .btn so nothing in this band looks like a
   different widget from a different program. Colours stay EveryCall's. */
.demo-dev{appearance:none;cursor:pointer;background:transparent;border:1px solid #2a3a4c;
border-radius:4px;color:#8fa0b0;text-align:center;font-family:var(--font-body);font-stretch:normal;
font-size:calc(16px * 0.88);letter-spacing:.08em;text-indent:.08em;text-transform:uppercase;line-height:1;padding:12px 8px;
transition:border-color .15s,color .15s}
/* Selected uses the same treatment as hover rather than an accent outline -
   a bright border here competed with the claim button, which is the only
   thing in this band that should be pulling the eye. */
.demo-dev:hover,.demo-dev.is-on{color:#e8eef4;border-color:#3d5169}
.demo-right{display:flex;align-items:center;gap:10px;flex:1 1 0;min-width:0;justify-content:flex-end}
/* Swatches sit with the device buttons: both are things EveryCall put in
   the bar for him to try, neither is part of his website. */
/* No "Colours" label. Four coloured circles in a preview bar do not need
   telling apart from anything, and the word was the only thing in the bar
   explaining a control rather than being one. margin-left goes with it -
   these are the leftmost thing in the bar now, not an addition to the
   right-hand group. */
/* flex:1 on both outer groups, so the device buttons sit in the middle
   of the WINDOW rather than in the middle of whatever is left over.
   space-between alone centres the middle child only when the two outer
   groups happen to be the same width, and they are not: four circles on
   the left against a 300px claim button on the right pushed the trio
   well left of centre. */
.demo-swatch{display:flex;align-items:center;gap:7px;flex:1 1 0;min-width:0}
.dsw{width:22px;height:22px;border-radius:50%;border:0;padding:0;cursor:pointer;
opacity:.65;transition:opacity .18s,transform .18s}
.dsw:hover{opacity:1;box-shadow:0 0 0 2px rgba(203,213,225,.35)}   /* 71.6 a ring, not a scale - scaling the dot scaled its hover text with it */
.dsw.on{opacity:1;outline:2px solid #cbd5e1;outline-offset:2px}
/* Hidden under 900px, but visibility:hidden rather than display:none so
   the left group keeps its width and the device buttons stay centred
   instead of jumping left the moment the swatches go. */
@media(max-width:900px){.demo-swatch{visibility:hidden}}
.demo-page{font-size:12.5px;color:#6b7c8c;letter-spacing:.06em}
/* 73.3 With the bar closed, the Demo site ribbon bottom left shows its
   Claim This Website button - at every width, the ribbon included on a
   phone where it is otherwise hidden - and a small Show bar after it. */
.demo-shut .demo-flag{display:flex!important}
.demo-shut .claim-flag{display:inline-block}
.demo-flag a.claim-flag{color:#0f1720}.demo-flag a.claim-flag:hover{color:#0f1720}
.demo-reopen{position:static;appearance:none;background:none;border:0;cursor:pointer;color:#8a97a6;
font:inherit;letter-spacing:.1em;text-transform:uppercase;margin-left:12px;padding:4px 2px;white-space:nowrap}
.demo-reopen:hover{color:#e8eef4}
/* On a phone the ribbon has room for the two buttons and nothing else. */
@media(max-width:700px){
  .demo-shut .demo-flag{font-size:0;padding:7px 8px}
  .demo-shut .demo-flag>a:not(.claim-flag){display:none}
  .demo-shut .demo-flag .claim-flag{font-size:12.5px;margin-left:0}
  .demo-shut .demo-reopen{font-size:11.5px;margin-left:10px}
}

.is-shot .demo-reopen{display:none!important}
.demo-close{appearance:none;background:none;border:0;cursor:pointer;color:#8fa0b0;
font-size:22px;line-height:1;padding:0 4px}
.demo-close:hover{color:#e8eef4}
/* 71.5 The bar's hover text in EveryCall's own panel, the way EveryLocal
   does its hours: card colour, hairline border, rounded, a shadow and a
   small arrow up at the button - not the browser's yellow box. Mouse
   only (a tap on a phone would leave it stuck open), after a short
   pause so it doesn't flash as the pointer crosses the bar. Centred
   under the device buttons, held to the left edge under the colour
   dots and to the right edge under Claim and the X, so none runs off
   the screen. */
@media(hover:hover){
  .demo-bar [data-tip]{position:relative}
  .demo-bar [data-tip]::after,.demo-bar [data-tip]::before{position:absolute;top:calc(100% + 12px);opacity:0;visibility:hidden;
    pointer-events:none;transition:opacity .15s ease .35s,visibility 0s linear .5s;z-index:160}
  .demo-bar [data-tip]::after{content:attr(data-tip);left:50%;transform:translateX(-50%);width:max-content;max-width:260px;
    padding:10px 13px 11px;background:#1c2632;border:1px solid #2f4157;border-radius:8px;box-shadow:0 16px 34px rgba(0,0,0,.5);
    color:#cbd5e1;font-family:var(--font-body);font-stretch:normal;font-size:13.5px;line-height:1.5;letter-spacing:0;
    text-transform:none;text-indent:0;text-align:left;white-space:normal;font-weight:400}
  .demo-bar [data-tip]::before{content:"";left:50%;margin-left:-7px;top:calc(100% - 2px);border:7px solid transparent;border-bottom-color:#2f4157}
  .demo-bar [data-tip]:hover::after,.demo-bar [data-tip]:hover::before,
  .demo-bar [data-tip]:focus-visible::after,.demo-bar [data-tip]:focus-visible::before{opacity:1;visibility:visible;transition-delay:.35s,0s}
  .demo-swatch [data-tip]::after{left:-6px;transform:none}
  .demo-right [data-tip]::after{left:auto;right:-6px;transform:none}
}
/* Every anchor target clears the sticky header — and on a demo, the band
   above it as well. Without this the browser scrolls the section to the
   very top of the window, which is where the header already is, so the
   heading lands underneath it. Services, Areas and Reviews seemed fine
   only because those bands open with generous padding; About and FAQ
   start on their heading and it disappeared.

   One number, adjusted in one place when the band is present, rather
   than a value per section that drifts the first time the header
   changes height. */
.band[id],.quote-card,[id="process"],[id="faq"]{scroll-margin-top:120px}
.has-demobar .band[id],.has-demobar .quote-card{scroll-margin-top:188px}

/* The band is fixed, so the page moves down and the sticky header sits under it. */
.has-demobar body{padding-top:64px}
.has-demobar .site-header{top:64px}
.demo-stage{position:fixed;inset:64px 0 0 0;z-index:140;background:#0c1014;
display:flex;justify-content:center;overflow:auto}
.demo-stage[hidden]{display:none}
.demo-frame{border:0;height:100%;background:#fff;transition:width .2s;
box-shadow:0 0 60px rgba(0,0,0,.5)}
/* On a real phone the switcher is pointless - you're already looking at it -
   but the BAND still matters, because a phone is where the demo actually
   gets opened. So the device pills and the stage go, and the band stays with
   just the label and the claim button. The corner ribbon goes at the same
   width: it would be saying the same thing twice, and it overlapped the hero
   and fought the client's call bar for the bottom of the screen.
   Cutoff sits below the widths you'd use in DevTools' device toolbar (780 etc)
   so the switcher survives responsive testing, but above a real phone. */
@media(max-width:700px){
  .demo-devices,.demo-page,.demo-stage{display:none}
  .demo-flag{display:none}
  .demo-bar{height:60px;padding:0 12px;gap:10px}
  .claim-btn{padding:11px 16px;font-size:calc(14px * 0.88)}
  .has-demobar body{padding-top:60px}
  .has-demobar .site-header{top:60px}
}
/* Screenshot mode — see ?shot=1 */
.is-shot .demo-flag,.is-shot .call-bar,.is-shot .demo-bar,.is-shot .demo-stage{display:none!important}
.is-shot body{padding-top:0!important}
.is-shot .site-header{top:0!important}
.is-shot body{padding-bottom:0!important}
.call-bar{display:none}
/* 58.123 / 58.124 Every quote form - the hero's, the ones on service,
   area and contact pages - was stretching to whatever width it was given:
   four short boxes 900px wide on a tablet, or on a page where the form
   sits in the main column. Held to 600px and left-aligned with the text
   above it. Beside the hero copy on a desktop the column is narrower than
   that anyway, so nothing changes there. A phone is under 601px and keeps
   the full width, which is what it wants. */
@media(min-width:601px){
.quote-card{max-width:600px}
}
@media(max-width:900px){
.hero-grid{grid-template-columns:minmax(0,1fr)}
.hero-btns{grid-auto-flow:row;grid-template-columns:minmax(0,1fr);width:100%;max-width:none}.hero-btns .btn{min-width:0}
.hero-svc{margin-top:24px;padding-top:20px}
.hero-svc-list{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 18px}
.hero-svc-list a,.hero-svc-list span{font-size:calc(16px * 0.88)}
.hero--panel{grid-template-columns:1fr}
.hero-panel-copy{padding:50px 28px}
.svc-list{grid-template-columns:1fr}
.areas-split{grid-template-columns:1fr}
.mapwrap iframe{height:280px}
.svc-grid,.area-grid,.rev-grid{grid-template-columns:repeat(2,1fr)}
.rev-wall{grid-template-columns:repeat(2,minmax(0,1fr))}
.process{grid-template-columns:repeat(2,1fr)}
.about-grid{grid-template-columns:1fr}.about-photo{max-width:300px}
.about-grid--wide .about-photo,.about-grid--top .about-photo{max-width:none}
.footer-inner{grid-template-columns:1fr 1fr}
.nav a:not(.btn):not(.nav-phone){display:none}
.nav-drop{display:none}
/* Every link is hidden here, and an empty flex:1 item still claims its
   share - which would hold the quote button in from the right edge.
   Collapse it so the header reads logo-left, button-right as before. */
.nav{flex:0 0 auto;gap:0}
.nav-burger{display:inline-flex}
.nav-act{gap:10px}
.hdr-phone{margin-right:10px}
.logo{font-size:calc(calc(30px * .86) * 0.88)}}
/* 58.150 The same collapse, on a wider screen, when the menu does not fit:
   a long business name, a long menu and the header phone together can run
   into each other well above 900px. A script in the footer measures and
   sets nav-tight only when they actually collide. */
/* 58.339 First step: the links close up - less space between them and the
   header's other parts, a touch less letter spacing - which is usually
   enough to keep the menu showing. */
html.nav-snug .site-header .wrap{gap:12px}
html.nav-snug .nav{gap:16px}
html.nav-snug .nav a:not(.btn){letter-spacing:.02em}
html.nav-snug .nav-act{gap:10px}
html.nav-snug .nav-act .btn{padding-left:18px;padding-right:18px}
html.nav-tight .nav a:not(.btn):not(.nav-phone){display:none}
html.nav-tight .nav-drop{display:none}
html.nav-tight .nav{flex:0 0 auto;gap:0}
html.nav-tight .nav-burger{display:inline-flex}
html.nav-tight .nav-act{gap:10px}
html.nav-tight .hdr-phone{margin-right:10px}
/* 58.150 Narrow tablets: the number steps out before the header runs off the side. The call bar takes over at 700. */
@media(max-width:760px){.nav-act .hdr-phone{display:none}}
@media(max-width:620px){
body{font-size:calc(16px * 0.88);padding-bottom:66px}
.band{padding:50px 20px}.hero{padding:50px 20px}
.hero--centred{padding:50px 20px}
.hero-panel-copy{padding:50px 22px}
.svc-grid,.area-grid,.area-grid--tight,.rev-grid,.process{grid-template-columns:1fr}
.rev-wall{grid-template-columns:minmax(0,1fr)}
.vt-grid{grid-template-columns:minmax(0,1fr)}
.mapwrap iframe{height:240px}
.footer-inner{grid-template-columns:1fr}
.nav .nav-phone,.nav>a.nav-phone,.nav-act .hdr-phone{display:none}  /* 55.30 the second selector is the one that works: .nav>a:not(.btn) above outranked the first, so the number never hid and pushed the header past the screen edge */
.logo{font-size:calc(calc(30px * .62) * 0.88)}
.logo--img img{height:42px;max-width:148px}
.logo-full{display:none}
.logo-short{display:inline}
.logo--mark .logo-badge{width:32px;height:32px;font-size:15px;border-radius:5px}
.logo--mark{gap:9px}
.site-header .wrap{gap:10px;padding:11px 0;min-width:0;min-height:64px}
.site-header .btn{font-size:calc(12.5px * 0.88);padding:9px 12px;letter-spacing:.05em;white-space:nowrap}
.trust-item{font-size:calc(12.5px * 0.88);padding:0 18px}
.demo-flag{bottom:66px;font-size:11.5px;padding:6px 12px}
/* The call bar is fixed full-width along the bottom on a phone, so the
   bubble has to clear it. Sits level with the demo flag — flag left,
   bubble right, both above the bar. */
.dchat{right:14px;bottom:66px}
.dchat>summary{width:50px;height:50px}
.dchat>summary svg{width:25px;height:25px}
.dchat-panel{bottom:62px;width:262px}
.claim-flag{display:inline-block;margin-left:10px;padding:8px 14px;font-size:13px}
.call-bar{display:flex;align-items:center;justify-content:center;gap:10px;position:fixed;
left:0;right:0;bottom:0;z-index:100;background:var(--cta);color:var(--on-cta);text-decoration:none;
padding:15px 20px;font-size:calc(18px * 0.88);letter-spacing:.06em;text-transform:uppercase;
box-shadow:0 -6px 24px rgba(0,0,0,.4)}
/* Two children on one line, and only one of them is allowed to give way.
   "CALL DEVLIN DRYWALL (604) 774-8949" at 17px uppercase runs past a 380px
   phone and wrapped BOTH parts onto two lines, splitting the number across
   a line break. The number is the whole point of the bar, so it is pinned
   and the business name truncates instead - which also survives a name far
   longer than this one. */
.call-bar span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.call-bar strong{color:var(--on-cta);font-weight:500;flex:0 0 auto;white-space:nowrap}}
@media(max-width:430px){
/* Below this the two parts stop fitting at full size however hard the name
   truncates, so the whole bar steps down rather than eating the name. */
.call-bar{font-size:calc(16px * 0.88);letter-spacing:.03em;padding:14px 14px;gap:8px}}
/* 55.35 Motion. Nothing here hides anything on its own - the classes
   only exist once the script at the foot of the page has added them, to
   elements below the fold, so a page whose script never runs is simply
   a page with everything showing. */
.tk-rv{opacity:0;transform:translateY(22px);transition:opacity .7s ease,transform .7s cubic-bezier(.2,.7,.2,1)}
.tk-rvc{opacity:0;transform:translateX(-70px);transition:opacity 1s ease,transform 1.1s cubic-bezier(.16,.8,.24,1);
transition-delay:calc(var(--tk-i,0) * 180ms)}
.tk-rv.tk-in,.tk-rvc.tk-in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.tk-rv,.tk-rvc{opacity:1!important;transform:none!important;transition:none!important}}
@media print{.tk-rv,.tk-rvc{opacity:1!important;transform:none!important}}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}*{transition-duration:.01ms!important}
.trust-track{animation:none;flex-wrap:wrap;width:auto;justify-content:center}
.trust-item[aria-hidden]{display:none}}


/* ── LIGHT-THEME OVERRIDES ──────────────────────────────────────
   Last on purpose. These undo rules defined above them, and CSS
   settles a tie on document order - written earlier, as they were,
   every one of them lost to the rule it was meant to replace and
   the hero list stayed black on a dark scrim. */
/* Emitted on EVERY build, not just a light one, and hung off a class on
   <html> that the build sets and the demo swatch row retoggles.

   They used to be written only when the build itself was light, which
   was true of the page as delivered and false the moment anyone pressed
   a swatch. A dark build offers two light palettes in that row; clicking
   one reassigned every colour token and left these rules unwritten - so
   the headline and the lede went near-black over a photograph that is
   still sitting under a dark scrim, and the hero read as empty. Two of
   the five dots on every dark demo did that.

   Scoped rather than duplicated: one block, switched on and off by the
   class, which is also why it stays last in the file. */
/* The hero keeps light text on a light theme - but only the heroes that
   have a scrim to read against.

   Everything in it takes its colour from the page - which is right for
   the rest of the site and wrong here, because the hero lays a dark
   scrim over a photograph so a white headline can be read against it.
   On a dark theme the two agree by accident; on a light one the text
   goes near-black and disappears into the scrim.

   .hero--scrim rather than .hero, because two of the three layouts do
   not have one. The panel hero puts its copy on a solid --surface block
   BESIDE the photograph, and a hero with no photo paints a gradient of
   the theme's own colours; force white text on either and it is white
   on near-white. That is the same mistake in the opposite direction as
   the one this block exists to fix.

   Fixed values rather than tokens, since what these have to work
   against is the scrim, not the page. The dim slider changes how dark
   that scrim is, not what colour the words are. */
html.tk-light .hero--scrim,html.tk-light .hero--scrim h1,
html.tk-light .hero--scrim .lede,html.tk-light .hero--scrim .hero-lede,
html.tk-light .hero--scrim .hero-svc-h,
html.tk-light .hero--scrim .hero-svc-list a,
html.tk-light .hero--scrim .hero-svc-list span{color:#f4f7fa}
html.tk-light .hero--scrim .lede,html.tk-light .hero--scrim .hero-lede{color:#dde5ec}
html.tk-light .hero--scrim .hero-svc{border-top-color:rgba(255,255,255,.16)}
html.tk-light .hero--scrim .hero-svc-list a:hover{color:#ffffff}
/* Everything in the hero that takes the accent takes the lifted one.
   The ticks and the second line of the headline are the only coloured
   things up there, and both were his dark blue on a dark scrim. */
html.tk-light .hero--scrim .hero-svc-list svg{color:var(--hero-acc)}
html.tk-light .hero--scrim h1 span{color:var(--hero-hl)}   /* 58.226 a picked headline colour wins on a light build too */
/* The ghost button outlines itself in the page's border colour, which
   is a dark hairline on a light theme and vanishes over the scrim. */
/* Anything sitting ON the scrim needs light text, and on a light build
   the theme's own colours are the opposite of that. The homepage hero
   was already handled; the service and area page heroes use .band--shot
   and were not - so the first line of the heading was near-black text
   on a near-black scrim and had effectively vanished. */
/* The card off pure white. --surface on a light build is the page mixed
   55% toward white, so against the darkened hero it read as a light
   source rather than a panel. The page's own background is a shade
   down and gives the headline its position back without the form
   losing any of its prominence. */
/* Same story: on a light build the card sits a shade off white so it
   reads as a panel rather than a light source, but --bg on a dark theme
   is nearly black, so crossing families turned the form into a hole.
   The switcher sets --quote-bg; this is the light build's default. */
html.tk-light .hero .quote-card{background:var(--quote-bg,var(--bg))}
html .hero .quote-card,html.tk-light .hero .quote-card{background:rgba(255,255,255,0.8);-webkit-backdrop-filter:blur(14px) saturate(1.2);backdrop-filter:blur(14px) saturate(1.2);border-color:transparent;--text:#1b1f24;--off:#3a4149;--label:#4a525c;--muted:#5a626c;--placeholder:#8a929c;--border:rgba(20,28,38,.18);--dark2:#f4f6f8}html .hero .quote-card .quote-sub{color:#1b1f24}html .hero .quote-card .quote-alt{color:#5a626c}html .hero .quote-card .quote-alt a,html .hero .quote-card .quote-alt strong{color:#1b1f24}html .hero .qform input[type=text],html .hero .qform input[type=tel],html .hero .qform input[type=email],html .hero .qform textarea{background:#f4f6f8;color:#1b1f24;border-color:rgba(20,28,38,.18)}html .hero .qform input:focus,html .hero .qform textarea:focus{background:#fff;border-color:var(--accent)}html .hero .quote-card ::placeholder{color:#b9bfc6;opacity:1}html .hero .qform p.consent-note{color:#5a626c;opacity:1}html .hero .qform .consent-row{color:#1b1f24}
html.tk-light .band--shot h1{color:#ffffff}
html.tk-light .band--shot .lede{color:rgba(255,255,255,.86)}
html.tk-light .band--shot .eyebrow{color:var(--hero-acc)}
html.tk-light .band--shot h1 span{color:var(--hero-acc)}
html.tk-light .band--shot .btn--ghost{color:#f4f7fa;border-color:rgba(255,255,255,.45)}
html.tk-light .band--shot .btn--ghost:hover{background:rgba(255,255,255,.12);border-color:#ffffff;color:#ffffff}
html.tk-light .hero--scrim .btn--ghost{color:#f4f7fa;border-color:rgba(255,255,255,.45)}
html.tk-light .hero--scrim .btn--ghost:hover{background:rgba(255,255,255,.12);border-color:#ffffff;color:#ffffff}
/* Sticky header. The base rule is rgba(0,0,0,.55), written when every
   theme was dark. On a light build the nav links are --off, which is
   near-black, so they sat on a black-tinted bar: barely legible over
   the hero photo at the top of the page, and a grey slab across white
   sections once scrolled. Flipped to the theme's own surface so the
   header belongs to the site under it. Built from the surface hex
   rather than a flat white, so linen's warm paper stays warm. */
html.tk-light .site-header{background:var(--header-bg,rgba(255,255,255,.88))}
/* 58.122 Header links on a light build. They were --off, and on frost
   with his own colours in they came out a pale grey (and the number a
   pale cream) on a white bar. Pulled toward near-black whatever --off
   and --text are, so they always read; a dark --off barely moves. Only
   with the header on Automatic - the other header colours set their
   own ink - and only while the page is light, so a swatch that turns
   the demo dark drops it with the tk-light class. */

/* The dropdown's shadow was tuned for a dark page and reads as a smudge
   on a light one. */
html.tk-light .nav-menu{box-shadow:0 12px 30px rgba(20,30,45,.16)}
