/* Served from this domain rather than Google's.
   Going to Google for type costs four round trips before a word can be drawn in
   the brand face: dns, connect, the css, then the font itself. On a throttled
   phone that finished around eight seconds, and because the headline is the
   largest thing on the page, the browser recorded the largest paint at the
   moment the real font swapped in. First paint looked fine; the score did not.
   Two files, latin only, variable weight, preloaded. Both are open licence. */
@font-face{font-family:"Plus Jakarta Sans";font-style:normal;font-weight:200 800;
  font-display:swap;src:url(../fonts/jakarta-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:"Inter";font-style:normal;font-weight:100 900;
  font-display:swap;src:url(../fonts/inter-latin.woff2) format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
/* ============================================================
   GENIES PLUMBING - edit brand colours + sizes here
   ============================================================ */
:root{
  /* Brand colours. Blake's palette, set 3 September 2026. Seven, plus the red
   for problem markers. Everything else on the site is a tint or shade of one
   of these. Do not add a colour.
       Buttons            #922AFE     Gold accents       #F1A006
       Hover, links       #285BFE     Aqua accents       #5EF5F5
       Headings, dark bg  #0B1125     White              #FFFFFF
       Wrench Red         #EF3130     (warnings, problem markers only)      */
  --ink:#0B1125;         /* Deep Outline Navy - hero, footer, headings */
  --navy:#0B1125;        /* Dark Navy - the guarantee section */
  --gold:#F1A006;        /* Gold - buttons, prices, numbers */
  --gold-dark:#F1A006;   /* Bright Yellow - hover state on gold */
  --aqua:#285BFE;        /* Genies Blue */
  --cyan:#5EF5F5;        /* Genie Skin Cyan - icons and ticks on dark */
  --magenta:#922AFE;     /* Genies Purple - small graphic accents */
  --blue-2:#285BFE;      /* Secondary Blue - gradients */
  --red:#EF3130;         /* Wrench Red - warnings, problem markers */
  --paper:#FFFFFF;
  --mist:#F1F3F9;        /* light section background */
  --line:#D9DEEC;        /* borders */
  --body:#4A4F72;        /* body text */
  --radius:16px;
  --wrap:1200px;
  --shadow:0 10px 30px rgba(11,17,37,.10);
  --shadow-lg:0 24px 60px rgba(11,17,37,.18);
  /* fonts: Google Fonts first, then the Mac/Windows system font if there is no internet */
  --f-head:"Plus Jakarta Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  --f-body:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;padding-top:var(--header-h,116px);font-family:var(--f-body);color:var(--body);background:var(--paper);font-size:16.5px;line-height:1.6;-webkit-font-smoothing:antialiased}
h1,h2,h3,h4,.font-head{font-family:var(--f-head);color:var(--ink);line-height:1.12;letter-spacing:-.02em;margin:0 0 .5em}
h1{font-size:clamp(1.72rem,5.2vw,3.7rem);font-weight:800}
@media(max-width:560px){
  /* Was 1.72rem, which is about 27px. The live site and both competitors run
     their phone headline around 40px, and next to them ours read timid. */
  h1{font-size:2.1rem;line-height:1.1;letter-spacing:-.02em}
  .hero h1{margin-bottom:.38em}
  h2{font-size:1.6rem;line-height:1.15}
}
h2{font-size:clamp(1.7rem,3.6vw,2.6rem);font-weight:800}
h3{font-size:1.2rem;font-weight:700}
p{margin:0 0 1em}
a{color:inherit;text-decoration:none}
img{max-width:100%;display:block}
.wrap{max-width:var(--wrap);margin:0 auto;padding:0 22px}
.section{padding:clamp(56px,7vw,96px) 0}
.eyebrow{display:inline-flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--aqua);margin-bottom:14px}
.eyebrow::before{content:"";width:22px;height:2px;background:var(--magenta);border-radius:2px}
.lead{font-size:1.08rem;max-width:62ch}
.center{text-align:center}
.center .lead{margin-left:auto;margin-right:auto}

/* buttons */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;padding:15px 26px;border-radius:999px;font-weight:700;font-size:1rem;border:2px solid transparent;cursor:pointer;transition:transform .15s ease,box-shadow .15s ease,background .15s ease;font-family:inherit}
.btn:hover{transform:translateY(-2px)}
/* Ask Blake. His face rather than a chat bubble icon, because people ring a
   person and not a company. It sits clear of the sticky call bar on a phone,
   and the little card above it slides in on its own after a few seconds so
   somebody who was not looking for it notices it anyway. */
.askwrap{position:fixed;right:18px;bottom:18px;z-index:70;
  display:flex;flex-direction:column;align-items:flex-end;gap:10px}
.askblake{display:flex;align-items:center;gap:11px;background:var(--ink);color:#fff;
  border:1px solid rgba(255,255,255,.16);border-radius:999px;padding:8px 16px 8px 8px;
  cursor:pointer;font-family:inherit;text-align:left;
  box-shadow:0 14px 36px rgba(4,10,28,.45);transition:transform .18s ease,box-shadow .18s ease}
.askblake:hover{transform:translateY(-2px);box-shadow:0 18px 44px rgba(4,10,28,.55)}
.askblake:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
.askblake-face{position:relative;flex:0 0 46px;width:46px;height:46px}
.askblake-face img{width:46px;height:46px;border-radius:50%;object-fit:cover;
  border:2px solid var(--gold)}
.askblake-live{position:absolute;right:0;bottom:1px;width:12px;height:12px;border-radius:50%;
  background:#25D366;border:2px solid var(--ink);box-shadow:0 0 0 3px rgba(37,211,102,.28)}
.askblake-txt b{display:block;font-family:var(--f-head);font-size:.95rem;line-height:1.15}
.askblake-txt small{display:block;font-size:.72rem;color:#9AA0C4;margin-top:1px}

.askbub{position:relative;max-width:236px;background:var(--paper);color:var(--ink);
  border:1px solid var(--line);border-radius:14px;padding:13px 30px 13px 15px;
  box-shadow:0 16px 40px rgba(4,10,28,.34);
  animation:askpop .34s cubic-bezier(.22,.9,.34,1.2) both}
.askbub b{display:block;font-family:var(--f-head);font-size:.95rem;margin-bottom:2px}
.askbub span{display:block;font-size:.82rem;line-height:1.45;color:var(--body)}
.askbub::after{content:"";position:absolute;right:26px;bottom:-7px;width:13px;height:13px;
  background:var(--paper);border-right:1px solid var(--line);border-bottom:1px solid var(--line);
  transform:rotate(45deg)}
.askbub-x{position:absolute;top:5px;right:6px;width:24px;height:24px;border:0;background:none;
  color:var(--body);font-size:19px;line-height:1;cursor:pointer;border-radius:50%}
.askbub-x:hover{background:var(--mist)}
@keyframes askpop{from{opacity:0;transform:translateY(9px) scale(.94)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){ .askbub{animation:none} }
@media(max-width:760px){
  .askwrap{right:12px;bottom:78px}
  .askblake{padding:7px 14px 7px 7px}
  .askblake-face,.askblake-face img{flex-basis:40px;width:40px;height:40px}
  .askbub{max-width:212px}
}

/* The booking page turns the buttons over: gold fill, purple edge. It is the
   page somebody lands on having already decided, so the button is the loudest
   thing on it. */
.book-page .btn-gold{background:var(--gold);color:var(--ink);border-color:var(--magenta);
  box-shadow:0 0 0 1px rgba(146,42,254,.30),0 0 20px rgba(241,160,6,.34),
             0 10px 26px rgba(4,10,28,.42)}
.book-page .btn-gold:hover{background:var(--gold-dark);border-color:#285BFE;
  box-shadow:0 0 0 1px rgba(146,42,254,.42),0 0 26px rgba(241,160,6,.48),
             0 12px 30px rgba(4,10,28,.48)}
.book-page .vid-cue{background:var(--gold);color:var(--ink);border-color:var(--magenta)}
.book-page .vid-cue svg{color:var(--magenta)}

/* Genies purple with a gold outline, same as the play button, so the buttons
   and the video read as one thing. The gold edge is what keeps it visible on
   the navy, because purple on navy on its own would sink into the background. */
.btn-gold{background:var(--magenta);color:#fff;border-color:var(--gold);border-width:3px;
  box-shadow:0 0 0 1px rgba(241,160,6,.22),0 0 20px rgba(241,160,6,.30),
             0 10px 26px rgba(4,10,28,.42)}
.btn-gold:hover{background:#285BFE;border-color:var(--gold-dark);
  box-shadow:0 0 0 1px rgba(252,212,5,.34),0 0 26px rgba(241,160,6,.44),
             0 12px 30px rgba(4,10,28,.48)}
.btn-ghost{border-color:rgba(255,255,255,.35);color:#fff}
.btn-ghost:hover{background:rgba(255,255,255,.12)}
.btn-navy{background:var(--ink);color:#fff}
.btn-outline{border-color:var(--line);color:var(--ink);background:#fff}
.btn-lg{padding:18px 32px;font-size:1.05rem}

/* ============ HEADER ============ */
header{position:fixed;top:0;left:0;right:0;z-index:60;background:var(--ink);
  border-bottom:1px solid rgba(255,255,255,.10);
  transform:translateZ(0);-webkit-transform:translateZ(0);
  will-change:transform;-webkit-backface-visibility:hidden;backface-visibility:hidden}
/* Once you are properly into the page the logo row gets out of the way and the
   offer strip is the only thing left pinned, which is about two thirds of the
   header's height handed back on a phone.

   Done by sliding the whole header up by the height of the logo row and then
   pushing the strip back down by the same amount, rather than collapsing the
   row's height. Collapsing needs overflow:hidden on .navbar, and .subnav is
   positioned inside .navitem inside .navbar, so every dropdown on the desktop
   menu would have been clipped off at the header's edge. This way nothing is
   clipped, both moves are transforms the compositor can do on its own, and the
   header's laid out height never changes, so --header-h and the padding it
   sets on the body stay put and the page cannot jump.

   The row comes back on the first upward flick, not only at the top of the
   page: on a phone the burger inside it is the only way into the menu, and
   making somebody scroll all the way up to reach it would be worse than the
   height it saves. */
header.nav-off{transform:translate3d(0,calc(-1 * var(--nav-h,62px)),0)}
header{transition:transform .26s cubic-bezier(.4,0,.2,1)}
/* Held visible for the length of the slide, then taken out of the tab order,
   so nothing focusable is sitting behind the strip. */
header .navbar{visibility:visible;transition:visibility 0s}
header.nav-off .navbar{visibility:hidden;pointer-events:none;transition:visibility 0s linear .26s}
@media(prefers-reduced-motion:reduce){
  header{transition:none}
  header.nav-off .navbar{transition:none}
}
.dot{width:8px;height:8px;border-radius:50%;background:#5EF5F5;display:inline-block;margin-right:7px;color:rgba(94,245,245,.5)}
/* Both rings used to grow by animating box-shadow. A shadow cannot be handed
   to the compositor, so every frame of every pulse was repainted on the main
   thread, on five elements, forever. Lighthouse counts that against responsiveness
   and it is real: it competes with the tap you are waiting for. Same look, drawn
   as a ring on a pseudo-element that only scales and fades, which the compositor
   handles on its own. */
@keyframes pulse{
  0%{transform:translate(-50%,-50%) scale(1);opacity:.55}
  70%{transform:translate(-50%,-50%) scale(2.6);opacity:0}
  100%{transform:translate(-50%,-50%) scale(2.6);opacity:0}
}
.dot,.avail-dot{position:relative}
.dot::after,.avail-dot::after{content:"";position:absolute;left:50%;top:50%;
  width:100%;height:100%;border-radius:50%;background:currentColor;
  transform:translate(-50%,-50%);pointer-events:none;
  animation:pulse 2s ease-out infinite}
.navbar{display:flex;align-items:center;justify-content:space-between;gap:20px;padding-top:14px;padding-bottom:14px}
.logo{display:flex;align-items:center;gap:11px}
.logo img{height:110px;width:auto}
.logo-txt{font-family:var(--f-head);font-weight:800;font-size:1.3rem;color:#fff;letter-spacing:-.03em;line-height:1}
.logo-txt span{display:block;font-family:var(--f-body);font-size:.62rem;font-weight:600;letter-spacing:.22em;color:var(--aqua);text-transform:uppercase;margin-top:3px}
nav.main{display:flex;gap:26px;align-items:center}
nav.main a{font-weight:600;font-size:.95rem;color:#E3E6F3;padding:6px 0;border-bottom:2px solid transparent}
nav.main a:hover{color:#fff}
nav.main a:hover{border-color:var(--gold)}
.nav-cta{display:flex;align-items:center;gap:14px}
.phone-link{display:flex;align-items:center;gap:9px;font-weight:800;color:#fff;font-size:1.05rem;font-family:var(--f-head)}
.phone-link small{display:block;font-family:var(--f-body);font-size:.65rem;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--cyan)}
.burger{display:none;background:none;border:0;padding:8px;cursor:pointer}
/* Phone only availability chip. Hidden on desktop. */
.avail{display:none;align-items:center;gap:7px;font-size:.8rem;font-weight:700;
  color:#E3E6F3;background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.18);
  border-radius:999px;padding:8px 13px;white-space:nowrap}
.avail-dot{width:8px;height:8px;border-radius:50%;background:#5EF5F5;flex:0 0 8px;
  color:rgba(94,245,245,.5)}

.burger span{display:block;width:24px;height:2.5px;background:#fff;border-radius:2px;margin:5px 0;transition:.2s}

/* ============ HERO ============ */
.hero{position:relative;background:var(--ink);color:#fff;overflow:hidden}
/* The van behind the headline is a wash, not content: it sits at well under
   full opacity under a heavy scrim, and on a phone you can barely make it out.
   As an <img> covering the hero it was being recorded as the largest paint on
   the page, so the score described the arrival of a photograph nobody reads
   instead of the headline and the call button, which are there at 1.2 seconds.
   Drawn as a background now. It still preloads, so it appears just as fast. */
.hero-bg{position:absolute;inset:0;background-image:image-set(url(../images/r/hero-480.webp) 1x);
  background-size:cover;background-position:center 30%;opacity:.62}
@media(min-width:520px){ .hero-bg{background-image:image-set(url(../images/r/hero-800.webp) 1x)} }
@media(min-width:1000px){ .hero-bg{background-image:image-set(url(../images/r/hero-1200.webp) 1x);
  background-position:center;opacity:.72} }
.warranty-list li{color:#C3C7E4}
.warranty-list li::before{background:rgba(241,160,6,.18);color:var(--gold)}

/* The area map. A real map of the patch, tinted to the section, with the pins
   drawn over it so they stay crisp at any size. */
.seqmap{position:relative;border-radius:var(--radius);overflow:hidden;
  border:1px solid rgba(255,255,255,.12);line-height:0;background:var(--ink)}
.seqmap img{display:block;width:100%;height:100%;object-fit:cover}
.seqmap-pins{position:absolute;inset:0;width:100%;height:100%}
.seqmap-tag,.seqmap-cred{position:absolute;font-family:var(--f-body);line-height:1.2}
.seqmap{display:block;text-decoration:none;transition:border-color .18s ease}
.seqmap:hover{border-color:rgba(241,160,6,.55)}
.seqmap:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
.seqmap-tag{left:16px;bottom:14px;font-size:.7rem;font-weight:700;letter-spacing:1.4px;
  text-transform:uppercase;color:#C3C7E4;display:inline-flex;align-items:center;gap:5px}
.seqmap-tag b{color:var(--gold)}
.seqmap:hover .seqmap-tag{color:#fff}
.seqmap-cred{right:10px;bottom:8px;font-size:.58rem;color:rgba(255,255,255,.44)}

/* The yellow line under the headline, and the link to the offers the hero
   does not show. */
.h1-sub{display:block;color:var(--gold);font-size:.6em;line-height:1.25;margin-top:12px;font-weight:800}
.allofs{display:inline-flex;align-items:center;gap:6px;color:var(--cyan);
  font-family:var(--f-head);font-weight:700;font-size:.94rem;text-decoration:none;margin-top:2px}
.allofs:hover{text-decoration:underline}

/* You could not tell there was a ute behind the headline. The photo is lifted
   and the wash is heavy on the left, where the words sit, and lifts off the
   right so the vehicle and the branding read. */
.hero-bg img{width:100%;height:100%;object-fit:cover;opacity:.72;display:none;
  filter:blur(1px) brightness(1.16) saturate(1.08)}
.hero-bg::after{content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,rgba(11,17,37,.94) 0%,rgba(11,17,37,.80) 34%,rgba(11,17,37,.34) 68%,rgba(11,17,37,.16) 100%)}
.hero-inner{position:relative;display:grid;grid-template-columns:1.15fr .85fr;gap:56px;align-items:center;padding:clamp(52px,6.5vw,92px) 0}
.hero h1{color:#fff}
.hero h1 em{font-style:normal;color:var(--gold)}
.hero p.lead{color:#C3C7E4;font-size:1.12rem}
.rating{display:inline-flex;align-items:center;gap:12px;background:rgba(255,255,255,.09);border:1px solid rgba(255,255,255,.16);padding:9px 16px;border-radius:999px;margin-bottom:22px;font-size:.9rem;color:#D8DBF0}
.stars{color:var(--gold);letter-spacing:2px}
.hero-btns{display:flex;flex-wrap:wrap;gap:14px;margin:28px 0 26px}
/* These became links so the tick could point at the licence, and the rule
   below only named span, which put the tick above the words instead of beside
   them. Bigger too: they are the four things people scan for. */
.hero-points{display:flex;flex-wrap:wrap;gap:12px 26px;font-size:1rem;color:#C3C7E4}
.hero-points span,.hero-points .hero-pt{display:flex;align-items:center;gap:9px}
@media(max-width:560px){ .hero-points{font-size:.95rem;gap:10px 18px} }
/* On the navy panels the tick is cyan, on the pale blue ones it is a deeper
   blue. It was one colour for both, which meant whichever ground it was not
   designed for failed. */
.tick{width:21px;height:21px;flex:0 0 21px;border-radius:50%;background:rgba(94,245,245,.20);color:var(--cyan);display:grid;place-items:center;font-size:11px;font-weight:800}
.tick-lt{background:rgba(40,91,254,.12);color:#1D45C7}

/* booking card */
.book-card{background:#fff;border-radius:22px;padding:30px;box-shadow:var(--shadow-lg);color:var(--body)}
.book-card h3{font-size:1.35rem;margin-bottom:4px}
.book-card .sub{font-size:.9rem;margin-bottom:20px}
.field{margin-bottom:13px}
.field label{display:block;font-size:.76rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--ink);margin-bottom:6px}
.field input,.field select,.field textarea{width:100%;padding:13px 14px;border:1.5px solid var(--line);border-radius:11px;font-family:inherit;font-size:.97rem;color:var(--ink);background:#fff;transition:border .15s}
.field input:focus,.field select:focus,.field textarea:focus{outline:none;border-color:var(--aqua);box-shadow:0 0 0 3px rgba(40,91,254,.14)}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:13px}
.form-note{font-size:.76rem;text-align:center;margin:12px 0 0}
.form-ok{display:none;background:#EAF6FD;border:1px solid #A5D9F2;color:#285BFE;padding:14px;border-radius:12px;font-size:.92rem;margin-bottom:14px}

/* ============ TRUST BAR ============ */
.trustbar{background:var(--mist);border-bottom:1px solid var(--line)}
.trustbar .wrap{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;padding-top:26px;padding-bottom:26px}
.trust{display:flex;align-items:center;gap:13px;padding:0 14px;border-right:1px solid var(--line)}
.trust:last-child{border-right:0}
.trust svg{flex:0 0 34px}
.trust b{display:block;color:var(--ink);font-size:.98rem;font-family:var(--f-head)}
.trust small{font-size:.8rem}

/* ============ OFFERS ============ */
.offer{position:relative;background:var(--ink);border:0;border-radius:var(--radius);padding:0;overflow:hidden;box-shadow:var(--shadow);display:flex;flex-direction:column;transition:transform .18s ease,box-shadow .18s ease}
.offer-cover{position:absolute;inset:0;z-index:4}
.offer:hover{transform:translateY(-3px);box-shadow:0 16px 40px rgba(6,11,30,.34)}
.offer:focus-within{outline:3px solid var(--gold);outline-offset:3px}
.offer:hover .offer-bg{transform:scale(1.04)}
.offer-tag{position:absolute;top:16px;left:16px;z-index:3;display:inline-block;background:var(--gold);color:var(--ink);font-size:.66rem;font-weight:800;letter-spacing:.09em;text-transform:uppercase;padding:7px 15px;border-radius:999px;box-shadow:0 3px 12px rgba(6,11,30,.45)}
.offer-head{position:absolute;left:0;right:0;bottom:0;z-index:3;padding:0 18px 15px}
.offer h3{margin-bottom:7px}
.offer p{font-size:.93rem;margin:0}

/* ============ SERVICES ============ */
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:22px}
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:20px}
.svc{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:0;transition:.18s;position:relative;overflow:hidden}
.svc::before{content:"";position:absolute;left:0;top:0;height:3px;width:0;background:var(--gold);transition:width .25s}
.svc:hover{transform:translateY(-4px);box-shadow:var(--shadow);border-color:transparent}
.svc:hover::before{width:100%}
.svc .thumb{aspect-ratio:3/2;overflow:hidden;background:var(--mist)}
.svc .thumb img{width:100%;height:100%;object-fit:cover;transition:transform .45s}
.svc:hover .thumb img{transform:scale(1.07)}
.svc .body{padding:20px 22px 24px}
.svc h3{margin-bottom:6px}
.svc p{font-size:.93rem;margin:0}
.svc .more{display:inline-block;margin-top:14px;font-size:.85rem;font-weight:700;color:var(--aqua)}

/* ============ WISHES ============ */
.wishes{background:var(--navy);color:#fff;position:relative;overflow:hidden}
.wishes h2{color:#fff}
.wishes p{color:#B5B9D8}
.wish{background:rgba(255,255,255,.055);border:1px solid rgba(255,255,255,.11);border-radius:var(--radius);padding:30px 26px}
.wish .num{font-family:var(--f-head);font-size:2.4rem;font-weight:800;color:var(--gold);line-height:1;margin-bottom:14px;opacity:.9}
.wish h3{color:#fff;font-size:1.15rem}
.wish p{font-size:.94rem;margin:0}

/* ============ EMERGENCY STRIP ============ */
.emerg{background:linear-gradient(100deg,var(--gold),#FFD152);color:var(--ink)}
.emerg .wrap{display:flex;align-items:center;justify-content:space-between;gap:28px;padding-top:34px;padding-bottom:34px;flex-wrap:wrap}
.emerg h3{font-size:clamp(1.3rem,2.6vw,1.9rem);margin:0}
.emerg p{margin:6px 0 0;font-size:.98rem;color:#4A3502;font-weight:500}

/* ============ STEPS ============ */
.step{text-align:center;padding:0 12px}
.step .circle{width:64px;height:64px;border-radius:50%;background:var(--ink);color:var(--gold);display:grid;place-items:center;font-family:var(--f-head);font-weight:800;font-size:1.4rem;margin:0 auto 18px}
.steps-wrap{position:relative}
.steps-wrap::before{content:"";position:absolute;top:32px;left:16%;right:16%;height:2px;background:repeating-linear-gradient(90deg,var(--line) 0 8px,transparent 8px 16px)}
.steps-wrap .grid-3{position:relative}

/* ============ AREAS ============ */
.areas-grid{display:grid;grid-template-columns:1fr 1fr;gap:26px}
.area-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:30px;box-shadow:var(--shadow)}
.area-card h3{display:flex;align-items:center;gap:10px;font-size:1.3rem}
.pin{width:30px;height:30px;border-radius:9px;background:var(--gold);display:grid;place-items:center;color:var(--ink);font-size:.9rem}
.suburbs{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
.suburbs span{background:var(--mist);border:1px solid var(--line);border-radius:999px;padding:6px 13px;font-size:.85rem;color:var(--ink);font-weight:500}

/* ============ REVIEWS ============ */
.rev{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:26px;display:flex;flex-direction:column;gap:12px}
.rev .stars{font-size:1rem}
.rev p{font-size:.95rem;margin:0;flex:1}
.rev .who{display:flex;align-items:center;gap:11px;border-top:1px solid var(--line);padding-top:14px}
.avatar{width:38px;height:38px;border-radius:50%;background:var(--aqua);color:#fff;display:grid;place-items:center;font-weight:700;font-size:.9rem;font-family:var(--f-head)}
.who b{color:var(--ink);font-size:.92rem;display:block}
.who small{font-size:.78rem}
.gcard{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:46px 26px;text-align:center;max-width:640px;margin:0 auto;box-shadow:var(--shadow)}
.gscore{font-family:var(--f-head);font-size:4.2rem;font-weight:800;color:var(--ink);line-height:1}
.gcard p{max-width:470px;margin:18px auto 28px}
.placeholder-note{background:#FFF7E3;border:1px dashed var(--gold-dark);color:#7A5A02;border-radius:12px;padding:12px 16px;font-size:.86rem;margin-bottom:26px;text-align:center}

/* ============ GALLERY ============ */
.gal{border-radius:var(--radius);overflow:hidden;aspect-ratio:4/3;background:var(--mist)}
.gal img{width:100%;height:100%;object-fit:cover;transition:transform .4s}
.gal:hover img{transform:scale(1.06)}

/* ============ FAQ ============ */
.faq{max-width:840px;margin:0 auto}
details{border-bottom:1px solid var(--line);padding:4px 0}
summary{cursor:pointer;list-style:none;padding:20px 40px 20px 0;font-weight:700;color:var(--ink);font-family:var(--f-head);font-size:1.03rem;position:relative}
summary::-webkit-details-marker{display:none}
summary::after{content:"+";position:absolute;right:6px;top:50%;transform:translateY(-50%);font-size:1.5rem;color:var(--aqua);font-weight:400}
details[open] summary::after{content:"–"}
details p{padding:0 40px 20px 0;margin:0;font-size:.96rem}

/* ============ CTA + FOOTER ============ */
.bigcta{background:var(--ink);color:#fff;border-radius:24px;padding:clamp(36px,5vw,60px);text-align:center;position:relative;overflow:hidden}
.bigcta.with-van{display:grid;grid-template-columns:1fr .95fr;gap:34px;align-items:center;text-align:left}
.bigcta.with-van p{margin-left:0}
/* The van is a framed photo, not a cut-out. Two attempts at cutting it out
   left either a chopped roofline or a torn ladder, because the background
   removal cannot separate thin ladder rails from sky. A framed photo has no
   matte to get wrong, and it matches every other photo on the site. */
.bigcta .van{width:100%;height:auto;aspect-ratio:1200/860;object-fit:cover;
  border-radius:18px;box-shadow:0 20px 46px rgba(4,10,28,.55);
  border:1px solid rgba(255,255,255,.10);display:block}
.bigcta h2{color:#fff}
.bigcta p{color:#B5B9D8;max-width:56ch;margin-left:auto;margin-right:auto}
footer{background:var(--ink);color:#9AA0C4;font-size:.9rem;padding-top:64px}
/* levels follow the document outline, sizes stay where they were */
footer h3{color:#fff;font-size:.82rem;letter-spacing:.13em;text-transform:uppercase;margin-bottom:16px;font-family:var(--f-body);font-weight:700}
footer a:hover{color:var(--gold)}
.foot-grid{display:grid;grid-template-columns:1.5fr 1fr 1fr 1.2fr;gap:38px;padding-bottom:44px}
.foot-links{display:flex;flex-direction:column;gap:9px}
.foot-bottom{border-top:1px solid rgba(255,255,255,.10);padding:20px 0;display:flex;justify-content:space-between;gap:16px;flex-wrap:wrap;font-size:.82rem}
.socials{display:flex;gap:10px;margin-top:18px}
.socials a{width:36px;height:36px;border-radius:10px;background:rgba(255,255,255,.08);display:grid;place-items:center;color:#fff}
.socials a:hover{background:var(--gold);color:var(--ink)}

/* sticky mobile call bar */
.mobilebar{display:none;position:fixed;bottom:0;left:0;right:0;z-index:70;
  transform:translateZ(0);-webkit-transform:translateZ(0);backface-visibility:hidden;background:#fff;border-top:1px solid var(--line);padding:8px 12px;gap:8px;box-shadow:0 -6px 20px rgba(11,17,37,.10)}
/* One button in the bar now. Centred, and capped so it does not stretch
   into a letterbox on a wide phone. */
.mobilebar{justify-content:center}
.mobilebar .btn{flex:0 1 320px;padding:12px 10px;font-size:.95rem}

/* ============ SCROLL ANIMATION ============
   Elements ease up into place as you reach them. The .anim class is added
   by a one-line script in the <head>, so if JavaScript ever fails the page
   simply shows everything straight away. */
.anim .section .center,
.anim .offer,
.anim .prob,
.anim .why>div,
.anim .step,
.anim .svc,
.anim .gal,
.anim .wish,
.anim .area-card,
.anim .gcard,
.anim .proofbar>div,
.anim .trust,
.anim .faq details,
.anim .bigcta,
.anim .emerg .wrap>*{
  opacity:0;transform:translateY(22px);
  transition:opacity .7s cubic-bezier(.22,.61,.36,1),transform .7s cubic-bezier(.22,.61,.36,1)}
.anim .section .center.is-in,
.anim .offer.is-in,
.anim .prob.is-in,
.anim .why>div.is-in,
.anim .step.is-in,
.anim .svc.is-in,
.anim .gal.is-in,
.anim .wish.is-in,
.anim .area-card.is-in,
.anim .gcard.is-in,
.anim .proofbar>div.is-in,
.anim .trust.is-in,
.anim .faq details.is-in,
.anim .bigcta.is-in,
.anim .emerg .wrap>*.is-in{opacity:1;transform:none}

/* header lifts off the page once you start scrolling */
header{transition:box-shadow .25s ease,background .25s ease}
header.scrolled{box-shadow:0 8px 30px rgba(4,10,28,.45)}
/* The top strip stays. It was rolled up on scroll for a while to give 39px
   back to the page, but Blake pointed at that strip and asked for it to stick,
   and rolling it away on scroll is the opposite of that. Whole header pins,
   strip included. */
@media(prefers-reduced-motion:reduce){ .offerbar{transition:none} }

/* softer, slower hovers throughout */
.btn{transition:transform .2s cubic-bezier(.22,.61,.36,1),box-shadow .2s ease,background .2s ease}
.svc{transition:transform .28s cubic-bezier(.22,.61,.36,1),box-shadow .28s ease,border-color .28s ease}
.offer{transition:transform .28s cubic-bezier(.22,.61,.36,1),box-shadow .28s ease}
.offer:hover{transform:translateY(-6px);box-shadow:var(--shadow-lg)}
/* The edge picks up the brand gold on the way up. A card that only moves
   reads as a wobble; a card that moves and lights up reads as a button. */
.offer{outline:1px solid transparent;outline-offset:-1px;transition:transform .28s cubic-bezier(.22,.61,.36,1),box-shadow .28s ease,outline-color .28s ease}
.offer:hover{outline-color:rgba(241,160,6,.55)}
.area-card,.gcard,.prob,.why>div{transition:transform .28s cubic-bezier(.22,.61,.36,1),box-shadow .28s ease}
.why>div:hover,.prob:hover{transform:translateY(-3px);box-shadow:var(--shadow)}
summary{transition:color .2s ease}
summary:hover{color:var(--aqua)}
details p{animation:fadeIn .35s ease}
@keyframes fadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
.anim .section .center,
.anim .offer,
.anim .prob,
.anim .why>div,
.anim .step,
.anim .svc,
.anim .gal,
.anim .wish,
.anim .area-card,
.anim .gcard,
.anim .proofbar>div,
.anim .trust,
.anim .faq details,
.anim .bigcta,
.anim .emerg .wrap>*{opacity:1;transform:none;transition:none}
  .btn:hover,.svc:hover,.offer:hover,.why>div:hover,.prob:hover{transform:none}
}

/* ============ RESPONSIVE ============ */
@media(max-width:1024px){
  .hero-inner{grid-template-columns:1fr;gap:36px}
  .trustbar .wrap{grid-template-columns:1fr 1fr;gap:20px}
  .trust:nth-child(2n){border-right:0}
  .grid-4{grid-template-columns:1fr 1fr}
  .foot-grid{grid-template-columns:1fr 1fr;gap:30px}
  nav.main{display:none}
  .burger{display:block}
  nav.main.open{display:flex;position:absolute;top:100%;left:0;right:0;background:#fff;flex-direction:column;align-items:flex-start;gap:0;padding:8px 22px 18px;border-bottom:1px solid var(--line);box-shadow:var(--shadow)}
  nav.main.open a{width:100%;padding:14px 0;border-bottom:1px solid var(--line)}
}
@media(max-width:900px){
  .about-grid{grid-template-columns:1fr!important;gap:34px!important}
  .bigcta.with-van{grid-template-columns:1fr;text-align:center;gap:20px}
  .bigcta.with-van p{margin-left:auto}
}
@media(max-width:560px){
  /* two-up on a phone squeezed these into columns of two-word lines */
  .trustbar .wrap{grid-template-columns:1fr;gap:14px}
  .trust{border-right:0;padding:0;border-bottom:1px solid var(--line);padding-bottom:13px}
  .trust:last-child{border-bottom:0;padding-bottom:0}
}
@media(max-width:760px){
  .grid-3,.grid-4,.areas-grid{grid-template-columns:1fr}
  .steps-wrap::before{display:none}
  .phone-link{display:none}
  body{padding-bottom:68px}
  .mobilebar{display:flex}
  .field-row{grid-template-columns:1fr}
  .nav-cta .btn{display:none}   /* sticky bottom bar already has the CTA */
  .foot-grid{grid-template-columns:1fr}
  .emerg .wrap{flex-direction:column;text-align:center}
}

/* ============ OFFER CARDS ============ */
/* Five offers. A fixed column count strands the fifth card on the left of a
   row of its own, so these wrap and centre instead. */
.offers-grid{display:flex;flex-wrap:wrap;justify-content:center;gap:16px}
.offers-grid > .offer{flex:1 1 300px;max-width:372px}
.offer{background:var(--ink);border:0;border-radius:var(--radius);padding:0;overflow:hidden;
  box-shadow:var(--shadow);display:flex;flex-direction:column}
.offer-top{position:relative;background:var(--ink);aspect-ratio:1/1;flex:0 0 auto;overflow:hidden}
/* Watermark look: the photo shows through evenly across the whole card and the
   words sit on top of it. An even tint rather than a gradient wipe, so no part
   of the photo gets blacked out. The text shadows do the readability work. */
.offer-top::before{content:"";position:absolute;inset:0;z-index:2;background:linear-gradient(180deg,rgba(11,17,37,.22) 0%,rgba(11,17,37,.06) 26%,rgba(11,17,37,.62) 56%,rgba(11,17,37,.93) 78%,var(--ink) 100%)}
.offer-top::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;background:radial-gradient(120% 80% at 20% 18%,rgba(11,17,37,.28) 0%,rgba(11,17,37,0) 60%)}
/* Brand bar between the photo and the details: blue running into purple. */
.offer-rule{height:5px;flex:0 0 5px;background:linear-gradient(90deg,var(--cyan) 0%,var(--blue-2) 42%,var(--aqua) 68%,var(--magenta) 100%)}
.offer-tag{display:inline-block;background:var(--gold);color:var(--ink);font-size:.64rem;
  box-shadow:0 2px 10px rgba(6,11,30,.5);
  font-weight:800;letter-spacing:.1em;text-transform:uppercase;padding:5px 10px;border-radius:6px;
  margin-bottom:13px;position:relative;z-index:3}
.offer .price{font-family:var(--f-head);font-size:2.35rem;font-weight:800;color:#fff;line-height:1;letter-spacing:-.02em;text-shadow:0 2px 12px rgba(6,11,30,.6)}
.offer-for{font-family:var(--f-head);font-weight:800;text-transform:uppercase;color:var(--gold);font-size:1.06rem;line-height:1.14;margin-top:8px;max-width:92%}
.offer-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:1;transition:transform .5s ease}
.offer-terms{margin:16px 0 0;font-size:.7rem;line-height:1.55;color:#B5B9D8;text-align:center}
.offer-bottom{background:var(--ink);padding:24px 18px 22px;text-align:center;flex:1 1 auto;display:flex;flex-direction:column}
.promo-label{display:block;font-size:.66rem;font-weight:800;letter-spacing:.11em;text-transform:uppercase;color:#46A3E4}
.promo-code{font-family:var(--f-head);font-size:1.62rem;font-weight:800;color:var(--gold);margin:8px 0 16px;line-height:1;letter-spacing:-.01em}
.btn-claim{position:relative;z-index:5;display:flex;align-items:center;justify-content:center;gap:10px;border:2px solid #fff;color:#fff;border-radius:10px;padding:13px 8px;font-weight:800;font-size:.82rem;letter-spacing:.04em;text-transform:uppercase;transition:background .2s ease,color .2s ease}
.btn-claim .btn-ico{flex:0 0 auto;color:var(--cyan);transition:color .2s ease}
.btn-claim:hover .btn-ico{color:var(--aqua)}
.btn-claim:hover{background:#fff;color:var(--ink)}
.offer-link{position:relative;z-index:5;display:inline-block;margin:13px auto 0;font-size:.84rem;color:#46A3E4;text-decoration:underline;background:none;border:0;cursor:pointer;font-family:inherit}
.offer-link:hover{color:#fff}

/* ============ BRANDS WE INSTALL ============ */
.brands{background:var(--mist);border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  padding:34px 0 38px;overflow:hidden}
.brands h3{text-align:center;font-family:var(--f-body);font-size:.76rem;font-weight:700;
  letter-spacing:.14em;text-transform:uppercase;color:var(--body);margin:0 0 24px}
.brand-window{overflow:hidden;-webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent)}
.brand-track{display:flex;align-items:center;gap:60px;width:max-content;animation:marquee 34s linear infinite}
.brand-window:hover .brand-track{animation-play-state:paused}
.brand{font-family:var(--f-head);font-weight:800;font-size:1.55rem;letter-spacing:.01em;
  text-transform:uppercase;color:#6B7099;white-space:nowrap}
@keyframes marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){
  .brand-track{animation:none}
  .brand-window{overflow-x:auto}
}

/* hero offer chips */
.hero-offers{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:26px 0 6px}
.hchip{display:flex;align-items:center;gap:10px;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.15);border-radius:12px;padding:11px 14px;font-size:.86rem;color:#D8DBF0;text-decoration:none;transition:background .18s ease,border-color .18s ease,transform .18s ease}
.hchip b{color:var(--gold);font-family:var(--f-head);font-size:1.02rem;white-space:nowrap}
.hchip:hover{background:rgba(241,160,6,.14);border-color:var(--gold);transform:translateY(-2px)}
.hchip:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

/* why choose us */
.why{display:grid;grid-template-columns:repeat(3,1fr);gap:14px}
.why div{display:flex;gap:11px;align-items:center;background:#fff;border:1px solid var(--line);border-radius:12px;padding:16px 18px;font-weight:600;color:var(--ink);font-size:.95rem}

/* problem cards */
.probs{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.prob{background:#fff;border:1px solid var(--line);border-left:4px solid #EF3130;border-radius:12px;padding:18px 20px}
.prob b{display:block;color:var(--ink);font-family:var(--f-head);margin-bottom:3px}
.prob p{margin:0;font-size:.92rem}

/* proof */
.proofbar{display:grid;grid-template-columns:repeat(3,1fr);gap:20px;margin-top:34px}
.proofbar div{text-align:center;background:#fff;border:1px solid var(--line);border-radius:12px;padding:20px}
.proofbar b{display:block;font-family:var(--f-head);font-size:1.4rem;color:var(--ink);margin-bottom:2px}
.gal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-top:34px}

@media(max-width:1024px){
  .offer-for{max-width:58%}
  .why{grid-template-columns:1fr 1fr}
}
@media(max-width:760px){
  .why,.probs,.proofbar{grid-template-columns:1fr}
  /* Six offers stacked full width is six screens of scrolling before anybody
     reaches the reviews. Sideways instead, with the next card showing at the
     edge, so it is obvious there is more without a line of text saying so.
     Same pattern as the review carousel further down, deliberately. */
  .offers-grid{flex-direction:row;flex-wrap:nowrap;justify-content:flex-start;
    overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;gap:12px;
    /* out to both screen edges, so a card can genuinely sit half off */
    margin:0 -22px;padding:4px 22px 10px;
    scrollbar-width:none;-ms-overflow-style:none}
  .offers-grid::-webkit-scrollbar{display:none}
  .offers-grid > .offer{flex:0 0 84%;width:84%;max-width:84%;scroll-snap-align:center}

  /* The top of the card read left aligned while everything under the rule read
     centred. On a wide card nobody notices. Full width on a phone it just looks
     like something slipped. */
  .offer-head{padding-left:16px;padding-right:16px;text-align:center}
  .price,.offer-for{text-align:center}
  .offer-for{max-width:100%;margin-left:auto;margin-right:auto}
  /* Six of these stacked full width is most of a phone screen before you
     reach anything else. Two across halves it and they still read. */
  .hero-offers{grid-template-columns:1fr 1fr;gap:8px;margin:20px 0 4px}
  .hchip{padding:10px 11px;font-size:.78rem;gap:7px;border-radius:11px}
  .hchip b{font-size:.94rem}
  .gal-grid{grid-template-columns:1fr 1fr}
}

/* ============ AREA PAGES ============ */
.local-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:46px;align-items:center}
.local-grid .gal{aspect-ratio:4/3}
.probs-3{grid-template-columns:repeat(3,1fr)}
.probs-3 .prob{display:flex;align-items:center;min-height:78px}
.probs-3 .prob b{margin:0}

.svc-compact .svc .body{padding:16px 18px 18px}
.svc-compact .svc h3{margin:0;font-size:1rem}
.svc-compact .svc{display:block}

/* Five offers now. A fixed column count leaves the fifth card stranded on
   the left of a row of its own, so the row wraps and centres instead. */
.oband-grid{display:flex;flex-wrap:wrap;justify-content:center;gap:16px}
.oband{flex:1 1 280px;max-width:380px}
.oband{display:block;background:#fff;border:1px solid var(--line);border-top:4px solid var(--gold);border-radius:14px;padding:18px;text-align:center;text-decoration:none;color:inherit;transition:transform .18s ease,box-shadow .18s ease,border-color .18s ease}
.oband b{display:block;font-family:var(--f-head);font-size:1.6rem;font-weight:800;color:var(--ink);line-height:1}
.oband span{display:block;font-size:.86rem;margin:5px 0 10px}
.oband em{display:block;font-style:normal;font-family:var(--f-head);font-weight:800;
  font-size:.92rem;color:var(--aqua);letter-spacing:.02em}
.oband-go{display:block;font-style:normal;font-size:.72rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--aqua);margin-top:9px}
.oband:hover{transform:translateY(-3px);box-shadow:0 12px 28px rgba(11,17,37,.14);border-color:var(--gold)}
.oband:focus-visible{outline:3px solid var(--gold);outline-offset:3px}

.nearby{display:flex;flex-wrap:wrap;gap:10px;justify-content:center}
.nearby-link{background:#fff;border:1px solid var(--line);border-radius:999px;padding:9px 17px;
  font-size:.9rem;font-weight:600;color:var(--ink);transition:background .2s ease,border-color .2s ease}
.nearby-link:hover{background:var(--ink);color:#fff;border-color:var(--ink)}
.nearby-all{background:var(--gold);border-color:var(--gold);font-weight:800}
.nearby-all:hover{background:var(--gold-dark);border-color:var(--gold-dark);color:var(--ink)}

@media(max-width:1024px){
  .probs-3{grid-template-columns:1fr 1fr}
}
@media(max-width:900px){
  .local-grid{grid-template-columns:1fr;gap:30px}
}
@media(max-width:760px){
  .probs-3{grid-template-columns:1fr}
  .oband-grid{flex-direction:column}
  .oband{flex:0 0 auto;width:100%}
}

/* ============ ARTICLES ============ */
.article h2{font-size:clamp(1.25rem,2.4vw,1.6rem);margin-top:1.5em}
.article p{font-size:1.02rem;line-height:1.75}
.article p:first-of-type{font-size:1.08rem}

/* ============ REVIEWS, LOUD ============ */
/* Sits under the headline as a line of proof. Floating above it as a chip
   attached to nothing, it read as random. A quiet outline, not a gold panel,
   so the headline stays the loudest thing in the hero. */
.rating-big{display:inline-flex;align-items:center;flex-wrap:wrap;gap:9px;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);
  border-radius:999px;padding:7px 14px;margin:2px 0 8px}
.rating-big .stars{font-size:1.25rem;letter-spacing:3px}
.rating-big b{color:#fff;font-family:var(--f-head);font-size:1.3rem;line-height:1}
.rating-big span{color:#FFFFFF;font-size:.88rem;font-weight:600}
/* The six star line is a slogan, not a rating, so it is kept visually apart
   from the Google score above it. Six stars, gold, and the words underneath. */
/* The six gold stars sat directly under the 5.0 Google badge, so the hero was
   showing two star ratings and the word stars three times over. The badge is
   the one with a source behind it, so it stays and the slogan is just a line. */
.sixstar-line{display:block;margin:0 0 14px;font-family:var(--f-head);font-weight:800;
  color:var(--gold);font-size:1.18rem;letter-spacing:-.01em;line-height:1.2}

.revband{background:var(--ink);color:#fff;position:relative;overflow:hidden}
.revband::before{content:"";position:absolute;inset:0;
  background:radial-gradient(circle at 20% 20%,rgba(40,91,254,.34),transparent 55%),
             radial-gradient(circle at 85% 80%,rgba(146,42,254,.26),transparent 55%)}
.revband .wrap{position:relative;display:grid;grid-template-columns:auto 1fr auto;gap:44px;
  align-items:center;padding-top:52px;padding-bottom:52px}
.revband .score{font-family:var(--f-head);font-size:5rem;font-weight:800;line-height:.9;color:var(--gold)}
.revband .score small{display:block;font-size:1.5rem;letter-spacing:4px;margin-top:6px}
.revband h2{color:#fff;margin:0 0 8px;font-size:clamp(1.5rem,3vw,2.2rem)}
.revband p{color:#C3C7E4;margin:0;max-width:52ch}
.revband .acts{display:flex;flex-direction:column;gap:11px;min-width:230px}
@media(max-width:980px){
  .revband .wrap{grid-template-columns:1fr;gap:24px;text-align:center}
  .revband .acts{min-width:0}
  .revband p{margin-left:auto;margin-right:auto}
}

/* ============ DROPDOWN NAV ============ */
.navitem{position:relative}
.navtop,.navtop-link{background:none;border:0;font-family:inherit;font-weight:600;font-size:.95rem;color:#E3E6F3;cursor:pointer;padding:6px 0;display:flex;align-items:center;gap:6px;border-bottom:2px solid transparent;transition:border-color .18s ease,color .18s ease}
.navtop:hover,.navtop-link:hover,.navitem.open>.navtop{border-color:var(--gold);color:#fff}
.navtop svg{transition:transform .2s ease;opacity:.75}
.navitem.open>.navtop svg{transform:rotate(180deg);opacity:1}
.subnav{position:absolute;top:calc(100% + 10px);left:-14px;min-width:266px;background:#fff;
  border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow-lg);padding:8px;z-index:90;
  opacity:0;visibility:hidden;transform:translateY(-6px);
  transition:opacity .18s ease,transform .18s ease,visibility .18s}
.navitem.open>.subnav{opacity:1;visibility:visible;transform:none}
.subnav::before{content:"";position:absolute;top:-10px;left:0;right:0;height:10px}
nav.main .subnav a{display:block;padding:10px 13px;border-radius:9px;font-size:.92rem;font-weight:600;color:var(--ink);transition:background .15s ease,color .15s ease}
nav.main .subnav a:hover{background:var(--mist);color:var(--aqua)}
nav.main .subnav a.all{border-top:1px solid var(--line);margin-top:6px;padding-top:13px;color:var(--aqua)}
nav.main .subnav a.all:hover{background:var(--mist)}

/* ============ OFFER PAGE BITS ============ */
.promo-hero{display:inline-flex;flex-direction:column;gap:3px;background:rgba(241,160,6,.13);
  border:1.5px dashed var(--gold);border-radius:12px;padding:12px 20px;margin-top:22px}
.promo-hero span{font-size:.66rem;font-weight:700;letter-spacing:.13em;text-transform:uppercase;color:#FFFFFF}
.promo-hero b{font-family:var(--f-head);font-size:1.5rem;font-weight:800;color:var(--gold);line-height:1}
.terms-list{list-style:none;padding:0;margin:18px 0 0;display:flex;flex-direction:column;gap:13px}
.terms-list li{display:flex;gap:12px;font-size:.97rem;line-height:1.6}
.terms-list li::before{content:"";flex:0 0 7px;height:7px;border-radius:50%;background:var(--gold);margin-top:.55em}

@media(max-width:1024px){
  /* inside the burger menu the dropdowns become plain stacked lists */
  nav.main.open .navitem{width:100%;border-bottom:1px solid var(--line)}
  nav.main.open .navtop{width:100%;justify-content:space-between;padding:14px 0;border-bottom:0}
  nav.main.open .navtop-link{width:100%;padding:14px 0;border-bottom:0}
  nav.main.open .subnav{position:static;opacity:1;visibility:visible;transform:none;display:none;
    box-shadow:none;border:0;border-radius:0;padding:0 0 10px 12px;min-width:0;background:transparent}
  nav.main.open .navitem.open>.subnav{display:block}
  /* the original mobile nav rule underlines every link in the menu, which on a
     sub-item reads as an empty input box. Sub-items get a left rule instead. */
  nav.main.open .subnav a{padding:10px 0 10px 14px;font-size:.92rem;color:var(--body);
    border-bottom:0;border-left:2px solid var(--line);width:auto}
  nav.main.open .subnav a:hover,nav.main.open .subnav a:active{background:transparent;
    border-left-color:var(--gold);color:var(--ink)}
  nav.main.open .subnav a.all{border-top:0;margin-top:0;padding-top:10px;color:var(--aqua)}
}

/* ============ NEIGHBOURS BAND ============ */
.neighbours{background:linear-gradient(160deg,#0B1125,#0B1125);color:#fff;
  padding:clamp(48px,6vw,80px) 0}
.neighbours h2{color:#fff;text-transform:uppercase;letter-spacing:-.01em}
.neighbours .lead{color:#C3C7E4;max-width:68ch}
.nb-grid{display:grid;grid-template-columns:1fr 1fr;gap:34px;align-items:start;margin-top:34px}
.nb-card{background:rgba(94,245,245,.07);border:1.5px solid rgba(94,245,245,.34);
  border-radius:var(--radius);padding:26px}
.nb-card h3{color:#fff;font-size:1.02rem;margin-bottom:16px}
.nb-card ul{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:12px}
.nb-card li{display:flex;align-items:center;gap:11px;font-size:1rem;color:#C3C7E4}
.nb-card li svg{color:var(--cyan);flex:0 0 15px}
.nb-card li b{color:#fff;font-family:var(--f-head)}
.nb-total{margin-top:18px;padding-top:16px;border-top:1px solid rgba(255,255,255,.16);
  font-family:var(--f-head);font-weight:800;font-size:1.3rem;color:var(--gold)}
.nb-map{border-radius:var(--radius);overflow:hidden;border:1.5px solid rgba(94,245,245,.28)}
.nb-map svg{display:block;width:100%;height:auto}
@media(max-width:860px){ .nb-grid{grid-template-columns:1fr} }

/* Per suburb explanation blocks. */
.pdeep{background:#fff;border:1px solid var(--line);border-left:4px solid var(--gold);border-radius:14px;padding:20px 22px;margin-bottom:14px}
.pdeep h3{font-size:1.05rem;margin:0 0 8px;color:var(--ink)}
.pdeep p{margin:0;font-size:.95rem;line-height:1.65}

/* Genie Gold Club band on the home page. */
.goldband{background:linear-gradient(150deg,var(--ink),var(--navy));color:#fff}
.gb-inner{display:grid;grid-template-columns:1.5fr .78fr;gap:40px;align-items:start}
.goldband h2{color:#fff;margin:6px 0 10px}
.goldband .lead{color:#C3C7E4;max-width:52ch}
/* One column of benefits, each with its own line of explanation. The old two
   column layout went ragged the moment an item wrapped. */
.gb-list{list-style:none;margin:22px 0 26px;padding:0;display:grid;gap:13px}
.gb-list li{position:relative;padding-left:30px}
.gb-list li::before{content:"";position:absolute;left:0;top:5px;width:17px;height:17px;
  border-radius:50%;background:var(--gold)}
.gb-list li::after{content:"";position:absolute;left:5px;top:10px;width:7px;height:3.5px;
  border-left:2.4px solid var(--ink);border-bottom:2.4px solid var(--ink);
  transform:rotate(-45deg)}
.gb-list b{display:block;font-size:.99rem;font-weight:700;color:#fff;line-height:1.3}
.gb-list span{display:block;font-size:.85rem;color:#9AA0C4;margin-top:2px;line-height:1.45}
.gb-acts{display:flex;gap:12px;flex-wrap:wrap}
.gb-card{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);
  border-left:3px solid var(--gold);border-radius:var(--radius);padding:26px 28px}
.gb-quote{margin:0 0 14px;font-family:var(--f-head);font-size:1.12rem;font-weight:700;
  line-height:1.4;color:#fff}
.gb-note{margin:0;font-size:.92rem;line-height:1.65;color:#C3C7E4}
/* Why choose Genies. Six reasons read better in two columns than as one long
   strip down the side of the card, and the quote under each one is the line a
   customer actually repeats back on the phone. */
.wc-grid{grid-template-columns:1fr 1fr;gap:15px 30px}
.wc-quote{display:block;margin-top:5px;font-style:normal;font-size:.84rem;line-height:1.45;
  color:var(--cyan);border-left:2px solid rgba(94,245,245,.32);padding-left:10px}
.wc-tag{display:block;font-size:.7rem;font-weight:800;letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold);margin-bottom:11px}
.wc-trust{list-style:none;display:flex;flex-wrap:wrap;gap:9px 24px;margin:20px 0 0;padding:0}
.wc-trust li{display:flex;align-items:center;gap:8px;font-size:.85rem;font-weight:600;color:#C3C7E4}
/* Six reasons make a taller left column than the Gold Club's five did, and the
   card is the only thing in its own column. Centred rather than pinned to the
   top, so the empty half sits either side of it instead of all under it. */
.wc-card{align-self:center}
@media(max-width:900px){
  .wc-grid{grid-template-columns:1fr}
}
@media(max-width:900px){
  .gb-inner{grid-template-columns:1fr;gap:28px}
  .gb-list{grid-template-columns:1fr}
}

/* Hand written local detail on the busiest suburbs. */
.deep-item{background:#fff;border:1px solid var(--line);border-radius:14px;padding:24px 26px;margin-bottom:16px}
.deep-item h3{font-size:1.12rem;margin:0 0 10px;color:var(--ink)}
.deep-item p{margin:0 0 12px;font-size:.96rem;line-height:1.7}
.deep-item p:last-child{margin-bottom:0}

@media(max-width:1024px){
  /* The header is dark, so the open burger menu is dark with it. */
  nav.main.open{background:rgba(8,18,46,.99);border-top:1px solid rgba(255,255,255,.10)}
  nav.main.open .navitem{border-bottom-color:rgba(255,255,255,.10)}
  nav.main.open a,nav.main.open .navtop,nav.main.open .navtop-link{color:#E3E6F3}
  nav.main.open .subnav a{color:#AEB5D4;border-left-color:rgba(255,255,255,.16)}
  nav.main.open .subnav a:hover,nav.main.open .subnav a:active{
    border-left-color:var(--gold);color:#fff}
  nav.main.open .subnav a.all{color:var(--cyan)}
}

/* Which city are you in. Sits under the hero on every service page. */
.rsw{background:var(--navy);border-bottom:1px solid rgba(255,255,255,.10)}
.rsw .wrap{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding-top:14px;padding-bottom:14px}
.rsw-label{font-size:.72rem;font-weight:800;letter-spacing:.11em;text-transform:uppercase;
  color:#9AA0C4;margin-right:4px}
.rsw-chip{display:inline-block;padding:8px 16px;border-radius:999px;font-size:.88rem;
  font-weight:700;color:#E3E6F3;border:1px solid rgba(255,255,255,.20);
  text-decoration:none;transition:.16s}
a.rsw-chip:hover{background:rgba(241,160,6,.16);border-color:var(--gold);color:#fff}
.rsw-chip.on{background:var(--gold);border-color:var(--gold);color:var(--ink)}
@media(max-width:560px){ .rsw-label{width:100%;margin-bottom:2px} }

/* Services index: one tile per job, with the city links underneath. */
.svc-fam{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);
  border-radius:var(--radius);overflow:hidden;box-shadow:var(--shadow)}
.svc-fam .svc-hit{display:block;color:inherit;text-decoration:none;flex:1 1 auto}
.svc-cities{display:flex;gap:8px;flex-wrap:wrap;padding:0 18px 18px;margin-top:-6px}
.svc-city{display:inline-block;padding:7px 13px;border-radius:999px;font-size:.79rem;
  font-weight:700;color:var(--aqua);border:1px solid var(--line);text-decoration:none;
  transition:.16s}
.svc-city:hover{background:var(--gold);border-color:var(--gold);color:var(--ink)}

/* Links that leave the site, so nobody wonders where they went. */
nav.main .subnav a.ext{display:flex;align-items:center;justify-content:space-between;gap:8px}
nav.main .subnav a.ext svg{opacity:.5;flex:0 0 auto}
nav.main .subnav a.ext:hover svg{opacity:1}

/* Hero background video. Sits over the hero photo and fades in once it is
   actually playing, so there is never a blank or a jump. Only ever loaded on
   a wide screen: a phone keeps the photo and downloads none of the video. */
.hero-vid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity .9s ease;pointer-events:none}
.hero-vid.on{opacity:1}
@media(prefers-reduced-motion:reduce){ .hero-vid{display:none} }

/* Video band. Dark, so the footage is the brightest thing on the screen, and
   the portrait clip sits in a frame instead of floating in a grey void.
   YouTube is only contacted once somebody presses play. */
.vidband{background:linear-gradient(160deg,var(--ink),var(--navy));color:#fff;
  padding:clamp(46px,5.5vw,74px) 0;position:relative;overflow:hidden}
.vidband::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(52% 62% at 78% 46%,rgba(241,160,6,.16),transparent 70%)}
.vidband .wrap{position:relative;max-width:1060px}
/* Everything from the video band down is skipped until it is scrolled near.
   The browser stops laying out and painting work nobody is looking at, which is
   most of this page: it stands over five thousand pixels tall and a phone shows
   eight hundred of them. The reserved height keeps the scrollbar honest so
   nothing jumps as you go. */
.vidband,.brands,.gal-grid,.rvband,.faq,.emerg{
  content-visibility:auto;contain-intrinsic-size:auto 700px}
.vid-grid{display:grid;grid-template-columns:1fr 340px;gap:clamp(30px,5vw,64px);
  align-items:center}
.vidband h2{color:#fff;margin:6px 0 12px}
.vidband .lead{color:#C3C7E4;max-width:46ch}
.vid-points{list-style:none;margin:20px 0 26px;padding:0;display:grid;gap:10px}
.vid-points li{position:relative;padding-left:28px;font-size:.94rem;color:#E3E6F3}
.vid-points li::before{content:"";position:absolute;left:0;top:7px;width:15px;height:15px;
  border-radius:50%;background:var(--gold)}
.vid-points li::after{content:"";position:absolute;left:4.5px;top:11px;width:6px;height:3px;
  border-left:2px solid var(--ink);border-bottom:2px solid var(--ink);transform:rotate(-45deg)}

/* The frame. A thin bezel makes a portrait clip read as deliberate. */
.vid-stage{position:relative;padding:9px;border-radius:26px;
  background:linear-gradient(160deg,rgba(255,255,255,.16),rgba(255,255,255,.04));
  box-shadow:0 26px 60px rgba(4,10,28,.55)}
.vid-play,.vid-frame{display:block;width:100%;border:0;border-radius:18px;
  aspect-ratio:9/16;background:#0B1430}
.vid-play{position:relative;padding:0;cursor:pointer;overflow:hidden;transition:transform .22s ease}
.vid-play:hover{transform:scale(1.012)}
.vid-play img{display:block;width:100%;height:100%;object-fit:cover}
.vid-play::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(11,20,48,.10),rgba(11,20,48,.55))}
.vid-len{position:absolute;right:12px;bottom:12px;z-index:2;font-size:.74rem;font-weight:700;
  letter-spacing:.04em;color:#fff;background:rgba(11,20,48,.72);border-radius:6px;padding:4px 8px}
.vid-play:focus-visible{outline:3px solid var(--gold);outline-offset:4px}
@media(max-width:820px){
  .vid-grid{grid-template-columns:1fr;gap:30px}
  /* Held to a sensible size on a phone. It is a video shot upright, so at the
     old width it stood 537 pixels tall, half a screen of thumbnail before
     anybody had pressed anything, and it pushed everything under it further
     down. Smaller reads better and costs less to scroll past. */
  .vid-stage{max-width:210px;margin:0 auto}
}


/* ============================================================
   PHONE LAYOUT
   Written against a real audit: tap targets were as small as 15px,
   some labels were 10.5px, and the phone number in the header was a
   text link rather than something you could hit with a thumb.
   Apple and Google both put the minimum tap target at 44px.
   ============================================================ */
@media(max-width:760px){

  /* --- header: logo left, phone button right, both easy to hit --- */
  .navbar{padding-top:10px;padding-bottom:10px;gap:10px}
  .logo img{height:62px}
  .nav-cta{gap:8px}
  /* The sticky bottom bar already has "Call now to book", so a second big
     call button up here was just taking up room. A small availability chip
     earns its space instead, and still dials if you tap it. */
  .phone-link{display:none}
  .avail{display:inline-flex;min-height:38px}
  .burger{min-width:46px;min-height:46px;display:flex;flex-direction:column;
    align-items:center;justify-content:center}

  /* --- anything tappable gets a thumb sized target --- */
  nav.main.open .navtop,
  nav.main.open .navtop-link{min-height:50px;align-items:center}
  nav.main.open .subnav a{min-height:44px;display:flex;align-items:center}
  .suburbs a{min-height:40px;display:inline-flex;align-items:center;
    padding:9px 14px;font-size:.88rem}
  .offer-link{min-height:44px;display:inline-flex;align-items:center;
    justify-content:center;font-size:.92rem}
  .foot-links a,.nearby-link{min-height:42px;display:inline-flex;align-items:center}
  footer a[href^="tel:"],footer a[href^="mailto:"]{min-height:44px;
    display:inline-flex;align-items:center;font-size:1.05rem}
  /* "or skip the form and ring 0476 104 630" was an inline link 15px tall.
     On a phone, somebody with water on the floor wants a button. */
  .form-note{text-align:center}
  .form-note a[href^="tel:"]{margin-top:10px;min-height:48px;
    border:2px solid var(--ink);border-radius:999px;
    display:flex;align-items:center;justify-content:center;
    font-size:1.05rem;font-weight:800;color:var(--ink)!important}
  .foot-bottom a{min-height:42px;display:inline-flex;align-items:center;padding:0 2px}
  .foot-bottom span{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center}
  .socials a{min-width:44px;min-height:44px;display:inline-flex;
    align-items:center;justify-content:center}

  /* --- nothing under 12.5px, which is where phone text stops being read --- */
  .eyebrow{font-size:.8rem;letter-spacing:.1em}
  .promo-label,.promo-hero span{font-size:.8rem}
  .offer-terms{font-size:.76rem}
  .trust small{font-size:.86rem}

  /* --- one thumb, one column: full width buttons --- */
  .hero-btns{flex-direction:column;gap:11px;margin:24px 0 22px}
  .hero-btns .btn,.gb-acts .btn,.vidband .btn{width:100%}
  .gb-acts{flex-direction:column;gap:11px}
  .btn-lg{padding:17px 22px;font-size:1.02rem}

  .sixstar-stars svg{width:30px;height:30px}
  .sixstar b{font-size:1.55rem}
  /* A pill that hugs its text. Full width made it a slab. */
  .rating-big{padding:7px 14px;width:auto;justify-content:flex-start}

  /* --- trust bar as a 2x2 grid, no dividing lines to go ragged --- */
  .trustbar .wrap{grid-template-columns:1fr 1fr;gap:14px;
    padding-top:20px;padding-bottom:20px}
  .trust{border-right:0;padding:0;gap:10px}
  .trust svg{flex:0 0 26px;width:26px;height:26px}
  .trust b{font-size:.9rem;line-height:1.25}

  /* --- service tiles get a real button, the way a phone user expects --- */
  .svc-compact .svc .body{padding-bottom:18px}
  .svc-fam .svc-cities{padding:0 16px 16px}
  .svc-city{min-height:40px;display:inline-flex;align-items:center}
}

@media(max-width:560px){
  .wrap{padding-left:18px;padding-right:18px}
  .section{padding-top:38px;padding-bottom:38px}
  .hero .lead{font-size:1rem}
  .offer .price{font-size:2.5rem}
  .promo-code{font-size:1.7rem}
  .vid-points li{font-size:.9rem}
  .gb-list b{font-size:1rem}
}

@media(max-width:760px){
  /* On a phone the hero is over 1500px tall, so a 105deg overlay put its solid
     end across the whole top of the screen and the ute never showed at all.
     Runs top to bottom here instead: light enough at the top to see the crew
     behind the headline, solid by the time it reaches the booking card. */
  .hero-bg::after{background:linear-gradient(180deg,rgba(11,17,37,.92) 0%,rgba(11,17,37,.78) 45%,rgba(11,17,37,.60) 100%)}
  .hero-bg::after{background:linear-gradient(180deg,
    rgba(11,17,37,.70) 0%,rgba(11,17,37,.84) 44%,var(--ink) 76%)}
}

/* Link to the guide that belongs with a service. */
.readmore{display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  background:var(--mist);border:1px solid var(--line);border-left:4px solid var(--gold);
  border-radius:14px;padding:18px 22px;text-decoration:none;color:var(--ink);
  transition:transform .16s ease,box-shadow .16s ease}
.readmore:hover{transform:translateY(-2px);box-shadow:0 10px 26px rgba(11,17,37,.12)}
.readmore-tag{font-size:.68rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--aqua)}
.readmore b{flex:1 1 260px;font-family:var(--f-head);font-size:1.05rem;line-height:1.3}
.readmore-go{font-weight:700;color:var(--aqua);white-space:nowrap}
@media(max-width:560px){ .readmore{padding:16px 18px;gap:8px} }

/* Availability strip on the booking card. */
.avail-strip{display:flex;align-items:center;gap:9px;flex-wrap:wrap;
  background:#EAF6FD;border:1px solid #A5D9F2;border-radius:11px;
  padding:10px 13px;margin:0 0 16px}
.avail-strip[data-state="good"]{background:#EAF6FD;border-color:#A5D9F2}
.avail-strip[data-state="warm"]{background:#FFF7E3;border-color:#FFD152}
.avail-strip .avail-dot{width:9px;height:9px;border-radius:50%;background:#25D366;
  flex:0 0 9px;color:rgba(37,211,102,.5)}
.avail-strip[data-state="warm"] .avail-dot{background:var(--gold);
  box-shadow:0 0 0 3px rgba(241,160,6,.28)}
.avail-msg{font-weight:700;font-size:.9rem;color:var(--ink)}
.avail-time{margin-left:auto;white-space:nowrap;font-size:.74rem;font-weight:700;letter-spacing:.03em;color:var(--ink);background:rgba(11,17,37,.07);border-radius:999px;padding:4px 10px;font-variant-numeric:tabular-nums}
@media(max-width:560px){ .avail-time{margin-left:0;width:100%} }

/* The placeholder was long enough to force a scrollbar inside the box. */
.field textarea{resize:vertical;min-height:96px;overflow-y:auto;overflow-x:hidden}

/* "Before you ring" diagnostic list on the service pages. */
.dg-list{list-style:none;margin:0;padding:0;display:grid;gap:12px;counter-reset:dg}
.dg-item{display:flex;gap:16px;align-items:flex-start;background:#fff;
  border:1px solid var(--line);border-radius:14px;padding:18px 20px}
.dg-n{flex:0 0 30px;width:30px;height:30px;border-radius:50%;background:var(--gold);
  color:var(--ink);font-family:var(--f-head);font-weight:800;font-size:.92rem;
  display:flex;align-items:center;justify-content:center;margin-top:1px}
.dg-item b{display:block;font-size:1.02rem;color:var(--ink);margin-bottom:4px;
  font-family:var(--f-head)}
.dg-item p{margin:0;font-size:.94rem;line-height:1.65}
.dg-close{margin:22px 0 0;padding:18px 20px;background:var(--mist);
  border-left:4px solid var(--gold);border-radius:12px;font-size:.97rem;
  line-height:1.65;font-weight:600;color:var(--ink)}
@media(max-width:560px){ .dg-item{padding:16px;gap:12px} }

/* Google review carousel. Only renders when there are real reviews in
   _build/data/reviews.py. Scrolls sideways with a thumb or the arrows. */
.rvband{background:var(--mist);padding:clamp(34px,4vw,54px) 0}
.rv-head{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin-bottom:18px}
.rv-g{width:26px;height:26px;border-radius:50%;background:#fff;border:1px solid var(--line);
  display:flex;align-items:center;justify-content:center;font-family:var(--f-head);
  font-weight:800;color:#1558D6;font-size:.95rem}
.rv-head .rv-stars{color:var(--gold);letter-spacing:1px;font-size:1.05rem}
.rv-head b{font-family:var(--f-head);font-size:1.1rem;color:var(--ink)}
.rv-head a{font-size:.92rem;font-weight:700;color:var(--aqua);text-decoration:underline}
.rv-nav{margin-left:auto;display:flex;gap:8px}
.rv-nav button{width:38px;height:38px;border-radius:50%;border:1px solid var(--line);
  background:#fff;color:var(--ink);font-size:1.2rem;cursor:pointer;line-height:1;
  transition:.16s}
.rv-nav button:hover{border-color:var(--gold);background:var(--gold)}
.rv-track{display:flex;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding-bottom:6px;scrollbar-width:thin}
.rv-card{flex:0 0 300px;scroll-snap-align:start;background:#fff;
  border:1px solid var(--line);border-radius:14px;padding:18px 20px}
.rv-card .rv-stars{color:var(--gold);letter-spacing:1px;font-size:.95rem;margin-bottom:9px}
.rv-text{margin:0 0 14px;font-size:.93rem;line-height:1.6;color:var(--body)}
.rv-who b{display:block;font-size:.92rem;color:var(--ink)}
.rv-who span{font-size:.78rem;color:var(--body)}
@media(max-width:560px){ .rv-card{flex-basis:82%} .rv-nav{display:none} }

/* ------------------------------------------------------------
   Brand-dark section. Used behind the offer cards so the block
   reads as Genies instead of a blank white page. Cards sit on
   the deep navy and lift off it with a hairline and a shadow.
   ------------------------------------------------------------ */
.section-brand{background:var(--ink);color:#fff}
.section-brand h1,.section-brand h2,.section-brand h3{color:#fff}
.section-brand .lead{color:#C3C7E4}
.section-brand .eyebrow{color:var(--cyan)}
.section-brand .eyebrow::before{background:var(--cyan)}
.section-brand .offer{background:#1C2657;border:1px solid rgba(255,255,255,.13);box-shadow:0 22px 48px rgba(3,7,22,.55)}
.section-brand .offer-bottom{background:#1C2657}
.section-brand .offer:hover{border-color:rgba(241,160,6,.45);box-shadow:0 30px 60px rgba(3,7,22,.62)}
.offers-note{margin:30px 0 0;font-size:.9rem;color:#C3C7E4}
.offers-note a{color:var(--gold);text-decoration:underline;text-underline-offset:3px}
.offers-note a:hover{color:var(--gold-dark)}

/* Offer terms grid on the offers page. The conditions live here in full so
   the cards themselves can stay short. */
.offer-terms-grid{display:grid;grid-template-columns:1fr 1fr;gap:20px}
.terms-card{background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);padding:24px 26px 26px}
.terms-card h3{display:flex;align-items:center;justify-content:space-between;gap:14px;margin:0;font-size:1.05rem}
.terms-code{flex:0 0 auto;background:var(--ink);color:var(--gold);font-family:var(--f-head);font-size:.68rem;font-weight:800;letter-spacing:.09em;padding:6px 12px;border-radius:999px}
.terms-card .terms-list li{font-size:.92rem}
.offer-terms-grid > :last-child:nth-child(odd){grid-column:1 / -1}
@media(max-width:860px){.offer-terms-grid{grid-template-columns:1fr}}

/* The real reviews run from 165 characters to just over 1000. Without a clamp
   the whole row grows to the tallest card and the short ones sit in a pool of
   white space. Ten lines, then the name pinned to the bottom of every card. */
.rv-card{display:flex;flex-direction:column}
.rv-text{display:-webkit-box;-webkit-line-clamp:10;-webkit-box-orient:vertical;overflow:hidden}
.rv-who{margin-top:auto}

/* Ask Blake inside the sticky phone bar. The floating pill used to hover just
   above the bar, which crowded the bottom of the screen. One button in the bar
   instead of two stacked on top of each other. */
/* The bar is Call now and Book online. The chat used to be the second button
   and it fought the corner bubble for the same space, so the bar does the two
   things a bar should and the bubble does the chat. */
.bar-book{flex:1;display:flex;align-items:center;justify-content:center;
  padding:11px 10px;border-radius:999px;border:1px solid var(--line);
  background:var(--paper);color:var(--ink);text-decoration:none;
  font-family:var(--f-head);font-weight:700;font-size:.88rem}
.bar-book:active{background:var(--mist)}
.bar-ask{flex:1;display:flex;align-items:center;justify-content:center;gap:9px;
  padding:5px 14px 5px 5px;border-radius:999px;border:1px solid rgba(255,255,255,.16);
  background:var(--ink);color:#fff;font-family:inherit;cursor:pointer}
.bar-ask b{font-family:var(--f-head);font-weight:700;font-size:.88rem;line-height:1}
.bar-ask-face{position:relative;flex:0 0 31px;width:31px;height:31px}
.bar-ask-face img{width:31px;height:31px;border-radius:50%;object-fit:cover;border:2px solid var(--gold)}
.bar-ask:focus-visible{outline:3px solid var(--gold);outline-offset:3px}

/* The line people need right before they hand over a phone number. */
.form-calm{margin:11px 0 0;font-size:.83rem;line-height:1.5;color:var(--body);text-align:center}

/* "What we fix". The visitor's own problem, in a list, before any prose. */
.fix-list{list-style:none;padding:0;margin:0 auto;max-width:900px;
  display:grid;grid-template-columns:1fr 1fr;gap:12px 30px}
.fix-list li{display:flex;gap:12px;align-items:flex-start;font-size:1rem;line-height:1.55;color:var(--ink)}
.fix-list li::before{content:"\2713";flex:0 0 22px;height:22px;margin-top:2px;border-radius:50%;
  background:var(--gold);color:var(--ink);font-size:.78rem;font-weight:800;
  display:flex;align-items:center;justify-content:center}
.fix-cta{display:flex;flex-wrap:wrap;justify-content:center;gap:12px;margin-top:26px}
@media(max-width:760px){.fix-list{grid-template-columns:1fr;gap:11px}}

/* The rating badge is the strongest proof on the page, so it goes where the
   proof lives. Opens the Google listing in a new tab. */
.rating-big{transition:background .18s ease,border-color .18s ease}
.rating-big:hover{background:rgba(241,160,6,.22)}
.rating-big:focus-visible{outline:3px solid var(--gold);outline-offset:3px}
.rb-go{opacity:.6;flex:0 0 13px;margin-left:2px}
.rating-big:hover .rb-go{opacity:1}
.askblake-mail{color:var(--cyan)}

/* ------------------------------------------------------------------
   PHONE LAYOUT: take the boxes off.
   On a phone the page was a column of white cards with borders and
   rounded corners, stacked on alternating white and grey bands, which
   reads as a pile of boxes rather than a page. Everything below strips
   the card chrome so photos and words sit on the background, centres
   the short lines the way people actually read on a phone, and pulls
   the vertical spacing in. Desktop is untouched.
   ------------------------------------------------------------------ */
@media(max-width:760px){
  /* service tiles: photo, then words. No frame around either. */
  .svc{background:transparent;border:0;box-shadow:none;border-radius:0}
  .svc:hover{transform:none;box-shadow:none}
  .svc::before{display:none}
  .svc .thumb{border-radius:18px;overflow:hidden}
  .svc .body{padding:14px 4px 0;text-align:center}
  .svc h3{margin-bottom:5px}
  .grid-4.svc-compact,.grid-3.svc-compact,.grid-4,.grid-3{gap:34px}

  /* photos elsewhere lose the frame too */
  .gal{border-radius:18px}
  .gal-grid{gap:14px}

  /* the family tiles on the services index */
  .svc-fam{background:transparent;border:0;box-shadow:none}
  .svc-cities{justify-content:center}

  /* centre the short lines. Body paragraphs stay left, because long
     centred text is harder to read, not easier. */
  .local-grid>div>h2,.local-grid>div>.eyebrow{text-align:center}
  .local-grid>div>.eyebrow{justify-content:center}
  .local-grid .btn{display:flex;width:100%}

  /* one call to action per row, full width, like a phone expects */
  .hero-btns .btn,.fix-cta .btn,.bigcta .btn{width:100%}
  .hero-btns,.fix-cta{gap:11px}

  /* the booking card was 30px of padding around big fields */
  .book-card{padding:22px 18px;border-radius:18px}
  .field{margin-bottom:14px}
  .field input,.field textarea{padding:12px 13px}
  .field textarea{min-height:76px}

  /* Tighter run into the headline, so the bigger type costs nothing above
     the fold. The call button has to stay on the first screen. */
  /* Tightening this broke the wrap: it split "Google / reviews" across two
     lines mid phrase. Smaller text keeps it on one tidy line and the badge
     reads as a chip rather than a panel. */
  .rating-big{padding:7px 13px;gap:9px}
  .rating-big .stars{font-size:.95rem;letter-spacing:2px}
  .rating-big b{font-size:1.02rem}
  .rating-big span{font-size:.78rem}
  .sixstar-line{font-size:1.02rem;margin-bottom:10px}
  .hero p.lead{font-size:1rem}
  .hero-inner{padding-top:26px;padding-bottom:34px;gap:26px}

  /* Photos were the length problem. A square offer photo at full width is
     354px tall before a word of copy, and there are four of them. */
  .offer-top{aspect-ratio:16/10}
  .offer-bottom{padding:18px 16px 18px}
  .offer-terms{margin-top:12px}
  .offers-grid{gap:16px}
  .svc .thumb{aspect-ratio:16/10}

  /* The rest of the cards. Stacked one per row on a phone, a bordered box
     with its own background is just a box. Hairline between items instead,
     so a list reads as a list. The review carousel keeps its cards, because
     there they scroll sideways and a card is the right shape for that. */
  .oband,.area-card,.dg-item,.wish,.readmore{
    background:transparent;border:0;box-shadow:none;border-radius:0;
    padding-left:0;padding-right:0}
  .oband{border-top:1px solid var(--line);padding:18px 0}
  .oband-grid{gap:0}
  .oband-grid .oband:first-child{border-top:0}
  .dg-item{border-top:1px solid var(--line);padding:18px 0;border-radius:0}
  .dg-list{gap:0}
  .dg-list .dg-item:first-child{border-top:0}
  .area-card{border-top:1px solid var(--line);padding:24px 0 6px}
  .areas-grid>.area-card:first-child{border-top:0}
  .wish{border-top:1px solid rgba(255,255,255,.14);padding:24px 0}
  .wishes .grid-3>.wish:first-child,.wishes .grid-4>.wish:first-child{border-top:0}
  .readmore{border-top:1px solid var(--line);padding:18px 0}
  .readmore:hover{transform:none;box-shadow:none}
  .area-card,.oband,.dg-item{transition:none}
  .bigcta{border-radius:20px;padding:30px 20px}

  /* less air between slabs so it stops reading as a stack */
  .section{padding-top:34px;padding-bottom:34px}
  .steps-wrap .center,.center{margin-bottom:22px!important}
}

/* A still gold button on a page of gold accents does not read as the thing to
   press. A slow ring every few seconds does, and it stops for anyone who has
   asked their phone to reduce motion. */
@keyframes ringpulse{
  0%{transform:scale(1);opacity:.6}
  55%{transform:scale(1.09);opacity:0}
  100%{transform:scale(1.09);opacity:0}
}
.mobilebar .btn-gold,.hero-btns .btn-gold{position:relative}
.mobilebar .btn-gold::after,.hero-btns .btn-gold::after{content:"";position:absolute;
  inset:0;border-radius:inherit;box-shadow:0 0 0 6px rgba(241,160,6,.6);
  pointer-events:none;animation:ringpulse 3.4s ease-out infinite}
.mobilebar .btn-gold:hover,.hero-btns .btn-gold:hover,
.mobilebar .btn-gold:active,.hero-btns .btn-gold:active{animation:none}
@media(prefers-reduced-motion:reduce){
  .mobilebar .btn-gold,.hero-btns .btn-gold{animation:none}
}

/* ------------------------------------------------------------------
   Leak checker, on the leak detection page. Built from the site's own
   parts rather than importing the standalone page's stylesheet.
   ------------------------------------------------------------------ */
.lk-tabs{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:18px}
.lk-tab{background:#fff;border:1.5px solid var(--line);border-radius:14px;padding:13px 12px;
  font-family:var(--f-head);font-weight:800;font-size:.98rem;color:var(--ink);cursor:pointer;
  display:flex;flex-direction:column;gap:3px;align-items:center;transition:border-color .15s ease,background .15s ease}
.lk-tab small{font-family:var(--f-body);font-weight:600;font-size:.72rem;color:var(--body)}
.lk-tab.on{border-color:var(--gold);background:rgba(241,160,6,.10)}
.lk-tab:focus-visible{outline:3px solid var(--gold);outline-offset:2px}
.lk-pane{display:none;background:#fff;border:1px solid var(--line);border-radius:18px;padding:22px}
.lk-pane.on{display:block}
.lk-hint{font-size:.92rem;margin:0 0 16px}
.lk-fields{display:grid;gap:12px;margin-bottom:16px}
.lk-steps{margin:0 0 18px;padding-left:20px;display:flex;flex-direction:column;gap:9px;font-size:.95rem}
.lk-steps b{color:var(--ink)}
.lk-timer{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:18px;
  background:var(--mist);border-radius:14px;padding:14px 16px}
.lk-clock{font-family:var(--f-head);font-size:1.9rem;font-weight:800;color:var(--ink);line-height:1;
  font-variant-numeric:tabular-nums}
.lk-out{display:none}
.lk-out.show{display:block;margin-top:18px;border-radius:14px;padding:18px;border:1px solid var(--line)}
.lk-out h3{margin:0 0 8px;font-size:1.15rem}
.lk-out p{margin:0 0 8px;font-size:.95rem}
.lk-out.ok{background:#EAF7F0;border-color:#B7E3CC}
.lk-out.warn{background:#FFF6E3;border-color:#F2DCA6}
.lk-out.bad{background:#FDECEC;border-color:#F3C4C4}
.lk-note{font-size:.86rem;color:var(--body)}
.lk-stats{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:14px}
.lk-stats div{background:rgba(11,17,37,.05);border-radius:12px;padding:12px;text-align:center}
.lk-stats b{display:block;font-family:var(--f-head);font-size:1.35rem;color:var(--ink);line-height:1.1}
.lk-stats span{font-size:.76rem;color:var(--body)}
.lk-foot{margin:18px 0 0;font-size:.88rem;text-align:center}
.lk-foot a{color:var(--aqua);font-weight:700}
.lk-rebate{display:grid;grid-template-columns:1fr 1fr;gap:22px}
.lk-rebate h3{margin-bottom:8px;font-size:1.1rem}
.lk-rebate p{font-size:.94rem;margin:0 0 10px}
.lk-num a{color:var(--aqua);font-weight:700}
@media(max-width:760px){
  .lk-tabs{grid-template-columns:1fr}
  .lk-pane{padding:18px 16px;border-radius:16px}
  .lk-rebate{grid-template-columns:1fr;gap:18px}
  .lk-stats{grid-template-columns:1fr}
}

/* The ads landing page puts hard proof above the fold rather than after three
   scrolls. Rating, no call out fee, licence number, all in one line. */
.offer-beat{font-family:var(--f-head);font-weight:800;color:#fff;font-size:1.12rem;
  margin:-2px 0 12px;letter-spacing:-.01em}
.urgent-line{margin:0 0 16px;padding:11px 15px;border-radius:12px;font-size:.95rem;
  background:rgba(241,160,6,.13);border:1px solid rgba(241,160,6,.30);color:#FFFFFF}
.urgent-line b{color:var(--gold)}
.trust-chips{list-style:none;padding:0;margin:0;display:flex;flex-wrap:wrap;gap:8px}
.trust-chips li{display:inline-flex;align-items:center;gap:6px;font-size:.82rem;color:#C3C7E4;
  background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.14);
  border-radius:999px;padding:7px 13px}
.trust-chips b{color:#fff;font-family:var(--f-head);font-weight:800}
/* Anywhere the licence, the rating or the no call-out promise is mentioned,
   it goes to the thing that proves it. Underlined faintly so it reads as a
   link without turning the header into a row of blue text. */
.proof-link{color:inherit;text-decoration:underline;text-decoration-color:rgba(255,255,255,.34);
  text-underline-offset:3px}
.proof-link:hover{text-decoration-color:var(--gold)}
.hero-pt{color:inherit;text-decoration:none}
.hero-pt:hover .tick,.hero-pt:focus-visible .tick{background:var(--gold);color:var(--ink)}
a.prob{text-decoration:none;color:inherit;display:block}
.proofbar a{color:inherit;text-decoration:none}
.proofbar a:hover b{color:var(--gold)}

/* every chip goes somewhere: the rating to Google, the call-out to its own
   page, the licence to the QBCC register so it can be checked */
.trust-chips a{display:inline-flex;align-items:center;gap:6px;color:inherit;
  text-decoration:none;cursor:pointer}
.trust-chips li:hover{border-color:rgba(255,255,255,.34);background:rgba(255,255,255,.10)}
.trust-chips a:focus-visible{outline:3px solid var(--gold);outline-offset:4px;border-radius:999px}
.trust-chips li:first-child b{color:var(--gold)}
@media(max-width:760px){
  .trust-chips{gap:7px}
  .trust-chips li{font-size:.78rem;padding:6px 11px}
  .offer-beat{font-size:1rem}
}

/* The play facade, small, at the top of an offer page. Named offer-vid and not
   hero-vid, because hero-vid is already the background video element. A
   vertical Short at full column width would swallow the hero, so it is capped. */
.offer-vid{width:100%;max-width:330px;aspect-ratio:9/16;margin:0 auto;justify-self:center;
  border-radius:18px;overflow:hidden;box-shadow:0 18px 40px rgba(4,10,28,.45);
  border:1px solid rgba(255,255,255,.14)}
/* the button and the player that replaces it both fill the wrapper, so
   pressing play does not resize anything */
.offer-vid > .vid-play,.offer-vid > .vid-frame{width:100%;height:100%;border-radius:0}
@media(max-width:760px){ .offer-vid{max-width:260px;margin:18px auto 0} }

/* A box around the player, so it reads as "watch this about the $249 drain
   clean" rather than a loose tile floating in the hero. */
.offer-vidcard{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.14);
  border-radius:22px;padding:18px 18px 20px;max-width:376px;margin:0 auto;
  box-shadow:0 22px 50px rgba(4,10,28,.42)}
.offer-vidcard-head{text-align:center;margin-bottom:14px}
.offer-vidcard-head .eyebrow{color:var(--gold);margin-bottom:6px;justify-content:center}
.offer-vidcard-head .eyebrow::before{background:var(--gold)}
/* Any heading level, not just h3. The live site uses an h2 here and this rule
   named h3, so the heading kept the global dark heading colour and rendered
   invisible on a dark card. Naming a tag in a rule like this is a trap: the
   markup only has to change once. */
.offer-vidcard-head h1,.offer-vidcard-head h2,
.offer-vidcard-head h2,.offer-vidcard-head h4{color:#fff;font-size:1.12rem;margin:0;line-height:1.25}
@media(max-width:760px){
  .offer-vidcard{padding:15px 15px 17px;border-radius:20px;max-width:300px}
  .offer-vidcard-head h1,.offer-vidcard-head h2,
  .offer-vidcard-head h2,.offer-vidcard-head h4{font-size:1.02rem}
}

/* The promo code was a box as big as the price, which made the price look
   conditional. It is a note now. */
.promo-note{margin:0 0 14px;font-size:.9rem;color:#C3C7E4;max-width:46ch}
.promo-note b{color:var(--gold);font-family:var(--f-head);letter-spacing:.03em}

/* The one review that is about the thing this page is selling. */
/* it flows straight out of the hero, so it keeps the hero's background.
   Styled for white text and put on a white section, it was invisible. */
.pull-rev{background:var(--ink);color:#fff;padding-top:8px;padding-bottom:34px}
.pull-rev figure{margin:0 auto;max-width:640px;text-align:center}
.pull-stars{color:var(--gold);letter-spacing:4px;font-size:1.1rem;margin-bottom:12px}
.pull-rev blockquote{margin:0 0 14px;font-family:var(--f-head);font-weight:700;
  font-size:1.18rem;line-height:1.45;color:#fff;letter-spacing:-.01em}
.pull-rev figcaption b{display:block;color:#fff;font-size:.95rem}
.pull-rev figcaption span{font-size:.8rem;color:#9AA0C4}
@media(max-width:760px){ .pull-rev blockquote{font-size:1.05rem} .pull-rev{padding-top:26px} }
/* Two more real reviews under the big one. Same band, smaller type, so the
   proof stacks up without the section running half a screen tall. */
.pull-more{display:grid;grid-template-columns:1fr 1fr;gap:30px;max-width:900px;
  margin:32px auto 0;padding-top:28px;border-top:1px solid rgba(255,255,255,.14)}
.pull-sm{max-width:none}
.pull-sm .pull-stars{font-size:.9rem;letter-spacing:3px;margin-bottom:9px}
.pull-rev .pull-sm blockquote{font-size:1rem;line-height:1.6;font-weight:600;margin-bottom:11px}
.pull-sm figcaption b{font-size:.9rem}
@media(max-width:760px){
  .pull-more{grid-template-columns:1fr;gap:26px;margin-top:26px;padding-top:24px}
  .pull-rev .pull-sm blockquote{font-size:.98rem}
}

/* The offer, pinned once the hero has scrolled away, so the price and the
   phone stay on screen the whole way down. Sits under the sticky header,
   which is why the top offset is measured at runtime rather than guessed. */
/* Pinned inside the header rather than positioned from a measurement of it,
   so the two cannot drift apart and there is no gap to show text through.
   It rolls open on scroll instead of sliding down over the page. */
.offerbar{max-height:0;overflow:hidden;opacity:0;
  border-top:1px solid rgba(255,255,255,.10);
  background:#0A1330;
  transition:max-height .28s cubic-bezier(.22,.61,.36,1),opacity .2s ease}
.offerbar.on{max-height:120px;opacity:1}
.offerbar .wrap{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding-top:10px;padding-bottom:10px}
.offerbar-what{color:#fff;font-family:var(--f-head);font-size:1rem;font-weight:700;
  line-height:1.2;min-width:0}
.offerbar-what b{color:var(--gold);font-size:1.18rem;margin-right:6px}
.offerbar .btn{padding:11px 20px;font-size:.95rem;flex:0 0 auto}
@media(max-width:560px){
  .offerbar .wrap{gap:10px;padding-top:8px;padding-bottom:8px}
  .offerbar-what{font-size:.86rem}
  .offerbar-what b{font-size:1.02rem;display:block;margin:0}
  .offerbar .btn{padding:10px 16px;font-size:.9rem}
}
@media(prefers-reduced-motion:reduce){ .offerbar{transition:none} }

/* The offer pages carry a photo of a plumber doing the actual job behind the
   headline, so the picture is lifted and the wash over it pulled back. Any
   further and the white text stops being comfortable to read. */

/* While the chat is open, the Ask Blake button and the bottom bar get out of
   the way, or the panel's close button and the launcher sit on top of each
   other in the same corner. */
body.chat-open .askblake,
body.chat-open .askbub,
body.chat-open .mobilebar{opacity:0;pointer-events:none;visibility:hidden}

/* The about story runs to about 370 words and the photo beside it is 390px
   tall, so the picture used to sit in the middle of a column with 600px of
   nothing under it. It follows you down the page instead, and the opening
   paragraph is bigger because it is the bit people actually read. */
.about-story .local-grid{align-items:start}
.about-story .gal{position:sticky;top:calc(var(--header-h,116px) + 22px)}
.about-story .lead{font-size:1.16rem;line-height:1.6;color:var(--ink);font-weight:600}
.about-story p{margin-bottom:14px}
@media(max-width:900px){ .about-story .gal{position:static} }

/* The three of them, one card each. Photos are cropped so the face is big
   enough to recognise at card size, which the wide shots were not. */
.team-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:22px;max-width:1000px;margin:0 auto}
.mate{margin:0;background:var(--paper);border:1px solid var(--line);border-radius:var(--radius);
  overflow:hidden;box-shadow:var(--shadow)}
.mate img{display:block;width:100%;aspect-ratio:4/5;object-fit:cover}
.mate figcaption{padding:18px 20px 22px}
.mate b{display:block;font-family:var(--f-head);font-size:1.2rem;color:var(--ink);line-height:1.2}
.mate span{display:block;color:var(--aqua);font-family:var(--f-head);font-weight:700;
  font-size:.85rem;letter-spacing:.4px;margin:3px 0 10px}
.mate p{margin:0;font-size:.95rem;line-height:1.6;color:var(--body)}
@media(max-width:900px){ .team-grid{grid-template-columns:1fr 1fr;gap:16px} }
@media(max-width:600px){ .team-grid{grid-template-columns:1fr;max-width:380px} }

/* The brands, as names rather than logos. Thirty trademarks we do not have
   artwork for, and a wall of other people's logos would swamp the page. */
.brands{background:var(--mist)}
.brands h2{font-size:clamp(1.25rem,2.4vw,1.75rem)}
.brand-list{list-style:none;display:flex;flex-wrap:wrap;justify-content:center;
  gap:9px;padding:0;margin:0 auto;max-width:920px}
.brand-list li{font-family:var(--f-head);font-weight:700;font-size:.9rem;color:var(--ink);
  background:var(--paper);border:1px solid var(--line);border-radius:999px;padding:7px 14px}
@media(max-width:560px){ .brand-list{gap:7px} .brand-list li{font-size:.83rem;padding:6px 11px} }

/* The promises, as badges. Four short ones read faster than a paragraph, and
   every one of them is something we can actually be held to. */
.gtees{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:14px}
.gtee{border:1px solid var(--line);border-radius:14px;padding:16px 18px;text-align:center;background:var(--paper)}
.gtee b{display:block;font-family:var(--f-head);font-size:1.02rem;color:var(--ink);margin-bottom:5px}
.gtee span{font-size:.94rem;line-height:1.5;color:var(--body)}

/* How soon, and do you own the place. Radio buttons dressed as chips, because
   a tap is easier than a dropdown on a phone and Blake can sort the callbacks
   before he rings anybody. */

/* On a phone the top of an offer page was the logo row and then the price bar,
   which is a lot of the screen gone before any content and was cutting the top
   off the video. So the moment the price bar opens the logo row folds away and
   the top of the screen is one bar. The row stays until then, so the page never
   opens with a header that says nothing. */
@media(max-width:760px){
  .offer-page header .navbar{max-height:200px;overflow:hidden;
    transition:max-height .22s ease,opacity .18s ease,padding .22s ease}
  .offer-page header.bar-on .navbar{max-height:0;opacity:0;pointer-events:none;
    padding-top:0;padding-bottom:0}
  .offer-page header.bar-on{--nav-h:0px}
}
@media(max-width:760px) and (prefers-reduced-motion:reduce){
  .offer-page header .navbar{transition:none}
}

/* Landing page shell. No menu, no suburb list, no footer full of links.
   Somebody who clicked a paid ad has one job to do and every link is a way
   to not do it. The logo still goes home so the header does not read as
   broken, and the legal links stay because they have to. */
.header-lite .burger{display:none}
.header-lite .nav-cta{margin-left:auto}
.foot-lite{background:var(--ink);color:#C3C7E4;text-align:center;padding:34px 0 30px}
.foot-lite .btn{margin-bottom:20px}
.foot-lite p{margin:0 0 6px;font-size:.85rem}
.foot-lite-legal a{color:#9AA0C4;text-decoration:underline;text-underline-offset:3px}
.foot-lite-legal a:hover{color:#fff}

/* A bare play triangle asks somebody to work out what it does. This says it. */
/* Genies purple with a gold outline, which is the brand rather than a plain
   gold circle, and it says what it does instead of leaving a triangle to
   explain itself. */
.vid-cue{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:2;
  display:inline-flex;align-items:center;gap:8px;white-space:nowrap;
  background:var(--magenta);color:#fff;border:2px solid var(--gold);border-radius:999px;
  padding:11px 20px 11px 16px;font-family:var(--f-head);font-weight:800;font-size:.95rem;
  box-shadow:0 10px 26px rgba(4,10,28,.55);transition:transform .18s ease,background .18s ease}
.vid-cue svg{color:var(--gold)}
.vid-play:hover .vid-cue{background:#285BFE}
.vid-play:hover .vid-cue{transform:translate(-50%,-50%) scale(1.05)}
@media(max-width:560px){ .vid-cue{font-size:.86rem;padding:10px 15px 10px 12px;gap:6px} }

/* With a fixed header, an anchor jump lands underneath it unless every target
   is told to leave room. */
[id]{scroll-margin-top:calc(var(--header-h,116px) + 12px)}

@media(max-width:380px){
  /* on the very narrow ones let them stack rather than squeeze */
  .hero-offers{grid-template-columns:1fr}
}

/* The offer hero is one centred column at every width, the way a landing page
   reads: claim, proof, the offer, the button, then the video. It used to be
   two columns with the words on the left, which is right for a website page
   and wrong for a page somebody landed on from an ad. */
.offer-hero{display:flex;flex-direction:column;align-items:center;text-align:center;
  max-width:720px;margin-left:auto;margin-right:auto;gap:0}
.offer-hero > div{width:100%}
.offer-hero .offer-vidcard{order:2;margin:22px auto 0}
.offer-hero .hero-extras{order:3;margin-top:18px}
.offer-hero .hero-btns{justify-content:center}
.offer-hero .trust-chips{justify-content:center}
.offer-hero .promo-note{margin-left:auto;margin-right:auto}
.offer-hero .urgent-line{max-width:46ch;margin-left:auto;margin-right:auto}
.offer-hero .lead{margin-left:auto;margin-right:auto}
.offer-hero .sixstar-line,.offer-hero h1,.offer-hero .offer-beat{text-align:center}

/* and the rest of the offer page follows the same centre line */
.offer-page .local-grid,.offer-page .prob,.offer-page .terms-list li{text-align:center}
.offer-page .terms-list li{justify-content:center}
.offer-page .lead{margin-left:auto;margin-right:auto}
.offer-page .local-grid{grid-template-columns:1fr;gap:26px;justify-items:center}
.offer-page .local-grid>div{max-width:640px}
.offer-page .local-grid .eyebrow{justify-content:center}
.offer-page .local-grid .gal{width:100%;max-width:560px}
.offer-page .local-grid .btn{margin-left:auto;margin-right:auto}
.offer-page .section>.wrap>.eyebrow{justify-content:center;text-align:center}
.offer-page .section>.wrap>h2,.offer-page .section>.wrap>p{text-align:center}

/* ------------------------------------------------------------
   Testimonials page and sitemap page. Added 3 Sep 2026.

   The carousel cards are a fixed 300px wide and clamp the text
   at ten lines, which is right for a scrolling row and wrong for
   a page whose whole job is the full review. .tm-card undoes both
   inside .tm-grid only, so the carousel elsewhere is untouched.

   No new colours. Everything below uses the ten already at the
   top of this file.
   ------------------------------------------------------------ */
.tm-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px;align-items:start}
.tm-grid .tm-card{flex:none;width:auto}
.tm-grid .tm-card .rv-text{display:block;-webkit-line-clamp:none;overflow:visible}
@media(max-width:900px){ .tm-grid{grid-template-columns:repeat(2,1fr)} }
@media(max-width:620px){ .tm-grid{grid-template-columns:1fr} }

.sm-wrap{display:grid;gap:34px;margin-top:30px}
.sm-group h2{font-size:clamp(1.15rem,2.2vw,1.45rem);margin:0 0 4px}
.sm-note{margin:0 0 12px;font-size:.9rem;color:var(--body)}
.sm-links{display:grid;grid-template-columns:repeat(4,1fr);gap:6px 22px;
  border-top:1px solid var(--line);padding-top:14px;margin-top:10px}
.sm-links a{font-size:.92rem;line-height:1.75;color:var(--body);text-decoration:none}
.sm-links a:hover{color:var(--aqua);text-decoration:underline}
@media(max-width:900px){ .sm-links{grid-template-columns:repeat(2,1fr)} }
@media(max-width:560px){ .sm-links{grid-template-columns:1fr} }

/* A gallery row of two rather than three. The grid is three across, so a page
   with two photos was leaving an empty third cell that read as a picture that
   had failed to load. Only applies where the template asks for it. */
.gal-grid.gal-2{grid-template-columns:repeat(2,1fr)}
@media(max-width:700px){ .gal-grid.gal-2{grid-template-columns:1fr} }


/* Bolder headings, asked for 3 Sep 2026. Plus Jakarta Sans stops at 800 and
   h1 and h2 were already there, so the lift is h3 and the eyebrow up to 800,
   and the big two pulled a touch tighter so they read heavier at the same
   weight. */
h3,.eyebrow{font-weight:800}
h1,h2{letter-spacing:-.03em}

/* The palette swap turned the stars white, because they inherit from
   .rating-big span and that tint became white. They are the gold, as Blake's
   own screenshots show. */
.rating-big .stars{color:var(--gold)}

/* The neighbours card on the two region pages sits on white. Its ticks and
   tint were the aqua, which is a dark ground colour and measured 1.3:1 on
   white. They take the link blue there. */
.nb-card{background:rgba(40,91,254,.06);border-color:rgba(40,91,254,.30)}
.nb-card li svg{color:var(--aqua)}

/* The secondary button on dark ground. It had a 35% white outline that
   vanished into the hero photo. It takes the aqua at the same 3px as the
   purple button beside it, so the two read as a pair. Asked for 3 Sep 2026. */
.btn-ghost{border-color:var(--cyan);border-width:3px;color:#fff;background:rgba(94,245,245,.06)}
.btn-ghost:hover{background:rgba(94,245,245,.16);border-color:var(--cyan);color:#fff}

/* Three things a full-page contrast and overlap sweep turned up, 3 Sep 2026.

   The eyebrow is the link blue, which is right on white and only 3.6:1 on the
   dark reasons band. It takes the aqua there. */
.wishes .eyebrow{color:var(--cyan)}
.wishes .eyebrow::before{background:var(--cyan)}

/* On a phone the Ask Blake button sat on top of the sticky call bar and
   covered part of it. It lifts clear of the bar instead. */
@media(max-width:760px){
  .askwrap{bottom:calc(env(safe-area-inset-bottom, 0px) + 86px)}

  /* On a phone the full button was about 190px wide and sat over two of the
     six offer chips, so a third of the offers were hidden behind it. It keeps
     Blake's face, which is the point of it, and drops the words. The label is
     still there for a screen reader through the button's aria-label. */
  .askblake-txt{display:none}
  .askblake{padding:6px;gap:0;border-radius:999px}
}

/* On a phone the hero stacks to one column and everything in it was still
   ragged against the left edge. Blake asked for it centred. Only below the
   breakpoint where the hero loses its second column: on a desktop the text
   sits beside the booking form and belongs on the left. The offer chips keep
   their own alignment, because a price and its label read better as a pair
   than stacked in the middle of a box. */
@media(max-width:1024px){
  .hero-inner > div:first-child{text-align:center}
  .hero h1,.h1-sub{text-align:center}
  .hero-btns{justify-content:center}
  .hero-points{justify-content:center}
  .sixstar-line{justify-content:center}
  .hero .lead{margin-left:auto;margin-right:auto}
}

/* ------------------------------------------------------------
   Readable text and thumb-sized targets, everywhere. 3 Sep 2026.

   A sweep of every page template at 375 and at 1280 found the same
   handful of problems on all of them, because they all come out of
   the same templates. Fixing them here fixes all 262 pages.

   Nothing below changes a colour, a layout or a word. It raises text
   that was under 12px and gives standalone links enough height to hit
   with a thumb. Genies advertises a seniors discount, so small type is
   not a neutral choice here.
   ------------------------------------------------------------ */

/* Type floor. These were 10.2px to 11.8px. */
.offer-tag{font-size:.75rem}
.promo-label{font-size:.75rem}
.avail-time{font-size:.75rem}
.oband-go{font-size:.75rem}
.phone-link small{font-size:.75rem}
.askblake-txt small{font-size:.75rem}

/* Thumb targets on phones. Only standalone links get padding, never a
   link inside a sentence, which would break the line spacing. */
@media(max-width:760px){
  .avail{min-height:44px}
  .allofs,.rv-head a,.proof-link{display:inline-flex;align-items:center;min-height:44px}
  .rating-big{min-height:44px}
}

/* Two links the first pass missed, because neither carries a class. The
   services link at the end of the brands band on every suburb page, and the
   rating line in the offer page's trust strip. Both were about 20px tall. */
@media(max-width:760px){
  .brands .center a{display:inline-flex;align-items:center;min-height:44px}
  .trust-chips a{display:inline-flex;align-items:center;min-height:44px}
  .foot-lite-legal a{display:inline-flex;align-items:center;min-height:44px}
}

/* The gold reads at about 2:1 on white, which is fine for a star that everyone
   recognises by shape and poor for anything you have to read. The stars get a
   thin outline so they hold their shape on a light background without changing
   the brand colour. */
.rv-stars{-webkit-text-stroke:.4px rgba(122,90,2,.55);text-shadow:0 0 1px rgba(122,90,2,.35)}
.rvband .rv-stars,.rv-head .rv-stars{-webkit-text-stroke:0;text-shadow:none}


/* ---------------------------------------------- the review numbers count up
   The rating and the review count climb to their real figures the first time
   somebody scrolls to them. 200 reviews at 5.0 is the strongest thing on this
   site and it was being scrolled past.

   tabular-nums matters more than it sounds: without it every digit is a
   different width, so the number jitters as it counts and drags the line
   around with it. */
.rv-head b[data-count],.rv-head a[data-count]{font-variant-numeric:tabular-nums}

/* Anybody who has asked for less motion gets the finished number, immediately. */
@media(prefers-reduced-motion:reduce){
  .rv-head b[data-count],.rv-head a[data-count]{animation:none}
}

/* Was an h3 for its size, not its rank. It follows the page h1, so it is an
   h2 now and this holds the look it always had. */
.ask-h{font-size:1.05rem;letter-spacing:-.02em;margin:0 0 .5em}

/* Said to a screen reader, drawn for nobody. The star glyphs beside a rating are
   a picture of a number that is already written next to them, so they are hidden
   from assistive tech and the rating is given as words instead. Gold on white is
   2.15 to 1 and cannot reach 4.5 without turning brown, and a brown star is not
   a star. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}


/* ---------------------------------------------------------------- Ask Blake
   The chat panel. Ours, so it gets the site's own type and palette rather than
   a third party's grey. It sits inside .askwrap above the button, which is why
   the open state hides the button and not the wrapper.

   Sized to the phone first: most people who open this are standing next to the
   problem holding one. On a phone it takes the width and stops short of the
   top so the page behind is still visibly there. */
/* display:flex on a class beats the browser's own [hidden] rule, so the panel
   sat open on every page until this was put back. */
.askchat[hidden]{display:none}
.askchat{
  width:min(370px,calc(100vw - 24px));
  display:flex;flex-direction:column;overflow:hidden;
  background:var(--paper);border:1px solid var(--line);border-radius:18px;
  box-shadow:0 24px 60px rgba(4,10,28,.42);
  animation:askpop .28s cubic-bezier(.22,.9,.34,1.2) both;
}
.askchat-top{
  display:flex;align-items:center;gap:11px;padding:12px 13px;
  background:var(--ink);color:#fff;
}
.askchat-face{width:36px;height:36px;border-radius:50%;object-fit:cover;
  border:2px solid var(--gold);flex:0 0 36px}
.askchat-who{flex:1;min-width:0}
.askchat-who b{display:block;font-family:var(--f-head);font-size:.95rem;line-height:1.15}
.askchat-who small{display:block;font-size:.72rem;color:#9AA0C4;margin-top:1px}
.askchat-x{width:30px;height:30px;flex:0 0 30px;border:0;border-radius:50%;
  background:rgba(255,255,255,.1);color:#fff;font-size:20px;line-height:1;cursor:pointer}
.askchat-x:hover{background:rgba(255,255,255,.2)}

.askchat-log{
  flex:1;min-height:180px;max-height:min(52vh,420px);overflow-y:auto;
  padding:14px 13px;display:flex;flex-direction:column;gap:9px;
  background:var(--mist);
  overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
}
.askchat-msg{
  max-width:84%;padding:9px 13px;border-radius:15px;font-size:.9rem;line-height:1.5;
  white-space:pre-wrap;overflow-wrap:anywhere;
}
.askchat-msg.them{align-self:flex-start;background:var(--paper);color:var(--ink);
  border:1px solid var(--line);border-bottom-left-radius:5px}
.askchat-msg.you{align-self:flex-end;background:var(--magenta);color:#fff;
  border-bottom-right-radius:5px}
/* A refusal or an outage. Said in the conversation rather than an alert box,
   because that is where the person is looking. */
.askchat-msg.oops{align-self:center;max-width:100%;text-align:center;
  background:transparent;border:0;color:var(--body);font-size:.82rem;padding:2px 6px}

/* Three dots while the answer is being written. */
.askchat-dots{align-self:flex-start;display:flex;gap:4px;padding:12px 14px;
  background:var(--paper);border:1px solid var(--line);border-radius:15px;
  border-bottom-left-radius:5px}
.askchat-dots i{width:6px;height:6px;border-radius:50%;background:#9AA0C4;
  animation:askdot 1.1s infinite ease-in-out both}
.askchat-dots i:nth-child(2){animation-delay:.15s}
.askchat-dots i:nth-child(3){animation-delay:.3s}
@keyframes askdot{0%,72%,100%{opacity:.28;transform:translateY(0)}
  36%{opacity:1;transform:translateY(-3px)}}


/* The photo button. Same size and shape as Send so the row stays even, but
   quiet rather than gold: sending a picture is the helpful extra, not the
   thing we are asking them to do. A photo of a hot water unit tells the
   plumber more than three messages describing it. */
.askchat-clip{flex:0 0 38px;width:38px;height:38px;border:0;border-radius:50%;
  background:none;color:var(--ink);opacity:.62;cursor:pointer;
  display:flex;align-items:center;justify-content:center;transition:opacity .15s}
.askchat-clip:hover,.askchat-clip:focus-visible{opacity:1}
.askchat-clip:focus-visible{outline:2px solid var(--aqua);outline-offset:2px}
.askchat-clip[disabled]{opacity:.3;cursor:default}
/* What they picked, before it goes. Small, so the panel does not jump. */
.askchat-pend{display:flex;align-items:center;gap:8px;padding:8px 12px 0;font-size:.8rem;color:var(--ink)}
.askchat-pend img{width:34px;height:34px;border-radius:8px;object-fit:cover}
.askchat-pend button{border:0;background:none;color:var(--ink);opacity:.6;cursor:pointer;font-size:1.1rem;line-height:1}
/* A photo inside a message bubble. Capped so a portrait shot cannot fill the
   panel and push the conversation off screen. */
.askchat-msg img{display:block;max-width:100%;max-height:220px;border-radius:10px;margin-top:6px}

.askchat-ask{display:flex;align-items:flex-end;gap:8px;padding:10px;
  background:var(--paper);border-top:1px solid var(--line)}
.askchat-ask textarea{
  flex:1;resize:none;max-height:104px;font:inherit;font-size:16px;line-height:1.45;
  color:var(--ink);background:var(--mist);border:1px solid var(--line);
  border-radius:13px;padding:9px 12px;
}
.askchat-ask textarea:focus{outline:none;border-color:var(--magenta);background:var(--paper)}
.askchat-go{flex:0 0 40px;width:40px;height:40px;border:0;border-radius:50%;
  background:var(--magenta);color:#fff;cursor:pointer;
  display:grid;place-items:center;transition:background .15s ease}
.askchat-go:hover{background:var(--aqua)}
.askchat-go:disabled{background:var(--line);color:#8890AE;cursor:not-allowed}
.askchat-go:focus-visible,.askchat-x:focus-visible{outline:3px solid var(--gold);outline-offset:2px}

@media(max-width:760px){
  .askchat{width:calc(100vw - 24px)}
  .askchat-log{max-height:calc(100vh - 290px);min-height:150px}
}
@media(prefers-reduced-motion:reduce){
  .askchat{animation:none}
  .askchat-dots i{animation:none;opacity:.55}
}

/* The step cards on the service-plus-suburb pages. Most of those pages have
   four steps and a few have five, so this fits the row to the count instead
   of leaving a hole on the end of a fixed four column grid. */
.steps{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:20px}
@media(max-width:1024px){.steps{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.steps{grid-template-columns:1fr}}

/* "What we fix" on the service-plus-suburb pages runs to four, five or six
   items depending on the suburb. A fixed three column grid leaves a gap on the
   end of the last row, which reads as something that failed to load. This lays
   the same cards out in rows of three and centres whatever is left over. */
.probs-fit{display:flex;flex-wrap:wrap;justify-content:center;gap:16px}
.probs-fit .prob{flex:1 1 292px;max-width:calc(33.333% - 11px)}
@media(max-width:900px){.probs-fit .prob{max-width:calc(50% - 8px)}}
@media(max-width:560px){.probs-fit .prob{max-width:100%;flex-basis:100%}}
