/* ==========================================================================
   RegReady Care Consultancy - design system
   Tokens derived from the approved brand sheet and the approved slide deck.
   Colours were sampled directly from the deck PDF, not approximated.
   ========================================================================== */

/* Poppins, self-hosted. Not a variable font, so one file per weight; latin
   subset only, which covers British English including the pound sign. */
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-600.woff2') format('woff2');
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  src: url('/assets/fonts/poppins-800.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- tokens ------------------------------------------------------- */

:root {
  /* brand
     Green has two documented shades, and the rule is consistent site-wide:
     --green      #2EA353  the brand green from the sheet. Decorative only:
                           ticks, icons, rules, focus ring, chip borders.
     --green-text #1A7A3B  the same hue darkened to clear WCAG AA. Used for
                           every green *word*, and for any green surface that
                           carries white text (buttons, step markers).
     The brand green at 15px reads 3.24:1 on white, which fails AA, so text
     never uses it. */
  --navy: #13335B;
  --navy-deep: #0C2444;
  --green: #2EA353;
  --green-text: #1A7A3B;
  --green-deep: #146030;

  /* semantic - light */
  --surface: #FFFFFF;
  --surface-alt: #F1F4F6;
  --surface-sunk: #E7ECF1;
  --surface-inv: #13335B;
  --surface-inv-alt: #1B4070;

  --heading: #13335B;
  --body: #5B6676;
  --muted: #616B79;
  --accent: #2EA353;
  --accent-text: #1A7A3B;
  --accent-hover: #146030;

  --on-inv: #FFFFFF;
  --on-inv-body: #AFBDD1;
  --on-inv-line: rgba(255, 255, 255, 0.16);
  --accent-inv: #4CC172;

  --line: #DEE4EB;
  --line-strong: #C8D2DD;

  --focus: #2EA353;

  /* elevation - tinted to the brand navy, never flat black */
  --lift-1: 0 1px 2px rgba(19, 51, 91, 0.04), 0 6px 18px rgba(19, 51, 91, 0.05);
  --lift-2: 0 2px 4px rgba(19, 51, 91, 0.05), 0 14px 34px rgba(19, 51, 91, 0.08);
  --lift-3: 0 4px 8px rgba(19, 51, 91, 0.06), 0 22px 52px rgba(19, 51, 91, 0.13);
  /* Hover shadow for the green CTA, tinted to the button rather than to navy,
     so the lift reads as the button's own rather than a grey drop shadow. */
  --lift-green: 0 2px 6px rgba(26, 122, 59, 0.22), 0 14px 30px rgba(26, 122, 59, 0.24);

  /* shape: cards 14px, controls 8px, chips full. One documented rule. */
  --r-card: 14px;
  --r-control: 8px;
  --r-chip: 999px;

  /* spacing scale */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.5rem;
  --s-6: 2rem;
  --s-7: 3rem;
  --s-8: 4rem;
  --s-9: 6rem;
  --s-10: 8rem;

  --shell: 1200px;
  --gutter: clamp(1.25rem, 4vw, 3rem);

  /* type scale */
  /* Capped so the six-word positioning line holds to two lines at every width. */
  --fs-display: clamp(1.95rem, 1.2rem + 2.35vw, 2.6rem);
  --fs-h1: clamp(1.65rem, 1.1rem + 2.1vw, 2.6rem);
  --fs-h2: clamp(1.38rem, 1.05rem + 1.35vw, 2rem);
  --fs-h3: clamp(1.15rem, 1.05rem + 0.35vw, 1.3rem);
  --fs-body: 1.0625rem;
  --fs-sm: 0.9375rem;
  --fs-xs: 0.8125rem;
  --fs-label: 0.75rem;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  /* Micro-interaction easing. Decelerates hard and settles with a ~2% overshoot,
     which reads as "alive" without the dated elastic bounce. */
  --spring: cubic-bezier(0.22, 1.12, 0.36, 1);

  /* Tabler arrow-right, inlined as a mask so CTAs get a moving arrow with no
     markup change. */
  --arrow-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='M13 18l6-6'/%3E%3Cpath d='M13 6l6 6'/%3E%3C/svg%3E");
}

@media (prefers-color-scheme: dark) {
  :root {
    /* The brand sheet sanctions a reversed, dark treatment. Dark mode stays
       inside the navy family rather than inventing a new neutral palette. */
    --surface: #0D2140;
    --surface-alt: #0A1B33;
    --surface-sunk: #081628;
    --surface-inv: #071527;
    --surface-inv-alt: #102E52;

    --heading: #EDF2F7;
    --body: #A9B9CB;
    --muted: #8C9BB0;
    --accent: #45BC6B;
    /* On dark surfaces the lighter green already clears AA, so both roles
       collapse to one value. */
    --accent-text: #45BC6B;
    --accent-hover: #63CE85;

    --on-inv: #FFFFFF;
    --on-inv-body: #A3B4C8;
    --on-inv-line: rgba(255, 255, 255, 0.12);

    --line: rgba(255, 255, 255, 0.13);
    --line-strong: rgba(255, 255, 255, 0.22);

    --focus: #45BC6B;

    --lift-1: 0 1px 2px rgba(0, 0, 0, 0.28), 0 6px 18px rgba(0, 0, 0, 0.24);
    --lift-2: 0 2px 4px rgba(0, 0, 0, 0.3), 0 16px 38px rgba(0, 0, 0, 0.34);
  }
}

/* ---------- reset -------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  font-family: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: var(--fs-body);
  line-height: 1.7;
  color: var(--body);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }
h1, h2, h3, h4 {
  color: var(--heading);
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.15;
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); font-weight: 700; letter-spacing: -0.015em; line-height: 1.35; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; }
a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 3px;
}

.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -100px;
  z-index: 100;
  background: var(--surface-inv);
  color: var(--on-inv);
  padding: var(--s-3) var(--s-5);
  border-radius: var(--r-control);
  font-weight: 600;
  text-decoration: none;
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: var(--s-4); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- layout primitives -------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: clamp(3.5rem, 2rem + 6vw, 6.5rem); }
.section--tight { padding-block: clamp(2.75rem, 1.75rem + 4vw, 4.5rem); }
.section--alt { background: var(--surface-alt); }
.section--inv { position: relative; isolation: isolate; overflow: hidden; background: var(--surface-inv); }

/* Navy sections get one soft brand field so they read as a lit surface rather
   than a flat block. Painted once, never animated. */
.section--inv::before {
  content: '';
  position: absolute;
  inset: -40% -20% auto -20%;
  height: 180%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(46% 42% at 82% 6%, rgba(46, 163, 83, 0.13), transparent 68%),
    radial-gradient(52% 46% at 4% 96%, rgba(120, 170, 255, 0.07), transparent 70%);
}

/* Section overlap.
   Pulls a block up over the boundary above it so the two bands interlock
   instead of butting together. Used on two places sitewide, not everywhere. */
.overlap-up {
  position: relative;
  z-index: 1;
  margin-top: calc(-1 * clamp(2.5rem, 1.5rem + 4vw, 5rem));
}
.section--pad-for-overlap { padding-bottom: clamp(5rem, 3rem + 8vw, 9rem); }

.section--inv,
.section--inv p,
.section--inv li { color: var(--on-inv-body); }
.section--inv h1,
.section--inv h2,
.section--inv h3,
.section--inv h4,
.section--inv strong { color: var(--on-inv); }

.stack > * + * { margin-top: var(--s-4); }
.stack-lg > * + * { margin-top: var(--s-6); }

.lede {
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem);
  line-height: 1.65;
  max-width: 60ch;
}
.measure { max-width: 64ch; }
.measure-sm { max-width: 52ch; }

.eyebrow {
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-text);
  margin-bottom: var(--s-3);
}

.section-head { max-width: 62ch; margin-bottom: clamp(2rem, 1.25rem + 2.5vw, 3.25rem); }
.section-head p { margin-top: var(--s-4); }

.hairline { border: 0; border-top: 1px solid var(--line); margin: 0; }
.section--inv .hairline { border-color: var(--on-inv-line); }

/* ---------- brand lockup --------------------------------------------------
   Mark and wordmark are both approved artwork from the brand sheet. Nothing
   here is typeset, so the logo cannot drift when the site font changes.
   --lockup-size is the one dial: everything scales from it.
   ------------------------------------------------------------------------- */

.lockup {
  display: inline-flex;
  align-items: center;
  gap: 0.62em;
  text-decoration: none;
  font-size: var(--lockup-size, 15px);
  line-height: 0;
}
@media (max-width: 560px) {
  /* Keeps the lockup to roughly a third of a 390px screen, so it reads as a
     logo rather than as the page's main content. */
  .lockup { font-size: 10.5px; gap: 0.55em; }
}
.lockup > picture { display: block; flex: none; line-height: 0; }
.lockup__mark { width: 2.55em; height: auto; flex: none; }
.lockup__type { width: 9.4em; height: auto; flex: none; }

/* ---------- buttons ------------------------------------------------------- */

.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 0.8rem 1.4rem;
  border-radius: var(--r-control);
  border: 1px solid transparent;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 700;
  letter-spacing: -0.005em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background-color 0.24s var(--ease), border-color 0.24s var(--ease),
    color 0.24s var(--ease), transform 0.26s var(--spring), box-shadow 0.26s var(--ease);
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); transition-duration: 0.08s; }
@media (prefers-reduced-motion: reduce) {
  .btn:hover, .btn:active { transform: none; }
}

/* The trailing arrow is drawn with a mask from the Tabler arrow-right path, so
   the motion works on every CTA without touching markup on fourteen pages.
   Its width is reserved permanently and only transform/opacity animate, so
   hovering never reflows the label. */
.btn--primary::after,
.btn--navy::after {
  content: '';
  width: 15px;
  height: 15px;
  flex: none;
  background: currentColor;
  opacity: 0.7;
  -webkit-mask: var(--arrow-mask) no-repeat center / contain;
  mask: var(--arrow-mask) no-repeat center / contain;
  transition: transform 0.3s var(--spring), opacity 0.22s var(--ease);
}
.btn--primary:hover::after,
.btn--primary:focus-visible::after,
.btn--navy:hover::after,
.btn--navy:focus-visible::after {
  transform: translateX(4px);
  opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
  .btn--primary:hover::after, .btn--navy:hover::after { transform: none; }
}

.btn--primary { background: var(--green-text); color: #FFFFFF; box-shadow: var(--lift-1); }
.btn--primary:hover { background: var(--green-deep); box-shadow: var(--lift-green); }

.btn--navy { background: var(--navy); color: #FFFFFF; box-shadow: var(--lift-1); }
.btn--navy:hover { background: var(--navy-deep); box-shadow: var(--lift-2); }

.btn--ghost {
  background: transparent;
  color: var(--heading);
  border-color: var(--line-strong);
}
.btn--ghost:hover {
  border-color: var(--heading);
  background: var(--surface-alt);
  box-shadow: var(--lift-1);
}

.btn--on-inv {
  background: transparent;
  color: var(--on-inv);
  border-color: rgba(255, 255, 255, 0.4);
}
.btn--on-inv:hover { background: rgba(255, 255, 255, 0.12); border-color: #FFFFFF; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
  align-items: center;
}

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--accent-text);
  text-decoration: none;
}
.link-arrow svg { transition: transform 0.22s var(--ease); }
.link-arrow:hover { color: var(--accent-hover); }
.link-arrow:hover svg { transform: translateX(3px); }
@media (prefers-reduced-motion: reduce) {
  .link-arrow:hover svg { transform: none; }
}

/* ---------- header -------------------------------------------------------- */

.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid transparent;
  transition: background-color 0.3s var(--ease), border-color 0.3s var(--ease),
    box-shadow 0.3s var(--ease);
}
@supports not (backdrop-filter: blur(4px)) {
  .masthead { background: var(--surface); }
}
/* Set by the sentinel observer in site.js once the page has scrolled. The
   header earns its edge instead of always wearing one. */
.masthead.is-scrolled {
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(16px) saturate(140%);
  border-bottom-color: var(--line);
  box-shadow: 0 1px 0 rgba(19, 51, 91, 0.03), 0 10px 30px rgba(19, 51, 91, 0.07);
}
@media (prefers-color-scheme: dark) {
  .masthead.is-scrolled { box-shadow: 0 10px 30px rgba(0, 0, 0, 0.35); }
}

/* Zero-height probe the header observer watches. */
.scroll-sentinel {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  pointer-events: none;
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  /* Fixed height on purpose. Animating it would reflow the sticky box on every
     frame; the elevation change alone communicates the scrolled state. */
  height: 76px;
}

.nav { display: flex; align-items: center; gap: clamp(0.5rem, 1.4vw, 1.4rem); }
/* :not(.btn) so the in-menu CTA keeps its own button colours. */
.nav a:not(.btn) {
  position: relative;
  text-decoration: none;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--body);
  padding: 0.4rem 0;
  white-space: nowrap;
  transition: color 0.24s var(--ease);
}
/* Underline wipes in from the left on hover and sits permanently under the
   current page, so the indicator and the hover affordance are one idea. */
.nav a:not(.btn)::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.32s var(--ease);
}
.nav a:not(.btn):hover { color: var(--heading); }
.nav a:not(.btn):hover::after,
.nav a:not(.btn):focus-visible::after { transform: scaleX(1); }
.nav a:not(.btn)[aria-current='page'] { color: var(--heading); }
.nav a:not(.btn)[aria-current='page']::after { transform: scaleX(1); }
@media (prefers-reduced-motion: reduce) {
  .nav a:not(.btn)::after { transition: none; }
}

.masthead__actions { display: flex; align-items: center; gap: var(--s-3); }

.nav-toggle {
  display: none;
  width: 44px; height: 44px;
  align-items: center; justify-content: center;
  background: transparent;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-control);
  color: var(--heading);
  cursor: pointer;
}
.nav-toggle:hover { border-color: var(--heading); }

@media (max-width: 1040px) {
  .masthead__inner { height: 68px; }
  .nav-toggle { display: inline-flex; }
  .nav {
    position: absolute;
    inset: 100% 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--lift-2);
    padding: var(--s-3) var(--gutter) var(--s-5);
    /* Transitioned open rather than display-toggled. visibility keeps the menu
       out of the tab order while closed; transform and opacity do the motion,
       so nothing here touches layout. */
    display: flex;
    visibility: hidden;
    opacity: 0;
    transform: translateY(-8px);
    transition: opacity 0.26s var(--ease), transform 0.32s var(--ease),
      visibility 0s linear 0.32s;
  }
  .nav[data-open='true'] {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition: opacity 0.26s var(--ease), transform 0.36s var(--spring),
      visibility 0s;
  }
  .nav a:not(.btn) { padding: 0.85rem 0; border-bottom: 1px solid var(--line); font-size: 1rem; }
  /* The desktop underline indicator would sit on top of the row divider here,
     so the current page is marked with the accent rule instead. */
  .nav a:not(.btn)::after { display: none; }
  .nav a:not(.btn)[aria-current='page'] { border-bottom-color: var(--accent); }

  /* Menu items arrive just behind the panel, in reading order. */
  .nav > * {
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
  }
  .nav[data-open='true'] > * { opacity: 1; transform: none; }
  .nav[data-open='true'] > *:nth-child(1) { transition-delay: 0.04s; }
  .nav[data-open='true'] > *:nth-child(2) { transition-delay: 0.08s; }
  .nav[data-open='true'] > *:nth-child(3) { transition-delay: 0.12s; }
  .nav[data-open='true'] > *:nth-child(4) { transition-delay: 0.16s; }
  .nav[data-open='true'] > *:nth-child(5) { transition-delay: 0.2s; }
  .nav[data-open='true'] > *:nth-child(6) { transition-delay: 0.24s; }

  .masthead__actions .btn { display: none; }
  .nav .btn { display: inline-flex; margin-top: var(--s-4); }

  @media (prefers-reduced-motion: reduce) {
    .nav, .nav > * { transition: none; transform: none; }
    .nav[data-open='true'] > * { transition-delay: 0s; }
  }
}
@media (min-width: 1041px) { .nav .btn { display: none; } }

/* Hamburger reacts to press, and the icon nudges on hover. */
.nav-toggle {
  transition: border-color 0.22s var(--ease), background-color 0.22s var(--ease),
    transform 0.2s var(--spring);
}
.nav-toggle:hover { background: var(--surface-alt); }
.nav-toggle:active { transform: scale(0.94); }
.nav-toggle svg { transition: transform 0.3s var(--spring); }
.nav-toggle[aria-expanded='true'] svg { transform: rotate(90deg); }
@media (prefers-reduced-motion: reduce) {
  .nav-toggle:active { transform: none; }
  .nav-toggle[aria-expanded='true'] svg { transform: none; }
}

/* ---------- hero ---------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* Extra bottom room: the figures board overlaps up into it. */
  padding-block: clamp(2.75rem, 1.5rem + 4vw, 4.5rem) clamp(4.5rem, 3rem + 5vw, 7rem);
}

/* Depth behind the hero: two soft brand-tinted fields plus a fine grain.
   Both layers are painted once and never animate, so they cost nothing to
   scroll past. The green is held at 6% because it is an accent, not a wash. */
.hero::before {
  content: '';
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 150%;
  z-index: -2;
  background:
    radial-gradient(58% 48% at 78% 18%, rgba(46, 163, 83, 0.06), transparent 68%),
    radial-gradient(64% 56% at 8% 8%, rgba(19, 51, 91, 0.09), transparent 70%),
    radial-gradient(42% 40% at 92% 82%, rgba(19, 51, 91, 0.05), transparent 72%);
  pointer-events: none;
}
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.35;
  pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.055'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) {
  .hero::before {
    background:
      radial-gradient(58% 48% at 78% 18%, rgba(69, 188, 107, 0.09), transparent 68%),
      radial-gradient(64% 56% at 8% 8%, rgba(76, 132, 204, 0.12), transparent 70%),
      radial-gradient(42% 40% at 92% 82%, rgba(46, 163, 83, 0.05), transparent 72%);
  }
  .hero::after { opacity: 0.5; }
}

/* A single slow-drifting field, well under the content. Fifty seconds per
   cycle: enough to give the page a pulse, slow enough that nobody catches it
   moving. It is the only continuously animating thing on the site. */
@media (prefers-reduced-motion: no-preference) {
  .hero__drift {
    position: absolute;
    top: -18%;
    right: -14%;
    width: min(46rem, 68vw);
    aspect-ratio: 1;
    z-index: -2;
    border-radius: 50%;
    pointer-events: none;
    background: radial-gradient(circle at 38% 38%, rgba(46, 163, 83, 0.1), transparent 62%);
    filter: blur(24px);
    animation: drift 50s var(--ease) infinite alternate;
    will-change: transform;
  }
  @keyframes drift {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to { transform: translate3d(-4%, 3%, 0) scale(1.08); }
  }
}
.hero__drift { position: absolute; z-index: -2; pointer-events: none; }
.hero__grid {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 4rem);
  align-items: center;
  grid-template-columns: 1fr;
}
/* Two columns only once the text column is wide enough to hold the positioning
   line on two lines. Below this the hero stacks, which reads better than a
   cramped three-line headline next to a shrunken photograph. */
@media (min-width: 1040px) {
  .hero__grid { grid-template-columns: minmax(0, 1.18fr) minmax(0, 0.82fr); }
}
.hero h1 { font-size: var(--fs-display); }
.hero .lede { margin-top: var(--s-5); }
.hero .btn-row { margin-top: var(--s-6); }

/* Hero entrance.
   Driven by CSS animation rather than a JS-applied class, so the content is
   never gated behind a script that might not run. Order follows how the page
   is read: headline, then the promise, then the action, with the photograph
   arriving alongside. */
@media (prefers-reduced-motion: no-preference) {
  .hero h1 {
    animation: hero-headline 1s var(--ease) both;
    /* Clip reveal needs a little vertical slack so descenders are not shaved. */
    padding-bottom: 0.08em;
    margin-bottom: -0.08em;
  }
  .hero .lede { animation: hero-rise 0.85s var(--ease) 0.16s both; }
  .hero .btn-row { animation: hero-rise 0.85s var(--ease) 0.28s both; }
  .hero__figure { animation: hero-figure 1.1s var(--ease) 0.12s both; }

  @keyframes hero-headline {
    from { opacity: 0; transform: translateY(16px); clip-path: inset(0 0 100% 0); }
    to { opacity: 1; transform: none; clip-path: inset(0 0 -20% 0); }
  }
  @keyframes hero-rise {
    from { opacity: 0; transform: translateY(14px); }
    to { opacity: 1; transform: none; }
  }
  @keyframes hero-figure {
    from { opacity: 0; transform: translateY(20px) scale(0.985); }
    to { opacity: 1; transform: none; }
  }
}

/* Parallax.
   CSS scroll-driven timelines run off the main thread, so this costs nothing
   and cannot jank. Browsers without support simply get a static image, which
   is a perfectly good hero. The shift is ~3%: felt as depth, not noticed as
   an effect. */
@supports (animation-timeline: view()) {
  @media (min-width: 700px) and (prefers-reduced-motion: no-preference) {
    .hero__figure img {
      animation: parallax-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
      will-change: transform;
    }
    @keyframes parallax-drift {
      from { transform: scale(1.09) translateY(-2.4%); }
      to { transform: scale(1.09) translateY(2.4%); }
    }
  }
}

.hero__figure {
  position: relative;
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: var(--lift-2);
  aspect-ratio: 4 / 3.2;
}
.hero__figure img { width: 100%; height: 100%; object-fit: cover; }

/* On wide screens the photograph runs past the container into the gutter, so
   the composition is not a tidy box inside a tidy box. The hero clips its own
   overflow, so this can never create a horizontal scrollbar. */
@media (min-width: 1280px) {
  .hero__figure--bleed { margin-right: calc(-1 * clamp(0.5rem, 3vw, 2.5rem)); }
}
/* Brand colour treatment: a navy multiply layer plus a bottom scrim, per the
   deck's photographic style. */
.hero__figure::before,
.hero__figure::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.hero__figure::before { background: var(--navy); opacity: 0.1; mix-blend-mode: multiply; }
.hero__figure::after {
  background: linear-gradient(to top, rgba(12, 36, 68, 0.5), transparent 55%);
}

.page-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--surface-alt);
  border-bottom: 1px solid var(--line);
  padding-block: clamp(2.75rem, 1.75rem + 4vw, 4.75rem);
}
/* The same brand field as the homepage hero, at lower strength. Inner pages
   share the family without competing with it. */
.page-hero::before {
  content: '';
  position: absolute;
  inset: -60% -10% auto -10%;
  height: 220%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(50% 44% at 88% 10%, rgba(46, 163, 83, 0.07), transparent 68%),
    radial-gradient(56% 50% at 2% 92%, rgba(19, 51, 91, 0.06), transparent 72%);
}
.page-hero h1 { font-size: var(--fs-h1); }
.page-hero .lede { margin-top: var(--s-5); }

/* Inner-page entrance. Same grammar as the homepage hero, shorter, so moving
   between pages feels like one site rather than one animated page and
   thirteen static ones. */
@media (prefers-reduced-motion: no-preference) {
  .page-hero .crumb { animation: hero-rise 0.6s var(--ease) both; }
  .page-hero h1 { animation: hero-rise 0.7s var(--ease) 0.06s both; }
  .page-hero .lede { animation: hero-rise 0.7s var(--ease) 0.14s both; }
  .page-hero .btn-row { animation: hero-rise 0.7s var(--ease) 0.22s both; }
}

.crumb {
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--muted);
  margin-bottom: var(--s-4);
}
.crumb a { text-decoration: none; color: var(--muted); }
.crumb a:hover { color: var(--accent-text); text-decoration: underline; }
.crumb span { padding-inline: 0.4em; }

/* ---------- pillars ------------------------------------------------------- */

.pillars {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
@media (min-width: 820px) { .pillars { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* Below ~560px two columns leave a ~91px content box, which is narrower than
   single words like "Accommodation". One column, with tighter padding. */
@media (max-width: 560px) {
  .pillars { grid-template-columns: 1fr; }
  .pillars > div { padding: var(--s-5) var(--s-4); }
}
.pillars > div {
  padding: var(--s-6) var(--s-5);
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  transition: background-color 0.3s var(--ease);
}
.pillars > div:hover { background: color-mix(in srgb, var(--accent) 4%, transparent); }
.pillars svg { transition: transform 0.4s var(--spring); }
.pillars > div:hover svg { transform: translateY(-2px) scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .pillars > div:hover svg { transform: none; }
}
.pillars h3 {
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent-text);
  font-weight: 700;
  margin: var(--s-4) 0 var(--s-2);
}
.pillars p { font-size: var(--fs-sm); }
.pillars svg { color: var(--accent); }
.section--inv .pillars { border-color: var(--on-inv-line); }
.section--inv .pillars > div { border-color: var(--on-inv-line); }
.section--inv .pillars h3, .section--inv .pillars svg { color: var(--accent-inv); }

/* ---------- contrast panels (document ready / genuinely ready) ------------- */

.contrast {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: 1fr;
}
@media (min-width: 860px) { .contrast { grid-template-columns: 1fr 1.12fr; } }
/* When the two panels differ a lot in length, let them size to their content
   rather than stretching the shorter one into a field of empty space. */
.contrast--top { align-items: start; }

.panel {
  border-radius: var(--r-card);
  padding: clamp(1.5rem, 1rem + 1.6vw, 2.5rem);
  border: 1px solid var(--line);
  background: var(--surface);
}
.panel--inv {
  background: var(--surface-inv);
  border-color: transparent;
  box-shadow: var(--lift-2);
}
.panel--inv h3, .panel--inv .panel__kicker { color: var(--on-inv); }
.panel--inv p, .panel--inv li { color: var(--on-inv-body); }
/* Content nested in a navy panel needs the same inversion as a navy section. */
.panel--inv strong,
.panel--inv .num-list a,
.panel--inv .num-list strong { color: var(--on-inv); }
.panel--inv .num-list li,
.panel--inv .rule-list li { border-color: var(--on-inv-line); }
.panel--inv .num-list li::before { color: var(--accent-inv); }
.panel--inv .tick-list li::before { border-color: var(--accent-inv); }
.panel__kicker {
  font-size: var(--fs-label);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--s-4);
}
.panel--inv .panel__kicker { color: var(--accent-inv); }
.panel h3 { font-size: clamp(1.15rem, 1rem + 0.7vw, 1.45rem); margin-bottom: var(--s-4); }

.chips { display: flex; flex-wrap: wrap; gap: var(--s-2); margin: var(--s-5) 0; }
.chips li {
  list-style: none;
  border-radius: var(--r-chip);
  border: 1px solid rgba(255, 255, 255, 0.28);
  padding: 0.4rem 0.9rem;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--on-inv);
  background: rgba(255, 255, 255, 0.06);
}

/* ---------- split columns ------------------------------------------------- */

.split {
  display: grid;
  gap: clamp(2rem, 1rem + 4vw, 4.5rem);
  grid-template-columns: 1fr;
}
@media (min-width: 900px) {
  .split { grid-template-columns: 1fr 1fr; }
  .split--rule > :last-child { border-left: 1px solid var(--line); padding-left: clamp(2rem, 4vw, 4rem); }
  .section--inv .split--rule > :last-child { border-color: var(--on-inv-line); }
}

/* rule list: hairline rows, used sparingly and only where rows are scannable */
.rule-list { list-style: none; }
.rule-list li {
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--line);
  font-weight: 600;
  color: var(--heading);
}
.rule-list li:first-child { padding-top: 0; }
.section--inv .rule-list li { border-color: var(--on-inv-line); color: var(--on-inv); }

.num-list { list-style: none; counter-reset: n; }
.num-list li {
  counter-increment: n;
  display: grid;
  grid-template-columns: 2.4rem 1fr;
  gap: var(--s-3);
  align-items: baseline;
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--line);
}
.num-list li:first-child { padding-top: 0; }
.num-list li::before {
  content: '0' counter(n);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--accent-text);
}
.num-list a, .num-list strong {
  color: var(--heading);
  font-weight: 700;
  text-decoration: none;
}
.num-list a:hover { color: var(--accent-text); }
.num-list p { font-size: var(--fs-sm); margin-top: var(--s-1); }
.section--inv .num-list li { border-color: var(--on-inv-line); }
.section--inv .num-list a, .section--inv .num-list strong { color: var(--on-inv); }
.section--inv .num-list li::before { color: var(--accent-inv); }

/* ---------- cards --------------------------------------------------------- */

.card-grid {
  display: grid;
  gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 285px), 1fr));
}
.card-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr)); }
/* Exactly two columns, for content that comes in pairs and must not orphan. */
.card-grid--pair { grid-template-columns: 1fr; }
@media (min-width: 760px) { .card-grid--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
  padding: clamp(1.35rem, 1rem + 1vw, 1.9rem);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  background: var(--surface);
  text-decoration: none;
  transition: border-color 0.3s var(--ease), box-shadow 0.34s var(--ease),
    transform 0.34s var(--spring);
}
.card p { font-size: var(--fs-sm); }

/* A hairline in the brand green wipes across the top edge on hover. It reads
   as the card acknowledging the pointer without the card itself changing
   colour, which would be too loud for this brand. */
a.card::before {
  content: '';
  position: absolute;
  inset: -1px -1px auto -1px;
  height: 2px;
  border-radius: var(--r-card) var(--r-card) 0 0;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.42s var(--ease);
}
a.card:hover::before,
a.card:focus-visible::before { transform: scaleX(1); }

a.card:hover {
  border-color: color-mix(in srgb, var(--accent) 55%, var(--line));
  box-shadow: var(--lift-3);
  transform: translateY(-4px);
}
a.card:active { transform: translateY(-1px); transition-duration: 0.1s; }

/* The arrow in a card foot follows the card's own hover, not just its own. */
a.card:hover .link-arrow { color: var(--accent-hover); }
a.card:hover .link-arrow svg { transform: translateX(4px); }

@media (prefers-reduced-motion: reduce) {
  a.card:hover, a.card:active { transform: none; }
  a.card::before { transition: none; }
  a.card:hover .link-arrow svg { transform: none; }
}
.card__foot { margin-top: auto; padding-top: var(--s-3); }
.card--sunk { background: var(--surface-alt); border-color: transparent; }

/* Navy cards, used to lift the two primary routes out of a grid of white ones. */
.card--feature {
  background: var(--surface-inv);
  border-color: transparent;
  box-shadow: var(--lift-1);
}
.card--feature h3 { color: var(--on-inv); }
.card--feature p { color: var(--on-inv-body); }
.card--feature .link-arrow { color: var(--accent-inv); }
a.card--feature:hover { border-color: transparent; box-shadow: var(--lift-2); }
a.card--feature:hover .link-arrow { color: #FFFFFF; }

.tick-list { list-style: none; }
.tick-list li {
  position: relative;
  padding-left: 1.75rem;
  padding-block: 0.3rem;
  font-size: var(--fs-sm);
}
.tick-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 0.7rem;
  height: 0.38rem;
  border-left: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}
.section--inv .tick-list li::before { border-color: var(--accent-inv); }

.col-list {
  columns: 2;
  column-gap: clamp(1.5rem, 4vw, 3rem);
}
@media (max-width: 700px) { .col-list { columns: 1; } }
.col-list li { break-inside: avoid; }

/* ---------- process ------------------------------------------------------- */

.process {
  display: grid;
  gap: var(--s-8) clamp(1.25rem, 2.5vw, 2.25rem);
  /* Fixed column counts so the six steps never orphan a single item on a row. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  counter-reset: step;
  list-style: none;
}
@media (min-width: 620px) { .process { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1000px) { .process { grid-template-columns: repeat(6, minmax(0, 1fr)); } }
.process li {
  counter-increment: step;
  position: relative;
  padding-top: 3.75rem;
}
.process li::before {
  content: counter(step);
  position: absolute;
  top: 0;
  left: 0;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--r-chip);
  display: grid;
  place-items: center;
  font-weight: 700;
  font-size: var(--fs-sm);
  color: #FFFFFF;
  background: var(--navy);
}
.process li:nth-child(3)::before,
.process li:nth-child(6)::before { background: var(--green-text); }
.process li strong {
  display: block;
  color: var(--heading);
  font-weight: 700;
  font-size: var(--fs-sm);
  line-height: 1.4;
  letter-spacing: -0.01em;
}
.process li p {
  font-size: var(--fs-sm);
  line-height: 1.6;
  margin-top: var(--s-3);
  color: var(--body);
}
/* Labels run to one or two lines depending on the wording. Reserving two lines
   keeps every description starting on the same baseline across the row, which
   is what stops the six steps reading as ragged. */
@media (min-width: 620px) {
  .process li strong { min-height: 2.8em; }
}

/* connector rule between steps, desktop only */
@media (min-width: 1000px) {
  .process li::after {
    content: '';
    position: absolute;
    top: 1.375rem;
    left: 3.25rem;
    right: calc(-1 * clamp(1.25rem, 2.5vw, 2.25rem));
    height: 1px;
    background: var(--line-strong);
  }
  .process li:last-child::after { display: none; }
}
.section--inv .process li strong { color: var(--on-inv); }
.section--inv .process li::after { background: var(--on-inv-line); }
.section--inv .process li::before { background: var(--surface-inv-alt); }
.section--inv .process li:nth-child(3)::before,
.section--inv .process li:nth-child(6)::before { background: var(--green-text); }

/* ---------- price table --------------------------------------------------- */

.price-board {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: clamp(1.25rem, 0.75rem + 2vw, 2.5rem);
  box-shadow: var(--lift-1);
}
.price-cols {
  display: grid;
  gap: 0 clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 820px) { .price-cols { grid-template-columns: 1fr 1fr; } }
.price-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-4) 0;
  border-bottom: 1px solid var(--line);
}
.price-row:last-child { border-bottom: 0; }
/* Scanning a price list is a row-by-row job, so the row acknowledges the
   pointer. Colour only: moving a table row would be noise. */
.price-row { transition: border-color 0.24s var(--ease); }
.price-row dt, .price-row dd { transition: color 0.24s var(--ease); }
.price-board:hover .price-row:hover { border-bottom-color: var(--accent); }
.price-board:hover .price-row:hover dt { color: var(--accent-text); }
.price-row dt { font-weight: 600; color: var(--heading); }
.price-row dd {
  margin: 0;
  font-weight: 700;
  color: var(--heading);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.price-row dd.is-accent { color: var(--accent-text); }
.price-note { font-size: var(--fs-sm); color: var(--muted); margin-top: var(--s-5); }

/* ---------- contact ------------------------------------------------------- */

.contact-list { list-style: none; display: grid; gap: var(--s-4); }
.contact-list li { display: flex; gap: var(--s-3); align-items: flex-start; }
.contact-list svg { color: var(--accent); flex: none; margin-top: 0.35rem; }
.section--inv .contact-list svg { color: var(--accent-inv); }
.contact-list a { font-weight: 700; color: var(--heading); text-decoration: none; }
.contact-list a:hover { color: var(--accent-text); text-decoration: underline; }
.section--inv .contact-list a { color: var(--on-inv); }
.section--inv .contact-list a:hover { color: var(--accent-inv); }

.form { display: grid; gap: var(--s-5); }
.field { display: grid; gap: var(--s-2); }
.field label { font-weight: 700; font-size: var(--fs-sm); color: var(--heading); }
.field .hint { font-size: var(--fs-xs); color: var(--muted); }
.field input,
.field select,
.field textarea {
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--heading);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-control);
  padding: 0.8rem 0.9rem;
  width: 100%;
  transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}
.field textarea { min-height: 8rem; resize: vertical; }
.field input::placeholder,
.field textarea::placeholder { color: var(--muted); }
.field input:hover,
.field select:hover,
.field textarea:hover { border-color: var(--heading); }
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent);
}
.field .error { font-size: var(--fs-xs); font-weight: 600; color: #C0392B; }
@media (prefers-color-scheme: dark) { .field .error { color: #FF8F80; } }
.field[data-invalid='true'] input,
.field[data-invalid='true'] textarea,
.field[data-invalid='true'] select { border-color: #C0392B; }

.form-status {
  border-radius: var(--r-control);
  border: 1px solid var(--line);
  background: var(--surface-alt);
  padding: var(--s-4) var(--s-5);
  font-size: var(--fs-sm);
}
.form-status[hidden] { display: none; }

/* ---------- callout / CTA band -------------------------------------------- */

.cta-band {
  display: grid;
  gap: var(--s-5) clamp(2rem, 5vw, 4rem);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 860px) { .cta-band { grid-template-columns: 1.4fr auto; } }

.note {
  background: var(--surface-alt);
  border-radius: var(--r-control);
  padding: var(--s-4) var(--s-5);
  font-size: var(--fs-sm);
}
.section--alt .note { background: var(--surface-sunk); }
.section--inv .note { background: rgba(255, 255, 255, 0.06); }

/* ---------- footer -------------------------------------------------------- */

.footer {
  background: var(--surface-inv);
  color: var(--on-inv-body);
  padding-block: clamp(3rem, 2rem + 3vw, 4.5rem) var(--s-6);
}
.footer__grid {
  display: grid;
  gap: var(--s-7) clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 760px) { .footer__grid { grid-template-columns: 1.3fr 1fr 1fr; } }
.footer h2 {
  font-size: var(--fs-label);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--on-inv);
  font-weight: 700;
  margin-bottom: var(--s-4);
}
.footer ul { list-style: none; display: grid; gap: var(--s-3); }
.footer a { color: var(--on-inv-body); text-decoration: none; font-size: var(--fs-sm); }
.footer a:hover { color: var(--on-inv); text-decoration: underline; }
.footer__base {
  margin-top: var(--s-7);
  padding-top: var(--s-5);
  border-top: 1px solid var(--on-inv-line);
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-5);
  justify-content: space-between;
  font-size: var(--fs-xs);
}

/* ---------- reveal engine -------------------------------------------------
   One system for the whole site. Elements carry data-anim with a variant, and
   site.js adds .is-in when they enter the viewport, once.

   Three safety rules, in order of importance:
     1. Gated on html.js, set by an inline script in <head>. Without JS nothing
        is ever hidden, so the page renders complete for crawlers, for readers
        with JS off, and in any renderer that does not run scripts.
     2. Gated on prefers-reduced-motion: no-preference.
     3. site.js also settles everything immediately if IntersectionObserver is
        missing.
   ------------------------------------------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  html.js [data-anim] {
    opacity: 0;
    transition: opacity 0.7s var(--ease), transform 0.7s var(--ease),
      clip-path 0.8s var(--ease);
    transition-delay: var(--anim-delay, 0s);
  }

  html.js [data-anim='up'] { transform: translateY(22px); }
  html.js [data-anim='fade'] { transform: none; }
  html.js [data-anim='left'] { transform: translateX(-24px); }
  html.js [data-anim='right'] { transform: translateX(24px); }
  html.js [data-anim='scale'] { transform: scale(0.96); }
  /* Curtain reveal, for photographs and the panels that carry the argument. */
  html.js [data-anim='clip'] {
    transform: translateY(16px);
    clip-path: inset(0 0 100% 0);
  }

  html.js [data-anim].is-in {
    opacity: 1;
    transform: none;
    clip-path: inset(0 0 -20% 0);
  }

  /* Stagger. Only the parent carries markup; the children are animated by
     descent and pick up an index from nth-child. The parent is what gets
     observed, so every child starts from the same instant and the delays read
     as one movement with internal order rather than a queue of separate
     events. 70ms is the step. */
  html.js [data-anim-group] > * {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
    transition-delay: var(--anim-delay, 0s);
  }
  html.js [data-anim-group].is-in > * { opacity: 1; transform: none; }

  html.js [data-anim-group] > *:nth-child(1) { --anim-delay: 0s; }
  html.js [data-anim-group] > *:nth-child(2) { --anim-delay: 0.07s; }
  html.js [data-anim-group] > *:nth-child(3) { --anim-delay: 0.14s; }
  html.js [data-anim-group] > *:nth-child(4) { --anim-delay: 0.21s; }
  html.js [data-anim-group] > *:nth-child(5) { --anim-delay: 0.28s; }
  html.js [data-anim-group] > *:nth-child(6) { --anim-delay: 0.35s; }
  html.js [data-anim-group] > *:nth-child(7) { --anim-delay: 0.42s; }
  html.js [data-anim-group] > *:nth-child(8) { --anim-delay: 0.49s; }
  html.js [data-anim-group] > *:nth-child(n + 9) { --anim-delay: 0.56s; }

  /* Section heads: the rule above the heading draws itself in. Used sparingly,
     only where a section opens a new argument. */
  html.js .section-head[data-anim] .eyebrow { position: relative; }
}

/* ---------- counters ------------------------------------------------------ */

/* The elevated surface the figures sit on. It is what actually straddles the
   section boundary, so the overlap reads as a deliberate object rather than
   as content that slipped upward. */
.stat-board {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--lift-3);
  padding: clamp(1.5rem, 1rem + 2vw, 2.75rem);
}

.stat-band {
  display: grid;
  gap: var(--s-5) clamp(1.5rem, 4vw, 3rem);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (min-width: 860px) { .stat-band { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.stat { border-top: 1px solid var(--line); padding-top: var(--s-4); }
.section--inv .stat { border-color: var(--on-inv-line); }
.stat__figure {
  display: flex;
  align-items: baseline;
  gap: 0.18em;
  font-size: clamp(2.1rem, 1.4rem + 2.4vw, 3.1rem);
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1;
  color: var(--heading);
  /* Tabular figures so a counter running 0 to 90 never changes width and
     never shifts the layout beside it. */
  font-variant-numeric: tabular-nums;
}
.section--inv .stat__figure { color: var(--on-inv); }
.stat__unit { font-size: 0.42em; font-weight: 700; letter-spacing: -0.01em; color: var(--accent-text); }
.section--inv .stat__unit { color: var(--accent-inv); }
.stat__label {
  margin-top: var(--s-3);
  font-size: var(--fs-sm);
  line-height: 1.5;
  max-width: 26ch;
}

/* ---------- people --------------------------------------------------------
   Named leaders on the About page. Deliberately not a card grid: the page
   already runs a card grid for ethics and a ruled split for the experience
   lists, so this reads as photo-plus-prose rows divided by a hairline. Two
   people, two rows. If a third is added the pattern extends without change.
   -------------------------------------------------------------------------- */

.people { display: grid; gap: clamp(2.25rem, 1.5rem + 2.5vw, 3.5rem); }

.person {
  display: grid;
  gap: clamp(1.25rem, 0.75rem + 2vw, 2.5rem);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 760px) {
  .person { grid-template-columns: minmax(0, 220px) minmax(0, 1fr); }
}
.person + .person {
  border-top: 1px solid var(--line);
  padding-top: clamp(2.25rem, 1.5rem + 2.5vw, 3.5rem);
}

.person__photo {
  display: block;
  width: 100%;
  max-width: 220px;
  /* The width/height attributes stay on the tag so the box is reserved before
     the file lands, but the height attribute maps to a presentational
     height that beats aspect-ratio and stretches the frame. height:auto puts
     aspect-ratio back in charge, so the frame is square whatever the source. */
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: var(--r-card);
  border: 1px solid var(--line);
  box-shadow: var(--lift-1);
  /* Reserves the box before the file lands, so nothing shifts on load. */
  background: var(--surface-sunk);
}

.person__name { font-size: var(--fs-h3); }
.person__role {
  margin-top: var(--s-2);
  font-size: var(--fs-sm);
  font-weight: 700;
  color: var(--accent-text);
}
.person__credential {
  margin-top: 0.2rem;
  font-size: var(--fs-xs);
  color: var(--muted);
}
.person__bio { margin-top: var(--s-4); max-width: 62ch; }
.person__bio > * + * { margin-top: var(--s-4); }

/* ---------- consent banner ------------------------------------------------
   Only rendered when GA4_MEASUREMENT_ID is set in build.mjs. Sits above the
   sticky masthead (z-index 100) because it blocks a legal decision. Colours
   come from the same tokens as everything else, so dark mode needs no extra
   rules.
   -------------------------------------------------------------------------- */
.consent {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 120;
  padding: var(--s-4);
  padding-bottom: max(var(--s-4), env(safe-area-inset-bottom));
  pointer-events: none;
}
.consent__panel {
  pointer-events: auto;
  max-width: var(--shell);
  margin-inline: auto;
  display: grid;
  gap: var(--s-5);
  align-items: center;
  padding: var(--s-5);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--lift-3);
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 0.32s var(--ease), transform 0.36s var(--spring);
}
.consent.is-open .consent__panel { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .consent__panel { transition: none; opacity: 1; transform: none; }
}
@media (min-width: 800px) {
  .consent__panel { grid-template-columns: minmax(0, 1fr) auto; }
}
.consent__title {
  font-size: var(--fs-h3);
  color: var(--heading);
  line-height: 1.3;
}
.consent__text {
  margin-top: var(--s-2);
  max-width: 62ch;
  font-size: var(--fs-sm);
  color: var(--body);
}
.consent__text a { color: var(--accent-text); }
.consent__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}
.consent__actions .btn { flex: 1 1 auto; }
@media (min-width: 800px) {
  .consent__actions .btn { flex: 0 0 auto; }
}
/* The moving arrow belongs to forward-navigation CTAs, not to a yes/no choice. */
.consent .btn--primary::after { content: none; }
