/* ============================================================
   SmartLockPro design system
   ------------------------------------------------------------
   Hand-written CSS, deliberately replacing the Tailwind browser
   CDN this site used to load. That script was 276KB of JS that
   compiled CSS in the browser on every page load — Tailwind's own
   docs say not to do that in production, and it made the "mobile
   PageSpeed > 90" launch target in PLAN.md unreachable. The whole
   site is ~10 templates, so hand-written CSS is both smaller and
   easier to reason about.

   Fonts are self-hosted (static/fonts/) rather than pulled from
   Google Fonts: no third-party request on every page load, no
   extra DNS/TLS round trip, and nothing leaks visitor IPs to a
   third party (which also keeps the privacy policy honest).
   ============================================================ */

/* ---------- fonts ---------- */
@font-face {
  font-family: "Archivo";
  src: url("../fonts/archivo-latin.cd56e2ec63d7.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex";
  src: url("../fonts/plex-400-latin.b2c9031d9fd6.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Plex";
  src: url("../fonts/plex-600-latin.70800b98b5e7.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* ---------- tokens ---------- */
:root {
  --ink: #0e1116;
  --ink-2: #171b22;
  /* Pure white. This was #f7f4ef, a warm off-white — 8 points more red than
     blue — chosen with the charcoal-and-brass palette. It costs about 10% of
     every text contrast ratio against it (body copy 7.68 vs 8.43 on white)
     and reads as slightly dim next to a genuinely white page, which is what
     comparing it against smartlockinstaller made obvious. */
  --paper: #ffffff;
  --surface: #ffffff;
  --brass: #b8752b;
  --brass-hover: #9c6222;
  /* Brass as a FILL behind white text. #b8752b is only 3.74:1 against
     white, below WCAG AA's 4.5:1 for normal text — which put the site's
     single most important element, the primary CTA, under the bar. This
     is the same hue a shade deeper: 5.16:1. --brass stays as-is for text,
     rules and accents on dark, where it passes comfortably. */
  --brass-fill: #9c5f1f;
  --brass-fill-hover: #834d16;
  --brass-lt: #e8b872;
  /* Brass as TEXT on a light ground. --brass is #b8752b, which measures only
     3.41:1 on --paper — below the 4.5:1 AA needs for normal text, and the
     single most common "hard to read" complaint about this site. Same hue,
     deep enough to clear 4.5 on every light ground the site uses: 5.12 on
     --paper, 5.61 on white, and 4.75 on the tinted .notice panel, which is
     the darkest of them and the one that decided this value. Text on DARK
     keeps --brass — this one drops to 3.37 there. */
  --brass-text: #96591b;
  /* Muted body text. Was #5f6772, which measures 5.22:1 on --paper — it
     passes AA and still reads washed out, which is what "the grey text is
     hard to read" actually meant. smartlockinstaller's equivalent sits at
     8.03 and is visibly easier; this matches it at 7.68 on --paper and 8.43
     on white. Passing the minimum and being comfortable are not the same
     thing. */
  --steel: #464e58;
  /* Card and divider edges. Slightly deeper now --paper is white: the cards
     are also white, so this border is the only thing separating them from the
     page — the warm paper used to do half that job on its own. */
  --line: #ddd5c8;
  --on-dark: #ede8e0;
  --on-dark-dim: #9aa1ac;
  --good: #047857;
  --warn: #b45309;
  --danger: #b91c1c;

  --wrap: 1200px;
  --wrap-narrow: 760px;
  --radius: 2px;

  --font-display: "Archivo", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-body: "Plex", ui-sans-serif, system-ui, -apple-system, sans-serif;
}

/* ---------- base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  flex: 1;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  letter-spacing: -0.03em;
  text-wrap: balance;
  margin: 0;
  line-height: 1.12;
}

a {
  color: var(--brass-text);
}
a:hover {
  color: var(--brass-hover);
}

img {
  max-width: 100%;
  height: auto;
}

:focus-visible {
  outline: 2px solid var(--brass);
  outline-offset: 2px;
}

[x-cloak] {
  display: none !important;
}

/* ---------- layout ---------- */
.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 28px;
}
.wrap-narrow {
  max-width: var(--wrap-narrow);
  margin: 0 auto;
  padding: 0 28px;
}

.section {
  padding: 84px 0;
}
.section-sm {
  padding: 52px 0;
}
.section-dark {
  background: var(--ink);
  color: var(--on-dark);
}
.section-dark h1,
.section-dark h2,
.section-dark h3 {
  color: #fff;
}

.sec-head {
  max-width: 680px;
  margin-bottom: 48px;
}
.sec-head h2 {
  font-size: clamp(28px, 3.4vw, 42px);
  font-weight: 800;
  margin-top: 14px;
}
.sec-head p {
  color: var(--steel);
  font-size: 17px;
  margin: 16px 0 0;
}
.section-dark .sec-head p {
  color: var(--on-dark-dim);
}

.label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  /* Light ground by default: --brass is only 3.41:1 on --paper. The dark
     sections put it back below, where --brass reads at 5.06 and this one
     would drop to 3.67. Neither colour works on both grounds. */
  color: var(--brass-text);
  margin: 0;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  background: var(--brass-fill);
  color: #fff;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  padding: 13px 24px;
  border: 1px solid var(--brass-fill);
  border-radius: var(--radius);
  text-decoration: none;
  cursor: pointer;
  transition:
    background 0.15s,
    border-color 0.15s;
}
.btn:hover {
  background: var(--brass-fill-hover);
  border-color: var(--brass-fill-hover);
  color: #fff;
}
.btn-block {
  width: 100%;
  justify-content: center;
}

.btn-outline {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}
.btn-outline:hover {
  background: rgba(0, 0, 0, 0.04);
  color: var(--ink);
  border-color: var(--steel);
}
.section-dark .btn-outline,
.hero .btn-outline,
.cookie .btn-outline {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.28);
}
.section-dark .btn-outline:hover,
.hero .btn-outline:hover,
.cookie .btn-outline:hover {
  background: rgba(255, 255, 255, 0.08);
  color: #fff;
}

/* ---------- cards ---------- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
}
a.card {
  display: block;
  text-decoration: none;
  color: inherit;
  transition:
    border-color 0.18s,
    transform 0.18s;
}
/* Cards carry a motif rather than being plain white boxes: concentric arcs
   struck from the top-right corner, which reads as a lock cylinder and uses
   the brass that is already the brand's material. Drawn in CSS, so there is
   no image to load and it scales to any card size.
   `isolation: isolate` makes the card its own stacking context, so the
   z-index:-1 pseudo-element paints above the card's background but below its
   text — without it the motif would either vanish behind the card or sit on
   top of the copy. */
.card {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.card::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 150px;
  height: 150px;
  /* Masked so the arcs are strongest in the corner and dissolve before they
     reach the copy. Unmasked at a readable strength they ran straight across
     the body text; faint enough not to, they stopped reading as a motif at
     all. The mask is what lets it be visible AND stay out of the way. */
  -webkit-mask-image: radial-gradient(
    circle at 100% 0,
    #000 0%,
    rgba(0, 0, 0, 0.6) 52%,
    transparent 84%
  );
  mask-image: radial-gradient(
    circle at 100% 0,
    #000 0%,
    rgba(0, 0, 0, 0.6) 52%,
    transparent 84%
  );
  background: radial-gradient(
      circle at 100% 0,
      rgba(184, 117, 43, 0.16) 0%,
      rgba(184, 117, 43, 0) 72%
    ),
    repeating-radial-gradient(
      circle at 100% 0,
      transparent 0 11px,
      var(--brass) 11px 12.5px
    );
  opacity: 0.62;
  pointer-events: none;
  z-index: -1;
  transition:
    opacity 0.18s ease,
    transform 0.18s ease;
}
a.card:hover {
  border-color: var(--brass);
  transform: translateY(-2px);
  color: inherit;
  box-shadow: 0 14px 30px rgba(14, 17, 22, 0.09);
}
a.card:hover::before {
  opacity: 0.95;
  transform: scale(1.08);
}
a.card:hover .go svg {
  transform: translateX(3px);
}
.card .go svg {
  transition: transform 0.18s ease;
}
@media (prefers-reduced-motion: reduce) {
  a.card,
  .card::before,
  .card .go svg {
    transition: none;
  }
  a.card:hover {
    transform: none;
  }
  a.card:hover::before {
    transform: none;
  }
}
.card h3 {
  font-size: 19px;
  font-weight: 700;
  margin-bottom: 8px;
}
.card p {
  color: var(--steel);
  font-size: 17px;
  margin: 0;
}
.go {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 16px;
  color: var(--brass);
  font-weight: 600;
  font-size: 14.5px;
}

/* ---------- nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(14, 17, 22, 0.94);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.nav-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 68px;
  gap: 28px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 19px;
  color: #fff;
  text-decoration: none;
  letter-spacing: -0.02em;
  white-space: nowrap;
}
.brand:hover {
  color: #fff;
}
.brand img {
  width: 26px;
  height: 26px;
  flex: none;
}
.nav-links {
  display: flex;
  align-items: center;
  gap: 22px;
  font-size: 15px;
  color: #c6cbd3;
}
.nav-links a {
  color: #c6cbd3;
  text-decoration: none;
}
.nav-links a:hover {
  color: var(--brass-lt);
}
.nav-cta {
  display: flex;
  align-items: center;
  gap: 14px;
}
.tel {
  display: flex;
  align-items: center;
  gap: 7px;
  color: #fff;
  text-decoration: none;
  font-weight: 600;
  font-size: 15px;
  white-space: nowrap;
}
.tel:hover {
  color: var(--brass-lt);
}
.wa {
  display: inline-flex;
  padding: 7px;
  color: #25d366;
  border-radius: var(--radius);
}
.wa:hover {
  background: rgba(255, 255, 255, 0.08);
  color: #25d366;
}

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  color: #fff;
  padding: 8px;
  margin-right: -8px;
  cursor: pointer;
}

/* dropdown */
.has-menu {
  position: relative;
}
.menu-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: none;
  border: 0;
  color: #c6cbd3;
  font-family: var(--font-body);
  font-size: 15px;
  cursor: pointer;
  padding: 0;
}
.menu-btn:hover {
  color: var(--brass-lt);
}
.menu-btn svg {
  transition: transform 0.15s;
}
.menu-panel {
  position: absolute;
  left: 0;
  top: 100%;
  padding-top: 14px;
  width: 290px;
}
.menu-panel-in {
  background: var(--ink-2);
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: 8px;
}
.menu-panel a {
  display: block;
  padding: 10px 12px;
  color: #d7dbe1;
  text-decoration: none;
  font-size: 15px;
}
.menu-panel a:hover {
  background: rgba(255, 255, 255, 0.06);
  color: var(--brass-lt);
}

/* display:none here is the DESKTOP state only. Alpine's x-show works by
   setting and clearing an INLINE display, so it can never override a
   stylesheet rule — with `display: none` and nothing re-enabling it, the
   panel could not be shown at any width. The burger toggled, the icon
   swapped to a cross, and nothing appeared. See the 1000px query below,
   which is where the burger itself becomes visible. */
.nav-mobile {
  display: none;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  background: var(--ink);
  padding: 16px 0 22px;
}
.nav-mobile a {
  display: block;
  padding: 11px 0;
  color: #d7dbe1;
  text-decoration: none;
  font-size: 15px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}
.nav-mobile a:hover {
  color: var(--brass-lt);
}
/* `.nav-mobile a` (0,1,1) outranks `.btn` (0,1,0) and forces display:block,
   which kills the button's own flex centring and padding. Restore both. */
.nav-mobile .btn {
  display: flex;
  justify-content: center;
  margin-top: 16px;
  padding: 13px 20px;
  border-bottom: 0;
}

/* 1180, not 1000. With Contact added the desktop nav carries eight items plus
   the phone number and the quote button, and below about 1180px that no longer
   fits on one row: it wrapped to two and pushed the page into a 17px sideways
   scroll at 1024px. Collapsing to the burger earlier is the honest fix — a
   two-row nav that also scrolls horizontally is worse than a menu button. */
/* Mirrors the nav breakpoint exactly. Above it Contact is a nav link; below
   it the nav is a burger, so the hero carries the button instead. Tied to the
   same number on purpose — pick two different ones and there is a band of
   widths with no visible way to contact anybody. */
.hero-contact {
  display: none;
}

@media (max-width: 1180px) {
  .hero-contact {
    display: inline-flex;
  }

  .nav-links,
  .nav-cta .tel,
  .nav-cta .btn {
    display: none;
  }
  .nav-toggle {
    display: block;
  }
  /* Lets x-show take over: it hides the panel with an inline display:none
     when closed, and clears it to reveal this. [x-cloak] covers the gap
     before Alpine initialises. */
  .nav-mobile {
    display: block;
  }
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: #fff;
  color: var(--brass-text);
  padding: 12px 20px;
  z-index: 100;
  font-weight: 600;
}
.skip:focus {
  left: 12px;
  top: 12px;
}

/* ---------- hero ---------- */
.hero {
  position: relative;
  background: var(--ink);
  color: #fff;
  overflow: hidden;
}
.hero-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 45%;
}
.hero-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    rgba(14, 17, 22, 0.96) 0%,
    rgba(14, 17, 22, 0.9) 42%,
    rgba(14, 17, 22, 0.45) 72%,
    rgba(14, 17, 22, 0.25) 100%
  );
}
.hero-in {
  position: relative;
  /* padding-top only — a `padding: 92px 0 0` shorthand here overrides .wrap's
     own `padding: 0 28px`, zeroing the horizontal gutters. Invisible on
     desktop, where .wrap's max-width creates the margin anyway, but on any
     viewport narrower than --wrap it put the hero copy flush against the
     screen edge while every other section stayed inset. */
  padding-top: 92px;
}
.hero-copy {
  max-width: 620px;
}
.hero h1 {
  font-size: clamp(36px, 4.6vw, 57px);
  font-weight: 800;
  line-height: 1.02;
  margin-top: 16px;
  color: #fff;
}
.hero .sub {
  color: #c6cbd3;
  font-size: 18px;
  margin: 22px 0 0;
  max-width: 520px;
}
.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin-top: 34px;
}
.price-tag {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 15px;
  color: #fff;
  padding-left: 16px;
  border-left: 2px solid var(--brass);
}
.price-tag span {
  display: block;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 13.5px;
  color: var(--on-dark-dim);
}

.spec {
  position: relative;
  margin: 72px 0 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: 48px;
}
.spec > div {
  position: relative;
  padding: 22px 0 24px;
}
/* Divider lives centred in the column gap, not on the cell edge. As a
   border-right it sat hard against the next column's text — with no
   horizontal padding the label started at exactly the divider's x, so the
   rule appeared to be touching the words. Inset top and bottom too, so it
   reads as a separator rather than a table gridline running into the
   border above. */
.spec > div + div::before {
  content: "";
  position: absolute;
  left: -24px;
  top: 20px;
  bottom: 22px;
  width: 1px;
  background: rgba(255, 255, 255, 0.13);
}
.spec dt {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass-lt);
  margin-bottom: 5px;
}
.spec dd {
  margin: 0;
  font-size: 15.5px;
  color: #e7e9ec;
  font-weight: 500;
}
@media (max-width: 820px) {
  .spec {
    grid-template-columns: 1fr 1fr;
    column-gap: 28px;
  }
  .spec > div {
    padding: 16px 0 18px;
  }
  /* Two columns: only the second cell of each row gets a vertical rule,
     otherwise a divider appears at the start of the second row. */
  .spec > div:nth-child(odd)::before {
    display: none;
  }
  .spec > div + div::before {
    left: -14px;
  }
  /* And a horizontal rule between the two rows. */
  .spec > div:nth-child(n + 3)::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 1px;
    background: rgba(255, 255, 255, 0.1);
  }
  .hero-in {
    padding-top: 60px;
  }
}

/* ---------- service grid ---------- */
.svc {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 20px;
}
.svc-col {
  display: grid;
  gap: 20px;
  grid-template-rows: repeat(3, 1fr);
}
.svc-feature {
  position: relative;
  padding: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.svc-feature img {
  width: 100%;
  height: 290px;
  object-fit: cover;
  display: block;
}
.svc-feature .fbody {
  padding: 28px 30px 30px;
}
.svc-feature h3 {
  font-size: 25px;
  margin-bottom: 10px;
}
.svc-feature p {
  font-size: 15.5px;
}
.tag {
  position: absolute;
  top: 18px;
  left: 18px;
  background: var(--brass-fill);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 6px 11px;
  z-index: 2;
}
.grid-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}
.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
}
.grid-1 {
  display: grid;
  grid-template-columns: minmax(0, 640px);
  gap: 20px;
}
.grid-2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
}
@media (max-width: 980px) {
  .grid-4 {
    grid-template-columns: 1fr 1fr;
  }
}
@media (max-width: 900px) {
  .svc {
    grid-template-columns: 1fr;
  }
  .svc-col {
    grid-template-rows: none;
  }
  .grid-3 {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 620px) {
  .grid-4,
  .grid-2 {
    grid-template-columns: 1fr;
  }
}

/* ---------- steps ---------- */
.steps {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid rgba(255, 255, 255, 0.14);
}
.step {
  padding: 30px 26px 8px 0;
  border-right: 1px solid rgba(255, 255, 255, 0.14);
  position: relative;
}
.step:last-child {
  border-right: 0;
}
.step::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 34px;
  height: 3px;
  background: var(--brass);
}
.step .n {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 13px;
  color: var(--brass-lt);
  letter-spacing: 0.1em;
}
.step h3 {
  font-size: 18px;
  font-weight: 700;
  margin: 12px 0 8px;
  color: #fff;
}
.step p {
  color: var(--on-dark-dim);
  font-size: 15.5px;
  margin: 0;
}
@media (max-width: 860px) {
  .steps {
    grid-template-columns: 1fr 1fr;
  }
  .step {
    border-right: 0;
    padding-right: 20px;
  }
}
@media (max-width: 520px) {
  .steps {
    grid-template-columns: 1fr;
  }
}

/* ---------- prose ---------- */
.prose {
  color: var(--ink);
  font-size: 17px;
  line-height: 1.72;
}
/* Reset with the SAME specificity as the sibling rule below, so the sibling
   rule wins for everything after the first child. `.prose p { margin: 0 }`
   was (0,1,1) and beat `.prose > * + *` at (0,1,0) whatever the order, which
   silently removed the gap between every pair of paragraphs site-wide —
   headings still had theirs, so it read as "long blocks of text" rather than
   an obvious bug. */
.prose > * {
  margin: 0;
}
.prose > * + * {
  margin-top: 1.1em;
}
.prose h2 {
  font-size: clamp(24px, 2.8vw, 32px);
  font-weight: 800;
  margin-top: 1.9em;
}
.prose h3 {
  font-size: 20px;
  font-weight: 700;
  margin-top: 1.6em;
}
.prose ul,
.prose ol {
  margin: 0;
  padding-left: 24px;
}
.prose li + li {
  margin-top: 0.5em;
}
.prose a {
  color: var(--brass-text);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.prose strong {
  font-weight: 600;
}
.prose img {
  display: block;
  border: 1px solid var(--line);
}
.prose blockquote {
  margin: 0;
  padding: 4px 0 4px 24px;
  border-left: 3px solid var(--brass);
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 700;
  line-height: 1.35;
  letter-spacing: -0.02em;
}

.page-head {
  background: var(--ink);
  color: #fff;
  padding: 56px 0 60px;
}
.page-head h1 {
  font-size: clamp(32px, 4.4vw, 52px);
  font-weight: 800;
  color: #fff;
  margin-top: 14px;
}
.page-head .intro {
  color: #c6cbd3;
  font-size: 18px;
  margin: 18px 0 0;
  max-width: 620px;
}
.page-head .intro p {
  margin: 0 0 0.7em;
}
.page-head .intro p:last-child {
  margin-bottom: 0;
}
.page-head .intro a {
  color: var(--brass-lt);
}
.crumb {
  font-size: 14px;
  color: var(--on-dark-dim);
}
.crumb a {
  color: var(--on-dark-dim);
  text-decoration: none;
}
.crumb a:hover {
  color: var(--brass-lt);
}
.head-actions {
  margin-top: 30px;
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
}

/* ---------- trust strip ---------- */
/* margin:0 is load-bearing. A <dl> carries a UA default margin of 1em 0, and
   .section-dark has no vertical padding or border to contain it — so that
   16px escaped by margin collapse and drew a white strip ABOVE AND BELOW the
   dark band, on the page's own paper ground. Two identical gaps from one
   unreset browser default. */
.trust {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  border-bottom: 1px solid rgba(255, 255, 255, 0.12);
}
.trust > div {
  padding: 26px 24px 26px 0;
  border-right: 1px solid rgba(255, 255, 255, 0.12);
}
.trust > div:last-child {
  border-right: 0;
}
.trust dt {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass-lt);
  margin-bottom: 6px;
}
.trust dd {
  margin: 0;
  color: #fff;
  font-weight: 600;
  font-size: 15px;
}
.trust dd span {
  display: block;
  font-weight: 400;
  font-size: 14.5px;
  color: var(--on-dark-dim);
  margin-top: 3px;
}
.trust a {
  color: var(--brass-lt);
}
@media (max-width: 880px) {
  .trust {
    grid-template-columns: 1fr 1fr;
  }
  .trust > div {
    border-right: 0;
    padding: 20px 16px 20px 0;
  }
}
@media (max-width: 520px) {
  .trust {
    grid-template-columns: 1fr;
  }
}

/* ---------- pricing ---------- */
.price-card {
  display: flex;
  flex-direction: column;
}
.price-card .amount {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 800;
  color: var(--ink);
  margin: 6px 0 2px;
  letter-spacing: -0.03em;
}
.price-card .unit {
  font-size: 14px;
  color: var(--steel);
}
.price-card .desc {
  margin-top: 12px;
}
.fineprint {
  margin-top: 26px;
  font-size: 15px;
  color: var(--steel);
}

/* ---------- FAQ ---------- */
.faq-item {
  border-bottom: 1px solid var(--line);
}
.faq-q {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  text-align: left;
  background: none;
  border: 0;
  padding: 20px 0;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--ink);
  cursor: pointer;
}
.faq-q:hover {
  color: var(--brass);
}
.faq-q svg {
  flex: none;
  transition: transform 0.15s;
  color: var(--brass);
}
.faq-a {
  padding: 0 0 22px;
  color: var(--steel);
  font-size: 16px;
  line-height: 1.7;
  max-width: 72ch;
}
.faq-a p {
  margin: 0 0 0.8em;
}
.faq-a p:last-child {
  margin-bottom: 0;
}

/* ---------- forms ---------- */
.field {
  display: block;
  margin-bottom: 18px;
}
.field > label,
.field-label {
  display: block;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink);
  margin-bottom: 6px;
}
.input {
  width: 100%;
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
}
.input:focus {
  outline: none;
  border-color: var(--brass);
  box-shadow: 0 0 0 3px rgba(184, 117, 43, 0.18);
}
select.input {
  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='%235f6772' 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: 18px;
  padding-right: 40px;
}
.errorlist {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  color: var(--danger);
  font-size: 14.5px;
}
.form-actions {
  display: flex;
  gap: 12px;
  margin-top: 8px;
}
.steps-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--steel);
  margin-bottom: 22px;
}
.steps-bar .on {
  /* On the white form card, so the deeper brass: --brass is 3.74:1 here. */
  color: var(--brass-text);
}
.choice-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
  margin-bottom: 18px;
}
.choice {
  display: block;
  text-align: center;
  padding: 16px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
  font-weight: 600;
  font-size: 15.5px;
}
.choice:has(:checked) {
  border-color: var(--brass);
  box-shadow: inset 0 0 0 1px var(--brass);
}
.choice input {
  display: block;
  margin: 0 auto 8px;
  accent-color: var(--brass);
}

/* ---------- misc ---------- */
.band {
  background: var(--brass-fill);
  color: #fff;
}
.band .wrap {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 34px;
  padding-top: 50px;
  padding-bottom: 50px;
  flex-wrap: wrap;
}
.band h2 {
  font-size: clamp(24px, 3vw, 34px);
  font-weight: 800;
  max-width: 560px;
  color: #fff;
}
.band p {
  margin: 10px 0 0;
  color: rgba(255, 255, 255, 0.88);
  font-size: 16px;
}
.band .btn {
  background: #fff;
  color: var(--brass-text);
  border-color: #fff;
}
.band .btn:hover {
  background: #f2e6d6;
  border-color: #f2e6d6;
  color: var(--brass);
}

.post-list {
  display: grid;
  gap: 2px;
  background: var(--line);
  border: 1px solid var(--line);
}
.post-item {
  background: var(--surface);
  padding: 26px 28px;
  text-decoration: none;
  color: inherit;
  display: block;
  transition: background 0.15s;
}
.post-item:hover {
  background: #fffdf9;
  color: inherit;
}
.post-item h2 {
  font-size: 22px;
  font-weight: 700;
  margin-bottom: 6px;
}
.post-meta {
  font-size: 13.5px;
  color: var(--steel);
  letter-spacing: 0.04em;
}
.post-item p {
  color: var(--steel);
  margin: 10px 0 0;
  font-size: 15px;
}

.notice {
  padding: 14px 18px;
  border-left: 3px solid var(--brass);
  background: rgba(184, 117, 43, 0.07);
  font-size: 15px;
}
.ok-msg {
  color: var(--good);
  font-weight: 600;
}

.cookie {
  position: fixed;
  bottom: 18px;
  left: 18px;
  right: 18px;
  max-width: 440px;
  background: var(--ink);
  color: var(--on-dark);
  border: 1px solid rgba(255, 255, 255, 0.14);
  padding: 20px 22px;
  z-index: 90;
  font-size: 15px;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
}
.cookie p {
  margin: 0 0 14px;
}
.cookie a {
  color: var(--brass-lt);
}
.cookie .row {
  display: flex;
  gap: 10px;
}
.cookie .btn {
  padding: 10px 18px;
  font-size: 15px;
}
.form-success {
  color: #1f6f4a;
  font-weight: 600;
  background: #eaf6ef;
  border: 1px solid #bfe0cd;
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 0;
}
.hidden {
  display: none;
}

/* ---------- footer ---------- */
.site-footer {
  background: var(--ink);
  color: var(--on-dark-dim);
  padding: 62px 0 28px;
  font-size: 15px;
  margin-top: auto;
}
.fgrid {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr;
  gap: 38px;
}
.site-footer h4 {
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #fff;
  margin: 0 0 14px;
}
.site-footer ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 9px;
}
.site-footer a {
  color: var(--on-dark-dim);
  text-decoration: none;
}
.site-footer a:hover {
  color: var(--brass-lt);
}
.fbot {
  margin-top: 44px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 13.5px;
}
@media (max-width: 820px) {
  .fgrid {
    grid-template-columns: 1fr 1fr;
  }
}
@media (max-width: 520px) {
  .fgrid {
    grid-template-columns: 1fr;
  }
}

/* ---------- utilities (sparingly) ---------- */
.center {
  text-align: center;
}
.muted {
  color: var(--steel);
}
.stack > * + * {
  margin-top: 18px;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- layout helpers (used by templates instead of inline styles) ---------- */
.measure {
  max-width: 820px;
}
.measure-text {
  max-width: 72ch;
}
.mt-sm {
  margin-top: 20px;
}
.mt-md {
  margin-top: 34px;
}
.mt-lg {
  margin-top: 70px;
}
.mt-xl {
  margin-top: 80px;
}
.mb-md {
  margin-bottom: 28px;
}
.h-section {
  font-size: clamp(26px, 3.2vw, 38px);
  font-weight: 800;
  max-width: 680px;
}
.h-block {
  font-size: clamp(26px, 3.2vw, 36px);
  font-weight: 800;
  margin: 12px 0 26px;
}
.h-sub {
  font-size: 24px;
  font-weight: 800;
  margin-bottom: 10px;
}
.btn-grow {
  flex: 1;
  justify-content: center;
}
.btn-wa {
  background: #25d366;
  border-color: #25d366;
  margin-top: 10px;
}
.btn-stack {
  margin-top: 10px;
}
.row {
  display: flex;
  gap: 10px;
}
.img-full {
  display: block;
  width: 100%;
  border: 1px solid var(--line);
}
.img-portrait {
  display: block;
  max-width: 420px;
  border: 1px solid var(--line);
}
.map {
  position: relative;
  z-index: 0;
  height: 340px;
  width: 100%;
  border: 1px solid var(--line);
}
.wrap-form {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 28px;
}
.post-body {
  padding-bottom: 70px;
}
.brand-footer {
  margin-bottom: 14px;
}
.footer-blurb {
  margin: 0;
  max-width: 290px;
}
.meta-line {
  margin-top: 18px;
}
.lede-gap {
  margin: 0 0 26px;
}
.date-line {
  margin: 0 0 34px;
}
.warn-msg {
  color: var(--warn);
  font-weight: 600;
}

/* ---------- StreamField rhythm ----------
   Wagtail wraps every block in .block-<name>, so spacing lives here rather
   than as per-template classes. An earlier pass converted inline styles to
   classes and silently dropped several margin-top values, which is why
   images and grids ended up flush against whatever preceded them. */
.streamfield {
  padding: 56px 0 78px;
}
.streamfield-flush {
  padding-top: 0;
}
.block-hero {
  margin-top: 0;
}
.block-heading {
  margin-top: 58px;
}
.block-paragraph {
  margin-top: 20px;
}
.block-image,
.block-portrait_image {
  margin-top: 34px;
}
.block-service_grid {
  margin-top: 30px;
}
.block-quote {
  margin-top: 36px;
}
.block-faq {
  margin-top: 64px;
}
.block-coverage_map {
  margin-top: 36px;
}
.block-reviews_coming_soon {
  margin-top: 0;
}
.streamfield > *:first-child {
  margin-top: 0;
}

/* ---------- video ---------- */
.block-video {
  margin-top: 36px;
}
.video-figure {
  margin: 0;
  max-width: 820px;
}
.video-frame {
  position: relative;
  padding-top: 56.25%;
  background: var(--ink);
  border: 1px solid var(--line);
}
.video-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.video-figure figcaption {
  margin-top: 12px;
  font-size: 15px;
  color: var(--steel);
}
.video-figure figcaption strong {
  display: block;
  color: var(--ink);
  font-weight: 600;
  margin-bottom: 2px;
}

/* ---------- hero: split layout with a product carousel ---------- */
.hero-split {
  position: relative;
}
/* Depth for the large dark field behind the copy. Anchored well left of the
   visual on purpose: the slide images fade to exactly var(--ink) at their
   edges, so any gradient reaching under them would show as a seam. */
.hero-split::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(
    46% 62% at 16% 52%,
    rgba(184, 117, 43, 0.13) 0%,
    rgba(184, 117, 43, 0.04) 46%,
    rgba(184, 117, 43, 0) 70%
  );
  pointer-events: none;
}
.hero-split .hero-in {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  grid-template-areas: "copy visual" "spec spec";
  align-items: center;
  column-gap: 44px;
  padding-top: 58px;
}
.hero-split .hero-copy {
  grid-area: copy;
}
.hero-split .spec {
  grid-area: spec;
  margin-top: 50px;
}
.hero-visual {
  grid-area: visual;
  position: relative;
  justify-self: end;
  width: 100%;
  max-width: 470px;
}
.hslides {
  display: grid;
}
.hslide {
  grid-area: 1 / 1;
  position: relative;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.6s ease,
    visibility 0.6s;
}
.hslide.on {
  opacity: 1;
  visibility: visible;
}
.hslide img {
  display: block;
  width: 100%;
  height: auto;
}
/* Overlaid, not stacked underneath: captions vary in length, so in normal
   flow each slide changed the block's height and visibly shunted the
   carousel up and down. The slide art already fades to var(--ink) at its
   bottom edge, so the text sits on the image's own dark ground. */
.hslide figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 46px 22px 16px;
  font-size: 14.5px;
  line-height: 1.5;
  color: #b4bbc4;
  background: linear-gradient(
    to bottom,
    rgba(14, 17, 22, 0) 0%,
    rgba(14, 17, 22, 0.86) 55%,
    rgba(14, 17, 22, 0.96) 100%
  );
}
.hdots {
  display: flex;
  gap: 8px;
  margin-top: 16px;
  /* Matches the caption's own horizontal padding so the dots and the caption
     text share one left edge. Flush against the image edge instead, they sat
     22px left of the caption above them — a visible step between two
     adjacent elements. Left, not centred: the whole layout is left-aligned,
     and a centred control under a left-aligned caption reads as detached. */
  padding-left: 22px;
}
.hdots button {
  width: 26px;
  height: 3px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: rgba(255, 255, 255, 0.22);
  cursor: pointer;
  transition: background 0.3s ease;
}
.hdots button.on {
  background: var(--brass-lt);
}
.hdots button:focus-visible {
  outline: 2px solid var(--brass-lt);
  outline-offset: 3px;
}
@media (prefers-reduced-motion: reduce) {
  .hslide {
    transition: none;
  }
}

/* ---------- rotating coverage area ---------- */
.rotator {
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
  height: 1.3em;
}
.rotator > span {
  grid-area: 1 / 1;
  line-height: 1.3;
  white-space: nowrap;
  color: var(--brass-lt);
  opacity: 0;
  transform: translateY(0.7em);
  animation: rotate-area 15s infinite;
}
.rotator > span:nth-child(2) {
  animation-delay: 2.5s;
}
.rotator > span:nth-child(3) {
  animation-delay: 5s;
}
.rotator > span:nth-child(4) {
  animation-delay: 7.5s;
}
.rotator > span:nth-child(5) {
  animation-delay: 10s;
}
.rotator > span:nth-child(6) {
  animation-delay: 12.5s;
}
@keyframes rotate-area {
  0% {
    opacity: 0;
    transform: translateY(0.7em);
  }
  3%,
  15% {
    opacity: 1;
    transform: translateY(0);
  }
  18%,
  100% {
    opacity: 0;
    transform: translateY(-0.7em);
  }
}
/* Reduced motion: no cycling — show the primary area, statically. */
@media (prefers-reduced-motion: reduce) {
  .rotator {
    height: auto;
  }
  .rotator > span {
    animation: none;
    opacity: 0;
    transform: none;
  }
  .rotator > span:first-child {
    opacity: 1;
  }
}

/* Balanced line lengths only above the stacked breakpoint. On narrow
   screens balancing makes the browser break inside "software-first",
   leaving "software-" hanging; greedy wrapping there gives three clean
   lines instead. */
@media (min-width: 901px) {
  .hero h1 {
    text-wrap: balance;
  }
}

@media (max-width: 900px) {
  .hero-split .hero-in {
    grid-template-columns: 1fr;
    grid-template-areas: "copy" "visual" "spec";
    row-gap: 0;
    padding-top: 34px;
  }
  .hero-split .hero-copy {
    max-width: none;
  }
  /* Left-aligned, not centred. Everything else in this design sits on the
     same left edge, so a centred visual under left-aligned copy reads as a
     mistake rather than a choice. */
  .hero-visual {
    justify-self: start;
    max-width: 340px;
    margin-top: 26px;
  }
  .hero .sub {
    margin-top: 16px;
    max-width: none;
  }
  .hero-actions {
    margin-top: 24px;
  }
  .hero-split .spec {
    margin-top: 26px;
  }
}

@media (max-width: 560px) {
  .hero-split .hero-in {
    padding-top: 28px;
  }
  /* Side by side they don't fit, and left-aligned they stack to two
     different widths, which reads as an accident. Full width is the
     deliberate-looking version and gives a bigger tap target. */
  /* With the gutters restored the copy column is 56px narrower, which
     pushed "smart lock installer" onto its own fourth line. 35px fits it
     back onto three. */
  .hero h1 {
    font-size: 35px;
  }
  .hero-actions {
    display: grid;
    gap: 10px;
  }
  .hero-actions .btn {
    justify-content: center;
    width: 100%;
  }
  /* Button labels on phones. 15px was chosen for a desktop nav button and
     carried over unchanged to a full-width tap target on a 400px screen,
     where it reads tiny against everything around it. Bigger type with less
     padding, so the button BOX stays the size it was — 52px, comfortably
     above the 44px tap target. */
  .btn,
  button[type="submit"] {
    font-size: 18px;
    padding-top: 10px;
    padding-bottom: 10px;
  }
  /* One compact line instead of a two-line block stranded on its own row
     under the buttons, where the brass rule read as a stray mark. */
  .price-tag {
    display: flex;
    align-items: baseline;
    gap: 7px;
    padding-left: 12px;
  }
  .price-tag span {
    display: inline;
  }
  .hero-visual {
    max-width: 100%;
    margin-top: 22px;
  }
  .hslide figcaption {
    padding: 34px 14px 13px;
    font-size: 13.5px;
  }
  .hdots {
    margin-top: 13px;
    padding-left: 14px;
  }
  .spec > div {
    padding: 13px 0;
  }
}

.fnote {
  margin: 34px 0 0;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.09);
  font-size: 13.5px;
  line-height: 1.6;
  color: #9aa1ac;
  max-width: 760px;
}

.legal-address {
  margin: 4px 0 18px;
  padding-left: 16px;
  border-left: 2px solid var(--brass);
  font-style: normal;
  line-height: 1.65;
}

.price-card .extra-lock {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--line);
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--steel);
}
.price-card .extra-lock strong {
  color: var(--ink);
}

/* ---------- post-submission success panel ----------
   Replaces the single line of green text that used to be the entire
   confirmation, which left the visitor on a page with no way onward. */
.success-panel {
  border: 1px solid var(--line);
  border-left: 3px solid var(--brass);
  background: var(--surface);
  padding: 32px 34px 34px;
}
.success-panel:focus {
  outline: none;
}
.success-eyebrow {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--brass-fill);
  margin: 0 0 10px;
}
.success-panel h2 {
  font-family: var(--font-display);
  font-size: clamp(23px, 2.6vw, 30px);
  line-height: 1.15;
  margin: 0 0 12px;
}
.success-lead {
  margin: 0 0 22px;
  font-size: 17px;
  color: var(--ink);
}
.success-steps {
  list-style: none;
  margin: 0 0 22px;
  padding: 0;
  border-top: 1px solid var(--line);
}
.success-steps li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15.5px;
  color: var(--steel);
}
.success-steps span {
  flex: none;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--brass-fill);
  color: #fff;
  font-size: 12.5px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.success-note {
  font-size: 15.5px;
  color: var(--steel);
  margin: 0 0 24px;
}
.success-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

.field-hint {
  font-size: 14px;
  color: var(--steel);
  margin: 6px 0 0;
}
.choice-grid-2 {
  grid-template-columns: repeat(2, 1fr);
}

/* ---------- photo upload guidance ---------- */
.photo-guide {
  border-left: 3px solid currentColor;
  padding: 2px 0 2px 16px;
  margin: 0 0 16px;
  opacity: 0.92;
}
.photo-guide-lead {
  margin: 0 0 8px;
  font-weight: 600;
  font-size: 15px;
}
.photo-guide-list {
  margin: 0 0 10px;
  padding-left: 18px;
  font-size: 15.5px;
  line-height: 1.55;
}
.photo-guide-list li + li {
  margin-top: 6px;
}
.photo-guide-note {
  margin: 0;
  font-size: 14.5px;
  opacity: 0.75;
}

/* Example photos in the booking form's photo guidance. Two side by side on
   anything wider than a phone, stacked below that. Fixed aspect via the
   width/height attributes on the <img>, so the layout does not jump while
   they load. */
.photo-guide-examples {
  display: grid;
  gap: 14px;
  list-style: none;
  padding-left: 0;
  counter-reset: none;
}
@media (min-width: 560px) {
  .photo-guide-examples {
    grid-template-columns: 1fr 1fr;
  }
}
.photo-guide-examples li + li {
  margin-top: 0;
}
.photo-guide-examples figure {
  margin: 0;
}
.photo-guide-examples img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 6px;
}
.photo-guide-examples figcaption {
  padding-top: 7px;
  font-size: 0.88rem;
  line-height: 1.45;
}

/* .label on dark grounds. --brass-text is tuned for paper and drops to 3.67
   on the hero's near-black, so the original brass returns here at 5.06. */
.hero .label,
.section-dark .label,
.band .label {
  color: var(--brass);
}

/* ---------- mid-article offer card ---------- */
/* Sits in the reading flow of a blog post. The label is deliberately small and
   the button deliberately large: the sentence explains, the button is the
   thing being offered, and a reader scanning at speed should be able to act
   without reading a word of it. */
.post-offer {
  max-width: 820px;
  margin: 44px auto;
  padding: 26px 28px;
  /* A faint warm tint rather than --brass-lt (#e8b872), which is a mid brass
     and far too saturated behind body text now the page ground is pure white.
     This lifts the card off the page without competing with the brass rule or
     the button. */
  background: #fbf7f1;
  border: 1px solid var(--line);
  border-left: 4px solid var(--brass);
}
.post-offer-label {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--brass-text);
}
.post-offer-line {
  margin: 0 0 18px;
  font-size: 16px;
  line-height: 1.55;
  color: var(--steel);
}
.post-offer-btn {
  font-size: 17px;
  padding: 14px 26px;
}
@media (max-width: 560px) {
  .post-offer {
    /* .wrap's 28px gutter already insets the article, so the card only needs
       its own breathing room, not another full gutter. */
    margin: 32px 0;
    padding: 22px 20px;
  }
  .post-offer-line {
    font-size: 15px;
  }
  .post-offer-btn {
    display: block;
    text-align: center;
    font-size: 17px;
  }
}

/* ---------- the header CTA on phones ---------- */
/* It was display:none below 1180px, so a phone visitor had NO way to reach a
   quote from any page without opening the burger menu — on the homepage, the
   service pages and every blog post alike. The button is the single most
   useful thing in that bar; the phone number can go instead, since the burger
   menu carries it. */
@media (max-width: 1180px) {
  .nav-cta .btn {
    display: inline-flex;
    padding: 9px 14px;
    font-size: 14px;
    white-space: nowrap;
  }
}
@media (max-width: 430px) {
  .nav-cta .btn {
    padding: 8px 11px;
    font-size: 13px;
  }
}

/* ---------- booking form, step 1 context ---------- */
.book-assure {
  list-style: none;
  margin: 0 0 26px;
  padding: 0 0 22px;
  border-bottom: 1px solid var(--line);
}
.book-assure li {
  position: relative;
  padding-left: 26px;
  margin-bottom: 9px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--steel);
}
.book-assure li:last-child {
  margin-bottom: 0;
}
.book-assure li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 7px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--brass);
}
.book-assure strong {
  color: var(--ink);
}
/* .card p is (0,1,1) and sets margin:0, so the bare .field-hint rule further
   up (0,1,0) loses inside this form and its margin has never applied here.
   Scoped to match the specificity rather than reaching for !important — the
   same trap as .wrap and .article-body h2, and the reason the old
   .book-step-hint rule existed before the hint moved under the select. */
.card p.field-hint {
  margin: 6px 0 0;
  font-size: 14px;
  line-height: 1.45;
  color: var(--steel);
}
/* .card p is (0,1,1) and sets margin:0, so a bare .book-step-hint (0,1,0)
   loses. This form lives inside .card, which is also why the pre-existing
   .field-hint rule's margin has never actually applied here. Matching the
   specificity rather than reaching for !important. */

/* ---------- shop: catalog, product page, featured block ---------- */
/* Pricing proof, not a shop row. The fitted figure is the one that earns, so
   it gets the size; the supply-only line sits under it as an alternative
   rather than a competing offer. */
.featprod {
  margin: 0 0 12px;
}
.featprod-intro {
  max-width: 62ch;
  color: var(--steel);
}
.featprod-grid,
.prodgrid {
  list-style: none;
  margin: 26px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 26px;
}
.featprod-grid > li,
.prodgrid > li {
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 0 0 18px;
  background: #fff;
  overflow: hidden;
}
.featprod-grid img,
.prodgrid img {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 14px;
}
.featprod-grid h3,
.prodgrid h2 {
  margin: 0 18px 6px;
  font-size: 1.1rem;
  line-height: 1.25;
}
.featprod-grid a,
.prodgrid a {
  text-decoration: none;
  color: inherit;
}
.featprod-grid a:hover h3,
.prodgrid a:hover h2 {
  color: var(--brass);
}
.featprod-sum,
.prodgrid p {
  margin: 0 18px 10px;
  font-size: 0.95rem;
  color: var(--steel);
}
.featprod-price,
.card-price {
  margin: 0 18px 2px;
  font-size: 1.02rem;
}
.featprod-price strong,
.card-price strong {
  font-size: 1.3rem;
}
.featprod-alt,
.card-price-alt {
  margin: 0 18px;
  font-size: 0.9rem;
  color: var(--steel);
}
.featprod-note {
  margin: 22px 0 0;
  font-size: 0.95rem;
  color: var(--steel);
}
.product {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 40px;
  align-items: start;
  margin: 26px 0 0;
}
.product-img {
  width: 100%;
  height: auto;
  border: 1px solid var(--line);
}
.product-buy {
  border: 1px solid var(--line);
  padding: 24px;
  background: var(--paper-2, #fbfaf8);
}
.price-fitted {
  margin: 0 0 4px;
}
.price-fitted .price-amount {
  font-size: 2rem;
  font-weight: 700;
  display: block;
  line-height: 1.1;
}
.price-supply {
  margin: 0 0 18px;
  color: var(--steel);
}
.price-supply .price-amount {
  font-weight: 600;
}
.price-label {
  font-size: 0.95rem;
}
.stock-out {
  margin: 0 0 16px;
  font-weight: 600;
}
.product-note {
  margin: 14px 0 0;
  font-size: 0.9rem;
  line-height: 1.5;
  color: var(--steel);
}
/* .prod-spec, NOT .spec: the hero strip already owns .spec, and a second
   definition later in the file overrode its grid-template-columns — turning a
   four-across desktop strip into 2x2. Order won, not specificity, so moving
   the rule would not have helped; the name had to change. */
.prod-spec {
  margin: 22px 0 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 8px 24px;
  max-width: 620px;
}
.prod-spec dt {
  font-weight: 600;
}
.prod-spec dd {
  margin: 0;
  color: var(--steel);
}
@media (max-width: 900px) {
  .featprod-grid,
  .prodgrid {
    grid-template-columns: repeat(2, 1fr);
  }
  .product {
    grid-template-columns: 1fr;
    gap: 24px;
  }
}
@media (max-width: 620px) {
  .featprod-grid,
  .prodgrid {
    grid-template-columns: 1fr;
  }
}
.price-save,
.featprod-save {
  margin: 0 0 16px;
  font-size: 0.95rem;
  color: var(--brass);
  font-weight: 600;
}
.featprod-save {
  margin: 0 18px 2px;
}
.price-save s {
  color: var(--steel);
  font-weight: 400;
}

/* ---------- cart and checkout ---------- */
.cartlist {
  list-style: none;
  margin: 26px 0;
  padding: 0;
  border-top: 1px solid var(--line);
}
.cartlist > li {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 18px;
  align-items: center;
  padding: 16px 0;
  border-bottom: 1px solid var(--line);
}
.cart-mode {
  margin: 4px 0 0;
  font-size: 0.9rem;
  color: var(--steel);
}
.cart-price {
  margin: 0;
  font-weight: 600;
  white-space: nowrap;
}
.linkish {
  background: none;
  border: 0;
  padding: 0;
  color: var(--steel);
  text-decoration: underline;
  cursor: pointer;
  font-size: 0.9rem;
}
.cart-total {
  font-size: 1.3rem;
  margin: 0 0 8px;
}
.cart-note {
  color: var(--steel);
  max-width: 60ch;
  margin: 0 0 20px;
}
.field-consent label {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-weight: 400;
  line-height: 1.5;
  font-size: 0.95rem;
}
.field-consent input {
  margin-top: 3px;
  flex: 0 0 auto;
}
#payment-element {
  margin: 0 0 20px;
}
.nav-cart {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: #c6cbd3;
  text-decoration: none;
  padding: 6px 8px;
}
.nav-cart:hover {
  color: var(--brass-lt);
}
.nav-cart-n {
  font-size: 0.8rem;
  font-weight: 700;
  background: var(--brass);
  color: #fff;
  border-radius: 999px;
  min-width: 18px;
  height: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 5px;
}

/* Shop buy controls. .btn-ghost is the lock-only choice: a real option, given
   real weight, but not the one competing with supplied-and-fitted. */
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: rgba(14, 17, 22, 0.25);
}
.btn-ghost:hover {
  background: rgba(14, 17, 22, 0.05);
  color: var(--ink);
  border-color: var(--ink);
}
.btn-sm {
  font-size: 13.5px;
  padding: 9px 15px;
}
.product-buy form + form {
  margin-top: 9px;
}
.card-buy {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
}
.card-buy form {
  margin: 0;
}

/* Brand, basket, CTA and burger do not all fit on a 375px phone — the row ran
   47px past the viewport and scrolled the page sideways. The CTA is the one
   that earns its place there; the burger menu carries a Basket link.
   This has to sit AFTER .nav-cart's own display rule, not with the other
   narrow-width rules a few hundred lines up: same specificity, so the later
   declaration wins and putting it there did nothing. */
@media (max-width: 430px) {
  .nav-cart {
    display: none;
  }
}

/* The header row overflowed every page by up to 58px on small phones —
   brand + CTA + burger against 28px gutters and a 28px gap. Longhand padding
   only: .nav-in also carries .wrap, and a shorthand here would zero the
   vertical padding .wrap's own rule is not setting. */
@media (max-width: 430px) {
  .nav-in {
    padding-left: 15px;
    padding-right: 15px;
    gap: 8px;
  }
  .brand {
    font-size: 16px;
  }
  /* Brand, WhatsApp, CTA and burger against a 375px viewport is 21px more
     than fits. Both contact routes stay — they are the two things a phone
     visitor actually taps — so the space comes out of type and gaps. */
  .nav-cta {
    gap: 8px;
  }
}

/* The header row is flex, and flex items shrink before their container
   overflows — so once the basket joined the row, "How it works", "About us"
   and the CTA broke mid-label into two lines instead of pushing the page
   wide. That is why an overflow check read zero while the bar looked mangled:
   nothing overflowed, the labels were being squashed.
   Labels never break; the row tightens its gaps instead, and collapses to the
   burger when even that is not enough. */
.nav-links a,
.nav-links > div > button,
.nav-cta .tel,
.nav-cta .btn {
  white-space: nowrap;
}
.nav-cta .btn,
.nav-cta .tel,
.nav-wa,
.nav-cart {
  flex-shrink: 0;
}
@media (min-width: 1181px) and (max-width: 1460px) {
  .nav-links {
    gap: 18px;
  }
  .nav-in {
    gap: 18px;
  }
  .nav-cta {
    gap: 10px;
  }
}

/* ---------- checkout ---------- */
.checkout {
  display: grid;
  grid-template-columns: minmax(0, 560px) minmax(0, 320px);
  gap: 34px;
  align-items: start;
  margin-top: 26px;
}
.checkout-form {
  padding: 30px;
}
.checkout-sum {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
  background: var(--surface);
  position: sticky;
  top: 92px;
}
.checkout-sum h2 {
  font-size: 1.05rem;
  margin: 0 0 14px;
}
.checkout-sum ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.checkout-sum li {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
}
.checkout-sum li small {
  display: block;
  color: var(--steel);
  font-size: 13px;
}
.checkout-total {
  display: flex;
  justify-content: space-between;
  margin: 14px 0 0;
  font-size: 17px;
}
.checkout-note {
  font-size: 13.5px;
  color: var(--steel);
  margin: 14px 0 0;
  line-height: 1.5;
}
@media (max-width: 900px) {
  .checkout {
    grid-template-columns: minmax(0, 1fr);
    gap: 24px;
  }
  /* Summary first on a phone: they should see what they are paying for before
     a screenful of fields, not after it. */
  .checkout-sum {
    order: -1;
    position: static;
  }
  .checkout-form {
    padding: 22px 18px;
  }
}
