/* ============================================================
   smartlockinstaller.co.uk

   Rebuilt 2026-07-28 after the first attempt was, correctly, called out
   as a reskin of smartlockpro.co.uk: it kept that site's whole page
   architecture — sticky single-row nav, eyebrow/h1/sub/two-buttons hero,
   4-column spec strip, card grid, FAQ accordion, dark 3-column footer —
   and only changed the palette and typeface. Anyone visiting both would
   have recognised it immediately.

   What is deliberately different here, structurally, not just visually:
     - masthead header (brand row + nav row beneath a rule), NOT sticky,
       instead of a single sticky bar with brand-left/links-right/CTA
     - full-bleed photographic hero with the headline sitting ON it,
       instead of a text hero beside a product carousel
     - specs as an inline rule-separated run of text, not a 4-column grid
     - numbered full-width alternating image/text bands, instead of a
       heading + prose + card-grid rhythm
     - coverage as a dense district list, instead of cards
     - FAQ as an open two-column definition list with no JS, instead of
       an Alpine accordion
     - light minimal footer, instead of a dark 3-column one

   Palette is cool accent on light, chosen for maximum perceptual distance
   from smartlockpro's warm brass accent on a charcoal ground. Photography
   is duotoned into this palette (see seed_assets/build_images.py) which is
   also what stops shared source photos reading as the same pictures.
   ============================================================ */

@font-face {
  font-family: "Bricolage";
  src: url("/static/installer/fonts/bricolage-800.8269ac867c19.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
}
/* One variable file covering 400-700, declared as a range so the browser
   interpolates the real 600 rather than synthesising a fake bold from 400.
   Replaces two subsets that between them contained a single usable ASCII
   letter — "A" — which meant this site rendered in Georgia and system-ui
   from the day it was built. */
@font-face {
  font-family: "Instrument";
  src: url("/static/installer/fonts/instrument.fa41c43a3d8e.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
}

:root {
  --ink: #131a2b;
  --ink-soft: #46506a;
  --paper: #ffffff;
  --mist: #eef0f6;
  --line: #d7dbe6;
  --accent: #3d34d6;
  --accent-dark: #2c25a8;
  --wrap: 1240px;
  --display: "Bricolage", Georgia, serif;
  --body: "Instrument", system-ui, -apple-system, sans-serif;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.6;
}
h1,
h2,
h3 {
  font-family: var(--display);
  font-weight: 800;
  line-height: 1.04;
  letter-spacing: -0.025em;
  margin: 0;
  text-wrap: balance;
}
img {
  max-width: 100%;
  height: auto;
  display: block;
}
a {
  color: var(--accent);
}

.wrap {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 26px;
}
.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: 12px;
  top: 12px;
  z-index: 99;
  background: var(--ink);
  color: #fff;
  padding: 10px 14px;
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* ---------- masthead (two rows, not a sticky bar) ---------- */
.util {
  background: var(--ink);
  color: #c9d0e2;
  font-size: 13.5px;
}
.util .wrap {
  display: flex;
  gap: 22px;
  align-items: center;
  min-height: 38px;
  flex-wrap: wrap;
}
.util a {
  color: #fff;
  text-decoration: none;
  font-weight: 600;
}
.util .spacer {
  margin-left: auto;
}

.masthead {
  border-bottom: 1px solid var(--line);
}
.masthead .wrap {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
  padding-top: 26px;
  padding-bottom: 0;
}
.wordmark {
  display: block;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(21px, 2.5vw, 27px);
  letter-spacing: -0.035em;
  color: var(--ink);
  text-decoration: none;
  line-height: 1;
}
.wordmark span {
  color: var(--accent);
}
.masthead-strap {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 7px 0 0;
  /* Adding Shop and the basket widened the nav enough to squeeze this column
     and wrap the strap onto two lines, which shifted the whole brand block.
     It is one short phrase and it is meant to read as one. */
  white-space: nowrap;
}
.mastnav {
  display: flex;
  align-items: center;
  /* Gap trimmed from 26px when Shop and the basket joined the row: the nav has
     to stay one line, and wrapping it was worse than tightening it. */
  gap: 20px;
  white-space: nowrap;
  padding-bottom: 12px;
}
.mastnav a {
  color: var(--ink);
  text-decoration: none;
  font-size: 15px;
  font-weight: 600;
  padding-bottom: 10px;
  border-bottom: 2px solid transparent;
  /* Never break a label across two lines. Seven items do not fit at full
     size around 1000-1150px, and the default was to wrap the words instead
     — "What we install" over two lines, ragged against its neighbours. The
     row tightens below instead. */
  white-space: nowrap;
}
.mastnav a:hover {
  border-bottom-color: var(--accent);
}
.mast-toggle {
  display: none;
  background: none;
  border: 0;
  color: var(--ink);
  padding: 0 0 14px;
  cursor: pointer;
}
.mobnav {
  display: none;
  border-bottom: 1px solid var(--line);
  background: var(--mist);
}
.mobnav a {
  display: block;
  padding: 13px 0;
  color: var(--ink);
  text-decoration: none;
  font-weight: 600;
  border-bottom: 1px solid var(--line);
}
.mobnav a:last-child {
  border-bottom: 0;
}
[x-cloak] {
  display: none !important;
}

/* ---------- buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  background: var(--accent);
  color: #fff;
  font-family: var(--body);
  font-weight: 600;
  font-size: 16px;
  padding: 14px 24px;
  border: 2px solid var(--accent);
  border-radius: 2px;
  text-decoration: none;
  cursor: pointer;
}
.btn:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--ink);
}
.btn-ghost:hover {
  background: var(--ink);
  color: #fff;
}
.btn-light {
  background: #fff;
  color: var(--ink);
  border-color: #fff;
}
.btn-block {
  width: 100%;
  justify-content: center;
}

/* ---------- full-bleed hero ---------- */
.hero {
  position: relative;
  background: var(--ink);
  min-height: 62vh;
  display: flex;
  align-items: flex-end;
}
.hero img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Full strength. At 0.62 over the indigo --ink ground, better than a third
     of every visible pixel was flat brand colour, so the hero photograph read
     as a blue monochrome no matter what the JPEG contained — which is exactly
     what it looked like after the images were regraded to colour and the hero
     stubbornly did not change. The darkening is the scrim's job alone. */
}
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  /* Directional scrim: heaviest bottom-left where the type sits, clearing
     toward the top right so the photograph is still legible as a picture.
     Near-neutral black rather than --ink: an indigo scrim at this strength
     tints the whole frame toward the accent and reads as a colour filter. */
  background: linear-gradient(
    to top right,
    rgba(9, 11, 17, 0.95) 0%,
    rgba(9, 11, 17, 0.84) 30%,
    rgba(9, 11, 17, 0.46) 62%,
    rgba(9, 11, 17, 0.1) 88%
  );
}
.hero-in {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-top: 96px;
  padding-bottom: 46px;
}
.hero h1 {
  color: #fff;
  /* 74px over a 15ch measure broke the headline across four lines and let
     it swallow the photograph. Longer measure, slightly smaller cap. */
  font-size: clamp(34px, 5.2vw, 62px);
  max-width: 19ch;
}
.hero .sub {
  color: #d6dcec;
  font-size: clamp(17px, 1.7vw, 20px);
  max-width: 50ch;
  margin: 22px 0 0;
}
.hero-actions {
  margin-top: 30px;
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}

/* Specs as an inline rule-separated run, not a column grid. */
.specline {
  background: var(--ink);
  color: #b9c2d8;
  font-size: 14px;
}
.specline .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0 30px;
  padding-top: 15px;
  padding-bottom: 15px;
}
.specline b {
  color: #fff;
  font-weight: 600;
}
.specline span + span::before {
  content: "";
  display: inline-block;
  width: 1px;
  height: 11px;
  background: rgba(255, 255, 255, 0.28);
  margin-right: 30px;
  vertical-align: -1px;
}

/* ---------- vertical rhythm ----------
   Wagtail wraps every StreamField block in <div class="w-block-x block-x">,
   so the block's own <section> is a grandchild of <main> and can never be
   targeted as a child. Spacing therefore has to live on these wrappers.
   Full-bleed blocks (hero, process bands, CTA strip) carry their own
   padding and must be exempt, or they gain a stripe of page background. */
main > [class*="block-"] {
  padding: 36px 0;
}
main > .block-hero,
main > .block-process,
main > .block-cta {
  padding: 0;
}
main > .block-heading {
  padding-bottom: 6px;
}
main > .block-hero + * {
  padding-top: 62px;
}
main > [class*="block-"]:last-child {
  padding-bottom: 84px;
}
main > .block-cta:last-child {
  padding-bottom: 0;
}

/* ---------- prose / headings ---------- */
.section {
  padding: 74px 0;
}
.section-mist {
  background: var(--mist);
}
.h-section {
  font-size: clamp(28px, 3.6vw, 44px);
  max-width: 20ch;
}
.prose {
  max-width: 66ch;
  font-size: 17.5px;
  line-height: 1.68;
}
.prose > * {
  margin: 0;
}
.prose > * + * {
  margin-top: 1.05em;
}
.prose ul {
  padding-left: 1.15em;
}
.prose li + li {
  margin-top: 0.4em;
}
.lede {
  font-size: clamp(19px, 2.1vw, 24px);
  line-height: 1.45;
  max-width: 34ch;
  color: var(--ink);
}

/* ---------- numbered alternating bands ---------- */
.band {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  border-top: 1px solid var(--line);
}
.band-media {
  position: relative;
  min-height: 380px;
  background: var(--mist);
}
.band-media img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.band-body {
  padding: 58px clamp(26px, 5vw, 84px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  max-width: 660px;
}
/* Reverse every other band so the eye zig-zags down the page. */
.band:nth-child(even) .band-media {
  order: 2;
}
.band-num {
  font-family: var(--display);
  font-weight: 800;
  font-size: 15px;
  letter-spacing: 0.06em;
  color: var(--accent);
}
.band h3 {
  font-size: clamp(24px, 2.8vw, 34px);
  margin: 10px 0 14px;
}
.band p {
  margin: 0;
  color: var(--ink-soft);
  max-width: 46ch;
}
.band p + p {
  margin-top: 0.9em;
}

/* ---------- coverage list ---------- */
.districts {
  columns: 3;
  column-gap: 40px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.districts li {
  break-inside: avoid;
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15.5px;
}
.districts .code {
  font-weight: 600;
  min-width: 76px;
}
.districts .where {
  color: var(--ink-soft);
}

/* ---------- FAQ: open list, no accordion, no JS ---------- */
.qa {
  columns: 2;
  column-gap: 56px;
  margin: 0;
}
.qa > div {
  break-inside: avoid;
  margin-bottom: 30px;
}
.qa dt {
  font-weight: 600;
  font-size: 17px;
  margin-bottom: 7px;
}
.qa dd {
  margin: 0;
  color: var(--ink-soft);
  font-size: 16px;
}

/* ---------- page head (interior pages) ---------- */
.page-head {
  border-bottom: 1px solid var(--line);
  padding: 54px 0 44px;
}
.page-head .crumb {
  font-size: 13.5px;
  color: var(--ink-soft);
  margin: 0 0 14px;
}
.page-head h1 {
  font-size: clamp(34px, 5vw, 58px);
  max-width: 17ch;
}
.page-head .intro {
  margin-top: 18px;
  max-width: 58ch;
  color: var(--ink-soft);
  font-size: 18px;
}

/* ---------- forms ---------- */
.field {
  display: block;
  margin-bottom: 18px;
}
.field > label,
.field-label {
  display: block;
  font-size: 13.5px;
  font-weight: 600;
  margin-bottom: 6px;
}
.input {
  width: 100%;
  font-family: inherit;
  font-size: 16px;
  color: var(--ink);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 2px;
  padding: 13px 14px;
}
.input:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.form-actions {
  display: flex;
  gap: 12px;
  margin-top: 8px;
}
.steps-bar {
  display: flex;
  gap: 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 24px;
}
.steps-bar .on {
  color: var(--accent);
}
.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: 2px;
  background: #fff;
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
}
.choice:has(:checked) {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.choice input {
  display: block;
  margin: 0 auto 8px;
  accent-color: var(--accent);
}
.form-success {
  color: #1c3fb0;
  font-weight: 600;
  background: #e8ebfb;
  border: 1px solid #c3cbf3;
  border-radius: 2px;
  padding: 14px 16px;
  margin: 0;
}

/* ---------- CTA strip ---------- */
.cta {
  background: var(--ink);
  color: #fff;
  padding: 64px 0;
}
.cta h2 {
  color: #fff;
  font-size: clamp(28px, 3.6vw, 42px);
  max-width: 20ch;
}
.cta p {
  color: #c3cbdf;
  max-width: 50ch;
  margin: 16px 0 28px;
}

/* ---------- footer: light, minimal, single row ---------- */
.site-footer {
  border-top: 1px solid var(--line);
  padding: 40px 0 46px;
  font-size: 14.5px;
  color: var(--ink-soft);
}
.site-footer a {
  color: var(--ink-soft);
  text-decoration: none;
}
.site-footer a:hover {
  color: var(--accent);
}
.frow {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 28px;
  align-items: baseline;
}
.frow .spacer {
  margin-left: auto;
}
.fnote {
  margin: 26px 0 0;
  font-size: 12.5px;
  max-width: 92ch;
  color: #6b7488;
}
.fbot {
  margin-top: 16px;
  display: flex;
  gap: 8px 22px;
  flex-wrap: wrap;
  font-size: 12.5px;
}

/* ---------- cookie banner ---------- */
.cookie {
  position: fixed;
  bottom: 18px;
  left: 18px;
  right: 18px;
  max-width: 430px;
  background: var(--ink);
  color: #dfe4f2;
  padding: 20px 22px;
  z-index: 90;
  font-size: 14px;
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.32);
}
.cookie p {
  margin: 0 0 14px;
}
.cookie a {
  color: #fff;
}
.cookie .row {
  display: flex;
  gap: 10px;
}
/* base.html's cookie banner markup uses .btn-outline. The rebuild renamed
   that variant to .btn-ghost, which left both consent buttons rendering as
   the same solid indigo — so "Essential only" and "Accept all" were visually
   indistinguishable, on the one control where the choice has to be obvious. */
.cookie .btn-outline {
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, 0.45);
}
.cookie .btn-outline:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: #fff;
}
.hidden {
  display: none;
}

@media (max-width: 1180px) {
  .masthead {
    position: relative;
    z-index: 10;
  }
  /* DIRECT CHILD, not a descendant selector. .mobnav lives inside .masthead,
     so `.masthead .wrap` also matched `.mobnav .wrap` and pushed the header's
     card treatment — and its align-items: flex-start — onto the menu panel.
     That is why the menu links shrank to their own text width and their
     underlines came out as ragged stubs instead of full-width rules. */
  /* Full-width bar, not an inset card. Insetting it exposed the card's own
     left and right borders as two vertical strokes either side of the logo
     and burger, which read as stray bracket marks. The surface and shadow
     live on .masthead so the bar spans the viewport, while the padding
     keeps its contents on the page's 26px gutter. */
  .masthead {
    background: #ffffff;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06);
  }
  .masthead > .wrap {
    align-items: flex-start;
    justify-content: space-between;
    flex-wrap: nowrap;
    margin: 0;
    padding: 14px 26px;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  .masthead > .wrap > div:first-child {
    min-width: 0;
    flex: 1 1 auto;
  }
  .masthead-strap {
    display: none;
  }
  /* No !important needed: this matches .mastnav at the same specificity and
     sits later in the file, so it already wins. */
  .mastnav {
    display: none;
  }
  .mast-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-left: auto;
    padding: 0;
    line-height: 1;
    align-self: flex-start;
  }
  .mast-toggle svg {
    display: block;
  }
  /* Overlays rather than pushing the page down, and is styled explicitly
     here instead of inheriting the header's box by accident. Same margin,
     border and radius as the header card above it, so the two read as one
     component. */
  .mobnav {
    display: block;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    width: 100%;
    border: 0;
    border-bottom: 1px solid var(--line);
    background: #ffffff;
    box-shadow: 0 18px 34px rgba(0, 0, 0, 0.12);
  }
  .mobnav .wrap {
    display: flex;
    flex-direction: column;
    /* stretch, so each row fills the panel and its underline is a full-width
       rule. Without it the rows shrink-wrapped their text. */
    align-items: stretch;
    margin: 0;
    padding: 4px 26px 14px;
    background: transparent;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
  .mobnav a {
    display: block;
    padding: 15px 2px;
  }
  .band {
    grid-template-columns: 1fr;
  }
  .band:nth-child(even) .band-media {
    order: 0;
  }
  .band-media {
    min-height: 260px;
  }
  .band-body {
    padding: 40px 26px;
    max-width: none;
  }
  .districts {
    columns: 2;
  }
  .qa {
    columns: 1;
  }
}
/* The inline dividers only work while the spec strip is a single row. Once
   it wraps, every item starting a new line carries a leading bar with
   nothing before it, reading as a broken bullet list. Below this width the
   strip becomes an explicit stack instead. */
@media (max-width: 760px) {
  .specline .wrap {
    flex-direction: column;
    gap: 7px;
  }
  .specline span + span::before {
    display: none;
  }
}

@media (max-width: 620px) {
  /* The strap wraps to two lines beside the burger at this width and
     unbalances the masthead; the same claims are on the page anyway. */
  .masthead-strap {
    display: none;
  }
  .districts {
    columns: 1;
  }
  .choice-grid {
    grid-template-columns: 1fr;
  }
  .hero {
    min-height: 56vh;
  }
  .util .wrap {
    font-size: 12.5px;
    gap: 14px;
  }
}

.formwrap {
  max-width: 620px;
}

/* ---------- contact page ---------- */
.contact-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 340px);
  gap: 56px;
  align-items: start;
}
.contact-aside h2 {
  font-size: 20px;
  margin-bottom: 18px;
}
.contact-list {
  margin: 0;
}
.contact-list > div + div {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.contact-list dt {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 5px;
}
.contact-list dd {
  margin: 0;
  font-size: 15.5px;
}
@media (max-width: 900px) {
  .contact-cols {
    grid-template-columns: 1fr;
    gap: 40px;
  }
}

/* ---------- post-submission success panel ----------
   Shared template with smartlockpro (home/templates/booking/_success.html),
   this brand's values. Replaces the single line of text that used to be the
   whole confirmation and left the visitor with nowhere to go. */
.success-panel {
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  background: var(--mist);
  padding: 34px 36px 36px;
}
.success-panel:focus {
  outline: none;
}
.success-eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 10px;
}
.success-panel h2 {
  font-family: var(--display);
  font-size: clamp(24px, 2.8vw, 33px);
  line-height: 1.1;
  margin: 0 0 12px;
}
.success-lead {
  margin: 0 0 24px;
  font-size: 17px;
}
.success-steps {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
}
.success-steps li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15.5px;
  color: var(--ink-soft);
}
.success-steps span {
  flex: none;
  width: 21px;
  height: 21px;
  background: var(--accent);
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.success-note {
  font-size: 14.5px;
  color: var(--ink-soft);
  margin: 0 0 26px;
}
.success-actions {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
}

/* ---------- quote form ----------
   This brand's own form (installer/booking/_form.html), not smartlockpro's
   three-step wizard. Everything on one screen, in numbered sections, with a
   wider measure than the other site's narrow single column. */
.formwrap {
  max-width: 780px;
}
.qsection {
  padding: 26px 0 4px;
  border-top: 1px solid var(--line);
}
.qsection:first-of-type {
  border-top: 0;
  padding-top: 0;
}
.qlegend {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: 19px;
  margin: 0 0 18px;
}
.qnum {
  font-family: var(--display);
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: var(--accent);
}
.qgrid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 18px;
}
.qgrid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0 18px;
}
/* Inline pills, not the other site's three equal cards in a grid. */
.qchoices {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}
.qchoice {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #fff;
  cursor: pointer;
  font-size: 14.5px;
  font-weight: 600;
}
.qchoice:has(:checked) {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.qchoice input {
  margin: 0;
  accent-color: var(--accent);
}
.qsubmit {
  margin-top: 26px;
  padding-top: 22px;
  border-top: 1px solid var(--line);
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}
.qsubmit p {
  margin: 0;
  font-size: 14px;
  color: var(--ink-soft);
  max-width: 42ch;
}
@media (max-width: 720px) {
  .qgrid-2,
  .qgrid-3 {
    grid-template-columns: 1fr;
  }
}

.field-hint {
  font-size: 13px;
  color: var(--ink-soft);
  margin: 6px 0 0;
}

/* ---------- 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: 14.5px;
  line-height: 1.55;
}
.photo-guide-list li + li {
  margin-top: 6px;
}
.photo-guide-note {
  margin: 0;
  font-size: 13.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;
}

/* ---------- notes index + note ---------- */
/* A ruled list, not cards. The installer identity is a masthead over a rule
   and full-width bands — a grid of rounded cards here would be smartlockpro's
   language, and these two sites deliberately share no markup or styling. */
.note-list {
  list-style: none;
  margin: 0 0 72px;
  padding: 0;
  border-top: 1px solid var(--line);
}
.note-list li {
  border-bottom: 1px solid var(--line);
}
.note-list a {
  display: block;
  padding: 26px 0;
  text-decoration: none;
  color: inherit;
}
.note-list a:hover {
  background: var(--mist);
}
.note-list time {
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.note-list h2 {
  font-family: var(--display);
  font-size: 27px;
  line-height: 1.2;
  margin: 6px 0 8px;
  color: var(--ink);
}
.note-list p {
  margin: 0;
  max-width: 68ch;
  color: var(--ink-soft);
  line-height: 1.55;
}
.note-empty {
  padding: 26px 0;
  color: var(--ink-soft);
}
.note-meta {
  margin: 0 0 18px;
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
@media (max-width: 640px) {
  .note-list h2 {
    font-size: 23px;
  }
  .note-list a {
    padding: 20px 0;
  }
}

/* ---------- masthead quote button, phones only ---------- */
/* Shown exactly when the nav row stops carrying "Request a quote" — i.e.
   when .mastnav collapses behind the burger, which happens at 980px.

   This used to appear at 900px on the reasoning that "the nav row already
   carries it above here". It does not: the nav hides at 980. That left an
   80px band, 901-980px, with the nav behind a burger and no quote button
   anywhere on the page — a range that includes real tablet and small-laptop
   widths. Keep this number equal to the .mastnav collapse breakpoint. */
.mast-quote {
  display: none;
  background: var(--accent);
  color: #fff;
  text-decoration: none;
  font-weight: 600;
  font-size: 14px;
  padding: 9px 14px;
  white-space: nowrap;
  margin-left: auto;
  margin-right: 10px;
}
.mast-quote:hover {
  background: var(--accent-dark);
}
@media (max-width: 1180px) {
  .mast-quote {
    display: inline-flex;
    align-items: center;
  }
}
@media (max-width: 400px) {
  .mast-quote {
    font-size: 13px;
    padding: 8px 11px;
    margin-right: 6px;
  }
}

/* Lead band on the intro-only pages (contact, notes index). Those two
   carried no image at all — a page of grey text with a form under it gives
   a visitor nothing to look at while they decide whether to trust us. */
.lead-band {
  display: block;
  width: 100%;
  height: auto;
  max-height: 340px;
  object-fit: cover;
  margin: 26px 0 0;
}

/* "Who we work for" grid. Deliberately not a row of rounded white cards on
   a tinted ground — that is smartlockpro's service grid and the two sites
   have already been called out once for reading as the same page. These are
   flush panels divided by rules, with the accent only on the left edge. */
.aud {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.aud > li {
  background: var(--paper);
  padding: 26px 24px 24px;
  border-left: 3px solid transparent;
  transition:
    border-color 0.15s ease,
    background 0.15s ease;
}
.aud > li:hover {
  border-left-color: var(--accent);
  background: var(--mist);
}
.aud h3 {
  font-family: var(--display);
  font-size: 1.18rem;
  font-weight: 800;
  line-height: 1.2;
  margin: 0 0 8px;
  color: var(--ink);
}
.aud p {
  margin: 0 0 14px;
  font-size: 0.97rem;
  line-height: 1.5;
  color: var(--ink-soft);
}
.aud a {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
}
.aud a:hover {
  color: var(--accent-dark);
}
@media (max-width: 900px) {
  .aud {
    grid-template-columns: repeat(2, 1fr);
  }
}
@media (max-width: 620px) {
  .aud {
    grid-template-columns: 1fr;
  }
}

/* "Request a quote" as a button in the nav row, not a seventh plain link.

   It sat between "Contact" and nothing, styled identically to "Notes" and
   "Coverage" — so the one item on the page that is the actual conversion
   carried no more weight than a link to a blog index. Only the phone
   breakpoint had a visible button (.mast-quote), and desktop is where most
   of this site's traffic reads.

   align-self keeps it centred without touching .mastnav's alignment, which
   the text links' hover underline depends on. */
.mastnav a.nav-cta {
  align-self: center;
  margin-left: 4px;
  background: var(--accent);
  color: #fff;
  padding: 11px 20px;
  border: 2px solid var(--accent);
  border-radius: 2px;
}
.mastnav a.nav-cta:hover {
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}

/* Between the nav collapsing (980px) and the width where seven items fit
   comfortably, tighten the row rather than let labels wrap. Below 980 this
   is all moot — the burger takes over. */
@media (min-width: 1181px) and (max-width: 1400px) {
  .mastnav {
    gap: 15px;
  }
  .mastnav a {
    font-size: 14px;
  }
  .mastnav a.nav-cta {
    padding: 10px 14px;
  }
}

/* Footer area links. These are the pages local search lands on, and they
   were reachable only from /coverage/ — one click in, and in practice
   unfindable. Kept as their own labelled row rather than dropped into the
   main link run, which would have made that row twenty links long. */
.fareas {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 18px;
  margin: 20px 0 0;
  padding: 18px 0 0;
  border-top: 1px solid var(--line);
  font-size: 14px;
}
.fareas-label {
  font-weight: 700;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.fareas a {
  color: var(--ink-soft);
  text-decoration: none;
  border-bottom: 1px solid transparent;
}
.fareas a:hover {
  color: var(--accent);
  border-bottom-color: currentColor;
}
.fareas a.fareas-all {
  color: var(--accent);
  font-weight: 600;
}

/* Shop buy controls and the masthead basket. Square-cornered and rule-edged
   like the rest of this site's furniture — deliberately not smartlockpro's
   pill-and-badge treatment. */
.mast-cart {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ink);
  text-decoration: none;
  padding: 4px 6px;
}
.mast-cart:hover {
  color: var(--accent);
}
.mast-cart-n {
  font-family: var(--body);
  font-size: 12px;
  font-weight: 700;
  background: var(--accent);
  color: #fff;
  min-width: 17px;
  height: 17px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 4px;
  border-radius: 2px;
}
.btn-line {
  background: transparent;
  color: var(--ink);
  border-color: var(--ink);
}
.btn-line:hover {
  background: var(--ink);
  color: #fff;
  border-color: var(--ink);
}
.btn-sm {
  font-size: 14px;
  padding: 10px 16px;
  border-width: 1px;
}
.buyrun-acts,
.prodrun-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: 16px 0 0;
}
.buyrun-acts form,
.prodrun-acts form {
  margin: 0;
}
.prodrun-out {
  font-family: var(--body);
  font-size: 14px;
  color: var(--ink-soft);
  margin-top: 12px;
}

/* ---------- checkout ---------- */
.cosum {
  border-top: 2px solid var(--ink);
  margin: 22px 0 0;
  max-width: 680px;
}
.cosum p {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 16px;
  align-items: baseline;
  margin: 0;
  padding: 13px 0;
  border-bottom: 1px solid var(--line);
}
.cosum p span {
  color: var(--ink-soft);
  font-size: 15px;
}
.cosum p b {
  font-weight: 700;
  min-width: 82px;
  text-align: right;
}
/* .cosum .cosum-total, not .cosum-total: `.cosum p` is (0,1,1) and beats a
   bare class (0,1,0), so the heavier rule under the total silently stayed a
   1px hairline. Same family as .article-body h2 vs .verdict-head. */
.cosum .cosum-total {
  /* Flex, not the item rows' three-column grid: the total has no
     "supplied and fitted" middle cell, and re-declaring the grid left the
     amount auto-placed onto a second row. Two children, space-between. */
  display: flex;
  justify-content: space-between;
  border-bottom-width: 2px;
  border-bottom-color: var(--ink);
  font-size: 18px;
}
.cosum-note {
  max-width: 680px;
  color: var(--ink-soft);
  font-size: 15px;
  margin: 14px 0 0;
}
.coform {
  max-width: 520px;
  margin-top: 30px;
}
