/* ==========================================================================
   Office Cleaning London — Homepage
   Design tokens: simplified to one blue (#0B86A0) + white, per request —
   "simple contrast to work with, then we can integrate more." Token names
   are kept as-is (--blue-deep, --cream, etc.) since they're used all over
   this file; only the values changed, so nothing downstream needed editing.
   ========================================================================== */

:root {
  /* Colour — a single brand blue (#0B86A0) used everywhere blue appears.
     blue-deep/blue-sky/blue-pale are computed shades of that SAME blue
     (darker for hover-fills, lighter for washes/borders) — not separate
     brand colors, just what's needed for hover feedback and subtle tinted
     backgrounds to still read against a plain white base. */
  --blue-brand:  #0B86A0;   /* the one brand blue */
  --blue-deep:   #096E83;   /* darker shade of the same blue — hover-fills, headings */
  --blue-sky:    #7ABDCB;   /* lighter shade — secondary accents, borders */
  --blue-pale:   #E2F1F4;   /* very light tint — wash backgrounds */
  --cream:       #FFFFFF;   /* was eggshell, now plain white */
  --cream-deep:  #F2F2F2;   /* light neutral grey — the only non-blue, non-white panel tint left */
  --cream-line:  #E3E3E3;   /* neutral hairline rules */
  --ink:         #1A1A1A;   /* near-black body text (was warm brown-black, now neutral to match) */
  --ink-soft:    #5C5C5C;   /* secondary text (was warm brown-grey, now neutral) */
  --white:       #FFFFFF;
  --accent-gold: #C4922F;   /* one small warm accent, used sparingly (key-features icons) to break up the blue/white pairing */

  /* Poppins is the live site's actual typeface (pulled from its @font-face
     rules) — used for both display and body, matching officecleaningldn.com
     rather than the earlier heritage-serif direction. */
  --font-display: "Poppins", "Segoe UI", system-ui, sans-serif;
  --font-body: "Poppins", "Segoe UI", system-ui, sans-serif;

  --container: 1180px;
  --radius: 4px;
  --shadow-card: 0 1px 2px rgba(11, 134, 160, 0.08), 0 8px 24px rgba(11, 134, 160, 0.09);
}

* { box-sizing: border-box; }
/* Keeps anchor-link jumps (#services, #faq, #contact, #where-we-work) from
   landing partly hidden under the sticky header. */
section[id] { scroll-margin-top: 110px; }
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; }
}

html, body { overflow-x: hidden; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; }
button { font-family: inherit; }

.container {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 24px;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--ink);
  margin: 0;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--blue-brand);
}
.eyebrow::before {
  content: "";
  width: 22px;
  height: 1px;
  background: var(--blue-brand);
  display: inline-block;
}

.section {
  padding: 96px 0;
}
.section--tight { padding: 64px 0; }
.section--cream-deep { background: var(--cream-deep); }
.section--navy {
  background: var(--blue-brand);
  color: var(--cream);
}
.section--navy h2, .section--navy h3 { color: var(--white); }
.section--navy .eyebrow { color: var(--white); }
.section--navy .eyebrow::before { background: var(--white); }
.section--navy .section-head p { color: rgba(255, 255, 255, 0.78); }
.section--brand {
  background: var(--blue-brand);
  color: var(--white);
}

.section-head {
  max-width: 640px;
  margin-bottom: 48px;
}
.section-head h2 {
  font-size: clamp(28px, 3.4vw, 40px);
  margin-top: 14px;
  line-height: 1.15;
}
.section-head p {
  margin-top: 16px;
  color: var(--ink-soft);
  font-size: 17px;
}

/* Buttons ---------------------------------------------------------------- */
.btn {
  position: relative;
  z-index: 0;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 26px;
  border-radius: var(--radius);
  font-weight: 600;
  font-size: 15px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  overflow: hidden;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.btn:active { transform: translateY(1px); }
/* .btn's own `display: inline-flex` has the same specificity as the
   browser's built-in `[hidden] { display: none }` and is declared later,
   so it silently wins — a button with both a .btn class and the `hidden`
   attribute stays visible. Only matters where JS toggles `hidden` on a
   .btn (the quote wizard's step nav), but worth fixing at the source. */
.btn[hidden] { display: none !important; }
.btn-primary {
  background: var(--blue-brand);
  color: var(--white);
  box-shadow: 0 1px 0 rgba(0,0,0,0.06), 0 10px 24px rgba(11, 134, 160, 0.28);
}
.btn-primary:hover { box-shadow: 0 10px 28px rgba(11, 134, 160, 0.38); }
/* Radial hover-fill (ported from "Origin Button") — a circle grows from
   the cursor's contact point rather than a flat color swap on hover.
   js/script.js writes --origin-x/-y/-r from real pointer position. */
.btn-primary::before {
  content: "";
  position: absolute;
  left: var(--origin-x, 50%);
  top: var(--origin-y, 50%);
  width: calc(var(--origin-r, 100%) * 2);
  height: calc(var(--origin-r, 100%) * 2);
  background: var(--blue-deep);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: -1;
  pointer-events: none;
}
.btn-primary:hover::before,
.btn-primary:focus-visible::before {
  transform: translate(-50%, -50%) scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .btn-primary::before { display: none; }
}
.btn-ghost {
  background: transparent;
  color: var(--blue-deep);
  border-color: var(--cream-line);
}
.btn-ghost:hover { border-color: var(--blue-brand); color: var(--blue-brand); }
.btn-on-navy {
  background: var(--cream);
  color: var(--blue-deep);
  transition: color 0.3s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
/* Same radial hover-fill mechanic as .btn-primary (see js/script.js), just
   with colors flipped so it stays readable on the CTA band's blue
   background: light button at rest, fills to blue-deep with white text
   on hover instead of the reverse. */
.btn-on-navy::before {
  content: "";
  position: absolute;
  left: var(--origin-x, 50%);
  top: var(--origin-y, 50%);
  width: calc(var(--origin-r, 100%) * 2);
  height: calc(var(--origin-r, 100%) * 2);
  background: var(--blue-deep);
  border-radius: 50%;
  transform: translate(-50%, -50%) scale(0);
  transition: transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
  z-index: -1;
  pointer-events: none;
}
.btn-on-navy:hover,
.btn-on-navy:focus-visible {
  color: var(--white);
}
.btn-on-navy:hover::before,
.btn-on-navy:focus-visible::before {
  transform: translate(-50%, -50%) scale(1);
}
@media (prefers-reduced-motion: reduce) {
  .btn-on-navy::before { display: none; }
}
.btn-outline-on-navy {
  background: transparent;
  color: var(--cream);
  border-color: rgba(255, 255, 255, 0.4);
}
.btn-outline-on-navy:hover { border-color: var(--cream); }

/* Header ------------------------------------------------------------------ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--cream);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
/* Scroll state (ported from "Header 3"'s useScroll behavior) — a plain
   opaque background + border/shadow rather than backdrop-filter, since
   backdrop-filter on this element previously broke the mobile nav's
   position:fixed sizing (it creates a containing block for descendants). */
.site-header.is-scrolled {
  border-bottom-color: var(--cream-line);
  box-shadow: 0 1px 0 rgba(9, 110, 131, 0.04), 0 8px 24px -12px rgba(9, 110, 131, 0.12);
}
.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 28px 36px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
}
.brand-word {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 21px;
  color: var(--blue-brand);
  line-height: 1.1;
}
/* Header wordmark: just "OCL" set large, standing in for a logo mark until
   the real logo file is supplied. "Est. 1985" sits beside it (not stacked
   underneath) behind a divider line, like a badge on a logo lockup. */
.brand-word--mark {
  font-size: 66px;
  letter-spacing: -0.01em;
}
.brand-est {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 11px;
  line-height: 1.35;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--blue-brand);
  border-left: 1px solid var(--cream-line);
  padding-left: 12px;
  white-space: nowrap;
}

.main-nav { display: flex; align-items: center; gap: 48px; margin-left: 12px; }
.main-nav ul {
  display: flex;
  align-items: center;
  gap: 46px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.main-nav a.nav-link {
  text-decoration: none;
  color: var(--ink);
  font-size: 15px;
  font-weight: 600;
  position: relative;
  padding: 6px 0;
}
.main-nav a.nav-link::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 2px;
  background: var(--blue-brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.2s ease;
}
.main-nav a.nav-link:hover::after { transform: scaleX(1); }

.has-dropdown { position: relative; }

/* Mega menu (ported from the "Header 3" 21st.dev component): a two-column
   grid of icon + title + description links instead of a plain link list. */
.mega-menu {
  position: absolute;
  top: calc(100% + 14px);
  left: 50%;
  transform: translateX(-50%) translateY(6px);
  width: 520px;
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 10px;
  box-shadow: var(--shadow-card);
  padding: 14px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
}
/* Desktop-only: hover/focus-within is what opens the mega-menu on a mouse.
   On mobile the menu is opened by the JS click handler's .is-open class
   instead (position:static, full width, no transform — see the 980px
   breakpoint below), but tapping "Services" still focuses the link first,
   and this selector's higher specificity (3 classes vs. 2) was winning
   over the mobile layout's `transform: none` regardless of the media
   query, shoving the full-width mobile panel left by half its own width
   for one frame until the tap that actually toggled .is-open landed.
   Scoping this to real desktop widths removes the conflict entirely. */
@media (min-width: 981px) {
.has-dropdown:hover .mega-menu,
.has-dropdown:focus-within .mega-menu {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
}
.mega-menu .mega-menu__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.mega-menu__grid a {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink);
}
.mega-menu__grid a:hover { background: var(--blue-pale); }
.mega-menu__grid a:hover strong { color: var(--blue-brand); }
.mega-menu__grid strong { display: block; font-size: 14px; color: var(--blue-deep); transition: color 0.15s ease; }
.mega-menu__grid small { display: block; font-size: 12px; color: var(--ink-soft); margin-top: 2px; font-weight: 500; }
.mega-menu__icon {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 8px;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
}
.mega-menu__footer {
  border-top: 1px solid var(--cream-line);
  margin-top: 8px;
  padding: 12px 10px 4px;
}
.mega-menu__footer p { margin: 0; font-size: 13px; color: var(--ink-soft); }
.mega-menu__footer a { color: var(--blue-brand); font-weight: 700; text-decoration: none; }
.mega-menu__footer a:hover { text-decoration: underline; }

.header-cta { display: flex; align-items: center; gap: 20px; }
.header-phone {
  display: flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  font-weight: 600;
  font-size: 14.5px;
  color: var(--blue-deep);
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  padding: 6px;
}
.nav-toggle span {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--blue-deep);
  margin: 5px 0;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

/* Hero --------------------------------------------------------------------
   .hero__backdrop is a static fallback wash, painted first. .hero__wave is
   the mount point for the animated WebGL gradient (js/gradient-wave.js) —
   it sits on top of the fallback so there's still a reasonable background
   if WebGL fails to init, and a light scrim keeps hero text legible over
   the moving gradient. */
.hero {
  position: relative;
  overflow: hidden;
  padding-top: 40px;
}
.hero__backdrop {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 80% 60% at 18% -10%, rgba(142,182,220,0.55), transparent 60%),
    radial-gradient(ellipse 70% 50% at 100% 0%, rgba(11, 134, 160,0.18), transparent 60%),
    var(--cream);
}
.hero__wave {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}
.hero__wave::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Was a stronger white wash (0.55/0.12/0.35) on desktop only — the user
     preferred the lighter mobile-only version enough to bring it to
     desktop too. Revert by swapping these three opacity values back to
     0.55 / 0.12 / 0.35 if it doesn't work out on the bigger screen. */
  background: linear-gradient(180deg, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.05) 35%, rgba(255,255,255,0.16) 100%);
  pointer-events: none;
}
/* Soft blue "guard" behind the headline/lede only — the wave keeps animating
   underneath and shows through, but this caps how light it can read right
   behind the white text so it never washes out to white there, without
   touching the animation anywhere else in the hero (image side included). */
.hero__text-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 62% 80% at 25% 48%, rgba(9, 110, 131, 0.72) 0%, rgba(9, 110, 131, 0.46) 45%, transparent 78%);
}
.hero__inner {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 48px;
  align-items: center;
  padding: 28px 24px 48px;
}
/* Grid items default to min-width:auto, which stops this column from
   shrinking below the headline's unwrapped text width — without this it
   silently overflows the viewport on narrow screens instead of wrapping. */
.hero__copy { min-width: 0; }
.hero__crest-line {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 24px;
}
.hero__crest-line .rule { width: 40px; height: 1px; background: var(--white); }
.hero__crest-line span {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--white);
}
.hero h1 {
  font-size: clamp(38px, 5.4vw, 62px);
  line-height: 1.04;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--white);
}
.hero h1 em {
  font-style: normal;
  color: var(--white);
}
.hero__lede {
  margin-top: 22px;
  font-size: 19px;
  color: rgba(255,255,255,0.78);
  max-width: 46ch;
}
.hero__ctas {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: 30px;
  flex-wrap: wrap;
}
.hero__link {
  text-decoration: none;
  font-weight: 600;
  color: var(--white);
  border-bottom: 1px solid rgba(255,255,255,0.45);
  padding-bottom: 2px;
}
/* White/blue to match the CTA band's light button (.btn-on-navy) instead
   of the site-wide solid blue — was mobile-only at first, now applied at
   every width since the user preferred it there too. Also a punchier
   hover for this button specifically: a small pop in scale plus a bigger
   shadow lift, and the radial fill sped up with a slight overshoot
   ("back out") easing instead of the site-wide button's plain ease-out,
   so the moment of hovering reads as a bigger, more satisfying change. */
.hero__ctas .btn-primary {
  background: var(--white);
  color: var(--blue-brand);
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.25s ease, color 0.15s ease;
}
.hero__ctas .btn-primary::before {
  background: var(--blue-brand);
  transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.hero__ctas .btn-primary:hover,
.hero__ctas .btn-primary:focus-visible {
  transform: scale(1.05);
  box-shadow: 0 14px 32px rgba(11, 134, 160, 0.45);
  color: var(--white);
}

.hero__imagebox {
  position: relative;
  justify-self: end;
  align-self: center;
  width: 90%;
  margin-top: -22px;
  aspect-ratio: 4 / 3.4;
  border-radius: 10px;
  overflow: hidden;
  background: rgba(255, 253, 248, 0.55);
  border: 1.5px dashed rgba(9, 110, 131, 0.28);
  box-shadow: var(--shadow-card);
  backdrop-filter: blur(2px);
}
.hero__imagebox img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* A real photo in the box: same size and shape as the original placeholder
   (4:3.4, 90% of the column); the picture is made to the same shape, so
   nothing is cropped. No dashed placeholder frame or frosted fill. */
.hero__imagebox--photo { border: 0; background: none; backdrop-filter: none; }
.hero__imagebox-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--blue-deep);
}
.hero__imagebox-placeholder span {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--ink-soft);
}

/* Mobile-only three-card image fan (ported from "Hero 10") — an
   alternative to .hero__imagebox above, hidden here and switched on only
   inside the mobile media query below. */
.hero__fan { display: none; }

/* Key features strip -------------------------------------------------------*/
.features-strip {
  background: var(--blue-brand);
}
.features-strip .container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
}
.feature-item {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  padding: 26px 20px;
}
.feature-item + .feature-item { border-left: 1px solid rgba(255,255,255,0.22); }
.feature-item svg { flex-shrink: 0; color: var(--white); }
.feature-item h4 { font-family: var(--font-body); font-size: 15px; color: var(--white); font-weight: 700; }
.feature-item p { margin: 2px 0 0; font-size: 13.5px; color: rgba(255,255,255,0.78); }

/* Services --------------------------------------------------------------
   Bordered hover grid (ported from the "Features Section With Hover
   Effects" 21st.dev component): a spreadsheet-style grid where each cell
   grows a blue accent bar and nudges its title on hover, with a soft
   directional glow that reads as coming from the row's outer edge. */
.services-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--cream-line);
  border-left: 1px solid var(--cream-line);
}
.service-card {
  position: relative;
  overflow: hidden;
  background: var(--white);
  border-right: 1px solid var(--cream-line);
  border-bottom: 1px solid var(--cream-line);
  padding: 40px 32px;
  text-decoration: none;
  display: block;
}
.service-card::after {
  content: "";
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
  background: linear-gradient(to top, var(--blue-pale), transparent);
}
.service-card:nth-child(n+4)::after {
  background: linear-gradient(to bottom, var(--blue-pale), transparent);
}
.service-card:hover::after { opacity: 1; }
.service-card__accent {
  position: absolute;
  left: 0;
  top: 40px;
  height: 24px;
  width: 4px;
  border-radius: 0 4px 4px 0;
  background: var(--cream-line);
  transition: height 0.2s ease, background 0.2s ease;
}
.service-card:hover .service-card__accent {
  height: 32px;
  background: var(--blue-brand);
}
.service-card__icon {
  position: relative;
  z-index: 1;
  display: inline-flex;
  color: var(--blue-brand);
  margin-bottom: 4px;
}
.service-card h3 {
  position: relative;
  z-index: 1;
  font-size: 20px;
  margin-top: 18px;
  transition: transform 0.2s ease;
}
.service-card:hover h3 { transform: translateX(6px); }
.service-card p {
  position: relative;
  z-index: 1;
  margin-top: 12px;
  font-size: 15px;
  color: var(--ink-soft);
  max-width: 30ch;
}
.service-card a.card-link {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: 18px;
  font-size: 14px;
  font-weight: 700;
  color: var(--blue-brand);
  text-decoration: none;
}
.section-head-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 24px;
  margin-bottom: 48px;
}
.section-head-row .section-head { margin-bottom: 0; }

/* Why choose us ---------------------------------------------------------- */
.why-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px 32px;
}
/* End of Tenancy's "why it matters" is the only .why-grid on the site with
   exactly 4 items (every other page has 6, or the other 3 one-off pages'
   3) — at the shared 3-column default, a 4th item just orphans alone on
   its own row instead of filling a clean grid. Scoped to this one
   section/page via its #why-it-matters id, matching the section's own
   content rather than changing the shared component everyone else uses. */
#why-it-matters .why-grid { grid-template-columns: repeat(2, 1fr); }
.why-item { display: flex; gap: 16px; }
.why-item .icon {
  flex-shrink: 0;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255, 255, 255,0.25);
  display: flex; align-items: center; justify-content: center;
  color: var(--cream);
}
/* .why-item's icon is translucent-on-dark by design (see .why-item .icon
   above) — it was never meant for a light background, so this text-color
   override belongs on any dark/blue section it's used in, not just
   .section--navy specifically. .section--brand renders the identical blue
   (both resolve to var(--blue-brand)), so widening this costs nothing on
   every other page — they only ever pair .why-grid with .section--navy. */
.section--navy .why-item h4, .section--brand .why-item h4 { color: var(--white); font-family: var(--font-display); font-size: 18px; }
.section--navy .why-item p, .section--brand .why-item p { color: rgba(255, 255, 255,0.72); font-size: 14.5px; margin-top: 6px; }

/* Heritage / story teaser -------------------------------------------------*/
.heritage {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 48px;
  align-items: stretch;
}
.heritage__art {
  position: relative;
  border-radius: 6px;
  overflow: hidden;
  background: rgba(255, 253, 248, 0.55);
  border: 1.5px dashed rgba(255, 255, 255, 0.5);
  backdrop-filter: blur(2px);
}
.heritage__art img { width: 100%; height: 100%; object-fit: cover; }
/* A real photo in the slot: no dashed "placeholder" frame or frosted fill,
   the image fills the box (which stretches to the text column beside it),
   and a minimum height keeps it visible when the layout stacks on tablet. */
.heritage__art--photo { border: 0; background: none; backdrop-filter: none; box-shadow: var(--shadow-card); min-height: 320px; }
.heritage__art--photo img { position: absolute; inset: 0; object-position: center 40%; }
.heritage__art-placeholder {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  color: var(--blue-deep);
}
.heritage__art-placeholder span { font-size: 13.5px; font-weight: 600; color: var(--ink-soft); }
/* Section sits on the solid brand-blue background (.section--brand), so its
   own text needs light-on-blue overrides — the badge card stays light (a
   "seal" resting on the blue band) since it's a self-contained element. */
.heritage .eyebrow { color: var(--white); }
.heritage .eyebrow::before { background: var(--white); }
.heritage h2 { font-size: clamp(28px, 3.2vw, 38px); line-height: 1.15; margin-top: 10px; color: var(--white); }
.heritage p { margin-top: 14px; color: rgba(255,255,255,0.82); font-size: 16.5px; max-width: 54ch; }
/* Stats sit in their own panel rather than loose on the section background
   — otherwise they read as a continuation of the paragraph above rather
   than as distinct figures. A CSS grid (not flex+gap) gives each stat an
   equal-width slot regardless of how long its number/label text is, so
   they land evenly spaced instead of drifting off-center. */
.heritage__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin-top: 22px;
  padding: 20px 8px;
  background: rgba(0, 0, 0, 0.18);
  border-radius: var(--radius);
}
.heritage__stats div {
  position: relative;
  text-align: center;
  padding: 0 12px;
}
.heritage__stats div + div::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 4px;
  width: 1px;
  background: rgba(255, 255, 255, 0.22);
}
.heritage__stats div strong {
  display: block;
  font-family: var(--font-display);
  font-size: 32px;
  color: var(--white);
}
.heritage__stats div span {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: rgba(255,255,255,0.72);
  font-weight: 600;
}
.heritage .btn-ghost { color: var(--white); border-color: rgba(255,255,255,0.4); }
.heritage .btn-ghost:hover { color: var(--white); border-color: var(--white); }

/* CTA band ----------------------------------------------------------------
   Full-bleed (.section--brand provides the blue background) rather than a
   floating card, so it reads as a distinct band in the page's color rhythm
   instead of a small blue chip sitting inside another cream section. */
.cta-band {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
  flex-wrap: wrap;
}
.cta-band h2 { color: var(--white); font-size: clamp(24px, 3vw, 32px); max-width: 20ch; }
.cta-band p { margin-top: 10px; color: rgba(255,255,255,0.82); font-size: 15.5px; }

/* FAQ ---------------------------------------------------------------------*/
.faq-list { max-width: 780px; margin: 0 auto; }
.faq-item {
  border-bottom: 1px solid var(--cream-line);
  padding: 22px 0;
}
.faq-item summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  font-family: var(--font-display);
  font-size: 19px;
  color: var(--ink);
  font-weight: 500;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary .plus {
  flex-shrink: 0;
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 1px solid var(--blue-sky);
  position: relative;
}
.faq-item summary .plus::before, .faq-item summary .plus::after {
  content: "";
  position: absolute;
  background: var(--blue-brand);
  top: 50%; left: 50%;
  transform: translate(-50%, -50%);
}
.faq-item summary .plus::before { width: 10px; height: 1.5px; }
.faq-item summary .plus::after { width: 1.5px; height: 10px; transition: transform 0.2s ease; }
.faq-item[open] summary .plus::after { transform: translate(-50%, -50%) scaleY(0); }
.faq-item p {
  margin: 16px 0 0;
  color: var(--ink-soft);
  font-size: 15.5px;
  max-width: 62ch;
  line-height: 1.7;
}
/* Letter-by-letter blur reveal (ported from "Text Reveal FAQs") — js/script.js
   rebuilds the answer into one <span> per character on each open, each with
   a staggered animation-delay, so this keyframe plays across the sentence.
   .faq-letter needs inline-block for the blur/opacity animation, but
   adjacent inline-block boxes are independently breakable — without
   .faq-word wrapping each one, the browser can (and did) wrap a line
   between any two letters, including mid-word. white-space: nowrap here
   keeps a word's letters together; the real space between .faq-word spans
   is still a normal, breakable word boundary. */
.faq-word { display: inline-block; white-space: nowrap; }
.faq-letter {
  display: inline-block;
  opacity: 0;
  filter: blur(10px);
  animation: faq-letter-in 0.3s ease forwards;
}
@keyframes faq-letter-in {
  to { opacity: 1; filter: blur(0); }
}

/* Testimonials ------------------------------------------------------------
   Auto-scrolling columns (ported from the "Testimonials Columns" 21st.dev
   component): each column's track is the card list duplicated once, drifting
   upward on a seamless loop (translateY 0 -> -50%) at its own speed. A mask
   fades the top/bottom edges so cards scroll in and out smoothly. */
.testimonials-columns {
  display: flex;
  justify-content: center;
  gap: 22px;
  margin-top: 8px;
  max-height: 521px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 12%, black 88%, transparent);
  mask-image: linear-gradient(to bottom, transparent, black 12%, black 88%, transparent);
}
.testimonials-col { flex: 1 1 0; min-width: 0; max-width: 380px; }
.testimonials-col__track {
  display: flex;
  flex-direction: column;
  gap: 20px;
  animation: testimonials-scroll var(--duration, 18s) linear infinite;
}
@keyframes testimonials-scroll {
  from { transform: translateY(0); }
  to { transform: translateY(-50%); }
}
.t-card {
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 14px;
  padding: 26px;
  box-shadow: var(--shadow-card);
}
/* Deliberately reads as a placeholder, not a real review — dashed border,
   muted text, neutral avatar mark instead of colored initials. */
.testimonials-col .t-card { padding: 22px; }
.t-card--placeholder {
  box-shadow: none;
  border-style: dashed;
  border-color: var(--cream-line);
}
.t-card--placeholder p { color: var(--ink-soft); font-style: italic; }
.t-card--placeholder .t-card__avatar { background: var(--cream-deep); color: var(--ink-soft); }
.t-card--placeholder .t-card__who strong { color: var(--ink-soft); font-weight: 600; }
.t-card p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.65;
  color: var(--ink);
}
.t-card__who {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
}
.t-card__avatar {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--blue-brand);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  font-family: var(--font-display);
}
.t-card__who strong { display: block; font-size: 13.5px; color: var(--ink); }
.t-card__who small { display: block; font-size: 12px; color: var(--ink-soft); font-weight: 500; margin-top: 1px; }

/* Where we work — interactive map (ported from "Mapcn Marker Label",
   MapLibre GL loaded via CDN in index.html <head>/before js/script.js).
   .map-pin / .maplibregl-popup are unscoped element/library classes coming
   from the map library itself, styled here to match the brand. */
.map-layout {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 24px;
  align-items: stretch;
  margin-top: 32px;
}
.map-card {
  display: flex;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--cream-line);
  box-shadow: var(--shadow-card);
}
.map-card__map {
  height: 100%;
  min-height: 430px;
  width: 100%;
  background: var(--cream-deep);
}
/* Area list — grouped by zone with filter tabs (see js/where-we-work-map.js).
   Choosing a tab dims the other zones (no layout change, so the section
   never jumps) and zooms the map to it. Chips are white cards, so the same
   panel reads on both the white and the blue "Where we work" sections. */
.areas-panel { display: flex; flex-direction: column; gap: 10px; min-width: 0; }
.areas-tabs { display: flex; flex-wrap: wrap; gap: 6px; }
.areas-tabs button {
  font: inherit; font-size: 12.5px; font-weight: 700; cursor: pointer;
  padding: 7px 13px; border-radius: 999px; line-height: 1.2;
  border: 1px solid var(--cream-line); background: var(--white); color: var(--blue-deep);
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.areas-tabs button:hover { border-color: var(--blue-brand); }
.areas-tabs button.is-active { background: var(--blue-brand); border-color: var(--blue-brand); color: var(--white); }
.section--navy .areas-tabs button { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.35); color: var(--white); }
.section--navy .areas-tabs button.is-active { background: var(--white); border-color: var(--white); color: var(--blue-deep); }
.areas-zone { transition: opacity 0.25s ease; }
.areas-zone h4 {
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--blue-deep); margin: 0 0 8px; display: flex; align-items: center; gap: 10px;
}
.areas-zone h4::after { content: ""; flex: 1; height: 1px; background: var(--cream-line); }
.section--navy .areas-zone h4 { color: rgba(255, 255, 255, 0.85); }
.section--navy .areas-zone h4::after { background: rgba(255, 255, 255, 0.25); }
.areas-panel[data-focus="west"] .areas-zone:not([data-zone="west"]),
.areas-panel[data-focus="city"] .areas-zone:not([data-zone="city"]),
.areas-panel[data-focus="south"] .areas-zone:not([data-zone="south"]) { opacity: 0.3; }
.areas-grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
.areas-grid li { display: block; min-width: 0; }
.areas-grid a, .areas-grid .is-soon {
  display: flex; align-items: center; gap: 7px; height: 100%; min-height: 30px;
  border: 1px solid var(--cream-line); background: var(--white); border-radius: 8px;
  padding: 5px 10px; font-size: 12.5px; font-weight: 600; line-height: 1.2;
  color: var(--ink); text-decoration: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.areas-grid a::before, .areas-grid .is-soon::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--blue-brand); flex-shrink: 0;
}
.areas-grid a:hover, .areas-grid a.is-active, .areas-grid .is-soon.is-active { background: var(--blue-pale); border-color: var(--blue-brand); }
.areas-grid .is-soon { border-style: dashed; color: var(--ink-soft); background: rgba(255, 255, 255, 0.7); }
.areas-grid .is-soon::before { background: transparent; border: 1.5px solid var(--blue-brand); box-sizing: border-box; }
.areas-grid .is-soon em { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
.areas-legend { display: flex; align-items: center; gap: 8px; margin: 0; font-size: 12px; color: var(--ink-soft); }
.areas-legend i { width: 9px; height: 9px; border-radius: 50%; background: var(--blue-brand); display: inline-block; }
.areas-legend i.is-soon { background: transparent; border: 1.5px solid var(--blue-brand); box-sizing: border-box; margin-left: 10px; }
.section--navy .areas-legend { color: rgba(255, 255, 255, 0.85); }
.section--navy .areas-legend i { background: var(--white); }
.section--navy .areas-legend i.is-soon { background: transparent; border-color: var(--white); }
/* Map pins — small dots (solid = live, hollow = coming soon) */
.map-pin {
  width: 13px; height: 13px; border-radius: 50%; padding: 0; cursor: pointer;
  background: var(--blue-brand); border: 2px solid var(--white);
  box-shadow: 0 1px 4px rgba(9, 110, 131, 0.5);
  transition: transform 0.15s ease, background 0.15s ease, opacity 0.25s ease;
}
.map-pin--soon { background: var(--white); border-color: var(--blue-brand); }
.map-pin.is-dim { opacity: 0.22; }
.map-pin:hover, .map-pin:focus-visible { transform: scale(1.5); background: var(--blue-deep); outline: none; }
.map-pin--soon:hover, .map-pin--soon:focus-visible { background: var(--blue-pale); }
.map-popup__link { display: inline-block; margin-top: 6px; font-size: 12px; font-weight: 700; color: var(--blue-brand); text-decoration: none; }
.maplibregl-popup-content {
  font-family: var(--font-body);
  padding: 10px 14px;
  border-radius: 8px;
  box-shadow: var(--shadow-card);
}
.maplibregl-popup-content strong { display: block; font-size: 13.5px; color: var(--blue-deep); }
.maplibregl-popup-content span { display: block; font-size: 12px; color: var(--ink-soft); margin-top: 1px; }
.maplibregl-popup-tip { border-top-color: var(--white) !important; }

/* Get in touch ------------------------------------------------------------
   Ported from the "Contact Card" 21st.dev component: a two-panel card
   (info + form) with plus-mark corners for a blueprint/dev-tool feel.
   Note: the form has no backend wired up yet — script.js intercepts submit
   and shows a confirmation message, but nothing is actually sent anywhere
   until a real endpoint (e.g. Formspree, a serverless function) is added. */
.contact-card {
  position: relative;
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  background: var(--white);
  border: 1px solid var(--cream-line);
  box-shadow: var(--shadow-card);
}
.contact-card__info { padding: 48px; }
.contact-card__info h2 { margin-top: 12px; font-size: clamp(28px, 3.2vw, 38px); }
.contact-card__info > p { margin-top: 16px; color: var(--ink-soft); font-size: 16px; max-width: 44ch; }

.contact-card__chips {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-top: 32px;
}
.contact-chip { display: flex; align-items: center; gap: 12px; }
.contact-chip--wide { grid-column: 1 / -1; }
.contact-chip__icon {
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  border-radius: 10px;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
}
.contact-chip strong { display: block; font-size: 14px; color: var(--ink); }
.contact-chip > div span { display: block; font-size: 13.5px; color: var(--ink-soft); margin-top: 1px; }

.contact-card__form-panel {
  background: var(--cream-deep);
  border-left: 1px solid var(--cream-line);
  padding: 40px;
  display: flex;
  align-items: center;
}
.contact-form { width: 100%; display: flex; flex-direction: column; gap: 16px; }
.contact-form__field { display: flex; flex-direction: column; gap: 6px; }
.contact-form__field label { font-size: 13px; font-weight: 600; color: var(--ink); }
.contact-form__field input,
.contact-form__field select,
.contact-form__field textarea {
  font-family: var(--font-body);
  font-size: 14.5px;
  padding: 11px 13px;
  border: 1px solid var(--cream-line);
  border-radius: 4px;
  background: var(--white);
  color: var(--ink);
  resize: vertical;
}
.contact-form__field select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235C5C5C' stroke-width='2'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 16px;
  padding-right: 36px;
}
.contact-form__field input:focus,
.contact-form__field select:focus,
.contact-form__field textarea:focus {
  outline: none;
  border-color: var(--blue-brand);
  box-shadow: 0 0 0 3px rgba(11, 134, 160, 0.15);
}
.contact-form__note {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--blue-brand);
  text-align: center;
}

/* Contact page hero — single centered column (no wizard/feature-grid beside
   it, unlike the other .service-hero pages), with a row of quick-reach
   pills replacing the usual CTA buttons. Scoped by ID same way #quote-hero
   is, so it doesn't affect the shared .service-hero rules elsewhere. */
#contact-hero .service-hero__inner {
  grid-template-columns: 1fr;
  max-width: 720px;
  margin: 0 auto;
  text-align: center;
}
#contact-hero .service-hero__copy p { margin-left: auto; margin-right: auto; }
.hero-reach {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin-top: 32px;
  flex-wrap: wrap;
}
.hero-reach__item {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 12px 20px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.25);
  color: var(--white);
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.hero-reach__item:hover { background: rgba(255, 255, 255, 0.16); border-color: rgba(255, 255, 255, 0.4); }
.hero-reach__item svg { flex-shrink: 0; }

/* Contact page — "Who You'll Reach" team grid. Avatar placeholder reuses
   the same dashed-border "photo not yet supplied" language as
   .heritage__art-placeholder, just circular and sized for a headshot. */
.team-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.team-card {
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 6px;
  padding: 36px 28px;
  text-align: center;
  box-shadow: var(--shadow-card);
}
.team-card__avatar {
  width: 84px;
  height: 84px;
  margin: 0 auto 18px;
  border-radius: 50%;
  border: 1.5px dashed var(--blue-sky);
  background: var(--blue-pale);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--blue-brand);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 22px;
}
.team-card h3 { font-size: 19px; margin: 0; }
.team-card__role {
  display: block;
  color: var(--blue-brand);
  font-weight: 600;
  font-size: 12.5px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 4px;
}
.team-card p { margin-top: 14px; color: var(--ink-soft); font-size: 14px; line-height: 1.6; }
.team-card__contact {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--cream-line);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.team-card__contact a { font-size: 13.5px; color: var(--blue-deep); font-weight: 600; }
.team-card__contact a:hover { text-decoration: underline; }

/* Our Story hero — distinct from the site's other 3 hero treatments
   (homepage/get-a-quote's gradient-wave, the service pages' flowing
   background-paths, the location pages' topo-lines): no animated backdrop
   at all, just an oversized ghost numeral of the founding year bleeding
   off the edge. A quieter, more editorial "heritage" device that fits a
   history page better than another generative background, and ties back
   to the "Est. 1985" heritage direction set for this rebuild from the
   start. Scoped by ID same way #quote-hero/#contact-hero are. */
#story-hero { overflow: hidden; }
/* Two columns like every other .service-hero page (copy left, a visual
   right) rather than the earlier single centered column — a lone
   left-aligned text block floating in a much wider section read as
   unbalanced/accidental rather than composed, and there was nowhere for a
   photo to go. The ghost year numeral stays, but now sits behind the photo
   box specifically (both are children of the same z-index:1 stacking
   context, so the box wins) — like a print laid over an old ledger page,
   rather than floating in otherwise-empty space. */
.story-hero__art { min-height: 320px; }
.story-hero__year {
  position: absolute;
  right: -0.05em;
  top: 50%;
  transform: translateY(-46%);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(160px, 22vw, 380px);
  line-height: 1;
  letter-spacing: -0.02em;
  color: rgba(255, 255, 255, 0.09);
  pointer-events: none;
  user-select: none;
  z-index: 0;
  white-space: nowrap;
}
#story-hero .heritage__stats { margin-top: 30px; max-width: 460px; margin-left: 0; }

/* .section--brand only sets `color` on the section itself — it has no
   blanket heading override the way .section--navy does. Left alone, any
   .section-head placed directly on a .section--brand background falls
   back to the global h1-h4 { color: var(--ink) } and
   .eyebrow { color: var(--blue-brand) } rules, both illegible on top of
   the same blue. First hit on Our Story's #journey timeline (originally
   patched with an ID-scoped fix there), then again on the after-build
   one-off page — recurring enough to fix once at the component level
   instead of re-patching per page. Safe to apply generally: the one place
   a black h2 legitimately sits on a .section--brand background is
   .contact-card (a white card floating on the blue section), and that
   heading lives in .contact-card__info, never inside .section-head. */
.section--brand .section-head .eyebrow { color: rgba(255, 255, 255, 0.85); }
.section--brand .section-head .eyebrow::before { background: rgba(255, 255, 255, 0.85); }
.section--brand .section-head h2 { color: var(--white); }

/* Our Story — vertical milestone timeline, structurally referenced from
   21st.dev's "Timeline-02" (a left dot-rail with a card per milestone),
   ported to vanilla HTML/CSS and given a light-on-blue treatment since it
   sits on .section--brand rather than a plain card background. */
.story-timeline { position: relative; max-width: 720px; margin: 0 auto; }
.story-timeline__rail {
  position: absolute;
  left: 15px;
  top: 8px;
  bottom: 8px;
  width: 1px;
  background: rgba(255, 255, 255, 0.22);
}
.story-timeline__item { position: relative; padding-left: 48px; }
.story-timeline__item + .story-timeline__item { margin-top: 32px; }
.story-timeline__dot {
  position: absolute;
  left: 8px;
  top: 6px;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: var(--white);
  box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.18);
}
.story-timeline__era {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.65);
}
.story-timeline__card {
  margin-top: 6px;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 6px;
  padding: 20px 22px;
}
.story-timeline__card h3 { color: var(--white); font-size: 18px; margin: 0; }
.story-timeline__card p { margin-top: 8px; color: rgba(255, 255, 255, 0.78); font-size: 14.5px; line-height: 1.6; }

/* Our Story — "What Hasn't Changed" strip. Deliberately not .why-item
   (that component's icon/text colors assume a dark section background) —
   this sits on white, so it gets its own light-context icon badge in the
   same rounded-square blue-pale language as .service-hero__feature-icon. */
.stayed-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 32px; }
.stayed-item .icon {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
}
.stayed-item h4 { font-family: var(--font-display); font-size: 16px; margin: 0; }
.stayed-item p { margin-top: 6px; font-size: 13.5px; color: var(--ink-soft); line-height: 1.55; }

/* Blog — there's no real photography for posts yet (same placeholder gap
   as everywhere else on the site), so rather than a photo-grid blog layout
   with a "coming soon" box on every card, this leans on typography and the
   site's existing icon-badge language instead: a featured-post band, then
   a plain grid of icon-led cards below it. Structurally referenced from
   21st.dev's "Blog Posts" (a big primary post beside smaller secondary
   ones) but rebuilt without its photo-background cards, which this site
   can't support yet. (An earlier pass added a giant faint "BLOG" watermark
   behind the featured card, matching Our Story's "1985" treatment —
   removed per request, so this section is just plain white now.) */
.blog-featured {
  display: grid;
  grid-template-columns: 0.55fr 1.45fr;
  gap: 40px;
  align-items: center;
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 8px;
  padding: 44px;
  box-shadow: var(--shadow-card);
  margin-bottom: 32px;
}
.blog-featured__icon {
  width: 84px;
  height: 84px;
  border-radius: 18px;
  background: var(--blue-brand);
  color: var(--white);
  display: flex;
  align-items: center;
  justify-content: center;
}
.blog-featured__category {
  display: inline-block;
  margin-top: 20px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--blue-brand);
  background: var(--blue-pale);
  padding: 4px 12px;
  border-radius: 999px;
}
.blog-featured h2 { font-size: clamp(24px, 2.6vw, 32px); line-height: 1.2; margin-top: 14px; }
.blog-featured p { margin-top: 12px; color: var(--ink-soft); font-size: 15.5px; max-width: 58ch; }
.blog-featured__meta {
  display: block;
  margin-top: 18px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-soft);
}

.blog-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
/* Blog card — ported from 21st.dev's "Glass Blog Card" (React/shadcn/
   framer-motion; rebuilt here in plain HTML/CSS, same as every other
   21st.dev component on this site). Recoloured from its dark-glass/black
   default theme to the site's own white-card/blue-accent language — same
   shape (image up top with tags floating over it, a hover zoom + "Read
   Article" reveal, title/excerpt, then an author+meta footer under a
   divider), just matched to how every other card on this site already
   looks instead of a glassmorphic dark panel. The avatar stays the site's
   established initials-circle rather than a stock headshot — there's no
   real photo of Mike to use yet, and a fake one would be worse than none
   (see Important Notes on the testimonials in the same position). */
.blog-card {
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}
.blog-card:hover {
  transform: translateY(-4px);
  border-color: var(--blue-sky);
  box-shadow: 0 24px 44px -24px rgba(11, 134, 160, 0.35);
}
.blog-card__media { position: relative; aspect-ratio: 16 / 9; overflow: hidden; background: var(--blue-pale); }
.blog-card__media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.5s ease; }
.blog-card:hover .blog-card__media img { transform: scale(1.08); }
.blog-card__tags { position: absolute; left: 12px; bottom: 12px; z-index: 2; display: flex; gap: 6px; }
.blog-card__tag {
  padding: 5px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--blue-deep);
}
.blog-card__hover {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(9, 110, 131, 0.55);
  opacity: 0;
  transition: opacity 0.25s ease;
}
.blog-card:hover .blog-card__hover { opacity: 1; }
.blog-card__read-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 11px 22px;
  border-radius: 999px;
  background: var(--white);
  color: var(--blue-deep);
  font-weight: 700;
  font-size: 14px;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.22);
  transform: translateY(8px);
  transition: transform 0.25s ease;
}
.blog-card:hover .blog-card__read-btn { transform: translateY(0); }
.blog-card__body { padding: 22px; display: flex; flex-direction: column; gap: 10px; flex-grow: 1; }
.blog-card__body h3 { font-size: 18px; line-height: 1.32; }
.blog-card__body p {
  margin: 0;
  color: var(--ink-soft);
  font-size: 13.5px;
  line-height: 1.6;
  flex-grow: 1;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.blog-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 6px;
  padding-top: 16px;
  border-top: 1px solid var(--cream-line);
}
.blog-card__author { display: flex; align-items: center; gap: 10px; min-width: 0; }
.blog-card__avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 13px;
  flex-shrink: 0;
}
.blog-card__author-meta { display: flex; flex-direction: column; font-size: 11.5px; line-height: 1.35; min-width: 0; }
.blog-card__author-meta strong { color: var(--ink); font-size: 12.5px; font-weight: 700; }
.blog-card__author-meta span { color: var(--ink-soft); }
.blog-card__readtime { display: flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--ink-soft); font-weight: 600; flex-shrink: 0; }

/* Blog hero — trial of 21st.dev's "Aurora Background" (pasted in as a
   React/Tailwind/framer-motion component; this project has none of those,
   so the technique is ported straight to CSS instead of installed).
   The original renders on a near-white ground with dark text — but every
   hero on this site is solid brand-blue with white text, and this one
   sits directly above a white section, so swapping to a light hero would
   put two white-family sections back to back and break the alternation
   rule the rest of the site holds to. Same blurred, animated,
   repeating-gradient streak technique, recolored to drift across the
   existing blue instead of replacing it. .service-hero__paths (the
   flowing-lines mount) is simply not present on this page while trying
   this — nothing to hide. */
.aurora-hero { isolation: isolate; }
.aurora-hero::before,
.aurora-hero::after {
  content: "";
  position: absolute;
  inset: -15%;
  z-index: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(100deg, rgba(255, 255, 255, 0.4) 0%, rgba(255, 255, 255, 0.4) 6%, transparent 10%, transparent 14%, rgba(255, 255, 255, 0.4) 18%),
    repeating-linear-gradient(100deg, var(--blue-sky) 8%, var(--blue-pale) 16%, var(--blue-brand) 24%, var(--blue-deep) 32%, var(--blue-sky) 40%);
  background-size: 300% 200%, 200% 100%;
  filter: blur(28px);
  opacity: 0.5;
  mix-blend-mode: soft-light;
  animation: aurora-drift 45s linear infinite;
}
.aurora-hero::after { animation-duration: 60s; animation-direction: reverse; opacity: 0.3; filter: blur(38px); }
@keyframes aurora-drift {
  from { background-position: 0% 50%, 0% 50%; }
  to { background-position: 300% 50%, 300% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .aurora-hero::before, .aurora-hero::after { animation: none; }
}

/* Newsletter card — ported from the 21st.dev "Newsletter 2" component,
   recolored from its neutral/black shadcn theme to the brand palette
   (cream-deep card, blue primary button) rather than copied as-is. Copy
   (eyebrow, heading, description) on one side, the signup form on the
   other — stacked on mobile, side by side from tablet up. One shared
   component used everywhere on the site. */
/* .section--tight's default 64px top padding read as a huge dead gap
   above this specific card — cut to a quarter (16px) here, on the section
   itself rather than the card, so the section-to-section rhythm elsewhere
   on the page is untouched. */
.newsletter { padding-top: 16px; padding-bottom: 16px; }
.newsletter-card {
  /* No max-width — the 1024px cap it had made it noticeably narrower than
     .contact-card and every other full-bleed box on the page (which just
     fill .container's 1180px), so it read as a cramped funnel next to them
     when scrolling past. Filling the container like they do matches it up. */
  background: var(--cream-deep);
  border-radius: var(--radius);
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 32px;
}
.newsletter-card__copy { display: flex; flex-direction: column; gap: 10px; }
.newsletter-card__copy h2 { font-size: clamp(24px, 2.6vw, 30px); line-height: 1.2; font-weight: 800; letter-spacing: -0.01em; margin: 0; }
.newsletter-card__copy p { margin: 0; color: var(--ink-soft); font-size: 14px; line-height: 1.5; }
@media (min-width: 761px) {
  .newsletter-card { flex-direction: row; align-items: center; justify-content: space-between; gap: 64px; padding: 48px; }
  .newsletter-card__copy { max-width: 384px; }
}

.newsletter__signup { display: flex; flex-direction: column; gap: 12px; max-width: 448px; width: 100%; }
.newsletter__form { display: flex; gap: 8px; }
.newsletter__form input {
  flex: 1;
  min-width: 0;
  height: 48px;
  font-family: var(--font-body);
  font-size: 14px;
  padding: 0 16px;
  border: 1.5px solid var(--cream-line);
  border-radius: var(--radius);
  background: var(--white);
  color: var(--ink);
}
.newsletter__form input:focus {
  outline: none;
  border-color: var(--blue-brand);
  box-shadow: 0 0 0 3px rgba(11, 134, 160, 0.15);
}
.newsletter__form .btn-primary { flex-shrink: 0; height: 48px; padding: 0 20px; }
.newsletter__form .btn-primary svg { flex-shrink: 0; }
.newsletter__consent {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 13.5px;
  color: var(--ink-soft);
  cursor: pointer;
}
.newsletter__consent input {
  width: 16px;
  height: 16px;
  accent-color: var(--blue-brand);
  flex-shrink: 0;
}
.newsletter__privacy {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--ink-soft);
  margin-top: -6px;
}
.newsletter__privacy svg { flex-shrink: 0; color: var(--ink-soft); }
.newsletter__note {
  margin: 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--blue-brand);
}

/* 404 page (ported from "Not Found 2", recolored to the brand palette
   instead of its original dark theme) -------------------------------- */
.not-found {
  min-height: 62vh;
  display: flex;
  align-items: center;
  background: var(--cream);
}
.not-found__inner {
  max-width: 640px;
  text-align: center;
  margin: 0 auto;
  padding: 64px 24px;
}
.not-found__code {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(110px, 22vw, 200px);
  line-height: 1;
  color: var(--blue-brand);
  -webkit-mask-image: linear-gradient(to bottom, transparent, black 20%, black 80%, transparent);
  mask-image: linear-gradient(to bottom, transparent, black 20%, black 80%, transparent);
}
.not-found__title {
  margin-top: -8px;
  font-size: clamp(24px, 3vw, 32px);
}
.not-found__lede {
  margin-top: 16px;
  color: var(--ink-soft);
  font-size: 17px;
}
.not-found__ctas {
  margin-top: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* Service detail pages (services/<slug>/index.html) --------------------
   Self-contained block so nothing here touches the homepage. Shared by all
   six service pages once they're batched out from the office-cleaning
   template — keep any future edits here generic, not office-cleaning
   specific. */
.service-hero {
  position: relative;
  overflow: hidden;
  background: var(--blue-brand);
  color: var(--white);
  padding: 64px 0 72px;
}
/* Flowing line background (ported from "Background Paths" — see
   js/background-paths.js), sitting behind the hero copy. */
.service-hero__paths {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.service-hero__paths svg { width: 100%; height: 100%; display: block; }
.bg-path {
  stroke: var(--white);
  stroke-opacity: var(--op, 0.12);
  animation: bg-path-flow 22s linear infinite;
}
@keyframes bg-path-flow {
  to { stroke-dashoffset: -2000; }
}
/* Merged service-hero background (js/flow-topo.js). Built so almost nothing
   is repainted per frame: each contour layer is a static SVG inside a
   .flow-drift wrapper that slides via a transform (GPU-composited), and only
   the few thin .flow-dash paths (in their own small SVG) animate. The fade
   behind the hero copy is the ::after gradient below rather than an SVG mask
   (masks over animated content force a full repaint every frame). Scoped to
   .flow-topo so the Contact hero, which still uses the older flowing lines
   in the same container, is untouched. */
.service-hero__paths.flow-topo::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background: radial-gradient(ellipse 40% 60% at 30% 50%,
    color-mix(in srgb, var(--blue-brand) 88%, transparent) 0%,
    color-mix(in srgb, var(--blue-brand) 55%, transparent) 55%,
    transparent 100%);
}
.flow-drift {
  position: absolute;
  inset: 0;
  will-change: transform;
  animation: flow-drift var(--dur, 18s) ease-in-out infinite alternate;
}
/* Slightly oversized so the drift never exposes an uncovered edge. */
.service-hero__paths .flow-svg {
  position: absolute;
  left: -30px;
  top: -30px;
  width: calc(100% + 60px);
  height: calc(100% + 60px);
}
@keyframes flow-drift {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(var(--dx, 0px), var(--dy, 0px), 0); }
}
.flow-line { fill: none; stroke: var(--white); stroke-linecap: round; }
.flow-dash {
  fill: none;
  stroke: var(--white);
  stroke-opacity: 0.65;
  stroke-linecap: round;
  animation: flow-dash-travel 26s linear infinite;
}
/* Offset by exactly one dash period (the path's own length) so the loop is
   seamless, unlike the fixed -2000 used by .bg-path above. */
@keyframes flow-dash-travel {
  to { stroke-dashoffset: calc(var(--len, 1000px) * -1); }
}
.service-hero__paths[data-paused="true"] .flow-drift,
.service-hero__paths[data-paused="true"] .flow-dash { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) {
  .flow-drift, .flow-dash { animation: none; }
}
.service-hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.15fr 1fr;
  gap: 48px;
  align-items: center;
}
/* Get a Quote — the hero carries the full quote panel now, not a small
   feature grid, so it needs more room than a normal service-hero: extra
   padding, more width given to the panel than the copy, and top-aligned
   instead of centered since the panel is much taller than the copy beside
   it. Scoped to this page only via #quote-hero, and to min-width:981px
   specifically — an ID selector beats the plain-class mobile stacking rule
   below on specificity alone regardless of source order, so without this
   media guard the two-column layout would wrongly survive on mobile. */
#quote-hero, #careers-hero { padding: 56px 0 72px; }
@media (min-width: 981px) {
  /* Same treatment now applied to careers.html: its panel was still using
     the default 1.15fr/1fr split (copy wider than panel) even though the
     copy here is short and the panel is the actual point of the page —
     at in-between desktop widths (~1200-1300px, common laptop territory,
     not just the widest monitors) that made the panel narrow enough that
     "Deep Cleaning / One-Off Jobs" and the "e.g. Mayfair, Soho, Victoria"
     placeholder both ran right up against their box edges. */
  #quote-hero .service-hero__inner,
  #careers-hero .service-hero__inner { grid-template-columns: 0.85fr 1.15fr; align-items: flex-start; }
  #quote-hero .service-hero__copy,
  #careers-hero .service-hero__copy { padding-top: 12px; }
}
.service-hero__copy { min-width: 0; }
.service-hero .eyebrow { color: rgba(255, 255, 255, 0.85); }
.service-hero .eyebrow::before { background: rgba(255, 255, 255, 0.85); }
.service-hero h1 {
  color: var(--white);
  font-size: clamp(32px, 4.2vw, 48px);
  margin-top: 10px;
  line-height: 1.12;
  max-width: 20ch;
}
.service-hero__copy p {
  margin-top: 14px;
  color: rgba(255, 255, 255, 0.82);
  font-size: 17px;
  max-width: 52ch;
}
.service-hero__ctas {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 30px;
  flex-wrap: wrap;
}
/* Get a Quote — a vertical list of the trust points that used to be the
   4-box grid, filling the copy column's height next to the much taller
   quote panel instead of leaving it looking empty beside it. Reuses
   .why-item's icon-circle language (translucent ring on a blue ground)
   rather than duplicating it, just restyled as a column instead of a grid
   and with its own text-color rules since it isn't inside .section--navy. */
.service-hero__points {
  margin-top: 32px;
  display: flex;
  flex-direction: column;
  gap: 20px;
}
.service-hero__point { display: flex; gap: 14px; align-items: flex-start; }
.service-hero__point .icon {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.25);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--white);
}
.service-hero__point h4 { color: var(--white); font-family: var(--font-display); font-size: 15.5px; margin: 0; }
.service-hero__point p { margin-top: 3px; color: rgba(255, 255, 255, 0.75); font-size: 13.5px; line-height: 1.5; max-width: none; }

/* Short centered intro inside the panel itself, above the step rail —
   moved in from a separate heading that used to sit above/beside the box
   on the blue background, which read like two unrelated columns of text
   next to each other rather than one unit. */
.quote-panel__intro { text-align: center; margin-bottom: 28px; }
.quote-panel__intro h3 { font-size: clamp(20px, 2.2vw, 24px); margin: 0; }
.quote-panel__intro p { margin-top: 8px; color: var(--ink-soft); font-size: 14.5px; }

/* 2x2 key-features box (ported from the old standalone .features-strip
   section, folded into the hero instead so the hero isn't followed
   immediately by another solid-blue section — two adjacent blue sections
   read as "blue on blue" with nothing to break them up, so the strip moved
   in here as a white card floating on the hero background instead). Split
   into 4 individual cards. An earlier pass gave each card an animated
   traveling-light border (ported from "BorderTrail", ~component-library.md)
   using offset-path/offset-distance — reverted per request ("look weird"):
   a 34px glowing dot chasing the edge of a ~240x100px card is a lot of
   motion for a secondary element, and offset-path's rect() shape has real
   cross-browser gaps, so it likely wasn't rendering as intended everywhere.
   Replaced with the site's own established icon-badge language instead
   (same rounded-square blue-pale badge already used for .mega-menu__icon
   and .contact-chip__icon), which is proven to render correctly. */
.service-hero__features {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
.service-hero__feature {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--white);
  border-radius: 14px;
  padding: 16px;
  box-shadow: var(--shadow-card);
}
.service-hero__feature-icon {
  width: 38px;
  height: 38px;
  flex-shrink: 0;
  border-radius: 10px;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
}
.service-hero__feature h4 { font-family: var(--font-display); font-size: 14px; font-weight: 700; color: var(--ink); margin: 0; }
.service-hero__feature p { margin: 0; font-size: 12px; line-height: 1.45; color: var(--ink-soft); max-width: none; }


/* What's included checklist ---------------------------------------------*/
.included-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 18px 32px;
}
.included-grid li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--ink);
}
.included-check {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  margin-top: 1px;
  border-radius: 50%;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Trusted-by logo cloud (ported from "Cinematic Logo Cloud", grid variant)
   — text-only "logos" since there are no real client logos yet; swap the
   .logo-cloud__item text for real client names later, same markup applies.
   Folded into the Client Words/testimonials section (a light background),
   so colors here are ink-based rather than the white/blue-badge combo an
   earlier pass used when this had its own solid-blue section. Compound
   `.logo-cloud__item[data-reveal]` selectors (not bare `.logo-cloud__item`)
   so this beats the generic [data-reveal] rule further down the file
   regardless of source order. */
.testimonial-divider {
  margin: 44px 0 0;
  border: none;
  border-top: 1px solid rgba(33, 29, 20, 0.14);
}
.logo-cloud__row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 20px 40px;
}
.logo-cloud__item[data-reveal] {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 17px;
  color: var(--ink);
  opacity: 0;
  filter: blur(8px);
  transform: translateY(14px);
  transition: opacity 0.7s ease, transform 0.7s ease, filter 0.7s ease;
}
.logo-cloud__item[data-reveal].is-visible { opacity: 1; filter: blur(0); transform: translateY(0); }
/* Placeholder "logo" mark — a lettermark badge standing in for a real
   company logo, since there are none yet (these are fictional client
   names). Plain text alone read as too bare, per feedback. */
.logo-cloud__mark {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12.5px;
  font-weight: 800;
}
.logo-cloud__item:nth-child(1) { transition-delay: 0ms; }
.logo-cloud__item:nth-child(2) { transition-delay: 70ms; }
.logo-cloud__item:nth-child(3) { transition-delay: 140ms; }
.logo-cloud__item:nth-child(4) { transition-delay: 210ms; }
.logo-cloud__item:nth-child(5) { transition-delay: 280ms; }
.logo-cloud__item:nth-child(6) { transition-delay: 350ms; }
.logo-cloud__item:nth-child(7) { transition-delay: 420ms; }
.logo-cloud__item:nth-child(8) { transition-delay: 490ms; }
.logo-cloud__item:nth-child(9) { transition-delay: 560ms; }
.logo-cloud__item:nth-child(10) { transition-delay: 630ms; }

/* Route map — a winding path with 4 pin stops, ported from "Animated
   Roadmap" (a scroll-linked framer-motion path draw + pin pop-in over a
   map illustration). No framer-motion here, so the path is a hand-drawn
   SVG curve and the "draw in" + pin pop-in both ride the site's existing
   [data-reveal] IntersectionObserver via plain CSS descendant selectors —
   no JS changes needed. Sits above .process-steps as a glanceable index;
   the full step titles/descriptions still live in the cards below it. */
.route-map { position: relative; height: 260px; margin: 4px 0 56px; }
.route-map__path { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.route-map__path path {
  fill: none;
  stroke: var(--blue-sky);
  stroke-width: 4;
  stroke-linecap: round;
  stroke-dasharray: 14 10;
  stroke-dashoffset: 2000;
  transition: stroke-dashoffset 1.8s cubic-bezier(0.16, 1, 0.3, 1);
}
.route-map[data-reveal].is-visible .route-map__path path { stroke-dashoffset: 0; }
.route-map__pin {
  position: absolute;
  transform: translate(-50%, -30%) scale(0.6);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  opacity: 0;
  transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.route-map[data-reveal].is-visible .route-map__pin { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.route-map__pin:nth-child(2) { transition-delay: 0.15s; }
.route-map__pin:nth-child(3) { transition-delay: 0.45s; }
.route-map__pin:nth-child(4) { transition-delay: 0.75s; }
.route-map__pin:nth-child(5) { transition-delay: 1.05s; }
.route-map__pin--flip { flex-direction: column-reverse; }
.route-map__num {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  border-radius: 50%;
  background: var(--white);
  border: 2.5px solid var(--blue-brand);
  color: var(--blue-brand);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-card);
}
.route-map__label {
  padding: 6px 14px;
  border-radius: 999px;
  background: var(--white);
  border: 1px solid var(--cream-line);
  font-size: 12.5px;
  font-weight: 700;
  color: var(--ink);
  white-space: nowrap;
  box-shadow: var(--shadow-card);
}

/* Compact route map — the same winding path + pin pop-in as above, sized
   down for a 3-stop sequence (used for "What happens after you get in
   touch" on the location pages). vector-effect keeps the line a constant
   thickness even though the SVG is squashed to a shorter height. The
   descriptions sit in .process-steps underneath (as on the service pages),
   each title carrying a small numbered mark that matches its pin on the
   map — so the two read as one thing, and the number is still there on
   mobile where the map itself is hidden. .next-steps--four is the 4-item
   variant (Our Story). */
.route-map--compact { height: 170px; margin: 0 0 24px; }
.route-map--compact .route-map__path path { vector-effect: non-scaling-stroke; stroke-width: 3; stroke-dasharray: 12 9; }
.next-steps .process-steps { grid-template-columns: repeat(3, 1fr); }
.next-steps--four .process-steps { grid-template-columns: repeat(4, 1fr); }
.next-steps__mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  margin-right: 10px;
  border-radius: 50%;
  background: var(--blue-brand);
  color: var(--white);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: 800;
  vertical-align: 1px;
}
@media (max-width: 980px) {
  .next-steps--four .process-steps { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 760px) {
  .next-steps .process-steps { grid-template-columns: 1fr; gap: 24px; }
  .next-steps--four .process-steps { grid-template-columns: 1fr; }
}

/* How We Clean — process steps + method grid ------------------------------
   Numbered because it's a real sequence (each step happens in order), not
   decorative numbering. */
.process-steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 28px;
  margin-top: 8px;
}
.process-step__num {
  display: block;
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 800;
  color: var(--blue-sky);
  line-height: 1;
}
.process-step h3 { margin-top: 10px; font-size: 16.5px; }
.process-step p { margin-top: 8px; font-size: 14.5px; color: var(--ink-soft); line-height: 1.6; }

/* One-off service pages — process + what's included, merged into a single
   roadmap (referenced from the numbered .quote-rail step indicator, but
   built for real content underneath each number rather than a compact
   form-progress bar) instead of two separately-titled grids stacked on
   top of each other. (An earlier pass added a short connecting line before
   steps 2 and 3 — removed: with only 3 items spaced across a full-width
   row, two short disconnected dashes read as a stray mark next to some
   numbers and not others rather than an intentional connector. The
   numbering alone already reads as a sequence, same as .process-steps
   elsewhere on the site, which never had connecting lines either.) */
.oneoff-roadmap__steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; margin-top: 8px; }
.oneoff-roadmap__num {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--blue-brand);
  color: var(--white);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 16px;
}
.oneoff-roadmap__step h3 { font-size: 16.5px; margin: 0; }
.oneoff-roadmap__step p { margin-top: 8px; font-size: 14px; line-height: 1.6; color: var(--ink-soft); }
/* Reset: a bare <ul> keeps the browser's default marker gutter even with
   list-style set elsewhere, which left this list visibly indented from
   the paragraph text above it instead of flush with it. */
.oneoff-roadmap__list { margin-top: 14px; padding-left: 0; list-style: none; display: flex; flex-direction: column; gap: 7px; }
.oneoff-roadmap__list li { display: flex; align-items: flex-start; gap: 7px; font-size: 13px; color: var(--ink-soft); line-height: 1.4; }
.oneoff-roadmap__list li svg { flex-shrink: 0; margin-top: 2px; color: var(--blue-brand); }

.method-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 32px;
  margin-top: 48px;
  padding-top: 40px;
  border-top: 1px solid var(--cream-line);
}
.method-item h3 { font-size: 16px; }
.method-item p { margin-top: 8px; font-size: 14.5px; color: var(--ink-soft); line-height: 1.6; }

/* Who We Clean For — industry tags ----------------------------------------*/
.pill-row { display: flex; flex-wrap: wrap; gap: 12px; }
.pill {
  display: inline-flex;
  align-items: center;
  padding: 12px 22px;
  border-radius: 999px;
  background: var(--white);
  border: 1px solid var(--cream-line);
  color: var(--ink);
  font-weight: 600;
  font-size: 14px;
}

/* Testimonials — sliding marquee (ported from "Testimonials With Marquee" /
   testimonial-card), replacing the earlier static 3-up grid. A single row
   drifts left on a seamless loop (the card list is duplicated once in the
   HTML, aria-hidden on the duplicate) and pauses on hover/focus; the site's
   global prefers-reduced-motion override already freezes the animation for
   anyone who needs that. Cards reuse the same compact .t-card look the
   static grid introduced, scoped to .testimonial-marquee only so the
   homepage's own testimonials-columns marquee is untouched. */
.testimonial-marquee {
  position: relative;
  overflow: hidden;
  margin-top: 8px;
  -webkit-mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
  mask-image: linear-gradient(to right, transparent, black 6%, black 94%, transparent);
}
.testimonial-marquee__track {
  display: flex;
  width: max-content;
  gap: 22px;
  animation: testimonial-marquee-scroll 42s linear infinite;
}
.testimonial-marquee:hover .testimonial-marquee__track,
.testimonial-marquee:focus-within .testimonial-marquee__track {
  animation-play-state: paused;
}
@keyframes testimonial-marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
.testimonial-marquee .t-card {
  flex-shrink: 0;
  width: 300px;
  border: none;
  border-top: 3px solid var(--blue-sky);
  border-radius: 12px;
  background: linear-gradient(to bottom, var(--blue-pale), var(--white) 65%);
  box-shadow: none;
  padding: 22px;
}
.testimonial-marquee .t-card--placeholder {
  border-top: 3px dashed var(--cream-line);
  background: linear-gradient(to bottom, var(--cream-deep), var(--white) 65%);
}
.testimonial-marquee .t-card__who { margin-top: 0; margin-bottom: 16px; }
.testimonial-marquee .t-card__avatar { width: 48px; height: 48px; }
.testimonial-marquee .t-card p { font-size: 14.5px; }

/* Blog teaser — fills the white gap between Explore More and Contact with
   something genuinely useful for SEO (fresh, topical content signals +
   internal links) rather than a bare spacer. blog.html doesn't exist yet,
   so "Read more" 404s for now — same honest-placeholder pattern as every
   other not-yet-built page in the nav (Our Story, Blog, Services). */
.blog-teaser-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
.blog-teaser-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 14px;
  padding: 24px;
  box-shadow: var(--shadow-card);
}
.blog-teaser-card__tag {
  align-self: flex-start;
  padding: 4px 11px;
  border-radius: 999px;
  background: var(--blue-pale);
  color: var(--blue-brand);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.blog-teaser-card h3 { font-size: 16px; margin-top: 2px; color: var(--ink); }
.blog-teaser-card p { margin: 0; font-size: 13.5px; color: var(--ink-soft); line-height: 1.55; }
.blog-teaser-card a.blog-teaser-card__link {
  margin-top: auto;
  padding-top: 4px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--blue-brand);
  text-decoration: none;
}
/* Get a Quote — multi-step wizard ------------------------------------------
   Structural pattern referenced from 21st.dev's "Wizard Steps" (numbered
   progress rail with connecting lines, one panel visible at a time, back/
   next controls), rebuilt in vanilla JS/CSS for this site (js/quote-wizard.js)
   and restyled with the brand palette instead of that component's neutral
   theme — same reuse-the-shape-not-the-code approach as every other
   21st.dev-sourced piece on this site. */
.quote-panel {
  max-width: 760px;
  margin: 0 auto;
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 14px;
  box-shadow: var(--shadow-card);
  padding: 40px;
  /* js/quote-wizard.js scrolls the panel back into view on every step
     change — without this, `block: "start"` would align the panel's top
     edge exactly with the very top of the viewport, sliding it in right
     underneath (or behind) the sticky header. Same value already used for
     every other in-page section's own anchor-scroll offset. */
  scroll-margin-top: 110px;
}
.quote-rail { display: flex; align-items: flex-start; margin-bottom: 40px; }
.quote-rail__step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
  background: none;
  border: none;
  font: inherit;
  cursor: default;
  padding: 0;
}
.quote-rail__step.is-clickable { cursor: pointer; }
.quote-rail__num {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 2px solid var(--cream-line);
  background: var(--white);
  color: var(--ink-soft);
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.2s ease, background 0.2s ease, color 0.2s ease;
}
.quote-rail__label { font-size: 11.5px; font-weight: 600; color: var(--ink-soft); white-space: nowrap; transition: color 0.2s ease; }
.quote-rail__step.is-current .quote-rail__num { border-color: var(--blue-brand); color: var(--blue-brand); }
.quote-rail__step.is-current .quote-rail__label { color: var(--ink); }
.quote-rail__step.is-done .quote-rail__num { border-color: var(--blue-brand); background: var(--blue-brand); color: var(--white); }
.quote-rail__connector {
  flex: 1;
  height: 2px;
  background: var(--cream-line);
  margin: 16px 8px 0;
  position: relative;
  overflow: hidden;
}
.quote-rail__connector-fill {
  position: absolute;
  inset: 0;
  background: var(--blue-brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s ease;
}
.quote-rail__connector.is-filled .quote-rail__connector-fill { transform: scaleX(1); }

.quote-step__eyebrow { color: var(--blue-brand); }
.quote-step h3 { font-size: clamp(20px, 2.4vw, 25px); margin-top: 8px; }
.quote-step__desc { margin-top: 8px; color: var(--ink-soft); font-size: 14.5px; }
.quote-step__fields { margin-top: 24px; display: flex; flex-direction: column; gap: 18px; }
.quote-field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }

/* .quote-choice-grid's own margin-top is meant for steps where it sits
   directly under the step description (Step 1 on both this wizard and
   careers.html). On steps where it's nested one level deeper inside
   .quote-step__fields (careers.html Step 2, "When can you work?"), that
   wrapper already adds its own 24px margin-top before its first child —
   flex children don't collapse margins with their parent, so the grid's
   margin-top added on top of that, doubling the gap to 48px and reading
   as a big unexplained blank space compared to every other step. Zeroed
   here specifically for that nested case; standalone use elsewhere is
   unaffected. */
.quote-choice-grid { margin-top: 24px; display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.quote-step__fields > .quote-choice-grid { margin-top: 0; }
.quote-choice {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px 16px;
  border: 1.5px solid var(--cream-line);
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.quote-choice:has(input:checked) { border-color: var(--blue-brand); background: var(--blue-pale); }
.quote-choice input { width: 18px; height: 18px; flex-shrink: 0; accent-color: var(--blue-brand); }
.quote-choice span { font-size: 14.5px; font-weight: 600; color: var(--ink); }
.quote-step__warning {
  margin-top: 14px;
  font-size: 13.5px;
  font-weight: 600;
  color: #B0362C;
}

.quote-nav {
  margin-top: 32px;
  padding-top: 24px;
  border-top: 1px solid var(--cream-line);
  display: flex;
  align-items: center;
  gap: 14px;
}
.quote-nav .btn-primary,
.quote-nav .btn-ghost { margin-left: auto; }
.quote-nav .btn-ghost:first-child { margin-left: 0; margin-right: auto; }

.quote-success { text-align: center; padding: 24px 0; }
.quote-success__icon {
  width: 56px;
  height: 56px;
  margin: 0 auto 20px;
  border-radius: 50%;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
}
.quote-success h3 { font-size: clamp(22px, 2.6vw, 27px); }
.quote-success p { margin-top: 10px; color: var(--ink-soft); font-size: 15px; max-width: 44ch; margin-left: auto; margin-right: auto; }

/* Related services strip --------------------------------------------------*/
.related-services {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.related-service {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 13px 22px;
  border: 1px solid var(--cream-line);
  border-radius: 999px;
  background: var(--white);
  color: var(--blue-deep);
  font-weight: 600;
  font-size: 14.5px;
  text-decoration: none;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.related-service:hover { border-color: var(--blue-brand); background: var(--blue-pale); }

/* Footer ----------------------------------------------------------------*/
.site-footer {
  background: var(--blue-deep);
  color: rgba(255, 255, 255,0.75);
  padding-top: 64px;
}
.footer-top {
  display: flex;
  align-items: flex-start;
  gap: 64px;
  flex-wrap: wrap;
  padding-bottom: 40px;
}
.footer-brand .brand-word { color: var(--cream); }
.footer-brand p { margin-top: 16px; font-size: 14.5px; max-width: 32ch; }
.footer-social__icons { display: flex; gap: 12px; margin-top: 16px; }
.footer-social__icons a {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--white);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.footer-social__icons a:hover { background: rgba(255,255,255,0.12); border-color: var(--white); }

/* Footer newsletter — sits in the empty space to the right of "Follow Us" in
   .footer-top (moved here from a full-width card on the homepage). Own
   classes rather than reusing .newsletter__form: those are styled for a
   light background (white input, dark consent text) and this sits on the
   dark footer. margin-left:auto pushes it to the container's right edge so
   it balances the brand/social block on the left. Reuses #newsletter-form /
   #newsletter-note so the existing submit handler in js/script.js applies. */
.footer-newsletter { width: 100%; max-width: 400px; }
/* Desktop: line the newsletter's left edge up with the "Areas We Cover"
   column below (.footer-grid: three 240px columns + 64px gaps, so the third
   column starts 608px in). The top row becomes a grid whose first two
   columns are sized to add up to exactly that — brand block, Follow Us, then
   the newsletter starting on the Areas We Cover line. Smaller screens keep
   the wrapping flex layout from .footer-top. */
@media (min-width: 981px) {
  .footer-top {
    display: grid;
    grid-template-columns: 1.15fr 0.85fr 1.2fr 1.3fr;
    gap: 0 40px;
    /* Align on the first line's baseline so "Office Cleaning London"
       (larger type) sits on the same line as "Follow Us" / "Newsletter"
       instead of riding higher than them. */
    align-items: baseline;
  }
}
.footer-newsletter p { margin-top: 10px; font-size: 14px; max-width: 40ch; }
.footer-newsletter__form { display: flex; gap: 8px; margin-top: 14px; }
.footer-newsletter__form input {
  flex: 1;
  min-width: 0;
  height: 44px;
  padding: 0 14px;
  border-radius: var(--radius);
  border: 1px solid rgba(255, 255, 255, 0.3);
  background: rgba(255, 255, 255, 0.1);
  color: var(--white);
  font: inherit;
  font-size: 14px;
}
.footer-newsletter__form input::placeholder { color: rgba(255, 255, 255, 0.6); }
.footer-newsletter__form input:focus { outline: none; border-color: var(--white); background: rgba(255, 255, 255, 0.16); }
.footer-newsletter__form .btn { flex-shrink: 0; height: 44px; padding: 0 18px; font-size: 14px; }
.footer-newsletter__fine { font-size: 12px !important; color: rgba(255, 255, 255, 0.6); margin-top: 8px !important; }
.footer-newsletter__note { color: var(--white); font-weight: 600; font-size: 13.5px !important; }

/* Blank stand-in where each page's old newsletter card used to be (the
   newsletter now lives in the footer), until something new goes there. Look
   for the "PLACEHOLDER — REPLACE WITH CONTENT" comment in the HTML. */
.newsletter-placeholder {
  min-height: 220px;
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 8px;
  box-shadow: var(--shadow-card);
}


/* Footer link area — four columns across the full container width
   (Contact / Quick Links / Services / Who We Clean For), then a full-width
   "Areas We Cover" band split into three zones. */
.footer-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr 1.2fr 1.3fr;
  gap: 40px;
  padding-bottom: 48px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.15);
}
.footer-grid > div { min-width: 0; }
.site-footer h6 {
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6); margin: 22px 0 12px;
}
.footer-areas-band { padding-top: 40px; padding-bottom: 44px; border-bottom: 1px solid rgba(255, 255, 255, 0.15); }
.footer-areas-band > h5 { margin-bottom: 20px; }
.footer-areas-groups { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 40px; }
.footer-areas-groups h6 { margin: 0 0 12px; padding-bottom: 10px; border-bottom: 1px solid rgba(255, 255, 255, 0.12); }
.site-footer .footer-areas { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 20px; }
.footer-contact__address { font-size: 14.5px; line-height: 1.6; }
.footer-contact__item { margin-top: 16px; }
.footer-contact__label {
  display: block;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--white);
  margin-bottom: 4px;
}
.footer-contact__item a { font-size: 14.5px; }

.site-footer h5 {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--white);
  margin-bottom: 16px;
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.site-footer a { text-decoration: none; font-size: 14.5px; color: inherit; }
.site-footer a:hover { color: var(--white); }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* Longhand top/bottom only — this element also carries the shared
     .container class, which sets `padding: 0 24px` for the side gutter
     every other section on the site uses. The old shorthand `padding: 24px
     0` here zeroed that back out (same specificity, later in the file
     wins), so this one row sat flush against the screen edge with no
     margin at all while everything above it had the normal 24px inset. */
  padding-top: 24px;
  padding-bottom: 24px;
  font-size: 13px;
  gap: 16px;
  flex-wrap: wrap;
}

/* Location hero (Mayfair, etc.) --------------------------------------------
   Same solid-blue base as .service-hero, but the background is "Luminous
   Topography" instead of "Background Paths" — a vanilla port of the
   21st.dev component of the same name (js/topo-lines.js): static
   contour-map lines with a soft light sweeping across them, evoking an OS
   map's elevation rings around the area itself. A third distinct
   background treatment, alongside the homepage's gradient wave and the
   service pages' flowing paths — picked deliberately so each page tier
   reads as its own thing rather than one motif reused everywhere. */
.location-hero {
  position: relative;
  overflow: hidden;
  background: var(--blue-brand);
  color: var(--white);
  padding: 64px 0 72px;
}
.location-hero__topo {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.location-hero__topo svg { width: 100%; height: 100%; display: block; }
.location-hero__topo canvas { width: 100%; height: 100%; display: block; }
.topo-line { fill: none; stroke: var(--white); vector-effect: non-scaling-stroke; }
.topo-line--dim { stroke-opacity: 0.14; }
.topo-line--bright { stroke-opacity: 0.6; }
.topo-sweep { animation: topo-sweep-move 16s ease-in-out infinite alternate; }
@keyframes topo-sweep-move {
  from { transform: translateX(-420px); }
  to { transform: translateX(420px); }
}
@media (prefers-reduced-motion: reduce) {
  .topo-sweep { animation: none; }
}
.location-hero__inner {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: 1.1fr 0.9fr;
  gap: 48px;
  align-items: stretch;
}
.location-hero__copy { min-width: 0; display: flex; flex-direction: column; justify-content: center; }
.location-hero .eyebrow { color: rgba(255, 255, 255, 0.85); }
.location-hero .eyebrow::before { background: rgba(255, 255, 255, 0.85); }
.location-hero h1 {
  color: var(--white);
  font-size: clamp(32px, 4.2vw, 48px);
  margin-top: 10px;
  line-height: 1.12;
  max-width: 18ch;
}
.location-hero__copy p {
  margin-top: 14px;
  color: rgba(255, 255, 255, 0.82);
  font-size: 17px;
  max-width: 52ch;
}
.location-hero__ctas {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-top: 30px;
  flex-wrap: wrap;
}
.location-hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  margin-top: 28px;
}
.location-hero__fact {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.92);
}
.location-hero__fact svg { flex-shrink: 0; }
/* Numbered variant of the existing .heritage__art-placeholder "photo coming
   soon" pattern — same dashed box, plus the source photo's position in the
   old site's image order, so a real photo can be dropped in later without
   guessing which one goes where. */
.heritage__art-placeholder .placeholder-num {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 36px;
  color: var(--blue-brand);
  line-height: 1;
}
.location-hero .heritage__art-placeholder { color: rgba(255, 255, 255, 0.85); }
.location-hero .heritage__art-placeholder .placeholder-num { color: var(--white); }
.location-hero .heritage__art-placeholder span { color: rgba(255, 255, 255, 0.85); }
.location-hero .heritage__art { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.5); }
.location-hero .heritage__art--photo { background: none; border: 0; }

/* One-off services — reused old-site content (end of tenancy, carpet
   cleaning, deep clean, after-build) alongside the recurring contracts
   covered above. */
.oneoff-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
  margin-top: 8px;
}
.oneoff-card {
  background: var(--white);
  border: 1px solid var(--cream-line);
  border-radius: 14px;
  padding: 26px;
  box-shadow: var(--shadow-card);
  display: flex;
  flex-direction: column;
}
.oneoff-card__icon {
  width: 42px;
  height: 42px;
  border-radius: 10px;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 14px;
}
.oneoff-card h3 { font-size: 16px; margin: 0; }
.oneoff-card__price {
  display: block;
  margin-top: 6px;
  font-family: var(--font-display);
  font-weight: 800;
  color: var(--blue-brand);
  font-size: 14px;
}
.oneoff-card p { margin-top: 10px; font-size: 13.5px; line-height: 1.55; color: var(--ink-soft); flex-grow: 1; }
/* Each card now links through to its own dedicated page (built separately
   under /one-off/) — a small full-width button rather than a plain text
   link, since "Learn more" text alone was easy to miss against the card's
   existing icon/price/description. Reuses .btn-primary (so it picks up
   the site's pointer-following radial hover-fill for free, same as every
   other primary button) just at a more compact size for a card this size. */
.oneoff-card__cta {
  margin-top: 18px;
  padding: 10px 16px;
  font-size: 13px;
  width: 100%;
  justify-content: center;
}

/* Scroll reveal ----------------------------------------------------------*/
[data-reveal] { opacity: 0; transform: translateY(16px); transition: opacity 0.6s ease, transform 0.6s ease; }
[data-reveal].is-visible { opacity: 1; transform: translateY(0); }

/* Desktop/tablet spacing pass ----------------------------------------------
   Mobile's section padding was tightened up heavily over several earlier
   passes; desktop was still sitting at the original, much more generous
   96px/64px defaults the whole time, which read as excessive blank space
   once compared side by side. Scoped to min-width:761px specifically (not
   just edited on the base rules) so none of this touches the already-tuned
   mobile values — each section gets its own treatment per what actually
   needed trimming, not a uniform cut. */
@media (min-width: 761px) {
  #services { padding-top: 48px; padding-bottom: 86px; }
  .cta-section { padding: 36px 0; }
  .section--navy { padding-top: 48px; padding-bottom: 48px; }
  /* FAQ and Testimonials only had too much space above the heading — the
     bottom padding is left alone deliberately (FAQ accordions expand
     further, and the testimonials list fades out toward its own bottom
     edge, both need the existing breathing room). */
  #faq { padding-top: 48px; }
  #testimonials { padding-top: 48px; }
  .section--cream-deep { padding-top: 48px; }
  /* Get In Touch — top and bottom now match (48px each). Top was already
     right; bottom was still the original 96px, noticeably bigger than the
     top once compared side by side. */
  #contact { padding-top: 48px; padding-bottom: 48px; }
  /* Where We Work — top gap was still a bit big even after being left
     alone last pass; bottom wasn't flagged, so only trimmed here. */
  #where-we-work { padding-top: 40px; }
}

/* Responsive --------------------------------------------------------------*/
@media (max-width: 980px) {
  .hero__inner { grid-template-columns: 1fr; }
  .hero__imagebox { justify-self: start; max-width: 420px; width: 100%; margin-top: 0; }
  .service-hero__inner { grid-template-columns: 1fr; gap: 32px; }
  .service-hero__features { max-width: 460px; }
  /* Get a Quote — corrected per Jayden's follow-up: he wanted the heading
     ("Tell us about your building...") to stay first, then the wizard
     panel, then the 4 trust points last — not the whole copy block
     (heading + points together) pushed below the panel, which is what
     moving only .quote-panel achieved before. .service-hero__copy wraps
     the heading text AND .service-hero__points as one block, so getting
     the panel to sit between them needs .service-hero__copy split apart:
     `display: contents` drops its own box without touching the DOM,
     promoting the eyebrow/h1/p and .service-hero__points to be ordered
     independently, as if they were direct children of .service-hero__inner
     alongside .quote-panel. Scoped to #quote-hero only. */
  /* Same fix, now also applied to careers.html's #careers-hero — it has
     its own wizard panel and its own 4-point trust list, but was still
     using the older order (all the way down below all 4 points), which
     Jayden flagged in the same way he originally flagged it here: every
     step click meant scrolling past the same wall of copy again to see
     the panel change. */
  #quote-hero .service-hero__copy,
  #careers-hero .service-hero__copy { display: contents; }
  #quote-hero .service-hero__copy > .eyebrow,
  #quote-hero .service-hero__copy > h1,
  #quote-hero .service-hero__copy > p,
  #careers-hero .service-hero__copy > .eyebrow,
  #careers-hero .service-hero__copy > h1,
  #careers-hero .service-hero__copy > p { order: 1; }
  #quote-hero .quote-panel,
  #careers-hero .quote-panel { order: 2; }
  #quote-hero .service-hero__points,
  #careers-hero .service-hero__points { order: 3; }
  /* Correction: promoting eyebrow/h1/p to be their own grid items (above)
     meant .service-hero__inner's own 32px grid `gap` started applying
     BETWEEN each of them too — previously that gap only ever applied once,
     between the whole copy block and whatever came after it. That stacked
     on top of h1's own 10px margin-top and p's own 14px, producing the
     42px/46px gaps Jayden measured against a location page's tight
     10px/14px and flagged as "such a big gap" / "so much space between
     the text". Zeroing the grid gap for just these two sections and
     re-adding it as explicit margin only on the two boundaries that
     actually need it (before the panel, before the points) restores the
     eyebrow/h1/p spacing to the same tight, un-gapped rhythm every other
     .service-hero page already has. */
  #quote-hero .service-hero__inner,
  #careers-hero .service-hero__inner { gap: 0; }
  #quote-hero .quote-panel,
  #careers-hero .quote-panel { margin-top: 32px; }
  #quote-hero .service-hero__points,
  #careers-hero .service-hero__points { margin-top: 32px; }
  .location-hero__inner { grid-template-columns: 1fr; gap: 32px; }
  .location-hero .heritage__art { min-height: 260px; }
  .oneoff-grid { grid-template-columns: repeat(2, 1fr); }
  .services-grid { grid-template-columns: repeat(2, 1fr); }
  .why-grid { grid-template-columns: repeat(2, 1fr); }
  .process-steps { grid-template-columns: repeat(2, 1fr); }
  .oneoff-roadmap__steps { grid-template-columns: repeat(2, 1fr); }
  .method-grid { grid-template-columns: 1fr; }
  .heritage { grid-template-columns: 1fr; }
  /* Full-width single column here rather than 2 — with 3 real columns of
     content, a 2-column grid put Quick Links snugly beside Contact Us but
     left Areas We Cover to wrap alone onto its own row, giving it a
     completely different (bigger) gap from the other two. Stacking all
     three guarantees the same gap between every pair. */
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 36px 24px; }
  .footer-areas-groups { grid-template-columns: 1fr; gap: 28px; }
  .features-strip .container { grid-template-columns: repeat(2, 1fr); gap: 0; }
  .feature-item { border-left: none !important; border-top: 1px solid rgba(255,255,255,0.22); }
  .feature-item:nth-child(1), .feature-item:nth-child(2) { border-top: none; }
  .feature-item:nth-child(odd) { border-right: 1px solid rgba(255,255,255,0.22); }
  .testimonials-col--desktop-up { display: none; }
  .contact-card { grid-template-columns: 1fr; }
  .contact-card__form-panel { border-left: none; border-top: 1px solid var(--cream-line); }
  .map-layout { grid-template-columns: 1fr; }
  .areas-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .map-card__map { min-height: 380px; }
  .newsletter__signup { max-width: none; }
  .quote-panel { padding: 28px; }
  .quote-field-row { grid-template-columns: 1fr; }
  .team-grid { grid-template-columns: repeat(2, 1fr); }
  .stayed-grid { grid-template-columns: repeat(2, 1fr); gap: 24px; }
  .blog-featured { grid-template-columns: 1fr; text-align: left; padding: 32px; }
  .blog-grid { grid-template-columns: repeat(2, 1fr); }

  /* Header/nav — moved up from the 760px breakpoint below. The full desktop
     nav (6 links with 46px gaps, plus phone + CTA button) genuinely doesn't
     fit in anything narrower than ~1000px; leaving the hamburger switch at
     760px left a "dead zone" from 761–980px (an iPad in portrait, several
     Android phones/foldables) where the desktop nav rendered anyway and
     ran off the right edge of the header, taking Contact/the phone
     number/the quote button off-screen with it. Switching to the mobile
     nav pattern at the same 980px this file already treats as "not
     desktop" everywhere else closes that gap. */
  /* Same sizing the true-phone breakpoint below already used — reused here
     rather than duplicated with different numbers, because the open mobile
     nav panel's top edge is hardcoded to 66px (matching this exact shrunk
     header's real height). Leaving the header at full desktop size in this
     range while still switching to the fixed slide-in panel made the panel
     overlap and clip the bottom of the logo, since the untouched desktop
     logo is taller than 66px. */
  .header-inner { padding: 14px 16px; gap: 10px; }
  .brand { gap: 8px; min-width: 0; }
  .brand-word { font-size: 15px; }
  .brand-word--mark { font-size: 40px; }
  .brand-est { display: none; }
  .header-cta { gap: 8px; flex-shrink: 0; }
  .header-cta .btn-primary { padding: 10px 14px; font-size: 13.5px; }
  .main-nav { position: fixed; inset: 66px 0 0 0; margin-left: 0; background: var(--cream); flex-direction: column; align-items: stretch; padding: 24px; transform: translateX(100%); transition: transform 0.25s ease; overflow-y: auto; }
  .main-nav.is-open { transform: translateX(0); }
  .main-nav ul { flex-direction: column; align-items: flex-start; gap: 4px; width: 100%; }
  .main-nav ul > li { width: 100%; }
  .has-dropdown .mega-menu { position: static; width: 100%; transform: none; opacity: 1; visibility: visible; box-shadow: none; border: none; padding: 0 0 0 12px; display: none; }
  .has-dropdown.is-open .mega-menu { display: block; }
  .mega-menu .mega-menu__grid { grid-template-columns: 1fr; }
  .mega-menu__footer { display: none; }
  .nav-link { padding: 12px 0 !important; display: block; }
  .nav-toggle { display: block; flex-shrink: 0; }
}

@media (max-width: 760px) {
  /* Header sizing itself now lives in the 980px breakpoint above (applies
     here too, since 760 is inside that range) — only the true-phone-only
     override stays here: there's enough room for the phone number again
     above 760px, but not below it. */
  .header-phone { display: none; }

  /* Hero — mobile visitors are mostly local searchers who want the booking
     path fast, not the full desktop pitch, so the eyebrow label and lede
     paragraph are dropped here (still shown on desktop/tablet). Top
     padding trimmed too so the headline isn't sitting a quarter of the
     way down an empty gradient. "See our services" recolored to white —
     the same blue-on-light-wave contrast problem the headline had. */
  .hero { padding-top: 20px; }
  .hero__inner { padding: 24px 20px 36px; }
  .hero__crest-line { display: none; }
  .hero__lede { display: none; }

  /* Mobile hero image — per Jayden's follow-up, the 3-card fan (still 3
     empty "coming soon" placeholders — he doesn't want to go find real
     photos for these right now) is dropped in favour of just reusing the
     one real photo the site already has (the van), and moved to sit
     between the headline and the CTA button rather than below it. Same
     display:contents trick as the footer/quote-panel fixes: .hero__copy
     drops its own box so the h1 and .hero__ctas can be ordered
     independently with the imagebox between them, as if all three were
     siblings directly inside .hero__inner. */
  .hero__copy { display: contents; }
  .hero__copy > h1 { order: 1; }
  .hero__imagebox { order: 2; display: block; width: 100%; max-width: none; justify-self: stretch; margin: 14px 0 0; }
  .hero__ctas { order: 3; margin-top: 16px; }
  .hero__fan { display: none; }

  /* "See our services" doesn't earn its place on the mobile hero — dropped
     so the image sits right under the CTA button instead, tightening the
     hero up. Still shown on desktop/tablet. */
  .hero__link { display: none; }

  /* Key features strip — a compact 2x2 grid (icon + label only, no
     description) instead of the bulky bordered layout. Description text
     is still in the DOM (kept for SEO/desktop), just hidden here. */
  .features-strip .container { grid-template-columns: repeat(2, 1fr); }
  /* Icon above the heading instead of beside it — was centering against
     the whole text block, which made it look like it was floating in the
     middle relative to the heading alone. Matches the same icon-above-
     text pattern .why-item already uses on mobile. */
  /* Stacked (icon above heading) on mobile — this is a genuinely different
     layout from desktop now (icon beside the heading there, see the base
     rule), not the same rule inherited down. */
  .feature-item { flex-direction: column; padding: 16px 10px; gap: 8px; border-left: none !important; }
  .feature-item:nth-child(1), .feature-item:nth-child(2) { border-top: none; }
  .feature-item:nth-child(odd) { border-right: 1px solid rgba(255,255,255,0.22); }
  .feature-item:nth-child(even) { border-right: none; }
  .feature-item svg { width: 18px; height: 18px; }
  .feature-item h4 { font-size: 13.5px; }
  .feature-item p { display: none; }

  /* Services grid — same idea: icon + title + "Learn more" only, no
     description, so 6 services fit in 3 short rows instead of 6 tall
     ones. Full descriptions still live on services.html. */
  .section-head { margin-bottom: 28px; }
  .section-head-row { flex-direction: column; align-items: flex-start; gap: 16px; }
  .services-grid { grid-template-columns: repeat(2, 1fr); }
  .service-card { padding: 20px 16px; }
  .service-card__accent { display: none; }
  .service-card h3 { font-size: 16px; margin-top: 4px; }
  .service-card p { display: none; }
  .service-card a.card-link { margin-top: 10px; font-size: 13px; }

  /* Why Choose Us — "way too huge" on mobile; same icon+title-only
     compaction as Services, in a 2-column grid instead of one long
     stacked column. */
  .why-grid { grid-template-columns: repeat(2, 1fr); gap: 24px 16px; }
  .why-item { flex-direction: column; gap: 10px; }
  .why-item .icon { width: 36px; height: 36px; }
  .section--navy .why-item h4, .section--brand .why-item h4 { font-size: 15px; }
  .section--navy .why-item p, .section--brand .why-item p { display: none; }

  /* Our Story — the placeholder photo box wasn't reliably loading/showing
     on mobile (rendered as a barely-visible sliver on at least one real
     device even after the box was given an explicit height), and isn't
     essential content on a phone screen anyway, so it's dropped entirely
     on mobile rather than kept as a placeholder that might misbehave.
     Still shows normally on desktop/tablet once a real photo is added. */
  .heritage { gap: 20px; }
  .heritage .heritage__art { display: none; }
  .story-hero__art { display: none; }

  /* Contact page — team cards and the hero's quick-reach pills, both new
     on this page, get the same tighter mobile treatment as everything
     else in this block. */
  .team-grid { grid-template-columns: 1fr; gap: 16px; }
  .team-card { padding: 28px 22px; }
  /* Per Jayden's request, these badges (also on contact.html and all 4
     one-off pages) fit on one line on mobile now instead of wrapping —
     needs real shrinking to actually fit 3 phrases this length in ~340px,
     not just a small nudge down from the desktop size. */
  .hero-reach { gap: 6px; flex-wrap: nowrap; }
  .hero-reach__item { padding: 7px 8px; font-size: 10px; white-space: nowrap; }

  /* Our Story — hero watermark shrinks further (it's already low-opacity
     decoration, not content, so it just needs to stay subtle rather than
     dominate a narrow viewport), stats stack to 2-up, and the "What Hasn't
     Changed" strip drops to a single column. */
  .story-hero__year { font-size: clamp(110px, 34vw, 220px); opacity: 0.8; }
  /* All 3 numbers stay on one line on mobile too — they're short enough
     (1985 / 40+ / 14) to fit 3-up even at phone width, so the 2-up-then-
     one-orphan-below layout this used to force wasn't needed. */
  #story-hero .heritage__stats { grid-template-columns: repeat(3, 1fr); gap: 10px; }
  #story-hero .heritage__stats div strong { font-size: 26px; }
  #story-hero .heritage__stats div span { font-size: 11px; }
  .stayed-grid { grid-template-columns: 1fr; gap: 24px; }

  /* Blog — featured card drops its padding, and the secondary grid goes
     single-column. */
  .blog-featured { padding: 24px; gap: 24px; }
  .blog-featured__icon { width: 64px; height: 64px; }
  .blog-grid { grid-template-columns: 1fr; }
  .story-timeline__card { padding: 16px 18px; }

  /* Footer reorder, mobile only — revised per Jayden's follow-up: Quick
     Links and Contact Us sit side by side now (his words: "Contact us can
     go next to Quick links on the right"), rather than everything as one
     narrow column of text hugging the left edge the whole way down, which
     read as unbalanced/hard to read. A straight flex column (the first
     version of this) can't put two blocks side by side and everything
     else full-width below them, so this switches .site-footer to a 2-
     column grid instead, with every block given an explicit grid-row so
     the stacking order is exact regardless of source position: brand full
     width, Quick Links + Contact Us share row 2, then Areas We Cover,
     Newsletter, Follow Us and the copyright bar each full width on their
     own row after that. .footer-top / .footer-grid still need `display:
     contents` so all 6 blocks become direct grid children of .site-footer
     rather than staying trapped in their own separate containers. */
  /* padding-left/right here is load-bearing, not decorative — .footer-top
     and .footer-grid both carried the shared .container class, which is
     what actually supplied the 24px side inset every other block on the
     page has. `display: contents` right below drops those two boxes
     entirely so their 6 children can be reordered as one group — but a
     dropped box's padding disappears with it, so without restating it
     here directly on .site-footer, everything except the copyright bar
     (still its own real .container box, untouched) collapsed flush
     against the screen edge instead of sitting at the same 24px as it. */
  .site-footer { display: grid; grid-template-columns: 1fr 1fr; column-gap: 20px; row-gap: 32px; padding-left: 24px; padding-right: 24px; }
  .footer-top, .footer-grid { display: contents; }
  .footer-brand { grid-column: 1 / -1; grid-row: 1; }
  .footer-grid > .footer-col--links { grid-column: 1; grid-row: 2; min-width: 0; }
  .footer-contact { grid-column: 2; grid-row: 2; }
  .footer-grid > .footer-col--services { grid-column: 1; grid-row: 3; min-width: 0; }
  .footer-grid > .footer-col--sectors { grid-column: 2; grid-row: 3; min-width: 0; }
  .footer-areas-band { grid-column: 1 / -1; grid-row: 4; padding: 0; border-bottom: 0; }
  .footer-areas-groups { gap: 22px; }
  .footer-newsletter { grid-column: 1 / -1; grid-row: 5; }
  .footer-social { grid-column: 1 / -1; grid-row: 6; }
  /* footer-bottom kept its own .container box (it isn't display:contents,
     nothing here reorders it), so left unchecked it would double up: its
     own 24px .container padding stacked on top of .site-footer's new
     24px — zeroed here since the parent now supplies that inset for
     every child uniformly. */
  .footer-bottom { grid-column: 1 / -1; grid-row: 7; padding-left: 0; padding-right: 0; border-top: 1px solid rgba(255, 255, 255, 0.15); padding-top: 24px; }
  /* Contact Us / Quick Links are now half-width (~160px) instead of the
     full 342px content width — the email address and "Join Our Team"
     wrap more, so both shrink slightly to read cleanly at that width. */
  .footer-contact__address, .footer-contact__item a, .site-footer ul a { font-size: 13.5px; }
  /* Grid items default to min-width:auto, so an unbreakable string like an
     email address (no spaces to wrap at) was forcing the whole "Contact
     Us" column to grow past its intended half-width share to fit it,
     right up to the edge of the screen — min-width:0 lets the column
     actually respect the 1fr split, and overflow-wrap lets the email
     itself wrap mid-string once it no longer has the full row to run into. */
  .footer-contact { min-width: 0; }
  .footer-contact__item a { overflow-wrap: break-word; word-break: break-word; }
  .cta-band { flex-direction: column; align-items: flex-start; }
  /* Sections were flush against each other with no extra gap between them,
     so this 64px (top+bottom = 128px combined at every boundary) was the
     entire "dead space" between sections, not a stacking/doubling bug —
     confirmed by measuring actual section boundaries. Trimmed down
     site-wide on mobile; the CTA band is deliberately excluded (kept at
     64px via .cta-section below) since its own breathing room was called
     out as worth keeping, to make the "Get a quote" button easy to find. */
  .section { padding: 40px 0; }
  .cta-section { padding: 32px 0; }

  /* FAQ heading was center-aligned (an inline style, desktop-only choice)
     — left-aligned here to match the rest of the mobile page. */
  #faq .section-head { text-align: left !important; margin-left: 0 !important; margin-right: 0 !important; }
  #faq .eyebrow { justify-content: flex-start !important; }
  .testimonials-col--tablet-up { display: none; }
  .testimonials-columns { max-height: 380px; }

  /* Get In Touch — trimmed padding and internal spacing; it was reading
     as noticeably larger/looser than the rest of the mobile page.
     Pairing Email/Phone 2-across (an earlier attempt at compacting this
     further) looked worse per Jayden's direct feedback — reverted back
     to one full-width row each (Email, Phone, Address, each on their own
     line), which is what he actually asked for. The form's own field
     spacing/textarea height stay tightened, that part he was fine with. */
  .contact-card__info, .contact-card__form-panel { padding: 20px; }
  .contact-card__info h2 { margin-top: 8px; }
  .contact-card__info > p { margin-top: 10px; }
  .contact-card__chips { grid-template-columns: 1fr; gap: 10px; margin-top: 18px; }
  .contact-chip__icon { width: 34px; height: 34px; flex-shrink: 0; }
  .contact-form { gap: 12px; }
  /* The textarea's rows="4" HTML attribute (same on all 22 pages using
     this form) sets its height with no CSS override currently — an
     explicit height here actually shrinks it, where min-height wouldn't
     (rows=4 already renders taller than that). */
  .contact-form__field textarea { height: 72px; }
  /* Where We Work — this map + 14-pill list is the same shared component on
     the homepage, every service page and every location page, so this one
     change compacts it everywhere at once (per Jayden's 22 Sept note: "if
     we could make the locations any smaller, I wouldn't mind that at all
     ... do that across every page of mobile view"). The map was a fixed
     420px tall at every screen size with no mobile shrink at all, and the
     pill list below it (previously sized UP a round per earlier feedback
     that it read as "cramped") stacked under that as a 2-column, 7-row
     grid — together, ~800-900px of scrolling for one section on a phone.
     The map is decorative/hover-driven (genuinely useful with a mouse,
     much less so as something to pinch-zoom on a phone) and isn't the part
     someone who already knows their own area is trying to tap, so it's
     dropped here the same way the Our Story photo already is on mobile —
     leaving just the actual useful part, the tappable list of areas, now
     full-width and 3 columns instead of 2 so 14 names run ~5 short rows
     instead of 7 taller ones. */
  .map-layout { margin-top: 20px; }
  .map-card { display: none; }
  /* New grouped list: tabs hidden (the map they drive is hidden too), zones
     stacked under their small headings, two columns of compact chips. */
  .areas-tabs, .areas-legend { display: none; }
  .areas-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .areas-grid a, .areas-grid .is-soon { padding: 9px 10px; font-size: 12.5px; min-height: 40px; }

  /* Newsletter — the input and button stack directly on top of each other
     with only 8px between them on mobile (fine as a side-by-side row on
     desktop, too tight once stacked) — easy to fat-finger the button while
     aiming for the field, so that gap is widened just on mobile. */
  .newsletter__form { flex-direction: column; gap: 14px; }
  /* input's `flex: 1` (flex-basis: 0%) is meant for the desktop row, where
     it grows to fill the space beside the button — in the column layout
     above, flex-basis overrides the explicit height, collapsing the field
     down to its content size regardless of the 48px set on it. Reset to a
     fixed, non-growing box here so the real height actually applies. */
  .newsletter__form input { flex: none; width: 100%; }

  .service-hero { padding: 40px 0 44px; }
  /* The flowing-line background used to run the full height of the hero,
     including behind the 4 feature cards below the CTAs — on mobile,
     where copy and cards stack instead of sitting side by side like
     desktop, that meant the busy animated pattern ran on for another
     ~300-400px behind cards that are already opaque white anyway, rather
     than settling into the plain solid blue .service-hero already has as
     its own background. Capped to a fixed height that clears the CTA row
     on every service page (the longest headline/CTA combination still
     ends around 580px in from the top) with a soft fade rather than a hard
     edge, so it reads as "the background settles behind the button" per
     Jayden's request, not a visible cutoff line. */
  .service-hero__paths {
    height: 600px;
    inset: 0 0 auto 0;
    -webkit-mask-image: linear-gradient(to bottom, black 75%, transparent 100%);
    mask-image: linear-gradient(to bottom, black 75%, transparent 100%);
  }
  /* Smaller cards per Jayden's request, and explicitly pinned to 2 columns
     (already the desktop layout too) rather than left to fall back to
     whatever the container's width allows. */
  .service-hero__features { grid-template-columns: repeat(2, 1fr); gap: 8px; max-width: none; }
  .service-hero__feature { padding: 12px; gap: 6px; border-radius: 10px; }
  .service-hero__feature-icon { width: 30px; height: 30px; }
  .service-hero__feature-icon svg { width: 16px; height: 16px; }
  .service-hero__feature h4 { font-size: 12px; }
  .service-hero__feature p { font-size: 10.5px; line-height: 1.35; }

  /* Explore More — 5 pills (every other service minus the current page),
     each sized to its own text, wrap unevenly at phone width and leave an
     orphan alone on the last row (4 then 1) — there's no pill width that
     makes 5 items divide evenly, so rather than fight that, this switches
     to one full-width row each on mobile: still linear/scannable, and with
     every row the same width there's no uneven last line to look wrong. */
  .related-services { flex-direction: column; }
  .related-service { width: 100%; justify-content: space-between; }
  .route-map { display: none; }
  /* What's Included — 8 bullets read as "a lot" stacked one per row on a
     phone; kept 2-across like desktop instead (per Jayden's request —
     "cracking down on what's included" so it reads as a quick skim, not a
     long list to actually read line by line), just smaller/tighter to fit
     comfortably at half the width. */
  .included-grid { gap: 14px 16px; }
  .included-grid li { font-size: 12.5px; gap: 8px; }
  .included-check { width: 19px; height: 19px; }
  .included-check svg { width: 10px; height: 10px; }
  .process-steps { grid-template-columns: 1fr 1fr; gap: 24px; }
  /* Blog teaser — the same 3-card "Latest From The Blog" section on every
     location/service page, per Jayden's request to remove it from mobile
     view entirely (the blog itself is already unlinked from nav/footer
     sitewide; this was the one place its content still showed up on a
     phone). :has() targets the wrapping <section>, which carries no
     unique class of its own, by the blog-teaser-grid it contains, so the
     whole section — heading included — disappears, not just the cards. */
  .section:has(.blog-teaser-grid) { display: none; }
  .oneoff-roadmap__steps { grid-template-columns: 1fr; gap: 24px; }
  .method-grid { grid-template-columns: 1fr; gap: 24px; margin-top: 32px; padding-top: 28px; }
  .testimonial-marquee .t-card { width: 84vw; }
  /* The logo-cloud trust-name row that follows testimonials on every
     location/service page (not present on the homepage's own simpler
     "Client Words" section) wraps as a compact horizontal row on desktop,
     but on mobile it has nothing to wrap into except one long vertical
     stack of 9 company names — exactly the "scrap every testimonial [add-
     on] from mobile, use the homepage one" complexity Jayden flagged.
     Hidden here so mobile testimonials end the same clean way the
     homepage's do everywhere this component appears. */
  .testimonial-divider, .logo-cloud__row { display: none; }

  /* Location pages */
  .location-hero { padding: 40px 0 44px; }
  /* 4 trust facts, previously one per row (flex-wrap just fell back to a
     single column since none of these phrases are short enough to share a
     row on their own) — explicit 2-column grid instead, so it's a clean
     2x2 every time regardless of exact phrase length. */
  .location-hero__facts { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 12px; }
  .location-hero__fact { font-size: 12.5px; }
  .location-hero .heritage__art { min-height: 200px; }
  .oneoff-grid { grid-template-columns: 1fr; }

  /* Get a Quote wizard */
  .quote-panel { padding: 20px; }
  .quote-rail__num { width: 28px; height: 28px; font-size: 11.5px; }
  .quote-rail__label { font-size: 10px; }
  .quote-rail__connector { margin: 13px 4px 0; }
  /* Kept at 2 columns on mobile (was forced to 1 before) per Jayden's
     request — same "one column left, one column right" layout as desktop
     rather than every checkbox stacking into one long list. */
  .quote-choice-grid { gap: 8px; }
  .quote-choice { padding: 10px 12px; }
  .quote-nav { flex-wrap: wrap; }
}

/* Small print credit for an openly licensed photo, kept out of the picture itself. */
.footer-bottom .footer-credit { flex-basis: 100%; font-size: 11px; opacity: 0.6; }
.footer-bottom .footer-credit a { color: inherit; text-decoration: underline; }

/* Blog article ------------------------------------------------------------
   A plain, calm reading page rather than another animated hero — this is
   the one page type on the site whose actual job is being read start to
   finish, so the design gets out of the way of that instead of competing
   with it the way a moving background would. */
.article-hero {
  padding: 56px 0 40px;
  border-bottom: 1px solid var(--cream-line);
  text-align: center;
}
.article-hero .eyebrow { justify-content: center; }
.article-hero h1 {
  margin-top: 14px;
  font-size: clamp(30px, 4.2vw, 44px);
  line-height: 1.16;
  max-width: 760px;
  margin-left: auto;
  margin-right: auto;
}
.article-hero__dek {
  margin-top: 16px;
  font-size: 17px;
  color: var(--ink-soft);
  max-width: 620px;
  margin-left: auto;
  margin-right: auto;
}
.article-meta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 26px;
  font-size: 13.5px;
  color: var(--ink-soft);
  font-weight: 600;
}
.article-meta__avatar {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--blue-pale);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 12px;
  flex-shrink: 0;
}
.article-meta__dot { width: 3px; height: 3px; border-radius: 50%; background: var(--ink-soft); opacity: 0.5; }

/* Article page — reworked per Jayden's 23 Sept feedback: the old version
   was just black text on a plain white page start to finish, which read
   as flat/thin compared to a real editorial blog. This adds the things he
   pointed at specifically: a tinted page background so the article reads
   as a distinct card sitting on the page (not just "more white"), a
   bigger lead paragraph so the type has real hierarchy instead of one
   flat size throughout, a second in-article photo with a caption, a
   native "advert" callout block breaking up the text partway through
   (cross-promoting another post or a quote, the way a real site would
   sell ad space if it had any), and a right-hand sidebar on desktop with
   a quote CTA and further reading — the "something on the right" he
   described from blogs he's used as the standard. */
body.blog-post-page { background: var(--cream-deep); }

.article-wrap { padding: 0 0 64px; }
.article-layout {
  max-width: 1040px;
  margin: 0 auto;
  padding: 0 24px;
  display: grid;
  grid-template-columns: 1fr 300px;
  gap: 40px;
  align-items: start;
}
.article-card {
  background: var(--white);
  border-radius: 20px;
  box-shadow: var(--shadow-card);
  overflow: hidden;
  margin-top: -32px;
  position: relative;
  z-index: 2;
}

.article-body {
  max-width: 640px;
  margin: 0 auto;
  padding: 48px 24px 8px;
  color: var(--ink);
  font-size: 16.5px;
  line-height: 1.75;
}
.article-body > *:first-child { margin-top: 0; }
.article-body p { margin-top: 20px; }
.article-body h2 { font-size: clamp(22px, 2.6vw, 27px); margin-top: 44px; line-height: 1.25; }
.article-body h3 { font-size: 18px; margin-top: 32px; }
.article-body ul, .article-body ol { margin-top: 18px; padding-left: 22px; display: flex; flex-direction: column; gap: 10px; }
.article-body li { line-height: 1.6; }
.article-body a { color: var(--blue-brand); font-weight: 600; }
.article-body blockquote {
  margin: 32px 0;
  padding: 20px 24px;
  border-left: 3px solid var(--blue-brand);
  background: var(--blue-pale);
  border-radius: 0 10px 10px 0;
  font-size: 17px;
  color: var(--blue-deep);
  font-weight: 600;
}
/* The opening paragraph, set larger and softer than body copy — real
   typographic hierarchy instead of one flat size for the whole piece. */
.article-body p.article-lead {
  font-size: 20px;
  line-height: 1.55;
  color: var(--ink-soft);
  font-weight: 500;
}

/* Second in-article photo, roughly a third of the way through each post —
   "more photos with text" was one of the specific things flagged. */
.article-figure { margin: 36px 0; }
.article-figure img { width: 100%; border-radius: 12px; display: block; aspect-ratio: 16/9; object-fit: cover; }
.article-figure figcaption { margin-top: 10px; font-size: 12.5px; color: var(--ink-soft); text-align: center; }

/* Native "advert" — this is real self-promotion, not paid advertising
   (nobody's buying space on this blog), styled the way an actual ad slot
   would be so it reads as a deliberate break in the text rather than
   just another link, the same pattern most content blogs use to keep a
   reader on the site. */
.article-callout {
  margin: 40px 0;
  padding: 22px;
  border-radius: 14px;
  background: var(--blue-pale);
  border: 1px solid var(--blue-sky);
  display: flex;
  align-items: center;
  gap: 16px;
}
.article-callout__icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: var(--white);
  color: var(--blue-brand);
  display: flex;
  align-items: center;
  justify-content: center;
}
.article-callout__label { display: block; font-size: 10.5px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--blue-deep); opacity: 0.7; }
.article-callout a.article-callout__link { display: block; margin-top: 2px; font-size: 15.5px; font-weight: 700; color: var(--blue-deep); text-decoration: none; }
.article-callout a.article-callout__link:hover { text-decoration: underline; }
.article-callout p { margin: 2px 0 0; font-size: 13px; color: var(--ink-soft); }

.article-cta {
  max-width: 592px;
  margin: 16px auto 0;
  padding: 28px;
  border-radius: 14px;
  background: var(--blue-brand);
  color: var(--white);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}
.article-cta h3 { color: var(--white); font-size: 20px; margin: 0; }
.article-cta p { margin: 6px 0 0; color: rgba(255, 255, 255, 0.82); font-size: 14.5px; }
.article-cta .btn { flex-shrink: 0; }
.article-card .article-cta { padding-bottom: 28px; margin-bottom: 40px; }

/* Sidebar — sticky on desktop, the "something on the right" from the
   blogs Jayden's using as a reference. Its own white card too, matching
   the main article card rather than floating loose on the tinted page. */
.article-sidebar { position: sticky; top: 100px; display: flex; flex-direction: column; gap: 20px; }
.article-sidebar__card {
  background: var(--white);
  border-radius: 16px;
  box-shadow: var(--shadow-card);
  padding: 22px;
}
.article-sidebar__cta h4 { font-size: 16px; }
.article-sidebar__cta p { margin-top: 8px; font-size: 13px; color: var(--ink-soft); line-height: 1.55; }
.article-sidebar__cta .btn { margin-top: 14px; width: 100%; justify-content: center; font-size: 13.5px; padding: 11px 16px; }
.article-sidebar__more h4 { font-size: 12.5px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-soft); }
.article-sidebar__link {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
  text-decoration: none;
  color: inherit;
}
.article-sidebar__link:first-of-type { margin-top: 16px; }
.article-sidebar__link img { width: 56px; height: 56px; border-radius: 8px; object-fit: cover; flex-shrink: 0; }
.article-sidebar__link span { font-size: 13px; font-weight: 700; line-height: 1.35; color: var(--ink); }
.article-sidebar__link:hover span { color: var(--blue-brand); }

@media (max-width: 980px) {
  .article-layout { grid-template-columns: 1fr; }
  .article-sidebar { position: static; flex-direction: row; overflow-x: auto; }
  .article-sidebar__card { flex: 1; min-width: 240px; }
}

@media (max-width: 760px) {
  .article-hero { padding: 40px 0 32px; }
  .article-card { margin-top: -20px; border-radius: 16px; }
  .article-body { padding: 32px 18px 0; font-size: 15.5px; }
  .article-body p.article-lead { font-size: 17.5px; }
  .article-cta { flex-direction: column; align-items: flex-start; padding: 22px; }
  .article-sidebar { flex-direction: column; }
  .article-callout { flex-direction: column; align-items: flex-start; }
}

/* ==========================================================================
   Article v2 — pilot on colour-coded-cleaning-cloths-explained.html only
   (23 Sept). Everything is scoped to body.blog-post-page--v2 or to new
   class names so the other 8 posts are untouched until Jayden signs this
   look off, then it gets rolled out to them.
   What changed against v1, per his notes on the first version:
   - hero uses the same animated dark-blue shader as the blog index, and
     the card now starts BELOW the hero instead of overlapping up into it
   - no eyebrow label above the title
   - the mid-article "advert" callout and the wide CTA strip at the bottom
     of the text are gone from the reading column (they broke the text up);
     that job moves to a tall, bold CTA in the sidebar instead
   - "More from the blog" is now three large image cards, not 56px thumbs
   - the plain bullet list of colour codes is a 2x2 set of colour cards
   ========================================================================== */
.article-hero--wave {
  position: relative;
  overflow: hidden;
  background: var(--blue-deep);
  border-bottom: 0;
  padding: 76px 0 104px;
}
.article-hero--wave .container { position: relative; z-index: 2; }
.article-hero--wave h1 { color: var(--white); margin-top: 0; }
.article-hero--wave .article-hero__dek { color: rgba(255, 255, 255, 0.86); }
.article-hero--wave .article-meta { color: rgba(255, 255, 255, 0.9); flex-wrap: wrap; row-gap: 6px; }
/* each byline item stays on one line; the row wraps between items instead
   of breaking names/dates in half once there are three of them */
.article-meta > * { white-space: nowrap; }
.article-hero--wave .article-meta__avatar { background: rgba(255, 255, 255, 0.2); color: var(--white); }
.article-hero--wave .article-meta__dot { background: var(--white); }

body.blog-post-page--v2 .article-layout { padding-top: 48px; }
body.blog-post-page--v2 .article-card { margin-top: 0; }
body.blog-post-page--v2 .article-body { padding-bottom: 44px; }
body.blog-post-page--v2 .article-sidebar { position: static; flex-direction: column; overflow: visible; gap: 32px; }

/* Colour-code legend: the four cloth colours as cards instead of a bullet list */
.article-body .color-codes { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 22px; }
.article-body .color-code {
  --cc: var(--blue-brand);
  border: 1px solid var(--cream-line);
  border-top: 4px solid var(--cc);
  border-radius: 14px;
  padding: 16px 16px 18px;
  background: var(--white);
}
.article-body .color-code__chip { display: inline-flex; align-items: center; gap: 8px; font-weight: 800; font-size: 14.5px; color: var(--ink); }
.article-body .color-code__chip::before { content: ""; width: 14px; height: 14px; border-radius: 50%; background: var(--cc); }
.article-body .color-code p { margin: 10px 0 0; font-size: 14px; line-height: 1.55; color: var(--ink-soft); }
/* prefixed with .article-body so they out-rank the base .color-code rule's
   default --cc (same specificity before, and the default won) */
.article-body .color-code--blue { --cc: #2F6FD6; }
.article-body .color-code--green { --cc: #2E9E5B; }
.article-body .color-code--red { --cc: #D9443A; }
.article-body .color-code--yellow { --cc: #E8B923; }

/* Tall, bold sidebar CTA */
.side-cta {
  background: var(--blue-brand);
  color: var(--white);
  border-radius: 18px;
  padding: 28px 24px;
  box-shadow: var(--shadow-card);
}
.side-cta__icon { width: 46px; height: 46px; border-radius: 12px; background: rgba(255, 255, 255, 0.16); display: flex; align-items: center; justify-content: center; }
.side-cta h4 { margin-top: 18px; color: var(--white); font-size: 21px; line-height: 1.25; font-weight: 800; }
.side-cta p { margin-top: 10px; font-size: 14px; line-height: 1.6; color: rgba(255, 255, 255, 0.86); }
.side-cta__list { list-style: none; padding: 0; margin: 18px 0 0; display: flex; flex-direction: column; gap: 10px; }
.side-cta__list li { display: flex; gap: 10px; align-items: flex-start; font-size: 13.5px; font-weight: 600; line-height: 1.4; }
.side-cta__list li::before {
  content: "";
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22) url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6 9 17l-5-5'/></svg>") center / 11px no-repeat;
}
.side-cta .btn { margin-top: 22px; width: 100%; justify-content: center; padding-left: 12px; padding-right: 12px; font-size: 13.5px; }
.side-cta__phone { display: block; margin-top: 14px; text-align: center; font-size: 13px; font-weight: 600; color: rgba(255, 255, 255, 0.92); text-decoration: none; }
.side-cta__phone:hover { text-decoration: underline; }

/* "More from the blog" as big image cards */
.side-more__label { margin: 0 0 14px 4px; font-size: 12.5px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-soft); }
.side-more__list { display: grid; gap: 18px; }
.side-post {
  display: block;
  text-decoration: none;
  color: inherit;
  background: var(--white);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: var(--shadow-card);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.side-post:hover { transform: translateY(-4px); box-shadow: 0 24px 44px -24px rgba(11, 134, 160, 0.4); }
.side-post__media { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--blue-pale); }
.side-post__media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.5s ease; }
.side-post:hover .side-post__media img { transform: scale(1.07); }
.side-post__tag {
  position: absolute;
  left: 12px;
  bottom: 12px;
  padding: 5px 11px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--blue-deep);
}
.side-post__body { padding: 16px 18px 18px; }
.side-post__title { display: block; font-size: 16px; font-weight: 800; line-height: 1.3; color: var(--ink); }
.side-post:hover .side-post__title { color: var(--blue-brand); }
.side-post__meta { display: flex; align-items: center; gap: 6px; margin-top: 10px; font-size: 12px; font-weight: 600; color: var(--ink-soft); }

@media (max-width: 980px) {
  .side-more__list { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 760px) {
  .article-hero--wave { padding: 52px 0 76px; }
  .article-hero--wave .article-meta { justify-content: center; column-gap: 14px; }
  .article-hero--wave .article-meta__dot { display: none; }
  body.blog-post-page--v2 .article-layout { padding-top: 28px; }
  .side-more__list { grid-template-columns: 1fr; }
  .article-body .color-codes { grid-template-columns: 1fr; }
}

/* Service hero — flowing colour field (js/flow-field.js), piloted on
   services/office-cleaning only until Jayden approves it, then the other five
   service pages. Replaces the contour-line background (js/flow-topo.js) on
   pages that opt in via .service-hero--field. The section's own colour is the
   field's dark ground, so where the field fades out on mobile it fades into
   the same colour rather than into the plain brand blue. */
.service-hero--field { background: #04212B; }
.service-hero__field { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
@media (max-width: 760px) {
  /* same idea as the older paths background: the animation settles behind
     the CTA row and the feature cards below sit on plain colour */
  .service-hero__field {
    height: 600px;
    inset: 0 0 auto 0;
    -webkit-mask-image: linear-gradient(to bottom, black 75%, transparent 100%);
    mask-image: linear-gradient(to bottom, black 75%, transparent 100%);
  }
}

/* One-off service pages — hero, spacing and "other one-off services" ------
   The price card runs the full width of the feature grid (longer) with a
   large price figure; the hero buttons are bigger than the service pages'.
   The heritage photo and 4-item "why it matters" grid reuse the shared
   components. The trust strip is trimmed and the FAQ below it starts closer,
   so the two don't leave a big empty band. */
.service-hero--oneoff .service-hero__ctas .btn { padding: 18px 34px; font-size: 16px; }
.service-hero__feature--price { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: 18px; padding: 20px 22px; }
.service-hero__feature--price .service-hero__feature-icon { width: 48px; height: 48px; flex-shrink: 0; }
.service-hero__feature--price h4 { font-size: 30px; line-height: 1.1; color: var(--blue-brand); font-weight: 800; }
.service-hero__feature--price p { font-size: 13px; margin-top: 4px; }
.oneoff-strip { padding: 36px 0; }
.oneoff-strip + .section { padding-top: 40px; }
.oneoff-grid--three { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 980px) { .oneoff-grid--three { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 760px) {
  .oneoff-grid--three { grid-template-columns: 1fr; }
  .service-hero--oneoff .service-hero__ctas .btn { padding: 16px 28px; }
  .service-hero__feature--price { padding: 14px 16px; gap: 12px; }
  .service-hero__feature--price .service-hero__feature-icon { width: 36px; height: 36px; }
  .service-hero__feature--price h4 { font-size: 22px; }
}
/* Price card + guarantee card each take a full row, with the two smaller
   cards side by side between them, so the four points sit as 1 / 2 / 1
   instead of leaving one card alone on the last row. */
.service-hero--oneoff .service-hero__feature:last-child { grid-column: 1 / -1; }
@media (max-width: 760px) {
  /* One-off pages: the photo stays on mobile, as a short banner above the copy. */
  #what-is-it .heritage__art--photo { display: block; min-height: 210px; }
}
/* .hero-reach carries a 32px top margin meant for the hero; inside the
   trust strip it stacked on the strip's own padding and made the space above
   the badges more than double the space below. */
.oneoff-strip .hero-reach { margin-top: 0; }
/* Our Story hero: temporary "placeholder" label over the stand-in photo. */
.story-hero__placeholder-tag {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  padding: 10px 22px; border-radius: 999px;
  background: rgba(4, 33, 43, 0.72); border: 1px solid rgba(255, 255, 255, 0.5);
  color: var(--white); font-size: 14px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  backdrop-filter: blur(4px); z-index: 2;
}

/* Glass buttons -------------------------------------------------------------
   Ported from the 21st.dev "Glass Button" (React + Tailwind): a frosted card
   with an icon tile, title, subtitle and arrow; on hover it lifts, a soft
   shine sweeps across and the arrow slides. Recoloured from indigo to
   translucent white so it sits on the site's blue sections. Used as links
   (Explore More on the service pages, the contact hero) and, with
   --static, as non-clickable trust badges (one-off pages). */
.glass-btn {
  position: relative;
  overflow: hidden;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 14px 18px;
  min-width: 0;
  border-radius: 18px;
  border: 1.5px solid rgba(255, 255, 255, 0.4);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.06) 55%, rgba(255, 255, 255, 0.14));
  color: var(--white);
  text-decoration: none;
  text-align: left;
  box-shadow: 0 14px 30px -14px rgba(2, 30, 40, 0.5);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: transform 0.4s ease, box-shadow 0.4s ease, border-color 0.4s ease;
}
.glass-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.28), transparent);
  transform: translateX(-100%);
  transition: transform 0.9s ease;
  pointer-events: none;
}
.glass-btn__icon {
  position: relative;
  flex-shrink: 0;
  width: 46px;
  height: 46px;
  border-radius: 12px;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.34), rgba(255, 255, 255, 0.12));
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background 0.3s ease;
}
.glass-btn__icon svg { width: 22px; height: 22px; transition: transform 0.3s ease; }
.glass-btn__text { position: relative; flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.glass-btn__title { font-family: var(--font-display); font-weight: 700; font-size: 16px; line-height: 1.25; color: var(--white); }
.glass-btn__sub { font-size: 13px; line-height: 1.35; color: rgba(255, 255, 255, 0.75); overflow-wrap: anywhere; }
.glass-btn__arrow { position: relative; flex-shrink: 0; width: 18px; height: 18px; opacity: 0.45; transition: opacity 0.3s ease, transform 0.3s ease; }
a.glass-btn:hover, a.glass-btn:focus-visible { transform: translateY(-4px) scale(1.02); border-color: rgba(255, 255, 255, 0.75); box-shadow: 0 20px 36px -14px rgba(2, 30, 40, 0.65); }
a.glass-btn:hover::before, a.glass-btn:focus-visible::before { transform: translateX(100%); }
a.glass-btn:hover .glass-btn__icon, a.glass-btn:focus-visible .glass-btn__icon { background: linear-gradient(135deg, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0.18)); }
a.glass-btn:hover .glass-btn__icon svg { transform: scale(1.1); }
a.glass-btn:hover .glass-btn__arrow, a.glass-btn:focus-visible .glass-btn__arrow { opacity: 1; transform: translateX(4px); }
a.glass-btn:active { transform: scale(0.97); }
@media (prefers-reduced-motion: reduce) {
  .glass-btn, .glass-btn::before, .glass-btn__arrow { transition: none; }
}
/* Layouts: rows of three (5 items = 3 over 2 wider), collapsing on smaller screens */
.glass-grid { display: grid; grid-template-columns: repeat(6, 1fr); gap: 16px; }
.glass-grid > .glass-btn { grid-column: span 2; }
.glass-grid > .glass-btn:nth-child(n+4) { grid-column: span 3; }
.glass-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.hero .glass-row, .service-hero .glass-row { margin-top: 32px; }
@media (max-width: 980px) {
  .glass-grid { grid-template-columns: repeat(2, 1fr); }
  .glass-grid > .glass-btn, .glass-grid > .glass-btn:nth-child(n+4) { grid-column: auto; }
  .glass-grid > .glass-btn:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 760px) {
  .glass-grid, .glass-row { grid-template-columns: 1fr; gap: 10px; }
  .glass-grid > .glass-btn:last-child:nth-child(odd) { grid-column: auto; }
  .glass-btn { padding: 12px 14px; gap: 12px; border-radius: 16px; }
  .glass-btn__icon { width: 40px; height: 40px; }
}
/* Contact hero: the copy column is narrow, so let the three glass buttons run
   wider than it (centred on the same axis) — otherwise the email wraps. */
@media (min-width: 981px) {
  #contact-hero .glass-row { width: min(1120px, calc(100vw - 48px)); margin-left: calc(50% - min(560px, 50vw - 24px)); }
}

/* Contact page: tighter hero and team section; the intro line under
   "A small team" runs as one long line on desktop. */
#contact-hero { padding-top: 40px; padding-bottom: 48px; }
#contact-hero h1 { margin-top: 0; }
#team.section { padding: 56px 0; }
#team .section-head p { max-width: none; margin-top: 10px; }
@media (min-width: 981px) { #team .section-head p { white-space: nowrap; } }
.glass-row .glass-btn__title { white-space: nowrap; }

/* Desktop: let section headings run across the page instead of sitting in a
   narrow 640px column, and tighten the vertical rhythm (less dead space
   between sections). Mobile is untouched — it has its own spacing. Centred
   heads that set their own inline max-width (FAQ, testimonials) keep it. */
@media (min-width: 761px) {
  .section-head { max-width: none; margin-bottom: 32px; }
  .section-head p { max-width: 110ch; }
  .section-head-row .section-head { flex: 1; }
  .section { padding: 72px 0; }
  .section--tight { padding: 48px 0; }
}
@media (min-width: 761px) { .cta-band h2 { max-width: none; } }

/* Blog index — hero with a featured post + a bento grid of mixed tile sizes.
   Replaces the uniform 3-column card grid: one big square, two long
   horizontal cards, two tall ones and a few standard ones, broken up with
   non-post tiles (quote, newsletter, stats, phone). Desktop is an explicit
   12-column placement; below 981px everything reflows to 1–2 columns. */
.blog-hero__facts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.blog-hero__facts span {
  padding: 9px 16px; border-radius: 999px; font-size: 13.5px; color: rgba(255, 255, 255, 0.85);
  background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.28);
}
.blog-hero__facts strong { color: var(--white); }
.blog-hero__feature {
  display: block; text-decoration: none; color: var(--ink); background: var(--white);
  border-radius: 20px; overflow: hidden; box-shadow: 0 30px 60px -24px rgba(2, 30, 40, 0.6);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.blog-hero__feature:hover { transform: translateY(-5px) rotate(-0.4deg); box-shadow: 0 38px 70px -24px rgba(2, 30, 40, 0.7); }
.blog-hero__feature-media { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.blog-hero__feature-media img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.6s ease; }
.blog-hero__feature:hover img { transform: scale(1.05); }
.blog-hero__badge {
  position: absolute; left: 14px; top: 14px; padding: 6px 14px; border-radius: 999px;
  background: var(--white); color: var(--blue-deep); font-size: 11.5px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
}
.blog-hero__feature-body { padding: 20px 24px 24px; display: flex; flex-direction: column; gap: 8px; }
.blog-hero__feature-tag { font-size: 11.5px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--blue-brand); }
.blog-hero__feature h2 { font-size: 21px; line-height: 1.28; color: var(--ink); margin: 0; }
.blog-hero__feature-meta { font-size: 12.5px; color: var(--ink-soft); }

.blog-bento { display: grid; grid-template-columns: repeat(12, 1fr); grid-auto-rows: 150px; gap: 20px; }
.bt {
  position: relative; overflow: hidden; border-radius: 20px; text-decoration: none; color: var(--ink);
  background: var(--white); border: 1px solid var(--cream-line); box-shadow: var(--shadow-card);
  display: flex; flex-direction: column; min-width: 0;
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
a.bt:hover { transform: translateY(-5px); box-shadow: 0 26px 46px -22px rgba(11, 134, 160, 0.45); border-color: var(--blue-sky); }
.bt h3 { font-size: 17px; line-height: 1.3; margin: 0; }
.bt__img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.6s ease; }
a.bt:hover .bt__img { transform: scale(1.06); }
.bt__media { position: relative; flex: 1 1 0; min-height: 0; overflow: hidden; background: var(--blue-pale); }
.bt__tag {
  position: absolute; left: 12px; bottom: 12px; padding: 5px 12px; border-radius: 999px; z-index: 2;
  background: rgba(255, 255, 255, 0.92); color: var(--blue-deep); font-size: 11px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
}
.bt__meta { font-size: 12px; color: var(--ink-soft); line-height: 1.4; }
.bt__meta strong { color: var(--ink); }
.bt__excerpt { font-size: 14px; line-height: 1.55; color: var(--ink-soft); margin: 0; }
.bt__go {
  position: absolute; right: 14px; top: 14px; width: 38px; height: 38px; border-radius: 50%; z-index: 3;
  background: var(--white); color: var(--blue-brand); display: flex; align-items: center; justify-content: center;
  box-shadow: 0 8px 18px -8px rgba(2, 30, 40, 0.5); transition: transform 0.3s ease, background 0.3s ease, color 0.3s ease;
}
.bt__go svg { width: 18px; height: 18px; }
a.bt:hover .bt__go { transform: rotate(45deg); background: var(--blue-brand); color: var(--white); }
/* standard: photo over text */
.bt--std .bt__body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 8px; }
.bt--std .bt__go { display: none; }
/* long: photo left, text right */
.bt--long { flex-direction: row; }
.bt--long .bt__media { flex: 0 0 44%; }
.bt--long .bt__body { flex: 1; padding: 24px 28px; display: flex; flex-direction: column; justify-content: center; gap: 10px; }
.bt--long .bt__body h3 { font-size: 20px; }
.bt--long .bt__go { right: 14px; top: auto; bottom: 14px; }
/* big + tall: full-bleed photo with text over it */
.bt--big, .bt--tall { color: var(--white); border: 0; }
.bt--big .bt__img, .bt--tall .bt__img { position: absolute; inset: 0; }
.bt__shade { position: absolute; inset: 0; background: linear-gradient(to top, rgba(3, 26, 35, 0.92) 0%, rgba(3, 26, 35, 0.55) 45%, rgba(3, 26, 35, 0.05) 80%); }
.bt--big .bt__body, .bt--tall .bt__body { position: relative; z-index: 2; margin-top: auto; padding: 26px; display: flex; flex-direction: column; gap: 10px; align-items: flex-start; }
.bt--big h3, .bt--tall h3 { color: var(--white); font-size: 20px; }
.bt--big h3 { font-size: 30px; line-height: 1.18; max-width: 22ch; }
.bt--big .bt__excerpt, .bt--tall .bt__excerpt { color: rgba(255, 255, 255, 0.8); }
.bt--big .bt__meta, .bt--tall .bt__meta { color: rgba(255, 255, 255, 0.75); }
.bt--big .bt__meta strong, .bt--tall .bt__meta strong { color: var(--white); }
.bt--big .bt__tag, .bt--tall .bt__tag { position: static; }
/* non-post tiles */
.bt__kicker { font-size: 11.5px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.8; }
.bt--quote, .bt--call { padding: 26px; gap: 10px; justify-content: center; color: var(--white); border: 0; background: linear-gradient(140deg, var(--blue-deep), var(--blue-brand)); }
.bt--quote h3, .bt--call h3 { color: var(--white); font-size: 22px; }
.bt--quote p, .bt--call p { margin: 0; font-size: 14px; color: rgba(255, 255, 255, 0.82); line-height: 1.5; }
.bt__btn { align-self: flex-start; display: inline-flex; align-items: center; gap: 8px; margin-top: 6px; padding: 11px 20px; border-radius: 999px; background: var(--white); color: var(--blue-deep); font-weight: 700; font-size: 14px; }
.bt__btn svg { width: 16px; height: 16px; transition: transform 0.3s ease; }
a.bt:hover .bt__btn svg { transform: translateX(4px); }
.bt--call { background: linear-gradient(140deg, #053B47, var(--blue-deep)); }
.bt--news { padding: 26px; gap: 12px; justify-content: center; background: var(--blue-pale); border-color: transparent; }
.bt--news .bt__kicker { color: var(--blue-deep); }
.bt--news h3 { font-size: 21px; }
.bt__form { display: flex; gap: 8px; }
.bt__form input { flex: 1; min-width: 0; height: 44px; padding: 0 14px; border-radius: 10px; border: 1px solid var(--cream-line); font: inherit; font-size: 14px; background: var(--white); }
.bt__form input:focus { outline: 2px solid var(--blue-brand); outline-offset: 1px; }
.bt__form button { height: 44px; padding: 0 18px; border-radius: 10px; border: 0; background: var(--blue-brand); color: var(--white); font: inherit; font-weight: 700; font-size: 14px; cursor: pointer; }
.bt__thanks { margin: 0; font-weight: 600; color: var(--blue-deep); }
.bt--stats { flex-direction: row; align-items: center; justify-content: space-around; padding: 20px; background: var(--white); }
.bt--stats div { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 4px; }
.bt--stats strong { font-family: var(--font-display); font-size: 34px; font-weight: 800; color: var(--blue-brand); line-height: 1; }
.bt--stats span { font-size: 12px; color: var(--ink-soft); max-width: 12ch; }

@media (min-width: 981px) {
  .bt1 { grid-column: 1 / 7; grid-row: 1 / 5; }
  .bt2 { grid-column: 7 / 13; grid-row: 1 / 3; }
  .bt3 { grid-column: 7 / 10; grid-row: 3 / 5; }
  .bt4 { grid-column: 10 / 13; grid-row: 3 / 5; }
  .bt5 { grid-column: 1 / 5; grid-row: 5 / 7; }
  .bt6 { grid-column: 5 / 9; grid-row: 5 / 9; }
  .bt7 { grid-column: 9 / 13; grid-row: 5 / 7; }
  .bt8 { grid-column: 1 / 5; grid-row: 7 / 9; }
  .bt9 { grid-column: 9 / 13; grid-row: 7 / 9; }
  .bt10 { grid-column: 1 / 9; grid-row: 9 / 11; }
  .bt11 { grid-column: 9 / 13; grid-row: 9 / 13; }
  .bt12 { grid-column: 1 / 5; grid-row: 11 / 13; }
  .bt13 { grid-column: 5 / 9; grid-row: 11 / 13; }
}
@media (max-width: 980px) {
  .blog-bento { grid-template-columns: repeat(2, 1fr); grid-auto-rows: auto; grid-auto-flow: dense; gap: 16px; }
  .bt { min-height: 300px; }
  .bt1, .bt2, .bt10 { grid-column: 1 / -1; }
  .bt--big, .bt--tall { min-height: 360px; }
  .bt--std { min-height: 320px; }
  .bt--std .bt__media { flex: 0 0 170px; }
  .bt--quote, .bt--news, .bt--call, .bt--stats { min-height: 0; }
}
@media (max-width: 760px) {
  .blog-bento { grid-template-columns: 1fr; }
  .bt1, .bt2, .bt10 { grid-column: auto; }
  .bt--long { flex-direction: column; }
  .bt--long .bt__media { flex: 0 0 190px; }
  .bt--big h3 { font-size: 24px; }
  .bt__go { width: 34px; height: 34px; }
  .bt--stats strong { font-size: 28px; }
  .blog-hero__feature h2 { font-size: 18px; }
}
.bt--links { padding: 24px 26px; gap: 10px; justify-content: center; }
.bt--links .bt__kicker { color: var(--blue-brand); }
.bt--links h3 { font-size: 19px; }
.bt--links ul { list-style: none; padding: 0; margin: 4px 0 0; display: grid; grid-template-columns: 1fr 1fr; gap: 6px 18px; }
.bt--links a { display: flex; align-items: center; gap: 8px; padding: 6px 0; color: var(--blue-deep); font-weight: 600; font-size: 14px; text-decoration: none; border-bottom: 1px solid var(--cream-line); }
.bt--links a::after { content: "→"; margin-left: auto; transition: transform 0.2s ease; }
.bt--links a:hover::after { transform: translateX(3px); }
.blog-more { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
.blog-more .bt { min-height: 0; }
.blog-more .bt__media { flex: none; aspect-ratio: 16 / 9; }
.blog-more .bt--std .bt__body { flex: 1; }
@media (max-width: 980px) { .blog-more { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 760px) { .blog-more { grid-template-columns: 1fr; } }

/* Quote / careers wizard — the panel keeps a fixed width and simply grows
   downwards when a step is longer (Step 4's contact form). Fields in a row
   are forced to identical widths and heights (select and text inputs
   differ by a pixel otherwise, and long option text could push a column
   wider). */
.quote-field-row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
.quote-field-row .contact-form__field select,
.quote-field-row .contact-form__field input { width: 100%; min-width: 0; height: 46px; box-sizing: border-box; }

/* Contact hero: title on one line, more breathing room top and bottom. */
#contact-hero { padding-top: 80px; padding-bottom: 88px; }
@media (min-width: 981px) {
  #contact-hero .service-hero__inner { max-width: 1000px; }
  #contact-hero h1 { white-space: nowrap; }
}
@media (min-width: 981px) {
  #contact-hero .service-hero__copy, #contact-hero h1 { max-width: none; width: 100%; text-align: center; }
}
/* Steps 1–3 share one height (the tallest of the three) so Next/Back between
   them never moves the panel; Step 4's longer contact form just grows the
   panel downwards. Desktop only — on phones each step keeps its own height. */
@media (min-width: 761px) { .quote-step { min-height: 341px; } }

.section--navy .areas-grid .is-soon { background: rgba(255, 255, 255, 0.86); }

/* Footer v3 — mobile tweaks for the areas band */
@media (max-width: 760px) {
  .footer-areas-band { max-width: none; width: 100%; margin: 0; padding-left: 0; padding-right: 0; }
  .footer-areas-band > h5 { margin-bottom: 14px; }
  .site-footer .footer-areas { gap: 8px 16px; }
  .site-footer h6 { margin: 18px 0 10px; }
}

@media (min-width: 981px) { .footer-top .footer-newsletter { grid-column: 3 / 5; } }
/* "One-Off Cleans" inside the Services column reads as its own heading —
   same bold white style as the column headings. */
.footer-col--services h6 { font-size: 12.5px; color: var(--white); margin: 30px 0 16px; }

/* Mega menus v2 — Services is now three columns (core / specialist / one-off)
   and there's a second dropdown for Sectors. */
.mega-menu--wide { width: 800px; }
.mega-menu--sectors { width: 540px; }
.mega-menu__cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px 14px; }
.mega-menu__col .mega-menu__grid { grid-template-columns: 1fr; }
.mega-menu__label {
  margin: 2px 10px 6px; padding-bottom: 8px; border-bottom: 1px solid var(--cream-line);
  font-size: 11px; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--blue-brand);
}
.mega-menu--wide .mega-menu__grid a { padding: 8px 10px; }
.mega-menu--wide .mega-menu__grid small { font-size: 11.5px; }
@media (max-width: 980px) {
  .mega-menu--wide, .mega-menu--sectors { width: 100%; }
  .mega-menu__cols { grid-template-columns: 1fr; gap: 6px; }
  .mega-menu__label { margin-left: 0; }
}

/* Homepage — the Sectors band ----------------------------------------- */
.glass-grid--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.glass-grid--three > .glass-btn, .glass-grid--three > .glass-btn:nth-child(n+4) { grid-column: auto; }
.sectors-link { color: var(--white); font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.sectors-cta { margin-top: 44px; padding-top: 36px; border-top: 1px solid rgba(255, 255, 255, 0.28); }
@media (max-width: 980px) {
  .glass-grid--three { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .glass-grid--three > .glass-btn:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
@media (max-width: 760px) {
  .glass-grid--three { grid-template-columns: 1fr; }
  .glass-grid--three > .glass-btn:last-child:nth-child(odd) { grid-column: auto; }
  .sectors-cta { margin-top: 32px; padding-top: 28px; }
}
#sectors .section-head p { color: rgba(255, 255, 255, 0.88); }

/* Header fit — with the extra "Sectors" item, tighten the menu on laptop
   widths so the phone number and Get a Quote button never get pushed off. */
.main-nav a.nav-link { white-space: nowrap; }
@media (min-width: 981px) and (max-width: 1279px) {
  .main-nav { gap: 24px; margin-left: 4px; }
  .main-nav ul { gap: 22px; }
  .main-nav a.nav-link { font-size: 14px; }
  .header-phone { display: none; }
}
@media (min-width: 1280px) and (max-width: 1439px) {
  .main-nav ul { gap: 32px; }
}
.header-cta .btn { white-space: nowrap; }
@media (min-width: 981px) and (max-width: 1100px) { .header-cta .btn { padding-left: 16px; padding-right: 16px; } }

/* ==========================================================================
   Homepage hero v2 — deep flowing-colour hero, a live headline, an
   "area checker" and a glass proof row. (The old .hero rules above are no
   longer used by any page.)
   ========================================================================== */
.hero2 { position: relative; overflow: hidden; color: var(--white); padding: 34px 0 28px; }
.hero2__field { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.hero2__inner { position: relative; z-index: 1; display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 56px; align-items: center; }
.hero2__copy { min-width: 0; }
.hero2__pill {
  display: inline-flex; align-items: center; gap: 10px; padding: 8px 16px; border-radius: 999px;
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.04em; color: rgba(255, 255, 255, 0.9);
  background: rgba(255, 255, 255, 0.1); border: 1px solid rgba(255, 255, 255, 0.28);
}
.hero2__pill i { width: 8px; height: 8px; border-radius: 50%; background: #5FE0A8; box-shadow: 0 0 0 4px rgba(95, 224, 168, 0.22); }
.hero2 h1 { margin-top: 0; font-size: clamp(36px, 4.5vw, 56px); line-height: 1.05; font-weight: 800; letter-spacing: -0.025em; color: var(--white); text-wrap: balance; }
/* Fixed-width slot for the rotating word so the headline never re-wraps (and
   the page never jumps) when the word changes. */
.hero2__word-wrap { display: inline-block; min-width: 8em; white-space: nowrap; }
.hero2__word {
  display: inline-block; color: var(--white); transition: opacity 0.3s ease, transform 0.3s ease;
  border-bottom: 4px solid rgba(255, 255, 255, 0.75);
}
.hero2__word.is-out { opacity: 0; transform: translateY(10px); }
.hero2__lede { margin-top: 14px; font-size: 17.5px; line-height: 1.55; color: rgba(255, 255, 255, 0.8); max-width: 54ch; }

.area-check {
  margin-top: 18px; max-width: 540px; padding: 18px 18px 16px; border-radius: 20px;
  background: linear-gradient(140deg, rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0.06));
  border: 1.5px solid rgba(255, 255, 255, 0.38); box-shadow: 0 24px 50px -22px rgba(0, 10, 16, 0.7);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.area-check__label { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-family: var(--font-display); font-weight: 700; font-size: 16px; color: var(--white); }
.area-check__label span { font-family: var(--font-body); font-weight: 500; font-size: 12.5px; color: rgba(255, 255, 255, 0.7); }
.area-check__row { display: flex; gap: 8px; margin-top: 12px; }
.area-check__row input {
  flex: 1; min-width: 0; height: 52px; padding: 0 16px; border-radius: 12px; border: 0; font: inherit; font-size: 15.5px;
  background: var(--white); color: var(--ink);
}
.area-check__row input::placeholder { color: #7A8A90; }
.area-check__row input:focus { outline: 3px solid rgba(143, 227, 245, 0.7); outline-offset: 0; }
.area-check__row .btn { height: 52px; padding: 0 26px; border-radius: 12px; background: var(--blue-brand); color: var(--white); font-size: 15.5px; }
.area-check__row .btn:hover { background: var(--blue-deep); }
.area-check__try { margin-top: 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; font-size: 12.5px; color: rgba(255, 255, 255, 0.7); }
.area-check__try button {
  font: inherit; font-size: 12.5px; font-weight: 600; cursor: pointer; padding: 5px 12px; border-radius: 999px;
  color: var(--white); background: rgba(255, 255, 255, 0.12); border: 1px solid rgba(255, 255, 255, 0.3);
  transition: background 0.15s ease, transform 0.15s ease;
}
.area-check__try button:hover { background: rgba(255, 255, 255, 0.24); transform: translateY(-1px); }
.area-check__result { margin-top: 14px; }
.area-check__yes, .area-check__no { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; border-radius: 14px; background: var(--white); color: var(--ink); animation: area-pop 0.35s cubic-bezier(0.34, 1.56, 0.64, 1); }
.area-check__tick { flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%; background: #1FB57A; color: var(--white); display: flex; align-items: center; justify-content: center; }
.area-check__yes strong, .area-check__no strong { display: block; font-size: 15.5px; color: var(--blue-deep); }
.area-check__yes span, .area-check__no span { display: block; font-size: 13.5px; color: var(--ink-soft); margin-top: 2px; }
.area-check__links { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 10px; }
.area-check__cta { display: inline-block; padding: 9px 18px; border-radius: 999px; background: var(--blue-brand); color: var(--white) !important; font-weight: 700; font-size: 13.5px; text-decoration: none; }
.area-check__links a:not(.area-check__cta), .area-check__yes em a, .area-check__no a { color: var(--blue-brand); font-weight: 600; font-size: 13.5px; }
.area-check__yes em { display: block; margin-top: 8px; font-style: normal; font-size: 12.5px; color: var(--ink-soft); }
@keyframes area-pop { from { opacity: 0; transform: translateY(8px) scale(0.98); } to { opacity: 1; transform: none; } }
.hero2__quote { display: inline-block; margin-top: 14px; color: rgba(255, 255, 255, 0.85); font-weight: 600; font-size: 14.5px; text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, 0.4); padding-bottom: 2px; }
.hero2__quote:hover { color: var(--white); border-color: var(--white); }

.hero2__visual { position: relative; }
.hero2__photo {
  border-radius: 26px; overflow: hidden; aspect-ratio: 4 / 3.7; transform: rotate(1.6deg);
  box-shadow: 0 40px 80px -28px rgba(0, 8, 14, 0.85); border: 6px solid rgba(255, 255, 255, 0.92); background: #0A4F73;
}
.hero2__photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero2__badge {
  position: absolute; display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 999px;
  background: var(--white); color: var(--blue-deep); font-weight: 700; font-size: 13.5px; box-shadow: 0 16px 34px -14px rgba(0, 8, 14, 0.7);
  animation: hero2-float 5s ease-in-out infinite;
}
.hero2__badge svg { color: var(--blue-brand); }
.hero2__badge--a { top: 22px; left: -22px; }
.hero2__badge--b { bottom: 34px; right: -14px; animation-delay: -2.4s; }
@keyframes hero2-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
.hero2__proof { position: relative; z-index: 1; margin-top: 24px; }
.glass-row--four { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.glass-row--four .glass-btn { padding: 12px 14px; gap: 12px; }
.glass-row--four .glass-btn__icon { width: 40px; height: 40px; }
.glass-row--four .glass-btn__title { font-size: 14.5px; }
.glass-row--four .glass-btn__sub { font-size: 12.5px; }

@media (max-width: 980px) {
  .hero2__inner { grid-template-columns: 1fr; gap: 36px; }
  .hero2__visual { max-width: 520px; margin: 0 auto; width: 100%; }
  .glass-row--four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 760px) {
  .hero2 { padding: 22px 0 24px; }
  .hero2__pill { font-size: 11.5px; padding: 7px 12px; }
  .hero2 h1 { font-size: clamp(31px, 9vw, 40px); margin-top: 0; }
  .hero2__lede { font-size: 16px; margin-top: 14px; }
  .area-check { margin-top: 20px; padding: 14px; border-radius: 16px; }
  .area-check__label { flex-direction: column; gap: 2px; font-size: 15px; }
  .area-check__row input, .area-check__row .btn { height: 48px; }
  .area-check__row .btn { padding: 0 18px; }
  .hero2__visual { max-width: none; }
  .hero2__photo { aspect-ratio: 16 / 10; transform: none; border-width: 4px; border-radius: 18px; }
  .hero2__badge { font-size: 12px; padding: 8px 12px; }
  .hero2__badge--a { top: 12px; left: 10px; }
  .hero2__badge--b { bottom: 12px; right: 10px; }
  .hero2__proof { margin-top: 28px; }
  .glass-row--four { grid-template-columns: 1fr 1fr; gap: 8px; }
  .glass-row--four .glass-btn { padding: 10px; gap: 8px; }
  .glass-row--four .glass-btn__icon { width: 32px; height: 32px; }
  .glass-row--four .glass-btn__sub { display: none; }
  .glass-row--four .glass-btn__title { font-size: 12.5px; white-space: normal; }
}
@media (prefers-reduced-motion: reduce) { .hero2__badge { animation: none; } .hero2__word { transition: none; } }
.area-check__yes .area-check__tick { display: flex; margin: 0; color: var(--white); }

/* Non-link glass cards (homepage proof row, one-off trust strip) get the same
   hover glisten as the glass links: a soft shine sweeps across, the card lifts
   a little and the icon tile brightens. */
div.glass-btn { cursor: default; }
div.glass-btn:hover { transform: translateY(-4px) scale(1.02); border-color: rgba(255, 255, 255, 0.75); box-shadow: 0 20px 36px -14px rgba(2, 30, 40, 0.65); }
div.glass-btn:hover::before { transform: translateX(100%); }
div.glass-btn:hover .glass-btn__icon { background: linear-gradient(135deg, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0.18)); }
div.glass-btn:hover .glass-btn__icon svg { transform: scale(1.1); }

/* Hero v2 — the quote is a proper button (with the phone number beside it); the
   van photo is marked as a placeholder until a real photo replaces it. */
.hero2__photo { position: relative; }
.hero2__ctas { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; margin-top: 18px; }
.hero2__btn { background: var(--white); color: var(--blue-deep); font-weight: 700; padding: 16px 30px; font-size: 16px; border-radius: 12px; box-shadow: 0 16px 34px -14px rgba(0, 20, 30, 0.6); transition: transform 0.2s ease, box-shadow 0.2s ease; }
.hero2__btn:hover { transform: translateY(-2px) scale(1.02); box-shadow: 0 22px 40px -14px rgba(0, 20, 30, 0.7); }
.hero2__call { color: var(--white); font-weight: 600; font-size: 15px; text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, 0.5); padding-bottom: 2px; }
.hero2__call:hover { border-color: var(--white); }
@media (max-width: 760px) { .hero2__ctas { gap: 14px; } .hero2__btn { width: 100%; text-align: center; justify-content: center; } }

/* Sticky Call / Get a quote bar on phones (added by js/script.js). */
.mobile-cta { display: none; }
@media (max-width: 760px) {
  .mobile-cta {
    display: grid; grid-template-columns: 1fr 1.4fr; gap: 10px; position: fixed; left: 0; right: 0; bottom: 0; z-index: 90;
    padding: 10px 14px calc(10px + env(safe-area-inset-bottom)); background: rgba(255, 255, 255, 0.96);
    border-top: 1px solid var(--cream-line); box-shadow: 0 -10px 30px -18px rgba(2, 30, 40, 0.5);
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  }
  .mobile-cta a { display: flex; align-items: center; justify-content: center; gap: 8px; height: 46px; border-radius: 12px; font-weight: 700; font-size: 15px; text-decoration: none; }
  .mobile-cta__call { color: var(--blue-deep); border: 1.5px solid var(--blue-brand); background: var(--white); }
  .mobile-cta__quote { color: var(--white); background: var(--blue-brand); }
  body.has-mobile-cta { padding-bottom: 72px; }
}

/* Homepage — proof strip (rating, clients, quotes) and the tabbed service cards
   (taken from the homepage B test). */
/* proof */
.hb-proof { background: var(--white); }
.hb-proof__top { display: flex; align-items: center; justify-content: space-between; gap: 24px 40px; flex-wrap: wrap; padding-bottom: 28px; border-bottom: 1px solid var(--cream-line); }
.hb-rating { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--ink-soft); }
.hb-rating strong { font-family: var(--font-display); font-size: 26px; color: var(--ink); }
.hb-stars { color: #E5A82A; letter-spacing: 2px; }
.hb-logos { display: flex; align-items: center; gap: 12px 28px; flex-wrap: wrap; font-weight: 700; color: #8A979B; font-size: 14.5px; }
.hb-logos__label { font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-soft); }
.hb-logos em, .hb-rating em { font-style: normal; opacity: 0.7; }
.hb-quotes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; margin-top: 28px; }
.hb-quote { margin: 0; padding: 24px; border: 1px solid var(--cream-line); border-radius: 16px; background: var(--white); box-shadow: var(--shadow-card); display: flex; flex-direction: column; gap: 12px; }
.hb-quote blockquote { margin: 0; font-size: 15.5px; line-height: 1.6; color: var(--ink); }
.hb-quote figcaption { display: flex; align-items: center; gap: 12px; margin-top: auto; font-size: 13.5px; }
.hb-quote figcaption strong { display: block; color: var(--ink); }
.hb-quote figcaption small { display: block; color: var(--ink-soft); font-size: 12px; }
/* services */
.hb-tabs { display: inline-flex; padding: 5px; gap: 4px; border-radius: 999px; background: var(--blue-pale); margin-bottom: 24px; }
.hb-tabs button { font: inherit; font-weight: 700; font-size: 14px; border: 0; cursor: pointer; padding: 10px 20px; border-radius: 999px; background: transparent; color: var(--blue-deep); }
.hb-tabs button.is-active { background: var(--blue-brand); color: var(--white); }
.hb-cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.hb-cards[hidden] { display: none; }
.hb-card { display: flex; flex-direction: column; text-decoration: none; color: var(--ink); background: var(--white); border: 1px solid var(--cream-line); border-radius: 18px; overflow: hidden; box-shadow: var(--shadow-card); transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease; }
.hb-card:hover { transform: translateY(-5px); border-color: var(--blue-brand); box-shadow: 0 24px 44px -22px rgba(11,134,160,0.5); }
.hb-card__img { position: relative; aspect-ratio: 16 / 8; display: flex; align-items: center; justify-content: center; background: linear-gradient(135deg, var(--blue-pale), #C8E4EA); color: var(--blue-brand); }
.hb-card__img em { position: absolute; right: 12px; bottom: 10px; font-style: normal; font-size: 11px; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; color: var(--blue-deep); opacity: 0.6; }
.hb-card__body { display: flex; flex-direction: column; gap: 6px; padding: 18px 20px 20px; }
.hb-card__body strong { font-size: 17.5px; color: var(--ink); }
.hb-card__body span { font-size: 14.5px; line-height: 1.5; color: var(--ink-soft); }
.hb-card__body b { margin-top: 6px; font-size: 13.5px; color: var(--blue-brand); }
.hb-services { background: var(--blue-pale); }
.hb-services .hb-tabs { background: var(--white); }
@media (max-width: 980px) { .hb-quotes, .hb-cards { grid-template-columns: 1fr 1fr; } }
@media (max-width: 760px) { .hb-quotes, .hb-cards { grid-template-columns: 1fr; } }

/* FAQ page */
.faq-page { max-width: 820px; }
.faq-page__group { font-size: 13px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--blue-brand); margin: 44px 0 4px; }
.faq-page__group:first-child { margin-top: 0; }
.faq-page__list { max-width: none; margin: 0; }

/* Homepage reviews strip on the blue theme: white text, glass cards. */
.hb-proof.section--brand { background: var(--blue-brand); }
.hb-proof.section--brand .hb-proof__top { border-bottom-color: rgba(255, 255, 255, 0.28); }
.hb-proof.section--brand .hb-rating, .hb-proof.section--brand .hb-rating strong { color: var(--white); }
.hb-proof.section--brand .hb-rating span:last-child { color: rgba(255, 255, 255, 0.8); }
.hb-proof.section--brand .hb-stars { color: #FFD166; }
.hb-proof.section--brand .hb-logos, .hb-proof.section--brand .hb-logos span { color: rgba(255, 255, 255, 0.82); }
.hb-proof.section--brand .hb-logos__label { color: rgba(255, 255, 255, 0.7); }
.hb-proof.section--brand .hb-quote { background: linear-gradient(140deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.07)); border-color: rgba(255, 255, 255, 0.38); box-shadow: 0 24px 44px -24px rgba(0, 20, 30, 0.6); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.hb-proof.section--brand .hb-quote blockquote { color: var(--white); }
.hb-proof.section--brand .hb-quote figcaption strong { color: var(--white); }
.hb-proof.section--brand .hb-quote figcaption small { color: rgba(255, 255, 255, 0.78); }
.hb-proof.section--brand .t-card__avatar { background: var(--white); color: var(--blue-deep); }
.hb-card__img { aspect-ratio: 16 / 9; overflow: hidden; }
.hb-card__img img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 0.6s ease; }
.hb-card:hover .hb-card__img img { transform: scale(1.05); }

/* Homepage — Our Story + Questions (one blue section, two blocks) ---------- */
.story2__grid { display: grid; grid-template-columns: 1.02fr 0.98fr; gap: 56px; align-items: start; }
.story2 h2 { font-size: clamp(30px, 3.6vw, 44px); line-height: 1.1; color: var(--white); max-width: 18ch; }
.story2__story > p { margin-top: 18px; max-width: 54ch; font-size: 17px; line-height: 1.65; color: rgba(255, 255, 255, 0.88); }
.story2__photo { position: relative; margin: 30px 0 0; }
.story2__photo > img { width: 100%; height: 340px; object-fit: cover; object-position: 100% 40%; border-radius: 22px; display: block; box-shadow: 0 30px 60px -30px rgba(0, 20, 30, 0.7); }
.story2__stats { position: relative; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin: -44px 16px 0; }
.story2__stat {
  padding: 14px 16px; border-radius: 16px; color: var(--white); text-align: left;
  background: linear-gradient(140deg, rgba(6, 60, 78, 0.85), rgba(6, 60, 78, 0.65)); border: 1.5px solid rgba(255, 255, 255, 0.4);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); box-shadow: 0 18px 34px -18px rgba(0, 20, 30, 0.7);
  transition: transform 0.3s ease, border-color 0.3s ease;
}
.story2__stat:hover { transform: translateY(-4px); border-color: rgba(255, 255, 255, 0.8); }
.story2__stat strong { display: block; font-family: var(--font-display); font-size: 30px; font-weight: 800; line-height: 1; }
.story2__stat span { display: block; margin-top: 6px; font-size: 12px; color: rgba(255, 255, 255, 0.8); line-height: 1.3; }
.story2__link { display: inline-block; margin-top: 24px; color: var(--white); font-weight: 700; text-decoration: none; border-bottom: 1.5px solid rgba(255, 255, 255, 0.6); padding-bottom: 2px; }
.story2__link:hover { border-color: var(--white); }
.story2__faq { background: var(--white); color: var(--ink); border-radius: 26px; padding: 34px 34px 28px; box-shadow: 0 40px 70px -34px rgba(0, 20, 30, 0.7); }
.story2__faq h3 { font-size: 24px; margin: 0 0 6px; color: var(--ink); }
.story2__faq .faq-list { max-width: none; margin: 0; }
.story2__faq .faq-item summary { font-size: 16px; }
.story2__more { display: inline-block; margin-top: 18px; font-weight: 700; color: var(--blue-brand); text-decoration: none; }
.story2__more:hover { text-decoration: underline; }
@media (max-width: 980px) { .story2__grid { grid-template-columns: 1fr; gap: 40px; } .story2 h2 { max-width: none; } }
@media (max-width: 760px) {
  .story2__photo > img { height: 240px; border-radius: 18px; }
  .story2__stats { margin: -30px 10px 0; gap: 8px; }
  .story2__stat { padding: 10px 12px; }
  .story2__stat strong { font-size: 22px; }
  .story2__stat span { font-size: 11px; }
  .story2__faq { padding: 24px 20px 20px; border-radius: 20px; }
}
.story2__right { display: flex; flex-direction: column; gap: 20px; min-width: 0; }
.story2__call { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; padding: 20px 24px; border-radius: 20px; background: linear-gradient(140deg, rgba(255,255,255,0.16), rgba(255,255,255,0.06)); border: 1.5px solid rgba(255,255,255,0.38); }
.story2__call strong { display: block; color: var(--white); font-size: 18px; font-family: var(--font-display); }
.story2__call span { display: block; margin-top: 2px; color: rgba(255,255,255,0.8); font-size: 14px; }

/* Story section refinements + small white closing strip ------------------- */
.story2__grid { align-items: stretch; }
.story2__right { justify-content: space-between; }
.story2__photo > img { height: 360px; }
.story2__stats { margin: -38px 16px 0; align-items: stretch; }
.story2__stat { padding: 14px 14px 13px; display: flex; flex-direction: column; justify-content: space-between; min-height: 84px; }
.story2__stat span { font-size: 11.5px; white-space: nowrap; }
.story2__faq { padding: 30px 32px 26px; }
.end-strip { background: var(--white); padding: 40px 0; }
.end-strip__inner { display: flex; align-items: center; justify-content: space-between; gap: 20px 40px; flex-wrap: wrap; }
.end-strip h2 { font-size: clamp(22px, 2.6vw, 30px); color: var(--ink); margin: 0; }
.end-strip__actions { display: flex; align-items: center; gap: 22px; flex-wrap: wrap; }
.end-strip__call { color: var(--blue-deep); font-weight: 700; text-decoration: none; border-bottom: 1.5px solid var(--blue-brand); padding-bottom: 2px; }
@media (max-width: 760px) {
  .story2__photo > img { height: 250px; }
  .story2__stat { min-height: 72px; padding: 10px 10px; }
  .story2__stat span { white-space: normal; }
  .end-strip { padding: 30px 0; }
  .end-strip__inner { flex-direction: column; align-items: flex-start; }
}
.story2__right { justify-content: flex-start; }
.story2__photo > img { height: 320px; }
@media (max-width: 760px) { .story2__photo > img { height: 250px; } }

/* Homepage — Our Story, photo-led editorial (replaces the story+FAQ block) --- */
.story3__grid { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 64px; align-items: center; }
.story3__photo { margin: 0; }
.story3__photo img { width: 100%; aspect-ratio: 4 / 4.6; object-fit: cover; object-position: 78% 40%; border-radius: 28px; display: block; box-shadow: 0 40px 70px -34px rgba(0, 20, 30, 0.75); }
.story3 h2 { margin-top: 14px; font-size: clamp(30px, 3.6vw, 44px); line-height: 1.1; color: var(--white); max-width: 18ch; }
.story3__copy > p { margin-top: 18px; max-width: 54ch; font-size: 17px; line-height: 1.65; color: rgba(255, 255, 255, 0.88); }
.story3__stats { display: flex; margin: 32px 0 0; padding: 22px 0 0; border-top: 1px solid rgba(255, 255, 255, 0.3); gap: 0; }
.story3__stats > div { flex: 1; padding: 0 24px; border-left: 1px solid rgba(255, 255, 255, 0.3); }
.story3__stats > div:first-child { padding-left: 0; border-left: 0; }
.story3__stats dt { font-family: var(--font-display); font-size: clamp(30px, 3.4vw, 42px); font-weight: 800; line-height: 1; color: var(--white); }
.story3__stats dd { margin: 8px 0 0; font-size: 13px; color: rgba(255, 255, 255, 0.8); }
.story3__link { display: inline-block; margin-top: 28px; color: var(--white); font-weight: 700; text-decoration: none; border-bottom: 1.5px solid rgba(255, 255, 255, 0.6); padding-bottom: 2px; }
.story3__link:hover { border-color: var(--white); }
@media (max-width: 980px) { .story3__grid { grid-template-columns: 1fr; gap: 36px; } .story3__photo img { aspect-ratio: 16 / 11; } .story3 h2 { max-width: none; } }
@media (max-width: 760px) { .story3__stats > div { padding: 0 12px; } .story3__stats dt { font-size: 26px; } .story3__stats dd { font-size: 11.5px; } }

/* Reviews slider (homepage) ------------------------------------------------- */
.hb-slider { margin-top: 28px; }
.hb-slider__track {
  display: flex; gap: 20px; overflow-x: auto; scroll-snap-type: x mandatory; scroll-behavior: auto; padding: 4px 2px 18px;
  scrollbar-width: none; -ms-overflow-style: none; outline-offset: 4px;
}
.hb-slider__track::-webkit-scrollbar { display: none; }
.hb-slider .hb-quote { flex: 0 0 calc((100% - 40px) / 3); scroll-snap-align: start; min-width: 0; }
.hb-slider__bar { display: flex; align-items: center; gap: 16px; margin-top: 4px; }
.hb-slider__btn {
  width: 46px; height: 46px; border-radius: 50%; border: 1.5px solid rgba(255, 255, 255, 0.55); background: rgba(255, 255, 255, 0.12);
  color: var(--white); font-size: 19px; cursor: pointer; display: flex; align-items: center; justify-content: center;
  transition: background 0.2s ease, transform 0.2s ease, opacity 0.2s ease;
}
.hb-slider__btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.28); transform: scale(1.06); }
.hb-slider__btn:disabled { opacity: 0.35; cursor: default; }
.hb-slider__count { font-size: 14px; font-weight: 600; color: var(--white); min-width: 84px; font-variant-numeric: tabular-nums; }
.hb-slider__progress { flex: 1; height: 4px; border-radius: 4px; background: rgba(255, 255, 255, 0.25); overflow: hidden; }
.hb-slider__progress i { display: block; height: 100%; width: 10%; border-radius: 4px; background: var(--white); transition: width 0.25s ease; }
.hb-slider__note { margin: 14px 0 0; font-size: 12px; color: rgba(255, 255, 255, 0.65); }
@media (max-width: 980px) { .hb-slider .hb-quote { flex-basis: calc((100% - 20px) / 2); } }
@media (max-width: 760px) { .hb-slider .hb-quote { flex-basis: 88%; } .hb-slider__count { min-width: 64px; font-size: 13px; } }

/* tighter reviews section */
.hb-proof.section--tight { padding: 38px 0 40px; }
.hb-proof__top { padding-bottom: 20px; }
.hb-slider { margin-top: 20px; }
.hb-slider__track { padding-bottom: 10px; }
.hb-slider .hb-quote { padding: 20px 22px; gap: 10px; }
.hb-slider .hb-quote blockquote { font-size: 15px; line-height: 1.55; }

/* Hero decluttered: no floating badges, a thin line of proof instead of four cards */
.hero2__ticks { list-style: none; margin: 0; padding: 18px 0 0; display: flex; flex-wrap: wrap; gap: 8px 30px; border-top: 1px solid rgba(255, 255, 255, 0.3); font-size: 14.5px; font-weight: 600; color: rgba(255, 255, 255, 0.95); }
.hero2__ticks li::before { content: "\2713"; margin-right: 9px; color: #B8F5D8; font-weight: 800; }
.hero2__proof { margin-top: 26px; }
@media (max-width: 760px) { .hero2__ticks { gap: 6px 18px; font-size: 13px; padding-top: 14px; } }

/* Our Story on a white background (it now follows the blue sectors band) */
.story3 { background: var(--white); }
.story3 h2 { color: var(--ink); }
.story3__copy > p { color: var(--ink-soft); }
.story3__photo img { box-shadow: 0 34px 60px -34px rgba(9, 110, 131, 0.55); }
.story3__stats { border-top-color: var(--cream-line); }
.story3__stats > div { border-left-color: var(--cream-line); }
.story3__stats dt { color: var(--blue-brand); }
.story3__stats dd { color: var(--ink-soft); }
.story3__link { color: var(--blue-deep); border-bottom-color: var(--blue-brand); }
.story3__link:hover { border-bottom-color: var(--blue-deep); }

/* Homepage — Our Story v4: people-led (white) ------------------------------- */
.story4 { background: var(--white); }
.story4__top { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: 64px; align-items: start; }
.story4 h2 { margin-top: 14px; font-size: clamp(30px, 3.6vw, 44px); line-height: 1.1; color: var(--ink); max-width: 18ch; }
.story4__intro > p { margin-top: 18px; max-width: 56ch; font-size: 17px; line-height: 1.65; color: var(--ink-soft); }
.story4__timeline { list-style: none; margin: 8px 0 0; padding: 0 0 0 26px; position: relative; display: flex; flex-direction: column; gap: 22px; }
.story4__timeline::before { content: ""; position: absolute; left: 6px; top: 10px; bottom: 10px; border-left: 2px dashed var(--blue-sky); }
.story4__timeline li { position: relative; display: grid; grid-template-columns: 76px 1fr; gap: 14px; align-items: baseline; }
.story4__timeline li::before { content: ""; position: absolute; left: -26px; top: 9px; width: 14px; height: 14px; border-radius: 50%; background: var(--blue-brand); box-shadow: 0 0 0 5px var(--blue-pale); }
.story4__timeline b { font-family: var(--font-display); font-size: 24px; font-weight: 800; color: var(--blue-brand); line-height: 1.1; }
.story4__timeline span { font-size: 15px; line-height: 1.5; color: var(--ink-soft); }
.story4__people { display: grid; grid-template-columns: 1.25fr 1fr 1fr; gap: 20px; margin-top: 52px; align-items: stretch; }
.story4__card { margin: 0; display: flex; flex-direction: column; border-radius: 22px; overflow: hidden; background: var(--white); border: 1px solid var(--cream-line); box-shadow: var(--shadow-card); }
.story4__card > img, .story4__portrait { flex: 1; min-height: 300px; width: 100%; object-fit: cover; object-position: 78% 40%; display: block; }
.story4__portrait { position: relative; display: flex; align-items: center; justify-content: center; background: linear-gradient(160deg, var(--blue-pale), #C6E2E9); color: var(--blue-brand); }
.story4__portrait svg { width: 38%; opacity: 0.55; }
.story4__card figcaption { padding: 16px 20px 18px; display: flex; flex-direction: column; gap: 4px; }
.story4__card figcaption strong { font-family: var(--font-display); font-size: 17px; color: var(--ink); }
.story4__card figcaption span { font-size: 13.5px; line-height: 1.45; color: var(--ink-soft); }
.story4__ways { list-style: none; margin: 44px 0 0; padding: 32px 0 0; border-top: 1px solid var(--cream-line); display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; }
.story4__ways li { display: flex; gap: 16px; align-items: flex-start; }
.story4__icon { flex-shrink: 0; width: 48px; height: 48px; border-radius: 14px; background: var(--blue-pale); color: var(--blue-brand); display: flex; align-items: center; justify-content: center; }
.story4__ways strong { display: block; font-size: 16.5px; color: var(--ink); }
.story4__ways p { margin: 4px 0 0; font-size: 14.5px; line-height: 1.5; color: var(--ink-soft); }
@media (max-width: 980px) { .story4__top { grid-template-columns: 1fr; gap: 32px; } .story4 h2 { max-width: none; } .story4__people { grid-template-columns: 1fr 1fr; } .story4__card--photo { grid-column: 1 / -1; } .story4__card--photo > img { min-height: 260px; max-height: 340px; } }
@media (max-width: 760px) {
  .story4__timeline li { grid-template-columns: 62px 1fr; }
  .story4__people { gap: 12px; margin-top: 36px; }
  .story4__card > img, .story4__portrait { min-height: 190px; }
  .story4__card figcaption { padding: 12px 14px 14px; }
  .story4__ways { grid-template-columns: 1fr; gap: 20px; margin-top: 32px; padding-top: 24px; }
}
.story4__card figcaption { min-height: 112px; }
@media (max-width: 760px) { .story4__card figcaption { min-height: 0; } }
.story4__card figcaption { min-height: 124px; }
@media (max-width: 760px) { .story4__card figcaption { min-height: 0; } }
/* Story timeline spans exactly the intro column: first entry level with the headline, last entry level with the paragraph's last line */
@media (min-width: 981px) {
  .story4__top { align-items: stretch; }
  .story4__timeline { margin: 0; justify-content: space-between; gap: 0; padding-top: 36px; padding-bottom: 4px; }
  .story4__timeline::before { top: 46px; bottom: 16px; }
}
@media (min-width: 981px) { .story4__timeline { padding-top: 43px; padding-bottom: 17px; } .story4__timeline::before { top: 53px; bottom: 29px; } }

/* Area checker card: the pale animated background sometimes washed out the glass
   card. A deeper, more opaque navy tint and a firmer border keep it readable on
   every part of the animation. */
.hero2 .area-check {
  background: linear-gradient(140deg, rgba(5, 52, 68, 0.82), rgba(7, 70, 90, 0.72));
  border: 1.5px solid rgba(255, 255, 255, 0.55);
  box-shadow: 0 26px 50px -22px rgba(0, 20, 30, 0.75), 0 0 0 1px rgba(3, 30, 40, 0.25);
}

/* Hero, shorter: wider/smaller headline, one-line lede, quote pill on the photo */
@media (min-width: 981px) {
  .hero2 { padding: 26px 0 22px; }
  .hero2__inner { grid-template-columns: 1.25fr 0.75fr; gap: 40px; }
  .hero2 h1 { font-size: clamp(34px, 3.7vw, 50px); }
  .hero2__lede { margin-top: 12px; font-size: 17px; }
  .area-check { margin-top: 16px; max-width: 560px; padding: 14px 16px 12px; }
  .hero2__photo { aspect-ratio: 4 / 3.3; }
  .hero2__proof { margin-top: 18px; }
  .hero2__ticks { padding-top: 14px; }
}
.hero2__photo-cta {
  position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 3; white-space: nowrap;
  padding: 13px 26px; border-radius: 999px; background: var(--white); color: var(--blue-deep); font-weight: 700; font-size: 15.5px;
  text-decoration: none; box-shadow: 0 16px 34px -12px rgba(0, 20, 30, 0.7); transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.hero2__photo-cta:hover { transform: translateX(-50%) translateY(-2px) scale(1.03); }
.hero2__photo .story-hero__placeholder-tag { top: 44%; }
@media (max-width: 760px) { .hero2__photo-cta { bottom: 12px; padding: 11px 20px; font-size: 14.5px; } }
@media (max-width: 980px) {
  .hero2 .hero__text-scrim { background: linear-gradient(180deg, rgba(9, 110, 131, 0.78) 0%, rgba(9, 110, 131, 0.6) 60%, rgba(9, 110, 131, 0.7) 100%); }
}

/* Hero: a middle size (the shrink went too far) */
@media (min-width: 981px) {
  .hero2 { padding: 46px 0 34px; }
  .hero2__inner { grid-template-columns: 1.1fr 0.9fr; gap: 52px; }
  .hero2 h1 { font-size: clamp(38px, 4.5vw, 58px); }
  .hero2__lede { margin-top: 16px; font-size: 18px; }
  .area-check { margin-top: 24px; padding: 18px 18px 16px; }
  .hero2__photo { aspect-ratio: 4 / 3.9; }
  .hero2__proof { margin-top: 28px; }
  .hero2__ticks { padding-top: 18px; }
}

/* Icon-header variant of the homepage service cards (location and service pages:
   no photo, so no stock photo is repeated across dozens of pages). */
.hb-card--icon .hb-card__img { aspect-ratio: auto; height: 84px; }
.hb-card--icon .hb-card__body b { margin-top: auto; padding-top: 6px; }
.hb-card--icon .hb-card__body { flex: 1; }

/* Calm hero background: no white wash over the animation, and a soft deep-blue
   scrim on the left so the headline always has strong contrast. */
.hero2 .hero__wave::after { background: linear-gradient(180deg, rgba(3, 30, 42, 0.10), rgba(3, 30, 42, 0.02) 50%, rgba(3, 30, 42, 0.14)); }
.hero2 .hero__text-scrim { background: radial-gradient(ellipse 70% 95% at 22% 50%, rgba(4, 44, 62, 0.55) 0%, rgba(4, 44, 62, 0.28) 55%, transparent 82%); }

/* Cleaning specification page: room-by-room explorer */
.spec-explorer { display: grid; grid-template-columns: 300px minmax(0, 1fr); gap: 28px; align-items: start; }
.spec-rooms { display: flex; flex-direction: column; gap: 8px; }
.spec-room {
  display: flex; align-items: center; gap: 14px; text-align: left; font: inherit; font-weight: 700; font-size: 15px; cursor: pointer;
  padding: 13px 16px; border-radius: 14px; border: 1px solid var(--cream-line); background: var(--white); color: var(--ink);
  box-shadow: var(--shadow-card); transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
.spec-room:hover { border-color: var(--blue-brand); transform: translateX(3px); }
.spec-room__icon { flex-shrink: 0; width: 38px; height: 38px; border-radius: 10px; background: var(--blue-pale); color: var(--blue-brand); display: flex; align-items: center; justify-content: center; }
.spec-room.is-active { background: var(--blue-brand); border-color: var(--blue-brand); color: var(--white); }
.spec-room.is-active .spec-room__icon { background: rgba(255, 255, 255, 0.2); color: var(--white); }
.spec-panels { background: var(--white); border: 1px solid var(--cream-line); border-radius: 22px; padding: 30px 32px 26px; box-shadow: var(--shadow-card); min-height: 420px; }
.spec-panel h3 { font-size: 24px; margin: 0 0 20px; color: var(--ink); }
.spec-cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
.spec-col h4 { font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; color: var(--blue-brand); margin: 0 0 12px; padding-bottom: 10px; border-bottom: 2px solid var(--blue-pale); }
.spec-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 11px; }
.spec-col li { position: relative; padding-left: 24px; font-size: 14.5px; line-height: 1.5; color: var(--ink); }
.spec-col li::before { content: "\2713"; position: absolute; left: 0; top: 0; color: var(--blue-brand); font-weight: 800; }
.spec-note { max-width: 78ch; margin: 30px 0 0; font-size: 15px; line-height: 1.6; color: var(--ink-soft); }
.spec-note a { color: var(--blue-brand); font-weight: 600; }
@media (max-width: 980px) {
  .spec-explorer { grid-template-columns: 1fr; }
  .spec-rooms { flex-direction: row; overflow-x: auto; padding-bottom: 6px; scrollbar-width: none; }
  .spec-rooms::-webkit-scrollbar { display: none; }
  .spec-room { flex: 0 0 auto; white-space: nowrap; }
  .spec-cols { grid-template-columns: 1fr; gap: 22px; }
  .spec-panels { padding: 24px 20px; min-height: 0; }
}

/* Small "popular in this area / by area" link rows */
.area-links { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 26px; }
.area-links__label { font-size: 13px; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-soft); }
.area-links a { padding: 8px 16px; border-radius: 999px; border: 1px solid var(--cream-line); background: var(--white); color: var(--blue-deep); font-weight: 600; font-size: 14px; text-decoration: none; transition: background 0.15s ease, border-color 0.15s ease; }
.area-links a:hover { background: var(--blue-pale); border-color: var(--blue-brand); }
.area-links-band { padding: 0 !important; }
.area-links-band .area-links { margin: 0; padding: 28px 0; }

/* Get a Quote page (rebuilt) ------------------------------------------------ */
.quote-ticks { list-style: none; margin: 22px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; font-size: 16px; font-weight: 600; color: rgba(255, 255, 255, 0.95); }
.quote-ticks li::before { content: "\2713"; margin-right: 12px; color: #B8F5D8; font-weight: 800; }
.quote-call { display: inline-block; margin-top: 26px; color: rgba(255, 255, 255, 0.88); text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, 0.45); padding-bottom: 2px; }
.quote-call strong { color: var(--white); }
.quote-steps { margin-bottom: 44px; }
.quote-steps li > span { background: var(--blue-brand); color: var(--white); }
.quote-steps h3 { color: var(--ink); }
.quote-steps p { color: var(--ink-soft); }
.quote-factors__title { font-size: 20px; margin: 0 0 20px; color: var(--ink); }
#what-next .hb-steps__list { margin-bottom: 44px; }
@media (max-width: 980px) {
  #quote-hero .quote-ticks { order: 3; margin-top: 26px; }
  #quote-hero .quote-call { order: 4; margin-top: 18px; align-self: flex-start; }
}
/* 3-step list (copied from the homepage B test so it works on any page) */
.hb-steps__list { list-style: none; padding: 0; margin: 0 0 32px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 28px; }
.hb-steps__list li { position: relative; padding-top: 4px; }
.hb-steps__list li > span { width: 46px; height: 46px; border-radius: 50%; background: var(--blue-brand); color: var(--white); font-family: var(--font-display); font-weight: 800; font-size: 20px; display: flex; align-items: center; justify-content: center; margin-bottom: 16px; }
.hb-steps__list h3 { font-size: 20px; }
.hb-steps__list p { margin-top: 8px; font-size: 15.5px; max-width: 34ch; }
@media (max-width: 980px) { .hb-steps__list { grid-template-columns: 1fr; gap: 24px; } }

.form-privacy { margin: 16px 0 0; font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }
.form-privacy a { color: var(--blue-brand); font-weight: 600; }
.quote-step + .form-privacy { margin-top: 18px; }

.privacy { max-width: 760px; }
.privacy h1 { font-size: clamp(30px, 4vw, 42px); }
.privacy__updated { color: var(--ink-soft); font-size: 14px; margin-top: 6px; }
.privacy h2 { font-size: 20px; margin: 34px 0 8px; color: var(--ink); }
.privacy p, .privacy li { font-size: 16px; line-height: 1.65; color: var(--ink-soft); }
.privacy ul { padding-left: 22px; margin: 8px 0 0; }
.privacy a { color: var(--blue-brand); font-weight: 600; }

/* "Sending..." state on form buttons */
button.is-sending, .btn.is-sending { opacity: 0.85; cursor: progress; }
button.is-sending::after, .btn.is-sending::after {
  content: ""; display: inline-block; width: 13px; height: 13px; margin-left: 10px; vertical-align: -2px;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: ocl-spin 0.7s linear infinite;
}
@keyframes ocl-spin { to { transform: rotate(360deg); } }
#story .story4__people { margin-top: 48px; }

/* Text-only "what is it" section (pages without a photo) */
.what-text h2 { font-size: clamp(26px, 3vw, 36px); max-width: 26ch; }
.what-text__cols { columns: 2; column-gap: 56px; margin-top: 18px; }
.what-text__cols p { break-inside: avoid; margin: 0 0 16px; color: var(--ink-soft); font-size: 16.5px; line-height: 1.65; }
@media (max-width: 760px) { .what-text__cols { columns: 1; } }

/* Homepage emergency-cleaning promo (inside the white services section) */
.promo-emergency {
  display: flex; align-items: center; gap: 22px; margin-top: 34px; padding: 22px 28px; border-radius: 20px; color: var(--white);
  background: linear-gradient(120deg, #031A23 0%, #0A4F73 60%, #0B86A0 100%); box-shadow: 0 30px 50px -28px rgba(3, 26, 35, 0.7);
}
.promo-emergency__icon { flex-shrink: 0; width: 54px; height: 54px; border-radius: 16px; background: rgba(255, 255, 255, 0.14); border: 1px solid rgba(255, 255, 255, 0.35); display: flex; align-items: center; justify-content: center; }
.promo-emergency__text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.promo-emergency__text strong { font-family: var(--font-display); font-size: 20px; }
.promo-emergency__text span { font-size: 15px; line-height: 1.45; color: rgba(255, 255, 255, 0.85); max-width: 60ch; }
.promo-emergency__actions { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; justify-content: flex-end; }
.promo-emergency__call { color: var(--white); font-weight: 700; text-decoration: none; border-bottom: 1px solid rgba(255, 255, 255, 0.5); padding-bottom: 2px; white-space: nowrap; }
@media (max-width: 980px) { .promo-emergency { flex-wrap: wrap; } .promo-emergency__actions { width: 100%; justify-content: flex-start; } }
@media (max-width: 760px) { .promo-emergency { padding: 18px; margin-top: 26px; } .promo-emergency__actions .btn { width: 100%; justify-content: center; } }

.what-text__inc-title { font-size: 18px; margin: 30px 0 12px; color: var(--ink); }
.what-text__inc { list-style: none; margin: 0; padding: 0; columns: 2; column-gap: 40px; }
.what-text__inc li { position: relative; padding-left: 26px; margin-bottom: 11px; break-inside: avoid; font-size: 15.5px; line-height: 1.5; color: var(--ink); }
.what-text__inc li::before { content: "\2713"; position: absolute; left: 0; top: 0; color: var(--blue-brand); font-weight: 800; }
@media (max-width: 760px) { .what-text__inc { columns: 1; } }
