/* ==========================================================================
   Asured Securities Limited — stylesheet
   --------------------------------------------------------------------------
   1.  Tokens            primitives + semantic roles
   2.  Base              reset, document, typography primitives
   3.  Layout            wrap, sections, surfaces
   4.  Buttons
   5.  Header & navigation
   6.  Mobile drawer
   7.  Page sections     hero, contact bar, about, services, why, dog feature,
                         coverage, accreditations, threat level, testimonials,
                         FAQ, forms, contact, footer
   8.  Inner pages       page hero, prose/legal, service detail, CTA strip, 404, auth
   9.  Fixed furniture   sticky CTA, WhatsApp, to-top, cookie banner, starfield
   10. Responsive
   11. Print
   ========================================================================== */

/* ==========================================================================
   0. METRIC-MATCHED FALLBACK FACES
   --------------------------------------------------------------------------
   font-display:swap means the fallback is painted first, then replaced. When
   the fallback sets type at a different width the text re-wraps and everything
   below it jumps — measured at 39px on the hero h1, which was the whole of the
   0.173 CLS. size-adjust scales each fallback so it occupies the same advance
   width as the real face, so the swap is invisible in layout terms.
   Percentages are calibrated empirically, per family, by comparing glyph
   advance widths (letter-spacing excluded, text-transform applied) between the
   real face and the fallback across the elements that actually use it:
     Montserrat 106%  (.hero-company-name 106.1, h1 105.8)
     Oswald      77%  (eyebrow 76.8, h2 75.6, nav 77.4, btn 75.8, h3 77.5)
     Inter      107%  (lead 107.5, body 107.2, footer 105.0)
   Measuring on a mixed-case sample gives the wrong answer - almost all display
   type here is uppercase and letter-spaced, which changes the ratio.
   ========================================================================== */

@font-face{
  font-family:'Montserrat Fallback';
  src:local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust:106%;
  font-weight:400 900;
  font-display:swap;
}
@font-face{
  font-family:'Oswald Fallback';
  src:local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust:77%;
  font-weight:400 700;
  font-display:swap;
}
@font-face{
  font-family:'Inter Fallback';
  src:local('Arial'), local('Helvetica Neue'), local('Liberation Sans');
  size-adjust:107%;
  font-weight:400 700;
  font-display:swap;
}

/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root{
  /* ---- primitives: brand ------------------------------------------------ */
  --navy-900:#05172b;
  --navy-800:#071d35;   /* brand navy */
  --navy-700:#0d2a4d;
  --navy-600:#123d69;
  --navy-500:#1b5390;
  --ink-900:#06131d;    /* deepest — footer, dog feature */

  --red-800:#a7182a;
  --red-700:#b81f2f;
  --red-600:#d72638;    /* brand red — AA on light surfaces only */
  --red-500:#ff9aa6;    /* dark-surface accent, hover step: 6.19:1 worst case */
  --red-400:#ff7a89;    /* AA-safe red for dark surfaces: 4.98:1 on the
                           lightest one (translucent cards), 6.79:1 on navy.
                           Same hue as --red-600 (354°) at full chroma — the
                           brand red simply lightened until it clears AA.
                           Do NOT set this to #d72638: that measures 2.51:1 on
                           a translucent card over navy-700 and 2.90:1 on
                           navy-700 itself. See --accent-solid for fills.    */
  --red-300:rgba(215,38,56,0.35);   /* decorative hover borders only */
  /* ---- primitives: neutrals --------------------------------------------- */
  --slate-900:#0f1a26;
  --slate-800:#1f2b38;
  --slate-700:#33414f;
  --slate-600:#4b5563;
  --slate-500:#5a6b7d;
  --slate-400:#8593a5;
  --slate-300:#cbd3dc;
  --slate-200:#e2e8ef;
  --slate-100:#f2f5f8;
  --white:#ffffff;

  /* ---- primitives: status ----------------------------------------------- */
  --green-700:#1e7a3c;
  --green-300:#5fd07d;
  --amber-500:#e3b23c;
  --orange-500:#e07b39;

  /* ---- semantic roles: light context (default) -------------------------- */
  --surface:var(--white);
  --surface-alt:var(--slate-100);
  --surface-raised:var(--white);
  --surface-sunken:var(--slate-200);

  --text:var(--slate-900);
  --text-muted:var(--slate-500);      /* 5.48:1 on white, 5.06:1 on --slate-100 */
  --text-subtle:var(--slate-600);

  --border:var(--slate-200);
  --border-strong:var(--slate-300);

  --accent:var(--red-600);            /* 4.97:1 on white — text + marks */
  --accent-hover:var(--red-800);
  --accent-quiet:rgba(215,38,56,.10);
  /*  --accent is free to shift per context to stay legible AS TEXT, which on
      dark means lightening it — and a lightened red cannot carry a white
      glyph (white on #ff7a89 is 2.5:1). So anything that FILLS a shape and
      puts white on top reads this instead: the one red that keeps white at
      4.97:1, in every context.                                              */
  --accent-solid:var(--red-600);

  --success:var(--green-700);
  --success-quiet:rgba(30,122,60,.10);
  --error:#b3261e;
  --error-quiet:rgba(179,38,30,.10);

  --focus-ring:var(--accent);

  /* ---- radius ------------------------------------------------------------ */
  --radius-sm:4px;
  --radius-md:8px;
  --radius-lg:14px;
  --radius-pill:999px;

  /* ---- spacing (4px base) ------------------------------------------------ */
  --space-1:4px;   --space-2:8px;   --space-3:12px;  --space-4:16px;
  --space-5:20px;  --space-6:24px;  --space-8:32px;  --space-10:40px;
  --space-12:48px; --space-16:64px; --space-20:80px; --space-24:96px;

  --section-y:clamp(56px, 8vw, 104px);
  --panel-pad:clamp(16px, 3.4vh, 44px);
  --section-y-tight:clamp(44px, 6vw, 80px);

  /* ---- type -------------------------------------------------------------- */
  --font-display:'Oswald', 'Oswald Fallback', 'Arial Narrow', sans-serif;
  --font-brand:'Montserrat', 'Montserrat Fallback', 'Segoe UI', sans-serif;
  --font-body:'Inter', 'Inter Fallback', 'Segoe UI', system-ui, sans-serif;

  --text-xs:clamp(12px, .3vw + 11px, 13px);
  --text-sm:clamp(14px, .3vw + 13px, 15px);
  --text-base:clamp(15px, .4vw + 14px, 16px);
  --text-lg:clamp(16px, .5vw + 15px, 18px);
  --text-xl:clamp(19px, .8vw + 17px, 22px);
  --text-2xl:clamp(22px, 1.2vw + 19px, 28px);
  --text-3xl:clamp(26px, 2vw + 20px, 38px);
  --text-4xl:clamp(32px, 3.6vw + 20px, 56px);

  --leading-tight:1.12;
  --leading-snug:1.3;
  --leading-normal:1.6;

  --tracking-tight:0.01em;
  --tracking-wide:0.06em;
  --tracking-wider:0.12em;
  --tracking-widest:0.24em;

  /* ---- elevation --------------------------------------------------------- */
  --shadow-1:0 1px 2px rgba(7,29,53,.06), 0 1px 3px rgba(7,29,53,.08);
  --shadow-2:0 2px 4px rgba(7,29,53,.06), 0 4px 12px rgba(7,29,53,.10);
  --shadow-3:0 4px 8px rgba(7,29,53,.08), 0 12px 28px rgba(7,29,53,.14);
  --shadow-4:0 8px 16px rgba(7,29,53,.10), 0 24px 56px rgba(7,29,53,.20);

  /* ---- motion ------------------------------------------------------------ */
  --dur-fast:120ms;
  --dur-base:200ms;
  --dur-slow:320ms;
  --dur-slower:500ms;
  --ease-out:cubic-bezier(.2,.8,.3,1);
  --ease-in-out:cubic-bezier(.4,0,.2,1);

  /* ---- layout ------------------------------------------------------------ */
  /*  Was 1240px — on anything wider than ~1300px that left a very large,
      visibly empty band on both sides of the actual content (background
      colour only, nothing sitting in it). Individual text elements already
      cap their own line length with ch-based max-widths (.section-head,
      .hero p.lead, etc.), so widening this doesn't create unreadably long
      lines — it just gives the grids/cards/images more of the screen.      */
  --maxw:1440px;
  /*  The nav bar stops short of --maxw on purpose. At the full 1440 it spans
      practically the whole window and reads as a page-wide band rather than a
      floating bar; pulling it in gives the pill room to sit as an object on
      the page. Its own token rather than a hard-coded value so the bar can be
      retuned without touching every other full-bleed container.             */
  --nav-maxw:1180px;
  --gutter:clamp(20px, 4vw, 40px);
  /*  asured.png is 578x432 (ratio 1.34) — a crest, not a wide wordmark. Sized
      by HEIGHT so the bar height is the constant and the logo follows it.
      Baseline rendered it 230x172, which is why the header was 205px tall.    */
  --header-h:78px;
  --logo-h:52px;
  /*  The visible pill sits inset within the header's own box rather than
      filling it — this is the gap eaten from the top, so the pill's rendered
      height is (--header-h - --header-gap). Every scroll-margin / panel-
      padding calculation site-wide reads --header-h alone and assumes it is
      the header's full on-screen footprint, so that footprint has to stay
      exactly --header-h regardless of how the visible pill is inset inside
      it — this is what keeps that unchanged.                                */
  --header-gap:10px;
  --bottom-bar-h:0px;   /* raised when the sticky CTA is on screen */
  /*  The open cookie banner's measured height, written to :root by
      initCookieConsent() while the banner is showing and reset to 0px the
      moment it is dismissed. The banner is anchored to the bottom EDGE, so
      without this the dock and the FAB stack sit underneath it - measured at
      390x844 the banner covered the WhatsApp button and Back to top outright.
      Every consumer adds it to its own bottom offset, so one number lifts the
      whole bottom-right stack over the banner and drops it back afterwards.  */
  --consent-h:0px;
  --fab-size:56px;      /* drives the whole bottom-right stack */

  /*  Display-cutout insets. Declared as zero here so every consumer has a
      valid value on browsers without env(), then overridden inside the
      @supports below — a bare env() in a calc() would drop the whole
      declaration on an engine that doesn't know the function.
      They are only non-zero once the viewport meta opts into viewport-fit=cover,
      which every page in this site does.                                      */
  --safe-t:0px;
  --safe-r:0px;
  --safe-b:0px;
  --safe-l:0px;
}

@supports (padding:env(safe-area-inset-bottom)){
  :root{
    --safe-t:env(safe-area-inset-top);
    --safe-r:env(safe-area-inset-right);
    --safe-b:env(safe-area-inset-bottom);
    --safe-l:env(safe-area-inset-left);
  }
}

/*  Dark surfaces re-declare the same semantic roles, so components never need
    a ".bg-navy &" variant — they read --text-muted and get the right value.   */
.hero,
.bg-navy,
.bg-charcoal,
.quote-section,
.dog-feature,
.page-hero,
.auth-section,
.dash-section,
.error-page,
.cta-strip,
.nav-card,
.cookie-banner,
footer{
  --surface:var(--navy-800);
  --surface-alt:var(--navy-700);
  --surface-raised:rgba(255,255,255,.05);
  --surface-sunken:rgba(0,0,0,.22);

  --text:var(--white);
  --text-muted:#c3ccd8;               /* 10.6:1 on navy */
  --text-subtle:#98a4b3;              /* 6.0:1 on navy, 5.5:1 on ink */

  --border:rgba(255,255,255,.12);
  --border-strong:rgba(255,255,255,.22);

  --accent:var(--red-400);            /* 4.98:1 on the worst dark surface */
  --accent-hover:var(--red-500);      /* 6.19:1 — hover brightens, as on light */
  --accent-quiet:rgba(255,122,137,.14);
  /*  Deliberately NOT lightened: this is the fill-under-white-glyph role.   */
  --accent-solid:var(--red-600);

  --success:var(--green-300);
  --success-quiet:rgba(95,208,125,.16);
  --error:#ff8a9b;
  --error-quiet:rgba(255,138,155,.12);

  --focus-ring:var(--white);
}

/* ==========================================================================
   2. BASE
   ========================================================================== */

*{box-sizing:border-box;}

/*  The UA's own [hidden] rule is a bare element selector, so ANY class that
    sets `display` silently beats it — which is how a hidden dashboard shell,
    a hidden filter row and a collapsed enquiry all rendered anyway. The
    attribute means "not rendered" everywhere in this codebase, so state it
    once, with the weight to hold.                                           */
[hidden]{display:none !important;}

html{
  scroll-behavior:smooth;
  scroll-padding-top:calc(var(--header-h) + var(--space-4));
  /*  Every page opens on navy-900 (.hero, .page-hero, .auth-section,
      .error-page, ...), so this is what iOS Safari's elastic overscroll
      reveals above the very top of the document instead of white - without
      it, pulling down flashes a white sliver above the header on every page. */
  background:var(--navy-900);
  /*  iOS Safari inflates the type of "wide" text blocks when the phone is
      turned to landscape, which breaks every measured clamp() on this page.
      Pinning it to 100% keeps rotation a pure reflow.                        */
  -webkit-text-size-adjust:100%;
  text-size-adjust:100%;
  /*  Not transparent: killing the highlight outright leaves Android with no
      tap feedback at all. A brand-tinted flash reads as intentional.         */
  -webkit-tap-highlight-color:rgba(215,38,56,.14);
  /*  Guaranteed backstop: overflow-wrap below (and min-width:0 on the grid/
      flex items further down that hold long tokens like the email address)
      fixes the actual causes, but this is the one rule that makes sideways
      drag structurally impossible no matter what a future change adds -
      nothing on this page ever needs to scroll horizontally.                  */
  overflow-x:hidden;
}

body{
  margin:0;
  /*  navy-900, matching html - body's own background is never meant to be
      seen (every section paints its own, edge to edge, all the way down),
      but a hairline sub-pixel gap can still show a sliver of it at the very
      top where hero overlaps the transparent header. White there read as a
      visible seam; navy-900 is invisible against the section it's under.    */
  background:var(--navy-900);
  color:var(--text);
  font-family:var(--font-body);
  font-size:var(--text-base);
  line-height:var(--leading-normal);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  /*  NO overflow-x here. html above already clips sideways drag at the
      viewport, and repeating it on body made body a scroll container of its
      own (overflow-y computes to auto the moment one axis is not visible).
      Two consequences, both measured: the sticky header resolved against
      body instead of the viewport, so it scrolled away at 176px instead of
      pinning - the nav, Login and Request a Quote were unreachable for the
      remaining ~8600px of the page - and body carried 60px of trapped scroll
      of its own that ate the first wheel tick on every page. One rule, on
      html, does the clipping job without either side effect.                */
  /*  A long unbroken token - an email address, a postcode-plus-URL - is wider
      than a 320px column and was the last source of sideways drag on the
      narrowest phones. Only takes effect once the grid/flex items holding
      these tokens can actually shrink below their content size - see the
      min-width:0 rules on .quote-grid/.contact-section-grid/.info-line/
      .contact-item children below, without which this alone doesn't kick in. */
  overflow-wrap:break-word;
  /*  Reserve the sticky bar's height so it never covers footer content. The
      home-indicator inset rides along with it, because the bar grows by the
      same amount.                                                             */
  padding-bottom:calc(var(--bottom-bar-h) + var(--safe-b));
}

h1,h2,h3,h4{
  font-family:var(--font-display);
  text-transform:uppercase;
  letter-spacing:var(--tracking-tight);
  line-height:var(--leading-snug);
  margin:0;
  color:var(--text);
  font-weight:600;
}
h1{line-height:var(--leading-tight);}

p{margin:0 0 var(--space-4);}
p:last-child{margin-bottom:0;}

a{color:inherit;text-decoration:none;}
ul{margin:0;padding:0;list-style:none;}
img{max-width:100%;display:block;}

/*  Inline colour patches removed from index/services live here instead.       */
/*  Standalone contact links are controls, not prose - give them a real target. */
.link-inherit{
  display:inline-flex;align-items:center;
  min-height:44px;
  color:inherit;
}
.link-inherit:hover{color:var(--accent);}

.eyebrow{
  font-family:var(--font-display);
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-widest);
  text-transform:uppercase;
  color:var(--accent);
  font-weight:600;
  margin:0;
  display:flex;
  align-items:center;
  gap:var(--space-3);
}
.eyebrow-center{justify-content:center;}

/*  Moved off-screen with transform rather than left:-9999px, which widens the
    scroll area on some engines.                                               */
.skip-link{
  position:fixed;left:0;top:0;z-index:400;
  display:inline-flex;align-items:center;min-height:44px;
  background:var(--red-600);color:var(--white);
  padding:var(--space-3) var(--space-6);
  border-radius:0 0 var(--radius-md) 0;
  font-family:var(--font-display);
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  font-weight:600;
  transform:translateY(-120%);
  transition:transform var(--dur-base) var(--ease-out);
}
.skip-link:focus{transform:translateY(0);}

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

/*  Pinned to the solid red rather than --accent: on a dark section --accent
    is the lightened red, and white on that is 2.5:1 — selecting text would
    make it harder to read, not easier. This keeps 4.97:1 site-wide.        */
::selection{background:var(--accent-solid);color:var(--white);}

/* ==========================================================================
   3. LAYOUT
   ========================================================================== */

.wrap{
  max-width:var(--maxw);
  margin:0 auto;
  /*  Held-sideways on a notched phone the cutout eats into one edge of the
      viewport, so the gutter has to be at least as wide as the inset.        */
  padding:0 max(var(--gutter), var(--safe-r)) 0 max(var(--gutter), var(--safe-l));
}

/*  Sections paint their own surface rather than letting the body show through.
    body is navy-900 (it has to be: it is what iOS elastic overscroll reveals,
    and what shows through the hairline under the transparent header), while a
    section with no .bg-* class is a LIGHT section - it resolves --text to
    slate-900 and its cards to white. Leaving it transparent painted near-black
    body copy onto navy: #about measured 1.03:1, i.e. the heading and lead were
    invisible on screen, and .btn-outline-dark disappeared with them.
    --surface is context-aware, so this one declaration is correct in both
    directions: white on a light section, navy-800 on anything that has opted
    into the dark role block. Every dark section sets its own background by
    class anyway, which outranks this element selector.                       */
section{padding:var(--section-y) 0;background:var(--surface);}
section.tight{padding:var(--section-y-tight) 0;}

/* ---------- the one-screen deck ----------
   Every top-level block on the home page is one panel, exactly one viewport
   tall, so a single flick of the wheel advances the reader by a whole section
   and nothing is ever left half-cut at the fold.

   The header is sticky, not fixed: it occupies the first --header-h of the
   document and then rides along on top of it. So the *first* panel is short by
   exactly that amount and snaps to 0 (via scroll-margin-top), while every
   later panel is a full 100svh and buys the header's height back inside its
   own top padding — the header then always covers panel padding, never panel
   content. That makes every snap point an exact multiple of one screen, which
   is the whole reason the previous version drifted: panels were sized
   100svh - header but snapped to their own top, so each one landed a header's
   height further out than the last.                                          */
html.home{
  scroll-snap-type:y proximity;
  /*  Panels carry their own header allowance, so the scroll container must not
      add a second one — in-page anchors land via scroll-margin-top instead.  */
  scroll-padding-top:0;
}

section.screen,
div.screen{
  scroll-snap-align:start;
  scroll-snap-stop:normal;
  scroll-margin-top:0;
  min-height:100vh;
  min-height:100svh;
  display:flex;
  flex-direction:column;
  justify-content:center;
  padding-top:calc(var(--header-h) + var(--panel-pad)) !important;
  padding-bottom:var(--panel-pad) !important;
}
/*  Every other panel is a full 100svh and buys the header's height back
    inside its own top padding, with the sticky header floating in front of
    that padding once scrolled - hero is the one panel that instead sits
    fully below the header in flow, which is exactly why a transparent
    header needed a hardcoded colour to look right on it at scroll:0. Pulling
    hero up by --header-h with a matching negative margin, and giving it the
    same "full screen + header-sized top padding" shape as every other panel,
    puts it in front of the header from the first frame instead - its own
    background is what the transparent gaps show, not a fixed colour that
    would drift from it. margin-top and the removed height deduction cancel
    exactly, so the panel's own bottom edge - and every panel after it -
    lands at the same position as before; only scroll-margin-top drops to 0
    to match, since hero's box now starts at the same document position
    (0) that used to require the --header-h compensation to reach.           */
.hero.screen{
  margin-top:calc(-1 * var(--header-h));
  min-height:100vh;
  min-height:100svh;
  scroll-margin-top:0;
  padding-top:calc(var(--header-h) + var(--panel-pad)) !important;
}
.screen > .wrap{width:100%;}
/*  Panels whose grid should expand into whatever height is left under the
    heading rather than sit centred inside it.                                */
.screen-fill > .wrap{display:flex;flex-direction:column;min-height:0;}

/*  dog-feature is a full-bleed two-column grid rather than a .wrap, so the
    header allowance moves onto its text column and the photo still bleeds to
    the very top of the panel.                                                */
.screen.dog-feature{display:grid !important;padding:0 !important;}
.screen.dog-feature .copy{padding-top:calc(var(--header-h) + var(--panel-pad));}

/*  Closing CTA + footer read as one unit and run taller than a panel on short
    screens, so they align to the bottom of the scrollport instead of the top. */
.page-end{scroll-snap-align:end;}

/*  Nothing from the fifth panel down needs styling or painting until it is
    near the scrollport. Each panel is exactly one screen, so the reserved
    intrinsic size is right first time and the scrollbar never jumps.         */
@media (min-width:1201px) and (min-height:601px){
  main .screen ~ .screen ~ .screen ~ .screen{
    content-visibility:auto;
    /*  The reserved size is the *content* box, so it has to exclude the header
        allowance and the panel padding that sit outside it - reserving a whole
        100svh made every skipped panel 130px too tall and the scrollbar lied
        about the length of the page until you had scrolled past it.          */
    contain-intrinsic-size:auto calc(100svh - var(--header-h) - var(--panel-pad) * 2);
  }
}

/*  Below the deck breakpoint panels return to ordinary flow. 1200px is where
    the existing responsive ladder starts folding grids (why-grid drops to
    three columns there), and a narrower column wraps enough extra lines that
    About and Why Choose Us stop clearing one screen - so that is where the
    deck hands over rather than showing half-cut panels. The third condition
    is the cramped corner - a narrow window that is also short - where the two
    limits compound and About stops fitting even at 1280.                     */
@media (max-width:1200px), (max-height:600px), (max-width:1400px) and (max-height:680px){
  html.home{scroll-snap-type:none;}
  section.screen,
  div.screen{
    min-height:0;
    padding-top:var(--section-y-tight) !important;
    padding-bottom:var(--section-y-tight) !important;
  }
  /*  margin-top:-header_h still applies from the base rule at every width -
      min-height and padding-top both have to keep accounting for it here too,
      the same way the base rule's do, or hero loses --header-h of height (the
      next panel shifts up to fill it) and its content loses the clearance
      that keeps it from rendering behind the header.                        */
  .hero.screen{
    min-height:100svh;
    padding-top:calc(var(--header-h) + clamp(40px, 6vw, 72px)) !important;
    padding-bottom:clamp(40px, 6vw, 72px) !important;
  }
  .screen.dog-feature{padding:0 !important;}
  .screen.dog-feature .copy{padding-top:clamp(28px, 5vh, 64px);}
}
@media (prefers-reduced-motion:reduce){html.home{scroll-snap-type:none;}}

.section-head{max-width:64ch;margin-bottom:clamp(var(--space-4), 3vh, var(--space-8));}
.section-head h2{font-size:var(--text-2xl);margin-top:var(--space-2);}
.section-head p{color:var(--text-muted);font-size:var(--text-sm);margin-top:var(--space-2);}

.section-title{font-size:var(--text-2xl);margin-top:var(--space-2);}

.bg-navy{background:linear-gradient(180deg, var(--navy-900) 0%, var(--navy-800) 100%);color:var(--text);position:relative;z-index:0;}
.bg-charcoal{background:linear-gradient(180deg, var(--navy-800) 0%, var(--navy-700) 100%);color:var(--text);position:relative;z-index:0;}
.bg-light{background:var(--slate-100);}


/* ==========================================================================
   4. BUTTONS
   ========================================================================== */

.btn{
  display:inline-flex;align-items:center;justify-content:center;
  gap:var(--space-2);
  min-height:44px;
  padding:var(--space-3) var(--space-8);
  border:2px solid transparent;
  border-radius:var(--radius-sm);
  font-family:var(--font-display);
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  font-weight:600;
  line-height:1.2;
  white-space:nowrap;
  cursor:pointer;
  transition:background 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);
}

.btn-red{
  background:var(--red-600);
  color:var(--white);
  border-color:var(--red-600);
  box-shadow:var(--shadow-1), 0 4px 14px rgba(215,38,56,.22);
}
.btn-red:hover{background:var(--red-800);border-color:var(--red-800);box-shadow:var(--shadow-2), 0 8px 22px rgba(215,38,56,.32);}
.btn-red:active{transform:translateY(1px);box-shadow:var(--shadow-1);}

.btn-outline{
  background:transparent;
  color:var(--white);
  border-color:rgba(255,255,255,.45);
}
.btn-outline:hover{border-color:var(--white);background:rgba(255,255,255,.10);}
.btn-outline:active{transform:translateY(1px);}

.btn-outline-dark{
  background:transparent;
  color:var(--navy-800);
  border-color:var(--navy-800);
}
.btn-outline-dark:hover{background:var(--navy-800);color:var(--white);}
.btn-outline-dark:active{transform:translateY(1px);}

.btn[disabled],.btn.is-busy{
  opacity:.6;
  cursor:not-allowed;
  box-shadow:none;
  transform:none;
}

.btn .spinner{
  width:14px;height:14px;flex:none;
  border:2px solid rgba(255,255,255,.35);
  border-top-color:var(--white);
  border-radius:var(--radius-pill);
  animation:spin .7s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg);}}

/* ==========================================================================
   5. HEADER & NAVIGATION  (CardNav)
   ==========================================================================
   Ported from the React Bits CardNav component into this site's shape: one
   bar that expands downward into three cards, replacing both the old link
   row and the separate off-canvas drawer. Two deliberate departures from
   the upstream component:

     no GSAP    upstream tweens height and staggers the cards on a paused
                gsap timeline. That is one 70KB dependency for a height
                tween and three transition-delays, on a site with no build
                step - so height is a CSS transition driven by an explicit
                pixel height JS measures, and the stagger is the same
                nth-child(transition-delay) ladder the old drawer already
                used. Behaviour matches; the payload is nothing.

     sticky     upstream is position:absolute, top:2em - fine for a one-page
                demo, wrong across 12 pages of varying length. The sticky
                full-width, transparent, exactly --header-h tall <header>
                box is kept exactly as it was, and .card-nav floats inside
                it, because every scroll-margin-top / scroll-padding-top
                calculation site-wide already reads --header-h as the
                header's on-screen footprint.

   Transparent, not a hardcoded colour: header is sticky, so once scrolled it
   sits in front of whatever section has scrolled up beneath it - a fixed
   colour would only ever match the one section it was tuned against. Each
   page's first section bleeds its own background up behind it instead - see
   .hero.screen, .page-hero, .auth-section and .error-page.                  */

header{
  position:sticky;top:0;z-index:100;
  height:var(--header-h);
  background:none;
  pointer-events:none;   /* clicks pass through the transparent margin around the bar */
}

/*  The visible bar. Collapsed it is exactly the old pill's height
    (--header-h - --header-gap); open, JS writes an explicit pixel height so
    the transition has two real endpoints to run between - height:auto is not
    animatable, and the measured value is what lets one rule serve both the
    desktop three-across layout and the stacked mobile one.                  */
.card-nav{
  pointer-events:auto;
  position:relative;
  display:block;
  overflow:hidden;
  width:calc(100% - var(--space-2) * 2);
  max-width:var(--nav-maxw);
  height:calc(var(--header-h) - var(--header-gap));
  margin:var(--header-gap) auto 0;
  background:var(--surface);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-3);
  /*  Opaque by default - see the @supports block below for why the glass is
      not the base state.                                                     */
  will-change:height;
  transition:height var(--dur-slow) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out);
}

/*  Upstream caps the bar at 800px, which is a demo width - this site already
    has a --maxw and a --gutter, so the bar tracks those and simply stops
    growing where every other full-bleed container on the page stops.        */
@media (min-width:1024px){
  .card-nav{width:calc(100% - var(--gutter) * 2);}
}

header.is-scrolled .card-nav{box-shadow:var(--shadow-4);}
.card-nav.is-open{box-shadow:var(--shadow-4);}

/*  Glass, and only where the blur is real. Without backdrop-filter a
    translucent bar is just a washed-out one - whatever is behind it shows
    through at full detail and the nav labels sit on top of hero photography.
    So the opaque --surface above stays the default and this lifts it only
    where the browser can actually frost what is underneath.

    .78 is deliberately high for a "slight" effect: the bar passes over the
    navy hero as well as the light panels, and at that alpha the navy shows
    through as a tint rather than darkening the bar enough to threaten the
    contrast of the dark nav labels on it (measured 8.8:1 over the hero,
    against the 4.5:1 floor).

    The edge highlight is an inset ring rather than a border because the bar's
    height is a calc() off --header-h and .card-nav-top is absolutely
    positioned to match it - a real border would eat a pixel of that and
    knock the two out of alignment.                                          */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card-nav{
    background:rgba(255,255,255,.78);
    -webkit-backdrop-filter:blur(18px) saturate(180%);
            backdrop-filter:blur(18px) saturate(180%);
    box-shadow:var(--shadow-3), inset 0 0 0 1px rgba(255,255,255,.55);
  }
  header.is-scrolled .card-nav,
  .card-nav.is-open{
    /*  Opened or scrolled, the bar has real content behind it and carries more
        of the page - firm it up so the panel's cards read against it.        */
    background:rgba(255,255,255,.88);
    box-shadow:var(--shadow-4), inset 0 0 0 1px rgba(255,255,255,.6);
  }
}

/* ---------- the collapsed bar ---------- */

/*  Pinned rather than in flow: the bar keeps its own band while the element
    around it grows to the open height, so nothing in the top row shifts as
    the cards come down.                                                     */
.card-nav-top{
  position:absolute;top:0;left:0;right:0;
  height:calc(var(--header-h) - var(--header-gap));
  z-index:2;
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--space-4);
  padding:0 var(--space-4) 0 var(--space-5);
}

/*  Burger left, logo optically centred, actions right - CardNav's own desktop
    arrangement. The logo is absolutely centred against the BAR, not laid out
    between the two side groups, so an uneven-width burger and action cluster
    cannot drag the brand mark off centre.                                    */
.card-nav-burger{
  flex:none;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;
  width:44px;height:44px;      /* full 44px target, not the 26px line width */
  padding:0;
  background:none;border:0;
  color:var(--navy-800);
  cursor:pointer;
  border-radius:var(--radius-md);
  transition:background var(--dur-fast) var(--ease-out);
}
.card-nav-burger:hover{background:var(--accent-quiet);}

.card-nav-burger-line{
  display:block;
  width:26px;height:2px;
  background:currentColor;
  border-radius:2px;
  transform-origin:50% 50%;
  transition:transform var(--dur-base) var(--ease-out),
             opacity var(--dur-fast) var(--ease-out);
}
.card-nav-burger:hover .card-nav-burger-line{opacity:.75;}
/*  Two lines crossing into an X - the upstream close affordance, kept.      */
.card-nav-burger[aria-expanded="true"] .card-nav-burger-line:first-child{
  transform:translateY(4px) rotate(45deg);
}
.card-nav-burger[aria-expanded="true"] .card-nav-burger-line:last-child{
  transform:translateY(-4px) rotate(-45deg);
}

.logo{
  position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%);
  display:flex;align-items:center;
  min-height:44px;
}
.logo-image{
  height:var(--logo-h);
  width:auto;
  object-fit:contain;
  display:block;
  transition:height var(--dur-base) var(--ease-out);
}

.card-nav-actions{
  display:flex;align-items:center;
  gap:var(--space-3);
  margin-left:auto;
}
.card-nav-actions .btn{padding:var(--space-3) var(--space-5);font-size:var(--text-xs);}

.account-btn{
  display:inline-flex;align-items:center;justify-content:center;
  gap:var(--space-2);
  min-height:44px;
  padding:0 var(--space-4);
  font-family:var(--font-display);
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  font-weight:700;
  color:var(--navy-800);
  background:none;
  border:1px solid var(--border-strong);
  border-radius:var(--radius-pill);
  transition:background var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out),
             color var(--dur-fast) var(--ease-out);
}
.account-btn svg{width:18px;height:18px;flex:none;}
.account-btn:hover{background:var(--navy-800);border-color:var(--navy-800);color:var(--white);}
.account-btn:active{transform:translateY(1px);}

/* ---------- the expanding card panel ---------- */

.card-nav-content{
  position:absolute;left:0;right:0;
  top:calc(var(--header-h) - var(--header-gap));
  display:flex;align-items:stretch;
  gap:var(--space-3);
  padding:0 var(--space-3) var(--space-3);
  /*  visibility (not display) so the panel is measurable while closed, and
      unreachable by pointer or tab until it is not - visibility:hidden also
      takes its links out of the tab order, so no inert bookkeeping is needed. */
  visibility:hidden;
  pointer-events:none;
}
.card-nav.is-open .card-nav-content{visibility:visible;pointer-events:auto;}

/*  Stacked on a short screen, three cards can measure taller than the
    viewport - 945px against an 844px phone - and with the body scroll-locked
    behind it the Contact card would simply be unreachable. When JS finds the
    natural height exceeds what fits, it caps the bar and sets this class, and
    the panel scrolls internally instead of being clipped by overflow:hidden.
    The class is off while measuring, so the cap never feeds back into it.    */
.card-nav.is-capped .card-nav-content{
  bottom:0;
  overflow-y:auto;
  overscroll-behavior:contain;
}

.nav-card{
  flex:1 1 0;
  min-width:0;
  display:flex;flex-direction:column;
  gap:var(--space-3);
  padding:var(--space-5) var(--space-5) var(--space-4);
  border-radius:calc(var(--radius-lg) - 4px);
  color:var(--white);
  user-select:none;
  /*  The GSAP stagger, as CSS. Delays apply on the way IN only - the base
      rule carries none, so the cards leave together instead of the last one
      hanging behind the closing bar.                                        */
  opacity:0;
  transform:translateY(50px);
  transition:opacity var(--dur-slow) var(--ease-out),
             transform var(--dur-slow) var(--ease-out);
}
.card-nav.is-open .nav-card{opacity:1;transform:none;}
.card-nav.is-open .nav-card:nth-child(1){transition-delay:80ms;}
.card-nav.is-open .nav-card:nth-child(2){transition-delay:160ms;}
.card-nav.is-open .nav-card:nth-child(3){transition-delay:240ms;}

/*  Three cards drawn from the brand ramp in navy -> navy -> red order, so the
    open panel reads as the brand mark enlarged rather than as three arbitrary
    colours. White clears AA on all three: 15.9:1 on navy-800, 9.6:1 on
    navy-600, and 4.97:1 on red-600 - which is exactly why the red here is
    --accent-solid and not --red-400.                                        */
.nav-card-about{background:var(--navy-800);}
.nav-card-services{background:var(--navy-600);}
.nav-card-contact{background:var(--accent-solid);}

.nav-card-label{
  font-family:var(--font-display);
  font-size:var(--text-xl);
  font-weight:700;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--white);
}

.nav-card-links{
  margin-top:auto;
  display:flex;flex-direction:column;
  gap:2px;
}
/*  Services carries ten links against the other cards' three. One column
    would set the open height by that card alone and leave the other two
    mostly empty; two columns keeps all three close to the same height.      */
.nav-card-services .nav-card-links{
  display:grid;
  grid-template-columns:repeat(2,minmax(0,1fr));
  gap:2px var(--space-4);
}

.nav-card-link{
  display:inline-flex;align-items:center;
  gap:var(--space-2);
  min-height:32px;
  font-size:var(--text-sm);
  color:rgba(255,255,255,.86);
  text-decoration:none;
  transition:color var(--dur-fast) var(--ease-out);
}
.nav-card-link:hover,
.nav-card-link:focus-visible{color:var(--white);}
.nav-card-link[aria-current]{color:var(--white);font-weight:700;}

.nav-card-link-icon{
  width:14px;height:14px;flex:none;
  opacity:.7;
  transition:transform var(--dur-fast) var(--ease-out),
             opacity var(--dur-fast) var(--ease-out);
}
.nav-card-link:hover .nav-card-link-icon{opacity:1;transform:translate(2px,-2px);}

/*  The backdrop is the old drawer's, kept: an open panel that overlays page
    content still needs the page behind it to recede and to be clickable-to-
    close. Sits under the header's z-index:100 so the bar stays lit.         */
.nav-backdrop{
  position:fixed;inset:0;z-index:90;
  background:rgba(6,19,29,.62);
  opacity:0;visibility:hidden;
  transition:opacity var(--dur-slow) var(--ease-out), visibility var(--dur-slow) var(--ease-out);
}
.nav-backdrop.is-open{opacity:1;visibility:visible;}

/*  Scroll lock for the open panel. position:fixed rather than overflow:hidden
    because overflow alone does not hold on iOS Safari; script.js pins the body
    at its current offset and restores it on close.                          */
body.nav-open{position:fixed;left:0;right:0;width:100%;overflow:hidden;}

/* ---------- header: responsive ladder ----------
   CardNav collapses to one bar at every width, so the old three-step ladder
   that shed links before falling back to a burger has nothing left to shed.
   What remains is the bar's own scale, and the point where three cards
   across stop fitting and stack.                                            */

@media (max-width:1199px){
  :root{--header-h:72px;--logo-h:48px;}
  .card-nav-actions{gap:var(--space-2);}
  .card-nav-actions .btn{padding:var(--space-3) var(--space-4);}
}

@media (max-width:1023px){
  /*  The account control drops to an icon - its label is the first thing
      worth spending width on, and the same link sits in the Contact card.   */
  .account-btn{width:44px;padding:0;}
  .account-label{
    position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
  }
}

/*  Upstream's breakpoint. Below it the cards stack, the CTA leaves the bar
    (this site already has a sticky bottom quote bar from here down), and the
    logo goes back to the left with the burger opposite it - a centred logo
    between a burger and nothing reads as misaligned, not centred.           */
@media (max-width:767px){
  :root{--header-h:60px;--logo-h:40px;}

  .card-nav-top{padding:0 var(--space-3);}
  .card-nav-burger{order:3;}
  .logo{position:static;transform:none;order:1;}
  .card-nav-actions{order:2;margin-left:auto;}
  .card-nav-cta{display:none;}

  .card-nav-content{
    flex-direction:column;
    gap:var(--space-2);
    padding:0 var(--space-2) var(--space-2);
  }
  .nav-card{padding:var(--space-4);gap:var(--space-2);}
  .nav-card-label{font-size:var(--text-lg);}
  /*  Two columns survive the stack - at 360px each column still holds a
      service name on one line, and ten stacked rows would push the Contact
      card off a small screen entirely.                                      */
  .nav-card-services .nav-card-links{gap:2px var(--space-3);}
}

@media (max-width:479px){
  :root{--header-h:56px;--logo-h:36px;}
}

/*  One column only on the narrowest phones. Ten services stacked singly cost
    roughly 160px more than the same ten in two columns, which is the
    difference between the stacked panel fitting a 844px screen and not - so
    two columns are held as long as a service name still fits one, and 360px
    is where that stops being true.                                          */
@media (max-width:359px){
  .nav-card-services .nav-card-links{grid-template-columns:1fr;}
}

/*  Never leave the cards invisible if the transition cannot run, and do not
    animate the bar's height for a visitor who asked for less motion.        */
@media (prefers-reduced-motion:reduce){
  .card-nav{transition:box-shadow var(--dur-base) var(--ease-out);}
  .nav-card{opacity:1;transform:none;transition:none;}
  .card-nav.is-open .nav-card:nth-child(1),
  .card-nav.is-open .nav-card:nth-child(2),
  .card-nav.is-open .nav-card:nth-child(3){transition-delay:0s;}
  .card-nav-burger-line{transition:none;}
}

/* ==========================================================================
   7. PAGE SECTIONS
   ========================================================================== */

/* ---------- hero ---------- */
.hero{
  position:relative;
  /*  Explicit z-index (not just position:relative) so this box becomes its
      own stacking context - otherwise a z-index:-1 descendant (the starfield
      layer below) has no local "floor" to sink to and escapes to the root
      stacking context, painting behind the section's own background rather
      than just behind its text.                                            */
  z-index:0;
  overflow:hidden;
  display:flex;
  align-items:center;
  min-height:calc(100svh - var(--header-h));
  padding:clamp(40px, 6vw, 72px) 0;
  background:
    radial-gradient(ellipse at 20% 20%, rgba(215,38,56,.12), transparent 55%),
    linear-gradient(180deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color:var(--text);
}
.hero::before{
  content:"";position:absolute;inset:0;
  background-image:
    linear-gradient(rgba(255,255,255,.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.035) 1px, transparent 1px);
  background-size:64px 64px;
  mask-image:radial-gradient(ellipse at 60% 30%, black 0%, transparent 75%);
  -webkit-mask-image:radial-gradient(ellipse at 60% 30%, black 0%, transparent 75%);
}

.scanline{
  position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg, transparent, var(--red-600), transparent);
  opacity:.7;
  will-change:transform;
  animation:sweep 7s linear infinite;
}
/*  Was animating `top`, which relaid out the whole hero on every frame of a
    7s loop that never stops. The same sweep on translateY is composited.     */
@keyframes sweep{
  0%{transform:translateY(-2vh);}
  100%{transform:translateY(calc(100svh - var(--header-h) + 2vh));}
}

.hero-inner{
  position:relative;z-index:2;
  width:100%;
  /*  Keeps the copy clear of the scroll cue pinned to the foot of the panel. */
  padding-bottom:clamp(24px, 7vh, 60px);
  display:grid;grid-template-columns:1.2fr .95fr;
  gap:clamp(32px, 5vw, 56px);
  align-items:center;
}

/*  The logo already says the company name 100px away, so setting it again at
    36px only stole room from the actual headline. Kept for the crawler and
    for brand recall, demoted to a tracked kicker above the eyebrow.          */
.hero-company-name{
  margin:0;
  color:var(--text-subtle);
  font-family:var(--font-display);
  font-size:var(--text-xs);
  line-height:1.2;
  letter-spacing:var(--tracking-widest);
  text-transform:uppercase;
  font-weight:600;
}
.hero-company-name span{color:var(--text-subtle);}
.hero-copy > .eyebrow{margin-top:clamp(8px, 1.4vh, 14px);}

/*  Sized to wrap word-per-line at this column width, like a poster headline,
    rather than the more conservative multi-word-per-line size used before.  */
.hero h1{
  font-family:var(--font-brand);
  font-weight:800;
  /*  Capped so the headline lands in two lines inside its column and the whole
      hero — kicker through stat row — still clears one screen at 700px tall. */
  font-size:clamp(30px, 3.2vw, 52px);
  line-height:1.06;
  letter-spacing:-.02em;
  margin:clamp(10px, 1.8vh, 18px) 0 clamp(10px, 1.8vh, 18px);
  text-wrap:balance;
  /*  A legibility floor now that the hero also carries a drifting starfield
      layer behind it - keeps the headline crisply separated from the texture
      without a scrim that would dull the section's own background.        */
  text-shadow:0 2px 20px rgba(0,0,0,.35);
}
.hero h1 em{color:var(--accent);font-style:normal;}
.hero p.lead{
  font-size:var(--text-base);
  color:var(--text-muted);
  max-width:56ch;
  margin-bottom:clamp(14px, 2.4vh, 26px);
}
.hero-ctas{display:flex;gap:var(--space-4);flex-wrap:wrap;}

/*  Balanced stat row under the CTAs — every number here is a verbatim
    restatement of something already stated in #about (stat-row/about-badge),
    not a new claim. Shares the .stat-row class purely so the existing
    count-up script (`.stat-row .num[data-count]`) picks it up too; the
    boxed .stat-card look from #about is deliberately not reused here.       */
.hero-stats.stat-row{
  grid-template-columns:repeat(3, minmax(0, 1fr));
  gap:0;
  margin-top:clamp(16px, 3vh, 30px);
  padding-top:clamp(12px, 2.2vh, 20px);
}
.hero-stat{
  display:flex;flex-direction:column;gap:var(--space-1);
  min-width:0;
  padding:0 var(--space-5);
}
.hero-stat:first-child{padding-left:0;}
.hero-stat:not(:first-child){border-left:1px solid var(--border);}

/*  Three columns of a two-word uppercase label stop fitting well before the
    hero itself runs out of room. At 430px each column is ~106px against an
    ~82px label, which still works once the dividers are tightened; below 480
    it is not close, and the labels were breaking mid-word ("NATIO NWIDE").
    Under that the three stats become three single-line rows, number and label
    side by side, which is shorter than the wrapped grid it replaces.        */
@media (max-width:600px){
  .hero-stat{padding:0 var(--space-3);}
}
@media (max-width:479px){
  .hero-stats.stat-row{grid-template-columns:1fr;gap:var(--space-2);}
  .hero-stat{
    flex-direction:row;align-items:baseline;
    gap:var(--space-3);
    padding:0;
  }
  .hero-stat:not(:first-child){
    border-left:none;
    border-top:1px solid var(--border);
    padding-top:var(--space-2);
  }
  .hero-stats .lab{line-height:1.2;}
}
.hero-stats .num{
  font-family:var(--font-display);
  font-size:var(--text-2xl);
  font-weight:700;
  color:var(--accent);
  font-variant-numeric:tabular-nums;
  line-height:1;
}
.hero-stats .lab{
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--text-muted);
}

/*  Outer box is deliberately NOT clipped — .hero-float badges are meant to
    overlap past the card's own edge, the way a floating stat callout does.
    The photo, its gradient and the inset ring live on the inner card, which
    is where overflow:hidden actually belongs.                              */
/*  Width, not height, is the constrained axis: aspect-ratio then derives the
    height, so the card scales with a short viewport without ever being
    over-constrained (max-height against aspect-ratio collapsed the box).     */
.hero-visual{
  position:relative;
  aspect-ratio:4/3.4;
  width:min(100%, 520px, 66vh);
  margin-inline:auto;
}
.hero-visual-card{
  position:relative;
  width:100%;height:100%;
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  background:linear-gradient(160deg, var(--navy-700), var(--navy-800));
  overflow:hidden;
  box-shadow:var(--shadow-3), 0 0 0 1px rgba(215,38,56,.10);
}
.hero-visual-card img.hero-photo{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;
  object-fit:cover;
  transition:transform var(--dur-slower) var(--ease-out);
}
.hero-visual:hover .hero-visual-card img.hero-photo{transform:scale(1.04);}
.hero-visual-card::after{
  content:"";
  position:absolute;inset:0;z-index:1;
  background:linear-gradient(165deg,
    rgba(5,23,43,.40) 0%,
    rgba(5,23,43,0) 36%,
    rgba(5,23,43,0) 56%,
    rgba(5,23,43,.72) 100%);
  pointer-events:none;
}
.hero-visual-card::before{
  content:"";
  position:absolute;inset:0;z-index:1;
  border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08);
  pointer-events:none;
}
.hero-visual-card .badge{
  position:absolute;z-index:2;
  bottom:var(--space-4);left:var(--space-4);right:var(--space-4);
  background:rgba(5,7,10,.88);
  border-left:3px solid var(--accent);
  border-radius:var(--radius-md);
  padding:var(--space-3) var(--space-4);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
}
.hero-visual-card .badge p{
  margin:0;
  font-family:var(--font-display);
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--white);
}
.hero-visual-card .badge span{font-size:var(--text-sm);color:var(--text-muted);}

/*  Floating credibility callouts, overlapping the card corners. Colours are
    literal, not the semantic --accent/--success tokens — this pill is always
    white regardless of the dark hero around it, so it needs the values that
    are safe on white, not the ones tuned for navy.                         */
.hero-float{
  position:absolute;z-index:3;
  display:flex;align-items:center;gap:var(--space-2);
  background:var(--white);
  color:var(--navy-800);
  border-radius:var(--radius-pill);
  padding:var(--space-2) var(--space-4);
  font-family:var(--font-display);
  font-size:var(--text-xs);
  font-weight:600;
  letter-spacing:var(--tracking-tight);
  white-space:nowrap;
  box-shadow:var(--shadow-3);
}
.hero-float svg{width:14px;height:14px;flex:none;}
.hero-float-top{top:calc(var(--space-5) * -1);left:var(--space-5);}
.hero-float-top svg{color:var(--green-700);}
.hero-float-bottom{bottom:calc(var(--space-4) * -1);right:calc(var(--space-4) * -1);}
.hero-float-bottom svg{color:var(--red-600);}

/*  Tells the reader, before they touch the wheel, that this page moves a
    screen at a time. Hidden once the deck is off (tablet and below).         */
.scroll-cue{
  position:absolute;z-index:3;
  left:50%;bottom:clamp(8px, 1.8vh, 20px);
  transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:var(--space-2);
  color:var(--text-subtle);
  font-family:var(--font-display);
  font-size:11px;
  letter-spacing:var(--tracking-widest);
  text-transform:uppercase;
  font-weight:600;
  transition:color var(--dur-base) var(--ease-out);
}
.scroll-cue:hover{color:var(--white);}
.scroll-cue-rail{position:relative;width:10px;height:38px;}
.scroll-cue-rail::before{
  content:"";
  position:absolute;left:50%;top:0;margin-left:-1px;
  width:2px;height:100%;
  border-radius:2px;
  background:linear-gradient(180deg, rgba(255,255,255,.30), rgba(255,255,255,0));
}
.scroll-cue-dot{
  position:absolute;left:50%;top:0;margin-left:-3px;
  width:6px;height:6px;
  border-radius:50%;
  background:var(--red-600);
  box-shadow:0 0 10px rgba(215,38,56,.85);
  animation:cue-fall 2.4s var(--ease-in-out) infinite;
}
@keyframes cue-fall{
  0%{transform:translateY(-6px);opacity:0;}
  25%{opacity:1;}
  100%{transform:translateY(36px);opacity:0;}
}
@media (max-width:1200px), (max-height:600px), (max-width:1400px) and (max-height:680px){.scroll-cue{display:none;}}

.corner{position:absolute;z-index:2;width:26px;height:26px;border:2px solid var(--accent);}
.corner.tl{top:-2px;left:-2px;border-right:none;border-bottom:none;}
.corner.tr{top:-2px;right:-2px;border-left:none;border-bottom:none;}
.corner.bl{bottom:-2px;left:-2px;border-right:none;border-top:none;}
.corner.br{bottom:-2px;right:-2px;border-left:none;border-top:none;}

/* ---------- contact bar ---------- */
.contact-bar{
  position:relative;overflow:hidden;
  background:linear-gradient(120deg, var(--red-700) 0%, var(--red-800) 100%);
  color:var(--white);
  padding:clamp(12px, 2.2vh, 32px) 0;
}
/*  Same 1px-grid texture as .cta-strip lower on the page, so the two red
    bands read as one family instead of a flat, unrelated colour block.     */
.contact-bar::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(90deg, rgba(255,255,255,.05) 1px, transparent 1px);
  background-size:48px 48px;
}
.contact-bar .wrap{
  position:relative;z-index:1;
  display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;
  gap:var(--space-6);
}
.contact-bar h2{color:var(--white);font-size:var(--text-2xl);}
.btn-white{background:var(--white);color:var(--red-700);border-color:var(--white);}
.btn-white:hover{background:var(--slate-100);}
.btn-white:active{transform:translateY(1px);}
/*  On the red band an accent-coloured hover would vanish — underline instead.  */
.contact-bar .link-inherit:hover{color:var(--white);text-decoration:underline;text-underline-offset:3px;}

.contact-grid{display:flex;flex-wrap:wrap;gap:var(--space-8);}
.contact-item{display:flex;align-items:center;gap:var(--space-3);}
/*  Flex items default to min-width:auto (sized to their content's intrinsic
    width), which overrides body's overflow-wrap:break-word and forces the
    row - and the whole page - wider than the viewport once the value is a
    long unbroken token like the email address. min-width:0 lets it shrink
    to the row's actual space so the wrap rule can do its job.               */
.contact-item > div{min-width:0;}
.contact-icon{
  display:flex;align-items:center;justify-content:center;flex:none;
  width:38px;height:38px;
  border-radius:50%;
  background:rgba(255,255,255,.15);
  color:var(--white);
}
.contact-icon svg{width:18px;height:18px;}
.contact-grid .label{
  font-family:var(--font-display);
  font-weight:500;
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wider);
  text-transform:uppercase;
  color:var(--white);
  margin-bottom:var(--space-1);
}
.contact-grid .value{font-weight:600;font-size:var(--text-base);}

/* ---------- about ---------- */
#about{position:relative;overflow:hidden;}
#about::before{
  content:"";
  position:absolute;z-index:0;
  top:-120px;right:-120px;
  width:420px;height:420px;
  border-radius:50%;
  background:radial-gradient(closest-side, rgba(215,38,56,.06), rgba(215,38,56,0));
  pointer-events:none;
}
#about .wrap{position:relative;z-index:1;}

/*  Copy column widened from 1.15fr: at the narrow end of the deck the lead
    and the body paragraph each picked up a line, which was the whole of the
    panel's overflow at 1280x640.                                           */
.about-grid{
  display:grid;grid-template-columns:.75fr 1.25fr;
  gap:clamp(24px, 4vw, 64px);
  /*  Stretch, not centre: on a one-screen panel a centred photo column leaves
      a band of empty white above and below it that the copy column does not. */
  align-items:stretch;
}
.about-grid > *{min-width:0;}
.about-copy{display:flex;flex-direction:column;justify-content:center;}

.about-visual-wrap{
  position:relative;
  display:flex;flex-direction:column;
}
.about-visual-wrap::before{
  content:"";
  position:absolute;z-index:0;
  top:var(--space-4);right:calc(-1 * var(--space-4));
  bottom:calc(-1 * var(--space-4));left:var(--space-4);
  background:var(--navy-800);
  border-radius:var(--radius-lg);
}

.about-visual{
  position:relative;z-index:1;flex:1;
  min-height:clamp(200px, 34vh, 360px);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  overflow:hidden;
  background:linear-gradient(160deg, var(--navy-700), var(--navy-800));
  box-shadow:var(--shadow-4);
}
.about-visual img{
  position:absolute;inset:0;z-index:0;
  width:100%;height:100%;
  object-fit:cover;
  transition:transform var(--dur-slower) var(--ease-out);
}
.about-visual-wrap:hover .about-visual img{transform:scale(1.05);}
.about-visual::after{
  content:"";
  position:absolute;inset:0;z-index:1;
  background:linear-gradient(200deg,
    rgba(5,23,43,.04) 30%,
    rgba(5,23,43,.28) 68%,
    rgba(5,23,43,.62) 100%);
  pointer-events:none;
}
.about-visual::before{
  content:"";
  position:absolute;inset:0;z-index:1;
  border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08);
  pointer-events:none;
}
.about-badge{
  position:absolute;z-index:2;
  bottom:var(--space-5);left:var(--space-5);
  display:flex;align-items:center;gap:var(--space-3);
  background:rgba(255,255,255,.96);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
  border-left:3px solid var(--accent);
  border-radius:var(--radius-md);
  padding:var(--space-3) var(--space-5);
  box-shadow:var(--shadow-4);
}
.about-badge .num{
  display:block;
  font-family:var(--font-display);
  font-size:var(--text-2xl);
  font-weight:700;
  color:var(--navy-800);
  line-height:1.1;
}
.about-badge .lab{
  display:block;
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--text-muted);
  max-width:16ch;
}

.accent-text{color:var(--accent);}

.about-copy .lead{
  font-size:var(--text-base);
  font-weight:600;
  color:var(--text);
  margin-bottom:var(--space-2);
}
.about-copy p{color:var(--text-subtle);margin-bottom:var(--space-2);font-size:var(--text-sm);}

.about-points{
  display:flex;flex-wrap:wrap;
  gap:var(--space-2);
  margin:clamp(6px, 1.2vh, 8px) 0 clamp(12px, 2.6vh, 20px);
  padding:0;
}
.about-points li{
  display:flex;gap:var(--space-2);align-items:center;
  font-size:var(--text-xs);
  font-weight:600;
  color:var(--navy-800);
  background:var(--slate-100);
  border:1px solid var(--border);
  border-radius:var(--radius-pill);
  padding:var(--space-1) var(--space-3) var(--space-1) var(--space-1);
  transition:background var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out);
}
.about-points li:hover{
  background:var(--accent-quiet);
  border-color:var(--red-300);
  transform:translateY(-2px);
}
.about-points svg{
  flex:none;width:18px;height:18px;padding:3px;
  border-radius:50%;
  background:var(--accent-solid);
  color:var(--white);
}

.about-ctas{display:flex;gap:var(--space-3);flex-wrap:wrap;margin-top:clamp(12px, 2.6vh, 20px);}

/* ---- stat cards ---- */
.stat-row{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:var(--space-3);
  padding-top:clamp(10px, 2vh, 16px);
  border-top:1px solid var(--border);
}
.stat-card{
  position:relative;
  display:flex;flex-direction:column;align-items:flex-start;
  gap:clamp(4px, 1vh, 8px);
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  padding:clamp(8px, 1.6vh, 12px);
  overflow:hidden;
  transition:transform var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out);
}
.stat-card::before{
  content:"";
  position:absolute;top:0;left:0;right:0;height:3px;
  background:linear-gradient(90deg, var(--accent), var(--navy-700));
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-slow) var(--ease-out);
}
.stat-card:hover{transform:translateY(-5px);box-shadow:var(--shadow-4);border-color:transparent;}
.stat-card:hover::before{transform:scaleX(1);}
.stat-card .icon{
  width:34px;height:34px;flex:none;
  display:flex;align-items:center;justify-content:center;
  border-radius:var(--radius-md);
  background:linear-gradient(150deg, var(--accent-solid), var(--red-800));
  color:var(--white);
  box-shadow:0 6px 14px rgba(215,38,56,.28);
}
.stat-card .icon svg{width:18px;height:18px;}
.stat-card .num{
  font-family:var(--font-display);
  font-size:clamp(19px, 3.4vh, 28px);
  color:var(--navy-800);
  font-weight:700;
  font-variant-numeric:tabular-nums;
  line-height:1.05;
}
.stat-card .lab{
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--text-muted);
}


/* ---------- services deck ----------
   Nine services, one screen. The old treatment was a 16:9 photo stacked over a
   title, a paragraph and a pill button inside a white card — about 300px of
   chrome per item, which is why the section ran to two and a half screens and
   never lined up with anything either side of it.

   Here the photo *is* the card: a wide crop under a scrim, with the title
   always legible and the description and link revealed on hover. The text
   stays in the DOM for crawlers and for anyone on a touch device, where the
   media query below shows it unconditionally.                               */
.services-deck{
  display:grid;
  grid-template-columns:repeat(3, 1fr);
  /*  minmax(0,1fr), not auto-rows:1fr - a row whose minimum is its content
      cannot shrink, so revealing a description on hover grew the row and
      pushed the third one off the bottom of the panel.                      */
  grid-template-rows:repeat(3, minmax(0, 1fr));
  gap:clamp(10px, 1.4vh, 18px);
  padding:0 var(--gutter);
  /*  width:100% is load-bearing: the panel is a column flex container and the
      tiles have no intrinsic width of their own (body and image are both
      absolutely positioned), so an auto inline margin with no definite width
      collapses the whole grid to its padding.                               */
  width:100%;
  max-width:var(--maxw);
  margin:clamp(10px, 2vh, 26px) auto 0;
  /*  Takes the height the heading leaves rather than pushing the panel taller. */
  flex:1;
  min-height:0;
}

.service-tile{
  position:relative;
  display:block;
  min-height:clamp(100px, 14vh, 240px);
  border-radius:var(--radius-lg);
  overflow:hidden;
  background:var(--navy-700);
  border:1px solid var(--border);
  transition:transform var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out);
}
.service-tile img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  opacity:.68;
  transition:transform var(--dur-slower) var(--ease-out),
             opacity var(--dur-base) var(--ease-out);
}
/*  Scrim paints after the image, so no z-index is needed to sit above it.     */
.service-tile::after{
  content:"";
  position:absolute;inset:0;
  background:linear-gradient(180deg,
    rgba(5,23,43,.15) 0%,
    rgba(5,23,43,.55) 45%,
    rgba(5,23,43,.94) 100%);
  pointer-events:none;
}
/*  Red rule that draws across the foot on hover.                             */
.service-tile::before{
  content:"";
  position:absolute;left:0;right:0;bottom:0;height:3px;z-index:3;
  background:var(--red-600);
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-slow) var(--ease-out);
}
.service-tile:hover,
.service-tile:focus-visible{
  transform:translateY(-4px);
  border-color:var(--red-300);
  box-shadow:0 18px 40px rgba(0,0,0,.42);
}
.service-tile:active{transform:translateY(-1px);transition-duration:var(--dur-fast);}
.service-tile:hover img,
.service-tile:focus-visible img{transform:scale(1.06);opacity:.44;}
.service-tile:hover::before,
.service-tile:focus-visible::before{transform:scaleX(1);}

.tile-num{
  position:absolute;z-index:2;
  top:var(--space-3);right:var(--space-4);
  padding:2px 5px;
  font-family:var(--font-display);
  font-size:var(--text-xs);
  font-weight:700;
  letter-spacing:var(--tracking-wide);
  /*  Was .42, which composites to 3.73:1 against the tile's own navy-700 —
      under AA for text this small. .58 clears it at 5.82:1 and still reads
      as a quiet index number rather than a second label.                    */
  color:rgba(255,255,255,.58);
  border:1px solid transparent;
  transition:color var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out);
}
/*  "Target acquired" read on the index number — same accent as the reticle
    corners elsewhere, cheap because it reuses an element already in place.   */
.service-tile:hover .tile-num,
.service-tile:focus-visible .tile-num{
  color:var(--white);
  border-color:var(--accent);
}

/*  Absolutely positioned, not in flow: a tile's height then comes only from
    its grid row, so revealing the description on hover can never feed back
    into the row size and grow the whole panel past one screen. The overflow
    is absorbed by .tile-reveal shrinking, which is why the heading has
    flex:none - the copy crops before the title ever does.                   */
.tile-body{
  position:absolute;inset:0;z-index:2;
  display:flex;flex-direction:column;justify-content:flex-end;
  overflow:hidden;
  padding:clamp(10px, 1.6vh, 20px) clamp(14px, 1.4vw, 20px);
}
.tile-body h3{
  flex:none;
  font-size:clamp(13px, .35vw + 12px, 16px);
  line-height:1.2;
  color:var(--white);
  margin:0;
}

/*  0fr -> 1fr animates to the real text height without a measured pixel value
    and without display:none, so the copy stays in the accessibility tree.     */
.tile-reveal{
  display:grid;
  grid-template-rows:0fr;
  /*  Lets the revealed block give way rather than pushing the title out of the
      top of a short tile - the paragraph crops, the heading never does.      */
  min-height:0;
  opacity:0;
  transition:grid-template-rows var(--dur-slow) var(--ease-out),
             opacity var(--dur-base) var(--ease-out);
}
.tile-reveal > div{overflow:hidden;min-height:0;}
.service-tile:hover .tile-reveal,
.service-tile:focus-visible .tile-reveal,
.service-tile:focus-within .tile-reveal{grid-template-rows:1fr;opacity:1;}

.tile-reveal p{
  margin:clamp(3px, .8vh, 8px) 0 0;
  font-size:var(--text-xs);
  line-height:1.35;
  color:var(--text-muted);
  /*  Two lines is what every one of these descriptions needs; the clamp is
      there so a longer one added later cannot outgrow the tile.             */
  display:-webkit-box;
  -webkit-line-clamp:2;
  -webkit-box-orient:vertical;
  overflow:hidden;
}
.tile-more{
  display:inline-flex;align-items:center;gap:var(--space-2);
  flex:none;
  margin-top:clamp(3px, .8vh, 8px);
  font-family:var(--font-display);
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  font-weight:600;
  color:var(--red-400);
}
.tile-more svg{width:15px;height:15px;flex:none;}

/*  Touch devices never get the hover, so they get the copy outright.          */
@media (hover:none){
  .tile-reveal{grid-template-rows:1fr;opacity:1;}
}
/*  On a short deck a tile is ~110px: enough to reveal the title and the link,
    not the description as well. Rather than crop a sentence mid-word, the
    short-viewport reveal is the link alone - the same sentence is one click
    away on the service page this tile points at. The threshold is where a
    tile first clears title + two lines + link (about a 760px viewport).      */
@media (min-width:1201px) and (max-height:760px){
  .tile-reveal p{display:none;}
}
@media (max-width:1024px){
  .services-deck{grid-template-columns:repeat(2, 1fr);grid-template-rows:none;grid-auto-rows:auto;}
  .service-tile{min-height:200px;}
}
@media (max-width:600px){
  .services-deck{grid-template-columns:1fr;}
  .service-tile{min-height:190px;}
}

/* ---------- why choose ---------- */
.why-grid{
  display:grid;grid-template-columns:repeat(4,1fr);
  grid-auto-rows:1fr;
  gap:clamp(var(--space-3), 2.5vh, var(--space-5));
  /*  Inside a .screen-fill panel this takes the height the heading leaves,
      so the two rows sit balanced instead of bunched at the top.            */
  flex:1;min-height:0;
}
/*  Numbered cards rather than a bare left-rule list — matches the .stat-card /
    .service-tile idiom already used elsewhere, so the page reads as one
    system instead of switching to a plainer treatment for this one section.
    Padding trimmed a notch from a first pass — this section keeps the
    one-screen-per-slide treatment (unlike Services/the forms, which don't
    fit one viewport at any reasonable size), so it needs the headroom.     */
.why-item{
  position:relative;
  padding:clamp(10px, 2vh, 16px) var(--space-4) clamp(8px, 1.6vh, 12px);
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  overflow:hidden;
  transition:transform var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out);
}
.why-item::before{
  content:"";
  position:absolute;top:0;left:0;right:0;height:3px;
  background:linear-gradient(90deg, var(--accent), var(--navy-700));
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-slow) var(--ease-out);
}
.why-item:hover{transform:translateY(-5px);box-shadow:var(--shadow-3);border-color:transparent;}
.why-item:active{transform:translateY(-2px);transition-duration:var(--dur-fast);}
.why-item:hover::before{transform:scaleX(1);}
/*  Corner brackets reuse the hero visual's targeting-reticle language (.corner,
    line ~1189) as a hover reveal, so the "focused on you" motif recurs as a
    system rather than a one-off hero flourish.                               */
.why-item::after{
  content:"";
  position:absolute;inset:var(--space-2);z-index:1;
  pointer-events:none;
  opacity:0;
  transition:opacity var(--dur-base) var(--ease-out);
  background:
    linear-gradient(var(--accent),var(--accent)) top left / 14px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top left / 2px 14px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top right / 14px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top right / 2px 14px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom left / 14px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom left / 2px 14px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom right / 14px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom right / 2px 14px no-repeat;
}
.why-item:hover::after,.why-item:focus-within::after{opacity:1;}
.why-num{
  display:block;
  font-family:var(--font-display);
  font-size:clamp(22px, 3.6vh, 38px);
  font-weight:700;
  line-height:1;
  /*  Was --border-strong — a hairline token doing duty as a text colour,
      which put these at 1.51:1 on white. --slate-400 is the quiet-grey
      token and clears the 3:1 large-text floor at 3.13:1, without
      promoting the index numbers over the headings they sit above.     */
  color:var(--slate-400);
  margin-bottom:clamp(4px, 1vh, 8px);
}
.why-item h3{font-size:clamp(15px, 2.7vh, 18px);margin-bottom:var(--space-1);color:var(--navy-800);}
.why-item p{color:var(--text-muted);font-size:var(--text-sm);}

/* ---------- dog feature ---------- */
.dog-feature{
  display:grid;grid-template-columns:1fr 1fr;
  padding:0;
  background:var(--ink-900);
  color:var(--text);
  position:relative;z-index:0;
}
.dog-feature .copy{
  padding:clamp(28px, 5vh, 64px) clamp(20px, 4vw, 60px);
  max-width:640px;
  margin-inline:auto;
  display:flex;flex-direction:column;justify-content:center;
}
.dog-feature .copy h2{font-size:var(--text-2xl);margin-top:var(--space-2);}
.dog-feature .visual{
  position:relative;
  min-height:clamp(280px, 60vh, 420px);
  overflow:hidden;
  background:linear-gradient(150deg, var(--navy-700), var(--ink-900));
}
.dog-feature .visual img{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  opacity:.85;
}

.dog-points{
  display:flex;flex-wrap:wrap;
  gap:clamp(8px, 1.4vh, 12px);
  margin:clamp(12px, 2.6vh, 24px) 0 0;
  padding:0;
}
.dog-points li{
  display:flex;gap:var(--space-2);align-items:center;
  font-size:var(--text-sm);
  font-weight:600;
  color:var(--white);
  background:rgba(255,255,255,.06);
  border:1px solid rgba(255,255,255,.14);
  border-radius:var(--radius-pill);
  padding:clamp(4px, 1.1vh, 8px) var(--space-4) clamp(4px, 1.1vh, 8px) var(--space-2);
  transition:background var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out);
}
.dog-points li:hover{
  background:rgba(215,38,56,.18);
  border-color:rgba(215,38,56,.45);
  transform:translateY(-2px);
}
.dog-points svg{
  flex:none;width:20px;height:20px;padding:4px;
  border-radius:50%;
  background:var(--accent-solid);
  color:var(--white);
}

.dog-cta{
  margin-top:clamp(12px, 2.6vh, 20px);
  padding-top:clamp(10px, 2vh, 16px);
  border-top:1px solid rgba(255,255,255,.12);
}
.dog-feature p.lead{color:var(--text-muted);font-size:var(--text-sm);margin:var(--space-2) 0 var(--space-1);}
.dog-feature .kicker{
  font-family:var(--font-display);
  font-weight:600;
  color:var(--white);
  font-size:var(--text-base);
  text-transform:uppercase;
  letter-spacing:var(--tracking-wide);
  margin:0;
}
.dog-feature .lead-tight{margin-bottom:clamp(12px, 2.6vh, 24px);}

/* ---------- coverage ---------- */
.coverage-grid{
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(32px, 5vw, 60px);
  align-items:center;
}
.coverage-grid p{color:var(--text-muted);margin-top:var(--space-4);}
/*  Outer wrap is the positioning context for the two floating stat pills
    (same overlap-the-corner idiom as .hero-visual/.hero-float), kept separate
    from the inner navy box so its own overflow:hidden — needed to clip the
    map artwork to the rounded corners — can't also clip the pills.          */
.coverage-map-wrap{
  position:relative;
  height:min(56vh, 440px);
  margin-inline:auto;
}
.coverage-map{
  height:100%;
  aspect-ratio:100/196;
  width:auto;
  position:relative;
  background:radial-gradient(ellipse at 50% 32%, var(--navy-600) 0%, var(--navy-900) 100%);
  border-radius:var(--radius-lg);
  display:flex;align-items:center;justify-content:center;
  overflow:hidden;
  box-shadow:var(--shadow-3), inset 0 0 0 1px rgba(255,255,255,.08);
}
/*  Same tactical-grid idiom as .map-facade-grid — ties the map to the site's
    established "ops display" language instead of a flat navy panel.        */
.coverage-map-grid{
  position:absolute;inset:0;z-index:0;
  background-image:
    linear-gradient(rgba(255,255,255,.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.07) 1px, transparent 1px);
  background-size:18px 18px;
  mask-image:radial-gradient(ellipse at 50% 35%, black 0%, transparent 80%);
  -webkit-mask-image:radial-gradient(ellipse at 50% 35%, black 0%, transparent 80%);
}
.coverage-map svg{position:relative;z-index:1;width:88%;height:88%;overflow:visible;}
/*  Bright, high-contrast outline rather than a near-invisible tint — this is
    the thing the previous pass got wrong: fill barely registered against the
    navy panel. The stroke, not the fill, is what has to carry the silhouette. */
.coverage-land{
  fill:rgba(255,255,255,.10);
  stroke:rgba(255,255,255,.85);
  stroke-width:1.5;
  stroke-linejoin:round;
}
.coverage-rings{fill:none;stroke:#ff6b7a;stroke-width:0.7;stroke-dasharray:2 3;}
.coverage-city title{pointer-events:none;}
.coverage-city circle{
  fill:#fff;
  stroke:var(--navy-900);
  stroke-width:0.6;
  filter:drop-shadow(0 0 2px rgba(0,0,0,.6));
  transition:fill var(--dur-fast) var(--ease-out), r var(--dur-fast) var(--ease-out);
}
.coverage-city:not(.coverage-hq):hover circle,
.coverage-city.is-active:not(.coverage-hq) circle{fill:#ff6b7a;r:3.2;}
.coverage-hq.is-active .coverage-hq-brackets{stroke-width:1.3;}
.coverage-label{
  font-family:var(--font-display);
  font-weight:700;
  letter-spacing:.03em;
  fill:#fff;
  paint-order:stroke;
  stroke:var(--navy-900);
  stroke-width:2.4;
  stroke-linejoin:round;
}
.coverage-hq-pulse{fill:none;stroke:#ff6b7a;stroke-width:1;opacity:.6;transform-origin:48.2px 115.1px;animation:coverageHqPulse 2.4s var(--ease-out) infinite;}
@keyframes coverageHqPulse{0%{r:3.6;opacity:.65;}100%{r:11;opacity:0;}}
.coverage-hq-dot{fill:#ff6b7a;stroke:var(--navy-900);stroke-width:0.6;}
.coverage-hq-brackets{fill:none;stroke:#ff6b7a;stroke-width:0.9;}
.coverage-hq-label-bg{fill:var(--navy-900);opacity:.82;}
.coverage-hq-label{fill:#fff;stroke:none;text-transform:uppercase;}
.coverage-float-top{top:calc(var(--space-4) * -1);left:calc(var(--space-4) * -1);}
.coverage-float-top svg{color:#d72638;}
.coverage-float-bottom{bottom:calc(var(--space-4) * -1);right:calc(var(--space-4) * -1);}
.coverage-float-bottom svg{color:#d72638;}
@media (max-width:640px){
  .coverage-float-top,.coverage-float-bottom{
    padding:var(--space-1) var(--space-3);
    font-size:11px;
  }
  .coverage-float-top{left:0;}
  .coverage-float-bottom{right:0;}
}
.coverage-list{display:flex;flex-wrap:wrap;gap:var(--space-2);margin:var(--space-4) 0 var(--space-5);}
.city-pill{
  cursor:pointer;
  transition:border-color var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out),
             box-shadow var(--dur-fast) var(--ease-out);
  font-family:var(--font-display);
  font-weight:500;
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  border:1px solid var(--border-strong);
  border-radius:var(--radius-pill);
  padding:var(--space-2) var(--space-4);
  color:var(--navy-800);
  background:var(--white);
}
.city-pill:hover,
.city-pill:focus-visible,
.city-pill.is-active{
  background:#d72638;
  border-color:#d72638;
  color:#fff;
  transform:translateY(-2px);
  box-shadow:var(--shadow-2);
}
.nationwide-note{
  display:flex;gap:var(--space-3);align-items:flex-start;
  background:var(--surface-sunken);
  border-left:3px solid var(--accent);
  border-radius:0 var(--radius-md) var(--radius-md) 0;
  padding:var(--space-3) var(--space-4);
  font-size:var(--text-xs);
  color:var(--text-subtle);
}
.nationwide-note svg{flex:none;width:18px;height:18px;margin-top:1px;color:var(--accent);}
/*  .coverage-grid p (line ~1942) is a descendant selector and reaches in
    here too, overriding the note's own --text-subtle with --text-muted:
    4.44:1 on --surface-sunken, just under AA. The note already sets the
    colour it wants on itself, so take it back.                          */
.nationwide-note p{margin:0;color:inherit;}
.nationwide-note strong{color:var(--navy-900);}

/* ---------- accreditations ---------- */
/*  Two lanes, opposite directions. Each lane is a genuine horizontal scroll
    container rather than a transform-animated track, because the brief asks for
    something the visitor can also grab and scroll: making scrollLeft the single
    source of truth means drag, wheel, trackpad, touch and arrow keys all work
    for free and cannot fight the animation, whereas a CSS keyframe marquee has
    to be torn down and re-derived the moment a finger lands on it.
    js/script.js clones the card set until the lane is at least twice its own
    width, then wraps scrollLeft modulo one set - so the loop is seamless in
    BOTH directions, which a one-way keyframe cannot do.                       */
.accred-marquee{
  display:flex;flex-direction:column;
  gap:clamp(var(--space-3), 2.2vh, var(--space-5));
  flex:1;min-height:0;
  justify-content:center;
  /*  Full-bleed out of .wrap so cards enter and leave at the true screen edge
      instead of appearing to pop in at a gutter line.                         */
  width:100vw;
  margin-left:calc(50% - 50vw);
  /*  The fade is what sells it as a continuous belt rather than a clipped row.
      Masked rather than covered by a gradient overlay so it works on the navy
      panel and the starfield behind it without having to match a colour.      */
  -webkit-mask-image:linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
          mask-image:linear-gradient(90deg, transparent 0, #000 7%, #000 93%, transparent 100%);
}

.accred-row{
  overflow-x:auto;overflow-y:hidden;
  /*  Auto-advance sets scrollLeft every frame; smooth scrolling inherited from
      html would queue an animation against each of those writes and stutter.  */
  scroll-behavior:auto;
  overscroll-behavior-x:contain;
  scrollbar-width:none;
  cursor:grab;
  padding:var(--space-2) 0;
}
.accred-row::-webkit-scrollbar{display:none;}
.accred-row:focus-visible{
  outline:3px solid var(--focus-ring);
  outline-offset:-3px;
  border-radius:var(--radius-md);
}
.accred-row.is-dragging{cursor:grabbing;user-select:none;}
/*  A drag that crosses a card must not end in a text selection or a ghost
    image of the logo being dragged out of the page.                           */
.accred-row.is-dragging img{pointer-events:none;}

.accred-track{
  display:flex;align-items:stretch;
  gap:clamp(var(--space-3), 1.6vw, var(--space-5));
  width:max-content;
  margin:0;padding:0 clamp(var(--space-3), 1.6vw, var(--space-5));
  list-style:none;
}

.accred-card{
  position:relative;
  /*  Fixed lane width: the cards must be a predictable size for the loop maths,
      and a uniform card is what makes a logo belt read as a set rather than as
      six differently-weighted marks. One lane rather than two frees the height
      for a card that can carry its description at a comfortable reading size
      instead of shrinking it to a caption.                                    */
  flex:0 0 clamp(268px, 25vw, 344px);
  display:flex;flex-direction:column;justify-content:flex-start;
  text-align:center;
  padding:clamp(var(--space-4), 2.2vh, var(--space-6));
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  background:var(--surface-raised);
  transition:border-color var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out);
}
.accred-card:hover{border-color:var(--accent);transform:translateY(-3px);box-shadow:var(--shadow-2);}
/*  Same reticle language as .why-item::after — verified accreditations get the
    "scanned and cleared" read, which fits the content better than a generic
    logo-tile hover.                                                          */
.accred-card::after{
  content:"";
  position:absolute;inset:var(--space-2);z-index:1;
  pointer-events:none;
  opacity:0;
  transition:opacity var(--dur-base) var(--ease-out);
  background:
    linear-gradient(var(--accent),var(--accent)) 0 0/10px 1px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 0 0/1px 10px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 100% 0/10px 1px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 100% 0/1px 10px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 0 100%/10px 1px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 0 100%/1px 10px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 100% 100%/10px 1px no-repeat,
    linear-gradient(var(--accent),var(--accent)) 100% 100%/1px 10px no-repeat;
}
.accred-card:hover::after{opacity:1;}
/*  Source logos are opaque 800x600 seals with a lot of built-in white
    margin around the mark, so a taller flex-centred white panel lets every
    logo scale to the same visible size regardless of its own margin.        */
.accred-img{
  display:flex;align-items:center;justify-content:center;
  /*  The source files are 800x600 seals carrying a lot of their own white
      margin, so the visible mark is always smaller than the box. A taller
      panel plus tighter padding is what actually makes the logo bigger -
      growing the card alone just adds more white around the same mark.       */
  height:clamp(116px, 17vh, 156px);
  margin-bottom:clamp(var(--space-3), 1.8vh, var(--space-4));
  padding:var(--space-2) var(--space-4);
  border-radius:var(--radius-md);
  background:var(--white);
}
.accred-img img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  /*  A dragged lane should move the lane, never detach a logo from it.        */
  -webkit-user-drag:none;user-select:none;}
.accred-card h3{font-size:var(--text-base);margin-bottom:var(--space-2);}
.accred-card p{
  font-size:var(--text-sm);
  line-height:var(--leading-normal);
  color:var(--text-muted);
  /*  Every card is the same width, so the only thing that can make the row
      look ragged is a description wrapping to a different number of lines.
      Balanced wrapping evens them out; browsers without it just wrap normally. */
  text-wrap:balance;
}

/*  Reduced motion stops the belt but keeps the lanes scrollable, so the content
    is still fully reachable by anyone who asked the OS to calm things down.   */
@media (prefers-reduced-motion:reduce){
  .accred-row{scroll-behavior:auto;}
}

/* ---------- threat level ---------- */
.threat-bar{display:grid;grid-template-columns:repeat(5,1fr);gap:clamp(6px, 1.2vh, 12px);margin-top:clamp(var(--space-4), 3.4vh, var(--space-8));}
.threat-tier{
  position:relative;
  display:flex;flex-direction:column;justify-content:center;
  padding:clamp(12px, 3vh, 26px) var(--space-3);
  text-align:center;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-bottom:4px solid transparent;
  border-radius:var(--radius-md);
}
.threat-tier .name{
  font-family:var(--font-display);
  font-size:clamp(14px, 2.2vh, 19px);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--white);
  font-weight:600;
}
.threat-tier .desc{font-size:var(--text-xs);color:var(--text-muted);margin-top:var(--space-1);display:block;min-width:0;overflow-wrap:break-word;}
.threat-tier.t-low{border-bottom-color:#3fa34d;}
.threat-tier.t-moderate{border-bottom-color:var(--amber-500);}
.threat-tier.t-substantial{border-bottom-color:var(--orange-500);}
.threat-tier.t-severe{border-bottom-color:var(--red-600);}
.threat-tier.t-critical{border-bottom-color:#7a0f22;}
.threat-tier.is-current{background:var(--accent-quiet);border-color:var(--accent);}
.threat-tier.is-current::before{
  content:"Current Level";
  position:absolute;top:-13px;left:50%;
  transform:translateX(-50%);
  background:var(--red-600);
  color:var(--white);
  border-radius:var(--radius-pill);
  font-family:var(--font-display);
  font-size:11px;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  padding:var(--space-1) var(--space-3);
  white-space:nowrap;
}
.threat-meta{
  display:flex;flex-wrap:wrap;gap:var(--space-6);
  margin-top:var(--space-4);
  font-size:var(--text-sm);
  color:var(--text-muted);
}
.threat-meta strong{color:var(--white);}
.threat-source{margin-top:var(--space-2);font-size:var(--text-xs);color:var(--text-subtle);}
.threat-source a{color:var(--accent);text-decoration:underline;text-underline-offset:2px;}

/* ---------- testimonials ---------- */
.testi-wrap{max-width:840px;margin:0 auto;text-align:center;position:relative;}
/*  The swipe handler only reads horizontal travel, so hand vertical panning
    straight back to the page - without this the browser has to wait to see
    which way a drag is going before it will scroll.                          */
#testiSlider{touch-action:pan-y;}
#testiSlider{
  position:relative;
  margin-top:clamp(24px, 5vh, 46px);
  padding:clamp(30px, 6vh, 60px) clamp(24px, 4vw, 56px) clamp(24px, 4.4vh, 44px);
  background:linear-gradient(160deg, rgba(255,255,255,.07), rgba(255,255,255,.02));
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-3);
}
#testiSlider::before{
  content:"\201C";
  position:absolute;left:50%;top:0;
  transform:translate(-50%, -44%);
  font-family:var(--font-brand);
  font-weight:800;
  font-size:clamp(64px, 11vh, 120px);
  line-height:1;
  color:var(--red-600);
  pointer-events:none;
}
.testi-slide{display:none;}
.testi-slide.active{display:block;animation:fade var(--dur-slower) var(--ease-out);}
@keyframes fade{from{opacity:0;transform:translateY(6px);}to{opacity:1;transform:none;}}
.testi-slide p.quote{
  font-family:var(--font-display);
  font-weight:500;
  font-size:clamp(20px, 4.2vh, 34px);
  color:var(--white);
  line-height:1.35;
  margin-bottom:var(--space-4);
}
.testi-slide .who{
  color:var(--accent);
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wider);
  text-transform:uppercase;
  margin:0;
}
.testi-nav{display:flex;justify-content:center;gap:var(--space-3);margin-top:var(--space-5);}
.testi-nav button{
  display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;
  background:transparent;
  color:var(--white);
  border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);
  cursor:pointer;
  transition:background var(--dur-base) var(--ease-out), border-color var(--dur-base) var(--ease-out);
}
.testi-nav button:hover{background:var(--red-600);border-color:var(--red-600);}
.testi-nav svg{width:16px;height:16px;}
/*  The visible dot stays 10px; the button around it is a full 44px target.
    Dots are generated in JS with no inner markup, so the dot is a ::before.   */
.testi-dots{display:flex;justify-content:center;gap:0;margin-top:var(--space-6);}
.testi-dots button{
  display:flex;align-items:center;justify-content:center;
  width:44px;height:44px;padding:0;
  border:none;border-radius:var(--radius-pill);
  background:none;
  cursor:pointer;
}
.testi-dots button::before{
  content:"";
  width:10px;height:10px;
  border-radius:var(--radius-pill);
  background:rgba(255,255,255,.28);
  transition:background var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
}
.testi-dots button:hover::before{background:rgba(255,255,255,.6);transform:scale(1.25);}
.testi-dots button.active::before{background:var(--accent);transform:scale(1.15);}

/* ---------- FAQ ---------- */
.faq-list{display:grid;gap:1px;background:var(--border);border-top:2px solid var(--accent);}
.faq-item{background:var(--white);}
.faq-q{
  width:100%;
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--space-5);
  padding:clamp(10px, 2vh, 16px) var(--space-5);
  background:none;border:none;
  cursor:pointer;text-align:left;
  font-family:var(--font-display);
  font-size:var(--text-base);
  letter-spacing:var(--tracking-tight);
  text-transform:uppercase;
  color:var(--navy-800);
  font-weight:600;
  transition:color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}
.faq-q:hover{color:var(--red-600);background:var(--slate-100);}
.faq-q .sign{
  display:flex;align-items:center;justify-content:center;
  flex:none;
  width:28px;height:28px;
  border:2px solid var(--red-600);
  border-radius:var(--radius-sm);
  color:var(--red-600);
  font-size:16px;line-height:1;
  transition:transform var(--dur-base) var(--ease-out),
             background var(--dur-base) var(--ease-out),
             color var(--dur-base) var(--ease-out);
}
.faq-q[aria-expanded="true"] .sign{background:var(--red-600);color:var(--white);transform:rotate(45deg);}
.faq-q[aria-expanded="true"]{color:var(--red-600);}

/*  Was a display:none/block flip, so the panel had no motion at all. The
    0fr -> 1fr grid row animates to the content's real height without needing a
    measured pixel value or any JS change - the .is-open class still drives it.
    visibility keeps the closed panel out of the accessibility tree.           */
.faq-a{
  display:grid;
  grid-template-rows:0fr;
  visibility:hidden;
  /*  Vertical padding lives on the animating container, not the child: padding
      inside a collapsed row still renders, which left a 24px gap when closed. */
  padding:0 var(--space-6);
  color:var(--text-subtle);
  font-size:var(--text-base);
  max-width:80ch;
  transition:grid-template-rows var(--dur-slow) var(--ease-out),
             padding-bottom var(--dur-slow) var(--ease-out),
             visibility 0s linear var(--dur-slow);
}
.faq-a > *{overflow:hidden;min-height:0;margin:0;padding:0;}
.faq-a.is-open{
  grid-template-rows:1fr;
  padding-bottom:clamp(12px, 2.4vh, 24px);
  visibility:visible;
  transition:grid-template-rows var(--dur-slow) var(--ease-out),
             padding-bottom var(--dur-slow) var(--ease-out),
             visibility 0s linear 0s;
}
@media (prefers-reduced-motion:reduce){
  .faq-a{transition:none;}
}

/* ---------- forms ---------- */
.quote-section{
  background:linear-gradient(180deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color:var(--text);
  position:relative;z-index:0;
}
.quote-grid{display:grid;grid-template-columns:.8fr 1.2fr;gap:clamp(24px, 4vw, 48px);align-items:center;}
/*  Grid items default to min-width:auto too - same fix as .contact-item > div
    above, needed here because .info's own email/phone rows can't shrink past
    their unbroken text without it, which was pushing the whole grid (and the
    page) wider than the viewport on narrow phones.                          */
.quote-grid > *{min-width:0;}
.quote-grid .info p{color:var(--text-muted);font-size:var(--text-sm);margin-top:var(--space-2);}

.info-line{display:flex;gap:var(--space-3);margin-top:var(--space-3);align-items:flex-start;}
.info-line > div{min-width:0;}
.info-line svg{width:18px;height:18px;color:var(--accent);flex:none;margin-top:2px;}
.info-line .label{
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wider);
  text-transform:uppercase;
  color:var(--text-subtle);
}
.info-line .value{font-size:var(--text-sm);font-weight:600;}

form.quote-form{
  display:grid;grid-template-columns:1fr 1fr;gap:clamp(var(--space-2), 1.3vh, var(--space-3));
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  padding:clamp(12px, 2.6vh, 24px);
}
form.quote-form .full{grid-column:1/-1;}
form.quote-form label,
form.auth-form label{
  display:block;
  font-size:var(--text-xs);
  /*  Body line-height on a one-line uppercase label was adding 8px per field,
      which is 56px across the quote form - the difference between the panel
      fitting one screen and not.                                            */
  line-height:1.25;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:#aab2bc;
  margin-bottom:var(--space-1);
}
form.quote-form input,
form.quote-form select,
form.quote-form textarea,
form.auth-form input{
  width:100%;
  min-height:clamp(34px, 5.7vh, 38px);
  background:rgba(255,255,255,.06);
  border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);
  color:var(--white);
  padding:var(--space-2) var(--space-3);
  font-family:var(--font-body);
  font-size:var(--text-sm);
  transition:border-color var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}
form.quote-form input::placeholder,
form.quote-form textarea::placeholder,
form.auth-form input::placeholder{color:#8a98a8;}
form.quote-form input:hover,
form.quote-form select:hover,
form.quote-form textarea:hover,
form.auth-form input:hover{border-color:rgba(255,255,255,.36);}
/*  Deliberately does NOT set outline:none — that was overriding the global
    :focus-visible ring and left keyboard users with only a border tint.       */
form.quote-form input:focus,
form.quote-form select:focus,
form.quote-form textarea:focus,
form.auth-form input:focus{
  border-color:var(--accent);
  background:rgba(255,255,255,.10);
}
form.quote-form textarea{resize:vertical;min-height:clamp(40px, 6.4vh, 72px);}
form.quote-form input:disabled,
form.quote-form select:disabled,
form.quote-form textarea:disabled,
form.auth-form input:disabled{
  opacity:.55;cursor:not-allowed;background:rgba(255,255,255,.03);
}
/*  A completed field reads as settled rather than still-empty.                */
form.quote-form input:not(:placeholder-shown):not([type=file]),
form.auth-form input:not(:placeholder-shown){border-color:rgba(255,255,255,.30);}
form.quote-form .btn,
form.auth-form .btn{margin-top:var(--space-1);width:100%;}

form.quote-form select{
  appearance:none;-webkit-appearance:none;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns=%27http://www.w3.org/2000/svg%27 viewBox=%270 0 24 24%27 fill=%27none%27 stroke=%27%238a98a8%27 stroke-width=%272%27%3E%3Cpath d=%27m6 9 6 6 6-6%27/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:right var(--space-3) center;
  background-size:16px;
  padding-right:var(--space-10);
}
form.quote-form select option{background:var(--navy-800);color:var(--white);}
form.quote-form input[type="file"]{padding:var(--space-2) var(--space-3);font-size:var(--text-sm);cursor:pointer;}
form.quote-form input[type="date"]::-webkit-calendar-picker-indicator{filter:invert(1);opacity:.6;cursor:pointer;}

/* ---------- form controls on touch / narrow viewports ----------
   The compact 34-38px field above exists so the ten-field quote form fits one
   deck panel on a desktop screen. Neither reason survives a phone: the deck is
   off below 1024px, and the compact sizing costs two things there.

   1. iOS Safari zooms the whole page in whenever a focused control's text is
      under 16px, and it does not zoom back out on blur - the visitor is left
      dragging a magnified page sideways for the rest of the form. 16px is the
      threshold, not a preference, so the value is literal rather than a token
      (--text-sm tops out at 15px).
   2. 38px is below the 44px minimum target both WCAG 2.5.8 and the iOS HIG
      ask for, and these are the controls the whole site funnels people into.

   (hover:none) carries the same fix onto a touch tablet wider than 1024px.  */
@media (max-width:1024px), (hover:none){
  form.quote-form input,
  form.quote-form select,
  form.quote-form textarea,
  form.auth-form input{
    font-size:16px;
    min-height:44px;
    padding:var(--space-3);
  }
  form.quote-form textarea{min-height:96px;}
  form.quote-form input[type="file"]{font-size:16px;}
  /*  The native date control renders its own text and honours the same rule. */
  form.quote-form input[type="date"]{min-height:44px;}
}

.field-error{
  display:block;
  margin-top:var(--space-2);
  font-size:var(--text-sm);
  color:var(--error);
  font-family:var(--font-body);
  letter-spacing:0;
  text-transform:none;
}
.has-error input,.has-error select,.has-error textarea{
  border-color:var(--error);
  background:var(--error-quiet);
}
.hp-field{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;}

.form-status{
  grid-column:1/-1;
  display:none;
  padding:var(--space-4) var(--space-5);
  border-left:3px solid transparent;
  border-radius:0 var(--radius-md) var(--radius-md) 0;
  font-size:var(--text-sm);
  margin:0;
}
.form-status.is-visible{display:block;}
.form-status.is-error{background:var(--error-quiet);border-left-color:var(--error);color:#ffd9de;}
.form-status.is-success{background:var(--success-quiet);border-left-color:var(--success);color:#d6f5db;}
.form-status.is-pending{background:rgba(255,255,255,.06);border-left-color:var(--text-subtle);color:var(--text-muted);}

/* ---------- contact ---------- */
.contact-section-grid{display:grid;grid-template-columns:.9fr 1.1fr;gap:clamp(24px, 4vw, 48px);align-items:center;}
.contact-section-grid > *{min-width:0;}
.contact-detail{padding:var(--space-3) 0;border-bottom:1px solid var(--border);}
.contact-detail:last-child{border-bottom:none;}
.contact-detail .label{
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wider);
  text-transform:uppercase;
  color:var(--text-muted);
  margin-bottom:var(--space-1);
}
.contact-detail .value{font-size:var(--text-base);font-weight:600;color:var(--navy-800);}
.map-block{
  background:var(--surface-sunken);
  min-height:clamp(220px, 46vh, 340px);
  height:clamp(220px, 46vh, 340px);
  border:1px solid var(--border-strong);
  border-radius:var(--radius-lg);
  overflow:hidden;
  position:relative;
}
.map-block iframe{width:100%;height:100%;min-height:220px;border:0;display:block;}

/*  Stands in for the Google Maps embed until somebody asks for it - the embed
    is the better part of a megabyte of third-party script, plus Google
    cookies, for a pin the column beside it already gives in text and links.  */
.map-facade{
  position:relative;
  width:100%;height:100%;
  display:flex;align-items:center;justify-content:center;
  background:linear-gradient(150deg, var(--navy-700), var(--navy-900));
  overflow:hidden;
}
.map-facade-grid{
  position:absolute;inset:0;
  background-image:
    linear-gradient(rgba(255,255,255,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.055) 1px, transparent 1px);
  background-size:34px 34px;
  mask-image:radial-gradient(ellipse at 50% 45%, black 0%, transparent 78%);
  -webkit-mask-image:radial-gradient(ellipse at 50% 45%, black 0%, transparent 78%);
}
.map-facade-body{position:relative;z-index:1;text-align:center;padding:var(--space-5);max-width:36ch;}
.map-pin{
  display:inline-flex;align-items:center;justify-content:center;
  width:42px;height:42px;
  margin-bottom:var(--space-3);
  border-radius:var(--radius-pill);
  background:var(--red-600);
  color:var(--white);
  box-shadow:0 10px 26px rgba(215,38,56,.36);
}
.map-pin svg{width:22px;height:22px;}
.map-facade-title{
  margin:0;
  font-family:var(--font-display);
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--white);
}
.map-facade-sub{margin:var(--space-1) 0 var(--space-4);font-size:var(--text-sm);color:#c3ccd8;}
/*  #contact is a light section, so the shared .btn-outline resolves to dark
    text here - restated for the dark panel it actually sits on.             */
.map-facade .btn-outline{
  color:var(--white);
  border-color:rgba(255,255,255,.42);
  padding:var(--space-2) var(--space-5);
  min-height:40px;
}
/*  40px is fine under a mouse; touch gets the full target - this is the
    control that loads the map.                                              */
@media (max-width:1024px), (hover:none){
  .map-facade .btn-outline{min-height:44px;}
}
.map-facade .btn-outline:hover{border-color:var(--white);background:rgba(255,255,255,.10);}
.map-facade-note{margin:var(--space-3) 0 0;font-size:var(--text-xs);color:#98a4b3;}
.maps-link{
  display:inline-flex;align-items:center;gap:var(--space-2);
  min-height:44px;
  margin-top:var(--space-2);
  font-family:var(--font-display);
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--red-600);
  font-weight:600;
}
.maps-link:hover{color:var(--red-800);}
.maps-link svg{width:16px;height:16px;}

/* ---------- footer ---------- */
footer{
  background:var(--ink-900);
  color:var(--text-muted);
  padding:clamp(20px, 3.5vh, 80px) 0 0;
  position:relative;z-index:0;
}
.footer-grid{
  display:grid;grid-template-columns:1.3fr 1fr 1fr 1fr;
  gap:clamp(24px, 4vw, 40px);
  padding-bottom:clamp(16px, 3.5vh, 64px);
  border-bottom:1px solid var(--border);
}
.footer-grid h3{
  color:var(--white);
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-wide);
  margin-bottom:clamp(10px, 1.8vh, 20px);
}
.footer-grid ul li{margin-bottom:clamp(0px, .5vh, 12px);font-size:var(--text-sm);}
.footer-grid ul li a{
  display:inline-flex;align-items:center;
  padding:var(--space-1) 0;
  transition:color var(--dur-base) var(--ease-out);
}
/*  The footer is the densest stack of links on the site - 22 of them, and at
    the mobile type scale each row came out 31px tall, close enough to its
    neighbours to mis-tap. Touch viewports get the full 44px row; the
    pointer-only rule below keeps the desktop footer compact.                 */
@media (max-width:1024px), (hover:none){
  .footer-grid ul li{margin-bottom:0;}
  .footer-grid ul li a{min-height:44px;}
}
.footer-grid ul li a:hover{color:var(--accent);text-decoration:underline;text-underline-offset:3px;}
/*  On the deck the closing band has to clear 100svh minus the sticky header,
    and at the narrow end of that range the four footer columns wrap enough
    extra lines to miss it. Pointer-only widths, so the tap target this trims
    is one the touch layout never sees.                                       */
@media (min-width:1201px){
  .footer-grid ul li a{padding:2px 0;}
}
.footer-brand .logo-image{height:52px;}
.footer-brand p{font-size:var(--text-sm);color:var(--text-subtle);margin-top:var(--space-4);max-width:34ch;}
.bottom-footer{
  display:flex;flex-wrap:wrap;justify-content:space-between;
  gap:var(--space-3);
  padding:clamp(10px, 1.6vh, 24px) 0;
  font-size:var(--text-sm);
  color:var(--text-subtle);
}
.bottom-footer a:hover{color:var(--white);}

/* ==========================================================================
   8. INNER PAGES
   ========================================================================== */

/* ---------- page hero ---------- */
/*  Pulled up behind the header the same way .hero.screen is (see that rule
    for the full reasoning) - its own top padding grows by --header-h to
    match, so the transparent header shows this section's own background
    instead of a fixed colour that would drift from it on other pages.       */
.page-hero{
  position:relative;z-index:0;overflow:hidden;
  margin-top:calc(-1 * var(--header-h));
  padding:calc(var(--header-h) + clamp(48px, 6vw, 74px)) 0 clamp(40px, 5vw, 62px);
  background:
    radial-gradient(ellipse at 15% 0%, rgba(215,38,56,.16), transparent 55%),
    linear-gradient(180deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color:var(--text);
}
.page-hero::before{
  content:"";position:absolute;inset:0;
  background-image:
    linear-gradient(rgba(255,255,255,.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.035) 1px, transparent 1px);
  background-size:64px 64px;
  mask-image:radial-gradient(ellipse at 50% 0%, black 0%, transparent 80%);
  -webkit-mask-image:radial-gradient(ellipse at 50% 0%, black 0%, transparent 80%);
}
.page-hero .wrap{position:relative;z-index:2;}
.page-hero h1{font-size:var(--text-4xl);margin-top:var(--space-4);text-shadow:0 2px 20px rgba(0,0,0,.35);}
.page-hero p{color:var(--text-muted);font-size:var(--text-base);margin-top:var(--space-4);max-width:70ch;}

.breadcrumb{margin-top:var(--space-5);font-size:var(--text-sm);color:var(--text-subtle);}
.breadcrumb ol{display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center;}
.breadcrumb li{display:flex;gap:var(--space-2);align-items:center;}
.breadcrumb a{display:inline-flex;align-items:center;}
.breadcrumb a:hover{color:var(--accent);}
/*  The crumb trail is the only way back up a service page on a phone, and its
    links were 23px tall in a row of similarly small text.                    */
@media (max-width:1024px), (hover:none){
  .breadcrumb a{min-height:44px;}
}
.breadcrumb [aria-current]{color:var(--white);}
.breadcrumb .sep{opacity:.5;}

/* ---------- prose / legal ---------- */
.prose{max-width:78ch;}
.prose h2{font-size:var(--text-2xl);margin:var(--space-12) 0 var(--space-4);scroll-margin-top:calc(var(--header-h) + var(--space-6));}
.prose h2:first-child{margin-top:0;}
.prose h3{font-size:var(--text-lg);margin:var(--space-8) 0 var(--space-3);}
.prose p{color:var(--text-subtle);margin:0 0 var(--space-4);font-size:var(--text-base);}
.prose ul{margin:0 0 var(--space-5);display:grid;gap:var(--space-3);}
.prose ul li{position:relative;padding-left:var(--space-6);color:var(--text-subtle);font-size:var(--text-base);}
.prose ul li::before{content:"";position:absolute;left:0;top:9px;width:8px;height:8px;background:var(--accent);}
.prose a{color:var(--red-600);text-decoration:underline;text-underline-offset:2px;}
.prose strong{color:var(--navy-800);}
.prose table{width:100%;border-collapse:collapse;margin:0 0 var(--space-6);font-size:var(--text-sm);}
.prose th,.prose td{text-align:left;padding:var(--space-3) var(--space-4);border:1px solid var(--border);vertical-align:top;}
.prose th{
  background:var(--surface-sunken);
  font-family:var(--font-display);
  font-size:var(--text-xs);
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  color:var(--navy-800);
}
/*  The scroller only works if it is allowed to be narrower than the table it
    holds. Its grid-item ancestor defaults to min-width:auto = the table's
    min-content (356px), which on a 320px phone widened the whole document and
    put the entire cookie policy into sideways scroll.                        */
.table-scroll{
  overflow-x:auto;
  max-width:100%;
}
.table-scroll table{min-width:420px;}
.prose .updated{
  font-family:var(--font-display);
  font-weight:500;
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-wider);
  text-transform:uppercase;
  color:var(--text-muted);
  border-left:3px solid var(--accent);
  padding-left:var(--space-4);
  margin-bottom:var(--space-8);
}
.legal-layout{display:grid;grid-template-columns:260px 1fr;gap:var(--space-12);align-items:start;}
.legal-layout > *{min-width:0;}
.legal-toc{
  position:sticky;top:calc(var(--header-h) + var(--space-6));
  border-left:2px solid var(--border);
  padding-left:var(--space-5);
}
.legal-toc h2{font-size:var(--text-xs);letter-spacing:var(--tracking-wider);color:var(--text-muted);margin-bottom:var(--space-4);}
.legal-toc a{
  display:flex;align-items:center;
  min-height:44px;
  font-size:var(--text-sm);
  color:var(--text-subtle);
  transition:color var(--dur-base) var(--ease-out);
}
.legal-toc a:hover{color:var(--red-600);}

/* ---------- service detail ---------- */
/*  #main is a unique landmark per document, so this counter only ever
    numbers the cards on the services page — harmless elsewhere.            */
#main{counter-reset:svc;}

.svc-detail{
  counter-increment:svc;
  display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(32px, 5vw, 64px);
  align-items:center;
  padding:clamp(28px, 4vw, 48px);
  margin-bottom:clamp(24px, 3.5vw, 36px);
  background:var(--surface-alt);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  scroll-margin-top:calc(var(--header-h) + var(--space-4));
  transition:border-color var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out);
}
.svc-detail:hover{border-color:var(--border-strong);box-shadow:var(--shadow-2);}
.svc-detail:last-of-type{margin-bottom:0;}
.svc-detail.flip .svc-media{order:1;}
.svc-media{
  position:relative;
  aspect-ratio:4/3;
  overflow:hidden;
  border-radius:var(--radius-md);
  background:var(--navy-800);
  box-shadow:var(--shadow-2);
}
.svc-media img{
  width:100%;height:100%;object-fit:cover;
  transition:transform var(--dur-slower) var(--ease-out);
}
.svc-detail:hover .svc-media img{transform:scale(1.05);}
.svc-media::after{
  content:"";
  position:absolute;inset:0;z-index:1;
  background:linear-gradient(180deg, rgba(5,23,43,0) 60%, rgba(5,23,43,.5) 100%);
  pointer-events:none;
}
.svc-media::before{
  content:"0" counter(svc);
  position:absolute;top:var(--space-4);left:var(--space-4);z-index:3;
  font-family:var(--font-display);
  font-size:var(--text-sm);
  font-weight:600;
  letter-spacing:var(--tracking-wider);
  line-height:1;
  color:var(--white);
  background:var(--red-600);
  padding:var(--space-2) var(--space-3);
  border-radius:var(--radius-sm);
  box-shadow:var(--shadow-2);
}
.svc-detail h2{font-size:var(--text-2xl);margin-top:var(--space-3);}
.svc-lede{color:var(--text-subtle);font-size:var(--text-lg);}
.svc-copy > p{color:var(--text-muted);font-size:var(--text-base);margin:var(--space-4) 0;}
.svc-points{display:grid;gap:var(--space-3);margin:var(--space-5) 0 var(--space-8);}
.svc-points li{
  position:relative;
  display:flex;gap:var(--space-3);align-items:flex-start;
  font-size:var(--text-base);color:var(--text-subtle);
}
.svc-points li::before{
  content:"";
  width:18px;height:18px;flex:none;margin-top:1px;
  border-radius:var(--radius-pill);
  background:var(--accent-quiet);
  box-shadow:inset 0 0 0 1.5px var(--accent);
}
.svc-points li::after{
  content:"";
  position:absolute;left:4px;top:7px;
  width:8px;height:4px;
  border-left:2px solid var(--accent);
  border-bottom:2px solid var(--accent);
  transform:rotate(-45deg);
}
.svc-cta{display:flex;gap:var(--space-4);flex-wrap:wrap;margin-top:var(--space-2);}

.svc-index{
  display:grid;grid-template-columns:repeat(3,1fr);
  gap:var(--space-3);
  margin-top:var(--space-12);
}
.svc-index a{
  display:flex;align-items:center;gap:var(--space-3);
  background:var(--surface);
  border:1px solid var(--border);
  padding:var(--space-4) var(--space-5);
  border-radius:var(--radius-md);
  font-family:var(--font-display);
  font-size:var(--text-sm);
  letter-spacing:var(--tracking-tight);
  text-transform:uppercase;
  color:var(--navy-800);
  transition:background var(--dur-base) var(--ease-out),
             color var(--dur-base) var(--ease-out),
             border-color var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out);
}
.svc-index a::before{
  content:"";width:8px;height:8px;flex:none;
  border-radius:var(--radius-pill);
  background:var(--red-600);
  transition:background var(--dur-base) var(--ease-out);
}
.svc-index a:hover{
  background:var(--navy-800);color:var(--white);
  border-color:var(--navy-800);
  transform:translateY(-2px);
  box-shadow:var(--shadow-2);
}
.svc-index a:hover::before{background:var(--white);}

/* ---------- CTA strip ---------- */
.cta-strip{
  position:relative;z-index:0;overflow:hidden;
  padding:var(--space-16) 0;
  background:linear-gradient(120deg, var(--navy-800) 0%, var(--navy-600) 100%);
  color:var(--text);
}
.cta-strip::before{
  content:"";position:absolute;inset:0;
  background-image:linear-gradient(90deg, rgba(255,255,255,.04) 1px, transparent 1px);
  background-size:48px 48px;
}
.cta-strip .wrap{
  position:relative;z-index:2;
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--space-8);flex-wrap:wrap;
}
.cta-strip h2{font-size:var(--text-2xl);}
.cta-strip p{color:#c3ccd8;margin:var(--space-3) 0 0;max-width:60ch;}
.cta-strip .btns{display:flex;gap:var(--space-4);flex-wrap:wrap;}

/* ---------- 404 ---------- */
/*  Pulled up behind the header the same way .hero.screen is (see that rule
    for the full reasoning) - its own top padding grows by --header-h to
    match, so the transparent header shows this section's own background
    instead of a fixed colour that would drift from it on other pages.       */
.error-page{
  min-height:60vh;
  display:flex;align-items:center;justify-content:center;
  text-align:center;
  margin-top:calc(-1 * var(--header-h));
  padding:calc(var(--header-h) + var(--space-24)) 0 var(--space-24);
  background:linear-gradient(180deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color:var(--text);
  position:relative;z-index:0;
}
.error-code{
  position:relative;
  display:inline-block;
  padding:0 .25em;
  font-family:var(--font-display);
  font-size:clamp(72px, 16vw, 170px);
  line-height:1;
  font-weight:700;
  color:transparent;
  -webkit-text-stroke:2px var(--accent);
  letter-spacing:.04em;
}
/*  Reticle frame reused from .why-item/.accred-card (search "reticle" in this
    file) — always on here rather than a hover reveal, since a 404 is a static
    read: it frames the numeral like a target the site failed to lock onto.   */
.error-code::after{
  content:"";
  position:absolute;inset:-.1em -.05em;
  pointer-events:none;
  background:
    linear-gradient(var(--accent),var(--accent)) top left / 20px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top left / 2px 20px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top right / 20px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top right / 2px 20px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom left / 20px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom left / 2px 20px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom right / 20px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom right / 2px 20px no-repeat;
  opacity:.55;
}
.error-page h1{font-size:var(--text-3xl);margin:var(--space-5) 0 var(--space-4);}
.error-page p{color:var(--text-muted);max-width:52ch;margin:0 auto var(--space-8);}
.error-actions{display:flex;gap:var(--space-4);justify-content:center;flex-wrap:wrap;}

/* ---------- auth pages ---------- */
/*  Pulled up behind the header the same way .hero.screen is (see that rule
    for the full reasoning). It has no padding of its own - the generic
    `section{padding:var(--section-y) 0}` rule supplies both sides normally -
    so padding-top is stated explicitly here to add --header-h on top of that
    same value rather than replacing it.                                     */
.auth-section{
  margin-top:calc(-1 * var(--header-h));
  padding-top:calc(var(--header-h) + var(--section-y));
  background:linear-gradient(180deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color:var(--text);
  position:relative;z-index:0;
}
.auth-wrap{max-width:460px;margin:0 auto;padding:0 var(--gutter);}
.auth-card{
  position:relative;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  padding:var(--space-10) var(--space-8);
  box-shadow:var(--shadow-3);
}
/*  Same reticle language as .why-item/.accred-card, always on rather than a
    hover reveal — a login card is the one place "this is a secured checkpoint"
    is the literal content, not just a brand flourish.                       */
.auth-card::after{
  content:"";
  position:absolute;inset:var(--space-3);
  pointer-events:none;
  background:
    linear-gradient(var(--accent),var(--accent)) top left / 18px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top left / 2px 18px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top right / 18px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) top right / 2px 18px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom left / 18px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom left / 2px 18px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom right / 18px 2px no-repeat,
    linear-gradient(var(--accent),var(--accent)) bottom right / 2px 18px no-repeat;
  opacity:.5;
}
.auth-card .eyebrow{justify-content:center;}
.auth-card h1{font-size:var(--text-2xl);margin-top:var(--space-4);text-align:center;}
.auth-card > p.auth-intro{color:var(--text-muted);font-size:var(--text-sm);margin-top:var(--space-3);text-align:center;}
form.auth-form{display:grid;gap:var(--space-4);margin-top:var(--space-8);}
.auth-links{
  margin-top:var(--space-5);
  text-align:center;
  font-size:var(--text-sm);
  color:var(--text-muted);
  display:flex;flex-direction:column;gap:var(--space-3);
}
.auth-links a{
  /*  "Forgotten your password?" is the second most-used control on this page;
      as a bare 23px line of text it was the hardest thing here to hit.       */
  display:inline-flex;align-items:center;justify-content:center;align-self:center;
  min-height:44px;
  color:var(--white);text-decoration:underline;text-underline-offset:3px;
}
.auth-links a:hover{color:var(--accent);}
.auth-panel{text-align:center;}
.auth-panel .icon{
  display:flex;align-items:center;justify-content:center;
  width:56px;height:56px;
  margin:0 auto var(--space-5);
  border-radius:var(--radius-pill);
  background:var(--accent-quiet);
  color:var(--accent);
}
.auth-panel .icon.is-success{background:var(--success-quiet);color:var(--success);}
.auth-panel .icon svg{width:26px;height:26px;}
.auth-panel h2{font-size:var(--text-xl);margin-top:0;}
.auth-panel p{color:var(--text-muted);font-size:var(--text-sm);margin-top:var(--space-3);}
.auth-panel .btn{margin-top:var(--space-5);}
/*  The resend form sits inside a centred panel, but a label above its field
    has to sit over the left edge of that field to read as belonging to it.   */
.auth-panel .resend-form{text-align:left;}
/* ---------------------------------------------------------- 8f. dashboard */
/*  account.html. Same dark checkpoint context as the auth pages, but laid out
    as a working surface rather than a single centred card: the wrap is wider,
    the card becomes three panels, and nothing is centred because this page is
    read line by line rather than looked at.                                  */
.dash-section{
  /*  Mirrors .auth-section: pull up under the fixed header, then add its
      height back as padding so the first line clears it.                    */
  margin-top:calc(-1 * var(--header-h));
  padding-top:calc(var(--header-h) + var(--section-y-tight));
  background:linear-gradient(180deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color:var(--text);
  position:relative;z-index:0;
}
.dash-wrap{max-width:920px;margin:0 auto;padding:0 var(--gutter);}
.dash-boot{
  color:var(--text-muted);font-size:var(--text-sm);
  text-align:center;padding:var(--space-16) 0;
}
.dash{display:grid;gap:var(--space-5);}

.dash-head{
  display:flex;flex-wrap:wrap;gap:var(--space-5);
  align-items:flex-end;justify-content:space-between;
}
.dash-head-text{min-width:0;}
.dash-head h1{font-size:var(--text-2xl);margin-top:var(--space-3);}
.dash-head-sub{
  margin-top:var(--space-2);
  color:var(--text-muted);font-size:var(--text-sm);
  overflow-wrap:anywhere;
}
.dash-head-actions{display:flex;flex-wrap:wrap;gap:var(--space-3);}

.dash-stats{
  display:grid;grid-template-columns:repeat(3, 1fr);gap:var(--space-4);
  list-style:none;margin:0;padding:0;
}
.dash-stat{
  display:grid;gap:var(--space-2);align-content:start;
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  padding:var(--space-5);
}
.dash-stat-value{
  font-family:var(--font-display);font-size:var(--text-2xl);
  line-height:1;color:var(--white);
}
.dash-stat-label{
  font-size:var(--text-xs);text-transform:uppercase;
  letter-spacing:var(--tracking-wide);color:var(--text-subtle);
}

.dash-panel{
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  padding:var(--space-6);
}
.dash-panel h2{font-size:var(--text-lg);}
.dash-panel-head{
  display:flex;flex-wrap:wrap;gap:var(--space-3);
  align-items:center;justify-content:space-between;
  margin-bottom:var(--space-5);
}
.dash-panel-head h2{margin:0;}

.dash-filters{display:flex;gap:var(--space-2);flex-wrap:wrap;}
.dash-filter{
  appearance:none;cursor:pointer;
  min-height:40px;padding:0 var(--space-4);
  background:transparent;color:var(--text-muted);
  border:1px solid var(--border-strong);border-radius:var(--radius-pill);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
  transition:color var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out);
}
.dash-filter:hover{color:var(--white);border-color:var(--white);}
.dash-filter.is-active{background:var(--white);color:var(--navy-800);border-color:var(--white);}

.dash-list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3);}
.dash-item{
  background:var(--surface-sunken);
  border:1px solid var(--border);
  border-radius:var(--radius-md);
  overflow:hidden;
}
.dash-item-head{
  width:100%;min-height:60px;
  display:flex;align-items:center;gap:var(--space-4);
  padding:var(--space-4);
  background:transparent;border:0;color:inherit;
  font-family:var(--font-body);text-align:left;cursor:pointer;
  transition:background var(--dur-fast) var(--ease-out);
}
.dash-item-head:hover{background:rgba(255,255,255,.05);}
.dash-item-main{display:grid;gap:4px;flex:1;min-width:0;}
.dash-item-title{
  color:var(--white);font-weight:600;font-size:var(--text-base);
  overflow-wrap:anywhere;
}
.dash-item-meta{color:var(--text-subtle);font-size:var(--text-xs);overflow-wrap:anywhere;}
.dash-item-chevron{
  flex:none;display:flex;color:var(--text-subtle);
  transition:transform var(--dur-base) var(--ease-out);
}
.dash-item-chevron svg{width:18px;height:18px;}
.dash-item.is-open .dash-item-chevron{transform:rotate(180deg);}
.dash-item-body{
  padding:var(--space-4);
  border-top:1px solid var(--border);
}

/*  Status is set by the team as an enquiry moves; the colours are the same
    three the forms already use for pending / working / done.                */
.dash-status{
  flex:none;
  padding:5px var(--space-3);
  border:1px solid currentColor;border-radius:var(--radius-pill);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
  white-space:nowrap;
}
.dash-status.is-new{color:var(--text-muted);}
.dash-status.is-in_progress{color:var(--amber-500);}
.dash-status.is-closed{color:var(--success);}

.dash-fields,.dash-details{display:grid;gap:var(--space-3);margin:0;}
.dash-fields > div,.dash-details > div{
  display:grid;grid-template-columns:minmax(110px, 170px) 1fr;gap:var(--space-4);
}
.dash-fields dt,.dash-details dt{
  color:var(--text-subtle);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.dash-fields dd,.dash-details dd{
  margin:0;color:var(--text-muted);font-size:var(--text-sm);
  overflow-wrap:anywhere;
}
.dash-details dd{color:var(--white);}
.dash-details a{
  color:var(--white);text-decoration:underline;text-underline-offset:3px;
  display:inline-flex;align-items:center;min-height:44px;
}
.dash-details a:hover{color:var(--accent);}

.dash-state{color:var(--text-muted);font-size:var(--text-sm);}
.dash-state.is-error{color:var(--error);}
.dash-foot{margin-top:var(--space-4);color:var(--text-subtle);font-size:var(--text-xs);}

@media (max-width:760px){
  .dash-head{align-items:flex-start;}
  .dash-head-actions{width:100%;}
  .dash-head-actions .btn{flex:1 1 auto;}
  .dash-stats{grid-template-columns:1fr;gap:var(--space-3);}
  .dash-stat{
    grid-template-columns:1fr auto;align-items:center;
    padding:var(--space-4) var(--space-5);
  }
  .dash-stat-label{order:-1;}
  .dash-filter{min-height:44px;}
  .dash-panel{padding:var(--space-5) var(--space-4);}
  .dash-item-head{gap:var(--space-3);flex-wrap:wrap;}
  .dash-fields > div,.dash-details > div{grid-template-columns:1fr;gap:var(--space-1);}
}

/* ==========================================================================
   8g. STAFF ADMIN (admin.html, admin-login.html)
   --------------------------------------------------------------------------
   A working tool rather than a page to be read: full-width, dense, no reveal
   animations, no marketing furniture.

   Bright, unlike the public site's dark panels. Staff sit in front of this for
   an hour at a time reading enquiry text and typing website copy, which is
   sustained reading work — dark-on-light is the right default for that, and it
   also stops the content editor lying about what it is editing, since every
   page it writes to is itself light. The brand still reads: the same red is
   the only accent, and the navy survives in the type.

   It therefore does NOT take the dark token set (note .admin-body's absence
   from the dark-context list near the top of this file). It redefines the same
   semantic roles light, and every rule below is written against those roles —
   so nothing here hardcodes a colour that would only work on one ground.
   ========================================================================== */

.admin-body{
  /* ---- surfaces ---- */
  --admin-bg:#f4f6fa;         /* page ground: white would leave cards invisible */
  --surface:var(--white);      /* cards, inputs, the top bar */
  --surface-alt:#eef2f7;
  --surface-raised:var(--white);
  --surface-sunken:#eef2f7;    /* grouped rows, the photo well */

  /* ---- text: measured on --surface (white) and on --admin-bg ---- */
  --text:var(--slate-900);     /* 16.8:1 on white */
  --text-muted:var(--slate-600);  /* 7.6:1 — body copy, not a whisper */
  --text-subtle:var(--slate-500); /* 5.5:1 — labels, meta; still AA */

  --border:var(--slate-200);
  --border-strong:var(--slate-300);

  /* ---- accent: the brand red that keeps white legible on top of it ---- */
  --accent:var(--red-600);        /* 4.97:1 on white */
  --accent-hover:var(--red-800);  /* 7.4:1 */
  --accent-quiet:rgba(215,38,56,.10);
  --accent-solid:var(--red-600);

  /*  Status colours are a separate axis from the accent — an enquiry's state
      must be readable as state, not as brand. All three clear AA on white,
      which the marketing --amber-500 (#e3b23c, 1.9:1) does not: hence a warn
      role of its own rather than reusing it.                                */
  --admin-warn:#8a5a00;        /* 6.4:1 — "In progress" */
  --success:var(--green-700);  /* 5.1:1 — "Closed" */
  --error:#b3261e;             /* 6.4:1 — delete, failures */
  --error-quiet:rgba(179,38,30,.08);

  --focus-ring:var(--accent);

  background:var(--admin-bg);
  color:var(--text);
  min-height:100vh;
}

/*  .btn-outline is white-on-transparent for the dark public site, which is
    invisible here. The admin uses it for every secondary action, so it is
    restated once against the light ground rather than swapped for a different
    class on a dozen buttons.                                                 */
.admin-body .btn-outline{
  color:var(--text);
  border-color:var(--border-strong);
  background:var(--surface);
}
.admin-body .btn-outline:hover{
  border-color:var(--text-subtle);
  background:var(--surface-alt);
}
.admin-boot{
  color:var(--text-muted);font-size:var(--text-sm);
  text-align:center;padding:var(--space-20) var(--gutter);
}

.admin-bar{
  /*  This is a <header>, so it inherits the marketing header's fixed height
      and pointer-events:none pass-through. Both have to go: this bar is a
      real, clickable, content-height toolbar.                               */
  position:sticky;top:0;z-index:50;
  height:auto;pointer-events:auto;
  background:var(--surface);
  border-bottom:1px solid var(--border);
  box-shadow:0 1px 2px rgba(7,29,53,.06), 0 4px 16px rgba(7,29,53,.05);
}
.admin-bar-inner{
  max-width:1240px;margin:0 auto;padding:var(--space-3) var(--gutter);
  display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);flex-wrap:wrap;
}
.admin-brand{display:flex;align-items:center;gap:var(--space-3);color:var(--text);}
.admin-brand img{height:38px;width:auto;}
.admin-brand span{
  font-family:var(--font-display);font-size:var(--text-sm);
  text-transform:uppercase;letter-spacing:var(--tracking-wider);
}
.admin-bar-actions{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;}
.admin-who{color:var(--text-subtle);font-size:var(--text-xs);overflow-wrap:anywhere;}

/*  The compact button used throughout the admin — same shape as .btn, sized
    for a dense screen but still 40px+ to stay tappable.                      */
.btn-sm{
  min-height:40px;
  padding:var(--space-2) var(--space-5);
  font-size:var(--text-xs);
  border-width:1px;
}

 /*  ...and these are <section>s, which the base stylesheet gives a full
     --section-y band and its own background.                                */
.admin-panel{padding:0;background:transparent;}

.admin-main{max-width:1240px;margin:0 auto;padding:var(--space-6) var(--gutter) var(--space-20);}

.admin-tabs{display:flex;gap:var(--space-2);border-bottom:1px solid var(--border);margin-bottom:var(--space-6);}
.admin-tab{
  appearance:none;background:transparent;border:0;cursor:pointer;
  padding:var(--space-4) var(--space-5);
  color:var(--text-subtle);
  font-family:var(--font-display);font-size:var(--text-sm);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
  border-bottom:2px solid transparent;margin-bottom:-1px;
  transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out);
}
.admin-tab:hover{color:var(--text);}
.admin-tab.is-active{color:var(--accent);border-bottom-color:var(--accent);}

.admin-toolbar{
  display:flex;flex-wrap:wrap;gap:var(--space-4);
  align-items:center;justify-content:space-between;
  margin-bottom:var(--space-5);
}
.admin-toolbar-right{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center;}
.admin-chips{display:flex;flex-wrap:wrap;gap:var(--space-2);}
.admin-chip{
  appearance:none;cursor:pointer;
  min-height:40px;padding:0 var(--space-4);
  background:transparent;color:var(--text-muted);
  border:1px solid var(--border-strong);border-radius:var(--radius-pill);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
  transition:color var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out),
             background var(--dur-fast) var(--ease-out);
}
.admin-chip span{opacity:.7;margin-left:6px;}
.admin-chip:hover{color:var(--text);border-color:var(--text-subtle);}
.admin-chip.is-active{background:var(--accent-solid);color:var(--white);border-color:var(--accent-solid);}

.admin-search{display:flex;gap:var(--space-2);}
.admin-search input{
  min-height:40px;min-width:220px;
  padding:0 var(--space-4);
  background:var(--surface);color:var(--text);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  font-family:var(--font-body);font-size:var(--text-sm);
}
.admin-select{display:inline-flex;flex-direction:column;gap:var(--space-1);}
.admin-select > span{
  font-size:var(--text-xs);color:var(--text-subtle);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-select select{
  min-height:40px;padding:0 var(--space-3);
  background:var(--surface);color:var(--text);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  font-family:var(--font-body);font-size:var(--text-sm);
}
.admin-select select option{background:var(--surface);color:var(--text);}

.admin-state{color:var(--text-muted);font-size:var(--text-sm);padding:var(--space-4) 0;}
.admin-state.is-error{color:var(--error);}

.admin-list{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3);}
.admin-item{
  background:var(--surface-raised);
  border:1px solid var(--border);border-radius:var(--radius-md);
  overflow:hidden;
}
.admin-item.is-open{border-color:var(--border-strong);}
.admin-item-head{
  display:flex;align-items:center;gap:var(--space-4);
  padding:var(--space-4);
}
.admin-item-main{flex:1;min-width:0;display:grid;gap:4px;}
.admin-item-title{color:var(--text);font-weight:600;font-size:var(--text-base);overflow-wrap:anywhere;}
.admin-item-meta{color:var(--text-subtle);font-size:var(--text-xs);overflow-wrap:anywhere;}
.admin-item-toggle{
  appearance:none;cursor:pointer;flex:none;
  min-height:40px;padding:0 var(--space-4);
  background:transparent;color:var(--text-muted);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-item-toggle:hover{color:var(--accent);border-color:var(--accent);}
.admin-item-body{padding:var(--space-4);border-top:1px solid var(--border);display:grid;gap:var(--space-5);}

.admin-status{
  flex:none;padding:5px var(--space-3);
  border:1px solid currentColor;border-radius:var(--radius-pill);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);white-space:nowrap;
}
.admin-status.is-new{color:var(--accent);}
.admin-status.is-in_progress{color:var(--admin-warn);}
.admin-status.is-closed{color:var(--success);}

.admin-contact{display:flex;flex-wrap:wrap;gap:var(--space-4);align-items:center;font-size:var(--text-sm);}
.admin-contact strong{color:var(--text);}
.admin-contact a{color:var(--accent);text-decoration:underline;text-underline-offset:3px;overflow-wrap:anywhere;}
.admin-contact a:hover{color:var(--accent-hover);}
.admin-contact span{color:var(--text-muted);}

.admin-fields{display:grid;gap:var(--space-2);margin:0;}
.admin-fields > div{display:grid;grid-template-columns:minmax(120px, 200px) 1fr;gap:var(--space-4);}
.admin-fields dt{
  color:var(--text-subtle);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-fields dd{margin:0;color:var(--text-muted);font-size:var(--text-sm);overflow-wrap:anywhere;}

.admin-item-controls{
  display:grid;gap:var(--space-4);
  padding-top:var(--space-4);border-top:1px dashed var(--border);
}
.admin-note{display:grid;gap:var(--space-2);}
.admin-note > span{
  font-size:var(--text-xs);color:var(--text-subtle);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-item-actions{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center;}
.admin-danger{border-color:rgba(179,38,30,.45);color:var(--error);}
.admin-danger:hover{border-color:var(--error);background:var(--error-quiet);color:var(--error);}
.admin-danger.is-armed{background:var(--error-quiet);border-color:var(--error);}

.admin-saved{font-size:var(--text-xs);color:var(--success);}
.admin-saved.is-error{color:var(--error);}
.admin-saved.is-pending{color:var(--text-muted);}

.admin-pager{
  display:flex;align-items:center;justify-content:center;gap:var(--space-4);
  margin-top:var(--space-6);color:var(--text-muted);font-size:var(--text-sm);
}

/* ---- content editor ---------------------------------------------------- */
.admin-content{display:grid;gap:var(--space-5);}
.admin-card{
  background:var(--surface-raised);
  border:1px solid var(--border);border-radius:var(--radius-lg);
  padding:var(--space-6);
  display:grid;gap:var(--space-5);
}
.admin-card-head h2{font-size:var(--text-lg);margin:0;}
.admin-card-head p{color:var(--text-muted);font-size:var(--text-sm);margin-top:var(--space-2);}
.admin-grid{display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:var(--space-4);}
.admin-wide{grid-column:1 / -1;}

.admin-card label{display:grid;gap:var(--space-2);font-size:var(--text-sm);color:var(--text-muted);}
.admin-card label > span{font-size:var(--text-sm);color:var(--text-muted);}
.admin-card small{color:var(--text-subtle);font-size:var(--text-xs);}
.admin-card input[type="text"],
.admin-card input[type="email"],
.admin-card textarea{
  width:100%;
  padding:var(--space-3);
  background:var(--surface);color:var(--text);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  font-family:var(--font-body);font-size:var(--text-sm);
  line-height:var(--leading-normal);
}
.admin-card input[type="text"]{min-height:44px;}
.admin-card textarea{resize:vertical;}
.admin-card input:focus,.admin-card textarea:focus,.admin-search input:focus{border-color:var(--accent);outline:2px solid var(--accent-quiet);outline-offset:1px;}

.admin-rows{display:grid;gap:var(--space-4);}
.admin-row{
  display:grid;grid-template-columns:repeat(2, minmax(0, 1fr));gap:var(--space-4);
  padding:var(--space-4);
  background:var(--surface-sunken);
  border:1px solid var(--border);border-radius:var(--radius-md);
}
.admin-row-remove{
  appearance:none;cursor:pointer;
  min-height:36px;padding:0 var(--space-4);
  background:transparent;color:var(--error);
  border:1px solid rgba(179,38,30,.4);border-radius:var(--radius-pill);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-row-remove:hover{border-color:var(--error);background:var(--error-quiet);}
.admin-add{justify-self:start;}
.admin-card-foot{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center;}

.visually-hidden{
  position:absolute;width:1px;height:1px;
  margin:-1px;padding:0;border:0;
  clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;white-space:nowrap;
}

/* ---- plain-language help panels ---------------------------------------- */
.admin-help{
  background:var(--surface-raised);
  border:1px solid var(--border);
  border-left:3px solid var(--accent);
  border-radius:var(--radius-md);
  padding:var(--space-5);
  margin-bottom:var(--space-5);
}
.admin-help h2{font-size:var(--text-base);margin:0;}
.admin-help p{
  color:var(--text-muted);font-size:var(--text-sm);
  line-height:var(--leading-normal);
  margin-top:var(--space-3);max-width:80ch;
}
.admin-help strong{color:var(--text);}

/*  An edited-but-unsaved card is the one state worth shouting about, since
    the work is only in the browser until Save is pressed.                   */
.admin-card.is-dirty{border-color:var(--admin-warn);}

/* ---- collection row controls ------------------------------------------- */
.admin-row-controls{
  grid-column:1 / -1;
  display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center;
  padding-top:var(--space-2);
  border-top:1px dashed var(--border);
}
.admin-row-move{
  appearance:none;cursor:pointer;
  min-height:36px;padding:0 var(--space-4);
  background:transparent;color:var(--text-muted);
  border:1px solid var(--border-strong);border-radius:var(--radius-pill);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-row-move:hover{color:var(--text);border-color:var(--text-subtle);}
.admin-row-remove{margin-left:auto;}

/*  Group heading inside the section-wording card: it lists a dozen blocks of
    the page, and without a break between them it reads as one long form.    */
.admin-group{
  grid-column:1 / -1;
  margin:var(--space-4) 0 0;
  padding-top:var(--space-4);
  border-top:1px solid var(--border);
  font-size:var(--text-sm);color:var(--accent);
  font-family:var(--font-display);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-group:first-child{margin-top:0;padding-top:0;border-top:0;}

/*  Fixed collection rows (the per-page title editor) name what they belong to
    instead of carrying move/remove controls.                                */
.admin-row-title{
  grid-column:1 / -1;
  margin:0;
  font-size:var(--text-sm);color:var(--text);
  font-family:var(--font-display);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}

/* ---- photo picker ------------------------------------------------------- */
.admin-photo{display:grid;gap:var(--space-3);}
.admin-photo-title{
  font-size:var(--text-sm);color:var(--text-muted);
}
.admin-photo-current{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4);}
.admin-photo-current img{
  width:104px;height:70px;object-fit:cover;
  background:var(--surface-sunken);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
}
.admin-photo-name{color:var(--text-subtle);font-size:var(--text-xs);overflow-wrap:anywhere;}

.admin-photo-grid{
  display:grid;grid-template-columns:repeat(auto-fill, minmax(130px, 1fr));
  gap:var(--space-3);
  max-height:340px;overflow:auto;
  padding:var(--space-3);
  background:var(--surface-sunken);
  border:1px solid var(--border);border-radius:var(--radius-md);
}
.admin-photo-option{
  appearance:none;cursor:pointer;
  display:grid;gap:var(--space-2);padding:var(--space-2);
  background:transparent;color:var(--text-muted);
  border:2px solid transparent;border-radius:var(--radius-sm);
  font-family:var(--font-body);font-size:var(--text-xs);text-align:left;
}
.admin-photo-option img{
  width:100%;aspect-ratio:3/2;object-fit:cover;
  border-radius:var(--radius-sm);background:var(--surface-sunken);
}
.admin-photo-option:hover{border-color:var(--border-strong);color:var(--text);}
.admin-photo-option.is-chosen{border-color:var(--accent);color:var(--text);}

.admin-photo-upload{
  display:grid;gap:var(--space-2);align-content:center;justify-items:center;
  padding:var(--space-3);cursor:pointer;text-align:center;
  border:2px dashed var(--border-strong);border-radius:var(--radius-sm);
  color:var(--text-muted);font-size:var(--text-xs);
}
.admin-photo-upload:hover{border-color:var(--accent);color:var(--accent);}
.admin-photo-upload input[type="file"]{
  /*  The label is the control; the input itself only needs to be reachable by
      keyboard, not seen.                                                     */
  width:1px;height:1px;opacity:0;position:absolute;
}

/* ---- staff management (superadmin only) --------------------------------- */
/*  The Staff panel reuses .admin-item / .admin-note wholesale; these fill the
    two gaps that markup leaves — a select inside .admin-note (the enquiry
    panel only ever puts one inside .admin-select), and the text input used for
    setting someone's password.                                               */
.admin-note select,
.admin-note input[type="text"]{
  min-height:44px;
  padding:0 var(--space-3);
  background:var(--surface);color:var(--text);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  font-family:var(--font-body);font-size:var(--text-sm);
}
.admin-note select:focus,
.admin-note input[type="text"]:focus{
  border-color:var(--accent);
  outline:2px solid var(--accent-quiet);outline-offset:1px;
}
.admin-note select option{background:var(--surface);color:var(--text);}

/*  A confirmation that outlives the list rebuild it triggered — the card the
    message came from is gone by the time it is read, so it lands here.      */
.admin-state.is-done{color:var(--success);}

/* ---- staff sign-in (admin-login.html) ----------------------------------- */
/*  Its own page rather than a mode of login.html: a customer arriving at the
    customer login must never be shown a staff door, and the two post to
    different endpoints under different rate limits.                          */
.admin-login-body{display:flex;flex-direction:column;}
.admin-login{
  flex:1;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--space-5);
  padding:var(--space-10) var(--gutter);
}
.admin-login-card{
  width:100%;max-width:420px;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius-lg);
  /*  The one piece of brand furniture on the page: the same red that caps the
      public site's header stripes, here as the card's top edge.             */
  border-top:3px solid var(--accent-solid);
  box-shadow:0 1px 2px rgba(7,29,53,.06), 0 12px 32px rgba(7,29,53,.10);
  padding:var(--space-8) var(--space-6) var(--space-6);
  display:grid;gap:var(--space-5);
}
.admin-login-head{display:grid;gap:var(--space-2);justify-items:start;}
.admin-login-head img{height:44px;width:auto;margin-bottom:var(--space-2);}
.admin-login-eyebrow{
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wider);
  color:var(--accent);margin:0;
}
.admin-login-head h1{font-size:var(--text-2xl);margin:0;color:var(--text);}
.admin-login-sub{
  color:var(--text-muted);font-size:var(--text-sm);
  line-height:var(--leading-normal);margin:0;
}
.admin-login-sub a{color:var(--accent);text-decoration:underline;text-underline-offset:3px;}
.admin-login-sub a:hover{color:var(--accent-hover);}

.admin-login-note{
  margin:0;padding:var(--space-3) var(--space-4);
  background:var(--accent-quiet);
  border-left:3px solid var(--accent);
  border-radius:var(--radius-sm);
  color:var(--text);font-size:var(--text-sm);
  line-height:var(--leading-normal);
}

.admin-login-form{display:grid;gap:var(--space-4);}
.admin-login-form label{
  display:grid;gap:var(--space-2);
  font-family:var(--font-display);font-size:var(--text-xs);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
  color:var(--text-subtle);
}
.admin-login-form input{
  width:100%;min-height:46px;
  padding:0 var(--space-4);
  background:var(--surface);color:var(--text);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  font-family:var(--font-body);font-size:var(--text-base);
  /*  The label above is uppercase display type; the value the user types is
      body type at reading size, so the two never look like one field.       */
  text-transform:none;letter-spacing:normal;
}
.admin-login-form input:focus{
  border-color:var(--accent);
  outline:2px solid var(--accent-quiet);outline-offset:1px;
}
.admin-login-submit{width:100%;}

.admin-login-status{
  margin:0;font-size:var(--text-sm);line-height:var(--leading-normal);
  min-height:1.2em;   /* holds its line so the button never jumps on error */
}
.admin-login-status.is-error{color:var(--error);}
.admin-login-status.is-success{color:var(--success);}
.admin-login-status.is-pending{color:var(--text-muted);}

.admin-login-foot{
  margin:0;color:var(--text-subtle);font-size:var(--text-xs);
  line-height:var(--leading-normal);
}
.admin-login-foot a{color:var(--accent);text-decoration:underline;text-underline-offset:3px;}
.admin-login-back{margin:0;}
.admin-login-back a{
  color:var(--text-subtle);font-size:var(--text-xs);
  font-family:var(--font-display);
  text-transform:uppercase;letter-spacing:var(--tracking-wide);
}
.admin-login-back a:hover{color:var(--accent);}

/* ---- idle-session warning ----------------------------------------------- */
/*  Fixed to the bottom rather than inserted in the flow: it can appear while
    the user is anywhere down a long content form, and a notice they have to
    scroll to find is not a warning.                                          */
.admin-idle{
  position:fixed;left:50%;bottom:var(--space-5);transform:translateX(-50%);
  z-index:200;
  display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap;
  max-width:calc(100% - var(--space-6));
  padding:var(--space-3) var(--space-4);
  background:var(--surface);
  border:1px solid var(--border-strong);
  border-left:3px solid var(--admin-warn);
  border-radius:var(--radius-md);
  box-shadow:0 8px 28px rgba(7,29,53,.18);
}
.admin-idle-text{color:var(--text);font-size:var(--text-sm);}

/* --------------------------------------------------------------------------
   Enquiry workflow: overview, filters, bulk bar, attachments, history.
   Everything below is written against the same semantic roles the rest of
   this section uses, so none of it hardcodes a colour.
   -------------------------------------------------------------------------- */

/*  The overview strip. Tiles are buttons because every one of them is a
    shortcut into the list filtered to exactly what it counted — a number you
    cannot act on is just decoration.                                        */
.admin-overview{
  display:grid;
  grid-template-columns:repeat(auto-fit, minmax(150px, 1fr));
  gap:var(--space-3);
  margin-bottom:var(--space-5);
}
.admin-stat{
  display:flex;flex-direction:column;gap:2px;
  padding:var(--space-4);text-align:left;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius-md);
  border-left:3px solid var(--border-strong);
  cursor:pointer;transition:border-color .15s ease, transform .15s ease;
}
.admin-stat.is-plain{cursor:default;}
.admin-stat:not(.is-plain):hover{border-color:var(--accent);border-left-color:var(--accent);transform:translateY(-1px);}
.admin-stat:not(.is-plain):focus-visible{outline:2px solid var(--accent);outline-offset:2px;}
.admin-stat.is-warn{border-left-color:var(--admin-warn);}
.admin-stat-num{font-size:26px;font-weight:700;color:var(--text);line-height:1.1;}
.admin-stat.is-warn .admin-stat-num{color:var(--admin-warn);}
.admin-stat-label{font-size:var(--text-xs);color:var(--text-muted);line-height:1.35;}

/*  A banner, not a toast: a mail outage is a standing condition, and it has
    to still be on screen when somebody looks up from the list.              */
.admin-alert{
  padding:var(--space-4) var(--space-5);
  margin-bottom:var(--space-5);
  border-radius:var(--radius-md);
  border:1px solid var(--border-strong);
  border-left:4px solid var(--admin-warn);
  background:var(--surface);
  color:var(--text);
  font-size:var(--text-sm);line-height:1.5;
}
.admin-alert.is-error{border-left-color:var(--accent-solid);}

.admin-toolbar-sub{margin-top:calc(var(--space-3) * -1);margin-bottom:var(--space-4);}
.admin-dates{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center;}
.admin-dates label{
  display:inline-flex;align-items:center;gap:var(--space-2);
  font-size:var(--text-xs);color:var(--text-muted);
}
.admin-dates input{
  padding:6px 10px;
  border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);
  background:var(--surface);color:var(--text);
  font:inherit;font-size:var(--text-sm);
}
.admin-result-count{font-size:var(--text-xs);color:var(--text-muted);}

/*  Sticks to the bottom so a selection made at the top of a long list is
    still actionable once you have scrolled to the end of it.                */
.admin-bulk{
  position:sticky;bottom:var(--space-4);z-index:5;
  display:flex;flex-wrap:wrap;gap:var(--space-4);align-items:center;justify-content:space-between;
  padding:var(--space-3) var(--space-4);margin-bottom:var(--space-4);
  background:var(--surface);
  border:1px solid var(--border-strong);
  border-left:3px solid var(--accent-solid);
  border-radius:var(--radius-md);
  box-shadow:0 8px 28px rgba(7,29,53,.16);
}
.admin-bulk-all{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm);color:var(--text);}
.admin-bulk-actions{display:flex;flex-wrap:wrap;gap:var(--space-3);align-items:center;}
.admin-item-tick{width:18px;height:18px;flex:none;margin-top:3px;accent-color:var(--accent-solid);cursor:pointer;}

/*  Says whether an application came with a CV before the card is opened —
    previously invisible until you expanded the row.                         */
.admin-badge{
  display:inline-block;width:fit-content;margin-top:4px;
  padding:2px 8px;border-radius:99px;
  font-size:10px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--success);background:rgba(30,122,60,.10);
}
.admin-badge.is-missing{color:var(--admin-warn);background:rgba(138,90,0,.10);}

.admin-file{color:var(--accent);font-weight:600;text-decoration:underline;text-underline-offset:3px;overflow-wrap:anywhere;}
.admin-file:hover{color:var(--accent-hover);}
.admin-file.is-missing{color:var(--text-muted);text-decoration:line-through;font-weight:400;}
.admin-file-size{color:var(--text-subtle);font-size:var(--text-xs);}
.admin-file-note{color:var(--text-muted);font-size:var(--text-xs);}

.admin-reply{
  display:grid;gap:var(--space-3);
  padding:var(--space-4);
  border:1px solid var(--border);
  border-radius:var(--radius-md);
  background:var(--admin-bg);
}
.admin-reply label{display:grid;gap:var(--space-1);}
.admin-reply label > span{font-size:var(--text-xs);color:var(--text-muted);text-transform:uppercase;letter-spacing:.06em;}
.admin-reply input,.admin-reply textarea{
  padding:10px 12px;
  border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);
  background:var(--surface);color:var(--text);
  font:inherit;font-size:var(--text-sm);line-height:1.5;
  resize:vertical;
}
.admin-reply-note{font-size:var(--text-xs);color:var(--text-muted);margin:0;}

.admin-history{border-top:1px solid var(--border);padding-top:var(--space-3);}
.admin-history summary{
  cursor:pointer;font-size:var(--text-xs);color:var(--text-muted);
  text-transform:uppercase;letter-spacing:.06em;font-weight:600;
}
.admin-history summary:hover{color:var(--text);}
.admin-trail{list-style:none;margin:var(--space-3) 0 0;padding:0;display:grid;gap:var(--space-2);}
.admin-trail li{
  display:grid;grid-template-columns:auto 1fr auto;gap:var(--space-3);align-items:baseline;
  font-size:var(--text-xs);padding-bottom:var(--space-2);border-bottom:1px solid var(--border);
}
.admin-trail li:last-child{border-bottom:0;padding-bottom:0;}
.admin-trail-when{color:var(--text-subtle);white-space:nowrap;}
.admin-trail-what{color:var(--text);overflow-wrap:anywhere;}
.admin-trail-who{color:var(--text-subtle);white-space:nowrap;overflow-wrap:anywhere;}

.admin-hint{font-size:var(--text-xs);color:var(--text-muted);margin:var(--space-2) 0 0;line-height:1.5;}

/* ---- email delivery panel ---- */
.admin-delivery{margin-bottom:var(--space-4);}
.admin-delivery-state{
  font-size:var(--text-base);font-weight:600;margin:0 0 var(--space-2);
  padding-left:var(--space-3);border-left:3px solid var(--border-strong);
}
.admin-delivery-state.is-healthy{color:var(--success);border-left-color:var(--success);}
.admin-delivery-state.is-degraded{color:var(--admin-warn);border-left-color:var(--admin-warn);}
.admin-delivery-state.is-failing,
.admin-delivery-state.is-unconfigured{color:var(--accent);border-left-color:var(--accent-solid);}

.admin-maillog{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-2);max-height:420px;overflow-y:auto;}
.admin-maillog-row{
  display:grid;grid-template-columns:64px 150px 1fr 1fr;gap:var(--space-3);align-items:baseline;
  padding:var(--space-2) var(--space-3);
  border:1px solid var(--border);border-radius:var(--radius-sm);
  font-size:var(--text-xs);
}
.admin-maillog-row.is-failed{border-left:3px solid var(--accent-solid);}
.admin-maillog-row.is-sent{border-left:3px solid var(--success);}
.admin-maillog-state{font-weight:700;}
.admin-maillog-row.is-sent .admin-maillog-state{color:var(--success);}
.admin-maillog-row.is-failed .admin-maillog-state{color:var(--accent);}
.admin-maillog-when,.admin-maillog-what{color:var(--text-muted);}
.admin-maillog-to{color:var(--text);overflow-wrap:anywhere;}
.admin-maillog-error{grid-column:1 / -1;color:var(--accent);overflow-wrap:anywhere;}

@media (max-width:820px){
  .admin-grid,.admin-row{grid-template-columns:1fr;}
  .admin-fields > div{grid-template-columns:1fr;gap:var(--space-1);}
  .admin-toolbar{align-items:stretch;}
  .admin-toolbar-right,.admin-search{width:100%;}
  .admin-search input{flex:1;min-width:0;}
  .admin-item-head{flex-wrap:wrap;}
  .admin-item-toggle{width:100%;}
  .admin-card{padding:var(--space-5) var(--space-4);}
  .admin-photo-grid{grid-template-columns:repeat(auto-fill, minmax(100px, 1fr));max-height:260px;}
  .admin-row-remove{margin-left:0;}
  .admin-row-move,.admin-row-remove{min-height:44px;}

  .admin-overview{grid-template-columns:repeat(auto-fit, minmax(130px, 1fr));gap:var(--space-2);}
  .admin-stat{padding:var(--space-3);}
  .admin-stat-num{font-size:22px;}
  .admin-bulk{position:static;flex-direction:column;align-items:stretch;}
  .admin-bulk-actions{width:100%;}
  .admin-bulk-actions .admin-select{flex:1;min-width:0;}
  .admin-dates{width:100%;}
  .admin-dates label{flex:1;min-width:0;}
  .admin-dates input{flex:1;min-width:0;}
  .admin-trail li{grid-template-columns:1fr;gap:2px;}
  .admin-maillog-row{grid-template-columns:1fr;gap:2px;}
}

/* ==========================================================================
   9. FIXED FURNITURE
   ========================================================================== */

/*  Floating icon dock, replacing the old full-width sticky CTA bar. Sized to
    its own content and centred rather than spanning edge to edge, so it reads
    as a compact capsule rather than a flat toolbar — the same dark-pill /
    white-chip language the desktop nav capsule uses above the fold, carried
    down into the one piece of mobile chrome that's on screen the whole visit.
    --bottom-bar-h still reserves the clearance beneath it: body padding, the
    WhatsApp/to-top stack and the cookie banner all key off that one token, so
    changing the dock's footprint only ever means changing that number.       */
.pill-nav{
  display:none;
  position:fixed;left:50%;z-index:200;
  bottom:calc(var(--consent-h) + var(--safe-b) + var(--space-4));
  transform:translateX(-50%);
  align-items:center;
  padding:4px;
  background:var(--ink-900);
  border:1px solid rgba(255,255,255,.10);
  border-radius:var(--radius-pill);
  box-shadow:var(--shadow-4);
  /*  Matches the banner's own slide so the dock travels with it instead of
      jumping to its raised position 500ms before the banner arrives.        */
  transition:bottom var(--dur-slower) var(--ease-out);
}
.pill-link{
  display:flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;
  padding:0 8px;
  border-radius:var(--radius-pill);
  color:rgba(255,255,255,.60);
  transition:background var(--dur-base) var(--ease-out),
             color var(--dur-base) var(--ease-out);
}
.pill-link:hover,.pill-link:focus-visible{color:var(--white);background:rgba(255,255,255,.10);}
.pill-icon{width:20px;height:20px;flex:none;}
/*  Collapsed to zero width rather than display:none, so the label stays in
    the accessibility tree and the chip's growth animates instead of jumping.  */
.pill-label{
  max-width:0;opacity:0;overflow:hidden;white-space:nowrap;
  margin-left:0;
  font-family:var(--font-display);
  font-size:11px;font-weight:600;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  transition:max-width var(--dur-base) var(--ease-out),
             opacity var(--dur-fast) var(--ease-out),
             margin-left var(--dur-base) var(--ease-out);
}
/*  68px comfortably fits the longest label this dock ever actually shows
    ("Services") without the row risking overflow on a 320px phone — the
    other four items stay pinned at the 44px floor, so the whole row's width
    is bounded by this one number.                                            */
.pill-link[aria-current]{background:var(--white);color:var(--navy-800);}
.pill-link[aria-current] .pill-label{max-width:68px;opacity:1;margin-left:5px;}

/*  Request a Quote is the one action worth spotting at a glance even when
    it isn't the current destination — the same red every other primary CTA
    on the site already uses, not a new colour introduced just for this.      */
.pill-link.pill-primary{color:var(--red-400);}
.pill-link.pill-primary:hover,
.pill-link.pill-primary:focus-visible{color:var(--white);background:rgba(215,38,56,.22);}
.pill-link.pill-primary[aria-current]{background:var(--red-600);color:var(--white);}

.whatsapp-float{
  position:fixed;z-index:210;
  right:max(var(--space-6), calc(var(--safe-r) + var(--space-3)));
  bottom:calc(var(--consent-h) + var(--bottom-bar-h) + var(--safe-b) + var(--space-6));
  width:var(--fab-size);height:var(--fab-size);
  border-radius:var(--radius-pill);
  background:#25d366;
  display:flex;align-items:center;justify-content:center;
  box-shadow:var(--shadow-3);
  transition:transform var(--dur-base) var(--ease-out),
             box-shadow var(--dur-base) var(--ease-out),
             bottom var(--dur-base) var(--ease-out);
}
.whatsapp-float svg{width:28px;height:28px;color:var(--white);}
.whatsapp-float:hover{transform:scale(1.08);box-shadow:var(--shadow-4);}
.whatsapp-float::before{
  content:"";position:absolute;inset:0;z-index:-1;
  border-radius:var(--radius-pill);
  background:#25d366;
  opacity:.55;
  animation:wa-pulse 2.4s ease-out infinite;
}
@keyframes wa-pulse{
  0%{transform:scale(1);opacity:.55;}
  100%{transform:scale(1.6);opacity:0;}
}

.to-top{
  position:fixed;z-index:205;
  right:max(var(--space-6), calc(var(--safe-r) + var(--space-3)));
  bottom:calc(var(--consent-h) + var(--bottom-bar-h) + var(--safe-b) + var(--space-6) + var(--fab-size) + var(--space-3));
  width:46px;height:46px;
  display:flex;align-items:center;justify-content:center;
  background:var(--navy-800);
  color:var(--white);
  border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);
  cursor:pointer;
  opacity:0;visibility:hidden;transform:translateY(10px);
  transition:opacity var(--dur-base) var(--ease-out),
             visibility var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out),
             background var(--dur-base) var(--ease-out),
             bottom var(--dur-base) var(--ease-out);
}
.to-top.is-visible{opacity:1;visibility:visible;transform:none;}
.to-top:hover{background:var(--red-600);border-color:var(--red-600);}
.to-top svg{width:18px;height:18px;}

/*  One dot per deck panel, injected by initPanelRail(). Vertically centred so
    it never meets the bottom-right FAB stack.                                */
.panel-rail{
  position:fixed;z-index:180;
  right:clamp(8px, 1.1vw, 16px);
  top:50%;
  transform:translateY(-50%);
  display:flex;flex-direction:column;align-items:flex-end;
  gap:1px;
}
.panel-dot{
  position:relative;
  display:flex;align-items:center;justify-content:center;
  /*  24, not 22. WCAG 2.2 Target Size (Minimum) floors a pointer target at
      24x24 CSS px, and the 1px rail gap means the spacing exception cannot
      make up the difference either (23px pitch). The dot itself is still the
      7px mark - only the hit area grew.                                      */
  width:24px;height:24px;
}
.panel-dot::after{
  content:"";
  width:7px;height:7px;
  border-radius:50%;
  /*  One neutral that carries on both the navy and the light panels rather
      than a token, which would flip with whichever section is behind it.    */
  background:rgba(120,140,165,.55);
  box-shadow:0 0 0 1px rgba(255,255,255,.28);
  transition:background var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out);
}
.panel-dot:hover::after{background:var(--red-600);transform:scale(1.3);}
.panel-dot.is-active::after{background:var(--red-600);transform:scale(1.45);}
.panel-dot.is-active::before{
  content:"";
  position:absolute;inset:2px;
  border:1px solid rgba(215,38,56,.45);
  border-radius:50%;
}
.panel-dot-label{
  position:absolute;right:calc(100% + 6px);
  white-space:nowrap;
  padding:5px 10px;
  border-radius:var(--radius-sm);
  background:var(--ink-900);
  color:var(--white);
  font-family:var(--font-display);
  font-size:11px;
  letter-spacing:var(--tracking-wide);
  text-transform:uppercase;
  font-weight:600;
  box-shadow:var(--shadow-3);
  opacity:0;transform:translateX(6px);
  pointer-events:none;
  transition:opacity var(--dur-base) var(--ease-out),
             transform var(--dur-base) var(--ease-out);
}
.panel-dot:hover .panel-dot-label,
.panel-dot:focus-visible .panel-dot-label{opacity:1;transform:none;}
@media (max-width:1200px), (max-height:600px), (max-width:1400px) and (max-height:680px){.panel-rail{display:none;}}

/*  Anchored to the bottom EDGE, not to --bottom-bar-h. That offset dates from
    the full-width sticky CTA bar the dock replaced: against a solid bar the
    banner read as one stacked block, but against a floating capsule it left
    an 84px band of live page showing between the banner and the screen edge,
    with the dock hovering in the middle of it - measured on a 390x844 phone.
    Sitting on the edge and lifting the dock/FAB stack by --consent-h instead
    keeps every piece of furniture on screen and the sheet solid to the edge. */
.cookie-banner{
  position:fixed;left:0;right:0;z-index:300;
  bottom:0;
  background:var(--ink-900);
  border-top:2px solid var(--red-600);
  color:var(--text-muted);
  padding:var(--space-5) 0 calc(var(--space-5) + var(--safe-b));
  transform:translateY(110%);
  transition:transform var(--dur-slower) var(--ease-out);
}
.cookie-banner.is-open{transform:translateY(0);}
.cookie-banner .wrap{
  display:flex;align-items:center;justify-content:space-between;
  gap:var(--space-6);flex-wrap:wrap;
}
.cookie-banner p{margin:0;font-size:var(--text-sm);max-width:70ch;}
.cookie-banner a{color:var(--accent);text-decoration:underline;text-underline-offset:2px;}
.cookie-actions{display:flex;gap:var(--space-3);flex-wrap:wrap;}
.cookie-actions .btn{padding:var(--space-3) var(--space-5);font-size:var(--text-xs);}

.noscript-note{
  background:#fff4ce;
  color:#5b4a00;
  border-bottom:2px solid var(--amber-500);
  padding:var(--space-3) var(--gutter);
  text-align:center;
  font-size:var(--text-sm);
}
.noscript-note a{color:#7a6000;text-decoration:underline;}  /* 5.45:1 on #fff4ce; #8a6d00 was 4.47 */

/* ---------- starfield ----------
   Ambient night-sky motion behind the site's dark panels - one pseudo-element,
   eight star dots as separate background-image layers so depth is faked
   without a second paint layer: five dim/small dots share a 190px tile,
   three bright/larger dots share a 280px tile. Both the ambient drift
   (background-position) and the cursor parallax (transform) are written by
   initStarfieldMotion() in script.js, not by a CSS @keyframes - a real,
   reproducible Chromium quirk means a var()-driven `transform` on an element
   that also has ANY running CSS animation (even one that never touches
   transform) stops updating after the animation's first tick and never
   recovers, which silently froze the parallax here. Doing both from JS
   avoids the interaction outright: --star-bg-pos carries the full 8-layer
   background-position string, --star-mx/--star-my the cursor offset, both
   as plain custom properties with no keyframes anywhere near them.

   z-index:-1 (not a bare ::before/::after with no z-index) is what keeps this
   from covering the section's own copy: it sinks the layer below ALL normal
   in-flow content in the same stacking context without needing to promote
   every heading/paragraph inside these sections to its own z-index - only
   the section itself needs position:relative to scope it, added inline
   below wherever a section didn't already have one for other reasons.

   inset:-60px (not 0) over-sizes the box so it still fully covers its
   section after the max 45px parallax shift in either direction; the
   transition on transform, not a JS easing loop, is what makes the cursor
   follow feel smooth - the browser tweens the computed value on its own
   timeline instead of snapping to every mousemove.                        */
/*  The -60px bleed below is real layout, not just paint: on every section that
    did not already clip, it put the starfield box 60px past the right edge and
    added exactly 60px to the document's scrollable width (measured: 447 on a
    387px viewport, 1581 on 1521 - the same 60 at every width, because the
    bleed is a fixed number). html's overflow-x:hidden hides that on desktop,
    but on a phone it is what let the page drag sideways into a bare navy strip
    - the html/body background showing beside sections that only ever paint
    their own viewport width.

    overflow-x:clip (not hidden) is what contains it: clip does not make these
    sections scroll containers, so the sticky header still resolves against the
    viewport and nothing gains a scroll offset of its own. The effect is
    untouched - the cursor parallax swings at most 45px and the box still
    over-hangs by 60, so the clip never exposes an unstarred edge, and it only
    ever runs behind (hover:hover) and (pointer:fine) anyway, i.e. never on the
    phones this fixes. .hero, .page-hero and .cta-strip already carry
    overflow:hidden and are listed only to keep the two selector lists in step.  */
.hero,
.page-hero,
.cta-strip,
.dog-feature,
.quote-section,
.auth-section,
.dash-section,
.error-page,
footer,
.bg-navy,
.bg-charcoal{
  overflow-x:clip;
}

.hero::after,
.page-hero::after,
.cta-strip::after,
.dog-feature::before,
.quote-section::before,
.auth-section::before,
.dash-section::before,
.error-page::before,
footer::before,
.bg-navy::before,
.bg-charcoal::before{
  content:"";
  position:absolute;inset:-60px;
  z-index:-1;
  pointer-events:none;
  background-repeat:repeat;
  background-size:
    190px 190px, 190px 190px, 190px 190px, 190px 190px, 190px 190px,
    280px 280px, 280px 280px, 280px 280px;
  background-image:
    radial-gradient(1px 1px at 14% 24%, rgba(255,255,255,.28), transparent 60%),
    radial-gradient(1px 1px at 46% 66%, rgba(255,255,255,.22), transparent 60%),
    radial-gradient(1px 1px at 76% 18%, rgba(255,255,255,.30), transparent 60%),
    radial-gradient(1px 1px at 28% 88%, rgba(255,255,255,.20), transparent 60%),
    radial-gradient(1px 1px at 90% 52%, rgba(255,255,255,.26), transparent 60%),
    radial-gradient(1.5px 1.5px at 20% 42%, rgba(255,255,255,.50), transparent 60%),
    radial-gradient(1.5px 1.5px at 64% 78%, rgba(255,255,255,.40), transparent 60%),
    radial-gradient(1.5px 1.5px at 84% 22%, rgba(255,255,255,.45), transparent 60%);
  background-position:var(--star-bg-pos, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0, 0 0);
  transform:translate3d(calc(var(--star-mx, 0) * 1px), calc(var(--star-my, 0) * 1px), 0);
  transition:transform .35s cubic-bezier(.2,.8,.3,1);
}

/* ---------- scroll reveal ---------- */
/*  Delay is set per element by initReveal() so a panel's contents cascade in
    document order rather than all landing on the same frame.                 */
.reveal{
  opacity:0;
  transform:translateY(18px);
  transition:opacity var(--dur-slower) var(--ease-out),
             transform var(--dur-slower) var(--ease-out);
}
.reveal.is-visible{opacity:1;transform:none;}
@media (prefers-reduced-motion:reduce){
  .reveal{transition-delay:0ms !important;}
}

/* ==========================================================================
   10. RESPONSIVE
   ========================================================================== */

/*  One ladder: 1200 / 1024 / 768 / 480. Grids step down a level at a time so
    there is never a jump straight from four columns to one.                   */

@media (max-width:1200px){
  .why-grid{grid-template-columns:repeat(3,1fr);}
}

@media (max-width:1024px){
  .hero-inner{grid-template-columns:1fr;}
  .hero-visual{max-width:100%;aspect-ratio:4/3;}
  .about-grid,.coverage-grid,.quote-grid,.contact-section-grid{grid-template-columns:1fr;}
  /*  Stacked under the copy there is width to spare but not height, so drive
      sizing off width instead of the desktop's height budget.               */
  .coverage-map-wrap{height:auto;width:min(100%, 260px);}
  /*  width:100% is load-bearing. margin-inline:auto cancels a grid item's
      stretch alignment, which left the wrap sized to fit-content - and its
      content width came from .about-visual's min-height run back through
      aspect-ratio (34vh x 16/9 = 510px on a 390x844 phone). The photo then
      overhung a 335px track by 175px and dragged the About copy out with it,
      both of them cropped by #about's overflow:hidden. Giving the wrap a
      definite width makes .about-visual stretch to the track instead, so
      min-height only ever sets the height.                                    */
  .about-visual-wrap{width:100%;max-width:560px;margin-inline:auto;}
  .about-visual{aspect-ratio:16/9;}
  .why-grid{grid-template-columns:repeat(2,1fr);}
  .dog-feature{grid-template-columns:1fr;}
  .dog-feature .visual{min-height:320px;}
  .footer-grid{grid-template-columns:1fr 1fr;}
  .legal-layout{grid-template-columns:1fr;gap:var(--space-8);}
  .legal-toc{position:static;}
  .svc-detail{grid-template-columns:1fr;}
  .svc-detail.flip .svc-media{order:0;}
  .svc-index{grid-template-columns:repeat(2,1fr);}
  .cta-strip .wrap{flex-direction:column;align-items:flex-start;}
  .contact-bar .wrap{flex-direction:column;align-items:flex-start;}
  .contact-bar .wrap .btn{width:100%;}
}

@media (max-width:768px){
  /*  The dock takes over exactly where the header CTA drops out, so Request a
      Quote is always reachable and never duplicated. 84px clears the pill's
      own height (44px content + 8px padding) plus its 16px bottom margin and
      a little breathing room above it for the FAB stack and cookie banner.    */
  .pill-nav{display:flex;}
  body{--bottom-bar-h:84px;}

  form.quote-form{grid-template-columns:1fr;padding:var(--space-6);}
  .contact-grid{flex-direction:column;gap:var(--space-4);}
  .cookie-banner .wrap{flex-direction:column;align-items:stretch;}
  .cookie-actions .btn{flex:1;}

  /*  Five columns can't hold a tier name, its description and the "Current
      Level" flag — at 320px the flag alone is 77px in a 54px column, which is
      what pushed the page into horizontal scroll. Stacking also lets every
      tier keep its description instead of hiding it.                          */
  .threat-bar{grid-template-columns:1fr;gap:var(--space-2);}
  /*  Grid rather than a wrapping flex row. flex-basis:100% is supposed to put
      the description on a line of its own; it shared the row with the tier
      name anyway and ran past the viewport edge at 320px. An explicit
      two-column grid with the description spanning both columns states the
      same layout without depending on line-breaking behaviour.               */
  .threat-tier{
    display:grid;
    grid-template-columns:auto 1fr;
    align-items:center;
    gap:var(--space-1) var(--space-3);
    text-align:left;
    padding:var(--space-3) var(--space-4);
  }
  .threat-tier .name{grid-column:1;grid-row:1;}
  .threat-tier .desc{grid-column:1 / -1;grid-row:2;margin-top:0;min-width:0;}
  .threat-tier.is-current::before{
    grid-column:2;grid-row:1;justify-self:end;
    position:static;transform:none;
  }
}

@media (max-width:480px){
  /*  Narrower cards below 480px so a second one is always peeking in at the
      edge - a lane showing exactly one card reads as a broken carousel rather
      than a moving belt.                                                      */
  .accred-card{flex-basis:min(76vw, 268px);}
  .accred-img{height:clamp(96px, 15vh, 124px);}

  .why-grid,.footer-grid,.svc-index{grid-template-columns:1fr;}
  .hero-ctas .btn,.error-actions .btn,.svc-cta .btn,.cta-strip .btns .btn{width:100%;}
  .hero-ctas,.svc-cta,.cta-strip .btns{width:100%;}
  .stat-row{grid-template-columns:1fr;gap:var(--space-3);}
  .stat-card{flex-direction:row;align-items:center;}
  .about-points li{width:100%;}
  .dog-points li{width:100%;}
  .about-ctas .btn{width:100%;}
  :root{--fab-size:50px;}
  .whatsapp-float svg{width:24px;height:24px;}
  .faq-q{padding:var(--space-4) var(--space-5);}
  .faq-a{padding:0 var(--space-5) var(--space-5);}
}

/* ==========================================================================
   11. REDUCED MOTION & PRINT
   ========================================================================== */

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  .reveal{opacity:1;transform:none;transition:none;}
  .scanline,.whatsapp-float::before,.scroll-cue-dot{animation:none;}
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
  }
}

@media print{
  header,.pill-nav,.whatsapp-float,.to-top,.cookie-banner,
  .nav-backdrop,.scanline,.hero-visual,.map-block,form.quote-form,.testi-nav,
  .testi-dots,.panel-rail,.scroll-cue{display:none;}
  .hero::after,.page-hero::after,.cta-strip::after,.dog-feature::before,
  .quote-section::before,.auth-section::before,.dash-section::before,.error-page::before,
  footer::before,.bg-navy::before,.bg-charcoal::before{display:none;}
  body{background:#fff;color:#000;}
  .hero,.bg-navy,.bg-charcoal,.quote-section,.dog-feature,footer,.page-hero{background:#fff;color:#000;}
  h1,h2,h3,h4,.hero h1{color:#000;}
  section{padding:var(--space-5) 0;page-break-inside:avoid;}
  a[href^="http"]::after{content:" (" attr(href) ")";font-size:10px;color:#555;}
  .reveal{opacity:1;transform:none;}
}