/* ============================================================================
   PICK A BLOCK BUILDING SERVICES LTD  —  v3
   Principles, in order:
     1. The photography and the film are the subject. Everything else gets out
        of the way. No overlays, no grids, no texture on top of the picture.
     2. Type is quiet. Nothing shouts. Headings are mid-weight and mid-scale.
     3. Light page, dark anchors. Gold is the client's own logo colour and is
        used as an accent on dark only, never as a theme.
   Mobile first. min-width queries only.
   ========================================================================= */

@font-face {
  font-family: 'Archivo';
  src: url('fonts/archivo-var.woff2') format('woff2');
  font-weight: 400 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Mulish';
  src: url('fonts/mulish-var.woff2') format('woff2');
  font-weight: 400 800; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Spline Sans Mono';
  src: url('fonts/spline-sans-mono-var.woff2') format('woff2');
  font-weight: 400 500; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* The display face. High-contrast serif for the big statements only; Archivo
   stays for the working headings and UI, Mulish for body. Serif + sans + a
   mono eyebrow is the editorial hierarchy that reads expensive, and it is the
   one thing that separates a good trades site from an architect's. */
@font-face {
  font-family: 'Playfair Display';
  src: url('fonts/playfair-var.woff2') format('woff2');
  font-weight: 400 900; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face { font-family: 'Playfair Fb'; src: local('Georgia'), local('Times New Roman'); size-adjust: 108%; ascent-override: 95%; descent-override: 23%; line-gap-override: 0%; }
@font-face { font-family: 'Archivo Fb'; src: local('Helvetica Neue'), local('Arial'); size-adjust: 96%; ascent-override: 94%; descent-override: 24%; line-gap-override: 0%; }
@font-face { font-family: 'Mulish Fb';  src: local('Helvetica Neue'), local('Arial'); size-adjust: 98%; ascent-override: 96%; descent-override: 25%; line-gap-override: 0%; }
@font-face { font-family: 'Mono Fb';    src: local('SF Mono'), local('Menlo'), local('Consolas'); size-adjust: 97%; }

:root {
  --paper:     #FFFFFF;
  --paper-2:   #F4F3F1;   /* quiet alternate band */
  --text:      #1A1815;   /* 16.4:1 on white */
  --text-mute: #5C574E;   /* 6.6:1 on white */
  --line:      #E4E1DB;

  --ink:       #0F0D0A;   /* dark anchors: hero, one band, footer */
  --ink-2:     #1A1712;
  --ink-line:  #2E2820;
  --bone:      #EFEDE8;
  --bone-mute: #ADA69A;

  --gold:      #EEB815;   /* the logo's own flat gold, sampled from the 06 Aug
                             designer file (median of the BLOCK letters).
                             dark bands only: 10.1:1 on ink, fails on white */
  --gold-ink:  #7A5A0D;   /* gold as text on light. 5.3:1 */

  --f-disp: 'Playfair Display', 'Playfair Fb', Georgia, 'Times New Roman', serif;
  --f-head: 'Archivo', 'Archivo Fb', Helvetica, Arial, sans-serif;
  --f-body: 'Mulish', 'Mulish Fb', Helvetica, Arial, sans-serif;
  --f-mono: 'Spline Sans Mono', 'Mono Fb', ui-monospace, Menlo, monospace;

  /* deliberately restrained. nothing here shouts. */
  --fs-hero:  clamp(2.2rem, 1.25rem + 3.1vw, 3.6rem);
  --fs-h1:    clamp(1.8rem, 1.25rem + 1.9vw, 2.7rem);
  --fs-h2:    clamp(1.45rem, 1.15rem + 1.15vw, 2.1rem);
  --fs-h3:    clamp(1.1rem, 1.03rem + .38vw, 1.35rem);
  --fs-lead:  clamp(1.05rem, 1rem + .32vw, 1.2rem);
  --fs-body:  1.0625rem;
  --fs-small: .875rem;
  --fs-mono:  .75rem;

  --sp-sm: 20px; --sp-md: 34px; --sp-lg: 56px; --sp-xl: 80px; --sp-2xl: 104px;
  --gut: 22px;
  --maxw: 1280px;

  --ease: cubic-bezier(.22,.61,.36,1);
  --hdr-h: 64px;
  --bar-h: 60px;
}
@media (min-width: 40em) {
  :root { --sp-sm: 26px; --sp-md: 48px; --sp-lg: 80px; --sp-xl: 112px; --sp-2xl: 148px; --gut: 34px; }
}
@media (min-width: 64em) {
  :root { --gut: clamp(40px, 5vw, 84px); --hdr-h: 78px; }
}

/* --- Reset -------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--paper); color: var(--text);
  font-family: var(--f-body); font-size: var(--fs-body); line-height: 1.7;
  -webkit-font-smoothing: antialiased; overflow-wrap: break-word;
  padding-bottom: var(--bar-h);
}
@media (min-width: 64em) { body { padding-bottom: 0; } }
img, video, svg { display: block; max-width: 100%; }
img, video { height: auto; }
a { color: inherit; text-underline-offset: 3px; }
button { font: inherit; color: inherit; }
h1, h2, h3, h4 { margin: 0; font-size: inherit; font-weight: inherit; }
p { margin: 0 0 1.05em; }
ul, ol { margin: 0; padding: 0; list-style: none; }
figure { margin: 0; }
table { border-collapse: collapse; }

:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; border-radius: 1px; }
.band--ink :focus-visible, .hero :focus-visible, .ftr :focus-visible { outline-color: var(--gold); }

.vh { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.skip {
  position: fixed; left: 12px; top: -80px; z-index: 200;
  background: var(--text); color: #fff; padding: 12px 20px; font-weight: 700; text-decoration: none;
}
.skip:focus { top: 12px; }

/* --- Type --------------------------------------------------------------- */
.t-hero, .t-h1, .t-h2, .t-h3 { font-family: var(--f-head); font-weight: 600; }
/* The three big sizes carry the serif. .t-h3 and everything smaller stays sans
   — a serif at UI size reads fussy, not expensive. */
.t-hero, .t-h1, .t-h2 { font-family: var(--f-disp); font-weight: 500; }
.t-hero { font-size: var(--fs-hero); line-height: 1.04; letter-spacing: -.014em; }
.t-h1   { font-size: var(--fs-h1);   line-height: 1.08; letter-spacing: -.012em; }
.t-h2   { font-size: var(--fs-h2);   line-height: 1.14; letter-spacing: -.01em;  }
.t-h3   { font-size: var(--fs-h3);   line-height: 1.3;  letter-spacing: -.005em; }
.lead   { font-size: var(--fs-lead); line-height: 1.6; color: var(--text-mute); max-width: 46ch; }
.prose  { max-width: 66ch; }
.prose p { color: var(--text-mute); }
.mono {
  font-family: var(--f-mono); font-size: var(--fs-mono); font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; font-variant-numeric: tabular-nums;
  color: var(--text-mute);
}

/* the only section marker: a short rule. no eyebrow labels, no codes. */
.krule { display: block; width: 30px; height: 2px; background: var(--gold-ink); margin-bottom: 20px; }
.band--ink .krule, .hero .krule { background: var(--gold); }

/* --- Layout ------------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.band--ink   { background: var(--ink);   color: var(--bone); }
.band--quiet { background: var(--paper-2); }
.band--ink .lead, .band--ink .prose p { color: var(--bone-mute); }
.band--ink .mono { color: var(--bone-mute); }

.pt-md { padding-top: var(--sp-md); }    .pb-md { padding-bottom: var(--sp-md); }
.pt-lg { padding-top: var(--sp-lg); }    .pb-lg { padding-bottom: var(--sp-lg); }
.pt-xl { padding-top: var(--sp-xl); }    .pb-xl { padding-bottom: var(--sp-xl); }
.pt-2xl{ padding-top: var(--sp-2xl); }   .pb-2xl{ padding-bottom: var(--sp-2xl); }

/* --- Buttons: dark on light, gold on dark ------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 0 24px;
  font-family: var(--f-body); font-weight: 700; font-size: .95rem;
  text-decoration: none; border: 1px solid transparent; border-radius: 2px;
  cursor: pointer; text-align: center;
  transition: background-color .18s var(--ease), color .18s var(--ease), border-color .18s var(--ease);
}
.btn--solid { background: var(--text); color: #fff; }
.btn--solid:hover { background: #000; }
.btn--line  { background: transparent; color: var(--text); border-color: #C9C4BA; }
.btn--line:hover { border-color: var(--text); }
.band--ink .btn--solid, .hero .btn--solid { background: var(--gold); color: var(--ink); }
.band--ink .btn--solid:hover, .hero .btn--solid:hover { background: #F7CC4B; }
.band--ink .btn--line, .hero .btn--line { color: #fff; border-color: rgba(255,255,255,.55); }
.band--ink .btn--line:hover, .hero .btn--line:hover { background: rgba(255,255,255,.1); border-color: #fff; }
.btns { display: flex; flex-wrap: wrap; gap: 10px; }
.btns > .btn { flex: 1 1 100%; }
@media (min-width: 30em) { .btns > .btn { flex: 0 0 auto; } }

.tlink { display: inline-block; font-weight: 700; text-decoration: none; border-bottom: 1px solid var(--gold-ink); padding-bottom: 2px; }
.tlink:hover { border-bottom-width: 2px; }
.band--ink .tlink, .ftr .tlink { border-color: var(--gold); color: var(--bone); }

/* --- Header ------------------------------------------------------------- */
.hdr {
  position: fixed; inset-inline: 0; top: 0; z-index: 60; height: var(--hdr-h);
  background: transparent;
  transition: background-color .22s linear, height .22s linear;
}
/* The scrim extends 64px past the bar so it holds ~0.8 alpha where the text
   actually sits and then fades softly, instead of decaying across the text. */
.hdr::before {
  content: ""; position: absolute; inset: 0 0 -64px 0; z-index: -1; pointer-events: none;
  background: linear-gradient(180deg, rgba(15,13,10,.92) 0%, rgba(15,13,10,.84) 44%,
              rgba(15,13,10,.48) 74%, rgba(15,13,10,0) 100%);
}
[data-hdr="solid"] .hdr::before, [data-hdr="open"] .hdr::before { display: none; }
.hdr__tel { text-shadow: 0 1px 6px rgba(15,13,10,.55); }
[data-hdr="solid"] .hdr__tel { text-shadow: none; }
.hdr__in { display: flex; align-items: center; gap: 14px; height: 100%; min-width: 0; }
[data-hdr="solid"] .hdr, [data-hdr="open"] .hdr {
  background: var(--ink); border-bottom: 1px solid var(--ink-line);
}
@media (min-width: 64em) { [data-hdr="solid"] .hdr { height: 64px; } }

.logo { display: flex; align-items: center; text-decoration: none; margin-right: auto; min-width: 0; }
/* the real lockup: height-led, width follows the 842x156 intrinsic ratio.
   a soft shadow does for the image what text-shadow did for the old lettering
   while the header sits over the film. */
.logo img { height: 34px; width: auto; flex: 0 0 auto; filter: drop-shadow(0 1px 5px rgba(15,13,10,.55)); }
[data-hdr="solid"] .logo img { filter: none; }
@media (min-width: 26em) { .logo img { height: 38px; } }
@media (min-width: 64em) { .logo img { height: 46px; } }

/* two numbers, stacked. the landline leads, agreed with Kyren 5 Aug. */
.hdr__tels { display: flex; flex-direction: column; align-items: flex-end; justify-content: center; }
.hdr__tel {
  display: inline-flex; align-items: center; min-height: 22px; padding: 0 4px;
  font-family: var(--f-mono); font-size: .78rem; font-weight: 500;
  color: #fff; text-decoration: none; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.hdr__tel--mob { color: rgba(255,255,255,.78); }
.hdr__tel:hover { color: var(--gold); }
.hdr__cta { display: none; background: transparent; color: #fff; border-color: rgba(255,255,255,.55); }
.hdr__cta:hover { background: rgba(255,255,255,.12); border-color: #fff; }
[data-hdr="solid"] .hdr__cta { border-color: rgba(255,255,255,.45); }
@media (min-width: 26em) { .hdr__tel { font-size: .84rem; padding: 0 8px; } }
@media (min-width: 64em) { .hdr__cta { display: inline-flex; } .hdr__tel { font-size: .9rem; padding: 0 10px; } }

.burger {
  width: 44px; height: 44px; flex: 0 0 auto; padding: 0;
  background: transparent; border: 1px solid rgba(255,255,255,.5); border-radius: 2px;
  cursor: pointer; position: relative;
}
.burger span, .burger span::before, .burger span::after {
  content: ""; position: absolute; left: 50%; width: 17px; height: 1.5px;
  background: #fff; transform: translateX(-50%); transition: transform .2s var(--ease);
}
.burger span { top: 50%; margin-top: -.75px; }
.burger span::before { left: 0; transform: none; top: -5.5px; }
.burger span::after  { left: 0; transform: none; top: 5.5px; }
[data-hdr="open"] .burger span { background: transparent; }
[data-hdr="open"] .burger span::before { transform: rotate(45deg); top: 0; }
[data-hdr="open"] .burger span::after  { transform: rotate(-45deg); top: 0; }

/* --- Nav overlay --------------------------------------------------------- */
.navov {
  position: fixed; inset: 0; z-index: 55; background: var(--ink);
  display: grid; align-content: start; grid-template-columns: 1fr;
  padding: calc(var(--hdr-h) + 28px) var(--gut) 40px; overflow-y: auto;
  opacity: 0; visibility: hidden; transition: opacity .28s var(--ease), visibility .28s;
}
[data-hdr="open"] .navov { opacity: 1; visibility: visible; }
.navov__main a {
  display: block; padding: 16px 0; border-bottom: 1px solid var(--ink-line);
  font-family: var(--f-head); font-weight: 600; font-size: 1.3rem; color: var(--bone);
  text-decoration: none; opacity: 0; transform: translateY(10px);
  transition: opacity .5s var(--ease) calc(45ms * var(--i,0)), transform .5s var(--ease) calc(45ms * var(--i,0)), color .16s linear;
}
[data-hdr="open"] .navov__main a { opacity: 1; transform: none; }
.navov__main a:hover { color: var(--gold); }
.navov__sec { display: flex; flex-wrap: wrap; gap: 2px 22px; margin-top: 22px; }
.navov__sec a { font-family: var(--f-head); font-weight: 600; font-size: 1rem; color: var(--bone-mute); text-decoration: none; padding: 9px 0; }
.navov__sec a:hover { color: var(--gold); }
.navov__foot { margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--ink-line); display: flex; flex-wrap: wrap; gap: 10px 26px; align-items: center; }
.navov__foot a { font-family: var(--f-mono); font-size: 1.15rem; color: var(--gold); text-decoration: none; font-variant-numeric: tabular-nums; }
.navov__fig { display: none; }
/* 21 Aug. The overlay figure's caption inherited .cap's --text-mute, which is
   a light-band colour: #5C574E on #0F0D0A measures 2.71:1 and fails WCAG AA.
   --bone-mute is the ink-band equivalent and measures 8.04:1. Scoped to the
   overlay so no other .cap on the site moves. */
.navov__fig .cap { color: var(--bone-mute); }
@media (min-width: 64em) {
  .navov { grid-template-columns: 62% 38%; gap: 56px; }
  .navov__fig { display: block; }
  .navov__fig img { width: 100%; aspect-ratio: 3/4; object-fit: cover; }
}

/* --- Sticky call bar ----------------------------------------------------- */
.actionbar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 50; height: var(--bar-h);
  display: grid; grid-template-columns: 1fr 1px 1fr;
  background: var(--ink); border-top: 1px solid var(--ink-line);
  transform: none; transition: transform .26s var(--ease);
}
/* 21 Aug: pinned and visible by default, in CSS, with no script involved. Only
   the homepage - which has a full-screen film to get out of the way of - opts
   into the slide-up-past-the-hero behaviour, and it is the only page that
   emits .actionbar--hero. The primary mobile CTA on every other page is now
   there whether or not site.js ever runs. */
.actionbar--hero { transform: translateY(100%); }
.actionbar.is-on, .actionbar--hero.is-on { transform: none; }
.actionbar__sep { background: var(--ink-line); }
.actionbar a { display: flex; align-items: center; justify-content: center; gap: 9px; font-weight: 600; font-size: .92rem; color: var(--bone); text-decoration: none; }
.actionbar svg { width: 18px; height: 18px; fill: var(--gold); flex: 0 0 auto; }
@media (min-width: 64em) { .actionbar { display: none; } }

/* ============================================================================
   HERO. The film is the subject.
   No grid overlay, no texture, no side plate. One soft gradient at the foot so
   the copy stays legible, and that is all that sits on the picture.
   ========================================================================= */
/* out of flow: a sentinel in normal flow would drag the page up */
#hdr-sentinel { position: absolute; top: 84%; left: 0; width: 1px; height: 1px; pointer-events: none; }
/* ---- Hero ---------------------------------------------------------------
   A 16:9 film cannot be full bleed AND un-cropped on a portrait phone: cover
   against a 390x844 screen keeps a quarter of the frame's width. So the two
   layouts are genuinely different shapes, not one shape with a tweak.

   DESKTOP (>=64em): unchanged. .hero__film is absolutely positioned, the film
   covers the section, the frame is nearly all there anyway (95.7% at 1440).

   MOBILE: full-height ink hero as a flex column. The film takes its own 16:9
   band at the top, so the WHOLE drone frame is on screen with nothing cropped,
   and the type gets the rest. Behind it, a 1.5KB 96x54 still of frame 0 is
   blown up and blurred to abstraction so the screen is alive edge to edge
   rather than letterboxed into black.                                       */
.hero {
  position: relative; background: var(--ink); overflow: hidden;
  height: 100svh; min-height: 600px;
  display: flex; flex-direction: column;
}

.hero__wash {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.25); filter: blur(34px) brightness(.5) saturate(.8); z-index: 0;
}
.hero__washveil {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: radial-gradient(140% 70% at 50% 16%, rgba(15,13,10,0) 0%, rgba(15,13,10,.34) 54%, rgba(15,13,10,.82) 100%);
}

/* the film band. margin-top clears the transparent header. */
.hero__film {
  position: relative; z-index: 2; flex: 0 0 auto;
  width: 100%; aspect-ratio: 16 / 9; margin-top: 74px;
}
/* a gold hairline under the film: it stops the band floating and it is the
   one place the brand colour touches the picture. */
.hero__film::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px; z-index: 3;
  background: linear-gradient(90deg, var(--gold) 0%, rgba(238,184,21,.4) 40%, rgba(238,184,21,0) 100%);
}

.hero__still, .hero__video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 45%;
}

@media (min-width: 64em) {
  .hero { height: 94svh; min-height: 560px; display: block; }
  .hero__film { position: absolute; inset: 0; width: 100%; height: 100%; aspect-ratio: auto; margin-top: 0; }
  .hero__film::after, .hero__wash, .hero__washveil { display: none; }
}
/* fully opaque once playing: a part-transparent video over the poster
   reads as a faint double image, which is not a look. */
/* the poster IS frame 0 of this encode, so the handover is a straight
   swap with no crossfade: the hero looks complete from first paint. */
.hero__video { opacity: 0; transition: opacity .12s linear; }
.hero__video.is-playing { opacity: 1; }

/* On mobile the type sits on ink, not on the picture, so the veil is only
   needed on desktop where the headline lies over the film. */
.hero__veil { display: none; }
.hero__wrap { position: relative; z-index: 3; flex: 1 1 auto; min-height: 0; display: flex; align-items: center; }
.hero__content { max-width: 30rem; padding-block: 16px; }
.hero__eyebrow {
  font-family: var(--f-mono); font-size: .66rem; font-weight: 500;
  letter-spacing: .17em; text-transform: uppercase; color: var(--gold);
  margin-bottom: 14px;
}
.hero__content .t-hero { color: #fff; margin-bottom: 14px; }
.hero__content p { color: #DCD8D0; font-size: 1rem; line-height: 1.6; margin-bottom: 24px; max-width: 34ch; }

@media (min-width: 64em) {
  .hero__veil {
    display: block;
    position: absolute; inset: auto 0 0 0; height: 62%; pointer-events: none; z-index: 3;
    background: linear-gradient(180deg, rgba(15,13,10,0) 0%, rgba(15,13,10,.30) 42%, rgba(15,13,10,.72) 78%, rgba(15,13,10,.86) 100%);
  }
  .hero__wrap { height: 100%; align-items: flex-end; }
  .hero__content { max-width: 34rem; padding-bottom: clamp(30px, 6vh, 68px); padding-block-start: 0; }
  .hero__content .t-hero { text-shadow: 0 1px 14px rgba(15,13,10,.6); }
  .hero__content p { color: #EFEDE8; line-height: 1.55; margin-bottom: 20px; text-shadow: 0 1px 12px rgba(15,13,10,.7); }
  /* on mobile the eyebrow sits on ink and the gold sings; on desktop it lies
     over the film, and gold on white render is unreadable at any shadow. */
  .hero__eyebrow { color: #EFEDE8; text-shadow: 0 1px 12px rgba(15,13,10,.9); }
}

/* On mobile the foot of the hero is the type block, so the control belongs on
   the film itself: the band is full-width, so its height is 56.25vw. */
.hero__pause {
  position: absolute; right: 14px; bottom: auto; z-index: 5;
  top: calc(74px + 56.25vw - 54px);
  width: 40px; height: 40px; display: grid; place-items: center;
  background: rgba(15,13,10,.42); border: 1px solid rgba(255,255,255,.34); border-radius: 50%; cursor: pointer;
}
@media (min-width: 64em) { .hero__pause { top: auto; bottom: 16px; right: 16px; } }
.hero__pause:hover { background: rgba(15,13,10,.7); }
.hero__pause svg { width: 12px; height: 12px; fill: #fff; }
.hero__pause .ico-play { display: none; }
.hero__pause[aria-pressed="true"] .ico-play { display: block; }
.hero__pause[aria-pressed="true"] .ico-pause { display: none; }
@media (min-width: 64em) { .hero__pause { right: 28px; bottom: 28px; width: 44px; height: 44px; } }

/* MOBILE HERO, 23 Aug. The full-viewport band below 64em existed to give the
   film room: a 16:9 frame inside a portrait screen loses most of its width to
   object-fit: cover, so the film sat in its own band above the copy and the
   section was sized to hold both. Measurement removed the film from mobile
   (see hero_video() in _build/build.py: LCP 1468ms -> 828ms, 2.66MB saved),
   and a 100svh band holding one still photograph and four lines of type is
   just the shape the film left behind. The poster is now the backdrop, as it
   already is on desktop, and the section is sized by its own content.
   It is STILL an <img> and still the LCP element - a CSS background image is
   not an LCP candidate, and swapping to one would have quietly invalidated
   the measurement that justified this. Homepage only: .hero appears nowhere
   else on the site. */
@media (max-width: 63.999em) {
  .hero { height: auto; min-height: 0; }
  .hero__film { position: absolute; inset: 0; width: 100%; height: 100%;
                aspect-ratio: auto; margin-top: 0; z-index: 1; }
  .hero__wrap { position: relative; z-index: 3; padding-block: 56px 40px; }
  /* The copy now sits ON the photograph instead of under it, so it needs a
     scrim it never needed before. Full height, not the desktop's bottom 62%:
     the eyebrow is at the TOP of this hero and the roof behind it is the
     brightest thing in the frame. */
  .hero__veil {
    display: block; position: absolute; inset: 0; pointer-events: none; z-index: 2;
    background: linear-gradient(180deg, rgba(15,13,10,.78) 0%, rgba(15,13,10,.60) 38%,
                rgba(15,13,10,.66) 70%, rgba(15,13,10,.86) 100%);
  }
  /* there is no film on mobile any more, so a play/pause control is a button
     for something that cannot happen. Done in CSS, not script: the inline
     hero script runs BEFORE this button exists in the document, so a
     querySelector for it there returns null and silently does nothing. */
  .hero__pause { display: none; }
}

/* --- Quiet trust line, replaces the four-cell ribbon -------------------- */
.trustline { border-bottom: 1px solid var(--line); }
.trustline ul { display: flex; flex-wrap: wrap; gap: 10px 30px; padding-block: 18px; }
.trustline li { display: flex; align-items: center; gap: 10px; font-size: .9rem; color: var(--text-mute); }
.trustline li::before { content: ""; width: 5px; height: 5px; border-radius: 50%; background: var(--gold-ink); flex: 0 0 auto; }

/* --- Section head -------------------------------------------------------- */
.shead { max-width: 60ch; margin-bottom: var(--sp-md); }
.shead .t-h2 { margin-bottom: 14px; }
.shead p { margin-bottom: 0; }

/* --- Services: photo-led rows, not a card grid --------------------------- */
.svcs { display: grid; gap: 2px; }
.svc {
  position: relative; display: block; text-decoration: none; color: inherit;
  overflow: hidden; background: var(--ink);
}
.svc img { width: 100%; aspect-ratio: 3/2; object-fit: cover; transition: transform .8s var(--ease), opacity .4s linear; opacity: .88; }
.svc:hover img { transform: scale(1.03); opacity: 1; }
.svc__cap {
  position: absolute; inset: auto 0 0 0; padding: 20px;
  background: linear-gradient(180deg, rgba(15,13,10,0) 0%, rgba(15,13,10,.82) 72%);
}
.svc__cap h3 { font-family: var(--f-head); font-weight: 600; font-size: 1.15rem; color: #fff; }
.svc__cap p { margin: 6px 0 0; font-size: .88rem; line-height: 1.45; color: #DEDAD2; max-width: 42ch; }
@media (min-width: 48em) {
  .svcs { grid-template-columns: 1fr 1fr; }
  .svc--wide { grid-column: 1 / -1; }
  .svc--wide img { aspect-ratio: 21/9; }
  .svc__cap { padding: 26px; }
  .svc__cap h3 { font-size: 1.3rem; }
}

/* --- Figures and galleries ---------------------------------------------- */
.cap { margin-top: 12px; font-family: var(--f-mono); font-size: var(--fs-mono); font-weight: 500; letter-spacing: .1em; text-transform: uppercase; color: var(--text-mute); }
.band--ink .cap { color: var(--bone-mute); }
.gal { display: grid; gap: 2px; grid-template-columns: 1fr; }
@media (min-width: 40em) { .gal { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em) { .gal { grid-template-columns: repeat(3, 1fr); } }
.gal figure { position: relative; background: var(--ink); overflow: hidden; }
.gal img { width: 100%; aspect-ratio: 3/2; object-fit: cover; transition: transform .8s var(--ease); }
.gal figure:hover img { transform: scale(1.03); }
.gal figcaption {
  position: absolute; inset: auto 0 0 0; margin: 0; padding: 14px 16px; color: #fff;
  background: linear-gradient(180deg, rgba(15,13,10,0), rgba(15,13,10,.8) 70%);
  font-family: var(--f-mono); font-size: .68rem; font-weight: 500; letter-spacing: .1em; text-transform: uppercase;
}

/* --- Before / after ------------------------------------------------------ */
.ba { position: relative; overflow: hidden; background: var(--paper-2); touch-action: pan-y; }
.ba img { width: 100%; display: block; }
.ba__after { position: absolute; inset: 0; clip-path: inset(0 calc(100% - var(--pos,50%)) 0 0); }
.ba__after img { width: 100%; height: 100%; object-fit: cover; }
.ba__chip {
  position: absolute; top: 14px; z-index: 3; background: rgba(15,13,10,.72); color: #fff;
  font-family: var(--f-mono); font-size: .64rem; font-weight: 500; letter-spacing: .12em;
  padding: 5px 9px; pointer-events: none;
}
.ba__chip--a { left: 14px; } .ba__chip--b { right: 14px; }
.ba__line { position: absolute; top: 0; bottom: 0; left: var(--pos,50%); width: 1px; background: rgba(255,255,255,.9); transform: translateX(-50%); z-index: 4; pointer-events: none; }
.ba__grab {
  position: absolute; top: 50%; left: var(--pos,50%); z-index: 5; width: 44px; height: 44px;
  margin: -22px 0 0 -22px; background: #fff; border-radius: 50%; pointer-events: none;
  display: grid; place-items: center; box-shadow: 0 2px 14px rgba(0,0,0,.3);
}
.ba__grab svg { width: 18px; height: 18px; fill: var(--text); }
.ba__range { position: absolute; inset: 0; z-index: 6; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: ew-resize; -webkit-appearance: none; appearance: none; background: transparent; }
.ba__range::-webkit-slider-thumb { -webkit-appearance: none; width: 44px; height: 44px; }
.ba__range::-moz-range-thumb { width: 44px; height: 44px; border: 0; opacity: 0; }

/* --- Process ------------------------------------------------------------- */
.proc { display: grid; gap: 0; }
/* The numeral is positioned, not a grid column. A grid column breaks the moment
   a step emits a different number of children: the paragraph drops into the
   numeral track and renders one word per line. This cannot. */
.proc__step { position: relative; padding: 22px 0 22px 3.2rem; border-top: 1px solid var(--line); }
.band--ink .proc__step { border-top-color: var(--ink-line); }
.proc__n {
  position: absolute; left: 0; top: 22px;
  font-family: var(--f-mono); font-weight: 500; font-size: .8rem; letter-spacing: .06em;
  color: var(--gold-ink); padding-top: .35em;
}
.band--ink .proc__n { color: var(--gold); }
.proc__step h3 { font-family: var(--f-head); font-weight: 600; font-size: var(--fs-h3); margin-bottom: 6px; }
.proc__step p { margin: 0; color: var(--text-mute); }
.band--ink .proc__step p { color: var(--bone-mute); }
@media (min-width: 64em) {
  .proclay { display: grid; grid-template-columns: 4fr 7fr; gap: var(--sp-xl); align-items: start; }
  .proclay > .prose { margin-top: 0; }
  .proclay__aside { position: sticky; top: calc(64px + var(--sp-md)); }
  .proc__step { padding: 26px 0 26px 4rem; }
  .proc__n { top: 26px; }
}

/* --- Split / editorial --------------------------------------------------- */
.split { display: grid; gap: var(--sp-md); grid-template-columns: 1fr; align-items: center; }
@media (min-width: 64em) { .split { grid-template-columns: 1fr 1fr; gap: var(--sp-xl); } }
.split img { width: 100%; object-fit: cover; }

/* --- Facts list ---------------------------------------------------------- */
.facts { display: grid; }
.facts > div { display: grid; grid-template-columns: 1fr; gap: 3px; padding: 15px 0; border-top: 1px solid var(--line); }
.band--ink .facts > div { border-top-color: var(--ink-line); }
.facts dt { font-family: var(--f-mono); font-size: var(--fs-mono); font-weight: 500; letter-spacing: .1em; text-transform: uppercase; color: var(--text-mute); }
.band--ink .facts dt { color: var(--gold); }
.facts dd { margin: 0; }
@media (min-width: 40em) { .facts > div { grid-template-columns: 190px 1fr; gap: 24px; align-items: baseline; } }

/* --- Areas --------------------------------------------------------------- */
.areas { display: grid; grid-template-columns: 1fr; gap: 0 var(--sp-xl); }
.areas h3 { font-family: var(--f-head); font-weight: 600; font-size: 1rem; margin: 20px 0 2px; }
.areas li { padding: 10px 0; border-top: 1px solid var(--line); font-size: .95rem; color: var(--text-mute); }
.band--ink .areas li { border-top-color: var(--ink-line); color: var(--bone-mute); }
@media (min-width: 40em) { .areas { grid-template-columns: 1fr 1fr; } }

/* --- FAQ ----------------------------------------------------------------- */
.faq details { border-top: 1px solid var(--line); }
.faq details:last-of-type { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 18px;
  padding: 20px 0; cursor: pointer; list-style: none;
  font-family: var(--f-head); font-weight: 600; font-size: 1.05rem;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary svg { flex: 0 0 auto; width: 14px; height: 14px; margin-top: 6px; stroke: var(--gold-ink); stroke-width: 2; transition: transform .24s var(--ease); }
.faq details[open] summary svg { transform: rotate(45deg); }
.faq__a { padding-bottom: 20px; color: var(--text-mute); max-width: 66ch; }
.faq__a p:last-child { margin-bottom: 0; }
.band--ink .faq details, .band--ink .faq details:last-of-type { border-color: var(--ink-line); }
.band--ink .faq summary { color: #fff; }
.band--ink .faq summary svg { stroke: var(--gold); }
.band--ink .faq__a, .band--ink .faq__a p { color: var(--bone-mute); }

/* --- Form ---------------------------------------------------------------- */
.form { display: grid; gap: 16px; }
.form__row { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 40em) { .form__row { grid-template-columns: 1fr 1fr; } }
.field { display: grid; gap: 6px; }
.field label { font-weight: 700; font-size: var(--fs-small); }
.field label .opt { font-weight: 400; color: var(--text-mute); }
.field input, .field select, .field textarea {
  font: inherit; font-size: 1rem; color: var(--text); background: #fff;
  min-height: 52px; padding: 13px 14px; width: 100%;
  border: 1px solid #8C8578; border-radius: 2px; transition: border-color .16s var(--ease);
}
.field textarea { min-height: 124px; resize: vertical; line-height: 1.55; }
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--text); }
/* 6 Sep: the postcode field became a free-text Area field. No uppercase
   transform - "bromley" would come back shouting. */
.field input::placeholder { color: var(--text-mute); opacity: 1; }
.field__file { border: 1px dashed #8C8578; border-radius: 2px; padding: 14px; background: #fff; }
.field__file input { border: 0; background: none; min-height: 0; padding: 0; font-size: var(--fs-small); }
.hp { position: absolute; left: -9999px; }
.form__note { font-size: var(--fs-small); color: var(--text-mute); }
.form__done { display: none; padding: 18px 20px; background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--gold-ink); }
.form__done.is-on { display: block; }
.band--ink .field label { color: var(--bone); }
.band--ink .field label .opt, .band--ink .form__note { color: var(--bone-mute); }
/* the file panel is white even inside a dark band, so its text stays dark */
.field__file .mono, .band--ink .field__file .mono { color: var(--text-mute); }

/* --- Breadcrumbs + page head --------------------------------------------- */
.crumbs { font-family: var(--f-mono); font-size: var(--fs-mono); letter-spacing: .08em; color: var(--bone-mute); }
.crumbs ol { display: flex; flex-wrap: wrap; gap: 8px; }
.crumbs a { color: var(--bone-mute); text-decoration: none; }
.crumbs a:hover { color: var(--gold); }
.crumbs li + li::before { content: "/"; color: var(--gold); margin-right: 8px; }
.phead { padding-top: calc(var(--hdr-h) + var(--sp-md)); }
.phead .t-h1 { color: #fff; margin: 16px 0 14px; }
.pheadlay { display: grid; gap: var(--sp-md); grid-template-columns: 1fr; }
@media (min-width: 64em) { .pheadlay { grid-template-columns: 6fr 5fr; gap: var(--sp-xl); align-items: center; } .pheadlay img { aspect-ratio: 4/5; object-fit: cover; width: 100%; } }

/* --- Filters ------------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: 8px; }
.filters button {
  min-height: 44px; padding: 10px 16px; cursor: pointer; background: transparent;
  border: 1px solid #C9C4BA; border-radius: 2px;
  font-family: var(--f-mono); font-size: .7rem; font-weight: 500; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-mute); transition: border-color .16s, color .16s, background-color .16s;
}
.filters button:hover { border-color: var(--text); color: var(--text); }
.filters button[aria-pressed="true"] { background: var(--text); border-color: var(--text); color: #fff; }
.band--ink .filters button { color: var(--bone-mute); border-color: rgba(255,255,255,.3); }
.band--ink .filters button:hover { color: #fff; border-color: #fff; }
.band--ink .filters button[aria-pressed="true"] { background: var(--gold); border-color: var(--gold); color: var(--ink); }

/* --- Footer -------------------------------------------------------------- */
.ftr { background: var(--ink); color: var(--bone-mute); }
.ftr__grid { display: grid; grid-template-columns: 1fr; gap: var(--sp-md); padding-block: var(--sp-lg) var(--sp-md); }
@media (min-width: 40em) { .ftr__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 64em) { .ftr__grid { grid-template-columns: 1.6fr 1fr 1fr 1.2fr; gap: var(--sp-lg); } }
.ftr__logo { width: 190px; height: auto; }
.ftr h4 { font-family: var(--f-mono); font-size: var(--fs-mono); font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--gold); margin-bottom: 14px; }
.ftr li { padding: 5px 0; }
.ftr a { color: var(--bone-mute); text-decoration: none; }
.ftr a:hover { color: #fff; }
.ftr__blurb { margin-top: 16px; font-size: var(--fs-small); max-width: 36ch; }
.ftr__base { display: flex; flex-wrap: wrap; gap: 8px 24px; justify-content: space-between; padding-block: 18px; border-top: 1px solid var(--ink-line); font-family: var(--f-mono); font-size: .68rem; letter-spacing: .08em; }

/* --- Town cards: each one a door to its own page -------------------------- */
.tgrid { display: grid; gap: 22px; grid-template-columns: 1fr; }
@media (min-width: 40em) { .tgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 64em) { .tgrid { grid-template-columns: repeat(3, 1fr); gap: 26px; } }
.tcardwrap { position: relative; scroll-margin-top: calc(var(--hdr-h) + 16px); }
.tcard {
  display: block; height: 100%; color: inherit; text-decoration: none;
  background: #fff; border: 1px solid var(--line);
  transition: border-color .3s var(--ease);
}
.tcard:hover { border-color: #B6B0A6; }
.tcard__ph { position: relative; display: block; overflow: hidden; background: var(--paper-2); }
.tcard__ph img { width: 100%; aspect-ratio: 3/2; object-fit: cover; transition: transform .8s var(--ease); }
.tcard:hover .tcard__ph img { transform: scale(1.03); }
/* the licence credit: quiet, present, exactly as the licence requires.
   it is a LINK, so it lives outside the card link and overlays the top
   right corner of the photograph. */
.tcredit {
  position: absolute; right: 0; bottom: 0; z-index: 2;
  font-family: var(--f-mono); font-size: .58rem; font-weight: 500; letter-spacing: .04em;
  color: #fff; background: rgba(15,13,10,.66); padding: 4px 8px; text-decoration: none;
}
.tcredit:hover { text-decoration: underline; }
.tcardwrap > .tcredit { bottom: auto; top: 1px; right: 1px; }
.tcard__body { display: block; padding: 18px 20px 20px; }
.tcard__t { display: block; font-family: var(--f-head); font-weight: 600; font-size: 1.15rem; }
.tcard__pc { font-family: var(--f-mono); font-size: .68rem; font-weight: 500; letter-spacing: .12em; text-transform: uppercase; color: var(--gold-ink); display: block; margin: 4px 0 10px; }
.tcard__p { display: block; font-size: .95rem; line-height: 1.6; color: var(--text-mute); }
.tcard__more {
  display: inline-block; margin-top: 14px; font-weight: 700; font-size: .88rem;
  border-bottom: 1px solid var(--gold-ink); padding-bottom: 2px;
}
.tcard:hover .tcard__more { border-bottom-width: 2px; }

/* --- Town chips: the per-town page index on the two service pages --------- */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip {
  display: inline-flex; align-items: center; min-height: 44px; padding: 10px 16px;
  border: 1px solid #C9C4BA; border-radius: 2px; text-decoration: none;
  font-family: var(--f-mono); font-size: .7rem; font-weight: 500;
  letter-spacing: .1em; text-transform: uppercase; color: var(--text-mute);
  transition: border-color .16s, color .16s;
}
.chip:hover { border-color: var(--text); color: var(--text); }
/* Chips on an ink band: the surface jump links in the driveways page header.
   Added 12 Aug. No chip sat inside a band--ink section before this, so the
   rule cannot change any existing page. */
.band--ink .chip { border-color: rgba(255,255,255,.4); color: var(--bone-mute); }
.band--ink .chip:hover { border-color: #fff; color: #fff; }

/* --- Licensed town figure on hub and service-in-town pages ---------------- */
.tphoto { position: relative; overflow: hidden; }
.tphoto img { width: 100%; aspect-ratio: 3/2; object-fit: cover; }
@media (min-width: 64em) { .tphoto img { aspect-ratio: 21/9; } }

/* --- Testimonial: one generous quote, only when a real one exists -------- */
.testi { max-width: 54ch; }
.testi__q { margin: 0; }
.testi__q p {
  font-family: var(--f-head); font-weight: 600; color: #fff;
  font-size: clamp(1.3rem, 1.05rem + 1.1vw, 1.9rem); line-height: 1.35;
  letter-spacing: -.01em;
}
.testi__q p:first-of-type::before { content: "\201C"; color: var(--gold); margin-right: 2px; }
.testi__q p:last-of-type::after { content: "\201D"; color: var(--gold); margin-left: 2px; }
.testi__who { margin-top: 18px; color: var(--bone-mute); }

/* --- Reveal -------------------------------------------------------------- */
.js-rv .rv { opacity: 0; transform: translateY(12px); transition: opacity .7s var(--ease), transform .7s var(--ease); }
.js-rv .rv.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  .js-rv .rv { opacity: 1 !important; transform: none !important; }
  .svc:hover img, .gal figure:hover img { transform: none; }
}
@media print {
  .hdr, .navov, .actionbar, .skip, .hero { display: none !important; }
  body { background: #fff; color: #000; padding: 0; }
}


/* ============================================================================
   CONVERSION OVERHAUL — 21 Aug 2026
   Kyren's verdict on the ad landing pages was that it was "still too difficult
   to get in touch", that the form section had to be "way more prominent", and
   that proof had to sit where people enquire. Everything below exists for one
   of those three sentences.
   ========================================================================= */

/* --- Stars ---------------------------------------------------------------
   The mark carries meaning, so it has to clear 3:1 as a non-text element.
   Flat --gold is 1.8:1 on white and fails, so on light grounds the stars use
   --gold-ink (the same amber the krule and the FAQ plus already use) and only
   go to full gold on an ink band, where gold is 10:1. */
.stars { display: flex; gap: 3px; }
.stars svg { width: 17px; height: 17px; fill: var(--gold-ink); flex: 0 0 auto; }
.band--ink .stars svg { fill: var(--gold); }

/* --- The review, in full -------------------------------------------------
   One real Google review and there is exactly one, so this is a single card
   and never a wall, a carousel or a count. */
.rev { max-width: 74ch; margin-inline: auto; }
.rev__card {
  background: #fff; border: 1px solid var(--line); border-top: 3px solid var(--gold-ink);
  padding: 26px 22px 24px;
}
@media (min-width: 40em) { .rev__card { padding: 38px 40px 34px; } }
.rev__card .t-h3 { margin: 0 0 20px; }
.rev__q { margin: 0; }                 /* the UA's 40px blockquote indent, off */
.rev__q p {
  font-family: var(--f-disp); font-weight: 500; color: var(--text);
  font-size: clamp(1.02rem, .99rem + .2vw, 1.16rem); line-height: 1.62;
  margin-bottom: .85em;
}
.rev__q p:first-of-type::before { content: "\201C"; color: var(--gold-ink); margin-right: 1px; }
.rev__q p:last-of-type::after   { content: "\201D"; color: var(--gold-ink); margin-left: 1px; }
.rev__who { margin-top: 22px; padding-top: 18px; border-top: 1px solid var(--line); }
.rev__name { font-family: var(--f-head); font-weight: 600; margin: 10px 0 2px; }
.rev__cred { margin: 0; color: var(--text-mute); }
.rev__note {
  margin: 16px 0 0; font-size: var(--fs-small); line-height: 1.5;
  color: var(--text-mute); max-width: 62ch;
}
/* on an ink band (the homepage slot) the card goes dark rather than punching a
   white slab through the middle of the page */
.band--ink .rev__card { background: var(--ink-2); border-color: var(--ink-line); border-top-color: var(--gold); }
.band--ink .rev__q p { color: #fff; }
.band--ink .rev__q p:first-of-type::before,
.band--ink .rev__q p:last-of-type::after { color: var(--gold); }
.band--ink .rev__who { border-top-color: var(--ink-line); }
.band--ink .rev__name { color: #fff; }
.band--ink .rev__cred, .band--ink .rev__note { color: var(--bone-mute); }

/* --- The enquiry panel: the destination ----------------------------------
   An ink band carrying a white card, on pages that are otherwise light. It is
   the only element built this way on the site, which is the entire point: it
   cannot be scrolled past as one more band of content. */
/* Card first in the document and first on a phone. On desktop it takes the
   left column and the proof sits beside it on the right, so the visual order
   is the document order and no `order` property is needed anywhere here. */
.qpanel { display: grid; gap: var(--sp-md); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 64em) { .qpanel { grid-template-columns: 6fr 5fr; gap: var(--sp-lg); } }
.qband { scroll-margin-top: var(--hdr-h); }
.qpanel__head { max-width: 54ch; margin-bottom: var(--sp-md); }
.qpanel__head .lead { color: var(--bone-mute); }
.qpromise { margin: 0; display: grid; }

.qpromise li { display: grid; gap: 2px; padding: 13px 0 13px 30px; position: relative; border-top: 1px solid var(--ink-line); }
.qpromise li::before {
  content: ""; position: absolute; left: 0; top: 19px; width: 13px; height: 8px;
  border-left: 2px solid var(--gold); border-bottom: 2px solid var(--gold);
  transform: rotate(-45deg);
}
.qpromise__t { font-family: var(--f-head); font-weight: 600; color: #fff; }
.qpromise__d { font-size: var(--fs-small); line-height: 1.5; color: var(--bone-mute); }

.qphone { margin: var(--sp-sm) 0 0; font-size: var(--fs-small); color: var(--bone-mute); }
.qphone a {
  display: block; font-family: var(--f-mono); font-variant-numeric: tabular-nums;
  font-size: 1.32rem; font-weight: 500; letter-spacing: .01em;
  color: var(--gold); text-decoration: none; margin: 4px 0 2px;
}
.qphone a:hover { text-decoration: underline; }
.qphone span { display: block; }

/* the review extract, beside the fields */
.qproof { margin-top: var(--sp-sm); padding: 18px 20px; border: 1px solid var(--ink-line); background: var(--ink-2); }
.qproof blockquote { margin: 0; }
.qproof blockquote p { margin: 0; color: var(--bone); font-size: var(--fs-small); line-height: 1.62; }
.qproof blockquote p::before { content: "\201C"; color: var(--gold); }
.qproof blockquote p::after  { content: "\201D"; color: var(--gold); }
.qproof__who { margin-top: 14px; }
.qproof__who .rev__name { font-size: .95rem; margin: 8px 0 1px; color: #fff; }
.qproof__who .rev__cred { color: var(--bone-mute); }
.qproof__link { margin: 12px 0 0; font-size: var(--fs-small); }

/* THE CARD. White, inside an ink band. Every dark-band rule that would leak
   into it is put back to its light-page value here; these rules are last in
   the file on purpose, because they match the .band--ink ones on specificity
   and win on order. */
/* the dark-band values first, so the .qcard overrides below still win on
   order inside the white card */
.band--ink .form__go__note, .band--ink .field__why { color: var(--bone-mute); }

.qcard {
  background: #fff; color: var(--text);
  border-top: 3px solid var(--gold); padding: 24px 20px 26px;
}
@media (min-width: 40em) { .qcard { padding: 32px 30px 34px; } }
.qcard--light { border: 1px solid var(--line); border-top: 3px solid var(--gold-ink); }
.qcard__h { margin-bottom: 6px; }
.qcard__sub { font-size: var(--fs-small); line-height: 1.55; color: var(--text-mute); margin-bottom: 20px; }
.qcard .form { margin-top: 18px; }
.qcard .field label { color: var(--text); }
.qcard .field label .opt, .qcard .form__note, .qcard .form__go__note,
.qcard .field__why, .qcard .mono, .qcard .cap { color: var(--text-mute); }
.qcard .krule { background: var(--gold-ink); }
.qcard .tlink { color: var(--text); border-color: var(--gold-ink); }
/* the card is white, so the ink band's gold focus ring (1.8:1 on white) has to
   go back to the dark one, which is 16.4:1 */
.qcard :focus-visible { outline-color: var(--text); }
.rev__card :focus-visible { outline-color: var(--text); }
.band--ink .rev__card :focus-visible { outline-color: var(--gold); }

/* --- Form: the commitment moment ----------------------------------------- */
/* Nothing sits between the last field and the button. The count of what is
   actually required, and what happens after it is pressed, sit BESIDE it. */
.form__go { display: grid; gap: 12px; align-items: center; }
@media (min-width: 34em) { .form__go { grid-template-columns: auto 1fr; gap: 18px; } }
.form__go .btn { width: 100%; }
@media (min-width: 34em) { .form__go .btn { width: auto; } }
.form__go__note { margin: 0; font-size: var(--fs-small); line-height: 1.5; color: var(--text-mute); }
.field__why { margin: 10px 0 0; font-size: var(--fs-small); line-height: 1.5; color: var(--text-mute); }

/* --- 25 Aug 2026 — conversion 3: proof in the fold, compact form, thank-you steps --- */
/* Two frames of the same house in the fold of the two ad pages. Plain frames, no slider. */
.proofpair { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 6px; align-content: start; }
.proofpair figure { margin: 0; background: var(--ink-2); }
.proofpair img { width: 100%; aspect-ratio: 4/3; object-fit: cover; display: block; }
.proofpair figcaption { margin-top: 8px; }
.proofpair__note { grid-column: 1 / -1; margin: 4px 0 0; font-size: var(--fs-small); line-height: 1.5; color: var(--bone-mute); }
@media (min-width: 64em) { .pheadlay .proofpair img { aspect-ratio: 4/3; } }
/* 6 Sep: the optional-fields <details> (.form__more) is gone with the
   fields it folded. The form is four inputs now; nothing to fold. */
/* /thank-you: what happens next, three lines. */
.nextsteps { margin: var(--sp-md) 0 0; padding-left: 1.25em; display: grid; gap: 10px; max-width: 54ch; color: var(--bone-mute); line-height: 1.55; }
.nextsteps strong { color: #fff; font-weight: 600; }

/* ============================================================================
   LIVE GOOGLE REVIEWS — 26 Aug 2026 (restyled same day to Cameron's spec)
   Google's own widget look, replicated from the reference on alogistics.uk:
   NOT site-matched by instruction. The section ships with the `hidden`
   attribute and reviews.js un-hides it only when /api/reviews answers with
   real data for the right listing, so nothing below ever styles an empty
   box. Every selector is scoped under .grevband/.gr-*: the page's element
   rules cannot restyle the widget's guts beyond the global reset, and
   nothing here can reach outside the section. The interior deliberately
   uses a Roboto/Arial stack and Google's own star amber (#FBBC04); the one
   brand touch is the client-gold review pill. NO date styles: dates are not
   rendered at all.
   ========================================================================= */
.grevband[hidden] { display: none; }    /* belt: hidden is the only off-switch */
.grevband .t-h2 { margin-bottom: var(--sp-md); }
.gr-card {
  background: #fff; border: 1px solid var(--line); border-radius: 20px;
  padding: 28px; box-shadow: 0 8px 22px rgba(26,24,21,.08);
  font-family: Roboto, 'Helvetica Neue', Arial, sans-serif;
}
.gr-head {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  border-bottom: 1px solid var(--line); padding-bottom: 20px; margin-bottom: 22px;
}
.gr-glogo { width: 40px; height: 40px; flex: 0 0 40px; }
.gr-agg { display: flex; align-items: center; gap: 12px; }
.gr-agg b { font-weight: 700; font-size: 2.1rem; color: var(--text); line-height: 1; }
.gr-stars { display: block; color: #FBBC04; letter-spacing: .14em; font-size: 1.02rem; line-height: 1.2; }
a.gr-count { display: block; font-size: .82rem; color: var(--text-mute); font-weight: 600; margin-top: 3px; text-decoration: none; }
a.gr-count:hover { text-decoration: underline; }
.gr-actions { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.gr-arrow {
  width: 40px; height: 40px; border-radius: 50%; border: 1px solid #C9C4BA;
  background: #fff; color: var(--text); display: grid; place-items: center;
  cursor: pointer; padding: 0; transition: border-color .2s, transform .15s;
}
.gr-arrow:hover { border-color: var(--text); transform: translateY(-1px); }
.gr-arrow svg { width: 17px; height: 17px; }
.gr-cta {
  font-weight: 700; font-size: .88rem; background: var(--gold); color: var(--ink);
  padding: 11px 20px; border-radius: 100px; text-decoration: none; white-space: nowrap;
  box-shadow: 0 8px 18px rgba(238,184,21,.28); transition: transform .15s, box-shadow .2s;
}
.gr-cta:hover { transform: translateY(-2px); box-shadow: 0 12px 24px rgba(238,184,21,.38); }
.gr-cta[hidden] { display: none; }
.gr-track {
  display: flex; gap: 16px; overflow-x: auto; scroll-snap-type: x mandatory;
  padding: 2px 2px 6px; scrollbar-width: none;
}
.gr-track.center { justify-content: center; }
.gr-track::-webkit-scrollbar { display: none; }
.grev {
  scroll-snap-align: start; flex: 0 0 340px; max-width: 82vw; box-sizing: border-box;
  background: #fff; border: 1px solid var(--line); border-radius: 16px;
  padding: 22px; display: flex; flex-direction: column; align-items: flex-start;
  box-shadow: 0 1px 3px rgba(26,24,21,.06);
}
.gr-top { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; width: 100%; }
.gr-ava { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex: 0 0 44px; }
.gr-ava-f {
  background: var(--gold-ink); color: #fff; display: grid; place-items: center;
  font-weight: 700; font-size: 1.1rem; text-transform: uppercase;
}
.gr-who { min-width: 0; }
.gr-who b {
  display: block; font-weight: 700; font-size: .98rem; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.gr-gicon { margin-left: auto; width: 22px; height: 22px; flex: 0 0 22px; }
.grev .gr-stars { font-size: .95rem; margin-bottom: 10px; }
/* Clamped, never cut: tap the text, or the Read more button below it, to
   unfold the whole review. A browser with no line-clamp shows the whole
   text and never gets the button. */
.gr-txt {
  margin: 0; font-size: .97rem; line-height: 1.6; color: var(--text);
  white-space: pre-line; display: -webkit-box; -webkit-line-clamp: 7;
  -webkit-box-orient: vertical; overflow: hidden; cursor: pointer;
}
.gr-txt.open { display: block; -webkit-line-clamp: unset; cursor: default; }
.gr-more {
  margin-top: 10px; padding: 0; background: none; border: 0; color: #1A73E8;
  font-family: inherit; font-weight: 600; font-size: .9rem; cursor: pointer; text-align: left;
}
.gr-more:hover { text-decoration: underline; }
@media (max-width: 40em) {
  .gr-card { padding: 18px 14px; border-radius: 16px; }
  .gr-actions { margin-left: 0; width: 100%; justify-content: flex-start; }
  .gr-cta { margin-left: auto; }
}

/* ============================================================================
   27 AUG 2026 — THE REVIEW, TWO WAYS, ON THE TWO AD LANDING PAGES
   Measured at a true 390x844 the qproof card between the enquiry heading and
   the first field cost 0.57 of a screen. Its POSITION was the differentiator
   (1 of 17 competitor pages puts proof at the decision point); its SIZE was
   the problem. So: a one-line strip in the form, and the review in full as an
   editorial pull quote on its own band lower down.
   WORDS, NOT STARS, in both. No stars, no rating number, no review count, no
   Google G: one quoted review is not a rating, and stars beside a hand-picked
   quote is the shape the ASA ruled misleading (Winedrops, Feb 2025). The
   Google widget on the same pages is the ONLY thing that shows a rating, and
   these two deliberately look nothing like its white cards.
   ========================================================================= */
/* --- The strip: between the heading and the first field, inside the ink
   band. One whole sentence in the display serif, then the attribution and
   the same-page link. Hairlines top and bottom, no box. */
.qstrip {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 28px;
  /* the heading wrapper above carries sp-md; the strip wants less air above
     its hairline than below it, and every pixel here is a pixel a thumb
     travels to reach the first field */
  margin: -12px 0 var(--sp-sm); padding: 11px 0 12px;
  border-top: 1px solid var(--ink-line); border-bottom: 1px solid var(--ink-line);
}
.qstrip__q { margin: 0; }
.qstrip__q p {
  margin: 0; font-family: var(--f-disp); font-weight: 500; color: #fff;
  font-size: 1.05rem; line-height: 1.45; letter-spacing: -.004em;
}
.qstrip__q p::before { content: "\201C"; color: var(--gold); margin-right: 1px; }
.qstrip__q p::after  { content: "\201D"; color: var(--gold); margin-left: 1px; }
.qstrip__who { margin: 0; font-size: .8rem; line-height: 1.45; color: var(--bone-mute); }
.qstrip__who .tlink { font-size: inherit; margin-left: 2px; white-space: nowrap; }

/* --- The pull quote: the review in full, no card. Display serif, one
   oversized mark, attribution under a hairline. Works on the quiet ground
   (render page) and the ink ground (EWI page). */
.pullq { margin: 0; max-width: 64ch; }
.pullq__h { margin: 0 0 var(--sp-sm); }
.pullq__mark {
  display: block; font-family: var(--f-disp); font-weight: 500;
  font-size: 5.6rem; line-height: 1; height: .52em; overflow: visible;
  color: var(--gold-ink); margin: 0 0 4px -.03em; user-select: none;
}
.pullq__q { margin: 0; }
.pullq__q p {
  font-family: var(--f-disp); font-weight: 500; color: var(--text);
  font-size: clamp(1.18rem, 1.06rem + .62vw, 1.62rem); line-height: 1.5;
  letter-spacing: -.005em; margin-bottom: .8em;
}
.pullq__q p:last-of-type { margin-bottom: 0; }
.pullq__q p:last-of-type::after { content: "\201D"; color: var(--gold-ink); margin-left: 1px; }
.pullq__who {
  margin-top: var(--sp-sm); padding-top: 16px; border-top: 1px solid var(--line);
  display: grid; gap: 4px; max-width: 60ch;
}
.pullq__name { font-family: var(--f-head); font-weight: 600; font-size: 1.05rem; color: var(--text); }
.pullq__cred { color: var(--text-mute); }
.pullq__where { margin-top: 6px; font-size: var(--fs-small); line-height: 1.5; color: var(--text-mute); }
.pullq__where .tlink { color: var(--text); border-color: var(--gold-ink); margin-left: 6px; }
.band--ink .pullq__mark, .band--ink .pullq__q p:last-of-type::after { color: var(--gold); }
.band--ink .pullq__q p, .band--ink .pullq__name { color: #fff; }
.band--ink .pullq__cred, .band--ink .pullq__where { color: var(--bone-mute); }
.band--ink .pullq__who { border-top-color: var(--ink-line); }
.band--ink .pullq__where .tlink { color: var(--bone); border-color: var(--gold); }
@media (min-width: 64em) {
  .pullq__mark { font-size: 7rem; margin-bottom: 2px; }
}

/* =========================================================================
   30 AUG 2026 — THE SOURCE-PROFILE NOTE
   The feed serves the PAVING listing. On /silicone-render and
   /external-wall-insulation that has to be said in words, under the cards,
   or five driveway reviews sitting on a render page read as render reviews.
   reviews.js writes the listing name from the API response; empty shell on
   disk, nothing claimed until the feed answers. Scoped under .gr-note only.
   ========================================================================= */
.gr-note {
  margin: 18px 0 0; padding-top: 16px; border-top: 1px solid var(--line);
  font-family: Roboto, 'Helvetica Neue', Arial, sans-serif;
  font-size: .82rem; line-height: 1.55; color: var(--text-mute);
}
.gr-note b { font-weight: 700; color: var(--text); }
.gr-note a {
  color: var(--text); font-weight: 600; text-decoration: underline; text-underline-offset: 2px;
  /* inline link inside a sentence: grow the hit area without moving the type */
  padding: 6px 2px; margin: -6px -2px;
}
.gr-note a:hover { color: var(--gold-ink); }
.gr-note[hidden] { display: none; }
@media (max-width: 600px) {
  .gr-note { margin-top: 14px; padding-top: 13px; }
}

/* =========================================================================
   30 AUG 2026 — THE FINISHED JOB, AT THE HEAD OF THE ASK
   One of Kyren's completed houses sits behind the top of the enquiry band,
   with the heading over it. The white card and every field below are
   untouched and DO NOT MOVE: the photograph is an absolutely positioned
   backdrop and contributes no height to the section. Measured before and
   after, both money pages, both widths.

   WHY A BAND AND NOT A FULL-BLEED COVER. On a 390px screen this section is
   1,672px tall on the landing pages and 1,873px on the homepage.
   object-fit: cover over 390x1873 crops a 2000x1500 frame to a narrow
   vertical sliver at about five times zoom - measured, and it read as brown
   noise rather than a house. So the photograph gets a height close to its
   own proportions and the ink takes over beneath it. Same lesson as the
   hero: "too zoomed in" is a height problem, not a crop problem.

   WHERE THE GRADIENT TURNS, AND WHY THERE. Measured against the real
   layout inside a 433px frame at 390px wide:
       homepage   heading 18-24%   lead 27-40%   opaque proof card from 48%
       landing    heading 24-36%   strip 41-68%  opaque white card from 72%
   So the type occupies everything from about 18% down, and a card covers the
   rest. The only genuinely open window is the slice ABOVE the heading. The
   scrim is therefore light for that first sixth - which is where the eye
   lands as the band scrolls in, and where the house has to read as a house -
   and then holds ~0.80 all the way down through the type before closing to
   solid ink so there is no seam into the band.

   EVERY FIGURE HERE WAS SAMPLED FROM RENDERED PIXELS with the text hidden,
   worst-pixel and not average. Assumed alpha values were wrong twice: the
   first attempt opened the scrim at the top, exactly where the type is.
   ========================================================================= */
.qband--shot { position: relative; isolation: isolate; }
.qband--shot > .wrap { position: relative; z-index: 2; }

.qshot {
  position: absolute; top: 0; left: 0; right: 0;
  height: clamp(430px, 30vw + 316px, 560px);
  overflow: hidden; z-index: 0;
}
.qshot__img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 58%;
  /* phone shots: a little contrast keeps the render texture alive under the
     scrim, and pulling the saturation back stops the sky fighting the gold */
  filter: saturate(.88) contrast(1.05);
}
/* a flat floor, so no frame is ever left completely unscrimmed */
.qshot::before {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: rgba(15, 13, 10, .16);
}
/* the shape: open where the eye lands, heavy through the type, ink at the foot */
.qshot::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(
    to bottom,
    rgba(15, 13, 10, .30)  0%,
    rgba(15, 13, 10, .44) 13%,
    rgba(15, 13, 10, .74) 22%,
    rgba(15, 13, 10, .78) 70%,
    rgba(15, 13, 10, .92) 88%,
    var(--ink)           100%);
}
/* Muted greys are the hierarchy on a flat ink band, where bone-mute measures
   8:1. Over a photograph of a white rendered wall the same grey measured
   1.38:1. On this band the hierarchy is carried by size and weight instead,
   and everything that has to be read goes to full bone. */
.qband--shot .qpanel__head .lead,
.qband--shot .qstrip__who { color: var(--bone); }
/* a hairline of the brand gold on the top edge, so the destination announces
   itself the moment the band comes into view */
.qband--shot::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--gold); z-index: 3;
}
/* Desktop: the card sits in the left column and the type block is narrower,
   so the frame can be taller and the open slice at the top deeper. */
@media (min-width: 64em) {
  /* A 4:3 frame across a 1440px band is a horizontal slice whatever you do,
     so the band is made as deep as the layout allows and the crop is biased
     UP: at 32vw and 60% it showed a wall and some windows, which is not a
     photograph of a finished house. Deeper and higher catches the roofline,
     the elevation and the head of the drive in one read. */
  .qshot { height: clamp(520px, 38vw, 720px); }
  .qshot__img { object-position: 50% 44%; }
  .qshot::after {
    background: linear-gradient(
      to bottom,
      rgba(15, 13, 10, .24)  0%,
      rgba(15, 13, 10, .38) 16%,
      rgba(15, 13, 10, .70) 27%,
      rgba(15, 13, 10, .74) 70%,
      rgba(15, 13, 10, .92) 88%,
      var(--ink)           100%);
  }
}

/* =========================================================================
   3 SEP 2026 — /external-wall-insulation: THE PHOTOGRAPH BEHIND THE HEADLINE
   Cameron, 3 Sep, on his phone: "Dark colour does not read premium, I want
   lighter. A brighter, more premium landing hero." The ink page head goes;
   one of Kyren's finished houses (No. 60, the same job the before/after
   further down shows) is the ground of the whole hero and the type sits on
   it in ink, on a wash of WHITE. Nothing dark is added to the picture.

   THE WASH IS MEASURED, NOT PICKED. --wash-m / --wash-t / --wash-d are set
   inline per page by _build/hero_wash.py from the photograph's own pixels:
   the alpha of white that lifts the 5th-percentile pixel under the type
   block to sRGB 136 (5.0:1 for --text; the floor is 4.5) and under the H1
   to 111 (3.5:1; floor 3.0). Solved in sRGB, not linear light, because that
   is how a browser composites rgba(). The real glyph runs are then sampled
   on the render by the contrast probe in _verify-ewi-3sep/.

   On a phone the wash belongs to the section from (--phero-clear - 130px)
   down: at its alpha over the type block, ramping to nothing across the
   130px above it, so the band under the fixed header is the photograph and
   the wash can never read as a plate. From 64em the type has a column on
   the left and the wash runs sideways across it, gone by 62%, so the house
   on the right is untouched. No blur, no dark scrim, no flat overlay.
   ========================================================================= */
.phero { position: relative; isolation: isolate; overflow: hidden; background: var(--paper-2); color: var(--text);
  --phero-clear: 158px; }
.phero__img { position: absolute; inset: 0; z-index: -2; }
.phero__img picture, .phero__img img { display: block; width: 100%; height: 100%; }
.phero__img img { object-fit: cover; object-position: 50% 50%; }
.phero::before { content: ""; position: absolute; left: 0; right: 0; z-index: -1;
  top: calc(var(--phero-clear) - 130px); bottom: 0;
  background: linear-gradient(to top,
    rgba(255,255,255,var(--wash-m)) 0,
    rgba(255,255,255,var(--wash-m)) calc(100% - 130px),
    rgba(255,255,255,calc(var(--wash-m) * .55)) calc(100% - 70px),
    rgba(255,255,255,0) 100%); }
.phero__in { position: relative; padding-top: var(--phero-clear); padding-bottom: 0; }
.phero__col { max-width: 46ch; }
/* Ink for everything on the photograph. The muted grey is 6.6:1 on paper and
   died at 1.4:1 on a white rendered wall in the 30 Aug measurement; here the
   hierarchy is size and weight, and every word that has to be read is --text. */
.phero .crumbs, .phero .crumbs a { color: var(--text); }
.phero .crumbs a:hover { color: var(--gold-ink); }
.phero .crumbs li + li::before { color: var(--gold-ink); }
.phero .krule { background: var(--gold-ink); margin-bottom: 14px; }
.phero .t-h1 { color: var(--text); margin: 10px 0 12px; }
.phero .lead { color: var(--text); }
/* ONE dominant ask, and the phone beside it. The quote button anchors to
   #quote on this page; the call route stays a real tel: link with a 44px
   tap height, and the pinned Call us / WhatsApp bar is under the thumb too. */
.phero__cta { display: flex; flex-wrap: wrap; align-items: center; gap: 0 14px; margin-top: 12px; }
.phero__cta .btn--solid { flex: 0 1 auto; }
.phero__call { display: inline-flex; align-items: center; min-height: 44px; padding: 0 2px;
  font-size: var(--fs-small); font-weight: 600; color: var(--text); text-decoration: none; white-space: nowrap; }
.phero__call span { font-family: var(--f-mono); font-variant-numeric: tabular-nums; font-size: 1rem; font-weight: 500;
  margin-left: 7px; border-bottom: 2px solid var(--gold-ink); padding-bottom: 1px; }
.phero__call:hover span { border-color: var(--text); }
/* The advert's four promises, verbatim markup from adtrust(), sitting at the
   foot of the hero so they are in the first screen with the ask. */
.phero .trustline { border-bottom: 0; }
.phero .trustline ul { padding-block: 6px 14px; gap: 2px 20px; }
.phero .trustline li { color: var(--text); font-size: .86rem; }
.phero .trustline li::before { background: var(--gold-ink); }
@media (min-width: 40em) {
  .phero { --phero-clear: 190px; }
  .phero::before { background: linear-gradient(to top,
    rgba(255,255,255,var(--wash-t)) 0,
    rgba(255,255,255,var(--wash-t)) calc(100% - 130px),
    rgba(255,255,255,calc(var(--wash-t) * .55)) calc(100% - 70px),
    rgba(255,255,255,0) 100%); }
  .phero__cta { gap: 6px 22px; }
  .phero__cta .btn--solid { flex: 0 0 auto; }
}
@media (min-width: 64em) {
  .phero { min-height: 600px; display: flex; flex-direction: column; justify-content: flex-end; }
  .phero__img img { object-position: 50% 45%; }
  .phero::before { top: 0; background: linear-gradient(90deg,
    rgba(255,255,255,var(--wash-d)) 0%,
    rgba(255,255,255,var(--wash-d)) 46%,
    rgba(255,255,255,calc(var(--wash-d) * .45)) 54%,
    rgba(255,255,255,0) 62%); }
  .phero__in { padding-top: calc(var(--hdr-h) + 64px); padding-bottom: 0; }
  .phero__col { max-width: 34rem; }
  .phero .t-h1 { margin: 16px 0 14px; }
  .phero .trustline ul { max-width: 40rem; padding-block: 12px 40px; gap: 4px 20px; }
}
