/* ==========================================================================
   NightOps: the one stylesheet (site/assets/css/site.css)
   --------------------------------------------------------------------------
   Every page links this file and nothing else. The site's CSP allows only
   this site's own files, so there are no <style> blocks and no style=""
   attributes anywhere: every style lives here.

   Sources (do not restyle; values are the mock-up's own):
   - design/NightOps Website.dc.html             (the mock-up, inline styles)
   - design_handoff.../README.md                  (refined spec, exact values)
   - NightOps/site/src/styles/global.css + components (proven port, pixel-matched)

   Layout of this file:
     1. Fonts (self-hosted) and metric-matched fallbacks
     2. Tokens
     3. Base rules, focus ring, reduced motion, skip link
     4. Layout utilities (container, section, section heads, backgrounds)
     5. Type utilities
     6. Buttons
     7. Small components (rule, tag, status line, bullets, cards, alert card)
     8. Forms (fields, inputs, chips, error and note)
     9. Brand: owl, wordmark, logo lockups
    10. Nav and mobile menu
    11. Footer
    12. Forced colours
    13. SECTIONS: insertion points for each builder's CSS (end of file)

   Notes kept from the proven port:
   - There is deliberately NO global box-sizing reset and NO global margin
     reset: the mock-up uses browser defaults (content-box) and sets margin:0
     on each heading and paragraph. Keep that so sizes match.
   - body line-height is deliberately left at `normal`, as in the mock-up.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Fonts
   --------------------------------------------------------------------------
   Self-hosted latin subsets, WOFF2 only. Nothing is requested from Google or
   any other server. Font files are never versioned with ?v=: a changed font
   gets a new file name.
   Oxanium 300 + 800 (wordmark), 500, 600 (eyebrows, labels), 700 (headings,
   buttons). Oxanium 400 is deliberately not loaded (nor in the mock-up): the
   FAQ +/- asks for 400 and renders in 500.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Oxanium';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('/assets/fonts/oxanium-300.woff2') format('woff2');
}
@font-face {
  font-family: 'Oxanium';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/oxanium-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Oxanium';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/assets/fonts/oxanium-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Oxanium';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/oxanium-700.woff2') format('woff2');
}
@font-face {
  font-family: 'Oxanium';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/assets/fonts/oxanium-800.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/atkinson-next-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/atkinson-next-700.woff2') format('woff2');
}
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/assets/fonts/plex-mono-500.woff2') format('woff2');
}

/* Latin Extended for text visitors type (Polish, Welsh, Czech... names): in the
   inputs (Atkinson 400), labels (Atkinson 700) and the "Thanks, {first name}."
   heading (Oxanium 700). unicode-range means a browser downloads one only when
   the page shows such a letter; the page's own copy never does. Defined after
   the main faces, so they are tried first for these letters. Fontsource's
   latin-ext subsets of the same font versions (SIL OFL). */
@font-face {
  font-family: 'Oxanium';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/oxanium-700-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/assets/fonts/atkinson-next-400-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/assets/fonts/atkinson-next-700-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Metric-matched fallbacks (no download: local() points at fonts already on
   the device, which is not a network request). While the web fonts load, text
   draws in Arial (desktop) or Roboto (Android) scaled to the web font's width,
   ascent, descent and line gap, so the swap does not move the layout. Values
   measured for the proven port (see NightOps/site/src/styles/fonts.css). */
@font-face {
  font-family: 'Oxanium Fallback';
  font-weight: 300;
  src: local('Arial'), local('ArialMT'), local('Roboto'), local('Roboto-Regular');
  size-adjust: 90.2%;
  ascent-override: 87.5831%;
  descent-override: 23.2816%;
  line-gap-override: 27.7162%;
}
@font-face {
  font-family: 'Oxanium Fallback';
  font-weight: 500;
  src: local('Arial'), local('ArialMT'), local('Roboto'), local('Roboto-Regular');
  size-adjust: 102.1%;
  ascent-override: 77.3751%;
  descent-override: 20.5681%;
  line-gap-override: 24.4858%;
}
@font-face {
  font-family: 'Oxanium Fallback';
  font-weight: 600;
  src: local('Arial Bold'), local('Arial-BoldMT'), local('Roboto Bold'), local('Roboto-Bold');
  size-adjust: 97%;
  ascent-override: 81.4433%;
  descent-override: 21.6495%;
  line-gap-override: 25.7732%;
}
@font-face {
  font-family: 'Oxanium Fallback';
  font-weight: 700;
  src: local('Arial Bold'), local('Arial-BoldMT'), local('Roboto Bold'), local('Roboto-Bold');
  size-adjust: 94.6%;
  ascent-override: 83.5095%;
  descent-override: 22.1987%;
  line-gap-override: 26.4271%;
}
@font-face {
  font-family: 'Oxanium Fallback';
  font-weight: 800;
  src: local('Arial Bold'), local('Arial-BoldMT'), local('Roboto Bold'), local('Roboto-Bold');
  size-adjust: 99.4%;
  ascent-override: 79.4769%;
  descent-override: 21.1268%;
  line-gap-override: 25.1509%;
}
@font-face {
  font-family: 'Atkinson Fallback';
  font-weight: 400;
  src: local('Arial'), local('ArialMT'), local('Roboto'), local('Roboto-Regular');
  size-adjust: 98.6%;
  ascent-override: 99.7972%;
  descent-override: 32.0487%;
  line-gap-override: 0%;
}
@font-face {
  font-family: 'Atkinson Fallback';
  font-weight: 700;
  src: local('Arial Bold'), local('Arial-BoldMT'), local('Roboto Bold'), local('Roboto-Bold');
  size-adjust: 97.4%;
  ascent-override: 101.0267%;
  descent-override: 32.4435%;
  line-gap-override: 0%;
}


/* --------------------------------------------------------------------------
   2. Tokens
   --------------------------------------------------------------------------
   "Night scope" palette and the rest of the system. Most rules below use the
   literal values (as the mock-up does); the tokens carry the same values for
   new section CSS. Never introduce a colour that is not listed here.
   -------------------------------------------------------------------------- */
:root {
  /* Night scope palette */
  --scope-950: #040605;    /* page bg, hero bottom, footer, inputs */
  --scope-alt: #050907;    /* problem, pricing, installers sections ("section alt") */
  --scope-900: #07100c;    /* how it works, privacy, FAQ, booking; hero top */
  --scope-800: #0b1310;    /* cards and form panels */
  --scope-700: #18241e;    /* card borders */
  --scope-text: #e4f1e8;   /* primary text, logo */
  --text-2: #b5cbbd;       /* hero pitch, nav links, secondary text on featured surfaces */
  --text-3: #a9c0b2;       /* body copy in cards and sections */
  --scope-muted: #8aa496;  /* eyebrows, footnotes, footer text, step numbers */
  --scope-green: #49f29a;  /* status dots, focus, link hover, bullets */
  --scope-lime: #8bff6a;
  --scope-teal: #2fd3c4;
  --scope-gradient: linear-gradient(90deg, #8bff6a, #2fd3c4);
  --scope-gradient-hover: linear-gradient(90deg, #a2ff86, #45e0d2);
  --featured-gradient: linear-gradient(160deg, rgba(139, 255, 106, .16), rgba(47, 211, 196, .05)); /* pilot card */
  --featured-border: rgba(73, 242, 154, .42);
  --text-on-accent: #03100a;
  --surface-hover: #0f1a15; /* secondary button hover background */

  /* State colours */
  --signal-red: #ff3b30;   /* person and recording dots, errors. "Red means act." */
  --amber: #ffb11f;        /* vehicle and floodlight states only */
  --amber-glow: rgba(255, 177, 31, .35);

  /* 3D yard concept in the hero (mock-up YardMap) */
  --hud-bg: rgba(13, 16, 19, .8);          /* HUD chips and controls on the yard */
  --yard-vignette: rgba(0, 0, 0, .22);     /* the frame's edge darkening */

  /* Phone notification mock (alert card) */
  --notif-bg: #f2f3f5;
  --notif-text: #111111;
  --notif-meta: #6b6e74;

  /* Form error box */
  --error-bg: rgba(255, 59, 48, .12);
  --error-border: rgba(255, 59, 48, .55);
  --error-text: #ffdcd9;

  /* Glows (exact strings from the mock-up) */
  --scope-glow: radial-gradient(ellipse 70% 70% at 85% 0%, rgba(73, 242, 154, .17), rgba(73, 242, 154, 0) 70%);   /* hero */
  --glow-installers: radial-gradient(ellipse 60% 80% at 0% 0%, rgba(73, 242, 154, .13), rgba(73, 242, 154, 0) 70%); /* top-left */

  /* Lines */
  --line-rule: rgba(73, 242, 154, .4);      /* feature top rules (.rule-top) */
  --line-seam: rgba(73, 242, 154, .12);     /* section seams (.seam-top) */
  --line-faq: rgba(228, 241, 232, .12);     /* FAQ dividers */
  --line-divider: rgba(228, 241, 232, .14); /* pricing card divider */
  --line-nav: rgba(255, 255, 255, .08);     /* nav bottom, footer legal top */
  --line-footer: rgba(255, 255, 255, .06);  /* footer top border */
  --line-input: rgba(255, 255, 255, .16);   /* input border */
  --line-chip: rgba(255, 255, 255, .22);    /* chip and ghost button border */

  /* Type */
  --font-display: 'Oxanium', 'Oxanium Fallback', sans-serif;
  --font-body: 'Atkinson Hyperlegible Next', 'Atkinson Hyperlegible', 'Atkinson Fallback', system-ui, sans-serif;
  --font-mono: 'IBM Plex Mono', monospace;

  /* Radii */
  --radius-tag: 3px;       /* tags */
  --radius-hud: 4px;       /* HUD chips */
  --radius-btn: 6px;       /* buttons, inputs */
  --radius-readout: 8px;   /* readouts, error box */
  --radius-card: 12px;     /* cards, notification */
  --radius-panel: 14px;    /* large cards, media frames, form panels */
  --radius-pill: 999px;    /* chips */

  /* Shadows (nothing else uses a shadow) */
  --shadow-notification: 0 8px 24px rgba(0, 0, 0, .35);
  --shadow-menu: 0 24px 48px rgba(0, 0, 0, .55);
  --glow-status: 0 0 10px #49f29a;

  /* Motion: functional only, 120-200ms, never bounces */
  --ease-out: cubic-bezier(.2, .7, .2, 1);
  --dur-fast: 120ms;
  --dur-base: 200ms;

  /* Layout */
  --container: 1200px;
  --pad-x: clamp(20px, 5vw, 32px);        /* section side padding */
  --pad-x-nav: clamp(16px, 5vw, 32px);    /* nav side padding */
  --section-pad-y: clamp(64px, 12vw, 96px);
  --nav-offset: 60px;                     /* where anchored sections land */
  --scroll-pad: 72px;                     /* clears the sticky nav for focus scrolling */
}


/* --------------------------------------------------------------------------
   3. Base rules
   -------------------------------------------------------------------------- */
html {
  scroll-behavior: smooth;
  /* Keyboard focus must never land under the sticky nav (WCAG 2.4.11): when the
     browser scrolls a focused control into view it keeps this much clear at the
     top. The nav is 65px tall on desktop and 69px on mobile. */
  scroll-padding-top: var(--scroll-pad);
}
/* Below 320px "Book a visit" wraps and the nav grows to about 83px, so keep
   92px clear there. Section anchors still land 60px down, because .section's
   scroll-margin is worked out from the same variable. */
@media (max-width: 319.98px) {
  :root { --scroll-pad: 92px; }
}

body {
  margin: 0;
  background: #040605;
  color: #e4f1e8;
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: inherit; text-decoration: none; }
a:hover { color: #49f29a; }

input, textarea, button, select { font-family: inherit; }

/* The `hidden` attribute always wins, even over a display:flex class
   (mobile menu, form states). */
[hidden] { display: none !important; }

/* Visible keyboard focus: 2px #49f29a ring, 2px offset. Text inputs use the
   border-colour focus from .input instead; chips put the ring on their pill. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible,
[tabindex]:not([tabindex="-1"]):focus-visible {
  outline: 2px solid #49f29a;
  outline-offset: 2px;
}

/* <main id="main" tabindex="-1"> takes focus from the skip link; no ring there. */
#main:focus { outline: none; }

/* Colour changes fade in 120ms. Gradients swap instantly. */
a, button {
  transition: color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}
input, textarea { transition: border-color var(--dur-fast) var(--ease-out); }

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

/* Skip link: off-screen until focused. First element in <body>. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 50;
  background: #e4f1e8;
  color: #03100a;
  padding: 12px 16px;
  border-radius: 6px;
  font-weight: 700;
}
.skip-link:focus { left: 8px; }
.skip-link:hover,
.skip-link:focus { color: #03100a; }


/* --------------------------------------------------------------------------
   4. Layout utilities
   -------------------------------------------------------------------------- */

/* .container: the 1200px content column inside a padded section. */
.container {
  max-width: 1200px;
  margin: 0 auto;
}

/* .section: standard section padding + anchor offset under the sticky nav.
   Anchors land 60px from the top: html scroll-padding (72px) and this margin
   add up, so the margin is 60 - 72. Background comes from a .bg-* class. */
.section {
  padding: clamp(64px, 12vw, 96px) clamp(20px, 5vw, 32px);
  scroll-margin-top: calc(var(--nav-offset) - var(--scroll-pad));
}

/* .seam-top: 1px section seam (problem, installers). */
.seam-top { border-top: 1px solid rgba(73, 242, 154, .12); }

/* Section backgrounds (put one on the section root). */
.bg-950 { background: #040605; }
.bg-alt { background: #050907; }
.bg-900 { background: #07100c; }
.bg-hero { background: var(--scope-glow), linear-gradient(180deg, #07100c, #040605); }
.bg-glow-left { background: var(--glow-installers), #050907; }    /* installers */

/* .section-inner: the column of blocks inside .container (48px apart). */
.section-inner {
  display: flex;
  flex-direction: column;
  gap: 48px;
}

/* .section-head: eyebrow + H2 (+ intro) stacked 14px apart, max 720px. */
.section-head {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 720px;
}

/* .section-head-row: head on the left, side copy bottom-aligned on the right,
   wrapping (problem and pricing). Give the side copy its own max-width. */
.section-head-row {
  display: flex;
  flex-wrap: wrap;
  gap: 24px 64px;
  align-items: flex-end;
  justify-content: space-between;
}
.section-head-row > .section-head { max-width: 640px; }
/* Balanced lines: no lone "farms", and "£35 a month + VAT" stays together. */
.section-head-row .h2 { text-wrap: balance; }

/* Breakpoint helpers: the only breakpoint in the design is 960px (nav). */
@media (max-width: 959.98px) {
  .desktop-only { display: none !important; }
}
@media (min-width: 960px) {
  .mobile-only { display: none !important; }
}


/* --------------------------------------------------------------------------
   5. Type utilities
   -------------------------------------------------------------------------- */

/* .eyebrow: section label, Oxanium 600 14px/1, 0.2em, #8aa496. Write the text
   in caps in the markup ("HOW IT WORKS"); no text-transform.
   .eyebrow--bright (#e4f1e8) on the problem and installers sections. */
.eyebrow {
  margin: 0;
  font: 600 14px/1 var(--font-display);
  letter-spacing: .2em;
  color: #8aa496;
}
.eyebrow--bright { color: #e4f1e8; }

/* .h2: section heading, Oxanium 700 clamp(36px,5vw,56px)/1.02. */
.h2 {
  margin: 0;
  font: 700 clamp(36px, 5vw, 56px)/1.02 var(--font-display);
}

/* .section-intro: body 19px/1.5 intro or side copy. Colour inherits: add
   .text-2 or .text-3 as the mock-up does. */
.section-intro {
  margin: 0;
  font-size: 19px;
  line-height: 1.5;
  text-wrap: pretty;
}

/* .gradient-text: the phosphor gradient clipped to text ("Eyes on.", stats). */
.gradient-text {
  background: linear-gradient(90deg, #8bff6a, #2fd3c4);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Text colour helpers. */
.text-1 { color: #e4f1e8; }
.text-2 { color: #b5cbbd; }
.text-3 { color: #a9c0b2; }
.text-muted { color: #8aa496; }

/* .small-print: 14px muted footnote ("Source: ...", VAT note). Line height
   normal, as the mock-up's source line and price note. */
.small-print {
  margin: 0;
  font-size: 14px;
  line-height: normal;
  color: #8aa496;
}

/* .link-strong: bold inline link in primary text colour, green on hover
   (e.g. the email link in "Prefer to email?"). */
.link-strong { color: #e4f1e8; font-weight: 700; }
.link-strong:hover { color: #49f29a; }

/* .link-underline: underlined inline link in the surrounding colour. */
.link-underline { text-decoration: underline; }

/* .visually-hidden: hidden visually, kept for screen readers. */
.visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
  border: 0 !important;
}


/* --------------------------------------------------------------------------
   6. Buttons
   -------------------------------------------------------------------------- */

/* .btn-primary: gradient CTA. Oxanium 700 17px/1, caps, 0.06em tracking plus
   text-indent .06em, padding 21px 24px 15px (asymmetric on purpose: it
   optically centres Oxanium caps; keep it), radius 6. <a> or <button>.
   Per-instance sizes from the mock-up go in the section's own CSS. */
.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 21px 24px 15px;
  border: 0;
  border-radius: 6px;
  background: linear-gradient(90deg, #8bff6a, #2fd3c4);
  color: #03100a;
  font: 700 17px/1 var(--font-display);
  letter-spacing: .06em;
  text-indent: .06em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn-primary:hover {
  background: linear-gradient(90deg, #a2ff86, #45e0d2);
  color: #03100a;
}
.btn-primary:disabled,
.btn-primary[aria-disabled="true"] { cursor: default; }

/* .btn-secondary: hero "How it works". Body 700 17px, padding 16px 20px,
   1px rgba(255,255,255,.18) border, radius 6; hover background #0f1a15. */
.btn-secondary {
  display: inline-block;
  padding: 16px 20px;
  border: 1px solid rgba(255, 255, 255, .18);
  border-radius: 6px;
  background: transparent;
  color: #e4f1e8;
  font-weight: 700;
  font-size: 17px;
  cursor: pointer;
}
.btn-secondary:hover { background: #0f1a15; color: #e4f1e8; }

/* .btn-outline: pricing "Register interest". Body 700 16px, padding 15px,
   1px rgba(228,241,232,.28) border, radius 6, centred; hover inverts to an
   #e4f1e8 background with #03100a text. */
.btn-outline {
  display: inline-block;
  text-align: center;
  padding: 15px;
  border: 1px solid rgba(228, 241, 232, .28);
  border-radius: 6px;
  background: transparent;
  color: #e4f1e8;
  font-weight: 700;
  font-size: 16px;
  cursor: pointer;
}
.btn-outline:hover { background: #e4f1e8; color: #03100a; }

/* .btn-ghost: "Book another visit". Body 700 15px, padding 12px 16px,
   1px rgba(255,255,255,.22) border, radius 6; hover border #e4f1e8. */
.btn-ghost {
  display: inline-block;
  padding: 12px 16px;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 6px;
  background: transparent;
  color: #e4f1e8;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}
.btn-ghost:hover { border-color: #e4f1e8; color: #e4f1e8; }

/* .btn-row: a wrapping row of buttons, 12px apart (hero). */
.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}


/* --------------------------------------------------------------------------
   7. Small components
   -------------------------------------------------------------------------- */

/* .rule-top: feature top rule (stats, privacy columns, detail columns):
   1px rgba(73,242,154,.4) + 20px padding-top. */
.rule-top {
  border-top: 1px solid rgba(73, 242, 154, .4);
  padding-top: 20px;
}

/* .tag: gradient label. Oxanium 700 12px/1, 0.16em, padding 5px 8px, radius 3.
   .tag--plan: the pricing "NOW OPEN" badge (0.14em, 6px 9px). */
.tag {
  display: inline-block;
  font: 700 12px/1 var(--font-display);
  letter-spacing: .16em;
  background: linear-gradient(90deg, #8bff6a, #2fd3c4);
  color: #03100a;
  padding: 5px 8px;
  border-radius: 3px;
}
.tag--plan {
  letter-spacing: .14em;
  padding: 6px 9px;
}

/* .status-dot: 9px green dot with glow. .status-line: dot + text, 16px.
   The dot sits on the first line when the text wraps (phones): top-aligned,
   6px down = (21px line box - 9px dot) / 2, the same as centred on one line. */
.status-dot {
  display: inline-block;
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #49f29a;
  box-shadow: 0 0 10px #49f29a;
}
.status-line {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  font-size: 16px;
  color: #e4f1e8;
  text-wrap: pretty;   /* "... within 30 miles / of Southam", not a lone word */
}
.status-line > .status-dot { margin-top: 6px; }

/* .amber-dot: 8px floodlight dot (How it works step 2). */
.amber-dot {
  display: inline-block;
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #ffb11f;
}

/* .bullets: list with 6x6 #49f29a square bullets, 17px/1.45 #a9c0b2.
   Markup: <ul class="bullets"><li><span class="bullet" aria-hidden="true"></span><span>Text</span></li></ul> */
.bullets {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 9px;
  font-size: 17px;
  line-height: 1.45;
  color: #a9c0b2;
  text-wrap: pretty;   /* no lone last word ("... updates for / the Brain") */
}
.bullets li {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}
.bullet {
  flex: none;
  width: 6px;
  height: 6px;
  margin-top: 9px;   /* sits on the first line's x-height */
  background: #49f29a;
}

/* .card: the How it works card. #0b1310, 1px #18241e, radius 12, padding 22,
   column, 14px gap.
   .card--panel: the larger panel (pricing cards, form panels): radius 14,
   padding 28. Set its own gap in the section CSS if it differs.
   .card--featured: the pilot card's gradient and green border. */
.card {
  background: #0b1310;
  border: 1px solid #18241e;
  border-radius: 12px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.card--panel {
  border-radius: 14px;
  padding: 28px;
}
.card--featured {
  background: linear-gradient(160deg, rgba(139, 255, 106, .16), rgba(47, 211, 196, .05));
  border-color: rgba(73, 242, 154, .42);
}

/* Card contents (How it works values). */
.card-step {
  font: 500 13px/1 var(--font-mono);
  color: #8aa496;
}
.card-title {
  margin: 0;
  font: 700 26px/1.1 var(--font-display);
}
.card-text {
  margin: 0;
  font-size: 16px;
  line-height: 1.5;
  color: #a9c0b2;
  text-wrap: pretty;
}

/* .readout: the chip pinned to the bottom of a card (margin-top:auto),
   #040605, radius 8, padding 10px 12px, 13px/1.4 (as is: the recorded
   warning). Modifiers:
   --mono   IBM Plex Mono 500 12px/1.5 (timestamps, camera IDs)
   --status 13px row with a dot (e.g. .amber-dot + "Yard floodlight on") */
.readout {
  margin-top: auto;
  background: #040605;
  color: #e4f1e8;
  border-radius: 8px;
  padding: 10px 12px;
  font-size: 13px;
  line-height: 1.4;
}
.readout--mono { font: 500 12px/1.5 var(--font-mono); }
.readout--status {
  display: flex;
  align-items: center;
  gap: 8px;
  line-height: normal;
}

/* .feature: a top-ruled column (privacy cards): title Oxanium 700 26px/1.15,
   text 17px/1.55 #a9c0b2, 10px apart. */
.feature {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.feature-title {
  margin: 0;
  font: 700 26px/1.15 var(--font-display);
}
.feature-text {
  margin: 0;
  font-size: 17px;
  line-height: 1.55;
  color: #a9c0b2;
  text-wrap: pretty;
}

/* .alert-card: the phone notification ("NightOps · now / Someone's at the
   yard gate. Floodlight's on."). #f2f3f5, #111 text, radius 12, padding
   12px 14px, shadow. 28px #040605 icon tile (radius 7) holding the full owl
   at 20x14 (with its eye and beak cut-outs). Position it in the section CSS.
   Markup in CONVENTIONS.md. .alert-card--compact drops the shadow and uses
   13px text (inside a How it works card). */
.alert-card {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 12px 14px;
  border-radius: 12px;
  background: #f2f3f5;
  color: #111111;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .35);
}
.alert-card-icon {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 7px;
  background: #040605;
  color: #e4f1e8;
  display: flex;
  align-items: center;
  justify-content: center;
}
.alert-card-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 14px;
  line-height: 1.4;
  text-wrap: pretty;   /* no lone "on." on the last line in narrow cards */
}
.alert-card-text p { margin: 0; }
.alert-card-meta { color: #6b6e74; }
.alert-card--compact {
  box-shadow: none;
  border-radius: 8px;
  padding: 10px 12px;
}
.alert-card--compact .alert-card-text { font-size: 13px; }


/* --------------------------------------------------------------------------
   8. Forms (site-visit and installer-interest)
   -------------------------------------------------------------------------- */

/* .field: a <label> wrapping its control. Body 700 15px, 7px gap. */
.field {
  display: flex;
  flex-direction: column;
  gap: 7px;
  font-size: 15px;
  font-weight: 700;
}

/* .field-label: the same 15px 700 text for a label that is not a <label>
   (a <legend>, or a group heading). */
.field-label {
  font-size: 15px;
  font-weight: 700;
}
/* .field-req: the visible "*" after a required field's label (aria-hidden:
   screen readers get "required" from the input's required attribute). Each
   form opens with the note "Fields marked * are required." */
.field-req {
  margin-left: 2px;
  color: #8aa496;
}

/* .input: text inputs and textarea. 17px 400, padding 13px 14px, radius 6,
   #040605 background, rgba(255,255,255,.16) border; focus border #49f29a. */
.input {
  background: #040605;
  color: #e4f1e8;
  border: 1px solid rgba(255, 255, 255, .16);
  border-radius: 6px;
  padding: 13px 14px;
  font-size: 17px;
  font-weight: 400;
}
.input:focus { border-color: #49f29a; outline: none; }
textarea.input { resize: vertical; }
/* When focus moves up to a field (Shift+Tab, or the browser jumping to the
   first invalid field) it lands just under the sticky nav: keep 30px more
   clear so the field's label above it stays in view too. */
.input { scroll-margin-top: 30px; }
/* Placeholder hints ("CV47") in muted text: about 7.6:1 on #040605 (Chrome's
   default #757575 is only 4.41:1). */
.input::placeholder { color: #8aa496; opacity: 1; }
/* .input--caps: shows the typed text in capitals (postcode). */
.input--caps { text-transform: uppercase; }
.input--caps::placeholder { text-transform: none; }

/* .form-grid: auto-fit 200px columns, 16px gap (name / phone / email / postcode). */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 16px;
}

/* Chips: real checkboxes styled as the mock-up's toggle chips.
   Markup:
     <fieldset class="chip-group">
       <legend class="field-label">What do you want watched?</legend>
       <div class="chips">
         <label class="chip"><input class="chip-input" type="checkbox" name="watch" value="Yard"><span class="chip-label">Yard</span></label>
         ...
       </div>
     </fieldset>
   Off: transparent, 1px rgba(255,255,255,.22) border, 15px, padding 9px 14px,
   radius 999; hover border #e4f1e8. On (checked): gradient, #03100a, 700,
   border #49f29a. The checkbox itself is visually hidden but stays focusable;
   keyboard focus puts the ring on the pill. */
.chip-group {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.chip-group > legend {
  padding: 0;
  margin-bottom: 10px;
}
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.chip {
  position: relative;
  flex: none;
  display: inline-flex;
  cursor: pointer;
}
.chip-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
  scroll-margin-top: 30px;   /* as .input: the first row keeps its legend in view */
}
.chip-label {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  background: transparent;
  color: #e4f1e8;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 999px;
  padding: 9px 14px;
  font-size: 15px;
  font-weight: 400;
  line-height: normal;
  transition: border-color var(--dur-fast) var(--ease-out);
}
.chip:hover .chip-label { border-color: #e4f1e8; }
.chip-input:checked + .chip-label {
  background: linear-gradient(90deg, #8bff6a, #2fd3c4);
  color: #03100a;
  border-color: #49f29a;
  font-weight: 700;
}
.chip-input:focus-visible + .chip-label {
  outline: 2px solid #49f29a;
  outline-offset: 2px;
}
/* Chips draw about 40px tall: stretch the hit area to 44px+ without changing
   how they look. 3px above and below stays inside the 8px gap. */
.chip-label::after {
  content: '';
  position: absolute;
  inset: -3px -1px;
}

/* .form-error: the role="alert" failure box. */
.form-error {
  margin: 0;
  background: rgba(255, 59, 48, .12);
  border: 1px solid rgba(255, 59, 48, .55);
  color: #ffdcd9;
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 15px;
  line-height: 1.5;
}
.form-error a,
.form-error a:hover { color: #ffffff; font-weight: 700; text-decoration: underline; }

/* .form-note: the 14px muted note under each form ("We only use your details
   to reply to you. See our privacy notice.") and at its top ("Fields marked *
   are required."). */
.form-note {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: #8aa496;
}
.form-note a { color: #e4f1e8; text-decoration: underline; }
.form-note a:hover { color: #49f29a; }

/* Small inline links (form notes, error boxes, the problem's source line,
   "Prefer to talk? Ring ... or email ..."): invisible wider tap areas on
   mobile, without changing the look. nowrap so the stretched area covers the
   whole link. */
@media (max-width: 959.98px) {
  .form-note a,
  .form-error a,
  .book-talk a { position: relative; white-space: nowrap; }
  /* The source link is the only link in its line: an inline-block keeps it
     whole like nowrap, but can still wrap inside itself when it is wider than
     the line (320px with enlarged text spacing), so it never scrolls sideways. */
  .problem-source a,
  .pages-notfound-inner a,
  .faq-a a { position: relative; display: inline-block; }
  .form-note a::before,
  .form-error a::before,
  .problem-source a::before,
  .pages-notfound-inner a::before,
  .faq-a a::before,
  .book-talk a::before {
    content: '';
    position: absolute;
    top: 50%;
    left: -10px;
    right: -10px;
    height: 44px;
    transform: translateY(-50%);
  }
  /* The failure messages and "Prefer to talk?" hold two links in one sentence,
     and the email link can wrap onto the line under the phone number. Keep
     each tap area to its own line, so the email link's area never covers the
     phone number (inline links in a sentence are exempt from WCAG 2.5.8). */
  .form-error a::before,
  .book-talk a::before {
    top: 0;
    bottom: 0;
    height: auto;
    transform: none;
  }
}

/* .honeypot: wraps Netlify's hidden bot-field input. Never shown, never
   focusable, never read out. */
.honeypot { display: none !important; }


/* --------------------------------------------------------------------------
   9. Brand: owl, wordmark, logo lockups
   --------------------------------------------------------------------------
   The owl is always the full path with fill-rule="evenodd" (eye and beak
   cut-outs), viewBox "-1 -1 102 71.5", fill="currentColor". Never redraw it.
   -------------------------------------------------------------------------- */
.owl {
  display: block;
  flex: none;
}

/* Wordmark: NIGHT in Oxanium 800 + OPS in Oxanium 300, caps, 0.14em.
   Presentational: aria-hidden; the logo link carries the name. */
.wordmark {
  font: 18px/1 var(--font-display);
  letter-spacing: .14em;
  white-space: nowrap;
}
.wordmark--nav {
  font-size: clamp(14px, 3.6vw, 18px);
  letter-spacing: clamp(.1em, .9vw, .14em);
}
.wordmark--footer {
  font-size: 18px;
  letter-spacing: .14em;
}
.wordmark--lockup {
  display: block;
  font-size: 40px;
  letter-spacing: .14em;
  padding-left: .14em;   /* optical centring */
}
.wordmark-night { font-weight: 800; }
.wordmark-ops { font-weight: 300; }

/* Logo lockup: owl + wordmark. Stays #e4f1e8 on hover. */
.logo {
  display: flex;
  align-items: center;
  color: #e4f1e8;
}
a.logo:hover { color: #e4f1e8; }
.logo--nav { gap: 10px; flex-shrink: 0; }
.logo--footer { gap: 12px; }
@media (max-width: 959.98px) {
  .logo--nav { min-height: 44px; }   /* 44px tap target */
}

/* Stacked lockup (installers, decorative, aria-hidden): owl 200x140, the
   wordmark at 40px, SECURITY, two gradient hairlines. */
.lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 40px 0;
  position: relative;
  color: #e4f1e8;
}
.lockup-descriptor {
  font: 700 18px/1 var(--font-display);
  letter-spacing: .3em;
  padding-left: .3em;
}
.lockup-hairline { height: 1px; }
.lockup-hairline--green {
  width: 100%;
  margin-top: 22px;
  background: linear-gradient(90deg, rgba(73, 242, 154, 0), #49f29a, rgba(73, 242, 154, 0));
}
.lockup-hairline--teal {
  width: 70%;
  margin-top: 10px;
  background: linear-gradient(90deg, rgba(47, 211, 196, 0), #2fd3c4, rgba(47, 211, 196, 0));
}


/* --------------------------------------------------------------------------
   10. Nav (sticky) and mobile menu
   --------------------------------------------------------------------------
   One bar, two layouts switched at 960px:
     desktop (>= 960px): logo · links (pushed right) · "Book a site visit"
     mobile  (<  960px): logo · "Book a visit" (pushed right) · 44x44 menu button
   The mobile menu is an overlay (panel + backdrop hanging off the bar), never
   a push-down. site.js toggles it. */
.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(5, 9, 7, .86);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid rgba(255, 255, 255, .08);
}

.nav-bar {
  max-width: 1200px;
  margin: 0 auto;
  padding: 12px clamp(16px, 5vw, 32px);
  display: flex;
  align-items: center;
  gap: clamp(12px, 3vw, 32px);
}

/* Desktop links: 15px #b5cbbd, 26px gap, pushed right; hover #49f29a. */
.nav-links {
  display: flex;
  gap: 26px;
  flex-wrap: wrap;
  margin: 0 0 0 auto;
  padding: 0;
  list-style: none;
  font-size: 15px;
  color: #b5cbbd;
}
.nav-links a { display: block; white-space: nowrap; }

/* Gradient "Book" buttons. Not .btn-primary: body font, sentence case. */
.nav-book {
  flex: none;
  white-space: nowrap;
  background: linear-gradient(90deg, #8bff6a, #2fd3c4);
  color: #03100a;
  font-weight: 700;
  border-radius: 6px;
}
.nav-book:hover {
  background: linear-gradient(90deg, #a2ff86, #45e0d2);
  color: #03100a;
}
.nav-book--desktop {
  font-size: 15px;
  padding: 10px 14px;
}
.nav-book--mobile {
  position: relative;
  margin-left: auto;
  font-size: 14px;
  padding: 11px 12px;
  /* At 320-350px the bar is too narrow for logo + button + menu on one line:
     the label wraps rather than squeezing the wordmark (from 320px the rule
     below keeps it on one line). */
  flex: 0 1 auto;
  min-width: 0;
  white-space: normal;
  text-align: center;
}
/* About 39px tall: widen the tap area to 44px without changing the look. */
.nav-book--mobile::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 44px;
  transform: translateY(-50%);
}
/* 320-339px: a slightly smaller gap and side padding keep "Book a visit" on
   one line, so the bar stays 69px tall as in the mock-up. Below 320px it
   still wraps (see --scroll-pad). */
@media (min-width: 320px) and (max-width: 339.98px) {
  .nav-bar { gap: 8px; }
  .nav-book--mobile {
    padding: 11px 9px;
  }
}

/* Menu button: 44x44, 1px rgba(228,241,232,.2) border, radius 6, three 18x2 bars. */
.nav-menu-btn {
  flex: none;
  width: 44px;
  height: 44px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 0;
  background: transparent;
  border: 1px solid rgba(228, 241, 232, .2);
  border-radius: 6px;
  cursor: pointer;
}
.nav-menu-btn span {
  width: 18px;
  height: 2px;
  background: #e4f1e8;
  border-radius: 1px;
}

/* Overlay: backdrop + panel hang off the bottom of the sticky bar. */
.nav-backdrop {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 100vh;
  background: rgba(2, 4, 3, .6);
  animation: nav-fade 160ms var(--ease-out);
}

.nav-menu {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  padding: 8px clamp(16px, 5vw, 32px) 16px;
  background: rgba(5, 9, 7, .97);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-top: 1px solid rgba(73, 242, 154, .12);
  border-bottom: 1px solid rgba(73, 242, 154, .18);
  box-shadow: 0 24px 48px rgba(0, 0, 0, .55);
  font-size: 18px;
  color: #e4f1e8;
  /* border-box so padding and borders count towards max-height and the panel
     never runs past the bottom of the screen; dvh allows for phone toolbars. */
  box-sizing: border-box;
  max-height: calc(100vh - 69px);
  max-height: calc(100dvh - 69px);
  overflow-y: auto;
  overscroll-behavior: contain;
  animation: nav-menu-in 160ms var(--ease-out);
}
.nav-menu ul {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}
.nav-menu a {
  display: block;
  padding: 14px 0;
  border-bottom: 1px solid rgba(228, 241, 232, .08);
}
.nav-menu li:last-child a { border-bottom: 0; }

/* Functional motion only: a short fade and a 4px slide on open. The global
   reduced-motion rule switches it off. */
@keyframes nav-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes nav-menu-in {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

/* The overlay has no place on the desktop bar. */
@media (min-width: 960px) {
  .nav-backdrop,
  .nav-menu { display: none !important; }
}


/* --------------------------------------------------------------------------
   11. Footer
   --------------------------------------------------------------------------
   #040605, text #8aa496, padding 56px top / 40px bottom, hairline top border.
   Top row: logo lockup + footer nav. Below: the contact and legal lines
   (14px/1.6) under a hairline. */
.footer {
  background: #040605;
  color: #8aa496;
  padding: 56px clamp(20px, 5vw, 32px) 40px;
  border-top: 1px solid rgba(255, 255, 255, .06);
}

.footer-inner {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  gap: 24px 48px;
  align-items: center;
  justify-content: space-between;
}

/* Footer nav: 15px #b5cbbd, 24px gap; hover #49f29a. */
.footer-links {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 15px;
  color: #b5cbbd;
}
.footer-links a { display: block; }

/* Contact and legal lines. */
.footer-legal {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 14px;
  line-height: 1.6;
  border-top: 1px solid rgba(255, 255, 255, .08);
  padding-top: 24px;
}
.footer-legal p { margin: 0; }
.footer-legal a {
  color: #b5cbbd;
  text-decoration: underline;
}
.footer-legal a:hover { color: #49f29a; }

/* 44px tap areas on mobile: the footer links are about 19-22px tall, so an
   invisible ::before stretches each one. The gaps keep them from overlapping. */
@media (max-width: 959.98px) {
  .footer-links a,
  .footer-legal a { position: relative; }
  .footer-links a::before,
  .footer-legal a::before {
    content: '';
    position: absolute;
    top: 50%;
    left: -10px;
    right: -10px;
    height: 44px;
    transform: translateY(-50%);
  }
  /* nowrap: a link split over two lines would get no stretched area. */
  .footer-legal a { white-space: nowrap; }
}


/* --------------------------------------------------------------------------
   12. Forced colours (Windows contrast themes)
   --------------------------------------------------------------------------
   Forced colours drop gradient backgrounds. These rules only apply there, so
   normal rendering stays pixel-identical. */
@media (forced-colors: active) {
  .btn-primary,
  .nav-book { border: 1px solid ButtonText; }
  .nav-menu-btn span { background: ButtonText; }
  .status-dot,
  .amber-dot,
  .bullet { forced-color-adjust: none; }
  .chip-input:checked + .chip-label {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
    border-color: Highlight;
  }
}


/* ==========================================================================
   13. SECTIONS
   ==========================================================================
   The integrator pastes each builder's site/assets/css/_partial-<key>.css
   here, in page order, between its two markers, then deletes the partial.
   Builders: never edit anything above this line; write your CSS in your own
   partial file and prefix every class with your key (see CONVENTIONS.md).
   ========================================================================== */

/* @css:hero ------------------------------------------------------------- */
/* <header id="top" class="hero bg-hero">: not a .section (different padding).
   48-80px top, 64-96px bottom. */
.hero {
  padding: clamp(48px, 10vw, 80px) clamp(20px, 5vw, 32px) clamp(64px, 12vw, 96px);
  color: #e4f1e8;
}

/* Two flex columns that wrap, 56px apart, centred vertically. */
.hero-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 56px;
  align-items: center;
}

/* Left column: eyebrow + H1 (18px apart), pitch, buttons, status line (28px apart). */
.hero-copy {
  flex: 1 1 440px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 28px;
}
.hero-head {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.hero-eyebrow {
  margin: 0;
  font: 600 clamp(15px, 1.8vw, 18px)/1.35 var(--font-display);
  letter-spacing: .04em;
  color: #49f29a;
  text-wrap: balance;
}
.hero-h1 {
  margin: 0;
  font: 700 clamp(46px, 8vw, 104px)/.95 var(--font-display);
  letter-spacing: -.01em;
}
.hero-pitch {
  margin: 0;
  font-size: 21px;
  line-height: 1.5;
  color: #b5cbbd;
  max-width: 520px;
  text-wrap: pretty;
}

/* Right column: the 3D yard concept (handoff "2. Hero", "Yard map" variant):
   height clamp(340px,85vw,480px), radius 14, with the export's 1px
   rgba(255,255,255,.08) media-frame edge so the dark frame shows against the
   hero gradient. A <figure>: the frame, then the muted caption 12px below. */
.hero-visual {
  flex: 1 1 460px;
  min-width: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.hero-yard {
  position: relative;
  isolation: isolate;
  box-sizing: border-box;
  height: clamp(340px, 85vw, 480px);
  border-radius: 14px;
  overflow: hidden;
  background: #040605;
  border: 1px solid rgba(255, 255, 255, .08);
}
.hero-caption { text-wrap: pretty; }

/* --- The yard frame's contents (site.js section 4 drives them) -------------
   .yard-canvas: role="img" layer. It holds the still poster and, once the
   scene runs, the WebGL canvas and the "Person"/"Vehicle" label layer that
   /yard/scene.js appends. It is a stacking context (z-index 0), so the poster
   (z-index 1) covers the canvas and its labels until the scene is shown, and
   the vignette and HUD after it stay on top of everything. */
.yard-canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
}
/* Only ever focused by script (after "Load the 3D concept", or when the
   controls hide), never by Tab. A keyboard user still sees where focus is
   while the yard loads: the 2px #49f29a ring is drawn inside the frame
   (.hero-yard clips overflow), following its inner corner radius (14px less
   the 1px border). It is a pseudo-element above the poster (z-index 1): an
   outline on this element would paint under its own positioned children. */
.yard-canvas:focus { outline: none; }
.yard-canvas:focus-visible::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  border: 2px solid #49f29a;
  border-radius: 13px;
  pointer-events: none;
}

/* The poster: a real frame of this scene, just after the yard floodlight
   comes on. The running scene starts at that same frame (data-yard-frame,
   site.js section 4), so the swap is a 200ms cross-fade between
   near-identical pictures. object-fit: cover crops the sides, exactly as the
   scene's camera does on a narrower frame. */
.yard-poster {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: block;
  pointer-events: none;
}
.yard-poster-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.hero-yard.is-live .yard-poster {
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base);
}

.yard-vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse at 50% 55%, rgba(0, 0, 0, 0) 60%, rgba(0, 0, 0, .22) 100%);
}

/* HUD chips (mock-up YardMap): IBM Plex Mono 500 12px/1, padding 7px 10px,
   radius 4, rgba(13,16,19,.8), 14px in from the frame's corners. */
.yard-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 7px 10px;
  border-radius: 4px;
  background: rgba(13, 16, 19, .8);
  color: #e4f1e8;
  font: 500 12px/1 var(--font-mono);
  white-space: nowrap;
  pointer-events: none;
}
.yard-live,
.yard-badge,
.yard-status { position: absolute; }
.yard-live { top: 14px; left: 14px; }
.yard-live-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #e4f1e8;
}
/* "CONCEPT": the gradient tag look (Oxanium 700, .16em) in a HUD chip. */
.yard-badge {
  top: 14px;
  right: 14px;
  background: linear-gradient(90deg, #8bff6a, #2fd3c4);
  color: #03100a;
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: .16em;
}
/* "Watching 4 cameras" (muted) / "Floodlight on · yard" (amber). The markup
   starts lit, to match the poster. */
.yard-status {
  bottom: 14px;
  left: 14px;
  color: #8aa496;
}
.yard-status.is-lit { color: #ffb11f; }

/* "Load the 3D concept" (Save-Data, 2g/3g, reduced motion, or a failed
   download) and the status message, centred over the poster. */
.yard-centre {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  white-space: nowrap;
}
.btn-primary.yard-load {
  font-size: 15px;
  padding: 18px 18px 13px;
}
/* role="status" stays in the page (so screen readers announce new text) but
   draws nothing while it is empty. */
.yard-msg { color: #8aa496; }
.yard-msg:empty {
  padding: 0;
  background: none;
}
/* After a failed tap, "The 3D yard didn't load." sits just above the button
   (button 46px tall, chip 26px, 10px apart). */
.hero-yard.is-failed .yard-msg {
  transform: translate(-50%, calc(-50% - 46px));
}

/* Controls (shown once the scene runs): "Pause", bottom-right, clear of the
   CONCEPT badge (top-right) and the status chip (bottom-left) down to 360px.
   The box itself lets pointers through (only the button and its tap area
   catch them), so a drag that starts beside it still reaches the scene.
   The Turn left / Turn right buttons were removed at Keaton's request
   (7 Oct 2026); the arrow keys on Pause still turn and tilt the view. */
.yard-ctrls {
  position: absolute;
  right: 14px;
  bottom: 14px;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 18px;
  pointer-events: none;
}
.yard-btn {
  position: relative;
  border: 0;
  cursor: pointer;
  pointer-events: auto;
}
.yard-btn:hover { color: #49f29a; }
/* The chip draws 26px tall; its tap area is 44px (handoff "Touch targets")
   without changing the look, and stays inside the frame's 14px inset. */
.yard-btn::before {
  content: '';
  position: absolute;
  top: 50%;
  left: -4px;
  right: -4px;
  height: 44px;
  transform: translateY(-50%);
}
.yard-pause::before {
  left: -6px;
  right: -6px;
}
/* Contrast themes drop the chip background: outline the buttons. */
@media (forced-colors: active) {
  .yard-btn { border: 1px solid ButtonText; }
}
/* /@css:hero */

/* @css:problem ---------------------------------------------------------- */
/* Side copy next to the heading (inherits #e4f1e8, as in the mock-up). */
.problem-side {
  max-width: 400px;
}

/* Stats grid: auto-fit 240px columns, 32px gap; each stat has the top rule. */
.problem-stats {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 32px;
}
.problem-stat {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Big stat: Oxanium 700 clamp(56px,7vw,88px)/1, -0.02em, gradient text
   (.gradient-text on the same element). */
.problem-num {
  margin: 0;
  font: 700 clamp(56px, 7vw, 88px)/1 var(--font-display);
  letter-spacing: -.02em;
}

/* "NEARLY" prefix: 0.32em, 0.1em tracking, raised 0.9em, 0.3em gap. It shares
   the parent's gradient. The visual "NEARLY30%" is aria-hidden; screen
   readers get "Nearly 30%" from a visually hidden copy. */
.problem-prefix {
  font-size: .32em;
  letter-spacing: .1em;
  vertical-align: .9em;
  margin-right: .3em;
}

.problem-label {
  margin: 0;
  font-size: 18px;
  line-height: 1.4;
  text-wrap: pretty;   /* "... theft, / to £3.5m", not a lone "£3.5m" */
}
/* The source link's 44px mobile tap area is the shared rule in section 8. */
/* /@css:problem */

/* @css:how -------------------------------------------------------------- */
/* The four steps and the line under them, 24px apart. */
.how-body {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

/* Four cards (.card), auto-fit 210px columns, 16px gap. */
.how-steps {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 16px;
}

/* Step 04's tag is the phone alert card (compact), pinned to the card bottom
   like the other readouts. As in the mock-up it is a plain light chip: no owl
   icon tile (the full .alert-card has one), and its two lines sit together
   with no gap (the mock-up joins them with a <br>). */
.how-alert {
  margin-top: auto;
}
.how-alert .alert-card-text { gap: 0; }

/* "When it's disarmed ...": body copy under the steps. */
.how-note {
  margin: 0;
  max-width: 720px;
  font-size: 17px;
  line-height: 1.5;
  color: #a9c0b2;
  text-wrap: pretty;
}
/* /@css:how */

/* @css:system ----------------------------------------------------------- */
/* What you get (#system, .bg-950). New section, built from the How it works
   card (.card + .card-step/-title/-text), the privacy top rule (.rule-top)
   and the pilot card's surface (.card--panel.card--featured). No new colours
   or fonts.

   Item grid: 7 cards, always in full rows (no empty cell at the end):
     < 600px     1 column
     600-959px   2 columns, card 07 spans 2           -> 2+2+2+2
     960-1199px  3 columns, cards 01 and 07 span 2    -> 3+3+3
     >= 1200px   4 columns, card 07 spans 2           -> 4+4
   The breakpoints follow the section padding (clamp(20px,5vw,32px)), so every
   column stays at least 260px wide, like the mock-up's auto-fit grids. */
/* Balanced heading: "The NightOps AI / Security System", not a lone "System". */
.system-title { text-wrap: balance; }

/* Keeps a number and its unit on one line ("2 TB", "4 MP", "30 m"). */
.system-nowrap { white-space: nowrap; }

.system-items {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 16px;
}
@media (min-width: 600px) {
  .system-items { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .system-item--survey { grid-column: span 2; }
}
@media (min-width: 960px) {
  .system-items { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .system-item--brain { grid-column: span 2; }
}
@media (min-width: 1200px) {
  .system-items { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .system-item--brain { grid-column: auto; }
}
/* Keep a readable line length in the cards that span two columns. */
.system-item .card-text { max-width: 640px; }

/* The two lines (left) and the monthly service panel (right). Two columns
   from about 730px wide, stacked below that. */
.system-more {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 32px 64px;
  align-items: start;
}
.system-notes {
  display: flex;
  flex-direction: column;
  gap: 20px;
  max-width: 560px;
}

/* "What the monthly service covers": the pilot card's surface. Secondary
   text on the featured surface is #b5cbbd, as on the pilot card. */
.system-service.card { gap: 18px; }
.system-service-list { color: #b5cbbd; }
.system-service-next {
  margin: 0;
  border-top: 1px solid rgba(228, 241, 232, .14);
  padding-top: 16px;
  font-size: 16px;
  line-height: 1.5;
  color: #b5cbbd;
  text-wrap: pretty;
}
/* /@css:system */

/* @css:privacy ---------------------------------------------------------- */
/* Privacy (#privacy, .bg-900). The mock-up's ruled columns (.feature +
   .rule-top), auto-fit 260px, 32px gap: four columns at full width. */
.privacy-points {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 32px;
}
/* Four cards: the auto-fit grid gives 3 columns from 908px to 1199px, which
   leaves the fourth card alone on a second row. Use a balanced 2x2 there.
   1200px and up stays 4 across; below 908px it is already 2x2, then 1. */
@media (min-width: 908px) and (max-width: 1199.98px) {
  .privacy-points { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
/* /@css:privacy */

/* @css:pricing ---------------------------------------------------------- */
/* --------------------------------------------------------------------------
   Pricing (#pricing, .section.bg-alt)
   Values ported from the Astro Pricing component (mock-up + handoff "7.
   Pricing"). The shared .card.card--panel(.card--featured) gives the card
   surface, radius 14 and padding 28; only what is new lives here.
   -------------------------------------------------------------------------- */

/* Side copy next to the heading (mock-up: max-width 420px). */
.pricing-side { max-width: 420px; }

/* Three cards: auto-fit 280px columns, 20px gap, equal heights. */
.pricing-plans {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 20px;
  align-items: stretch;
}

/* Card: column, 22px gap. Secondary text is #a9c0b2 on the standard cards;
   the pilot card uses #b5cbbd (soft) and #e4f1e8 (strong). */
.pricing-plan.card--panel { gap: 22px; }

/* Line the cards up row by row (name block, price, monthly line, button), so
   a subline that wraps in one card ("The next 25 farms, from December 2026"
   wraps below about 1260px) never pushes its price and divider out of line
   with the others. The rows take the tallest card's block, so at full width
   the cards are 5px taller than the mock-up's (the outline button's height),
   with the buttons still bottom-aligned. Browsers without subgrid keep the
   plain column above. Not a size container (that would cancel the subgrid):
   the price block is. */
@supports (grid-template-rows: subgrid) {
  .pricing-plan.card--panel {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
    row-gap: 22px;
  }
}
.pricing-plan {
  --pricing-soft: #a9c0b2;
  --pricing-strong: #a9c0b2;
}
.pricing-plan--featured {
  --pricing-soft: #b5cbbd;
  --pricing-strong: #e4f1e8;
}

.pricing-plan-top {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pricing-plan-name-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}

.pricing-plan-name {
  margin: 0;
  font: 700 28px/1 var(--font-display);
}

.pricing-plan-subline {
  margin: 0;
  font-size: 16px;
  color: var(--pricing-strong);
  text-wrap: pretty;   /* "... from / December 2026", not a lone "2026" */
}

/* The + VAT price large (56px), "+ VAT" beside it, inc VAT underneath. */
.pricing-plan-price {
  container-type: inline-size;   /* sizes the amount below (cqi); not on the card, which is a subgrid */
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.pricing-plan-amount-row {
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}

/* 56px, as the mock-up. Only where a card is too narrow for "£1,495 + VAT"
   on one line (inner width under about 230px: 944-967px three-up, and phones
   under about 330px) does it ease down, to no less than 48px, instead of
   dropping "+ VAT" to its own line in some cards and not others. */
.pricing-plan-amount {
  font: 700 56px/1 var(--font-display);
  font-size: clamp(48px, 23.5cqi, 56px);   /* dropped by browsers without cqi: 56px stays */
}

.pricing-plan-vat {
  font-size: 17px;
  color: var(--pricing-strong);
}

.pricing-plan-inc {
  margin: 0;
  font-size: 16px;
  color: var(--pricing-soft);
}

/* Monthly line under a hairline divider; the pilot deal line (a confirm
   block) sits under it. Removing that block leaves only the main line. */
.pricing-plan-monthly {
  border-top: 1px solid rgba(228, 241, 232, .14);
  padding-top: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.pricing-plan-monthly-main {
  margin: 0;
  font-size: 17px;
  font-weight: 700;
}

/* "(£42 inc VAT)" wraps as one piece. */
.pricing-plan-monthly-inc {
  font-weight: 400;
  color: var(--pricing-soft);
  white-space: nowrap;
}

.pricing-plan-deal {
  margin: 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--pricing-soft);
  text-wrap: pretty;
}

/* Buttons pinned to the bottom of each card so they line up across the row. */
.pricing-plan-cta { margin-top: auto; }
.pricing-plan-cta--primary {
  text-align: center;
  font-size: 16px;
  padding: 19px 16px 13px;
}

/* Under the cards: the terms (a confirm block) and the VAT small print.
   Removing the terms block leaves the small print 48px under the cards, as
   in the mock-up. */
.pricing-after {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.pricing-terms {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.pricing-terms-title {
  margin: 0;
  font: 700 22px/1.2 var(--font-display);
}
/* "FITTED PRICE" label above each plan price, as in the mock-up. */
.pricing-plan-label { margin: 0; font: 600 12px/1 var(--font-display); letter-spacing: .18em; color: var(--pricing-soft); }
/* The VAT note matches the mock-up's footnote and the add-ons note (15px / 1.5). */
.pricing-after > .small-print { font-size: 15px; line-height: 1.5; text-wrap: pretty; }
/* /@css:pricing */

/* @css:addons ----------------------------------------------------------- */
/* --------------------------------------------------------------------------
   Add-ons (#add-ons, .section.bg-950)
   No mock-up: built from the site's own patterns. Column labels in the
   eyebrow style, a green rule under the header (as .rule-top), FAQ-style
   hairlines between rows, Oxanium names, body copy in #a9c0b2.
   Below 720px the table restacks into one block per add-on, with the
   column label shown above each value (data-label), so it never scrolls
   sideways. The ARIA roles in the markup keep it a table for screen readers
   when its display changes.
   -------------------------------------------------------------------------- */

.addons-body {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.addons-table {
  width: 100%;
  border-collapse: collapse;
}

.addons-table th,
.addons-table td {
  padding: 20px 24px 20px 0;
  text-align: left;
  vertical-align: baseline;
}
.addons-table th:last-child,
.addons-table td:last-child { padding-right: 0; }

/* Column labels. */
.addons-table thead th {
  padding-top: 0;
  padding-bottom: 14px;
  vertical-align: bottom;
  font: 600 12px/1.2 var(--font-display);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: #8aa496;
  border-bottom: 1px solid rgba(73, 242, 154, .4);
}

.addons-col-name { width: 24%; }
.addons-col-price,
.addons-col-inc { width: 17%; }

.addons-table tbody tr + tr { border-top: 1px solid rgba(228, 241, 232, .12); }
.addons-table tbody tr:last-child { border-bottom: 1px solid rgba(228, 241, 232, .12); }

.addons-name {
  font: 700 20px/1.25 var(--font-display);
  color: #e4f1e8;
}

.addons-for {
  font-size: 17px;
  line-height: 1.5;
  color: #a9c0b2;
  text-wrap: pretty;
}

.addons-price {
  font-size: 17px;
  line-height: 1.5;
  font-weight: 700;
  color: #e4f1e8;
}

.addons-inc {
  font-size: 17px;
  line-height: 1.5;
  color: #a9c0b2;
}

/* "+£1,194" and "24 GB" never split over two lines. */
.addons-nowrap { white-space: nowrap; }

/* Narrower table (720-959px): a little less space between columns. */
@media (max-width: 959.98px) {
  .addons-table th,
  .addons-table td { padding-right: 16px; }
  .addons-table th:last-child,
  .addons-table td:last-child { padding-right: 0; }
}

/* The number-plate note under the table. */
.addons-note {
  margin: 0;
  max-width: 720px;
  font-size: 15px;
  line-height: 1.5;
  color: #8aa496;
  text-wrap: pretty;
}

/* Below 720px (phones, including landscape at 667-719px) the four columns
   are too cramped: labels and prices wrap word by word. */
@media (max-width: 719.98px) {
  .addons-table,
  .addons-table tbody,
  .addons-table tr,
  .addons-table th,
  .addons-table td { display: block; }

  /* The header row stays for screen readers; each value shows its label. */
  .addons-table thead {
    display: block;
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .addons-table tbody { border-top: 1px solid rgba(73, 242, 154, .4); }

  /* One block per add-on: name and purpose full width, the two prices side
     by side. */
  .addons-table tbody tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px 16px;
    padding: 20px 0;
  }
  .addons-table tbody th,
  .addons-table tbody td { padding: 0; }
  .addons-name,
  .addons-for { grid-column: 1 / -1; }

  .addons-for::before,
  .addons-price::before,
  .addons-inc::before {
    content: attr(data-label);
    content: attr(data-label) / "";   /* visual only: screen readers get the column header */
    display: block;
    margin-bottom: 6px;
    font: 600 12px/1.2 var(--font-display);
    letter-spacing: .18em;
    text-transform: uppercase;
    color: #8aa496;
  }
}
/* /@css:addons */

/* @css:faq -------------------------------------------------------------- */
/* FAQ (#faq, bg #07100c). Mock-up "faq" section; Astro Faq.astro; handoff "8. FAQ".
   Left: eyebrow + H2. Right: the questions, each a native <details>/<summary>
   (no JS needed to open and close). name="faq" makes it single-open, as the
   mock-up's accordion; the first item is open in the HTML. Markup:
     <details class="faq-item" id="faq-..." name="faq">
       <summary class="faq-q"><h3 class="faq-q-row"><span class="faq-q-text">Q</span><span class="faq-sign" aria-hidden="true"></span></h3></summary>
       <p class="faq-a">A</p>
     </details>
   The flex row sits on the <h3>, not the <summary>, so older Safari (which
   could not make <summary> a flex container) lays it out the same. */
.faq-inner {
  display: flex;
  flex-wrap: wrap;
  gap: 32px 80px;
}

.faq-intro {
  flex: 1 1 280px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.faq-list {
  flex: 2 1 520px;
  min-width: 0;
  border-bottom: 1px solid var(--line-faq);
}

/* scroll-margin: a question opened from a link (#faq-plates) lands 88px
   down (html scroll-padding 72 + 16), clear of the 65-69px sticky nav. */
.faq-item {
  border-top: 1px solid var(--line-faq);
  scroll-margin-top: 16px;
}

/* The question: hide the default disclosure triangle in every engine. */
.faq-q {
  display: block;
  list-style: none;
  padding: 22px 0;
  cursor: pointer;
  color: #e4f1e8;
  transition: color var(--dur-fast) var(--ease-out);
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::marker { content: ''; }
/* Hover dims the question (mock-up). Only where a pointer can hover: on a
   touch screen the tapped question would otherwise stay dimmed. */
@media (hover: hover) {
  .faq-q:hover { color: #8aa496; }
}

.faq-q-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  margin: 0;
  font: 700 21px/1.3 var(--font-display);
}

/* "+" when closed, "−" (U+2212) when open, as the mock-up. Oxanium 400 is not
   loaded: it renders in 500, as in the mock-up. */
.faq-sign {
  flex: none;
  width: 20px;
  text-align: center;
  font: 400 28px/1 var(--font-display);
}
.faq-sign::before { content: '+'; }
.faq-item[open] > .faq-q .faq-sign::before { content: '\2212'; }

.faq-a {
  margin: 0 0 24px;
  font-size: 17px;
  line-height: 1.6;
  color: #a9c0b2;
  max-width: 660px;
  text-wrap: pretty;
}
/* /@css:faq */

/* @css:installers ------------------------------------------------------- */
/* The mock-up clips the section (the lockup column never pushes it wider). */
.installers { overflow: hidden; }

.installers-row {
  display: flex;
  flex-wrap: wrap;
  gap: 48px 80px;
  align-items: center;
}
.installers-copy {
  flex: 1 1 440px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.installers-intro { max-width: 540px; }

/* "Register your interest": the mock-up's installers button size. */
.installers-btn {
  font-size: 16px;
  padding: 20px 22px 14px;
}

/* Form card and success card: #0b1310, 1px #18241e, radius 14, padding 24,
   max 560px (handoff "9. For CCTV installers", expanded state). */
.installers-form.card,
.installers-sent.card {
  border-radius: 14px;
  padding: 24px;
  max-width: 560px;
}
.installers-form.card { gap: 16px; }
.installers-grid.form-grid { gap: 14px; }

.installers-sent.card { gap: 8px; }
.installers-sent-status {
  display: flex;
  flex-direction: column;
  gap: 8px;
  overflow-wrap: anywhere;   /* a long typed name never widens the card */
}
.installers-sent-status:focus { outline: none; }
.installers-sent-title {
  margin: 0;
  font: 700 26px/1.15 var(--font-display);
}
.installers-sent-body {
  margin: 0;
  font-size: 17px;
  line-height: 1.5;
  color: #b5cbbd;
}

/* The decorative stacked lockup takes the right column (mock-up sizing). */
.installers-lockup { flex: 1 1 320px; }
/* /@css:installers */

/* @css:book ------------------------------------------------------------- */
.book-row {
  display: flex;
  flex-wrap: wrap;
  gap: 48px 80px;
  align-items: flex-start;
}
.book-copy {
  flex: 1 1 360px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.book-intro { max-width: 460px; }

/* "Prefer to email? Write to hello@nightops.co.uk." (No phone on the site: Keaton, 6 Oct 2026.) */
.book-talk {
  margin: 0;
  font-size: 17px;
  line-height: 1.5;
  color: #b5cbbd;
}
/* Its links (about 25px tall) get the shared 44px mobile tap area in section 8. */

/* Form card: .card.card--panel gives #0b1310, 1px #18241e, radius 14, padding 28. */
.book-panel {
  flex: 1 1 480px;
  min-width: 0;
}
.book-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
.book-submit { padding: 21px 18px 15px; }

/* Success (role="status"): "Thanks, {first name}." Oxanium 700 32px, then the
   18px line and the "Book another visit" button. */
.book-sent {
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 12px 0;
}
.book-sent-status {
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-wrap: anywhere;   /* a long typed name, phone or postcode never widens the card */
}
.book-sent-status:focus { outline: none; }
.book-sent-title {
  margin: 0;
  font: 700 32px/1.1 var(--font-display);
}
.book-sent-body {
  margin: 0;
  font-size: 18px;
  line-height: 1.5;
  color: #b5cbbd;
}
/* /@css:book */

/* @css:pages (privacy.html, 404.html) ------------------------------------ */
/* --------------------------------------------------------------------------
   Pages: privacy.html and 404.html
   --------------------------------------------------------------------------
   Built from the shared classes (.h2, .section-head, .small-print, .rule-top,
   .feature-title, .feature-text, .bullets, .section, .bg-hero, .link-strong).
   Only the page layout is new here.

   Privacy notice: a title band, then one block per heading. Each block has
   the green top rule; from about 960px the heading sits on the left and the
   text on the right (the FAQ's flex split: 1 1 280px / 2 1 520px, 80px
   apart), and below that they stack. Text keeps the FAQ answer's 660px
   measure.
   -------------------------------------------------------------------------- */

/* The hero's glow and gradient, sized like the hero band, then #040605 to the
   footer, so a long page does not stretch the glow down its whole length. */
.pages-privacy {
  background:
    var(--scope-glow) top / 100% 640px no-repeat,
    linear-gradient(180deg, #07100c, #040605) top / 100% 640px no-repeat,
    #040605;
}

.pages-head {
  padding: clamp(48px, 10vw, 80px) clamp(20px, 5vw, 32px) clamp(40px, 8vw, 64px);
}

.pages-body {
  padding: 0 clamp(20px, 5vw, 32px) clamp(64px, 12vw, 96px);
}

.pages-doc {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.pages-block {
  display: flex;
  flex-wrap: wrap;
  gap: 14px 80px;
}

.pages-block-title {
  flex: 1 1 280px;
  min-width: 0;
  text-wrap: balance;
}

.pages-block-body {
  flex: 2 1 520px;
  min-width: 0;
  max-width: 660px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  overflow-wrap: break-word;
}

/* Lists read at the paragraph's line height (.feature-text, 1.55); the square
   stays on the first line's middle (.775em = half of 1.55 lines, less half
   the 6px square). */
.pages-list.bullets { line-height: 1.55; }
.pages-list .bullet { margin-top: calc(.775em - 3px); }

/* Links in the notice: primary text, underlined; green on hover. Kept on one
   line, so a phone number or "ico.org.uk/make-a-complaint" never splits (the
   longest is about 230px wide: it fits the 320px column at 360px). */
.pages-doc a {
  color: #e4f1e8;
  text-decoration: underline;
  white-space: nowrap;
}
.pages-doc a:hover { color: #49f29a; }

/* 404: the hero background on a short band, as the proven port. */
.pages-notfound { min-height: 50vh; }

.pages-notfound-inner {
  display: flex;
  flex-direction: column;
  gap: 18px;
}
/* /@css:pages */
