@import url("../fonts/fonts.css");

/* =========================================================================
   PLYMOUTH BLOCK MANAGEMENT, "Considered"
   An editorial, architectural design system.
   Palette: navy · gold · white paper (Hudsons-style)
   ========================================================================= */

:root{
  /* colour */
  /* ---- colour ------------------------------------------------------------
     Single source of truth. Re-skinning the whole site = editing this block.
     The *-rgb channel vars back every rgba() tint below, so translucent
     lines/overlays follow the palette instead of drifting from it.        */
  /* Palette matched to the PBM logo: deep navy + green + silver/white.
     (--gold / --gold-2 keep their names for compatibility but now hold GREEN.) */
  --ink-rgb:15,24,46;      /* #0f1b3d navy (from logo background) */
  --navy-rgb:15,24,46;
  --paper-rgb:255,255,255;
  --gold-rgb:106,150,72;   /* #7cb342 PBM green */

  --ink:#0f182e;           /* headings + primary text (deep navy) */
  --navy:#0f182e;          /* dark bands / primary buttons */
  --navy-2:#1b2846;        /* lifted navy, consecutive dark bands / hover */
  --body:#3f4552;          /* secondary body copy on light bg (darkened 2026-07-24 for contrast) */
  /* Darkened #8a8a95 -> #6f6f7c on 2026-07-27. The old value measured 3.41:1 on white, below the
     WCAG AA 4.5:1 minimum, and it carries the breadcrumbs on EVERY page plus all 68 news card
     dates. #6f6f7c measures 4.96:1. Keep any replacement at or below luminance 0.183. */
  --muted:#6f6f7c;         /* meta / captions */
  --muted-tint:#f2f2f2;
  --paper:#ffffff;         /* page bg AND light text on navy, both white */
  --paper-2:#f2f4f2;       /* alt section band + utility bar (soft neutral) */
  --card:#ffffff;
  --gold:#4a6d2c;          /* accent, PBM green (darkened for AA on white) */
  --gold-2:#a7c28e;        /* lighter green for on-dark use */
  --green-hero:#7cb342;    /* the logo green at full strength (on dark only) */
  --line:rgba(var(--ink-rgb),.14);
  --line-soft:rgba(var(--ink-rgb),.08);
  --white:#ffffff;

  /* type */
  /* TWO faces, as the rest of this stylesheet has always assumed (2026-08-16).
     --serif and --sans used to BOTH be Lato: 16 rules asked for var(--serif) and got
     the body face back, so headings, pull quotes, stats and the marquee had no voice
     of their own. Source Serif 4 now fills that role — a humanist serif built as a
     companion to a humanist sans, with a true 300 Light to match h1/h2/.display.
     Body copy, UI, buttons and eyebrows all stay on Lato.
     To revert the whole site to one face, point --serif back at Lato here. */
  --serif:"Source Serif 4","Source Serif Fallback",Georgia,"Times New Roman",serif;
  --sans:"Lato",-apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif;

  /* rhythm */
  --wrap:1240px;
  --gutter:clamp(20px,5vw,72px);
  --section:clamp(54px,6.6vw,104px);
  --radius:0;              /* Hudsons is sharp-cornered throughout */
  --radius-lg:0;

  --ease:cubic-bezier(.22,.61,.36,1);
}

/* ---------- reset-ish ---------- */
*,*::before,*::after{box-sizing:border-box}
/* overflow-x:hidden on <body> makes body a scroll container, which silently breaks every
   position:sticky descendant: the sticky element resolves against body's scrollport, and body
   does not scroll, so it just scrolls away. overflow-x:clip gives the same horizontal guard
   without creating the container. Safari picked it up in 16, which is our floor. */
html,body{overflow-x:clip;max-width:100%}
svg{max-width:100%}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;overflow-x:clip}
/* grid/flex children default to min-width:auto which can force horizontal overflow */
.grid>*,.hero-grid>*,.feature>*,.stat-strip>*,.article-layout>*,.footer-grid>*,.flex>*{min-width:0}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:clamp(16px,1.05vw,18px);line-height:1.65;
  font-feature-settings:"kern","liga","cv11";
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:clip;   /* not hidden - see the note on html,body above */
}
img{max-width:100%;height:auto;display:block}
a{color:inherit;text-decoration:none}
button{font:inherit;cursor:pointer}
::selection{background:var(--gold);color:var(--paper)}
/* Surfaces the browser draws rather than the stylesheet: the caret, the focus ring and the
   scrollbar all ship in a blue that belongs to no part of this palette. */
html{caret-color:var(--gold);scrollbar-color:var(--line) transparent}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:2px}
::-webkit-scrollbar{width:12px;height:12px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{background:var(--line);border:3px solid var(--paper);border-radius:8px}
::-webkit-scrollbar-thumb:hover{background:var(--muted)}
/* Headings set their own rag rather than breaking wherever the box ends. */
h1,h2,h3,.display,.sec-head h2{text-wrap:balance}
p.lede,.ph-copy>p{text-wrap:pretty}

/* ---------- type ---------- */
/* Every heading starts each word with a capital (client 2026-08-04, "all headings", following
   his "make all higher cage first words" on What We Do). Done here as a DESIGN rule rather than
   by re-casing 842 headings in render.py, for three reasons:
     1. `capitalize` only raises the FIRST letter of each word and leaves the rest alone, so
        acronyms survive. A Python title-case pass over the same headings mangled ten of them —
        EPC->Epc, LVT->Lvt, FTT->Ftt, PAS 9980->Pas 9980, Grade II->Grade Ii, S.20C->S.20c.
     2. It reaches source-derived headings on the 68 news/legal articles without editing the
        client's own words in content.json.
     3. New content picks it up automatically, so it cannot drift.
   NB browsers also capitalise after a hyphen, which is what makes "Award-winning" render as
   "Award-Winning" — the exact example the client gave. Small words ("to", "and", "of") ARE
   capitalised too; CSS has no notion of title-case stop words. Delete this one declaration to
   revert the whole site. */
h1,h2,h3,h4{font-family:var(--serif);font-weight:400;line-height:1.04;
  letter-spacing:-.02em;margin:0;font-optical-sizing:auto;color:var(--ink)}
/* NB no text-transform here. Heading case is decided in render.py's finalize(), which can tell a
   label from a sentence and knows the acronym list; CSS capitalize could do neither and was
   capitalising every 'With', 'And' and 'A' in a ten-word question. */
.display{font-size:clamp(2.5rem,4.8vw,4.2rem);font-weight:300;letter-spacing:-.03em;line-height:1}
h1{font-size:clamp(2.15rem,3.9vw,3.5rem);font-weight:300}
h2{font-size:clamp(1.75rem,2.9vw,2.5rem);font-weight:300}
h3{font-size:clamp(1.3rem,1.9vw,1.7rem);font-weight:400}
h4{font-size:1.15rem;font-weight:400}
p{margin:0 0 1.1em}
.lede{font-size:clamp(1.1rem,1.5vw,1.35rem);line-height:1.5;color:var(--navy);
  font-weight:400;letter-spacing:-.01em}
em,i{font-style:italic}
strong{font-weight:700}
.eyebrow{font-family:var(--sans);font-size:.72rem;font-weight:700;letter-spacing:.22em;
  text-transform:uppercase;color:var(--gold);display:inline-flex;align-items:center;gap:.7em}
.eyebrow::before{content:"";width:26px;height:1px;background:var(--gold);display:inline-block}
.serif-accent{font-weight:400;color:var(--gold)}

/* ---------- layout ---------- */
.wrap{max-width:var(--wrap);margin-inline:auto;padding-inline:var(--gutter)}
.wrap-wide{max-width:1480px;margin-inline:auto;padding-inline:var(--gutter)}
.section{padding-block:var(--section)}
.section-sm{padding-block:clamp(38px,4.4vw,66px)}
.grid{display:grid;gap:clamp(24px,3vw,48px)}
.cols-2{grid-template-columns:repeat(2,1fr)}
.cols-3{grid-template-columns:repeat(3,1fr)}
.cols-4{grid-template-columns:repeat(4,1fr)}
@media(max-width:900px){.cols-3,.cols-4{grid-template-columns:repeat(2,1fr)}}
@media(max-width:620px){.cols-2,.cols-3,.cols-4{grid-template-columns:1fr}}
.hairline{height:1px;background:var(--line);border:0;margin:0}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:.6em;padding:.95em 1.9em;border-radius:0;
  font-family:var(--sans);font-weight:400;font-size:.82rem;letter-spacing:.1em;text-transform:uppercase;
  border:1px solid transparent;transition:.4s var(--ease);position:relative}
.btn svg{width:15px;height:15px;transition:transform .4s var(--ease)}
.btn:hover svg{transform:translateX(4px)}
.btn-primary{background:var(--navy);color:var(--paper)}
.btn-primary:hover{background:var(--gold)}
.btn-gold{background:var(--gold);color:var(--paper)}
.btn-gold:hover{background:var(--navy)}
.btn-ghost{border-color:var(--gold);color:var(--gold)}
.btn-ghost:hover{background:var(--gold);color:var(--paper)}
.btn-light{background:var(--paper);color:var(--ink)}
.btn-light:hover{background:var(--gold);color:var(--paper)}
.link-underline{position:relative;font-weight:700;color:var(--navy);display:inline-flex;gap:.5em;align-items:center}
/* inline SVGs have no intrinsic size, without this they expand to fill the flex line */
.link-underline svg{width:15px;height:15px;flex:none;transition:transform .4s var(--ease)}
.link-underline:hover svg{transform:translateX(4px)}
.link-underline::after{content:"";position:absolute;left:0;bottom:-3px;height:1px;width:100%;
  background:currentColor;transform:scaleX(0);transform-origin:right;transition:transform .45s var(--ease)}
.link-underline:hover::after{transform:scaleX(1);transform-origin:left}

/* ---------- header ---------- */
.site-header{position:fixed;inset:0 0 auto;z-index:100;transition:.5s var(--ease);
  background:var(--paper);border-bottom:1px solid var(--line-soft)}
.site-header .bar{display:flex;align-items:center;justify-content:space-between;
  padding:12px var(--gutter);transition:.45s var(--ease)}
.site-header.scrolled{background:rgba(var(--paper-rgb),.9);backdrop-filter:blur(14px);
  border-bottom:1px solid var(--line-soft)}
.site-header.scrolled .bar{padding-block:14px}
.brand{display:flex;flex-direction:column;align-items:center;gap:6px;font-family:var(--serif);
  font-size:.72rem;line-height:1;text-align:center}
.brand .mark{width:46px;height:46px;border-radius:50%;background:transparent;color:var(--gold);
  border:1.5px solid var(--gold);display:grid;place-items:center;font-size:.74rem;font-weight:700;
  letter-spacing:.02em;flex:none}
.brand-logo{display:block;flex:none}
.brand-logo img{width:clamp(150px,15vw,196px);height:auto;display:block}
/* header logo (navy tile), sits on the light header, condenses on scroll */
/* The AI-generated lockup is near-square (1.03) rather than wide, so it needs more height than
   the old oval logo to read at all, its wordmark lines are tiny. Raised 62–80px → 76–100px
   (2026-07-20). NB this sets the header height, which .hero-grid's padding-top is tuned to. */
/* Client 2026-07-20: "needs to be bigger so it takes up the corner". 76–100px -> 96–130px.
   Header bar padding also tightens so the logo fills the corner rather than floating in it. */
/* Client 2026-07-21: old oval logo back in the header, WHITE artwork on a GREEN tile.
   The tile is CSS (not baked into the PNG) so it tracks --gold if the palette moves. */
/* Green OVAL logo on plain white (client 2026-07-23) — the green tile/box was removed; the oval
   is baked into the PNG (pbm-oval-green.png), so no background here. */
.header-logo{display:inline-flex;align-items:center;position:relative}
/* Trade mark mark, bottom-left of the logo (client 2026-07-28). */
.brand-tm{position:absolute;left:0;bottom:6px;font-size:.62rem;font-weight:700;line-height:1;
  color:var(--gold);letter-spacing:0}
@media(max-width:560px){.brand-tm{bottom:9px;font-size:.7rem}}
/* Deliberate: the header CONDENSES on scroll (client-approved), which requires the logo's layout
   box to shrink, so transform:scale cannot substitute without leaving the old box behind. One
   element, two transitions per scroll-direction change, inside a position:fixed subtree. */
.header-logo img{height:clamp(56px,5vw,72px);width:auto;transition:height .45s var(--ease)} /* impeccable-disable-line layout-transition */
.site-header.scrolled .header-logo img{height:50px}
/* the AI lockup now sits in the footer at a comfortable size */
.site-footer .brand-logo img{width:auto;height:clamp(150px,15vw,210px)}
.brand .wordmark{font-size:.66rem;letter-spacing:.24em;text-transform:uppercase;color:var(--gold);
  font-weight:400;white-space:nowrap}
.brand small{display:none}
.nav{display:flex;align-items:center;gap:24px}
.nav a{font-size:.95rem;font-weight:500;letter-spacing:.07em;text-transform:uppercase;color:var(--gold);position:relative;padding:4px 0;white-space:nowrap}
.nav a::after{content:"";position:absolute;left:0;bottom:-3px;height:1px;width:100%;background:var(--gold);
  transform:scaleX(0);transform-origin:right;transition:transform .4s var(--ease)}
.nav a:hover::after,.nav a.active::after{transform:scaleX(1);transform-origin:left}
.nav a:hover,.nav a.active{color:var(--ink)}
.nav-cta{display:flex;align-items:center;gap:18px;flex:none}
/* THE HEADER PHONE IS THE 24-HOUR EMERGENCY LINE and is styled entirely in the emergency red used
   by the footer band, at the client's request (2026-07-28: "so all in red"). Three stacked lines:
   label, number, "Dial zero". The stack is ~42px tall, comfortably under the logo's
   clamp(56px,5vw,72px), so it does not change the header height that .hero-grid is tuned against. */
.header-phone{display:inline-flex;align-items:center;gap:.55em;font-weight:700;color:#c0392b;
  font-size:1.02rem;white-space:nowrap;letter-spacing:.01em}
.header-phone svg{width:19px;height:19px;stroke:#c0392b;flex:none}
.header-phone:hover,.header-phone:hover .ph-label,.header-phone:hover .num,.header-phone:hover .ph-sub{color:#a93226}
.header-phone:hover svg{stroke:#a93226}
.header-phone .ph-text{display:flex;flex-direction:column;line-height:1.12}
.header-phone .ph-label{font-size:.68rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:#c0392b;white-space:nowrap}
.header-phone .num{font-size:.98rem;color:#c0392b}
.header-phone .ph-sub{font-size:.68rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:#c0392b;white-space:nowrap}
/* Client 2026-07-28: make the header CTA smaller so it sits lighter beside the phone. */
.nav-cta .btn{padding:.72em 1.25em;font-size:.72rem}
.has-menu{position:relative;display:flex;align-items:center}
.dropdown{position:absolute;top:calc(100% + 18px);left:50%;transform:translateX(-50%) translateY(8px);
  background:var(--card);border:1px solid var(--line-soft);border-radius:0;padding:14px;
  min-width:290px;box-shadow:0 30px 60px -30px rgba(var(--ink-rgb),.4);opacity:0;visibility:hidden;
  transition:.35s var(--ease);display:grid;gap:2px}
.has-menu:hover .dropdown{opacity:1;visibility:visible;transform:translateX(-50%) translateY(0)}
.dropdown a{padding:10px 14px;border-radius:0;font-size:.9rem;display:flex;justify-content:space-between;
  align-items:center;transition:.25s}
.dropdown a::after{display:none}
.dropdown a:hover{background:var(--muted-tint)}
.dropdown a span{color:var(--muted);font-size:.75rem;display:inline-flex}
.dropdown a span svg{width:12px;height:12px;flex:none}
.menu-toggle{display:none;width:44px;height:44px;border:1px solid var(--gold);border-radius:0;
  background:transparent;flex-direction:column;gap:4px;align-items:center;justify-content:center}
.menu-toggle span{width:18px;height:1.5px;background:var(--ink);transition:.3s}

/* Mobile nav, full-screen overlay (rebuilt 2026-07-20 to a client reference: big centred links,
   close button top-right). Rendered in the SITE's language, not the reference's: navy ground,
   Lato uppercase with the same letter-spacing as the desktop nav, green accents.
   z-index sits ABOVE the header (100) so the overlay genuinely covers the page, the close
   button is then the only control, which is the whole point of the pattern. */
.mobile-nav{position:fixed;inset:0;z-index:200;background:var(--ink);color:var(--paper);
  overflow-y:auto;overscroll-behavior:contain;display:none;
  opacity:0;visibility:hidden;transition:opacity .4s var(--ease),visibility .4s var(--ease)}
.mobile-nav.open{opacity:1;visibility:visible}
.mnav-close{position:absolute;top:16px;right:calc(var(--gutter) - 8px);width:52px;height:52px;
  display:grid;place-items:center;background:transparent;border:0;color:var(--paper);
  cursor:pointer;transition:color .25s,transform .25s var(--ease)}
.mnav-close svg{width:30px;height:30px}
.mnav-close:hover{color:var(--gold-2);transform:rotate(90deg)}
/* `safe center` centres a short menu but falls back to flex-start once the list overflows, plain `center` would push the first links above the scroll origin and make them unreachable
   on short screens. The unprefixed `center` is the fallback for browsers that don't parse it. */
.mnav-inner{min-height:100%;display:flex;flex-direction:column;align-items:center;
  justify-content:center;justify-content:safe center;
  text-align:center;padding:88px var(--gutter) 52px;gap:0}
/* primary links */
.mobile-nav a{display:block;font-family:var(--sans);font-weight:300;text-transform:uppercase;
  letter-spacing:.09em;font-size:clamp(1.45rem,6.2vw,2.05rem);line-height:1.15;
  color:var(--paper);padding:clamp(13px,2.1vh,22px) 0;border:0;transition:color .25s}
.mobile-nav a:hover,.mobile-nav a:focus-visible{color:var(--gold-2)}
/* grouped sub-links (What We Do items, and the More column) */
.mnav-subs{display:flex;flex-direction:column;gap:0;margin:2px 0 10px}
.mobile-nav .sub{font-size:clamp(.92rem,3.6vw,1.02rem);letter-spacing:.07em;font-weight:400;
  color:rgba(var(--paper-rgb),.6);padding:7px 0;text-transform:uppercase}
.mobile-nav .sub:hover{color:var(--gold-2)}
.mnav-label{font-size:.7rem;letter-spacing:.22em;text-transform:uppercase;
  color:var(--gold-2);margin:26px 0 4px}
.mnav-cta{margin-top:30px;text-transform:uppercase;letter-spacing:.09em}
.mobile-nav a.mnav-cta{font-size:.85rem;color:var(--paper);padding:1em 2em}
.mobile-nav a.mnav-cta:hover{color:var(--paper)}
/* Desktop nav appears from 1201px up. History worth keeping: this was raised to 1281px on
   2026-07-27 because the bar genuinely did not fit between 1201 and 1239 once the language chip
   joined it (the CTA ran 26px past the edge and was silently clipped by body{overflow-x:hidden}).
   On 2026-07-28 "Building Safety" moved out of the top-level nav into the What We Do dropdown,
   which freed enough width that the bar fits again from 1160 up with 20px to spare, so the
   threshold is back at 1201 and more laptops get the full nav. Re-measure before changing. */
@media(max-width:1200px){
  .nav,.nav-cta .btn{display:none!important}
  .has-menu .dropdown{display:none!important}   /* absolutely-positioned dropdown could leak width */
  .menu-toggle{display:flex}
  .mobile-nav{display:block}
}
.ph-abbr{display:none}
@media(max-width:560px){
  .header-phone .ph-text{display:none}   /* the full three-line block does not fit */
  .header-phone .num{display:none}
  /* Once it is icon-only it measured 19px tall, far below a usable tap target for the single
     most important action on a mobile page. Give it a real 44px hit area.
     2026-08-16: icon-only also dropped the client's "24 hour" / "in red" instruction on phones,
     so the icon now stacks over an abbreviated red label. Still 44px, still one tap. */
  .header-phone{width:auto;min-width:44px;height:44px;flex-direction:column;justify-content:center;
    align-items:center;gap:1px}
  .header-phone svg{width:20px;height:20px}
  .ph-abbr{display:block;font-size:.58rem;font-weight:700;letter-spacing:.06em;
    text-transform:uppercase;color:#c0392b;line-height:1}
  .header-phone:hover .ph-abbr{color:#a93226}
}

/* ---------- hero ---------- */
.hero{position:relative;padding-top:clamp(150px,20vh,220px);padding-bottom:var(--section);
  overflow:hidden}
.hero-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(30px,5vw,80px);align-items:end}
@media(max-width:940px){.hero-grid{grid-template-columns:1fr;gap:40px}}
.hero .display{margin-bottom:.3em}
.hero-media{position:relative;border-radius:var(--radius-lg);overflow:hidden;aspect-ratio:4/5;
  box-shadow:0 40px 80px -40px rgba(var(--ink-rgb),.5)}
.hero-media img{width:100%;height:100%;object-fit:cover}
.hero-badge{position:absolute;bottom:20px;left:20px;right:20px;background:rgba(var(--ink-rgb),.72);
  backdrop-filter:blur(10px);color:var(--paper);border-radius:0;padding:16px 20px;
  display:flex;align-items:center;gap:14px;font-size:.85rem}
.hero-badge .dot{width:9px;height:9px;border-radius:50%;background:var(--gold-2);flex:none;
  box-shadow:0 0 0 4px rgba(var(--gold-rgb),.25)}
.hero-stats{display:flex;gap:clamp(24px,4vw,54px);margin-top:44px;flex-wrap:wrap}
.hero-stats .stat .n{font-family:var(--serif);font-size:clamp(2rem,3.4vw,3rem);line-height:1;
  color:var(--navy);font-weight:300}
.hero-stats .stat .l{font-size:.8rem;text-transform:uppercase;letter-spacing:.12em;color:var(--muted);
  margin-top:8px}

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

/* ---------- pill / meta ---------- */
.pill{display:inline-flex;align-self:flex-start;align-items:center;gap:.5em;padding:.4em .9em;border-radius:0;
  border:1px solid var(--line);font-size:.78rem;font-weight:400;letter-spacing:.02em;background:var(--card)}
.pill .dot{width:6px;height:6px;border-radius:50%;background:var(--gold)}

/* ---------- cards ---------- */
.card{background:var(--card);border:1px solid var(--line-soft);border-radius:var(--radius-lg);
  overflow:hidden;transition:.5s var(--ease);display:flex;flex-direction:column}
.card:hover{transform:translateY(-6px);box-shadow:0 40px 70px -44px rgba(var(--ink-rgb),.45);
  border-color:var(--line)}
.card .card-media{aspect-ratio:16/11;overflow:hidden}
.card .card-media img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.card:hover .card-media img{transform:scale(1.05)}
.card .card-body{padding:26px 26px 30px;display:flex;flex-direction:column;gap:12px;flex:1}
.card .card-body h3{font-size:1.35rem}
.card .card-body p{color:var(--body);font-size:.95rem;margin:0;flex:1}
.card .card-foot{margin-top:6px}

/* service list rows */
.svc-row{display:grid;grid-template-columns:auto 1fr auto;gap:clamp(20px,4vw,60px);
  align-items:baseline;padding:clamp(26px,3.4vw,42px) 0;border-top:1px solid var(--line);
  transition:.4s var(--ease)}
.svc-row:last-child{border-bottom:1px solid var(--line)}
.svc-row .num{font-family:var(--serif);font-size:1rem;color:var(--gold)}
.svc-row .svc-main h3{font-size:clamp(1.5rem,2.6vw,2.2rem);transition:.4s var(--ease)}
.svc-row .svc-main p{color:var(--body);margin:.5em 0 0;max-width:60ch}
.svc-row:hover{padding-left:clamp(6px,1.4vw,22px)}
.svc-row:hover .svc-main h3{color:var(--gold)}
.svc-row .svc-go{width:52px;height:52px;border-radius:50%;border:1px solid var(--line);
  display:grid;place-items:center;transition:.4s var(--ease);flex:none}
.svc-row .svc-go svg{width:18px;height:18px}
.svc-row:hover .svc-go{background:var(--navy);border-color:var(--navy);color:var(--paper);transform:rotate(-45deg)}
@media(max-width:680px){.svc-row{grid-template-columns:auto 1fr}.svc-row .svc-go{display:none}}

/* feature blocks */
.feature{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(24px,3vw,44px)}
@media(max-width:820px){.feature{grid-template-columns:1fr}}
.feature .item{padding-top:28px;border-top:2px solid var(--ink)}
.feature .item .ico{width:44px;height:44px;color:var(--gold);margin-bottom:18px}
.feature .item .ico svg{width:100%;height:100%}
.feature .item h4{font-family:var(--serif);font-size:1.35rem;margin-bottom:.4em}
.feature .item p{color:var(--body);font-size:.95rem;margin:0}

/* split band */
/* Dark bands (2026-07-20): flat navy over ~2,900px read as an empty slab. Subtle depth, a soft lift at the top edge and a slight settle toward the base, plus tighter vertical
   rhythm and a short accent rule instead of a stretched 1160px hairline. */
.band{color:var(--paper);
  background:linear-gradient(180deg,#17233f 0%,#0f182e 62%,#0c1427 100%)}
.band.section{padding-block:clamp(54px,6.6vw,100px)}
.band .sec-head{margin-bottom:clamp(18px,2.2vw,30px)}
.band .sec-head::after{max-width:none;width:64px;height:2px;background:var(--gold-2);
  margin-top:clamp(14px,1.6vw,20px)}
.band h2,.band h3,.band h4{color:var(--paper)}
.band .eyebrow{color:var(--gold-2)}
.band .lede{color:rgba(var(--paper-rgb),.82)}
.band a.link-underline{color:var(--gold-2)}
.band-ink{background:var(--ink);color:var(--paper)}
.band-ink h2,.band-ink h3{color:var(--paper)}
.band-paper2{background:var(--paper-2)}

/* stat strip */
.stat-strip{display:grid;grid-template-columns:repeat(4,1fr);gap:0;border:1px solid var(--line);
  border-radius:var(--radius-lg);overflow:hidden;background:var(--card)}
.stat-strip .cell{padding:clamp(28px,3vw,44px);border-right:1px solid var(--line)}
.stat-strip .cell:last-child{border-right:0}
.stat-strip .n{font-family:var(--serif);font-size:clamp(2.2rem,3.6vw,3.4rem);color:var(--navy);
  line-height:1;font-weight:300}
.stat-strip .l{margin-top:12px;font-size:.85rem;color:var(--body);line-height:1.4}
@media(max-width:820px){.stat-strip{grid-template-columns:1fr 1fr}
  .stat-strip .cell:nth-child(2n){border-right:0}
  .stat-strip .cell:nth-child(-n+2){border-bottom:1px solid var(--line)}}

/* testimonial */
.quote-block{font-family:var(--serif);font-size:clamp(1.6rem,3.2vw,2.6rem);line-height:1.28;
  font-weight:300;letter-spacing:-.02em;max-width:20ch}
.quote-mark{font-family:var(--serif);font-size:5rem;line-height:.5;color:var(--gold);height:.5em;display:block}

/* marquee */
/* Sits between the dark hero and the dark services band. On the white page background it read
   as a thin white sliver splitting two dark masses (client flagged 2026-07-20), so it now carries
   the navy through and the hero -> locations -> services reads as one continuous dark region. */
.marquee{overflow:hidden;background:var(--ink);border-block:1px solid rgba(var(--paper-rgb),.10);
  padding-block:22px;white-space:nowrap;position:relative}
.marquee::before,.marquee::after{content:"";position:absolute;top:0;bottom:0;width:9%;z-index:2;pointer-events:none}
.marquee::before{left:0;background:linear-gradient(90deg,var(--ink),transparent)}
.marquee::after{right:0;background:linear-gradient(270deg,var(--ink),transparent)}
.marquee .track{display:inline-flex;gap:56px;animation:scroll 40s linear infinite}
.marquee span{font-family:var(--serif);font-size:1.45rem;color:rgba(var(--paper-rgb),.72);
  display:inline-flex;align-items:center;gap:56px}
.marquee span::after{content:"◆";color:var(--gold-2);font-size:.7em;font-style:normal}
@keyframes scroll{to{transform:translateX(-50%)}}

/* ---------- article / prose ---------- */
.page-hero{padding-top:clamp(126px,13vh,158px);padding-bottom:clamp(30px,3.4vw,50px)}
/* Publication date on an article, under the lede where a byline belongs. It replaced a gold-ruled
   eyebrow ABOVE the h1 that also printed the section name already shown in the breadcrumb. */
.ph-byline{margin-top:22px;font-family:var(--sans);font-size:.82rem;letter-spacing:.04em;
  color:var(--muted)}
.page-hero .crumbs{font-size:.82rem;color:var(--muted);margin-bottom:26px;display:flex;gap:10px;
  align-items:center;letter-spacing:.02em}
.page-hero .crumbs a:hover{color:var(--gold)}
/* Page-hero with an image: heading/lede LEFT, contained image panel RIGHT (2026-07-20).
   Replaces the old full-width 16/10 slab that dominated the top of every article page. */
.ph-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(28px,4vw,60px);align-items:center}
@media(max-width:900px){.ph-grid{grid-template-columns:1fr;gap:28px}}
.ph-media{overflow:hidden;aspect-ratio:4/3;border-radius:var(--radius-lg);
  box-shadow:0 40px 80px -50px rgba(var(--ink-rgb),.45)}
.ph-media img{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:900px){.ph-media{aspect-ratio:16/9}}
.as-intro{max-width:780px}
.as-intro p{color:var(--body);margin:0}
/* Help & Resources: stacked guide sections */
.help-list{display:grid;grid-template-columns:1fr 1fr;gap:clamp(16px,1.8vw,24px);align-items:stretch}
@media(max-width:760px){.help-list{grid-template-columns:1fr}}
.help-item:last-child:nth-child(odd){grid-column:1/-1}
.help-item{background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold);
  padding:clamp(24px,2.6vw,36px);display:flex;flex-direction:column}
.help-item p{flex:1}
.help-item h2{font-size:clamp(1.35rem,2.2vw,1.85rem);font-weight:300;margin:0 0 .6em}
.help-item p{color:var(--body);margin:0 0 clamp(18px,2vw,24px)}
.help-item .btn{font-size:.78rem}
.prose{max-width:74ch}
/* 820px measured 95-102 characters per line depending on the face; the readable band is 65-75.
   83 of the 124 pages had body paragraphs over that, which is most of the reading on the site. */
.prose.wide{max-width:70ch}
.prose h2{margin:1.6em 0 .5em;font-size:clamp(1.6rem,2.6vw,2.3rem)}
.prose h3{margin:1.4em 0 .4em;font-size:clamp(1.25rem,2vw,1.6rem)}
.prose h4{margin:1.3em 0 .3em}
.prose p{color:var(--body);margin:0 0 1.15em}
.prose>p:first-of-type{font-size:1.18rem;color:var(--ink);line-height:1.6}
.prose ul,.prose ol{color:var(--body);margin:0 0 1.3em;padding-left:0;list-style:none}
.prose ul li{position:relative;padding:0 0 .7em 1.7em}
.prose ul li::before{content:"";position:absolute;left:0;top:.6em;width:8px;height:8px;
  border-radius:50%;border:1.5px solid var(--gold)}
.prose ol{counter-reset:li}
.prose ol li{counter-increment:li;position:relative;padding:0 0 .7em 2.2em}
.prose ol li::before{content:counter(li,decimal-leading-zero);position:absolute;left:0;top:0;
  font-family:var(--serif);color:var(--gold);font-size:.95em}
/* Mirror prose carries images of wildly different sizes: full-width photographs, portrait shots,
   and small Noun-Project line icons used as section marks in the original Elementor layout.
   width:100% stretched ALL of them to the column: a 118x118 icon was rendering at 350x350 (a 3x
   upscale, visibly blurry) and a 576x1024 portrait ran 622px tall on a phone. Sizing to the
   intrinsic width and capping the height keeps photographs generous and icons icon-sized. */
.prose img{border-radius:var(--radius-lg);margin:2em auto;display:block;
  width:auto;max-width:100%;height:auto;max-height:620px}
/* impeccable-disable-next-line side-tab -- pull-quote rule, not a callout: the refusal covers
   cards, list items, callouts and alerts. A left rule on a blockquote is the typographic
   convention for a quotation and predates the pattern by a few centuries. */
.prose blockquote{margin:2em 0;padding:8px 0 8px 28px;border-left:2px solid var(--gold);
  font-family:var(--serif);font-size:1.4rem;line-height:1.4;font-weight:300;color:var(--ink)}
.prose a{color:var(--navy);text-decoration:underline;text-decoration-color:var(--gold);
  text-underline-offset:3px}
.prose a:hover{color:var(--gold)}
/* real client testimonial embedded in prose (location pages) */
.prose blockquote.testi{border-left-color:var(--gold);background:var(--paper-2);
  padding:26px 30px;font-size:1.12rem;line-height:1.5;font-weight:400;font-style:normal;color:var(--ink)}
.prose blockquote.testi cite{display:block;margin-top:14px;font-size:.82rem;font-style:normal;
  color:var(--gold);font-weight:700;letter-spacing:.05em;text-transform:uppercase}

/* article layout with sidebar */
.article-layout{display:grid;grid-template-columns:1fr 300px;gap:clamp(40px,6vw,90px);
  align-items:start}
/* The aside is roughly 480px of card against 3,000-14,000px of prose, so once it ended the right
   third of every service, town and news page was empty for the entire remaining scroll. Sticking
   it keeps the enquire button and the sibling-page list in reach instead of stranding them at the
   top. align-self:start is required: a stretched grid item has no room to move within its track. */
/* Explicit placement so the contents nav can be FIRST in the DOM (and so first on a phone) while
   still sitting in the right-hand column beside the text on desktop. */
.article-layout>.article-toc{grid-column:2;grid-row:1;position:sticky;top:110px;align-self:start}
.article-layout>.prose{grid-column:1;grid-row:1/span 2}
.article-layout>aside{grid-column:2;grid-row:2;position:sticky;top:110px;align-self:start}
.article-layout:has(>.article-toc)>aside{top:calc(110px + var(--toc-h,0px))}
@media(max-width:960px){
  .article-layout{grid-template-columns:1fr}
  .article-layout>.article-toc,.article-layout>.prose,.article-layout>aside{
    grid-column:1;grid-row:auto;position:static}
}
.aside-card{background:var(--card);border:1px solid var(--line-soft);border-radius:var(--radius-lg);
  padding:28px;position:sticky;top:100px}
.aside-card h4,.aside-card h2{font-family:var(--sans);font-size:.75rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--gold);margin-bottom:16px}
/* :not(.btn) so the sidebar's list-link styling doesn't override .btn's own
   display/padding, that was clipping and left-aligning the "Enquire" button. */
.aside-card a:not(.btn){display:block;padding:9px 0;border-bottom:1px solid var(--line-soft);font-size:.92rem;
  color:var(--body);transition:.25s}
.aside-card a:not(.btn):hover{color:var(--gold);padding-left:6px}

/* ---------- forms ---------- */
.field{margin-bottom:20px}
.field label{display:block;font-size:.78rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--body);margin-bottom:8px;font-weight:700}
.field input,.field textarea,.field select{width:100%;padding:14px 16px;border:1px solid var(--line);
  border-radius:0;background:var(--card);font:inherit;color:var(--ink);transition:.3s}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--navy);
  box-shadow:0 0 0 4px rgba(var(--navy-rgb),.1)}
.field textarea{min-height:150px;resize:vertical}

/* ---------- footer ---------- */
.site-footer{background:var(--ink);color:rgba(var(--paper-rgb),.72);padding-top:clamp(70px,8vw,110px)}
.site-footer h2{color:var(--paper)}
.footer-cta{padding-bottom:clamp(60px,7vw,90px);border-bottom:1px solid rgba(var(--paper-rgb),.12)}
.footer-grid{display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:40px;
  padding-block:clamp(50px,6vw,80px)}
@media(max-width:900px){.footer-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.footer-grid{grid-template-columns:1fr}}
.site-footer .brand{color:var(--paper)}
.footer-col h5{font-family:var(--sans);font-size:.72rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--gold-2);margin:0 0 18px}
.footer-col a{display:block;padding:6px 0;font-size:.92rem;transition:.25s;color:rgba(var(--paper-rgb),.72)}
.footer-col a:hover{color:var(--paper)}
/* Sub-heading inside a footer column (the capability group under Services, 2026-07-27).
   .66rem measured 10.56px, the smallest text on the site; raised to match the column h5 at .72rem. */
.footer-subhead{display:block;margin:18px 0 6px;font-size:.72rem;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(var(--paper-rgb),.5)}
.footer-col a{line-height:1.35}
/* Mobile tap targets. Footer links measured 32px tall; the WCAG 2.5.8 minimum is 24px and the
   platform guidance is 44px, so they get real padding on small screens where they are actually
   thumbed. Desktop spacing is left alone so the footer does not grow a third taller.
   (The .footer-social sizing lives further down the file, so that one is re-stated after it.) */
@media(max-width:700px){
  .footer-col a{padding:11px 0;line-height:1.3}
  /* Remaining sub-40px controls measured on mobile: chips sat at 39px, breadcrumb links at 22px
     and standalone "Learn more" links at 26px. Breadcrumbs stay visually compact but gain a
     usable hit area through padding rather than by growing the type. */
  .chip{padding:.7em 1.2em}
  .crumbs a,.crumbs span{padding:9px 0;display:inline-block}
  .crumbs{gap:8px;flex-wrap:wrap}
  a.link-underline{padding-block:9px}
}
/* Footer brand column: PBM logo on top, contact details under it (client 2026-07-24). */
.footer-brand-logo{display:inline-block;margin:0 0 20px}
.footer-brand-logo img{width:auto;height:clamp(120px,12vw,168px)}
/* Social icons moved down from the top strip (client change 2026-07-20). */
.footer-social{display:flex;align-items:center;gap:14px;margin-top:22px}
.footer-social a{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;padding:0;border:1px solid rgba(var(--paper-rgb),.22);
  color:rgba(var(--paper-rgb),.72);transition:.25s var(--ease)}
.footer-social a:hover{color:var(--ink);background:var(--gold-2);border-color:var(--gold-2)}
.footer-social svg{width:16px;height:16px}
/* 36px is under the 44px touch guidance; declared after the base rule so it actually wins. */
@media(max-width:700px){.footer-social a{width:44px;height:44px}.footer-social{gap:12px}}
.footer-bottom{display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;
  padding-block:30px;border-top:1px solid rgba(var(--paper-rgb),.12);font-size:.82rem}
.footer-bottom a:hover{color:var(--paper)}

/* SECTION RHYTHM (2026-08-17). Every .section carries a full pad top AND bottom, so two plain
   sections in a row left ~288px of empty page between them: a void rather than a breath, and the
   main reason the page felt loose and undifferentiated. Where a coloured band follows, the colour
   change IS the boundary and both pads are earned; where two same-ground sections meet, one pad
   is enough. */
.section:not(.band):not(.band-paper2):not(.band-ink) + .section:not(.band):not(.band-paper2):not(.band-ink){padding-top:0}

/* ---------- reveal animation ---------- */
[data-reveal]{opacity:0;transform:translateY(28px);transition:opacity .9s var(--ease),transform .9s var(--ease)}
[data-reveal].in{opacity:1;transform:none}
[data-reveal][data-delay="1"]{transition-delay:.08s}
[data-reveal][data-delay="2"]{transition-delay:.16s}
[data-reveal][data-delay="3"]{transition-delay:.24s}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition:none!important}
  [data-reveal]{opacity:1;transform:none}
  html{scroll-behavior:auto}
}

/* small-screen typography guards (prevent horizontal clipping) */
@media(max-width:480px){
  .display{font-size:clamp(2.15rem,10.5vw,3rem);letter-spacing:-.03em}
  h1{font-size:clamp(2rem,9vw,2.8rem)}
  .eyebrow{letter-spacing:.14em;flex-wrap:wrap;font-size:.68rem}
  .hero{padding-top:130px}
  .page-hero h1,.page-hero .display{word-break:break-word}
  .prose{max-width:100%}
}
@media(max-width:360px){
  .display{font-size:1.95rem}
}

/* utility */
.text-center{text-align:center}
.mx-auto{margin-inline:auto}
.max-60{max-width:60ch}
.mt-s{margin-top:18px}.mt-m{margin-top:34px}.mt-l{margin-top:56px}
.flex{display:flex}.gap{gap:16px}.wrap-flex{flex-wrap:wrap}.items-center{align-items:center}
.mono{font-variant-numeric:tabular-nums}

/* =========================================================================
   V2, Hudsons-style homepage sections
   Navy/gold editorial treatment applied to Plymouth's own content.
   ========================================================================= */

/* ink == navy in v2, so band-ink would be indistinguishable from band.
   Lift it to navy-2 so consecutive dark bands still read as separate. */
.band-ink{background:var(--navy-2)}

/* The grey utility top bar was DELETED from the markup on 2026-07-20 (email, portal and socials
   moved to the footer; the tagline belongs over the hero visual, not in a utility bar). Its
   .topbar / .tb-* rules were left behind as inert CSS and are removed here (2026-07-27) —
   render.py's header() emits no such element. See the .tb-tag/.tb-emerg note further down. */

/* ---------- centred nav ---------- */
.site-header .bar{gap:24px}
.site-header .nav{flex:1;justify-content:center;gap:clamp(16px,1.9vw,30px)}
.site-header .nav > a,.site-header .has-menu > a{white-space:nowrap;font-size:.76rem;letter-spacing:.09em}
/* HEADER OVERFLOW FIX (2026-07-27). Measured across 125 pages: at a 1440px viewport .nav-cta
   ended at x=1474, i.e. 34px past the edge, so the "Get in touch" button was being CLIPPED by
   body{overflow-x:hidden} on every desktop page between the 1200px nav breakpoint and ~1550px.
   Seven nav items plus the phone plus the CTA simply did not fit at the old spacing.
   Tightening the nav gap and tracking below 1500px recovers ~100px, which keeps the phone number
   visible rather than hiding it. The old rule here was scoped to max-width:1200px, where the
   desktop nav is already hidden, so it never actually applied to anything.
   Space is recovered from SPACING, not type. The page gutter is clamp(20px,5vw,72px), i.e. 72px a
   side at 1440, which is generous for a full-width nav bar, so the header (and only the header)
   tightens its own inline padding. Combined with a smaller nav gap that frees well over the 34px
   needed, and the nav label size stays at .76rem. Two things measured along the way: shrinking the
   font to .72rem instead immediately produced 625 new sub-12px text findings (a bad trade), and
   reducing the nav gap ALONE was not sufficient, hence the padding change as well.
   Widened from 1500 to 1700 on 2026-07-27 when the language switcher joined the bar: 1510px was
   the worst case (106px of overflow) because it sat just above the old breakpoint. */
@media(max-width:1700px){
  .site-header .bar{padding-inline:clamp(20px,2.6vw,40px);gap:16px}
  .site-header .nav{gap:14px}
  .site-header .nav > a,.site-header .has-menu > a{letter-spacing:.05em}
  .nav-cta{gap:12px}
}
/* Raised 1340 -> 1400 on 2026-07-28: adding "· dial 0" widened the phone block to 166px and pushed
   the bar over at 1344 and 1348, i.e. in the narrow band just above the old breakpoint. */
@media(max-width:1400px){
  .site-header .bar{padding-inline:20px}
  .site-header .nav{gap:10px}
  .site-header .nav > a,.site-header .has-menu > a{letter-spacing:.01em}
  .nav-cta .btn{padding:.85em 1.1em}
  .header-logo img{height:clamp(48px,4.2vw,58px)}
}

/* ---------- split hero ---------- */
.hero-split{padding-top:clamp(164px,16vh,196px);padding-bottom:clamp(40px,5vw,70px)}
.hs-grid{display:grid;grid-template-columns:1.25fr 1fr;gap:clamp(18px,2vw,26px);align-items:stretch}
@media(max-width:980px){.hs-grid{grid-template-columns:1fr}}
.hs-media{position:relative;border-radius:var(--radius-lg);overflow:hidden;min-height:clamp(420px,62vh,620px);
  box-shadow:0 40px 90px -50px rgba(var(--ink-rgb),.55)}
.hs-media>img{width:100%;height:100%;object-fit:cover;position:absolute;inset:0}
.hs-media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(var(--ink-rgb),.15) 0%,rgba(var(--ink-rgb),.55) 55%,rgba(var(--ink-rgb),.86) 100%)}
.hs-overlay{position:relative;z-index:2;height:100%;display:flex;flex-direction:column;
  justify-content:flex-end;padding:clamp(26px,3.4vw,52px);color:var(--paper)}
.hs-overlay h1{color:var(--paper);font-size:clamp(2.1rem,4.4vw,3.9rem);font-weight:300;
  letter-spacing:-.03em;line-height:1.02;max-width:17ch}
.hs-overlay .eyebrow{color:var(--gold-2);margin-bottom:18px}
.hs-overlay .eyebrow::before{background:var(--gold-2)}
.hs-overlay p{color:rgba(var(--paper-rgb),.8);max-width:46ch;margin:18px 0 0;font-size:1.02rem}

/* featured panel (gold accent) */

/* ---------- hero enquiry form (right column of the split hero) ----------
   Replaces the featured panel: a white card with a gold top-edge, matching the
   reference lead-capture form. Stretches to the hero image's height; the message
   field grows to absorb the slack. */
.hero-form{background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold);
  padding:clamp(26px,2.1vw,38px);display:flex;flex-direction:column;
  box-shadow:0 50px 100px -55px rgba(var(--ink-rgb),.6)}
.hero-form .eyebrow{font-size:.68rem;margin-bottom:16px}
.hero-form h2{font-size:clamp(1.5rem,2vw,2rem);font-weight:300;letter-spacing:-.02em;color:var(--ink)}
.hero-form .hf-sub{color:var(--body);font-size:.92rem;line-height:1.55;margin:12px 0 22px}
.hero-form form{display:flex;flex-direction:column;flex:1}
.hero-form .field{margin-bottom:14px}
.hero-form .field label{margin-bottom:7px;font-size:.72rem;letter-spacing:.12em;color:var(--muted)}
/* Filled inputs (borderless until focus), mirrors the reference's soft-grey fields,
   reads warmer and more finished than an outline box. */
.hero-form .field input,.hero-form .field textarea{padding:13px 15px;background:var(--paper-2);
  border:1px solid transparent;transition:background .25s,border-color .25s,box-shadow .25s}
.hero-form .field input:focus,.hero-form .field textarea:focus{background:var(--card);
  border-color:var(--navy);box-shadow:0 0 0 4px rgba(var(--navy-rgb),.08)}
.hero-form .field input::placeholder,.hero-form .field textarea::placeholder{color:var(--muted)}
.hero-form .field.grow{flex:1;display:flex;flex-direction:column;min-height:104px}
.hero-form .field.grow textarea{flex:1;min-height:88px;resize:none}
.hero-form .btn{width:100%;justify-content:center;margin-top:6px;padding-block:1.05em}
.hero-form .hf-ok{display:none;margin:14px 0 0;font-size:.86rem;color:var(--navy);font-weight:400;line-height:1.5}
.hero-form .hf-ok a{color:var(--navy);font-weight:700;text-decoration:underline;text-decoration-color:var(--gold);text-underline-offset:2px}
.hero-form .hf-note{color:var(--muted);font-size:.76rem;text-align:center;margin:14px 0 0}
.hero-form .hf-note a{color:var(--navy);font-weight:700}

/* ---------- split hero: headline over image (left) + floating form card (right) ---------- */
.hero-full{position:relative;overflow:hidden}
.hero-full-media{position:absolute;inset:0}
.hero-full-media img{width:100%;height:100%;object-fit:cover;object-position:center 38%}
/* The header is position:fixed, so hero content must clear it BEFORE any visible gap starts, padding-top = header height + the gap you actually want to see. Measured header is ~123px
   desktop / ~106px mobile since the grey top strip was removed (2026-07-20); the client wants
   the hero image framing the form card on every side, so these add ~40px on top of that.
   RE-MEASURE these if the header's height ever changes again (logo size, strip added back).
   Re-measured 2026-07-23 after green box removed (oval on white): header 97px / ~90px mobile. */
.hero-grid{position:relative;z-index:2;display:grid;grid-template-columns:1.12fr .88fr;
  gap:clamp(26px,3.4vw,54px);align-items:center;min-height:clamp(470px,68vh,620px);
  padding-top:clamp(138px,13vh,158px);padding-bottom:clamp(52px,5vw,78px)}
@media(max-width:1000px){.hero-grid{grid-template-columns:1fr;min-height:0;gap:0;
    padding-top:clamp(130px,12.5vh,150px)}
  .hero-form-col{margin-top:34px}}
.hero-copy{color:var(--paper);max-width:560px}
.hero-copy .eyebrow{color:var(--gold-2);margin-bottom:16px}
.hero-copy .eyebrow::before{background:var(--gold-2)}
/* H1 stepped up a notch at the client's request (2026-07-20), was clamp(2rem,3.1vw,3.2rem). */
.hero-copy h1{color:var(--paper);font-size:clamp(2.25rem,3.5vw,3.65rem);font-weight:300;letter-spacing:-.025em;line-height:1.05}
.hero-copy .serif-accent{color:var(--gold-2)}
.hero-copy .hero-tagline{color:var(--gold-2);font-style:italic;font-weight:400;margin:12px 0 0;font-size:clamp(1rem,1.2vw,1.15rem)}
.hero-copy p{color:rgba(var(--paper-rgb),.88);max-width:44ch;margin:14px 0 0;font-size:clamp(.98rem,1.15vw,1.08rem)}
.hero-copy .hero-tagline + p{margin-top:10px}
.hero-trust{display:flex;flex-wrap:wrap;gap:10px 20px;margin-top:clamp(20px,2.6vw,28px)}
.hero-trust span{display:inline-flex;align-items:center;gap:.5em;color:var(--paper);font-size:.78rem;font-weight:700;letter-spacing:.02em}
.hero-trust svg{width:15px;height:15px;color:var(--gold-2);flex:none}
.hero-form-col{display:flex;justify-content:flex-end}
.hero-form-col .enquiry-card{width:100%;max-width:500px;box-shadow:0 60px 120px -45px rgba(0,0,0,.6)}
.hero-form-col .enquiry-card h3{font-size:clamp(1.3rem,1.7vw,1.55rem)}
.hero-form-col .enquiry-card .enq-sub{font-size:.86rem}
.hero-form-col .enquiry-card .field{margin-bottom:11px}
.hero-form-col .enquiry-card .field input,.hero-form-col .enquiry-card .field select,.hero-form-col .enquiry-card .field textarea{padding:11px 13px}
.hero-form-col .enquiry-card textarea{min-height:88px}
/* short hero form: soft-filled inputs like the reference */
.hero-quick .field input,.hero-quick .field textarea{background:var(--paper-2);border-color:transparent;transition:background .2s,border-color .2s,box-shadow .2s}
.hero-quick .field input:focus,.hero-quick .field textarea:focus{background:var(--card);border-color:var(--navy);box-shadow:0 0 0 4px rgba(var(--navy-rgb),.08)}
.hero-quick .field input::placeholder,.hero-quick .field textarea::placeholder{color:var(--muted)}
/* Two overlays: a strong left-to-right darkening so the left-aligned headline stays legible
   over the light stonework, plus a vertical one for the form card overlap at the bottom. */
.hero-full::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(100deg,rgba(var(--ink-rgb),.9) 0%,rgba(var(--ink-rgb),.72) 34%,rgba(var(--ink-rgb),.32) 66%,rgba(var(--ink-rgb),.12) 100%),
    linear-gradient(180deg,rgba(var(--ink-rgb),.35) 0%,rgba(var(--ink-rgb),.1) 30%,rgba(var(--ink-rgb),.55) 82%,rgba(var(--ink-rgb),.8) 100%)}
.hero-full-inner{position:relative;z-index:2;width:100%;padding-top:clamp(150px,16vh,190px);padding-bottom:clamp(48px,6vw,86px)}
.hero-full-content{max-width:660px;color:var(--paper)}
.hero-full-content .eyebrow{color:var(--gold-2);margin-bottom:20px}
.hero-full-content .eyebrow::before{background:var(--gold-2)}
.hero-full-content h1{color:var(--paper);font-size:clamp(2.4rem,5.2vw,4.6rem);font-weight:300;letter-spacing:-.03em;line-height:1.02}
.hero-full-content .serif-accent{color:var(--gold-2)}
.hero-full-content p{color:rgba(var(--paper-rgb),.86);max-width:52ch;margin:20px 0 0;font-size:clamp(1.02rem,1.4vw,1.2rem)}
/* discovery-form band sits just under the hero; lift the card to overlap slightly */
.enquiry-section{padding-top:0}
.enquiry-section .enquiry-wrap{margin-top:calc(-1 * clamp(40px,5vw,72px));position:relative;z-index:3}

/* ---------- centred intro / section heading ---------- */
/* Hudsons' signature: centred heading, light weight with a bold second half,
   underscored by a full-width hairline gold rule. */
.sec-head{text-align:center;margin-bottom:clamp(26px,3vw,42px)}
.sec-head h2{font-weight:300;font-size:clamp(1.7rem,3vw,2.5rem);letter-spacing:0;margin:0}
/* 600, not 700: Source Serif is self-hosted at 300/400/600, so 700 would be synthesised
   or snapped. 600 is the real cut and reads as the same emphasis against a 300 ground. */
.sec-head h2 b{font-weight:600}
/* A short accent bar, not a stretched divider (2026-08-16). This used to be a 1px hairline up to
   1160px wide, which read as a rule separating things rather than a mark belonging to the heading.
   The navy bands and the left-aligned heads were ALREADY using a 64px/2px bar, so the light
   sections were the odd ones out; all three now match. */
.sec-head::after{content:"";display:block;height:2px;background:var(--gold);
  margin:clamp(18px,2vw,26px) auto 0;width:64px}
.sec-head.on-dark h2{color:var(--paper)}
/* left-aligned section heads get a short left accent bar, not a stretched centred rule */
.sec-head[style*="left"]::after{margin-left:0;margin-right:auto;max-width:64px;width:64px;height:2px}
.intro-statement{text-align:center;max-width:940px;margin-inline:auto}
.intro-statement .eyebrow{justify-content:center}
.intro-statement h2{font-size:clamp(1.8rem,3.4vw,2.9rem);font-weight:300;line-height:1.2;
  letter-spacing:-.025em;margin:22px 0 0}
.intro-statement p{color:var(--body);font-size:1.08rem;max-width:68ch;margin:22px auto 0}

/* ---------- services: icons LEFT, heading+copy RIGHT, on the indigo band ----------
   Mirrors Hudsons' "Our Services": a 4-column grid of gold circular line-icons on the
   left, with the section heading, sub-heading and body copy stacked on the right. */
/* REBUILT 2026-07-20. Was `.svc-split`, icons left, copy right. With only 6 icons and short
   copy that left a large empty well bottom-right and read as two disconnected halves. Now it
   uses the site's standard band pattern: centred .sec-head, a centred intro, then ONE full-width
   row of 6 icons. Fills the measure, matches every other band, no void. */
.svc-intro{color:rgba(var(--paper-rgb),.82);font-size:1.02rem;line-height:1.65;text-align:center;
  max-width:62ch;margin:0 auto clamp(30px,3.4vw,48px)}
/* 3 featured services: image beside copy, alternating sides (client reference 2026-07-20).
   Sits on the navy band, so ticks and body copy take on-dark colours. */
/* Rows are separated by a hairline and generous padding rather than a plain gap, gives the
   block structure instead of three floating repeats. */
.svc-rows{display:flex;flex-direction:column;gap:0}
.svc-row{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,4vw,72px);align-items:center;
  padding-block:clamp(36px,4.4vw,66px);border-top:1px solid var(--line-soft)}
.svc-row:first-child{border-top:0;padding-top:clamp(6px,1vw,14px)}
.band .svc-row{border-top-color:rgba(var(--paper-rgb),.10)}
.svc-row:nth-child(even) .svc-row-media{order:2}
@media(max-width:860px){.svc-row{grid-template-columns:1fr;gap:22px}
  .svc-row:nth-child(even) .svc-row-media{order:0}}
/* A DEFINITE height is required here: with only min-height, the img's height:100% resolves to
   auto, so a portrait source (residential-block-management is 782x1024) renders at its natural
   aspect and inflates the whole row. aspect-ratio pins every row to the same shape. */
.svc-row-media{overflow:hidden;aspect-ratio:3/2;border-radius:var(--radius-lg);position:relative;
  box-shadow:0 36px 72px -38px rgba(0,0,0,.85)}
/* a hairline frame so the photo reads as a placed object, not a pasted rectangle */
.svc-row-media::after{content:"";position:absolute;inset:0;pointer-events:none;
  box-shadow:inset 0 0 0 1px rgba(var(--paper-rgb),.14)}
.band .svc-row-media::after{box-shadow:inset 0 0 0 1px rgba(var(--paper-rgb),.18)}
/* favour the upper third, these are building shots with a lot of foreground lawn/road */
.svc-row-media img{width:100%;height:100%;object-fit:cover;object-position:center 38%;display:block}
.svc-row-copy{display:flex;flex-direction:column;justify-content:center}
.svc-row-copy h3,.svc-row-copy h2{color:var(--ink);font-weight:300;font-size:clamp(1.7rem,3vw,2.5rem);letter-spacing:-.015em;margin:0}
.svc-row-sub{color:var(--gold);font-size:clamp(1.02rem,1.45vw,1.22rem);margin:.7em 0 1.15em;font-weight:400}
.svc-row-copy>p{color:var(--body);margin:0 0 1em;max-width:52ch;font-size:1.01rem;line-height:1.72}
.svc-row-copy>p:last-child{margin-bottom:0}
.svc-row-copy>p.svc-row-sub{color:var(--gold);max-width:none}
.svc-row-copy .link-underline{display:inline-flex;align-items:center;gap:.5em;margin-top:24px;font-weight:700;letter-spacing:.01em;
  color:var(--gold)}
.svc-row-copy .link-underline svg{width:18px;height:18px}
/* dark-band variant (homepage services sits on .band) */
.band .svc-row-copy h3{color:var(--paper)}
.band .svc-row-copy>p.svc-row-sub{color:var(--gold-2)}
.band .svc-row-copy>p:not(.svc-row-sub):not(.prop-meta){color:rgba(var(--paper-rgb),.88)}
.band .svc-row-copy .ticks li{color:rgba(var(--paper-rgb),.94)}
.band .svc-row-copy .ticks li::before{border-color:var(--gold-2)}
.band .svc-row-copy .link-underline{color:var(--gold-2)}
/* Featured services (homepage + Clients & Partners): the photo used to be vertically
   centred and shorter than its copy, so each image floated in a large empty band (client
   2026-07-24). Stretch the media to the full row height so image and copy are level, and
   tighten the vertical rhythm so the section reads as a set, not scattered pieces. */
.svc-rows .svc-row{align-items:stretch;padding-block:clamp(30px,3.4vw,52px)}
/* Let the copy drive the row height and the photo match it exactly (small floor only so a
   short row can't collapse). This keeps image and copy level whichever is taller. */
/* ⚠ max-height is load-bearing. height:100% with aspect-ratio:auto leaves the height indefinite,
   so a PORTRAIT source falls back to its natural ratio: residential-block-management is 782x1024
   and rendered 692px tall against 408px for its landscape neighbours, inflating that row to 791px
   and making the set look scattered - the exact failure the note above this block describes. The
   cap keeps the stretch behaviour for normal rows and stops a tall source running away. */
.svc-rows .svc-row-media{aspect-ratio:auto;height:100%;
  min-height:clamp(240px,20vw,300px);max-height:clamp(320px,26vw,430px)}
.band .svc-rows .svc-row{border-top-color:rgba(var(--paper-rgb),.16)}
@media(max-width:860px){.svc-rows .svc-row-media{height:auto;aspect-ratio:3/2;min-height:0}}
.svc-circles{display:grid;grid-template-columns:repeat(6,1fr);gap:clamp(24px,2.6vw,36px) clamp(12px,1.4vw,20px)}
@media(max-width:1100px){.svc-circles{grid-template-columns:repeat(3,1fr)}}
@media(max-width:560px){.svc-circles{grid-template-columns:repeat(2,1fr)}}
.svc-circle{text-align:center;display:flex;flex-direction:column;align-items:center;gap:14px;
  transition:.4s var(--ease)}
.svc-circle .ring{width:clamp(76px,6.4vw,94px);aspect-ratio:1;border-radius:50%;
  border:1px solid var(--gold);display:grid;place-items:center;
  color:var(--gold);transition:.45s var(--ease);flex:none}
.svc-circle .ring svg{width:36px;height:36px}
/* Reserve 3 lines so labels of 1/2/3 lines don't stagger the grid rows. */
.svc-circle h3{font-family:var(--sans);font-size:.72rem;font-weight:400;line-height:1.45;
  color:var(--gold);letter-spacing:.11em;text-transform:uppercase;max-width:15ch;
  min-height:4.35em;margin:0}
.svc-circle:hover .ring{background:var(--gold);color:var(--navy);transform:translateY(-3px)}
.svc-circle:hover h3{color:var(--paper)}

/* (.svc-copy / .svc-split removed 2026-07-20, the split layout was replaced by the centred
   full-width band above.) */

/* ---------- newsletter (inside the indigo band, per Hudsons) ---------- */
.nl-inband{margin-top:clamp(50px,6vw,86px);text-align:center}
.nl-inband h3{color:var(--paper);font-weight:300;font-size:clamp(1.1rem,1.8vw,1.5rem);margin:0 0 24px}
.nl-inband .news-form{max-width:580px;margin-inline:auto;justify-content:center}
.nl-label{display:block;text-align:left;max-width:580px;margin:0 auto 8px;
  color:rgba(var(--paper-rgb),.8);font-size:.78rem}
.nl-label i{color:#e06666;font-style:normal}

/* ---------- newsletter band ---------- */
.news-form{display:flex;gap:0;flex-wrap:wrap}
.news-form input{flex:1;min-width:220px;padding:14px 16px;border:1px solid var(--line);
  border-radius:0;background:var(--white);font:inherit;color:var(--ink);transition:.3s}
.news-form input:focus{outline:none;border-color:var(--navy);box-shadow:0 0 0 4px rgba(var(--navy-rgb),.1)}
.news-note{font-size:.74rem;color:rgba(var(--paper-rgb),.55);margin:14px 0 0}
.news-ok{display:none;margin:12px 0 0;font-size:.9rem;color:var(--paper);font-weight:400}

/* ---------- accreditations band ---------- */
.accred{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(22px,3vw,44px)}
@media(max-width:820px){.accred{grid-template-columns:1fr}}
.accred .item{text-align:center;padding:clamp(26px,3vw,40px) clamp(18px,2vw,28px);
  background:var(--card);border:1px solid var(--line-soft);border-radius:var(--radius-lg);
  transition:.45s var(--ease)}
.accred .item:hover{transform:translateY(-5px);box-shadow:0 40px 70px -46px rgba(var(--ink-rgb),.4);
  border-color:var(--line)}
.accred .ring{width:64px;aspect-ratio:1;border-radius:50%;border:1px solid var(--line);
  display:grid;place-items:center;color:var(--gold);margin:0 auto 18px}
.accred .ring svg{width:26px;height:26px}
.accred h3{font-size:1.2rem;margin-bottom:.45em}
.accred p{color:var(--body);font-size:.9rem;margin:0}

/* ---------- market updates (navy) ---------- */
.mu-grid{display:grid;grid-template-columns:1.5fr 1fr;gap:clamp(24px,3vw,44px);align-items:start}
@media(max-width:900px){.mu-grid{grid-template-columns:1fr}}
.mu-feature{position:relative;border-radius:var(--radius-lg);overflow:hidden;min-height:clamp(320px,42vh,430px);
  display:flex;flex-direction:column;justify-content:flex-end}
.mu-feature>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  transition:transform .9s var(--ease)}
.mu-feature:hover>img{transform:scale(1.04)}
.mu-feature::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(var(--ink-rgb),.1),rgba(var(--ink-rgb),.9))}
.mu-feature .mu-body{position:relative;z-index:2;padding:clamp(22px,2.6vw,36px)}
.mu-feature h3{color:var(--paper);font-size:clamp(1.4rem,2.2vw,2rem);max-width:22ch}
.mu-feature .mu-meta{color:var(--gold-2);font-size:.75rem;letter-spacing:.14em;
  text-transform:uppercase;margin-bottom:12px}
.mu-list{display:flex;flex-direction:column;gap:2px}
.mu-item{display:grid;grid-template-columns:76px 1fr;gap:16px;padding:16px 0;
  border-top:1px solid rgba(var(--paper-rgb),.14);align-items:center;transition:.35s var(--ease)}
.mu-item:last-child{border-bottom:1px solid rgba(var(--paper-rgb),.14)}
.mu-item .mu-thumb{aspect-ratio:1;border-radius:0;overflow:hidden}
.mu-item .mu-thumb img{width:100%;height:100%;object-fit:cover}
.mu-item h4{color:var(--paper);font-family:var(--serif);font-size:1rem;font-weight:400;
  line-height:1.3;transition:.3s var(--ease)}
.mu-item .mu-date{font-size:.72rem;color:rgba(var(--paper-rgb),.55);margin-top:5px}
.mu-item:hover{padding-left:8px}
.mu-item:hover h4{color:var(--gold-2)}

/* ---------- policies & procedures (document library) ---------- */
.doc-alert{display:flex;align-items:center;gap:clamp(16px,2vw,26px);
  padding:clamp(20px,2.2vw,30px);background:var(--navy);color:var(--paper);
  transition:.4s var(--ease)}
.doc-alert:hover{background:var(--navy-2)}
.doc-alert .doc-ico{border-color:rgba(var(--paper-rgb),.3);color:var(--gold-2)}
.doc-alert-body{flex:1;min-width:0}
.doc-alert-body h3,.doc-alert-body h2{color:var(--paper);font-size:1.25rem;margin:0 0 4px}
.doc-alert-body p{color:rgba(var(--paper-rgb),.72);font-size:.9rem;margin:0}
.doc-dl{flex:none;display:inline-flex;align-items:center;gap:.5em;color:var(--gold-2);
  font-size:.78rem;letter-spacing:.08em;text-transform:uppercase;font-weight:700;white-space:nowrap}
.doc-dl svg,.doc-meta svg{width:15px;height:15px;flex:none}
@media(max-width:620px){.doc-alert{flex-wrap:wrap}.doc-dl{width:100%}}

.doc-list{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(16px,2vw,22px)}
@media(max-width:760px){.doc-list{grid-template-columns:1fr}}
.doc-card{display:flex;gap:18px;align-items:flex-start;padding:clamp(22px,2vw,28px);
  background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold);
  transition:.4s var(--ease)}
.doc-card:hover{transform:translateY(-4px);border-color:var(--line);
  box-shadow:0 40px 70px -46px rgba(var(--ink-rgb),.4)}
.doc-ico{width:48px;height:48px;flex:none;border:1px solid var(--line);border-radius:50%;
  display:grid;place-items:center;color:var(--gold)}
.doc-ico svg{width:22px;height:22px}
.doc-body{min-width:0}
.doc-card h3{font-size:1.18rem;margin:0 0 7px}
.doc-card p{color:var(--body);font-size:.9rem;line-height:1.55;margin:0 0 14px}
.doc-meta{display:inline-flex;align-items:center;gap:.5em;color:var(--gold);
  font-size:.76rem;letter-spacing:.08em;text-transform:uppercase;font-weight:700}
.doc-card:hover .doc-meta{color:var(--navy)}
.doc-foot{margin-top:clamp(28px,3vw,44px);color:var(--body);font-size:1rem}

/* ---------- footer, card dates ---------- */
/* (.tb-tag / .tb-emerg removed 2026-07-27 with the rest of the deleted top strip.) */
/* footer now has a Downloads column (5 total) */
.footer-grid{grid-template-columns:1.5fr 1fr 1fr 1fr 1fr}
@media(max-width:900px){.footer-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.footer-grid{grid-template-columns:1fr}}
/* news card date meta */
.card-meta{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.card-date{font-size:.78rem;color:var(--muted);letter-spacing:.02em}

/* ================= homepage completeness sections ================= */
/* detailed services */
.dsvc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2vw,26px)}
@media(max-width:900px){.dsvc-grid{grid-template-columns:1fr 1fr}}
@media(max-width:600px){.dsvc-grid{grid-template-columns:1fr}}
.dsvc{padding:clamp(22px,2vw,28px);background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold)}
.dsvc h3{font-size:1.14rem;margin-bottom:.5em}
.dsvc p{color:var(--body);font-size:.92rem;margin:0}
.dsvc a{color:var(--navy);text-decoration:underline;text-decoration-color:var(--gold);text-underline-offset:2px}
.dsvc a:hover{color:var(--gold)}
/* benefits */
.benefits-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,2.4vw,32px)}
@media(max-width:900px){.benefits-grid{grid-template-columns:1fr 1fr}}
@media(max-width:600px){.benefits-grid{grid-template-columns:1fr}}
.benefit{padding:clamp(22px,2vw,30px);background:var(--card);border:1px solid var(--line-soft)}
.benefit .ring{width:56px;aspect-ratio:1;border-radius:50%;border:1px solid var(--line);display:grid;place-items:center;color:var(--gold);margin-bottom:16px}
.benefit .ring svg{width:24px;height:24px}
.benefit h3{font-size:1.14rem;margin-bottom:.45em}
.benefit p{color:var(--body);font-size:.92rem;margin:0}
/* tick lists */
.ticks{list-style:none;padding:0;margin:18px 0 0}
.ticks li{position:relative;padding:0 0 .7em 1.9em;color:var(--body)}
.svc-row-copy .ticks{margin-top:22px}
.svc-row-copy .ticks li{padding-bottom:.85em;line-height:1.5}
.ticks li::before{content:"";position:absolute;left:0;top:.5em;width:9px;height:9px;border:2px solid var(--gold);border-radius:50%}
/* testimonials */
.tgrid{column-count:3;column-gap:clamp(18px,2vw,26px)}
/* Homepage variant: three trimmed quotes of similar length, so a real grid with level bottoms
   reads as composed where masonry read as accidental. Full-length quotes on /testimonials/ keep
   the column flow above. */
.tgrid-even{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2vw,26px);
  column-count:auto;align-items:stretch}
.tgrid-even .tcard{margin:0;height:100%}
@media(max-width:900px){.tgrid-even{grid-template-columns:1fr 1fr}}
@media(max-width:600px){.tgrid-even{grid-template-columns:1fr}}
@media(max-width:900px){.tgrid{column-count:2}}
@media(max-width:600px){.tgrid{column-count:1}}
.tcard{margin:0 0 clamp(18px,2vw,26px);padding:clamp(24px,2.2vw,32px);background:var(--card);border:1px solid var(--line-soft);display:flex;flex-direction:column;gap:14px;break-inside:avoid}
.tcard .tmark{width:32px;height:32px;color:var(--gold)}
.tcard .tmark svg{width:100%;height:100%}
.tcard blockquote{margin:0;font-size:.98rem;line-height:1.6;color:var(--ink)}
.tcard figcaption{font-size:.8rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--gold)}
/* FAQ accordion */
.faq-wrap{max-width:900px;margin-inline:auto;border-top:1px solid var(--line)}
.faq-item{border-bottom:1px solid var(--line)}
.faq-item summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;align-items:center;gap:20px;padding:22px 4px;font-family:var(--serif);font-size:clamp(1.05rem,1.5vw,1.25rem);color:var(--ink);font-weight:400}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary svg{width:20px;height:20px;color:var(--gold);flex:none;transition:transform .3s var(--ease)}
.faq-item[open] summary svg{transform:rotate(135deg)}
.faq-a{padding:0 4px 24px}
.faq-a p{color:var(--body);margin:0;max-width:80ch}
/* resources row */
.resources{display:flex;flex-wrap:wrap;gap:14px clamp(24px,4vw,52px);justify-content:center;margin-top:clamp(34px,4vw,54px);padding-top:clamp(24px,3vw,36px);border-top:1px solid var(--line)}
.resources a{display:inline-flex;align-items:center;gap:.5em;font-size:.84rem;font-weight:700;letter-spacing:.04em;color:var(--navy);text-transform:uppercase}
.resources a svg{width:15px;height:15px;color:var(--gold);flex:none}
.resources a:hover{color:var(--gold)}
/* (.video-grid / .video-embed / .video-card removed 2026-07-27 — the Videos page was deleted at
   the client's request on 2026-07-17 and nothing emits these classes. See render.py's
   build_videos() note if the page is ever reinstated.) */

/* ================= 2026 client brief: new content pages ================= */
/* align-items:stretch, not start (2026-08-16). The cards already carry `margin-top:auto` on their
   "Read more" foot, with a comment saying the point is to get a row's CTAs onto one line — but
   `start` collapsed every card to its content height, so the CTAs never lined up and the row had
   a ragged base. Stretching lets the existing rule do what it was written to do, and gives each
   row a level bottom edge to match its level top rule. */
.feat-grid{display:grid;align-items:stretch;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2.2vw,28px)}
@media(max-width:900px){.feat-grid{grid-template-columns:1fr 1fr}}
@media(max-width:620px){.feat-grid{grid-template-columns:1fr}}
/* False positive below: --radius-lg is 0 and .feat-card computes to border-radius:0px (verified
   in-browser). The 50% radius the rule sees belongs to the nested .ring icon disc, not the card. */
.feat-card{padding:clamp(22px,2vw,30px);background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold);display:flex;flex-direction:column} /* impeccable-disable-line border-accent-on-rounded */
.feat-card .ring{width:52px;aspect-ratio:1;border-radius:50%;border:1px solid var(--line);display:grid;place-items:center;color:var(--gold);margin-bottom:16px}
.feat-card .ring svg{width:24px;height:24px}
.feat-card h3,.feat-card h2{font-size:1.18rem;margin-bottom:.5em}
.feat-card>p{color:var(--body);font-size:.94rem;margin:0}
.feat-card .ticks{margin-top:14px}
.feat-card .ticks li{font-size:.9rem}
.feat-grid.on-dark .feat-card{background:rgba(var(--paper-rgb),.04);border-color:rgba(var(--paper-rgb),.14);border-top-color:var(--gold-2)}
.feat-grid.on-dark .feat-card h3{color:var(--paper)}
.feat-grid.on-dark .feat-card>p{color:rgba(var(--paper-rgb),.85)}
.feat-grid.on-dark .feat-card .ring{border-color:rgba(var(--paper-rgb),.3);color:var(--gold-2)}
.step-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(16px,2vw,24px);counter-reset:step}
@media(max-width:820px){.step-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.step-grid{grid-template-columns:1fr}}
.step-grid .feat-card{counter-increment:step}
.step-grid .feat-card::before{content:counter(step,decimal-leading-zero);font-family:var(--serif);color:var(--gold);font-size:1rem;font-weight:700;display:block;margin-bottom:8px}
.chip-row{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;max-width:920px;margin:0 auto}
.chip{padding:.6em 1.2em;border:1px solid rgba(var(--paper-rgb),.3);color:var(--paper);font-size:.82rem;transition:.3s var(--ease)}
.chip:hover{background:var(--gold);border-color:var(--gold);color:var(--paper)}
/* discovery / enquiry form */
.enquiry-wrap{max-width:780px;margin:0 auto}
/* False positive, as .feat-card above: the card is square; the 50% belongs to a nested icon. */
.enquiry-card{background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold); /* impeccable-disable-line border-accent-on-rounded */padding:clamp(24px,2.6vw,40px);box-shadow:0 50px 100px -55px rgba(var(--ink-rgb),.6)}
.hs-grid .enquiry-card{display:flex;flex-direction:column}
.hs-grid .enquiry-card form{flex:1}
.enq-bubble{display:inline-block;background:var(--gold);color:var(--paper);font-weight:700;font-size:.9rem;line-height:1.35;padding:.7em 1.3em;border-radius:26px;margin-bottom:18px}
.enquiry-card h3{font-size:clamp(1.5rem,2.4vw,2rem);font-weight:300}
.enq-sub{color:var(--body);margin:10px 0 6px}
.enq-note{background:var(--paper-2);padding:14px 16px;font-size:.85rem;color:var(--body);margin:14px 0 22px}
.enquiry-card .field select{width:100%;padding:14px 16px;border:1px solid var(--line);background:var(--card);font:inherit;color:var(--ink);border-radius:0}
.enq-consent{display:flex;gap:10px;align-items:flex-start;font-size:.85rem;color:var(--body);margin:6px 0 18px}
.enq-consent input{margin-top:3px;flex:none}
.enq-ok{display:none;margin:14px 0 0;color:var(--navy);font-weight:400}
.enq-ok a,.enq-note a,.enq-consent a{color:var(--navy);text-decoration:underline;text-decoration-color:var(--gold)}
/* Compact the enquiry cards on phones (client 2026-07-20: "form is too big, especially on
   mobile"). Applies to BOTH the hero quick form and the full discovery form.
   NB inputs keep font-size:1rem, iOS Safari auto-zooms the page when a focused input is
   under 16px, so height comes off the PADDING, never the type size. Fields still land at
   ~44px, which is the minimum comfortable touch target. */
/* A button whose label is an email address cannot wrap at a space, so "Email
   move@plymouthblockmanagement.com" overflowed its own box by 8px at 390px wide and the text was
   clipped. Allow a break inside the address rather than shortening the label. */
@media(max-width:560px){
  .btn{overflow-wrap:anywhere;text-align:center;line-height:1.35}
}
@media(max-width:640px){
  .enquiry-card{padding:20px 18px}
  .enq-bubble{font-size:.76rem;padding:.5em 1em;margin-bottom:12px;border-radius:20px}
  .enquiry-card h3,.hero-form-col .enquiry-card h3{font-size:1.18rem}
  .enq-sub,.hero-form-col .enquiry-card .enq-sub{font-size:.82rem;margin:6px 0 2px;line-height:1.45}
  .enq-note{padding:10px 12px;font-size:.78rem;margin:10px 0 14px}
  .enquiry-card .field,.hero-form-col .enquiry-card .field{margin-bottom:10px}
  /* .68rem measured 10.88px, the smallest text on any form; raised to match the label scale
     used elsewhere. Field labels are the one thing a user must be able to read while typing. */
  .enquiry-card .field label{font-size:.72rem;letter-spacing:.06em;margin-bottom:4px}
  .enquiry-card .field input,.enquiry-card .field select,.enquiry-card .field textarea,
  .hero-form-col .enquiry-card .field input,.hero-form-col .enquiry-card .field select,
  .hero-form-col .enquiry-card .field textarea{padding:10px 12px;font-size:1rem}
  .enquiry-card .field textarea,.hero-form-col .enquiry-card textarea{min-height:66px}
  .enquiry-card .btn{padding:.9em 1.4em;font-size:.78rem}
  .enq-consent{font-size:.78rem;margin:4px 0 14px}
  .hero-form .hf-note,.hero-quick .hf-note{font-size:.7rem;margin-top:10px}
}
/* emergency band + red Please-call button (client request) */

/* ── Callout accents, reworked 2026-08-16 ────────────────────────────────────
   Six components carried a thick coloured border-left (3-5px): the emergency
   band on all 125 pages, the cladding banner, the repair band, the policy
   download, the building-safety notice and a dead .cp-block. A heavy coloured
   bar down one edge of a callout is one of the most recognisable tells of a
   generated interface, and it was doing the same job six different ways.
   The colour now lives in the ICON instead of a rail: a filled disc reads as a
   deliberate status mark rather than a decorative stripe, and it makes the
   emergency band MORE urgent, not less, which matters because that one is a
   safety affordance the client asked for specifically. Definition comes from a
   1px border in the accent hue. Card top-accents are untouched: they are the
   incumbent look the client signed off, and a 3px top rule is not the pattern
   at issue here. */
.emergency-band{display:flex;align-items:center;gap:clamp(16px,2vw,26px);background:#fdeceb;border:1px solid #e3948b;padding:clamp(20px,2.2vw,30px)}
.emergency-band .ring{width:52px;aspect-ratio:1;flex:none;border-radius:50%;border:1.5px solid #c0392b;background:#c0392b;display:grid;place-items:center;color:#fff}
.emergency-band .ring svg{width:26px;height:26px}
.emergency-band h3,.emergency-band h2{color:#c0392b;font-size:1.3rem;margin:0}
.emergency-band p{margin:4px 0 0;color:var(--body);font-size:.92rem}
.btn-emerg{margin-left:auto;flex:none;display:inline-flex;align-items:center;background:#c0392b;color:#fff;font-weight:700;padding:.95em 1.7em;letter-spacing:.02em;white-space:nowrap}
.btn-emerg:hover{background:#a93226}
@media(max-width:720px){.emergency-band{flex-wrap:wrap}.btn-emerg{margin-left:0;width:100%;justify-content:center}}
/* accreditation logos + awards (client-supplied) */
.accred-logos{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:clamp(22px,4vw,56px)}
.accred-logo{height:72px;display:flex;align-items:center;justify-content:center}
.accred-logo img{max-height:72px;width:auto;object-fit:contain}
.accred-tpi{flex-direction:column;gap:2px;border:1px solid var(--line);padding:12px 24px;height:auto}
.accred-tpi strong{font-family:var(--serif);font-size:1.7rem;color:var(--gold);letter-spacing:.06em;line-height:1}
.accred-tpi span{font-size:.68rem;color:var(--muted);text-transform:uppercase;letter-spacing:.08em}
.awards-band{max-width:940px;margin:clamp(36px,4vw,58px) auto 0}
.awards-band h3{text-align:center;font-size:1.3rem;margin-bottom:22px}
/* Award badges (client artwork added 2026-07-20). Mixed aspect ratios, so each badge sits in a
   fixed-height box and is contained, never cropped or stretched.
   3 columns since the 2026 badge was added 2026-07-27 (6 badges): 5-across left a single orphan
   on the second row, and 6-across inside the 940px band shrank each badge to ~156px. 3x2 keeps
   both rows full and the artwork legible. Revisit the column count if a 7th award lands. */
.awards-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(16px,2vw,28px);
  margin-top:clamp(10px,1.5vw,18px)}
@media(max-width:620px){.awards-grid{grid-template-columns:repeat(2,1fr)}}
.award-card{margin:0;text-align:center;display:flex;flex-direction:column;align-items:center;gap:12px}
/* Flex items don't shrink below their content by default, so max-height alone let the two
   PORTRAIT badges (2022, 2023) overflow the box and collide with their captions. Sizing the
   image to the box and containing it normalises every badge to a common height. */
/* Every badge in an identical frame (2026-08-17). The client's artwork runs from landscape 1.7
   to portrait 0.55, so contained inside a bare box the wide ones filled their column and the tall
   ones floated as small stamps in the middle of theirs: three banners above three postage stamps,
   which read as a broken grid rather than a set. A shared white tile normalises the frame so the
   differing artwork is obviously the artwork, not a layout fault. */
.award-badge{width:100%;height:clamp(124px,12vw,164px);overflow:hidden;flex:none;
  background:var(--card);border:1px solid var(--line-soft);
  padding:clamp(10px,1.2vw,16px)}
/* A PLAIN BLOCK parent, deliberately not grid. As a centred grid item the image is sized by its
   own content, so neither height:100% nor max-height:100% has a basis to resolve against and the
   portrait badges rendered 261x477 inside a 164px tile, clipped by overflow:hidden. Against a
   block parent of fixed height, height:100% resolves and object-fit letterboxes properly, which
   is what the original did before the frame was added. */
.award-badge img{width:100%;height:100%;object-fit:contain;display:block}
.award-card figcaption{font-size:.78rem;line-height:1.45;color:var(--body);max-width:22ch}
.awards-list{list-style:none;padding:0;margin:0;display:grid;grid-template-columns:1fr 1fr;gap:2px 34px}
@media(max-width:680px){.awards-list{grid-template-columns:1fr}}
.awards-list li{position:relative;padding:12px 0 12px 32px;border-bottom:1px solid var(--line-soft);color:var(--ink);font-size:.92rem}
.awards-list li::before{content:"";position:absolute;left:2px;top:15px;width:13px;height:13px;border:2px solid var(--gold);border-radius:50%;background:radial-gradient(circle,var(--gold) 40%,transparent 42%)}

/* Sustainability page: copy-only sections (until client images land) + image rows */
.sustain-copy{max-width:820px}
.sustain-copy h2{font-size:clamp(1.6rem,2.8vw,2.3rem);font-weight:300;margin:0 0 .6em}
.sustain-copy p{color:var(--body);margin:0 0 1.1em;max-width:70ch;line-height:1.72}
.sustain-copy p:last-child{margin-bottom:0}
.sustain-row .svc-row-copy h2{font-size:clamp(1.6rem,2.8vw,2.3rem);font-weight:300;margin:0 0 .5em;color:var(--ink)}
.sustain-row .svc-row-copy p{color:var(--body);margin:0 0 1em;line-height:1.72}
.band-paper2 .sustain-copy h2,.band-paper2 .sustain-row .svc-row-copy h2{color:var(--ink)}

/* FAQ page: search, quick-link chips, category sections */
.faq-search{margin-top:clamp(20px,2.4vw,30px);max-width:560px}
.faq-search input{width:100%;padding:15px 18px;border:1px solid var(--line);border-radius:0;
  background:var(--card);font:inherit;color:var(--ink);transition:.25s}
.faq-search input:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 4px rgba(var(--gold-rgb),.12)}
/* chips on a LIGHT page need dark ink + gold border (base .chip is white-on-dark) */
.faq-chips{margin-top:22px;gap:8px 10px;justify-content:flex-start}
.faq-chips .chip{font-size:.82rem;color:var(--ink);border-color:var(--line);text-transform:none;letter-spacing:0}
.faq-chips .chip:hover{background:var(--gold);border-color:var(--gold);color:var(--paper)}
/* The category heading spans the full 1096px column while the question list under it is capped
   at 900px and sits flush left, so the rule under each heading overhung its own list by 196px.
   The heading takes the list's measure. */
.faq-cat{margin-top:clamp(34px,4vw,56px);scroll-margin-top:120px;max-width:900px}
.faq-cat > h2{font-size:clamp(1.4rem,2.4vw,1.9rem);font-weight:300;margin:0 0 14px;
  padding-bottom:12px;border-bottom:2px solid var(--gold)}
.faq-cat[hidden]{display:none}
.faq-empty{color:var(--body);padding:20px 0}
.faq-empty a{color:var(--gold);text-decoration:underline}

/* Property Experience page */
.prop-lead{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(28px,4vw,60px);align-items:center}
@media(max-width:900px){.prop-lead{grid-template-columns:1fr;gap:24px}}
.prop-lead-copy h2{font-size:clamp(1.8rem,3vw,2.6rem);font-weight:300;margin:0}
.prop-meta{color:var(--gold);font-size:.92rem;letter-spacing:.02em;margin:.5em 0 1em;font-weight:700}
.prop-lead-copy p:not(.prop-meta),.svc-row-copy p:not(.prop-meta){color:var(--body);line-height:1.72}

/* Homepage hero: single column (form removed 2026-07-23) + clickable "bubble" CTA over the image */
.hero-grid-solo{grid-template-columns:1fr!important}
/* Hero CTA — a matched pair of pills (client 2026-07-24: the old sharp white button
   below the green bubble looked mismatched). Both are now rounded pills, same size. */
.hero-cta{display:flex;flex-direction:column;align-items:flex-start;gap:14px;margin-top:clamp(20px,2.6vw,30px)}
.hero-bubble{display:inline-flex;align-items:center;gap:.7em;
  background:var(--gold);color:var(--paper);font-weight:700;font-size:clamp(.95rem,1.3vw,1.08rem);
  line-height:1.3;padding:.9em 1.6em;border-radius:40px;max-width:36ch;
  box-shadow:0 18px 40px -18px rgba(0,0,0,.55);transition:.3s var(--ease)}
.hero-bubble:hover{background:var(--gold-2);color:var(--ink);transform:translateY(-2px)}
.hero-bubble svg{width:20px;height:20px;flex:none}
/* secondary: same pill shape, outlined instead of filled, so the two read as a set */
.hero-bubble-alt{background:transparent;color:var(--paper);font-weight:600;
  border:1.5px solid rgba(var(--paper-rgb),.5);box-shadow:none}
.hero-bubble-alt:hover{background:var(--paper);color:var(--ink);border-color:var(--paper);transform:translateY(-2px)}
@media(max-width:560px){.hero-bubble{max-width:none;width:100%;justify-content:space-between}}

/* Rotating hero background (client 2026-07-24) — crossfade between images */
.hero-rotator img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 38%;
  opacity:0;transition:opacity 1.4s var(--ease)}
.hero-rotator img.on{opacity:1}
@media(prefers-reduced-motion:reduce){.hero-rotator img{transition:none}.hero-rotator img:not(.on){display:none}}

/* Capability pages (/what-we-do/ sub-pages, added 2026-07-27). Long-form prose sections: a
   measured column so body copy stays readable, with the same heading rhythm as .sustain-copy. */
/* Centred measured column: at 1240px the wrap is far wider than a readable line length, so a
   left-aligned 860px block left ~380px of dead space down the right of every section. */
.cap-block{max-width:820px;margin-inline:auto}
.cap-block h2{font-size:clamp(1.55rem,2.7vw,2.25rem);font-weight:300;margin:0 0 .65em;color:var(--ink)}
.cap-block p{color:var(--body);margin:0 0 1.15em;line-height:1.75;font-size:1.02rem}
.cap-block p:last-child{margin-bottom:0}
.cap-block .ticks li{font-size:.98rem}
/* Clickable cards. These ARE links, but as flat panels they did not read as clickable (client
   2026-07-27: "I want them to be clickable"). The affordance is now explicit: pointer cursor, a
   lift with shadow, the top rule and heading pick up the accent green, and the "Read more"
   underline sweeps in from anywhere on the card rather than only when the label itself is hovered. */
a.feat-card{transition:.4s var(--ease);display:flex;flex-direction:column;cursor:pointer}
a.feat-card:hover,a.feat-card:focus-visible{transform:translateY(-4px);border-color:var(--line);
  border-top-color:var(--gold-2);box-shadow:0 40px 70px -40px rgba(var(--ink-rgb),.45)}
a.feat-card:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
a.feat-card:hover h3{color:var(--gold)}
a.feat-card h3,a.feat-card .ring{transition:color .3s var(--ease)}
/* push the CTA to the bottom so a row of cards has its "Read more" on one line */
a.feat-card .card-foot{display:inline-flex;margin-top:auto;padding-top:16px;color:var(--gold)}
a.feat-card:hover .card-foot::after{transform:scaleX(1);transform-origin:left}
a.feat-card:hover .card-foot svg{transform:translateX(4px)}
a.feat-card>p:last-of-type{margin-bottom:0}

/* The reviews band (.reviews-band / .reviews-embed) was REMOVED on 2026-07-30 with the widget it
   styled — client request. Nothing emits those classes any more. */

/* ---------- Cladding funding (2026-07-31) ----------
   Homepage banner + the full section on the Building Safety page.
   IT IS GREEN, NOT RED, ON PURPOSE. The first version used the emergency red of the 24-hour
   emergency band with a warning triangle, and the client's reaction was that it "reads as its bad
   not a opertunity". This is funding becoming available to their buildings — good news with a
   deadline — so it carries the brand accent green. Keep it out of the emergency palette: red on
   this site means "call us, something is wrong". */
/* Three-part status band: flag, message, action. Grid rather than flex (2026-08-16) because
   flex:1 on the copy and flex:none either side let the flag and the CTA drift in whatever space
   was left, so the three parts read as fragments floating in a box instead of one composed band.
   Explicit tracks give the flag a fixed column, the message the room it needs, and the action a
   column of its own. Below 780px it stacks. */
.clad-alert{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;
  gap:clamp(18px,2.6vw,34px);
  background:rgba(var(--gold-rgb),.10);border:1px solid rgba(var(--gold-rgb),.42);
  padding:clamp(20px,2.4vw,28px) clamp(20px,2.6vw,32px);transition:.35s var(--ease)}
@media(max-width:780px){
  .clad-alert{grid-template-columns:1fr;gap:14px;text-align:left}
}
.clad-alert:hover{background:rgba(var(--gold-rgb),.16);transform:translateY(-2px)}
.clad-flag{display:inline-flex;align-items:center;gap:.5em;color:var(--gold);
  font-size:.74rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase}
.clad-flag svg{width:20px;height:20px;flex:none}
.clad-alert-copy{color:var(--body);font-size:.96rem;line-height:1.6;max-width:68ch}
.clad-alert-copy b{color:var(--ink)}
.clad-alert-cta{display:inline-flex;align-items:center;gap:.5em;color:var(--gold);
  font-weight:700;font-size:.82rem;letter-spacing:.06em;text-transform:uppercase}
.clad-alert-cta svg{width:15px;height:15px;flex:none;transition:transform .35s var(--ease)}
.clad-alert:hover .clad-alert-cta svg{transform:translateX(4px)}
/* Fact strip: four short key/value cells on the navy band. */
.clad-facts{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:rgba(var(--paper-rgb),.16);
  border:1px solid rgba(var(--paper-rgb),.16);max-width:860px;margin:0 auto clamp(30px,4vw,48px)}
@media(max-width:640px){.clad-facts{grid-template-columns:1fr 1fr}}
.clad-fact{background:var(--navy);padding:clamp(16px,2vw,22px);text-align:center}
.cf-k{display:block;font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--gold-2);font-weight:700}
.cf-v{display:block;margin-top:7px;color:var(--paper);font-size:clamp(.95rem,1.4vw,1.12rem);font-weight:700}
.clad-cols{display:grid;grid-template-columns:1fr 1fr;gap:clamp(26px,4vw,56px);max-width:1000px;
  margin-inline:auto}
@media(max-width:820px){.clad-cols{grid-template-columns:1fr;gap:26px}}
.clad-col h3{color:var(--paper);font-size:clamp(1.15rem,1.8vw,1.4rem);margin:0 0 .6em}
.clad-col p{color:rgba(var(--paper-rgb),.88);line-height:1.7;margin:0 0 1em;font-size:.98rem}
.clad-col p b{color:var(--paper)}
.clad-caveat{max-width:860px;margin:clamp(28px,3.4vw,44px) auto 0;text-align:center;
  color:rgba(var(--paper-rgb),.66);font-size:.85rem;line-height:1.6}
.clad-caveat a{color:var(--gold-2);text-decoration:underline;text-underline-offset:3px}

/* ---------- named people (2026-07-28) ----------
   Jagoda on /sustainability/. Portrait sits in a fixed 4/5 frame so a phone photo does not run
   away with the row height, with the credentials read as a caption rather than body copy. */
.person-card{margin:0;background:var(--card);border:1px solid var(--line-soft);
  border-top:3px solid var(--gold);max-width:420px}
.person-photo{aspect-ratio:4/5;overflow:hidden}
.person-photo img{width:100%;height:100%;object-fit:cover;object-position:center 22%;display:block}
.person-card figcaption{padding:clamp(18px,2vw,26px)}
.person-name{display:block;font-family:var(--serif);font-size:1.25rem;font-weight:400;color:var(--ink)}
.person-role{display:block;margin-top:3px;font-size:.8rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--gold);font-weight:700}
.person-quals{list-style:none;padding:0;margin:14px 0 0}
.person-quals li{position:relative;padding:0 0 .45em 1.5em;color:var(--body);font-size:.9rem;line-height:1.5}
.person-quals li::before{content:"";position:absolute;left:0;top:.5em;width:8px;height:8px;
  border:2px solid var(--gold);border-radius:50%}
/* Two credential cards side by side (building safety team). Constrained so a pair of portraits
   does not sprawl across a 1240px wrap. */
.person-pair{max-width:900px;margin-inline:auto;align-items:start}
.person-pair .person-card{max-width:none}
@media(max-width:620px){.person-pair{gap:22px}}

/* Fire door inspection photos */
.fd-shot{overflow:hidden;aspect-ratio:4/3;border:1px solid var(--line-soft)}
.fd-shot img{width:100%;height:100%;object-fit:cover;object-position:center 30%;display:block}

/* Homepage "Report a repair" band */
.repair-band{display:flex;align-items:center;gap:clamp(16px,2.4vw,30px);
  background:var(--paper-2);border:1px solid var(--line);padding:clamp(22px,2.6vw,34px)}
.repair-band .ring{width:56px;aspect-ratio:1;flex:none;border-radius:50%;border:1px solid var(--gold);
  display:grid;place-items:center;color:var(--paper);background:var(--gold)}
.repair-band .ring svg{width:26px;height:26px}
.repair-copy{flex:1;min-width:0}
.repair-copy h2{font-size:clamp(1.35rem,2.2vw,1.9rem);font-weight:300;margin:0 0 .35em}
.repair-copy p{margin:0;color:var(--body);font-size:.96rem;line-height:1.6}
.repair-copy a{color:#c0392b;font-weight:700}
.repair-band .btn{flex:none}
@media(max-width:820px){.repair-band{flex-wrap:wrap}.repair-band .btn{width:100%;justify-content:center}}

/* ---------- footer enquiry modal (2026-07-28) ----------
   The sitewide "Get in touch" CTA opens this rather than a mailto. z-index sits above the mobile
   nav (200) and the translate notice (150) so it is never buried. */
.enq-modal{position:fixed;inset:0;z-index:300;display:flex;align-items:center;justify-content:center;
  padding:clamp(14px,4vw,40px)}
.enq-modal[hidden]{display:none}
.enq-modal-backdrop{position:absolute;inset:0;background:rgba(var(--ink-rgb),.66)}
.enq-modal-panel{position:relative;background:var(--card);border-top:3px solid var(--gold);
  width:min(640px,100%);max-height:90vh;overflow-y:auto;padding:clamp(26px,3vw,42px);
  box-shadow:0 60px 120px -40px rgba(0,0,0,.6)}
.enq-modal-close{position:absolute;top:10px;right:10px;width:44px;height:44px;display:grid;
  place-items:center;background:transparent;border:0;color:var(--muted);cursor:pointer;
  transition:color .25s,transform .25s var(--ease)}
.enq-modal-close:hover{color:var(--gold);transform:rotate(90deg)}
.enq-modal-close:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.enq-modal-close svg{width:22px;height:22px}
.enq-modal .enquiry-card h3{font-size:clamp(1.35rem,2.2vw,1.8rem);font-weight:300;padding-right:40px}
@media(max-width:620px){.enq-modal-panel{padding:24px 18px}}

/* ---------- language switcher (2026-07-27) ----------------------------------
   A native <select> deliberately: it is keyboard accessible, screen-reader friendly and gets the
   platform's own picker on mobile, which no custom dropdown matches. The globe and caret are
   decoration layered around it; the select itself is transparent and sits on top so the whole
   control is the hit area. */
/* 40px minimum so the chip is a usable target; 44px on touch widths. It never drives the header
   height, which is set by the logo at clamp(56px,5vw,72px). */
.lang-switch{position:relative;display:inline-flex;align-items:center;gap:.4em;flex:none;
  border:1px solid var(--line);padding:0 .5em 0 .6em;height:40px;transition:.3s var(--ease)}
@media(max-width:700px){.lang-switch{height:44px}}
.lang-switch:hover{border-color:var(--gold)}
.lang-switch:focus-within{outline:2px solid var(--gold);outline-offset:2px}
.lang-switch .lang-ico{display:inline-flex;color:var(--gold)}
.lang-switch .lang-ico svg{width:17px;height:17px}
.lang-switch .lang-caret{color:var(--muted);pointer-events:none;display:inline-flex}
.lang-switch .lang-caret svg{width:16px;height:16px}
.lang-switch select{appearance:none;-webkit-appearance:none;background:transparent;border:0;
  font:inherit;font-size:.78rem;color:var(--navy);padding:0 .2em;cursor:pointer;
  max-width:11ch;text-overflow:ellipsis}
.lang-switch select:focus{outline:none}
.lang-switch.is-translated{border-color:var(--gold);background:rgba(var(--gold-rgb),.07)}
/* HEADER VERSION. Deliberately NOT a bordered box: with a 1px frame it read as a form input
   dropped into the header and, next to the green-outlined hamburger, gave the bar three competing
   boxed controls (client 2026-07-27: "the button glitches out the top panel"). It now matches
   .header-phone exactly, green icon plus navy label, no chrome, so the header keeps one bordered
   control (the hamburger) and one filled button (the CTA). Padding preserves a 44px hit area.
   Globe + two-letter code only: the full language name needed ~110px the header does not have. */
.lang-compact{border:0;background:none;padding:0 6px;gap:.45em;min-height:44px;height:auto}
.lang-compact:hover{border-color:transparent}
.lang-compact .lang-ico{color:var(--gold)}
.lang-compact .lang-ico svg{width:19px;height:19px}
.lang-compact .lang-code{font-size:.95rem;font-weight:700;letter-spacing:.03em;color:var(--navy);
  transition:color .25s var(--ease)}
.lang-compact:hover .lang-code,.lang-compact:hover .lang-ico{color:var(--gold)}
.lang-compact.is-translated{background:none}
.lang-compact.is-translated .lang-code,.lang-compact.is-translated .lang-ico{color:var(--gold)}
.lang-compact:focus-within{outline:2px solid var(--gold);outline-offset:3px}
.lang-compact select{position:absolute;inset:0;width:100%;height:100%;max-width:none;opacity:0;
  padding:0;cursor:pointer}
/* Mobile overlay + in-card versions get room to breathe */
.mnav-lang{margin-top:26px;display:flex;justify-content:center}
.mnav-lang .lang-switch{height:46px;border-color:rgba(var(--paper-rgb),.35)}
.mnav-lang .lang-switch select{color:var(--paper);font-size:.95rem;max-width:none}
.mnav-lang .lang-switch select option{color:var(--ink)}
.mnav-lang .lang-ico{color:var(--gold-2)}
.card-lang{margin-top:18px;padding-top:16px;border-top:1px solid var(--line-soft)}
.card-lang-label{display:block;font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;
  color:var(--muted);margin-bottom:9px}
.card-lang .lang-switch{height:42px}
.card-lang .lang-switch select{max-width:none;font-size:.9rem}

/* Machine-translation notice. Fixed to the foot of the viewport so it stays visible while the
   visitor reads a translated page, which is the point of it. */
.translate-note{position:fixed;left:0;right:0;bottom:0;z-index:150;background:var(--ink);
  color:rgba(var(--paper-rgb),.9);display:flex;align-items:center;justify-content:center;
  gap:16px;flex-wrap:wrap;padding:12px clamp(16px,4vw,40px);font-size:.84rem;line-height:1.45;
  box-shadow:0 -14px 34px -22px rgba(0,0,0,.8)}
.translate-note button{background:var(--gold);color:var(--paper);border:0;padding:.6em 1.2em;
  font-size:.78rem;letter-spacing:.06em;text-transform:uppercase;font-weight:700;flex:none}
.translate-note button:hover{background:var(--gold-2);color:var(--ink)}
@media(max-width:620px){.translate-note{font-size:.78rem;gap:10px;padding:10px 14px}}
/* Suppress Google's own injected top bar and the body offset it applies; we show our own notice. */
.skiptranslate,.goog-te-banner-frame,#goog-gt-tt,.goog-te-balloon-frame{display:none!important}
html.has-gtranslate body{top:0!important;position:static!important}
#pbm-translate-host{display:none}
font[style]{background:none!important;box-shadow:none!important}

/* Building Safety Consultancy page */
/* Two-column tick list. The on-dark colours are scoped to .band: the class was written for the
   Building Safety navy band, and reusing it on a LIGHT band (the contractor trades list) rendered
   white-on-#f2f4f2, i.e. invisible. Caught 2026-07-27. Keep the colour rules inside .band. */
.bsc-cols{max-width:1000px;margin-left:auto;margin-right:auto;columns:2;column-gap:clamp(24px,4vw,64px)}
.bsc-cols li{break-inside:avoid}
.band .bsc-cols li{color:rgba(var(--paper-rgb),.9)}
.band .bsc-cols li::before{border-color:var(--gold-2)}
@media(max-width:640px){.bsc-cols{columns:1}}
.bsc-notice{max-width:900px;border:1px solid var(--line);
  background:var(--card);padding:clamp(22px,2.4vw,32px)}
.bsc-notice h3{font-size:1.1rem;margin:0 0 .5em}
.bsc-notice p{color:var(--body);margin:0;font-size:.92rem;line-height:1.7}

/* ---------- Meet the team (2026-07-30) ----------
   Reuses .person-card from the building-safety pair, adding an introduction paragraph above the
   credentials. auto-fit rather than a fixed column count so the grid stays correct as Spencer
   adds people: two cards centre themselves instead of leaving a hole in a three-column row. */
.team-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:clamp(20px,2.4vw,30px);max-width:1000px;margin-inline:auto;justify-items:center}
.team-grid .person-card{width:100%;max-width:340px}
.person-blurb{color:var(--body);font-size:.92rem;line-height:1.6;margin:12px 0 0}
.person-card .person-quals{margin-top:12px}

/* ---------- approved contractor logos (2026-07-30) ----------
   Each contractor's logo links to their own site. Two grounds are supported because contractors
   publish whatever they publish: .ctr-tile is light by default, and .is-dark gives the logo panel
   a dark ground for firms whose only available artwork is an on-black lockup with a white
   wordmark (West Country Gas Services). object-fit:contain everywhere, so no third-party mark is
   ever stretched or cropped. */
.ctr-row{display:flex;flex-wrap:wrap;justify-content:center;gap:clamp(16px,2vw,26px)}
.ctr-tile{display:flex;flex-direction:column;width:250px;background:var(--card);
  border:1px solid var(--line-soft);border-top:3px solid var(--gold);transition:.4s var(--ease)}
.ctr-tile:hover{transform:translateY(-4px);border-color:var(--line);
  box-shadow:0 40px 70px -44px rgba(var(--ink-rgb),.45)}
.ctr-tile:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
/* Size the IMAGE to the panel and contain it, exactly as .award-badge does. max-height:100% alone
   does NOT constrain here — measured 2026-07-30, the logos overflowed their 104px panel by 30px
   (AWL) and 67px (West Country Gas) and printed over the company name beneath. Same failure the
   award badges hit; same fix. The panel is deep enough for a STACKED lockup (mark above wordmark,
   ~1.3 aspect): at 104px a stacked logo contained to a short wide box shrank to ~96px wide and the
   wordmark was unreadable. */
.ctr-logo{height:132px;padding:14px 18px;background:var(--card);overflow:hidden}
.ctr-tile.is-dark .ctr-logo{background:#000}
.ctr-logo img{width:100%;height:100%;object-fit:contain;display:block}
/* Wordmark panel for firms whose logo artwork we do not have yet. Same footprint as a logo panel
   so the row stays even; swaps to the real logo when a file is added to the entry. */
.ctr-logo-text{display:grid;place-items:center;text-align:center;background:var(--paper-2)}
.ctr-logo-text.is-dark{background:var(--navy)}
.ctr-logo-text>span{font-weight:700;font-size:1.02rem;line-height:1.3;letter-spacing:.01em;
  color:var(--navy);padding:0 6px}
.ctr-logo-text.is-dark>span{color:var(--paper)}
/* Tiles with no verified website are not links, so they must not offer a pointer or a lift. */
.ctr-tile.is-plain{cursor:default}
.ctr-tile.is-plain:hover{transform:none;box-shadow:none;border-color:var(--line-soft)}
.ctr-tile.is-plain:hover .ctr-name{color:var(--ink)}
.ctr-name{display:block;padding:14px 18px 0;font-weight:700;font-size:.95rem;color:var(--ink)}
.ctr-trade{display:block;padding:3px 18px 16px;font-size:.8rem;color:var(--muted);line-height:1.4}
.ctr-tile:hover .ctr-name{color:var(--gold)}
/* Scrolling variant. Only used once there are enough logos to fill the track, see
   CONTRACTOR_MARQUEE_MIN in render.py; below that render.py emits .ctr-row instead. The track is
   two identical halves and translates -50%, matching the locations marquee. */
.ctr-marquee{overflow:hidden;position:relative;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.ctr-track{display:flex;width:max-content;animation:scroll 46s linear infinite}
.ctr-set{display:flex;gap:clamp(16px,2vw,26px);padding-right:clamp(16px,2vw,26px)}
.ctr-marquee:hover .ctr-track{animation-play-state:paused}
@media(prefers-reduced-motion:reduce){.ctr-track{animation:none;flex-wrap:wrap;justify-content:center}}
@media(max-width:560px){.ctr-tile{width:100%;max-width:300px}}

/* =========================================================================
   PRE-LAUNCH FIXES, 2026-08-16
   ========================================================================= */

/* Bypass block (WCAG 2.4.1). Off-canvas until focused, then pinned top-left above the
   fixed header (z-index 100) and the mobile overlay is not open at that point. */
.skip-link{position:absolute;left:-9999px;top:0;z-index:400;background:var(--navy);color:var(--paper);
  padding:14px 22px;font-size:.85rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase}
.skip-link:focus{left:0}
.skip-link:focus-visible{outline:2px solid var(--gold);outline-offset:-4px}

/* Anchor targets sat UNDER the 79px fixed header: every #enquire / #cladding / #register jump
   hid the top of the section it landed on. Worst case was the header CTA and the hero button,
   both of which point at #enquire, where the green CTA bubble was sliced in half.
   .faq-cat already had its own scroll-margin and keeps it. */
[id]{scroll-margin-top:110px}
@media(max-width:1200px){[id]{scroll-margin-top:96px}}

/* Honeypot. Off-canvas rather than display:none — some bots skip hidden fields, which would
   defeat the trap. aria-hidden + tabindex="-1" keep it away from real users entirely. */
.hp{position:absolute!important;left:-9999px!important;width:1px;height:1px;overflow:hidden}

/* Form result messages. .enq-ok was already display:none and revealed by the old inline
   onsubmit; both are now driven by main.js, which sets [data-state] on the form. */
.enq-err{display:none;margin:14px 0 0;color:#c0392b;font-weight:600;line-height:1.5}
.enq-err a{color:#c0392b;text-decoration:underline;text-underline-offset:2px}
form[data-state="sent"] .enq-ok{display:block}
form[data-state="error"] .enq-err{display:block}
form[data-state="sending"] button[type=submit]{opacity:.6;pointer-events:none}

/* Sub-12px text. Both of these repeat on all 125 pages: the header's "24hr emergency" label and
   the footer's "Block & estate management" sub-heading measured 10.88px and 11.52px. */
.header-phone .ph-label,.header-phone .ph-sub{font-size:.75rem}
.footer-subhead{font-size:.75rem}

/* PARTIAL FINAL ROWS IN THE CARD GRIDS.
   Counts that do not divide by 3 left the last row hanging against the left edge with a hole
   beside it: 8 cards on all nine capability pages, 5 on About's Our Values and the homepage
   benefits, 5 on the specialist services and the fire-door steps. The awards grid had exactly
   this problem and was solved by hand ("5-across left a single orphan on the second row"); this
   generalises that fix instead of repeating it per grid.

   Mechanism: lay the same three columns out as SIX and span each card across two. Geometry is
   identical for full rows — 2 cols + 1 internal gap equals one third of the track either way —
   but a partial row can now start on a half-column, so one orphan centres at column 3 and a pair
   centres starting at column 2.
     :last-child:nth-child(3n+1)       the last card is also the 1st of a row  -> exactly 1 orphan
     :nth-last-child(2):nth-child(3n+1) the 2nd-from-last starts a row         -> exactly 2 orphans
   Scoped above 900px, where these grids are actually three columns; below that they collapse to
   two and then one, and the selectors would be meaningless. */
@media(min-width:901px){
  .feat-grid,.benefits-grid,.dsvc-grid,.step-grid{grid-template-columns:repeat(6,1fr)}
  .feat-grid>*,.benefits-grid>*,.dsvc-grid>*,.step-grid>*{grid-column:span 2}
  /* NB the full `start / span` pair, not grid-column-start alone: the base rule above sets
     `grid-column: span 2`, which resolves to start:span 2 / end:auto. Overriding only the START
     leaves the end at auto, so the card collapses to a single column and sits half-width. */
  .feat-grid>:last-child:nth-child(3n+1),
  .benefits-grid>:last-child:nth-child(3n+1),
  .dsvc-grid>:last-child:nth-child(3n+1),
  .step-grid>:last-child:nth-child(3n+1){grid-column:3 / span 2}
  .feat-grid>:nth-last-child(2):nth-child(3n+1),
  .benefits-grid>:nth-last-child(2):nth-child(3n+1),
  .dsvc-grid>:nth-last-child(2):nth-child(3n+1),
  .step-grid>:nth-last-child(2):nth-child(3n+1){grid-column:2 / span 2}
}

/* TRANSLATED HEADER OVERFLOW.
   The header media queries were tuned against ENGLISH string widths. Translated nav labels run
   far longer ("Bewohnerunterstützung" for "Resident Support"), and the bar overflowed at every
   desktop width tested — the CTA was clipped by 29px at 1440 in Polish and 104px at 1300 in
   German. body{overflow-x:hidden} meant it just looked broken rather than scrolling.
   html.has-gtranslate is set by main.js when the translate widget initialises, so it is a free
   hook. Below 1600px the CTA gives up its space: the nav's own "Contact Us" item and the phone
   number both survive, so no route to contact is lost. */
@media(max-width:1600px){
  html.has-gtranslate .nav-cta .btn{display:none}
  html.has-gtranslate .site-header .nav{gap:10px}
  html.has-gtranslate .site-header .nav > a,
  html.has-gtranslate .site-header .has-menu > a{letter-spacing:0}
}

/* ---------- Review Pals experience widget (2026-08-17) ----------------------
   Framed in the site's own card language (white ground, hairline, green top rule) so a
   third-party embed reads as part of the page rather than a pasted-in box. The widget's own
   artwork already carries the PBM green oval and a serif heading, so it sits comfortably.
   Heights are per breakpoint: the iframe is cross-origin and cannot report its content height,
   and the supplied flat 600px left a dead band on phones (measured content ends at ~407px at
   390 wide, ~567px at 820). */
/* Review Pals embed. Two things had to be solved and they pull against each other.
   (1) It scrolled. The widget is cross-origin, so the only cure is to give the iframe exactly the
       height its content needs at the width we hand it. The first version guessed 600px and 470px
       against real content of 621px and 755px.
   (2) It was too big, and almost all of that was the widget's own internal padding, which we
       cannot reach from outside. Scaling shrinks the padding along with everything else.
   The catch: BELOW roughly 760px of iframe width the widget switches layout and its three faces
   collapse from 130px to about 20px, which looks broken. So on desktop the iframe is laid out at a
   fixed 860px, where it is verified to render correctly, and the whole thing is scaled to .68 to
   fit a 585px box. The wrapper carries the scaled size, since a transform does not affect layout.
   Below 700px there is no room to scale without pushing the type under a readable size, so the
   widget keeps its own narrow layout at 1:1 and only the heights are corrected. Measured:

       viewport   445-700   410-440   <=408
       content       629       667      756

   ⚠ 860x621 and the bands below are measured, not estimated. If the widget's copy, logo or
   breakpoints change, re-measure it; do not nudge these by eye. */
.review-embed{max-width:620px;margin-inline:auto;background:var(--card);
  border:1px solid var(--line-soft);border-top:3px solid var(--gold);
  padding:clamp(6px,1vw,12px)}
.review-frame{--rs:.68;width:calc(860px * var(--rs));height:calc(621px * var(--rs));
  overflow:hidden;margin-inline:auto}
.review-embed iframe{display:block;width:860px;height:621px;border:0;
  transform:scale(var(--rs));transform-origin:top left}
@media(max-width:700px){
  .review-frame{width:100%;height:634px}
  .review-embed iframe{width:100%;height:634px;transform:none}}
@media(max-width:440px){.review-frame,.review-embed iframe{height:672px}}
@media(max-width:408px){.review-frame,.review-embed iframe{height:762px}}

/* ---------- The Beagle, Plymouth waterfront news (2026-07-30) ----------
   The client's own ship mark beside their own copy and their own button label. The mark is a
   line drawing on white, so it sits in a plain panel rather than a card with a border. */
.beagle-band{display:grid;grid-template-columns:minmax(0,260px) 1fr;gap:clamp(24px,4vw,56px);
  align-items:center;max-width:940px;margin-inline:auto}
.beagle-mark{display:grid;place-items:center;padding:clamp(14px,2vw,22px);background:var(--card);
  border:1px solid var(--line-soft)}
.beagle-mark img{width:100%;height:auto;display:block}
.beagle-copy h2{font-size:clamp(1.6rem,2.8vw,2.3rem);font-weight:300;margin:12px 0 0}
.beagle-copy p{color:var(--body);margin:14px 0 22px;max-width:56ch;line-height:1.7}
@media(max-width:720px){
  .beagle-band{grid-template-columns:1fr;gap:22px;text-align:center}
  .beagle-mark{max-width:220px;margin-inline:auto}
  .beagle-copy p{margin-inline:auto}
  .beagle-copy .eyebrow{justify-content:center}
}


/* ============================================================================
   Design pass, 2026-08-17. Every rule below answers something seen in a
   rendered screenshot, not a detector reading.
   ============================================================================ */

/* Card affordance. The news and location grids each printed the same sentence on every card
   ("Read article", "Block management here") 67 and 17 times over. The card is a link already, so
   the repeated line is replaced by one drawn mark, pinned to the bottom of the body so that cards
   whose titles run to two lines and cards whose titles run to three still agree on a baseline. */
.card-go{margin-top:auto;padding-top:14px;display:inline-flex;color:var(--gold);
  transition:transform .3s cubic-bezier(.2,.8,.2,1)}
.card-go svg{width:20px;height:20px}
.card:hover .card-go{transform:translateX(6px)}
.card:hover h3{text-decoration:underline;text-decoration-color:var(--gold);text-underline-offset:4px}
/* A place card has a name and nothing else, so its body should not reserve paragraph height. */
.card-place .card-body{flex-direction:row;align-items:center;justify-content:space-between;gap:16px}
.card-place .card-go{margin-top:0;padding-top:0}

/* Footer. Services carried 16 links against 4-7 elsewhere, so the column ran 810px deep while the
   right two-thirds of the footer stopped at 475px and left a void the width of three columns. */
.footer-grid{grid-template-columns:1.4fr 2fr 1fr 1.1fr}
.footer-col-wide .footer-links-2{columns:2;column-gap:36px}
.footer-col-wide .footer-links-2>a{break-inside:avoid}
.footer-col-wide .footer-subhead{column-span:all}
@media(max-width:900px){.footer-grid{grid-template-columns:1fr 1fr}
  .footer-col-wide .footer-links-2{columns:1}}
@media(max-width:560px){.footer-grid{grid-template-columns:1fr}}
/* The sub-heading sat at 50% opacity on navy, well under the h5 beside it, so it read as a
   disabled item rather than a group label. Matched to the column headings it sits among. */
.footer-subhead{color:var(--gold-2);opacity:1}
/* The emergency band moved above the link columns; it no longer needs to clear the copyright. */
.footer-emergency{padding-top:clamp(34px,4vw,52px)}
/* A page that closes with its own dark CTA drops the footer's, so the footer opens on the
   emergency band and needs the padding the CTA block used to provide. */
.site-footer-nocta .footer-emergency{padding-top:clamp(50px,6vw,80px)}

/* Noun-Project line icons scraped into the town pages as ordinary content images. At prose width
   they rendered ~120px, centred, above a left-aligned heading they were meant to mark. */
.prose img.prose-ico{width:46px;height:46px;margin:2.2em 0 .2em;object-fit:contain;opacity:.85}

/* Cards whose bodies differ in length by 200px: the trailing link floated at whatever height the
   text happened to end, so a three-card row showed three links at three different heights. */
.feat-card>p,a.feat-card>p{flex:1}

/* Hub heroes. /locations/ and /news/ set their h1 to 14-16ch, which broke a six-word heading over
   five lines in the left third of the viewport and left the other two thirds blank. */
.page-hero h1.display{max-width:22ch}
@media(max-width:700px){.page-hero h1.display{max-width:100%}}

/* Per-town facts table on the location pages. Replaces the generic service prose that used to be
   pasted onto all 17 of them; a table of real values is unique per town by construction. */
.prose .loc-facts{width:100%;border-collapse:collapse;margin:1.6em 0;font-size:.95rem}
.prose .loc-facts caption{text-align:left;font-family:var(--serif);font-size:1.15rem;
  color:var(--ink);padding-bottom:.5em}
.prose .loc-facts th,.prose .loc-facts td{text-align:left;padding:.65em .9em;
  border-bottom:1px solid var(--line-soft);vertical-align:top}
.prose .loc-facts th{font-family:var(--sans);font-weight:700;color:var(--ink);width:38%;
  white-space:nowrap}
.prose .loc-facts td{color:var(--body)}
.prose .loc-facts tr:last-child th,.prose .loc-facts tr:last-child td{border-bottom:0}
@media(max-width:560px){.prose .loc-facts th{white-space:normal;width:44%}}

/* Section heading on an index page. It exists so the outline does not jump h1 -> h3 straight into
   the card grid; it is real content, set quietly so it structures without shouting. */
.sec-quiet{font-family:var(--serif);font-weight:300;font-size:clamp(1.25rem,2vw,1.6rem);
  color:var(--ink);margin:0 0 clamp(18px,2.4vw,28px)}

/* Related reading. Added because all 67 articles had exactly one inbound internal link, from the
   index alone - no topical link flow and one edit away from being orphaned. */
.prose .related{margin:2.6em 0 0;padding-top:1.6em;border-top:1px solid var(--line-soft)}
.prose .related h2{font-size:clamp(1.15rem,1.8vw,1.4rem);margin:0 0 .7em}
.prose .related ul{list-style:none;padding:0;margin:0}
.prose .related li{padding:0 0 .55em}
.prose .related li::before{content:none}
.prose .related a{color:var(--ink);text-decoration:none;font-weight:600;
  border-bottom:1px solid var(--line);padding-bottom:1px}
.prose .related a:hover{color:var(--gold);border-bottom-color:var(--gold)}
.prose .related span{display:block;font-family:var(--sans);font-size:.8rem;color:var(--muted);
  margin-top:2px}
.ph-byline .ph-cite{font-variant-numeric:tabular-nums;color:var(--ink)}

/* ============================================================================
   Reading design, 2026-08-18. The brief: "most of the site is just a bunch of
   words, and the design of it is long". Both true. An 8,400px article ran as
   unbroken grey paragraphs in a 70ch column with the right third empty the
   whole way down. These rules give the long pages structure to look at.
   ============================================================================ */

/* Contents nav. Sits in the column that was empty and follows the reader down. */
.toc{background:var(--card);border:1px solid var(--line-soft);border-top:3px solid var(--gold);
  padding:20px 22px 22px;margin-bottom:22px}
.toc h2{font-family:var(--sans);font-size:.72rem;letter-spacing:.18em;text-transform:uppercase;
  color:var(--gold-2);margin:0 0 12px;font-weight:700}
.toc ol{list-style:none;counter-reset:toc;margin:0;padding:0}
.toc li{counter-increment:toc;margin:0}
.toc a{display:flex;gap:10px;padding:7px 0;font-size:.9rem;line-height:1.35;color:var(--body);
  border-top:1px solid var(--line-soft);transition:color .2s}
.toc li:first-child a{border-top:0;padding-top:0}
.toc a::before{content:counter(toc,decimal-leading-zero);font-family:var(--serif);
  color:var(--gold);font-size:.82rem;flex:none;padding-top:.1em}
.toc a:hover{color:var(--gold)}
@media(max-width:960px){
  /* On a phone the nav is most useful collapsed at the top, not stretched full width. */
  .toc{margin:0 0 26px}
  .toc a{padding:9px 0}
}

/* Section rhythm. A hairline and generous air above each H2 turns one grey mass into
   readable chapters, and gives the eye somewhere to rest when scanning. */
.prose.wide h2{position:relative;margin-top:2.2em;padding-top:1.1em;
  border-top:1px solid var(--line-soft)}
.prose.wide h2:first-child{margin-top:0;padding-top:0;border-top:0}
.prose.wide h2 + p{margin-top:.2em}

/* The opening paragraph carries the page. Larger, darker, tighter measure. */
.prose.wide > p:first-of-type{font-size:1.2rem;line-height:1.62;color:var(--ink);max-width:62ch}

/* Long prose needs anchor-scroll clearance under the sticky header. */
.prose.wide h2[id]{scroll-margin-top:118px}

/* Lists inside prose were indistinguishable from paragraphs at a glance. */
.prose.wide ul li{padding-left:1.6em}
.prose.wide ul li::before{top:.62em;width:7px;height:7px;background:var(--gold);border:0}

/* Photograph inside prose. Full column width, with a caption that says what the building is -
   an uncaptioned photo on a service page reads as filler. */
.prose .prose-shot{margin:2.4em 0;padding:0}
.prose .prose-shot img{width:100%;height:auto;display:block;border-radius:0;margin:0;
  max-height:none;aspect-ratio:16/10;object-fit:cover}
.prose .prose-shot figcaption{font-family:var(--sans);font-size:.82rem;color:var(--muted);
  padding-top:10px;border-top:1px solid var(--line-soft);margin-top:10px}

/* Direct Google route beneath the review widget. See the note in review_widget(): the widget's own
   green face navigates the iframe to Google, which Google will not allow to be framed. */
.review-direct{text-align:center;margin:18px 0 0}
.review-direct .btn{display:inline-flex}

/* ---- Review chooser -------------------------------------------------------
   Replaces the supplier's iframe, whose green face navigated the frame to Google and produced a
   Google 401 (see review_widget() in render.py). Three real links, drawn faces, our type. */
.rfaces{list-style:none;display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(12px,1.6vw,22px);max-width:760px;margin:0 auto;padding:0}
.rfaces li::before{content:none}
.rface{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;
  padding:clamp(20px,2.4vw,30px) clamp(10px,1.4vw,18px);background:var(--card);
  border:1px solid var(--line-soft);border-top:3px solid transparent;
  transition:transform .3s cubic-bezier(.2,.8,.2,1),border-color .3s,box-shadow .3s;height:100%}
.rface svg{width:clamp(56px,6vw,74px);height:auto;transition:transform .3s cubic-bezier(.2,.8,.2,1)}
.rface-text{display:flex;flex-direction:column;gap:4px;align-items:center}
.rface-label{font-family:var(--serif);font-size:clamp(1.05rem,1.5vw,1.25rem);color:var(--ink)}
.rface-sub{font-family:var(--sans);font-size:.82rem;line-height:1.35;color:var(--muted)}
.rface:hover{transform:translateY(-4px);box-shadow:0 18px 36px -22px rgba(0,0,0,.4)}
.rface:hover svg{transform:scale(1.06)}
.rface-sad:hover{border-top-color:#e13b3b}
.rface-neutral:hover{border-top-color:#f2c500}
.rface-happy:hover{border-top-color:#4caf50}
.rface:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
@media(max-width:560px){
  /* Stacked rather than three 100px columns: the labels are the point and they need room. */
  .rfaces{grid-template-columns:1fr;max-width:340px}
  .rface{flex-direction:row;text-align:left;align-items:center;gap:16px;padding:16px 18px}
  .rface svg{width:48px;flex:none}
  /* Label above caption, not beside it: side by side, "It was OK" wrapped mid-phrase and the
     three cards disagreed about where their text started. */
  .rface-text{align-items:flex-start;gap:2px}
  .rface-label{font-size:1.05rem;white-space:nowrap}
}
