/* Elevated Polished Cleaning design system
   Display: Montserrat 600/700 (headings)
   UI/body: Montserrat 400 (everything else), self-hosted
   Accent:  gold, drawn from the mark, used as hairlines and labels only */

/* Montserrat, self-hosted. Served from this domain rather than from Google so
   that reading the site does not tell a third party what is being read, which
   is what the cookie notice promises. Variable weight 300-800 in one file.
   Licensed under the SIL Open Font License. */
@font-face{
  font-family:"Montserrat";
  src:url("/assets/fonts/montserrat.woff2") format("woff2");
  font-weight:300 800; font-style:normal; font-display:optional;
}

:root{
  --ink:#0E0F0C;
  --ink-2:#35372F;
  --paper:#FAF8F4;
  --cream:#F2EEE5;
  --muted:#6E6B62;
  --rule:#E0DACE;
  --rule-2:#CFC7B7;
  --gold:#A8841F;
  --gold-dark:#D6B45F;
  --dark:#111210;
  --dark-2:#1A1B17;
  --display:"Montserrat","Helvetica Neue",Arial,sans-serif;
  --ui:"Montserrat","Helvetica Neue",Arial,sans-serif;
  --measure:66ch;
  --gutter:clamp(20px,5vw,40px);
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *{animation:none!important;transition:none!important}
}
body{
  margin:0; background:var(--paper); color:var(--ink-2);
  font-family:var(--ui); font-weight:400; font-size:17px; line-height:1.7;
  -webkit-font-smoothing:antialiased;
}
img{max-width:100%; height:auto; display:block}
a{color:var(--gold); text-underline-offset:3px; text-decoration-thickness:1px}
a:focus-visible,button:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible{
  outline:2px solid var(--gold); outline-offset:3px;
}
.shell{max-width:1120px; margin:0 auto; padding-inline:var(--gutter)}
.narrow{max-width:760px}
.skip{position:absolute;left:-9999px}
.skip:focus{left:var(--gutter);top:10px;z-index:100;background:var(--paper);color:var(--ink);padding:10px 14px}

/* ---------- type ---------- */
/* Montserrat is wider and has a much larger x-height than the serif it
   replaced, so the same pixel sizes read considerably bigger. Sizes come down,
   weight goes up to 700, and the display sizes get negative tracking, which a
   geometric sans needs at scale and a serif does not. */
h1,h2,h3{font-family:var(--display); font-weight:700; color:var(--ink);
  line-height:1.2; letter-spacing:-.02em; text-wrap:balance; margin:0}
h1{font-size:clamp(27px,3vw,38px)}
h2{font-size:clamp(21px,2.2vw,28px)}
h3{font-size:clamp(17px,1.6vw,20px)}
h3{letter-spacing:-.01em}
h4{font-family:var(--ui); font-weight:500; font-size:17px; color:var(--ink); margin:0}
p{margin:0; max-width:var(--measure)}
.label{
  font-family:var(--ui); font-weight:400; font-size:11px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--gold); margin:0;
}
.lead{font-size:clamp(17px,1.6vw,19px); line-height:1.62; color:var(--ink-2)}
.flow > * + *{margin-top:1.1em}
.flow > * + h2{margin-top:2.2em}
.flow > * + h3{margin-top:1.9em}
.flow > h2 + *,.flow > h3 + *{margin-top:.85em}
.flow ul{margin:0; padding-left:1.15em; max-width:var(--measure)}
.flow li{margin-bottom:.45em}
.flow li::marker{color:var(--rule-2)}

/* diamond rule, echoes the mark */
.diamond{display:block; width:100%; height:9px; border:0; margin:0;
  background:
    linear-gradient(to right,var(--rule),var(--rule)) left center/calc(50% - 16px) 1px no-repeat,
    linear-gradient(to right,var(--rule),var(--rule)) right center/calc(50% - 16px) 1px no-repeat;
  position:relative;
}
.diamond::after{
  content:""; position:absolute; left:50%; top:50%; width:7px; height:7px;
  transform:translate(-50%,-50%) rotate(45deg); border:1px solid var(--gold);
}

/* ---------- header ---------- */
.masthead{background:var(--dark); color:#EDEAE2}
.masthead a{color:#EDEAE2; text-decoration:none}
/* Three columns, not two. With brand and nav as a space-between pair, the
   links sat wherever the wordmark's width left them, which read as a long gap
   after the logo and a nav drifting right. The outer columns take equal share
   of the leftover space, so the link row is centred in the masthead itself
   rather than in whatever is left over. */
.mast-inner{display:grid; grid-template-columns:1fr auto 1fr; align-items:center;
  gap:24px; padding-block:18px}
.mast-inner > .brand{justify-self:start}
.mast-inner > .nav{justify-self:center}
.mast-actions{justify-self:end; display:flex; align-items:center; gap:22px}

/* True centring needs the wordmark and the actions to sit in equal columns
   either side of the links. Measured, that needs 2x255 (the widest of the two)
   + 372 (nav) + 48 (gaps) + 80 (gutters) = 1010px. Between that and the phone layout the three columns would squeeze
   the links off-centre and eventually collide, so the middle band gives up
   centring and spaces the three groups out instead. Honest about the space it
   has, rather than pretending to be centred while visibly not being. */
@media (max-width:1009px) and (min-width:681px){
  .mast-inner{grid-template-columns:auto 1fr auto; gap:20px}
  .mast-inner > .nav{justify-self:center}
  .nav{gap:24px}
  .nav-item.has-menu{margin-right:-15px}
}
.brand{display:flex; align-items:center; gap:12px; text-decoration:none}
.brand-mark{width:30px; height:30px; flex:none}
.brand-text{display:flex; flex-direction:column; line-height:1}
.brand-name{font-family:var(--display); font-weight:700; font-size:19px; letter-spacing:.14em; color:#F3F0E8}
.brand-sub{font-family:var(--ui); font-weight:500; font-size:8px; letter-spacing:.26em;
  text-transform:uppercase; color:var(--gold-dark); margin-top:4px}
/* The gap is measured between BOXES, and a dropdown item's box includes its
   arrow button. That put 37px between "Services" and "Areas" but only 22px
   between "Approach" and "Prices", so the row of words lost its rhythm exactly
   where the arrows stopped. Pulling the arrow's width back out of the flow
   makes every word-to-word gap the same; the arrow keeps its full 24px hit
   area, it just stops pushing the next word along. */
.nav{display:flex; align-items:center; gap:30px; flex-wrap:wrap}
.nav-item.has-menu{margin-right:-15px}
.nav a{font-family:var(--ui); font-size:14px; font-weight:500; letter-spacing:.02em; opacity:.85}
.nav a:hover,.nav a[aria-current="page"]{opacity:1; color:var(--gold-dark)}
.mast-actions .tel{letter-spacing:.04em; font-weight:400}

/* ---------- nav dropdowns ---------- */
.vh{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap}
/* The padding grows the area that keeps the menu open; the matching negative
   margin means the masthead does not get taller for it. */
.nav-item{
  position:relative; display:inline-flex; align-items:center; gap:5px;
  padding-block:10px; margin-block:-10px;
}
.nav-item[data-section="true"] > a{opacity:1; color:var(--gold-dark)}
/* 24x24 hit area around a 10x6 arrow, per WCAG 2.2 target size, again
   without pushing the neighbours around. */
.nav-toggle{
  display:inline-flex; align-items:center; justify-content:center;
  background:none; border:0; cursor:pointer;
  padding:9px 7px; margin:-9px -7px;
  color:#EDEAE2; opacity:.85; line-height:0;
}
.nav-toggle:hover{opacity:1; color:var(--gold-dark)}
.nav-toggle svg{transition:transform .18s ease}
.nav-item[data-open="true"] .nav-toggle svg{transform:rotate(180deg)}

.nav-menu{
  position:absolute; top:calc(100% + 2px); left:-14px; z-index:60;
  min-width:232px; margin:0; padding:8px 0; list-style:none;
  background:var(--dark-2); border:1px solid #2E2F28;
  box-shadow:0 18px 40px rgba(0,0,0,.45);
  display:none;
}
.nav-item[data-open="true"] > .nav-menu{display:block}
/* The open/hover rules set display:block, which would beat the grid on the
   wide variant, so it is restated at the same specificity. */
.nav-item[data-open="true"] > .nav-menu--wide{display:grid}
/* Invisible bridge across the gap between the label and the menu. Without it
   the pointer leaves the item on the way down and the menu shuts under it. */
.nav-menu::before{
  content:""; position:absolute; left:0; right:0; top:-14px; height:14px;
}
/* Hover only where there is a real pointer: on a touch screen hover sticks. */
@media (hover:hover) and (pointer:fine){
  .nav-item:hover > .nav-menu,
  .nav-item:focus-within > .nav-menu{display:block}
  .nav-item:hover > .nav-menu--wide,
  .nav-item:focus-within > .nav-menu--wide{display:grid}
}
.nav-menu li{margin:0}
.nav-menu a{
  display:block; padding:9px 18px; font-size:14px; letter-spacing:.03em;
  color:#D8D4C9; opacity:1; white-space:nowrap;
}
.nav-menu a:hover,.nav-menu a:focus-visible{background:#24251F; color:var(--gold-dark)}
.nav-menu a[aria-current="page"]{color:var(--gold-dark)}
/* Twenty areas in one column overshoot the viewport, so a long menu runs in
   two, with the 'all' row spanning the foot of both.
   NOTE: no `display` here. `.nav-menu` sets display:none at the same
   specificity and earlier in the file, so declaring display:grid on this rule
   would beat it and leave the menu permanently open. The grid is switched on
   only by the open and hover rules above. */
.nav-menu--wide{
  grid-template-columns:1fr 1fr; min-width:380px;
  align-content:start;
}
.nav-menu--wide .nav-menu-all{grid-column:1 / -1}
.nav-menu-all{border-top:1px solid #2E2F28; margin-top:6px; padding-top:4px}
.nav-menu-all a{font-size:13px; letter-spacing:.1em; text-transform:uppercase; color:#A9A496}

/* On narrow screens the masthead nav wraps, and an absolutely positioned menu
   would hang off the side. Let it sit in the flow and push the nav open. */
@media (max-width:680px){
  .nav-item{flex-wrap:wrap}
  .nav-menu{
    position:static; min-width:0; width:100%; left:auto; top:auto;
    box-shadow:none; border-left:0; border-right:0; margin:8px 0 2px;
  }
  .nav-menu a{padding:10px 14px; white-space:normal}
  .nav-menu--wide{min-width:0}
  .nav-item[data-open="true"] > .nav-menu--wide{grid-template-columns:1fr}
}
.btn{
  display:inline-block; font-family:var(--ui); font-size:13px; font-weight:400;
  letter-spacing:.14em; text-transform:uppercase; text-decoration:none;
  padding:13px 24px; border:1px solid var(--gold); color:var(--gold); background:transparent;
  cursor:pointer;
}
.btn:hover{background:var(--gold); color:var(--dark)}
.masthead .btn{border-color:var(--gold-dark); color:var(--gold-dark)}
.masthead .btn:hover{background:var(--gold-dark); color:var(--dark)}
.btn-solid{background:var(--ink); border-color:var(--ink); color:var(--paper)}
.btn-solid:hover{background:var(--gold); border-color:var(--gold); color:var(--dark)}

/* ---------- hero ---------- */
.hero{background:var(--dark); color:#E8E5DC; padding-block:clamp(40px,5.5vw,72px)}
.hero h1{color:#F6F3EB; max-width:22ch}
.hero .label{color:var(--gold-dark)}
.hero p{color:#C6C2B6; max-width:56ch}
.hero .stack{display:flex; flex-direction:column; gap:18px; align-items:flex-start}
.hero-actions{display:flex; gap:14px; flex-wrap:wrap; align-items:center}

/* page intro (non-home) */
.page-head{background:var(--dark); color:#E8E5DC; padding-block:clamp(38px,4.5vw,60px)}
.page-head h1{color:#F6F3EB; max-width:22ch}
.page-head .lead{color:#C6C2B6; max-width:58ch; margin-top:18px}
.page-head .label{color:var(--gold-dark); margin-bottom:16px}
.crumbs{font-size:13px; color:#908C81; margin-bottom:18px; font-weight:300}
.crumbs a{color:#B6B1A4; text-decoration:none}
.crumbs a:hover{color:var(--gold-dark)}

/* ---------- sections ---------- */
.section{padding-block:clamp(48px,7vw,84px)}
.section--cream{background:var(--cream)}
/* Two cream blocks in a row would merge into one slab; a hairline keeps them
   legible as separate sections without reintroducing a dark band. */
.section--cream + .section--cream{border-top:1px solid var(--rule-2)}
.section--dark{background:var(--dark); color:#D8D4C9}
.section--dark h2,.section--dark h3{color:#F3F0E8}
.section--dark .label{color:var(--gold-dark)}
.section--dark a{color:var(--gold-dark)}
.sec-head{margin-bottom:34px}
.sec-head .label{margin-bottom:14px}

/* ---------- grids ---------- */
.grid{display:grid; gap:1px; background:var(--rule); border:1px solid var(--rule)}
.grid--3{grid-template-columns:repeat(3,1fr)}
.grid--2{grid-template-columns:repeat(2,1fr)}
.cell{background:var(--paper); padding:26px 24px}
/* The rules between cells are the container background showing through a 1px
   gap, so a part-filled final row leaves a bare grey rectangle. When the last
   item would sit alone, let it span the rest of the row instead. */
.grid--3 > .cell:last-child:nth-child(3n+2){grid-column:span 2}
.section--cream .cell{background:var(--cream)}
.cell h3{font-size:19px; margin-bottom:8px}
.cell p{font-size:15.5px; color:var(--muted); line-height:1.6}
.cell a{text-decoration:none}
.cell a:hover h3{color:var(--gold)}

/* numbered steps */
.steps{display:grid; gap:0; counter-reset:step}
.step{display:grid; grid-template-columns:54px 1fr; gap:20px;
  padding-block:22px; border-top:1px solid var(--rule)}
.step:first-child{border-top:0}
.step-n{font-family:var(--display); font-weight:700; font-size:22px; color:var(--gold); line-height:1.1}
.step h3{font-size:20px; margin-bottom:6px}
.step p{font-size:16px; color:var(--ink-2)}

/* credential strip */
.creds{display:flex; flex-wrap:wrap; gap:10px; list-style:none; padding:0; margin:0}
.creds li{font-family:var(--ui); font-size:12px; font-weight:400; letter-spacing:.1em;
  text-transform:uppercase; border:1px solid var(--rule-2); padding:9px 14px; color:var(--ink-2)}
.section--dark .creds li{border-color:#33342C; color:#C6C2B6}

/* area link columns */
.areas-group + .areas-group{margin-top:26px}
.areas-group h4{color:var(--gold); font-size:11px; letter-spacing:.22em;
  text-transform:uppercase; font-weight:400; margin-bottom:12px}
.arealinks{display:flex; flex-wrap:wrap; gap:8px 0; list-style:none; padding:0; margin:0}
.arealinks li{display:flex; align-items:center}
.arealinks li + li::before{content:""; width:4px; height:4px; transform:rotate(45deg);
  background:var(--rule-2); margin:0 14px}
.arealinks a{font-family:var(--ui); font-size:16px; text-decoration:none; color:var(--ink-2)}
.arealinks a:hover{color:var(--gold)}
.section--dark .arealinks a{color:#C6C2B6}
.section--dark .arealinks a:hover{color:var(--gold-dark)}
.section--dark .arealinks li + li::before{background:#3A3B33}

/* pull / method panel */
.panel{background:var(--cream); border-left:2px solid var(--gold); padding:26px 28px; max-width:var(--measure)}
.section--cream .panel{background:var(--paper)}
.panel > * + *{margin-top:1em}

/* testimonial */
.quote{max-width:62ch}
.quote blockquote{margin:0; font-family:var(--display); font-weight:500; font-size:clamp(19px,2.2vw,24px); letter-spacing:-.01em;
  line-height:1.4; color:var(--ink)}
.quote cite{display:block; margin-top:16px; font-family:var(--ui); font-style:normal;
  font-size:12px; letter-spacing:.18em; text-transform:uppercase; color:var(--muted)}

/* FAQ */
.faq{border-top:1px solid var(--rule); max-width:var(--measure)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{padding:18px 30px 18px 0; cursor:pointer; list-style:none;
  font-family:var(--ui); font-weight:500; font-size:17px; color:var(--ink); position:relative}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:""; position:absolute; right:4px; top:50%; width:8px; height:8px;
  border-right:1px solid var(--gold); border-bottom:1px solid var(--gold);
  transform:translateY(-70%) rotate(45deg)}
.faq details[open] summary::after{transform:translateY(-30%) rotate(-135deg)}
.faq details > p{padding:0 0 20px; font-size:16px; color:var(--ink-2)}

/* form */
.form{max-width:600px; display:grid; gap:18px}
.field{display:grid; gap:7px}
.field label{font-family:var(--ui); font-size:12px; letter-spacing:.14em;
  text-transform:uppercase; color:var(--muted)}
.field input,.field select,.field textarea{
  font-family:var(--ui); font-size:16px; color:var(--ink); background:var(--paper);
  border:1px solid var(--rule-2); padding:12px 14px; border-radius:0; width:100%;
}
.field textarea{min-height:110px; resize:vertical}
.form-note{font-size:14px; color:var(--muted); max-width:56ch}
.form-row{display:grid; grid-template-columns:1fr 1fr; gap:18px}
.form-row--3{grid-template-columns:1fr 1fr 1fr}

/* honeypot: hidden from people, visible to naive bots.
   Not display:none, which some bots detect and skip. */
.hp{position:absolute!important; left:-9999px!important; top:auto!important;
  width:1px!important; height:1px!important; overflow:hidden!important}

/* journal */
.posts{display:grid; gap:0; border-top:1px solid var(--rule)}
.post-row{display:grid; grid-template-columns:150px 1fr; gap:26px;
  padding-block:26px; border-bottom:1px solid var(--rule); text-decoration:none}
.post-row:hover h3{color:var(--gold)}
.post-meta{font-size:12px; letter-spacing:.14em; text-transform:uppercase; color:var(--muted); padding-top:6px}
.post-row h3{font-size:23px; margin-bottom:7px}
.post-row p{font-size:15.5px; color:var(--muted); line-height:1.6}

/* footer */
.footer{background:var(--dark); color:#9D998E; padding-block:56px 34px; font-size:14.5px}
.footer a{color:#C6C2B6; text-decoration:none}
.footer a:hover{color:var(--gold-dark)}
.footer h4{color:var(--gold-dark); font-size:11px; letter-spacing:.22em;
  text-transform:uppercase; font-weight:400; margin-bottom:14px}
.footer-grid{display:grid; grid-template-columns:1.4fr 1fr 1fr 1fr; gap:38px}
.footer ul{list-style:none; margin:0; padding:0}
.footer li{margin-bottom:8px}
.footer-base{margin-top:40px; padding-top:22px; border-top:1px solid #2A2B24;
  display:flex; justify-content:space-between; gap:18px; flex-wrap:wrap; font-size:13px}

/* ---------- responsive ---------- */
@media (max-width:900px){
  .grid--3{grid-template-columns:repeat(2,1fr)}
  .grid--3 > .cell:last-child:nth-child(3n+2){grid-column:auto}
  .grid--3 > .cell:last-child:nth-child(2n+1){grid-column:span 2}
  .footer-grid{grid-template-columns:1fr 1fr; gap:30px}
}
@media (max-width:680px){
  body{font-size:16.5px}
  .grid--3,.grid--2{grid-template-columns:1fr}
  .grid--3 > .cell:last-child{grid-column:auto}
  /* Below this width there is no room for three columns, so the masthead goes
     back to a wrapping row: wordmark and actions on the first line, the links
     underneath. */
  .mast-inner{display:flex; flex-wrap:wrap; align-items:center;
              justify-content:space-between; padding-block:14px; position:relative}
  .nav{gap:16px; width:100%; justify-content:flex-start; order:3}
  .mast-actions{gap:14px}
  /* On a phone the telephone number is the primary action, so it sits opposite
     the wordmark instead of trailing the nav list. Lifted out of the flow
     rather than moved in the markup, so the desktop masthead is untouched. */
  .mast-actions .tel{
    position:absolute; top:14px; right:var(--gutter);
    height:34px; display:inline-flex; align-items:center;
    font-size:15px; font-weight:500; letter-spacing:.02em;
    opacity:1; color:var(--gold-dark);
  }
  .nav .btn{display:none}
  .post-row{grid-template-columns:1fr; gap:8px}
  .post-meta{padding-top:0}
  .form-row,.form-row--3{grid-template-columns:1fr}
  .footer-grid{grid-template-columns:1fr}
  .step{grid-template-columns:38px 1fr; gap:14px}
}

/* ---------- photography ---------- */
.fig{margin:0; max-width:var(--measure)}
/* Most of these photographs are portrait, and at full column width a portrait
   image renders taller than the window. The cap goes on the figure's width,
   computed at build time from the photograph's own ratio, so the image itself
   keeps width:100% and still reserves its space before it loads. */
/* The per-image cap is applied here rather than inline, so the media query
   below can drop it. On a phone a portrait photo capped to its desktop width
   sits as a narrow column in the middle of the screen with gutters either
   side, which looks like a mistake rather than a decision. */
.fig{margin-inline:auto; max-width:var(--fig-max, none)}
.compare-pair{max-width:var(--pair-max, none)}
@media (max-width:680px){
  .fig, .compare-pair{max-width:none}
}
.fig picture, .fig img{display:block; width:100%; height:auto}
.fig figcaption, .compare figcaption{
  font-family:var(--ui); font-size:14px; color:var(--muted);
  margin-top:12px; line-height:1.5; max-width:var(--measure);
}
.flow > .fig, .flow > .compare{margin-top:1.6em}

.compare{margin:0}
.compare-pair{display:grid; grid-template-columns:1fr 1fr; gap:14px}
.compare-half{position:relative}
/* Both halves share a shape, so a pair whose sources differ slightly still
   lines up rather than stepping. */
.compare-half picture, .compare-half img{display:block; width:100%}
.compare-half img{aspect-ratio:var(--pair-ratio, 3 / 5); object-fit:cover; height:auto}
.compare-pair{margin-inline:auto}
.compare-tag{
  position:absolute; top:12px; left:12px; z-index:1;
  font-family:var(--ui); font-size:10.5px; letter-spacing:.16em; text-transform:uppercase;
  background:var(--dark); color:var(--gold-dark); padding:5px 10px;
}

/* a single photograph used as a section feature */
.feature-img{margin-top:38px}
.feature-img picture, .feature-img img{display:block; width:100%; height:auto}
.feature-img figcaption{
  font-family:var(--ui); font-size:14px; color:var(--muted); margin-top:12px;
}

@media (max-width:620px){
  .compare-pair{grid-template-columns:1fr; gap:18px}
}

/* ---------- full-bleed hero ---------- */
/* The photograph runs edge to edge behind the text. Source photographs are
   portrait, so the crop is handled by object-fit rather than by the file, and
   object-position favours the upper-middle of the frame where the subject is. */
.hero--cover{
  position:relative; isolation:isolate;
  display:grid; align-items:center;
  min-height:clamp(400px,50vh,540px);
  padding-block:clamp(48px,6vw,76px);
  text-align:center;
}
.hero--cover .hero-bg{position:absolute; inset:0; z-index:-1; overflow:hidden}
.hero--cover .hero-bg picture{display:block; width:100%; height:100%}
.hero--cover .hero-bg img{
  display:block; width:100%; height:100%;
  object-fit:cover; object-position:center 44%;
}
/* Scrim in the brand dark, heavier top and bottom so the masthead above and
   the section below both keep a clean edge, lighter through the middle so the
   photograph still reads. */
.hero--cover .hero-scrim{
  position:absolute; inset:0;
  /* Alpha is set from measurement, not taste: sampling the brightest pixel
     under each text band, AA needs .61 behind the lead and .65 behind the
     eyebrow. .70 through the middle clears both with margin, and the darker
     top and bottom edges carry the joins to the masthead and the next
     section. */
  background:linear-gradient(180deg,
    rgba(17,18,16,.82) 0%,
    rgba(17,18,16,.70) 16%,
    rgba(17,18,16,.70) 76%,
    rgba(17,18,16,.56) 100%);
}
.hero--cover .hero-inner{width:100%}
.hero--cover .stack{align-items:center; gap:20px}
.hero--cover h1{max-width:19ch; margin-inline:auto; color:#FBF9F4}
.hero--cover p.lead{max-width:58ch; margin-inline:auto; color:#E2DFD6}
.hero--cover .hero-actions{justify-content:center}
.hero--cover .label{color:#EBD49A}

/* Solid gold call to action: the one high-contrast element in the frame. */
.btn--gold{background:var(--gold-dark); border-color:var(--gold-dark); color:var(--dark)}
.btn--gold:hover{background:#E8CE86; border-color:#E8CE86; color:var(--dark)}
.hero-alt-link{color:#E2DFD6; font-family:var(--ui); font-size:15px}
.hero-alt-link:hover{color:var(--gold-dark)}

@media (max-width:720px){
  .hero--cover{min-height:clamp(360px,58vh,460px)}
  /* Let the headline use the full gutter width rather than wrapping to five
     ragged lines against an artificial measure. */
  .hero--cover h1{max-width:none}
  .hero--cover .hero-bg img{object-position:center 56%}
  .hero--cover p.lead{font-size:16.5px}
  /* The photograph is busiest and brightest through the middle at this width,
     where the lead sits, so the scrim carries more weight. */
  .hero--cover .hero-scrim{
    background:linear-gradient(180deg,
      rgba(17,18,16,.86) 0%,
      rgba(17,18,16,.76) 38%,
      rgba(17,18,16,.78) 62%,
      rgba(17,18,16,.90) 100%);
  }
}

/* sub-headings inside a section: h3 for semantics, sized as a UI label */
.flow h3.sub{
  font-family:var(--ui); font-weight:500; font-size:17px;
  color:var(--ink); letter-spacing:0; line-height:1.4;
}
.areas-group h3.group-label{
  font-family:var(--ui); font-weight:400; font-size:11px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--gold); margin-bottom:12px; line-height:1.4;
}
.footer .foot-label{
  color:var(--gold-dark); font-size:11px; letter-spacing:.22em;
  text-transform:uppercase; font-weight:400; margin:0 0 14px;
}

/* ---------- cookie consent ---------- */
.consent{
  position:fixed; left:0; right:0; bottom:0; z-index:200;
  background:var(--dark); color:#D8D4C9;
  border-top:1px solid var(--gold-dark);
  padding:18px var(--gutter) calc(18px + env(safe-area-inset-bottom,0px));
}
.consent-inner{
  max-width:1120px; margin:0 auto;
  display:flex; align-items:center; gap:28px; flex-wrap:wrap;
}
.consent-text{flex:1 1 460px; min-width:0}
.consent-text p{margin:0; font-size:14.5px; line-height:1.6; color:#C6C2B6; max-width:68ch}
.consent-text p + p{margin-top:8px}
.consent-text p:first-child{color:#F3F0E8; margin-bottom:6px}
.consent-text p:first-child strong{font-family:var(--display); font-weight:600; font-size:17px; letter-spacing:.01em}
.consent-text p + p strong{color:#F3F0E8; font-weight:600}
.consent-text a{color:var(--gold-dark)}
.consent-actions{display:flex; gap:12px; flex:0 0 auto; align-items:center}
/* Declining is exactly as easy as accepting, which the ICO requires. */
/* Both choices get identical weight: no nudging toward Accept. */
.consent .btn{padding:12px 26px; font-size:12.5px; min-width:132px; text-align:center}
.consent .consent-no{background:#F3F0E8; border-color:#F3F0E8; color:var(--dark)}
.consent .consent-no:hover{background:#fff; border-color:#fff; color:var(--dark)}
.consent .consent-yes{background:var(--gold-dark); border-color:var(--gold-dark); color:var(--dark)}
.consent .consent-yes:hover{background:#E4C87E; border-color:#E4C87E}
@media (max-width:620px){
  .consent-inner{gap:16px}
  .consent-actions{width:100%}
  .consent-actions .btn{flex:1 1 0; text-align:center}
  /* On a phone the full notice ran to about half the viewport, which buried
     whatever was underneath it. Cap the prose and let it scroll: the banner
     now takes roughly a third of the screen, and both buttons stay visible
     without the reader having to scroll the page behind it. */
  /* The notice is short enough now to show in full on a phone. The cap is a
     safety net for very small screens and for large text settings, not the
     normal case: clipped consent copy reads as though something is being
     hidden, which is the opposite of the point. */
  .consent-text{max-height:46vh; overflow-y:auto; overscroll-behavior:contain}
  .consent-text p{font-size:13.5px; line-height:1.5}
  .consent-text p + p{margin-top:7px}
  .consent{padding-top:14px}
}

/* ---------- photograph placeholders ---------- */
/* Deliberately plain and obviously unfinished, so an empty slot can never be
   mistaken for a design choice or for a broken image. */
.ph{
  width:100%;
  border:1px dashed var(--rule-2); background:var(--cream);
  display:grid; place-items:center; text-align:center;
}
.ph-in{display:flex; flex-direction:column; gap:7px; padding:22px; max-width:46ch}
.ph-tag{
  font-family:var(--ui); font-size:11px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--gold);
}
.ph-slug{font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:13px; color:var(--ink-2)}
.ph-brief{font-size:14px; line-height:1.55; color:var(--muted)}
.ph-shape{
  font-family:var(--ui); font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--muted); opacity:.8;
}
.section--cream .ph{background:var(--paper)}
/* The lead image sits tight under the page head rather than a full section. */
.section--lead-media{padding-block:clamp(24px,3vw,38px) 0}
.section--lead-media .ph,.section--lead-media img{max-width:100%}
/* The banner at the top of a service page was running to 61% of the screen on
   a laptop, which pushed the first paragraph below the fold on every one of
   them. Cropping it to a wider ratio rather than shrinking its width keeps the
   full-bleed look and loses a third of the height.

   aspect-ratio rather than max-height on purpose: the height stays derived
   from the width, so the box is reserved before the image loads and there is
   no layout shift. A max-height would reserve the tall box first and then
   collapse it. */
.section--lead-media picture img{
  display:block; width:100%; height:auto;
  aspect-ratio:7 / 2; object-fit:cover;
}
@media (max-width:680px){
  /* A 8:3 letterbox on a phone is a sliver, so the crop relaxes as the column
     narrows and the image is allowed to be taller relative to its width. */
  .section--lead-media picture img{aspect-ratio:3 / 2}
}
@media (max-width:680px){
  .ph-brief{font-size:13px}
  .ph-in{padding:16px}
}

/* ---------- service cards ---------- */
/* Flex rather than a fixed grid: five cards then sit three and two centred,
   instead of leaving a hole in the final row. */
.svc-cards{display:flex; flex-wrap:wrap; gap:26px; justify-content:center}
.svc-card{
  flex:1 1 300px; max-width:352px;
  display:flex; flex-direction:column;
  background:var(--paper); border:1px solid var(--rule);
}
.section--cream .svc-card{background:var(--paper)}
.svc-card-media{position:relative; background:var(--cream)}
.svc-card-media img,.svc-card-media picture{display:block; width:100%}
.svc-card-media img{aspect-ratio:16 / 10; object-fit:cover; height:auto}
.svc-card-media .ph{border:0; border-bottom:1px dashed var(--rule-2)}
.svc-card-body{display:flex; flex-direction:column; gap:12px; padding:24px 24px 26px; flex:1}
.svc-card-body h3{font-size:19px; margin:0}
.svc-card-body p{font-size:15.5px; line-height:1.6; color:var(--muted); margin:0; flex:1}
.btn--sm{align-self:flex-start; padding:10px 18px; font-size:11.5px}

/* ---------- areas we cover ---------- */
.section--cover .cover-inner{
  display:grid; grid-template-columns:1.05fr .95fr; gap:clamp(32px,5vw,64px);
  align-items:center;
}
.cover-text .lead{max-width:52ch}
.cover-group{margin-top:26px}
.cover-group h3{
  font-family:var(--ui); font-size:12px; font-weight:400; letter-spacing:.16em;
  text-transform:uppercase; color:var(--gold); margin:0 0 8px;
}
.cover-list{font-size:16px; line-height:1.9; color:var(--ink-2); margin:0; max-width:46ch}
.cover-list a{text-decoration:none; border-bottom:1px solid var(--rule-2)}
.cover-list a:hover{color:var(--gold); border-bottom-color:var(--gold)}
.cover-cta{margin-top:30px}
.cover-map img,.cover-map picture{display:block; width:100%; height:auto}
.cover-map img{border:1px solid var(--rule-2)}

/* ---------- coverage map ---------- */
.cover-svg{display:block; width:100%; height:auto; border:1px solid var(--rule-2)}
/* The patch: a soft shape behind the pins so the coverage reads as an area
   rather than as nineteen unconnected dots. */
.m-bg{fill:var(--paper)}
.m-patch{fill:rgba(168,132,31,.07)}
.m-patch-edge{fill:none; stroke:rgba(168,132,31,.32); stroke-width:1.5; stroke-dasharray:7 6}
.m-water{
  font-family:var(--ui); font-size:15px; font-weight:400; letter-spacing:.08em;
  fill:#8FA6B4; text-transform:uppercase;
}
.m-green{
  font-family:var(--ui); font-size:14px; font-weight:500; letter-spacing:.04em;
  fill:#8A9479;
}
.m-park{fill:#DFE3D4}
.m-river{stroke:#C8D4DC; stroke-width:16; stroke-linejoin:round; stroke-linecap:round}
.m-river-line{stroke:#AFC2CE; stroke-width:1; stroke-linejoin:round; stroke-linecap:round}
.m-hit{fill:transparent}
.m-dot{fill:var(--gold); stroke:var(--paper); stroke-width:3}
.m-leader{stroke:var(--rule-2); stroke-width:1.5}
.m-label{
  font-family:var(--ui); font-size:18px; font-weight:500;
  fill:var(--ink-2); paint-order:stroke; stroke:var(--paper); stroke-width:5;
  stroke-linejoin:round;
}
.m-area{cursor:pointer}
.m-area:hover .m-dot,.m-area:focus-visible .m-dot{fill:var(--ink)}
.m-area:hover .m-label,.m-area:focus-visible .m-label{fill:var(--ink)}
.m-area:focus-visible{outline:2px solid var(--gold); outline-offset:2px}

@media (max-width:860px){
  .section--cover .cover-inner{grid-template-columns:1fr; gap:32px}
  .cover-map{order:-1}
}

/* ---------- email in the masthead and above every form ---------- */
.sec-contact{
  margin:10px 0 0; font-size:15px; color:var(--muted); max-width:60ch;
}
.sec-contact a{color:var(--ink-2); border-bottom:1px solid var(--rule-2); text-decoration:none}
.sec-contact a:hover{color:var(--gold); border-bottom-color:var(--gold)}

/* Below about 360px the wordmark and the telephone meet in the middle, so both
   step down. Measured: at 320px they were overlapping by 8px. */
@media (max-width:360px){
  .brand-name{font-size:16px; letter-spacing:.1em}
  .brand-sub{font-size:7.5px; letter-spacing:.2em}
  .brand{gap:9px}
  .brand-mark{width:26px; height:26px}
  .mast-actions .tel{font-size:13.5px}
}

/* ---------- price tables ---------- */
.table-wrap{overflow-x:auto; margin:22px 0 6px; -webkit-overflow-scrolling:touch}
.ptable{border-collapse:collapse; width:100%; min-width:460px; font-family:var(--ui)}
.ptable caption{
  caption-side:top; text-align:left; padding:0 0 10px;
  font-size:12px; letter-spacing:.16em; text-transform:uppercase; color:var(--gold);
}
.ptable th,.ptable td{
  padding:12px 16px; text-align:left; font-size:15px; font-weight:400;
  border-bottom:1px solid var(--rule); font-variant-numeric:tabular-nums;
}
.ptable thead th{
  font-size:11.5px; letter-spacing:.12em; text-transform:uppercase;
  color:var(--muted); border-bottom:1px solid var(--rule-2); white-space:nowrap;
}
.ptable tbody th{font-weight:500; color:var(--ink); white-space:nowrap}
.ptable tbody tr:last-child th,.ptable tbody tr:last-child td{border-bottom:0}
.ptable td{color:var(--ink-2)}
.ptable .yes{color:var(--gold); font-weight:600}
.ptable .sub-h{display:block; font-size:10.5px; letter-spacing:.1em; color:var(--gold); margin-top:3px}
.ptable .no{color:var(--rule-2)}
.table-note{font-size:13.5px; color:var(--muted); margin:4px 0 0; line-height:1.6}
.section--cream .ptable th,.section--cream .ptable td{border-color:var(--rule-2)}
@media (max-width:680px){
  .ptable th,.ptable td{padding:10px 12px; font-size:14px}
}

/* ---------- enquiry form groups ---------- */
.fs{border:0; padding:0; margin:0 0 26px; min-width:0}
.fs legend{
  padding:0; margin:0 0 14px; font-family:var(--ui); font-size:11.5px;
  letter-spacing:.16em; text-transform:uppercase; color:var(--gold);
}
.fs + .fs{border-top:1px solid var(--rule-2); padding-top:24px}
.fs--choice legend{color:var(--ink); font-size:12px}
.choice{display:flex; gap:12px; flex-wrap:wrap}
.choice-opt{
  display:flex; align-items:center; gap:10px; cursor:pointer;
  border:1px solid var(--rule-2); background:var(--paper);
  padding:13px 20px; flex:1 1 200px;
  font-family:var(--ui); font-size:15px; color:var(--ink-2);
}
.choice-opt:hover{border-color:var(--gold)}
.choice-opt input{accent-color:var(--gold); width:17px; height:17px; flex:none}
.choice-opt:has(input:checked){border-color:var(--gold); background:#fff; color:var(--ink)}
.choice-opt:focus-within{outline:2px solid var(--gold); outline-offset:2px}

.foot-more{margin-top:8px}
.foot-more a{color:var(--gold-dark)}

/* ---- Homepage feature bands: deep cleaning, commercial cleaning ----
   A photograph beside a short piece of copy. Two columns on a wide screen,
   stacked on a phone with the picture first, so the band still reads as one
   object rather than a floating image above unrelated text. */
.feature{
  display:grid; gap:clamp(24px,4vw,56px); align-items:center;
}
.feature-media picture, .feature-media img{display:block; width:100%; height:auto}
.feature-media img{border-radius:2px}
.feature-text h2{margin-top:10px; max-width:20ch}
.feature-text p{max-width:52ch}
.feature-text p + p{margin-top:14px}
.feature-actions{
  display:flex; flex-wrap:wrap; gap:14px 22px; align-items:center;
  margin-top:26px;
}
.feature-alt-link{font-size:15px; white-space:nowrap}

@media (min-width:900px){
  .feature{grid-template-columns:1fr 1fr}
  /* The flipped band puts the text first in the grid while leaving the source
     order alone, so the reading order on a phone stays picture-then-text. */
  .feature--flip .feature-media{order:2}
  .feature--flip .feature-text{order:1}
}

/* ---- QR landing page (/hello) ----
   Three things a scanner might want: the phone number, a short form, and a way
   into the full site. The dark hero holds the first; the form and the site link
   follow it. The whole page is on the brand's dark ground so it reads as one
   piece rather than a card sitting on the ordinary site. */
.card-body{background:var(--dark)}
.card-page{
  min-height:100svh; display:flex; flex-direction:column;
  align-items:center; justify-content:center; text-align:center;
  background:var(--dark); color:#E9E6DE;
  padding:clamp(28px,7vw,56px) var(--gutter);
}
.card-page .brand-mark{width:62px; height:62px}
.card-page h1{
  color:#F5F2EA; font-size:clamp(27px,6.5vw,38px); margin:20px 0 0; max-width:16ch;
}
.card-page .card-sub{
  color:#B9B4A8; max-width:34ch; margin:14px auto 0; font-size:16px; line-height:1.6;
}
.card-actions{
  display:flex; flex-direction:column; gap:14px;
  width:100%; max-width:380px; margin:34px auto 0;
}
/* 56px tall: comfortably past the 24x24 WCAG 2.2 target minimum, and sized for
   a thumb on a phone held one-handed, which is how a scanned QR code is read. */
.card-actions .btn{
  min-height:56px; display:flex; align-items:center; justify-content:center;
  font-size:16px; width:100%;
}
/* The third action is a quieter one: it competes with neither calling nor
   enquiring, but it is still a full-width target rather than a text link. */
.card-actions .btn--quiet{
  border-color:#4A4B43; color:#CFCABE; background:transparent;
}
.card-actions .btn--quiet:hover{border-color:var(--gold-dark); color:var(--gold-dark)}
.card-meta{margin-top:30px; font-size:14px; color:#B9B4A8; line-height:1.7}
.card-meta a{color:var(--gold-dark)}

/* The form. Single column everywhere: this is a phone page first. */
.card-form{
  background:var(--dark-2); border-top:1px solid #2A2B25;
  padding:clamp(40px,8vw,68px) var(--gutter);
}
.card-form-inner{max-width:440px; margin:0 auto}
.card-form h2{color:#F5F2EA; font-size:clamp(21px,4.5vw,26px); margin:0}
.card-form-note{color:#B9B4A8; font-size:15px; margin:8px 0 24px}
.form--compact .field{margin-bottom:16px}
.form--compact label{
  display:block; font-size:13px; letter-spacing:.06em; text-transform:uppercase;
  color:#B9B4A8; margin-bottom:6px;
}
.form--compact input, .form--compact textarea{
  width:100%; background:#101109; color:#F0EDE5;
  border:1px solid #3A3B33; border-radius:2px;
  padding:13px 14px; font:inherit; font-size:16px;  /* 16px stops iOS zooming on focus */
  min-height:50px;
}
.form--compact textarea{min-height:88px; resize:vertical}
.form--compact input:focus-visible, .form--compact textarea:focus-visible{
  outline:2px solid var(--gold-dark); outline-offset:2px; border-color:var(--gold-dark);
}
.form--compact .btn{width:100%; min-height:56px; display:flex;
  align-items:center; justify-content:center; font-size:16px; margin-top:4px}
.form--compact .form-note{color:#8C887E; font-size:13px; line-height:1.6; margin-top:16px}
.form--compact .form-note a{color:#B9B4A8}

.card-tail{
  background:var(--dark); text-align:center;
  padding:clamp(32px,6vw,48px) var(--gutter) clamp(36px,7vw,56px);
}
.card-site-link{
  font-size:16px; color:var(--gold-dark); text-decoration:none;
  border-bottom:1px solid var(--gold-dark); padding-bottom:3px;
}
.card-site-link:hover{color:#E4C87E; border-color:#E4C87E}
.card-foot{margin-top:22px; font-size:13px; color:#8C887E; line-height:1.9}
.card-foot a{color:#B9B4A8}

/* A QR scan is always a first visit, so the cookie banner is always on screen
   the first time this page is seen. Centring the content vertically put the
   buttons directly behind it. On a phone the content starts at the top instead,
   and the buttons are lifted above the welcome line: the mark, the heading and
   all three targets then clear the banner on every phone size. Source order is
   unchanged, so a screen reader and the desktop layout still get heading,
   welcome, then buttons. */
@media (max-width:620px){
  .card-page{justify-content:flex-start; padding-top:clamp(18px,3vh,34px);
             min-height:auto; padding-bottom:clamp(28px,6vw,44px)}
  .card-page h1{font-size:clamp(25px,6vw,32px)}
  .card-page .brand-mark{width:52px; height:52px}
  .card-actions{order:1; margin-top:24px; gap:12px}
  .card-page .card-sub{order:2; margin-top:24px}
  .card-meta{order:3}
}

/* Short phones. With three buttons the tertiary one clipped the top of the
   cookie banner on a 667px screen, so tighten the block above them rather than
   shrink the targets themselves: a 56px button is the point of the page. */
@media (max-width:620px) and (max-height:720px){
  .card-page{padding-top:12px}
  .card-page .brand-mark{width:40px; height:40px}
  .card-page h1{margin-top:12px}
  /* 52px is still more than twice the 24px WCAG 2.2 minimum and still a
     comfortable thumb target; the 4px per button buys the room the cookie
     notice needs to show in full on a 667px phone. */
  .card-actions{margin-top:16px; gap:10px}
  .card-actions .btn{min-height:52px}
}

/* ---- Homepage "Why we're different" ----
   A dark band between the service features and the method steps. Dark because
   it is the one section making an argument rather than describing a service,
   and the change of ground gives it the weight to carry that. */
.section--dark{background:var(--dark); color:#CFCABE}
.sec-head--dark h2{color:#F5F2EA}
.sec-head--dark .label{color:var(--gold-dark)}
.diff-lead{
  max-width:62ch; color:#B9B4A8; font-size:clamp(16px,1.5vw,18px); line-height:1.65;
  margin:0 0 clamp(28px,4vw,44px);
}
.diff-grid{
  display:grid; gap:clamp(22px,3vw,34px);
  grid-template-columns:repeat(auto-fit,minmax(255px,1fr));
}
.diff-item{border-top:1px solid #3A3B33; padding-top:20px}
.diff-item h3{color:#F5F2EA; font-size:19px; margin:0 0 10px; max-width:22ch}
.diff-item p{color:#B9B4A8; font-size:15.5px; line-height:1.62; margin:0}

/* ---- Founders and testimonials ----
   Both render only when real data exists, so these rules are dormant until
   names, a photograph and review text have been supplied and approved. */
.founders{display:grid; gap:clamp(24px,4vw,48px); align-items:center}
.founders-media picture, .founders-media img{display:block; width:100%; height:auto}
.founders-media img{border-radius:2px}
.founders-text p{max-width:54ch}
.founders-list{list-style:none; padding:0; margin:22px 0 0; display:grid; gap:7px}
.founders-list li{font-size:15px; color:var(--ink-2)}
.founders-list strong{color:var(--ink); font-weight:600}
@media (min-width:900px){
  .founders{grid-template-columns:minmax(0,440px) 1fr}
  .founders--notext{grid-template-columns:1fr}
}

.reviews-note{
  max-width:56ch; color:var(--muted); font-size:15.5px; line-height:1.6;
  margin:0 0 clamp(24px,3vw,36px);
}
.reviews{display:grid; gap:clamp(20px,2.5vw,28px);
  grid-template-columns:repeat(auto-fit,minmax(275px,1fr))}
.review{margin:0; border-top:1px solid var(--rule); padding-top:20px}
.review blockquote{margin:0; font-size:16.5px; line-height:1.62; color:var(--ink-2)}
.review figcaption{margin-top:12px; font-size:13px; letter-spacing:.06em;
  text-transform:uppercase; color:var(--muted)}

/* ---- Related services, on service pages ---- */
.rel-cards{display:grid; gap:clamp(20px,2.5vw,30px);
  grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.rel-card{border-top:1px solid var(--rule); padding-top:20px}
.rel-card h3{font-size:19px; margin:0 0 9px}
.rel-card h3 a{text-decoration:none; border-bottom:1px solid var(--rule-2)}
.rel-card h3 a:hover{border-color:var(--gold)}
.rel-card p{margin:0; font-size:15.5px; line-height:1.62; color:var(--ink-2); max-width:46ch}

/* ---- Area page photograph ----
   Not the wide banner the service pages use. Several of these photographs are
   only 690-768px wide at source, and a 944px full-bleed band means a 2x screen
   asks for 1888px and gets upscaling it can see. Shown at 460px every source
   in the set is sharp, including the smallest, and the page keeps a real
   photograph rather than a blurry one. */
.section--area-media{padding-block:clamp(24px,3vw,38px) 0}
.section--area-media picture, .section--area-media img{display:block}
.section--area-media img{
  width:100%; max-width:460px; height:auto; margin-inline:auto;
  aspect-ratio:3 / 2; object-fit:cover;
}
@media (max-width:680px){
  .section--area-media img{max-width:none; aspect-ratio:3 / 2}
}
