/* ==========================================================================
   SENTINEL PROJECTS — MAIN.CSS
   Brand overrides on top of Bootstrap 5.3 + Bootstrap Icons (both loaded
   separately, self-hosted, from assets/vendor/ — see includes/head.php).
   This file must load AFTER those two so its rules win the cascade.

   Assembled from two source files, in order:
     1. design-system.css — brand tokens + component styles (design system v1.0)
     2. additional.css    — consent banner, honeypot, breadcrumb spacing, extras
   ========================================================================== */

/* ============== FROM design-system.css (design system v1.0) ============== */
/* ==========================================================================
   SENTINEL PROJECTS — DESIGN SYSTEM
   Built on Bootstrap 5.3, restyled to brand tokens.
   Spacing: strict 8px baseline grid (0.5rem increments).
   Colour: WCAG AA verified pairs only (see comments per pair).
   Motion: 150–300ms, transform/opacity only, reduced-motion aware.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. TYPEFACE — General Sans (Indian Type Foundry, via Fontshare, OFL/FFL
   free for commercial use). Self-hosted per architecture doc §4: max two
   font files, woff2 only, font-display: swap. Chosen over Inter/system-ui
   for more character while keeping the same screen-legibility discipline
   at small sizes (form labels, table data, secondary copy).
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'General Sans';
  src: url('../fonts/GeneralSans-SemiBold.woff2') format('woff2');
  font-weight: 600 800; /* static file mapped across 600–800 — everything in this system heavier
                            than regular resolves to this one semibold cut, so no request ever
                            falls back to synthetic faux-bold */
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   1. DESIGN TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* Brand colours — the only three hex values used raw; everything else
     below is derived from these so the palette can never drift. */
  --sp-dark: #142029;          /* dark backgrounds, dark text on light grey */
  --sp-accent: #CA202F;        /* CTAs, banners, accent */
  --sp-white: #FFFFFF;         /* white text on dark bg / on accent */

  /* Derived neutrals (tinted from --sp-dark so greys feel bonded to brand,
     not generic Bootstrap grey) */
  --sp-grey-100: #F5F6F7;      /* light grey page background */
  --sp-grey-200: #E7E9EB;      /* subtle section separators */
  --sp-grey-300: #CBD0D4;      /* borders, dividers */
  --sp-grey-500: #6B7680;      /* secondary/muted text — 4.6:1 on white */
  --sp-grey-700: #3A464E;      /* tertiary dark surface (cards on dark) */

  /* Accent tonal ramp — for hover/active states without introducing a new hue */
  --sp-accent-600: #A81A27;    /* accent hover/pressed (darker, keeps 4.5:1+ with white) */
  --sp-accent-100: #FBE8E9;    /* accent tint for subtle backgrounds/badges */

  /* Semantic tokens — this is what components actually consume */
  --color-bg-page: var(--sp-grey-100);
  --color-bg-surface: var(--sp-white);
  --color-bg-dark: var(--sp-dark);
  --color-bg-dark-raised: var(--sp-grey-700);
  --color-text-primary: var(--sp-dark);
  --color-text-secondary: var(--sp-grey-500);
  --color-text-on-dark: var(--sp-white);
  --color-text-on-dark-secondary: #B8C0C6; /* 4.6:1 on --sp-dark */
  --color-border: var(--sp-grey-300);
  --color-border-on-dark: rgba(255,255,255,0.16);
  --color-cta: var(--sp-accent);
  --color-cta-hover: var(--sp-accent-600);
  --color-cta-tint: var(--sp-accent-100);
  --color-focus-ring: #4DA3FF; /* distinct from brand red so focus is never mistaken for error/CTA */

  /* 8px baseline spacing scale — every gap, padding, margin in this system
     traces back to one of these. (4px reserved only for icon-to-label gaps.) */
  --space-1: 0.25rem;  /* 4px  — micro (icon/label gap only) */
  --space-2: 0.5rem;   /* 8px  — base unit */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-7: 3rem;     /* 48px */
  --space-8: 4rem;     /* 64px */
  --space-9: 6rem;     /* 96px */
  --space-10: 8rem;    /* 128px */

  /* Radius scale */
  --radius-sm: 0.25rem;  /* 4px  — badges, small chips */
  --radius-md: 0.5rem;   /* 8px  — buttons, inputs, cards */
  --radius-lg: 0.75rem;  /* 12px — larger cards, modals */
  --radius-pill: 999px;

  /* Elevation — consistent scale, used sparingly, never decorative-only */
  --shadow-sm: 0 1px 2px rgba(20,32,41,0.08);
  --shadow-md: 0 4px 12px rgba(20,32,41,0.10);
  --shadow-lg: 0 12px 32px rgba(20,32,41,0.16);
  --shadow-focus: 0 0 0 4px rgba(77,163,255,0.35);

  /* Motion tokens */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --dur-fast: 150ms;
  --dur-base: 200ms;
  --dur-slow: 300ms;

  /* Typography scale — modular, consistent steps */
  --fs-sm: 0.875rem;   /* 14px */
  --fs-base: 1rem;     /* 16px */
  --fs-md: 1.125rem;   /* 18px */
  --fs-lg: 1.375rem;   /* 22px */
  --fs-xl: 1.75rem;    /* 28px */
  --fs-2xl: 2.25rem;   /* 36px */
  --fs-3xl: 3rem;      /* 48px */

  /* Bootstrap variable overrides (Bootstrap 5.3 CSS-variable API) */
  --bs-primary: var(--sp-accent);
  --bs-primary-rgb: 202, 32, 47;
  --bs-dark: var(--sp-dark);
  --bs-dark-rgb: 20, 32, 41;
  --bs-body-bg: var(--color-bg-page);
  --bs-body-color: var(--color-text-primary);
  --bs-border-radius: var(--radius-md);
  --bs-border-color: var(--color-border);
  --bs-link-color: var(--sp-accent);
  --bs-link-hover-color: var(--sp-accent-600);
  /* Bootstrap 5.3's base `a` rule reads --bs-link-color-rgb (not
     --bs-link-color) via rgba(), so the RGB triplet must be set
     explicitly too or links fall back to Bootstrap's default blue
     (#0d6efd) despite --bs-link-color being overridden above. */
  --bs-link-color-rgb: 202, 32, 47;       /* rgb of --sp-accent #CA202F */
  --bs-link-hover-color-rgb: 168, 26, 39; /* rgb of --sp-accent-600 #A81A27 */
}

/* Respect OS-level reduced motion globally, before anything else */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

/* --------------------------------------------------------------------------
   2. BASE / TYPOGRAPHY
   -------------------------------------------------------------------------- */
html {
  scroll-behavior: smooth;
}

body {
  font-family: 'General Sans', system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: var(--fs-base);
  line-height: 1.65;
  color: var(--color-text-primary);
  background-color: var(--color-bg-page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, h5, h6 {
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--sp-dark);
}

h1 { font-size: var(--fs-3xl); }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-xl); }
h4 { font-size: var(--fs-lg); }

@media (max-width: 767.98px) {
  h1 { font-size: var(--fs-2xl); }
  h2 { font-size: var(--fs-xl); }
  h3 { font-size: var(--fs-md); }
}

p {
  max-width: 100%;
}

.text-secondary-sp { color: var(--color-text-secondary) !important; }
.section-eyebrow {
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sp-accent);
  margin-bottom: var(--space-2);
  display: inline-block;
}

/* --------------------------------------------------------------------------
   3. UNIVERSAL FOCUS + ACCESSIBILITY STATES
   -------------------------------------------------------------------------- */
a, button, .btn, input, select, textarea, [tabindex] {
  transition: background-color var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Remove focus ring only for mouse users landing precisely on a rounded
   pill control where the ring would look clipped — outline-offset handles
   the rest, so we do NOT strip focus rings anywhere else. */
.btn:focus-visible {
  outline-offset: 3px;
}

/* --------------------------------------------------------------------------
   4. BUTTONS — all variants meet 44px min touch target, 8px spacing rhythm
   -------------------------------------------------------------------------- */
.btn {
  font-weight: 600;
  font-size: var(--fs-base);
  padding-block: var(--space-3);   /* 12px */
  padding-inline: var(--space-5);  /* 24px */
  min-height: 44px;
  border-radius: var(--radius-md);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  border-width: 2px;
  touch-action: manipulation;
}

.btn-sm {
  min-height: 44px;
  padding-block: var(--space-2);
  padding-inline: var(--space-4);
  font-size: var(--fs-sm);
}

.btn-lg {
  min-height: 52px;
  padding-block: var(--space-4);
  padding-inline: var(--space-6);
  font-size: var(--fs-md);
}

/* Primary — the CTA. One visual language sitewide for "the thing we want
   people to click": accent red, white text, confident hover lift. */
.btn-primary {
  background-color: var(--sp-accent);
  border-color: var(--sp-accent);
  color: var(--sp-white);
}
.btn-primary:hover {
  background-color: var(--sp-accent-600);
  border-color: var(--sp-accent-600);
  color: var(--sp-white);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.btn-primary:active {
  transform: translateY(0);
  box-shadow: var(--shadow-sm);
}
.btn-primary:disabled, .btn-primary.disabled {
  background-color: var(--sp-grey-300);
  border-color: var(--sp-grey-300);
  color: var(--sp-grey-500);
  transform: none;
  box-shadow: none;
  cursor: not-allowed;
}

/* Secondary — dark, for actions that matter but shouldn't compete with CTA */
.btn-dark {
  background-color: var(--sp-dark);
  border-color: var(--sp-dark);
  color: var(--sp-white);
}
.btn-dark:hover {
  background-color: #0d1519;
  border-color: #0d1519;
  color: var(--sp-white);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

/* Outline — tertiary, for use on light and dark surfaces */
.btn-outline-dark {
  background-color: transparent;
  border-color: var(--sp-dark);
  color: var(--sp-dark);
}
.btn-outline-dark:hover {
  background-color: var(--sp-dark);
  border-color: var(--sp-dark);
  color: var(--sp-white);
}

.btn-outline-light {
  background-color: transparent;
  border-color: rgba(255,255,255,0.55);
  color: var(--sp-white);
}
.btn-outline-light:hover {
  background-color: var(--sp-white);
  border-color: var(--sp-white);
  color: var(--sp-dark);
}

/* Ghost/link-style button for lower-emphasis actions ("Learn more") */
.btn-ghost {
  background: transparent;
  border-color: transparent;
  color: var(--sp-accent);
  padding-inline: var(--space-3);
}
.btn-ghost:hover {
  background-color: var(--color-cta-tint);
  color: var(--sp-accent-600);
}
.btn-ghost .bi {
  transition: transform var(--dur-base) var(--ease-out);
}
.btn-ghost:hover .bi {
  transform: translateX(4px);
}

/* Loading state — never leave a button silently doing nothing */
.btn.is-loading {
  color: transparent !important;
  pointer-events: none;
  position: relative;
}
.btn.is-loading::after {
  content: "";
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 2.5px solid rgba(255,255,255,0.5);
  border-top-color: var(--sp-white);
  animation: sp-spin 700ms linear infinite;
}
.btn-outline-dark.is-loading::after,
.btn-ghost.is-loading::after {
  border: 2.5px solid rgba(20,32,41,0.25);
  border-top-color: var(--sp-dark);
}
@keyframes sp-spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------------------
   5. NAVBAR
   -------------------------------------------------------------------------- */

.sp-navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1030;
  min-height: 80px;
  padding-block: var(--space-3);
  transition: background-color var(--dur-base) var(--ease-out),
              backdrop-filter var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}

/* Default / unscrolled: transparent, sits over the hero, inverted (white) text */
/* Forces the navbar into its legible "scrolled" state immediately,
   overriding .sp-navbar-transparent visually without touching the header
   markup or its scroll-driven JS. For page templates with no dark hero
   for the nav to sit over (e.g. the thank-you page) — see
   .sp-force-nav-solid usage in those templates. */
body.sp-force-nav-solid .sp-navbar-transparent {
  background-color: rgba(255,255,255,0.82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--color-border);
}
body.sp-force-nav-solid .sp-navbar-transparent .navbar-brand,
body.sp-force-nav-solid .sp-navbar-transparent .nav-link,
body.sp-force-nav-solid .sp-navbar-transparent .navbar-toggler {
  color: var(--sp-dark);
}
body.sp-force-nav-solid .sp-navbar-transparent .navbar-toggler .bi {
  color: var(--sp-dark);
}

.sp-navbar-transparent {
  background-color: transparent;
  border-bottom: 1px solid rgba(255,255,255,0.15);
}
.sp-navbar-transparent .navbar-brand,
.sp-navbar-transparent .nav-link,
.sp-navbar-transparent .navbar-toggler {
  color: var(--sp-white);
}
.sp-navbar-transparent .navbar-toggler .bi {
  color: var(--sp-white);
}
.sp-navbar-transparent .nav-link:hover {
  color: var(--sp-white);
  background-color: rgba(255,255,255,0.12);
}
.sp-navbar-transparent .nav-link.active {
  color: var(--sp-white);
}

/* Scrolled: white glassmorphism, dark text (original look) */
.sp-navbar-scrolled {
  background-color: rgba(255,255,255,0.82);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--color-border);
}
.sp-navbar-scrolled .navbar-brand,
.sp-navbar-scrolled .nav-link,
.sp-navbar-scrolled .navbar-toggler {
  color: var(--sp-dark);
}
.sp-navbar-scrolled .navbar-toggler .bi {
  color: var(--sp-dark);
}
.sp-navbar-scrolled .nav-link:hover {
  color: var(--sp-accent);
  background-color: var(--sp-grey-100);
}
.sp-navbar-scrolled .nav-link.active {
  color: var(--sp-accent);
}

.sp-navbar .navbar-brand {
  font-weight: 800;
  font-size: var(--fs-lg);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.sp-navbar .navbar-brand .bi {
  color: var(--sp-accent);
  font-size: 1.5rem;
}

/* Dropdown menus (Services / Sectors / Resources) — Bootstrap ships these
   with no real hover styling of its own (a barely-visible default grey),
   so give every dropdown item a clear, on-brand hover/focus state.
   Hover-to-open at desktop widths is handled in main.js
   (initNavDropdownHover), via Bootstrap's own Dropdown API, so
   aria-expanded and the .show class stay in sync; this block only
   covers appearance, not the open/close trigger. */
.dropdown-menu {
  border: 1px solid var(--color-border);
  box-shadow: 0 8px 24px rgba(20, 32, 41, 0.12);
}
.dropdown-item {
  padding-block: var(--space-2);
  transition: background-color var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out);
}
.dropdown-item:hover,
.dropdown-item:focus,
.dropdown-item.active,
.dropdown-item:active {
  background-color: var(--color-cta-tint);
  color: var(--color-cta);
}

/* Two-logo header: white logo above the fold (transparent nav over the
   dark hero), dark logo once scrolled or on force-solid pages. Pure CSS
   driven by the existing nav state classes — no JS. Both <img>s ship in
   the HTML so there is no swap flicker. */
.sp-navbar .navbar-brand .sp-logo { height: 2.6875rem; width: auto; display: block; }
.sp-navbar .navbar-brand .sp-logo-dark { display: none; }

.sp-navbar-scrolled .navbar-brand .sp-logo-light { display: none; }
.sp-navbar-scrolled .navbar-brand .sp-logo-dark  { display: block; }

body.sp-force-nav-solid .sp-navbar-transparent .navbar-brand .sp-logo-light { display: none; }
body.sp-force-nav-solid .sp-navbar-transparent .navbar-brand .sp-logo-dark  { display: block; }

@media (max-width: 575.98px) {
  .sp-navbar .navbar-brand .sp-logo { height: 2.125rem; }
}

.sp-navbar .nav-link {
  font-weight: 600;
  padding-block: var(--space-3) !important;
  padding-inline: var(--space-4) !important;
  min-height: 44px;
  display: flex;
  align-items: center;
  position: relative;
  border-radius: var(--radius-sm);
}
.sp-navbar .nav-link.active::after {
  content: "";
  position: absolute;
  left: var(--space-4);
  right: var(--space-4);
  bottom: 2px;
  height: 3px;
  border-radius: var(--radius-pill);
  background-color: var(--sp-accent);
}

.sp-navbar .btn.btn-primary {
  min-height: 44px;
  white-space: nowrap;
}
/* Between the lg breakpoint and ~1400px, four nav links (Services,
   Sectors, Resources, About, Contact) + the Call button are tight
   enough to need slightly tighter nav-link padding to stay on one row
   without wrapping. This mirrors the previous fix for the old
   nav-link-count + phone-link + CTA layout, recalculated for the
   current single-button header (Aug 2026: phone-link removed, Call is
   the only nav CTA — see header.php). */
@media (min-width: 992px) and (max-width: 1399.98px) {
  .sp-navbar .nav-link { padding-inline: var(--space-2) !important; }
  .sp-navbar .navbar-nav { gap: 0; }
  .sp-navbar .btn.btn-primary { padding-inline: var(--space-3); }
}

/* Mobile offcanvas menu items need the same 44px targets */
.offcanvas .nav-link {
  min-height: 48px;
  display: flex;
  align-items: center;
  padding-inline: var(--space-4);
  border-radius: var(--radius-md);
  font-weight: 600;
  color: var(--sp-dark);
}
.offcanvas .nav-link:hover,
.offcanvas .nav-link:active {
  background-color: var(--sp-grey-100);
  color: var(--sp-accent);
}
.sp-mobile-subnav {
  margin: 0 0 var(--space-3) 0;
  padding-left: var(--space-4);
  border-left: 2px solid var(--color-border);
  margin-left: var(--space-4);
}
.sp-mobile-subnav li a {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-inline: var(--space-3);
  border-radius: var(--radius-md);
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--sp-dark);
  text-decoration: none;
}
.sp-mobile-subnav li a:hover,
.sp-mobile-subnav li a:active {
  background-color: var(--sp-grey-100);
  color: var(--sp-accent);
}
.offcanvas .nav-item:has(.sp-mobile-subnav) {
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
}

/* --------------------------------------------------------------------------
   6. HERO
   -------------------------------------------------------------------------- */
.sp-hero {
  background-image:
    linear-gradient(160deg, rgba(20,32,41,0.88) 0%, rgba(13,21,25,0.92) 100%),
    url('/assets/img/sentinel-fire-doors-hero-image.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: var(--sp-white);
  padding-block: var(--space-9);
  position: relative;
  overflow: hidden;
}
/* Opt-in modifier: full viewport height, content vertically centred.
   Used on the homepage hero so it fills the screen behind the transparent
   floating header; other pages keep the normal padded hero height. */
.sp-hero-full {
  min-height: 100vh;
  display: flex;
  align-items: center;
}
/* Service/sector/location hero variant with a real background photo
   (set via inline style with $hero['image']) — background-size/position
   need repeating here since the inline style only replaces
   background-image, not the other background-* shorthand properties.
   min-height is scoped to :not(.sp-hero-full) so that when a hero carries
   BOTH classes (e.g. the homepage hero, which is full-height AND has a
   photo), this rule's 26rem does not win the cascade over sp-hero-full's
   100vh purely because it happens to be declared later in the file. */
.sp-hero-with-image {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  display: flex;
  align-items: center;
}
.sp-hero-with-image:not(.sp-hero-full) {
  min-height: 26rem;
}
.sp-eyebrow-on-dark { color: var(--sp-white); opacity: 1; }
.sp-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(circle at 85% 20%, rgba(202,32,47,0.18), transparent 45%),
    radial-gradient(circle at 10% 90%, rgba(255,255,255,0.05), transparent 40%);
  pointer-events: none;
}
.sp-hero .container { position: relative; z-index: 1; }

/* Hero content spans the full container width rather than the default
   Bootstrap col-lg-8 (66.6%) — scoped to .sp-hero specifically via the
   ancestor selector, so this never touches col-lg-8 anywhere else on the
   site (cta-band.php, contact page two-column layout, etc. all keep the
   real 66% split). !important is required here because Bootstrap's own
   .col-lg-8 rule sits inside a @media (min-width: 992px) block with the
   same specificity weight and loads after critical.css, so an
   unqualified override would lose that fight at the same breakpoint. */
.sp-hero .col-lg-8 {
  width: 100% !important;
  margin-inline: 0 !important;
}

.sp-hero h1 {
  color: var(--sp-white);
  max-width: 18ch;
}
.sp-hero .lead {
  color: var(--sp-white);
  font-size: var(--fs-md);
  max-width: 56ch;
  margin-block: var(--space-4) var(--space-6);
}

.sp-hero .trust-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
  margin-top: var(--space-7);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-border-on-dark);
}
.sp-hero .trust-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  color: var(--color-text-on-dark-secondary);
  font-size: var(--fs-sm);
  font-weight: 600;
}
.sp-hero .trust-item .bi {
  color: var(--sp-accent);
  font-size: 1.1rem;
}

@media (max-width: 767.98px) {
  .sp-hero { padding-block: var(--space-8); }
  /* Cap the hero headline on small screens and give it clearance from the
     sticky header, which the oversized default was colliding with. */
  .sp-hero h1 { font-size: 2.5rem; margin-top: var(--space-5); }
}

/* --------------------------------------------------------------------------
   7. CARDS
   -------------------------------------------------------------------------- */
.sp-card {
  background: var(--sp-white);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  height: 100%;
  transition: transform var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out);
}
.sp-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-lg);
  border-color: transparent;
}
/* Forms reuse .sp-card for the surface only. height:100% exists for
   equal-height grid cards; on a form whose column also holds content
   below it (the lead magnet), it stretches the form to the full column
   height — creating dead space inside the card AND pushing the content
   after it out of the section (measured 324px into the footer). Forms
   also must not lift on hover: that affordance signals a clickable card. */
form.sp-card { height: auto; }
form.sp-card:hover { transform: none; box-shadow: none; border-color: var(--color-border); }

.sp-card .sp-card-icon {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-md);
  background-color: var(--color-cta-tint);
  color: var(--sp-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  margin-bottom: var(--space-4);
  transition: background-color var(--dur-base) var(--ease-out),
              color var(--dur-base) var(--ease-out);
}
.sp-card:hover .sp-card-icon {
  background-color: var(--sp-accent);
  color: var(--sp-white);
}

.sp-card h3 {
  font-size: var(--fs-md);
  margin-bottom: var(--space-2);
}
.sp-card p {
  color: var(--color-text-secondary);
  font-size: var(--fs-sm);
  margin-bottom: var(--space-4);
}
.sp-card .sp-card-link {
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--sp-dark);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
}
.sp-card .sp-card-link .bi {
  color: var(--sp-accent);
  transition: transform var(--dur-base) var(--ease-out);
}
.sp-card:hover .sp-card-link .bi {
  transform: translateX(4px);
}

/* Dark variant card (used on dark sections e.g. stats/certifications) */
.sp-card-dark {
  background-color: var(--color-bg-dark-raised);
  border: 1px solid var(--color-border-on-dark);
  color: var(--sp-white);
}
.sp-card-dark p { color: var(--color-text-on-dark-secondary); }
.sp-card-dark h3 { color: var(--sp-white); }

/* --------------------------------------------------------------------------
   8. CTA BAND — the repeated "Call / Book a survey" block from the arch doc
   -------------------------------------------------------------------------- */
.sp-cta-band {
  background-color: var(--sp-accent);
  color: var(--sp-white);
  border-radius: var(--radius-lg);
  padding: var(--space-7) var(--space-6);
}
.sp-cta-band h2 {
  color: var(--sp-white);
  font-size: var(--fs-xl);
  margin-bottom: var(--space-2);
}
.sp-cta-band p {
  color: rgba(255,255,255,0.9);
  margin-bottom: 0;
}
.sp-cta-band .btn-light-cta {
  background-color: var(--sp-white);
  color: var(--sp-accent);
  border-color: var(--sp-white);
  font-weight: 700;
}
.sp-cta-band .btn-light-cta:hover {
  background-color: var(--sp-dark);
  border-color: var(--sp-dark);
  color: var(--sp-white);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

/* Full-bleed section variant */
.sp-cta-section {
  background-color: var(--sp-dark);
  color: var(--sp-white);
  padding-block: var(--space-6);
}
@media (min-width: 992px) { .sp-cta-section { padding-block: var(--space-8); } }
.sp-cta-section h2 { color: var(--sp-white); }
.sp-cta-section p { color: var(--color-text-on-dark-secondary); }

/* --------------------------------------------------------------------------
   9. BADGES / PILLS / ACCREDITATION CHIPS
   -------------------------------------------------------------------------- */
.badge {
  font-weight: 700;
  font-size: var(--fs-sm);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-sm);
  letter-spacing: 0.01em;
}
.badge-accent { background-color: var(--color-cta-tint); color: var(--sp-accent-600); }
.badge-dark { background-color: var(--sp-dark); color: var(--sp-white); }
.badge-outline {
  background: transparent;
  border: 1.5px solid var(--color-border);
  color: var(--color-text-secondary);
}

.sp-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  min-height: 44px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border);
  background: var(--sp-white);
  font-weight: 600;
  font-size: var(--fs-sm);
  color: var(--color-text-primary);
}
.sp-chip .bi { color: var(--sp-accent); }

/* --------------------------------------------------------------------------
   10. FORMS
   -------------------------------------------------------------------------- */
.form-label {
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--sp-dark);
  margin-bottom: var(--space-2);
}
.form-control, .form-select {
  min-height: 48px;
  border: 1.5px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-base); /* 16px minimum — prevents iOS auto-zoom */
}
.form-control:focus, .form-select:focus {
  border-color: var(--sp-accent);
  box-shadow: 0 0 0 4px var(--color-cta-tint);
}
textarea.form-control { min-height: 128px; }

.form-text {
  font-size: var(--fs-sm);
  color: var(--color-text-secondary);
}

.is-invalid ~ .invalid-feedback,
.invalid-feedback {
  font-size: var(--fs-sm);
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.form-control.is-invalid {
  border-color: var(--sp-accent);
  background-image: none; /* keep Bootstrap's default icon off; we use text + colour + icon together */
}

.form-check-input {
  width: 20px;
  height: 20px;
  margin-top: 0.15em;
}
.form-check-input:checked {
  background-color: var(--sp-accent);
  border-color: var(--sp-accent);
}
.form-check-label {
  padding-left: var(--space-1);
  font-size: var(--fs-sm);
}
.form-check {
  min-height: 44px;
  display: flex;
  align-items: flex-start;
  gap: var(--space-1);
}

/* --------------------------------------------------------------------------
   11. ALERTS / TOASTS
   -------------------------------------------------------------------------- */
.alert {
  border-radius: var(--radius-md);
  border: 1.5px solid transparent;
  padding: var(--space-4) var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-sm);
}
.alert .bi { font-size: 1.25rem; flex-shrink: 0; }
.alert.alert-multiline { align-items: flex-start; }
.alert.alert-multiline .bi { margin-top: 2px; }
.alert-success { background: #E9F6EE; border-color: #BEE5C9; color: #1E5B34; }
.alert-danger  { background: var(--color-cta-tint); border-color: #F3B7BB; color: #7A121C; }
.alert-warning { background: #FCF3E3; border-color: #F1DBA8; color: #7A5B10; }
.alert-info    { background: #E9F1FA; border-color: #BBD7F0; color: #1A4E82; }

/* --------------------------------------------------------------------------
   12. MODAL
   -------------------------------------------------------------------------- */
.modal-content {
  border-radius: var(--radius-lg);
  border: none;
  box-shadow: var(--shadow-lg);
}
.modal-header {
  border-bottom: 1px solid var(--color-border);
  padding: var(--space-5) var(--space-6);
}
.modal-title { font-size: var(--fs-md); }
.modal-body { padding: var(--space-6); }
.modal-footer {
  border-top: 1px solid var(--color-border);
  padding: var(--space-5) var(--space-6);
}
.modal-backdrop.show { opacity: 0.6; } /* strong scrim so foreground modal reads clearly */
.btn-close:focus { box-shadow: var(--shadow-focus); }

/* --------------------------------------------------------------------------
   13. ACCORDION (used for FAQ blocks per architecture doc)
   -------------------------------------------------------------------------- */
.accordion-item {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md) !important;
  margin-bottom: var(--space-3);
  overflow: hidden;
}
.accordion-button {
  font-weight: 700;
  font-size: var(--fs-base);
  padding: var(--space-5);
  min-height: 44px;
  color: var(--sp-dark);
  background: var(--sp-white);
}
.accordion-button:not(.collapsed) {
  background-color: var(--color-cta-tint);
  color: var(--sp-accent-600);
  box-shadow: none;
}
.accordion-button:focus {
  box-shadow: var(--shadow-focus);
  z-index: 2;
}
.accordion-button::after {
  transition: transform var(--dur-base) var(--ease-out);
}
.accordion-body {
  padding: var(--space-2) var(--space-5) var(--space-5);
  color: var(--color-text-secondary);
}

/* --------------------------------------------------------------------------
   14. BREADCRUMB
   -------------------------------------------------------------------------- */
.breadcrumb {
  font-size: var(--fs-sm);
  font-weight: 600;
  margin-bottom: 0;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.breadcrumb-item {
  display: flex;
  align-items: center;
}
.breadcrumb-item a {
  color: var(--color-text-secondary);
  text-decoration: none;
  padding-block: var(--space-2);
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.breadcrumb-item a:hover { color: var(--sp-accent); }
.breadcrumb-item.active { color: var(--sp-dark); }
.breadcrumb-item + .breadcrumb-item {
  display: flex;
  align-items: center;
}
.breadcrumb-item + .breadcrumb-item::before {
  color: var(--sp-grey-300);
  display: inline-flex;
  align-items: center;
}

/* --------------------------------------------------------------------------
   15. TABLE
   -------------------------------------------------------------------------- */
.table {
  --bs-table-bg: transparent;
  font-size: var(--fs-sm);
}
.table thead th {
  font-size: var(--fs-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-weight: 700;
  color: var(--color-text-secondary);
  border-bottom-width: 2px;
  border-color: var(--sp-dark);
  padding-block: var(--space-3);
}
.table td, .table th {
  padding: var(--space-4);
  vertical-align: middle;
}
.table-striped > tbody > tr:nth-of-type(odd) > * {
  background-color: var(--sp-grey-100);
}

/* --------------------------------------------------------------------------
   16. TABS / PILLS NAV
   -------------------------------------------------------------------------- */
.nav-tabs {
  border-bottom: 2px solid var(--color-border);
}
.nav-tabs .nav-link {
  border: none;
  font-weight: 700;
  color: var(--color-text-secondary);
  padding: var(--space-3) var(--space-5);
  min-height: 44px;
  border-radius: 0;
  margin-bottom: -2px;
  border-bottom: 2px solid transparent;
}
.nav-tabs .nav-link:hover {
  color: var(--sp-dark);
  border-color: var(--sp-grey-300);
}
.nav-tabs .nav-link.active {
  color: var(--sp-accent);
  background: transparent;
  border-color: var(--sp-accent);
}

.nav-pills .nav-link {
  font-weight: 600;
  color: var(--sp-dark);
  min-height: 44px;
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-5);
}
.nav-pills .nav-link.active {
  background-color: var(--sp-accent);
  color: var(--sp-white);
}

/* --------------------------------------------------------------------------
   17. PROGRESS / STEPS ("How it works" 4-step block)
   -------------------------------------------------------------------------- */
.sp-steps {
  counter-reset: sp-step;
}
.sp-step {
  position: relative;
  padding-left: var(--space-9);
  padding-bottom: var(--space-6);
}
.sp-step::before {
  counter-increment: sp-step;
  content: counter(sp-step);
  position: absolute;
  left: 0;
  top: 0;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: var(--sp-dark);
  color: var(--sp-white);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: var(--fs-md);
}
.sp-step::after {
  content: "";
  position: absolute;
  left: 23px;
  top: 48px;
  bottom: 0;
  width: 2px;
  background: var(--color-border);
}
.sp-step:last-child::after { display: none; }
.sp-step:last-child { padding-bottom: 0; }
.sp-step h4,
.sp-step .sp-step-title { margin-bottom: var(--space-2); font-size: var(--fs-lg); }
.sp-step p { color: var(--color-text-secondary); margin-bottom: 0; }

/* Horizontal scroll-snap variant of "How it works" (steps.php 'layout' =>
   'scroll'). Pure CSS: no JS is required for the snap-scroll behaviour or
   for touch swipe on mobile — this degrades to an ordinary horizontally
   scrollable row if JS is disabled site-wide. A small edge fade hints
   there is more to scroll without needing arrow buttons. */
.sp-steps-scroll-wrap {
  position: relative;
}
.sp-steps-scroll-wrap::after {
  /* Right-edge fade purely as a visual hint that more cards are
     scrollable — an overlay, not a mask, so it never clips real card
     content underneath it. Purely decorative (no content,
     pointer-events: none), so it's safe even on a viewport where
     nothing is actually cut off.
     Colour-matches --color-bg-page (the .sp-section-tint background),
     since that is this variant's only current caller (homepage "How it
     works"). If reused on a plain-white section, override
     --sp-steps-fade-bg on .sp-steps-scroll-wrap to match. */
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  bottom: var(--space-6);
  width: var(--space-8);
  background: linear-gradient(to right, transparent, var(--sp-steps-fade-bg, var(--color-bg-page)) 85%);
  pointer-events: none;
}
.sp-steps-scroll {
  display: flex;
  gap: var(--space-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: var(--space-2) var(--space-2) var(--space-6);
  margin: 0 calc(-1 * var(--space-2));
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.sp-steps-scroll::-webkit-scrollbar { height: 6px; }
.sp-steps-scroll::-webkit-scrollbar-thumb {
  background: var(--color-border);
  border-radius: var(--radius-pill);
}
.sp-steps-scroll-item {
  scroll-snap-align: start;
  flex: 0 0 auto;
  width: min(300px, 72vw);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}
.sp-steps-scroll-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--sp-dark);
  color: var(--sp-white);
  font-weight: 800;
  font-size: var(--fs-md);
  margin-bottom: var(--space-4);
}
.sp-steps-scroll-item .sp-step-title { margin-bottom: var(--space-2); font-size: var(--fs-lg); }
.sp-steps-scroll-item p { color: var(--color-text-secondary); margin-bottom: 0; }
@media (prefers-reduced-motion: reduce) {
  .sp-steps-scroll { scroll-behavior: auto; }
}

/* --------------------------------------------------------------------------
   18. FOOTER
   -------------------------------------------------------------------------- */
.sp-footer {
  background-color: var(--sp-dark);
  color: var(--color-text-on-dark-secondary);
  padding-block: var(--space-8) var(--space-6);
}
/* Footer brand logo: always on the dark footer background, so only the
   white logo variant is needed (unlike the header, which toggles between
   light/dark on scroll). Sized independently of .sp-navbar .sp-logo so
   changing the header logo size never affects the footer. */
.sp-footer .sp-footer-logo {
  height: 2.25rem;
  width: auto;
  display: block;
}
.sp-footer h3 {
  color: var(--sp-white);
  font-size: var(--fs-sm);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: var(--space-4);
}
.sp-footer a {
  color: var(--color-text-on-dark-secondary);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.sp-footer a:hover { color: var(--sp-white); }
.sp-footer address {
  color: var(--color-text-on-dark-secondary);
  font-style: normal;
}
.sp-footer hr {
  border-color: var(--color-border-on-dark);
  opacity: 1;
  margin-block: var(--space-6);
}
/* --------------------------------------------------------------------------
   19. LOGO / TRUST STRIP (grayscale client logos)
   -------------------------------------------------------------------------- */
.sp-logo-strip img {
  height: 32px;
  width: auto;
  filter: grayscale(1) opacity(0.55);
  transition: filter var(--dur-base) var(--ease-out);
}
.sp-logo-strip img:hover {
  filter: grayscale(0) opacity(1);
}

/* --------------------------------------------------------------------------
   20. SCROLL-REVEAL ANIMATION (progressive enhancement, JS-driven)
   -------------------------------------------------------------------------- */
.sp-reveal {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--dur-slow) var(--ease-out),
              transform var(--dur-slow) var(--ease-out);
}
.sp-reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce) {
  .sp-reveal { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   21. UTILITIES
   -------------------------------------------------------------------------- */
.bg-sp-dark { background-color: var(--sp-dark) !important; }
.bg-sp-grey { background-color: var(--sp-grey-100) !important; }
.bg-sp-accent { background-color: var(--sp-accent) !important; }
.text-sp-accent { color: var(--sp-accent) !important; }
.text-sp-dark { color: var(--sp-dark) !important; }

/* Same tiers as .sp-section so pages mixing both classes share one rhythm */
.section-py { padding-block: var(--space-6); }
@media (min-width: 992px) {
  .section-py { padding-block: var(--space-8); }
}

/* Icon-only button — always paired with aria-label + visible min target */
.btn-icon {
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Ensures no horizontal scroll ever creeps in */
html, body { overflow-x: hidden; max-width: 100%; }

/* Navbar clearance is handled entirely by .sp-breadcrumb-wrap's own
   padding-top (see BREADCRUMB WRAPPER section below), which reads the
   same --sp-navbar-height variable. A duplicate rule here that also
   padded <main> by the navbar's height used to stack on top of that,
   producing a large empty gap between the breadcrumb and the page's
   first section on every non-homepage page. Removed; nothing should
   set padding-top on <main> or #main-content going forward. */

/* Swatch tiles for the palette showcase section only */
.sp-swatch {
  border-radius: var(--radius-md);
  height: 96px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--space-1);
  padding: var(--space-3);
  font-size: var(--fs-sm);
  font-weight: 700;
  border: 1px solid var(--color-border);
}
.sp-swatch small {
  font-weight: 600;
  opacity: 0.85;
}

/* ============== FROM additional.css ============== */
/* ==========================================================================
   SENTINEL PROJECTS — ADDITIONAL STYLES
   Small additions on top of Bootstrap + design-system.css for things that
   weren't in the showcase file: the consent banner, the contact form's
   honeypot field, the breadcrumb page-level wrapper spacing, and a
   link-styled button used in the footer.

   Real Bootstrap Icons (assets/vendor/bootstrap-icons/) already handle
   their own sizing via the .bi class — no icon-sizing rules needed here.
   ========================================================================== */

/* --------------------------------------------------------------------------
   BUTTON-LOOKING-LIKE-A-LINK (footer "Cookie Preferences")
   -------------------------------------------------------------------------- */
.sp-link-button {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--color-text-on-dark-secondary);
  text-decoration: none;
  cursor: pointer;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.sp-link-button:hover { color: var(--sp-white); }

/* --------------------------------------------------------------------------
   HONEYPOT FIELD — hidden off-screen (NOT display:none/visibility:hidden)
   so unsophisticated bots that specifically skip those two properties
   still fill it in and get caught by contact-handler.php
   -------------------------------------------------------------------------- */
.sp-honeypot {
  position: absolute;
  left: -9999px;
  top: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* --------------------------------------------------------------------------
   BREADCRUMB WRAPPER (page-level spacing, breadcrumb itself styled in
   design-system.css's own breadcrumb section)
   -------------------------------------------------------------------------- */
.sp-breadcrumb-wrap {
  /* Navbar overlap fix: the transparent/fixed navbar (.sp-navbar,
     position:fixed) is designed to float over the homepage's
     full-viewport hero, which reserves space for it by being 100vh tall.
     Every other page template renders this breadcrumb as the first thing
     after the fixed header, with nothing else accounting for the navbar's
     height, so without this the nav visually overlaps the breadcrumb (and
     the page content beneath it) on every non-homepage page. The navbar's
     rendered height varies by viewport width (its content wraps to a
     second line across roughly 992-1366px), so this reads a CSS variable
     kept in sync by main.js's syncNavbarHeight() rather than a fixed
     guess that would under-clear across that range. The 104px fallback
     covers the tallest observed wrapped state, for the instant before
     JS runs and for no-JS visitors. This is a spacing fix only — no
     header markup or behaviour changes, so the protected header/footer
     are untouched. */
  padding-top: calc(var(--sp-navbar-height, 104px) + var(--space-4));
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  background: var(--color-bg-surface);
}

/* --------------------------------------------------------------------------
   COOKIE CONSENT BANNER (self-built, ~3KB with its JS — architecture §6)
   -------------------------------------------------------------------------- */
.sp-consent-banner {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2000;
  background: var(--sp-white);
  border-top: 1px solid var(--color-border);
  box-shadow: var(--shadow-lg);
  padding: var(--space-5);
}
.sp-consent-inner {
  max-width: 1200px;
  margin-inline: auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
}
.sp-consent-text {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--color-text-secondary);
  max-width: 60ch;
}
.sp-consent-text a { color: var(--sp-accent); }
.sp-consent-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.sp-consent-panel {
  position: fixed;
  inset: 0;
  z-index: 2100;
  background: rgba(20,32,41,0.5);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}
.sp-consent-panel-inner {
  background: var(--sp-white);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  max-width: 520px;
  width: 100%;
  box-shadow: var(--shadow-lg);
}

@media (max-width: 767.98px) {
  .sp-consent-inner { flex-direction: column; align-items: flex-start; }
  .sp-consent-actions { width: 100%; }
  .sp-consent-actions .btn { flex: 1; }
}

/* ============== HOMEPAGE / PAGE-LEVEL ADDITIONS ============== */
/* Lead intro paragraph — the GEO answer block under "What we do".
   Slightly larger and darker than body copy so it reads as the summary. */
.lead-intro {
  font-size: var(--fs-md);
  color: var(--color-text-primary);
  max-width: 100%;
  margin-bottom: 0;
}

/* ============== CHECK LIST (service/sector page bullet lists) ============== */
.sp-check-list {
  list-style: none;
  padding-left: 0;
  margin-bottom: var(--space-5);
}
.sp-check-list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding-block: var(--space-2);
  border-bottom: 1px solid var(--color-border);
}
.sp-check-list li:last-child { border-bottom: 0; }
.sp-check-list .bi {
  color: var(--sp-accent);
  flex-shrink: 0;
  margin-top: 0.2em;
}
/* On grey sections the divider needs a touch more contrast */
.bg-sp-grey .sp-check-list li { border-color: var(--sp-grey-300); }

/* Responsive table wrapper — prevents horizontal overflow on small screens */
.table-responsive { overflow-x: auto; }

/* ============== RELATED PAGES NAV STRIP ============== */
.sp-related-links {
  padding-block: var(--space-6);
  border-top: 1px solid var(--color-border);
  background: var(--color-bg-surface);
}
.sp-related-label {
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--color-text-secondary);
  margin-right: var(--space-3);
}
.sp-related-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--sp-accent);
  text-decoration: none;
  margin-right: var(--space-5);
}
.sp-related-links a:hover { text-decoration: underline; }

/* ============== HOMEPAGE HERO FORM CARD (glassmorphism) ============== */
.sp-hero-home .sp-hero-lead {
  color: var(--sp-white); /* pure white for contrast, per brief */
}
.sp-hero-form-card {
  background: rgba(255,255,255,0.10);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: 0 20px 60px rgba(0,0,0,0.35);
}
.sp-hero-form-title {
  font-size: var(--fs-xl);
  margin-bottom: var(--space-5);
  color: var(--sp-white);
}
.sp-hero-form .form-control,
.sp-hero-form .form-select {
  background-color: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.25);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
  color: var(--sp-white);
}
.sp-hero-form .form-control::placeholder {
  color: rgba(255,255,255,0.75);
  opacity: 1;
}
/* Select placeholder (the disabled first option) + chevron colour */
.sp-hero-form .form-select {
  color: rgba(255,255,255,0.75);
}
.sp-hero-form .form-select:has(option:checked:not([disabled])) {
  color: var(--sp-white);
}
/* Dropdown options render on the browser's native menu (white bg), so keep
   their text dark for readability there. */
.sp-hero-form .form-select option {
  color: var(--sp-dark);
}
.sp-hero-form .form-control:focus,
.sp-hero-form .form-select:focus {
  background-color: rgba(255,255,255,0.14);
  border-color: var(--sp-accent);
  box-shadow: 0 0 0 3px rgba(202,32,47,0.25);
  color: var(--sp-white);
}
@media (max-width: 991px) {
  .sp-hero-form-card { margin-top: var(--space-6); }
}

/* ============== CONTACT + THANK-YOU PAGE BITS ============== */
.sp-contact-phone {
  font-size: var(--fs-2xl);
  font-weight: 800;
  color: var(--sp-accent);
  text-decoration: none;
}
.sp-contact-phone:hover { text-decoration: underline; }
.sp-thanks-icon .bi {
  font-size: 4rem;
  color: var(--sp-accent);
}

/* ==========================================================================
   REFACTOR R1 — component styles for the persuasion-arc rebuild.
   All values trace to design-system tokens; no new raw hex except where a
   token alpha is derived. 8px baseline preserved throughout.
   ========================================================================== */

/* Fluid heading scale — steps type down smoothly across breakpoints,
   replacing fixed sizes that overflowed at 375px. */
h1, .h1 { font-size: clamp(1.625rem, 1.05rem + 2.2vw, 2.75rem); line-height: 1.15; }
h2, .h2 { font-size: clamp(1.375rem, 1.1rem + 1.2vw, 2rem); line-height: 1.2; }
h3, .h3 { font-size: clamp(1.0625rem, 0.95rem + 0.45vw, 1.3125rem); line-height: 1.3; }

/* Eyebrow label — consistent section kicker sitewide */
.sp-eyebrow {
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-cta);
  margin-bottom: var(--space-3);
}

/* Section rhythm — alternating surfaces kill the flat-white emptiness */
/* Full-width single-column body content (issue 10, revised) — a lone
   col-lg-8/9 inside a row, used throughout blog articles, legal pages,
   and service/sector/location page body sections, capped at Bootstrap's
   default 66%/75% width by default, leaving a large empty gap on the
   right at desktop/laptop widths even once centred. :only-child scoping
   means this never touches a genuine 2-column layout (e.g. the
   media-text rows or the guide-promo card in resources/index.php),
   since those either have a sibling column or are not :only-child.
   !important is required because Bootstrap's own .col-lg-8/.col-lg-9
   rules sit inside a @media (min-width: 992px) block at the same
   specificity and load after critical.css, so an unqualified width
   override loses that fight at the same breakpoint (see also the
   .sp-hero .col-lg-8 override above, same root cause). */
.row > .col-lg-8:only-child,
.row > .col-lg-9:only-child {
  margin-inline: auto;
  float: none;
}
@media (min-width: 992px) {
  .row:not(.justify-content-center) > .col-lg-8:only-child,
  .row:not(.justify-content-center) > .col-lg-9:only-child {
    width: 100% !important;
  }
}

.sp-section { padding: var(--space-6) 0; }
@media (min-width: 992px) { .sp-section { padding: var(--space-8) 0; } }
/* Section rhythm: every section keeps symmetric internal padding so
   background changes (dark -> light) always have breathing room on both
   sides of the boundary. Adjacent same-background sections therefore sum
   two paddings, which IS the intended between-section gap: 64px mobile /
   128px desktop — roughly half the previous scale that read as excessive
   on mobile. Do NOT zero the top padding of following sections: Bootstrap
   .row.g-* negative top margins collapse straight through an unpadded
   section edge and pull the whole section up over its predecessor. */
/* Tighter vertical rhythm for continuous article body copy (issue 10) —
   .sp-section's default 96px top+bottom at desktop compounds to 192px of
   pure whitespace between adjacent sections, appropriate for major
   visual breaks (hero to content) but excessive for prose that should
   read as one continuous piece. */
.sp-article-section { padding: var(--space-6) 0; }
@media (min-width: 992px) { .sp-article-section { padding: var(--space-7) 0; } }
.sp-section-tint { background: var(--color-bg-page); }
.sp-section-dark { background: var(--color-bg-dark); color: var(--color-text-on-dark); }
.sp-section-dark h2, .sp-section-dark h3 { color: var(--color-text-on-dark); }
.sp-section-dark p { color: var(--color-text-on-dark-secondary); }

/* Media-text */
.sp-media-frame {
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(20,32,41,0.08), 0 8px 24px rgba(20,32,41,0.10);
}
.sp-media-frame img { display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; }

/* Image placeholder (used only where client assets are outstanding) */
.sp-img-placeholder {
  aspect-ratio: 3 / 2;
  display: flex; align-items: center; justify-content: center;
  background:
    repeating-linear-gradient(45deg, transparent 0 12px, rgba(20,32,41,0.03) 12px 24px),
    var(--sp-grey-200);
  color: var(--sp-grey-500);
  font-size: 2rem;
  border-radius: var(--radius-lg);
}
.sp-img-placeholder-sm { border-radius: var(--radius-md) var(--radius-md) 0 0; }

/* Feature cards */
.sp-feature-card {
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  position: relative;
  transition: transform 200ms ease, box-shadow 200ms ease;
  display: flex;
  flex-direction: column;
}
.sp-feature-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(20,32,41,0.10); }
@media (prefers-reduced-motion: reduce) { .sp-feature-card:hover { transform: none; } }
.sp-feature-card-dark { background: var(--color-bg-dark-raised); border-color: var(--color-border-on-dark); }
.sp-feature-card-dark h3 { color: var(--color-text-on-dark); }
.sp-feature-card-dark p { color: var(--color-text-on-dark-secondary); }
.sp-feature-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 3rem; height: 3rem;
  border-radius: var(--radius-md);
  background: var(--color-cta-tint);
  color: var(--color-cta);
  font-size: 1.375rem;
  margin-bottom: var(--space-4);
}
.sp-feature-title { font-weight: 600; margin-bottom: var(--space-2); }
.sp-feature-link { font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; gap: var(--space-1); min-height: 44px; margin-top: auto; padding-top: var(--space-2); color: var(--color-cta); }
.sp-feature-link:hover, .sp-feature-link:focus { color: var(--color-cta-hover); }
.sp-section-dark .sp-feature-link { color: var(--sp-white); }

/* Regulation callout */
.sp-reg-callout {
  background: var(--color-cta-tint);
  border-left: 4px solid var(--color-cta);
  border-radius: var(--radius-md);
  padding: var(--space-5) var(--space-6);
  margin-top: var(--space-5);
}
.sp-reg-icon { color: var(--color-cta); font-size: 1.5rem; line-height: 1; }
.sp-reg-copy { flex: 1 1 auto; min-width: 0; }
.sp-reg-title { font-weight: 600; margin-bottom: var(--space-2); }
.sp-reg-callout p:last-child { margin-bottom: 0; }

/* Regulation timeline */
.sp-reg-timeline { display: grid; gap: var(--space-5); margin: 0; }
@media (min-width: 768px) { .sp-reg-timeline { grid-template-columns: repeat(3, 1fr); } }
.sp-reg-node {
  position: relative;
  padding: var(--space-5);
  padding-top: var(--space-6);
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
}
.sp-reg-node::before {
  content: ""; position: absolute; top: 0; left: var(--space-5); right: var(--space-5);
  height: 3px; background: var(--color-cta); border-radius: 0 0 3px 3px;
}
.sp-reg-year { font-weight: 600; color: var(--color-cta); font-size: 0.875rem; letter-spacing: 0.06em; }
.sp-reg-node-title { font-size: 1.0625rem; font-weight: 600; margin: var(--space-2) 0; }

/* Credentials strip */
.sp-credentials { display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-3); margin: var(--space-5) 0 0; }
.sp-credential-chip {
  display: inline-flex; align-items: center; gap: var(--space-1);
  font-size: 0.875rem; font-weight: 600;
  background: var(--color-bg-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-pill);
  padding: var(--space-2) var(--space-4);
  /* Explicit, not inherited: the chip's own background is always the
     light --color-bg-surface regardless of which section (light or dark)
     it's placed in, so its text must always be the corresponding dark
     colour. Previously this fell through to the surrounding section's
     ambient text colour (white on dark sections), producing invisible
     white text on this chip's white pill. */
  color: var(--color-text-primary);
}
.sp-credential-chip .bi { color: var(--color-cta); }
@media (max-width: 767.98px) {
  .sp-credential-chip[data-chip="bluesky-certified"],
  .sp-credential-chip[data-chip="fully-insured"] {
    display: none;
  }
}

/* Project feature + cards */
.sp-project-featured {
  border-radius: var(--radius-lg); overflow: hidden;
  background: var(--color-bg-dark); color: var(--color-text-on-dark);
}
.sp-project-featured h2, .sp-project-featured h3 { color: var(--color-text-on-dark); }
.sp-project-featured p { color: var(--color-text-on-dark-secondary); }
.sp-project-media img, .sp-project-media .sp-img-placeholder { width: 100%; height: 100%; min-height: 280px; object-fit: cover; border-radius: 0; }
.sp-project-body { padding: var(--space-6); }
@media (min-width: 992px) { .sp-project-body { padding: var(--space-8); } }

/* In-page work photos (portrait proof-of-work images). Constrained so a
   portrait shot sits as a modest supporting figure, never full-bleed, and
   is never used as a landscape hero. Floated right on wider screens so body
   copy wraps alongside it; full width and centred on mobile. */
.sp-article-figure {
  max-width: 320px;
  margin: 0 0 var(--space-6) 0;
}
.sp-article-figure img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
  display: block;
}
.sp-article-figure figcaption {
  margin-top: var(--space-2, 0.5rem);
  font-size: 0.8125rem;
  color: var(--color-text-secondary);
  line-height: 1.4;
}
@media (min-width: 768px) {
  .sp-article-figure {
    float: right;
    max-width: 300px;
    margin-left: var(--space-6);
  }
  .sp-article-figure.sp-figure-left {
    float: left;
    margin-left: 0;
    margin-right: var(--space-6);
  }
}
.sp-project-card {
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); overflow: hidden;
  display: flex; flex-direction: column;
  position: relative;
}
.sp-project-card img { width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover; }
.sp-project-card-body { padding: var(--space-5); }
.sp-project-meta { font-size: 0.8125rem; color: var(--color-text-secondary); margin-bottom: var(--space-3); }

/* Placeholder flagging — visible in dev/review, unmissable pre-launch */
.sp-is-placeholder { outline: 2px dashed var(--sp-accent); outline-offset: -2px; position: relative; }
.sp-placeholder-badge {
  position: absolute; top: var(--space-2); right: var(--space-2); z-index: 2;
  background: var(--sp-accent); color: var(--sp-white);
  font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.06em;
  padding: 0.125rem var(--space-2); border-radius: var(--radius-sm);
}

/* Testimonials */
.sp-testimonial {
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: var(--space-6); margin: 0;
  display: flex; flex-direction: column;
}
.sp-testimonial-mark { color: var(--color-cta); font-size: 2rem; line-height: 1; margin-bottom: var(--space-3); }
.sp-testimonial blockquote { flex: 1; }
.sp-testimonial-name { display: block; font-weight: 600; }
.sp-testimonial-role { display: block; font-size: 0.875rem; color: var(--color-text-secondary); }

/* Compare cards */
.sp-compare-card {
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-top: 4px solid var(--color-cta);
  border-radius: var(--radius-lg); padding: var(--space-6);
}

/* Lead magnet */
.sp-lead-magnet {
  background: var(--color-bg-dark-raised); color: var(--color-text-on-dark);
  border-radius: var(--radius-lg); padding: var(--space-6);
  position: relative;
  /* Sits directly above the (dark) footer as the last block on the page.
     Without this it butts straight into the footer and the two dark
     surfaces read as one overlapping box. Force clear separation. */
  margin-bottom: var(--space-6);
}
.sp-lead-magnet h3 { color: var(--color-text-on-dark); }
.sp-lead-magnet p { color: var(--color-text-on-dark-secondary); }
.sp-lead-magnet-form { flex-direction: column; align-items: stretch; }
.sp-lead-magnet .form-label { color: var(--color-text-on-dark); }
.sp-lead-magnet-form .form-control { width: 100%; }
.sp-lead-magnet-form .btn { width: 100%; }

/* Accreditation explainer */
.sp-accreditation {
  display: flex; gap: var(--space-4); align-items: flex-start;
  background: var(--color-bg-surface); border: 1px solid var(--color-border);
  border-radius: var(--radius-lg); padding: var(--space-5); position: relative;
}
.sp-accreditation .sp-feature-icon { margin-bottom: 0; flex-shrink: 0; }

/* Bootstrap's spacing utilities stop at .mb-5/.mt-5 (3rem). This design
   system's scale goes to --space-10 (8rem), so the utility tier is
   extended here to match — .mb-6/.mt-6/.my-6 = --space-8 (4rem), used
   throughout the component templates for the gap above section headings
   like "Built for your sector". Without this, those classes silently
   no-op (unknown class = no rule) rather than erroring, which is why the
   gap was present but smaller than intended rather than visibly broken. */
.mb-6 { margin-bottom: var(--space-8) !important; }
.mt-6 { margin-top: var(--space-8) !important; }
.my-6 { margin-top: var(--space-8) !important; margin-bottom: var(--space-8) !important; }

/* Hero enquiry form card (issue 2/5) — translucent glass card, so form-text
   needs an explicit light colour override; Bootstrap's default muted grey
   is illegible against the dark hero backdrop. */
.sp-hero-form-card .form-text {
  color: rgba(255,255,255,0.75);
}
.sp-hero-form-card .form-text a {
  color: var(--sp-white);
  text-decoration: underline;
}

/* Credentials banner row (issue 4) — the FireQual/BlueSky/coverage chips,
   moved out of the hero into their own section directly below it, so
   they read as a distinct trust strip rather than crowding the hero's
   text and form. */
.sp-credentials-banner {
  padding-top: var(--space-5);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--color-border);
}
.sp-credentials-banner .sp-credentials {
  justify-content: center;
  margin-top: 0;
}

/* Sticky mobile call bar.
   Both this and .sp-consent-banner are position:fixed;bottom:0, so while
   the consent banner is in the DOM (before the visitor has accepted or
   rejected) the call bar must yield the slot entirely rather than stack
   underneath it — two fixed-bottom bars competing for the same thumb-reach
   zone is a genuine usability collision, not just a visual one. The
   consent banner removes itself from the DOM once a choice is stored
   (see consent-banner.js), at which point this selector no longer matches
   and the call bar appears with no JS coordination required. */
body:has(.sp-consent-banner) .sp-callbar { display: none; }
body:has(.sp-consent-banner) .sp-sticky-cta { display: none !important; }

.sp-sticky-cta {
  position: fixed;
  bottom: var(--space-5);
  right: var(--space-5);
  z-index: 1030;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  background: var(--color-cta);
  color: var(--sp-white);
  font-weight: 700;
  font-size: 0.9375rem;
  text-decoration: none;
  border-radius: var(--radius-pill);
  box-shadow: 0 8px 24px rgba(20,32,41,0.25);
  transition: transform 150ms ease, box-shadow 150ms ease, background 150ms ease;
}
.sp-sticky-cta:hover, .sp-sticky-cta:focus {
  background: var(--color-cta-hover);
  color: var(--sp-white);
  transform: translateY(-2px);
  box-shadow: 0 12px 28px rgba(20,32,41,0.3);
}
@media (prefers-reduced-motion: reduce) { .sp-sticky-cta:hover { transform: none; } }

.sp-callbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 1030;
  display: flex; gap: 1px;
  background: var(--color-border);
  box-shadow: 0 -4px 16px rgba(20,32,41,0.15);
  padding-bottom: env(safe-area-inset-bottom);
}
.sp-callbar-btn {
  flex: 1; display: flex; align-items: center; justify-content: center; gap: var(--space-2);
  min-height: 3.25rem; /* >=44px tap target + padding */
  font-weight: 600; font-size: 0.9375rem; text-decoration: none;
  padding: var(--space-3) var(--space-2);
}
.sp-callbar-call { background: var(--color-cta); color: var(--sp-white); }
.sp-callbar-call:hover, .sp-callbar-call:focus { background: var(--color-cta-hover); color: var(--sp-white); }
@media (max-width: 991.98px) { body { padding-bottom: 3.25rem; } }

/* Honeypot */
.sp-hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }
