/* ==========================================================================
   Progress Education — progresseducation.ca
   Palette, type and spacing per brand-assets/brand-guide.md v1.2
   Section 0: tokens, reset, base typography, shared primitives.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Font — self-hosted Plus Jakarta Sans, variable weight axis 200–800.
   One 32 KB file covers every weight the brand guide calls for.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: "Plus Jakarta Sans";
  src: url("../fonts/PlusJakartaSans-Variable.woff2") format("woff2-variations"),
       url("../fonts/PlusJakartaSans-Variable.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   2. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Brand palette — brand-guide §3. Change a hex here, not in the rules. */
  --navy:     #0B2E3A;  /* wordmark, body text, dark backgrounds */
  --teal:     #0E5E6F;  /* primary: buttons, headers, links       */
  --coral:    #FF7A59;  /* accent: ~5% of the page, never text on white */
  --amber:    #FFC16B;  /* secondary accent, sparingly            */
  --lagoon:   #3FA7A3;  /* secondary teal: dividers, decoration    */
  --seafoam:  #9ED8D2;  /* secondary text on dark                  */
  --mist:     #E8F3F2;  /* light section backgrounds, cards        */
  --slate:    #51656D;  /* secondary text on light                 */
  --white:    #FFFFFF;

  /* Semantic aliases — what the rules below actually reference. */
  --text:            var(--navy);
  --text-secondary:  var(--slate);
  --text-on-dark:            var(--white);
  --text-secondary-on-dark:  var(--seafoam);
  --surface:         var(--white);
  --surface-alt:     var(--mist);
  --surface-dark:    var(--navy);
  --border:          #D3E4E2;
  --border-on-dark:  rgba(158, 216, 210, 0.28);

  --font: "Plus Jakarta Sans", "Segoe UI", Helvetica, Arial, sans-serif;

  /* Fluid type — brand-guide §4 size guide, scaled between 360px and 1160px.
     H1 32→56px · H2 28→40px · H3 20→28px · body 16→18px */
  --fs-h1:      clamp(2rem,    1.40rem + 2.67vw, 3.5rem);
  --fs-h2:      clamp(1.75rem, 1.45rem + 1.33vw, 2.5rem);
  --fs-h3:      clamp(1.25rem, 1.15rem + 0.44vw, 1.75rem);
  --fs-lead:    clamp(1.125rem, 1.05rem + 0.33vw, 1.375rem);
  --fs-body:    clamp(1rem,    0.98rem + 0.11vw, 1.125rem);
  --fs-small:   0.9375rem;
  --fs-caption: 0.8125rem;

  --lh-tight: 1.15;
  --lh-snug:  1.35;
  --lh-body:  1.6;

  /* Spacing — 4px base */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;   --sp-3: 0.75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;   --sp-6: 2rem;     --sp-7: 2.5rem;   --sp-8: 3rem;
  --sp-9: 4rem;     --sp-10: 5rem;    --sp-11: 6rem;

  /* Vertical rhythm between sections — one knob for the whole page */
  --section-y: clamp(3.5rem, 2.5rem + 4.5vw, 6.5rem);

  --container: 1160px;
  --gutter: clamp(1.25rem, 0.9rem + 1.5vw, 2.5rem);

  --radius-sm: 8px;
  --radius:    16px;
  --radius-lg: 24px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(11, 46, 58, 0.06), 0 2px 8px rgba(11, 46, 58, 0.04);
  --shadow:    0 2px 4px rgba(11, 46, 58, 0.05), 0 8px 24px rgba(11, 46, 58, 0.07);
  --shadow-lg: 0 4px 8px rgba(11, 46, 58, 0.06), 0 16px 48px rgba(11, 46, 58, 0.10);

  --header-h: 76px;
  --header-h-scrolled: 64px;

  /* Motion. One easing vocabulary for the whole site.
     --ease-out is the workhorse: fast start, long settle. Things arrive
     with intent and stop; nothing bounces or overshoots. */
  --ease:        cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out:    cubic-bezier(0.16, 1.00, 0.30, 1.00);
  --ease-in-out: cubic-bezier(0.65, 0.00, 0.35, 1.00);
  --speed-fast:  150ms;
  --speed:       250ms;
  --speed-slow:  600ms;
  --speed-reveal: 700ms;
}

/* --------------------------------------------------------------------------
   3. Reset
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor targets clear the sticky header instead of hiding under it. */
  scroll-padding-top: calc(var(--header-h) + var(--sp-4));
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-body);
  font-weight: 400;
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--surface);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; }
li { list-style: none; }

img, svg, picture, video { display: block; max-width: 100%; }
img { height: auto; }

button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; padding: 0; cursor: pointer; }

/* --------------------------------------------------------------------------
   4. Base typography — brand-guide §4
   -------------------------------------------------------------------------- */
h1, h2, h3, h4 {
  font-weight: 800;
  line-height: var(--lh-tight);
  letter-spacing: -0.01em;
  text-wrap: balance;      /* keeps headline last lines from stranding a word */
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); font-weight: 700; }
h3 { font-size: var(--fs-h3); font-weight: 600; line-height: var(--lh-snug); letter-spacing: -0.005em; }
h4 { font-size: 1.125rem;     font-weight: 600; line-height: var(--lh-snug); letter-spacing: 0; }

p { text-wrap: pretty; }

a {
  color: var(--teal);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--speed) var(--ease);
}
a:hover { color: var(--navy); }

strong, b { font-weight: 700; }

.lead {
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--text-secondary);
}

/* Small eyebrow label above section headings */
.eyebrow {
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--teal);
  margin-bottom: var(--sp-3);
}

/* Legal / fine print — brand-guide §9 */
.fineprint {
  font-size: var(--fs-caption);
  color: var(--text-secondary);
  line-height: 1.5;
}

/* --------------------------------------------------------------------------
   5. Layout primitives
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--section-y); }
.section--alt  { background: var(--surface-alt); }
.section--dark { background: var(--surface-dark); color: var(--text-on-dark); }
.section--dark h1, .section--dark h2, .section--dark h3 { color: var(--text-on-dark); }
.section--dark p  { color: var(--text-secondary-on-dark); }

/* Measure: body copy stays readable, never a 1160px-wide paragraph */
.measure    { max-width: 62ch; }
.measure--narrow { max-width: 48ch; }

/* --------------------------------------------------------------------------
   6. Accessibility
   -------------------------------------------------------------------------- */

/* Skip link — first tab stop, visible only when focused */
.skip-link {
  position: absolute;
  top: var(--sp-3);
  left: var(--sp-3);
  z-index: 200;
  padding: var(--sp-3) var(--sp-5);
  background: var(--navy);
  color: var(--white);
  font-weight: 600;
  border-radius: var(--radius-sm);
  text-decoration: none;
  transform: translateY(-150%);
  transition: transform var(--speed) var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); color: var(--white); }

/* One focus ring for the whole site. Coral as pure decoration — allowed,
   since brand-guide §3 bars coral as *text* on white, not as a UI outline. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--coral);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}
/* On dark backgrounds coral still clears 5.6:1 against navy. */
.section--dark :where(a, button, input, summary):focus-visible,
.site-footer :where(a, button, input, summary):focus-visible {
  outline-color: var(--coral);
}

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

/* Respect the OS "reduce motion" setting: no transforms, no smooth scroll. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Decorative SVG motifs are hidden from assistive tech in the markup
   (aria-hidden) and pinned behind content here. */
.decor {
  position: absolute;
  pointer-events: none;
  user-select: none;
  z-index: 0;
}

/* --------------------------------------------------------------------------
   7. Print — a clean page if anyone prints or saves to PDF
   -------------------------------------------------------------------------- */
@media print {
  .skip-link, .site-header, .decor { display: none !important; }
  body { color: #000; background: #fff; font-size: 11pt; }
  .section { padding-block: 1.5rem; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; color: #444; }
}

/* ==========================================================================
   8. Motion — scroll reveals
   Elements are only hidden when JS is present (html.js), so with JS blocked
   or failed the page renders fully visible instead of blank.
   ========================================================================== */
.js .reveal {
  opacity: 0;
  transform: translateY(26px);
  transition:
    opacity   var(--speed-reveal) var(--ease-out),
    transform var(--speed-reveal) var(--ease-out);
  will-change: opacity, transform;
}
.js .reveal.is-visible { opacity: 1; transform: none; will-change: auto; }

/* Stagger: children of [data-stagger] arrive one after another. */
.js [data-stagger] > .reveal:nth-child(1)  { transition-delay: 0ms;   }
.js [data-stagger] > .reveal:nth-child(2)  { transition-delay: 80ms;  }
.js [data-stagger] > .reveal:nth-child(3)  { transition-delay: 160ms; }
.js [data-stagger] > .reveal:nth-child(4)  { transition-delay: 240ms; }
.js [data-stagger] > .reveal:nth-child(5)  { transition-delay: 320ms; }
.js [data-stagger] > .reveal:nth-child(6)  { transition-delay: 400ms; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ==========================================================================
   9. Buttons
   Coral is the single accent CTA per view (brand-guide §3, ~5% of the page).
   Coral buttons always take a NAVY label — 5.6:1. Coral text on white is
   2.6:1 and is never used.
   ========================================================================== */
.btn {
  --btn-bg: var(--teal);
  --btn-fg: var(--white);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  padding: 0.8125rem 1.375rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: var(--fs-small);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.005em;
  border-radius: var(--radius-pill);
  text-decoration: none;
  white-space: nowrap;
  transition:
    background-color var(--speed) var(--ease),
    color            var(--speed) var(--ease),
    transform        var(--speed) var(--ease-out),
    box-shadow       var(--speed) var(--ease-out);
}
.btn:hover { color: var(--btn-fg); transform: translateY(-2px); box-shadow: var(--shadow); }
.btn:active { transform: translateY(0); transition-duration: var(--speed-fast); }

.btn--accent { --btn-bg: var(--coral); --btn-fg: var(--navy); }
.btn--accent:hover { --btn-bg: #FF6A45; }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--teal);
  box-shadow: inset 0 0 0 1.5px var(--border);
}
.btn--ghost:hover { --btn-bg: var(--mist); box-shadow: inset 0 0 0 1.5px var(--teal); }

.btn--lg { padding: 1rem 1.75rem; font-size: var(--fs-body); }

/* The arrow slides on hover — the one piece of motion borrowed wholesale,
   because it reads as "this goes somewhere" better than any label change. */
.btn__icon {
  display: inline-flex;
  transition: transform var(--speed) var(--ease-out);
}
.btn:hover .btn__icon { transform: translateX(4px); }

@media (prefers-reduced-motion: reduce) {
  .btn:hover { transform: none; }
  .btn:hover .btn__icon { transform: none; }
}

/* ==========================================================================
   10. Site header — sticky, adapts on scroll
   ========================================================================== */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid transparent;
  transition:
    background-color var(--speed) var(--ease),
    border-color     var(--speed) var(--ease),
    box-shadow       var(--speed) var(--ease);
}
/* Browsers without backdrop-filter get an opaque bar rather than unreadable text. */
@supports not ((backdrop-filter: blur(12px)) or (-webkit-backdrop-filter: blur(12px))) {
  .site-header { background: var(--white); }
}

.site-header.is-scrolled {
  background: rgba(255, 255, 255, 0.92);
  border-bottom-color: var(--border);
  box-shadow: 0 1px 24px rgba(11, 46, 58, 0.06);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  height: var(--header-h);
  transition: height var(--speed) var(--ease);
}
.site-header.is-scrolled .site-header__inner { height: var(--header-h-scrolled); }

/* --- Logo --------------------------------------------------------------- */
.site-header__logo {
  display: block;
  flex: none;
  line-height: 0;
  border-radius: var(--radius-sm);
}
/* Covers both the inlined SVG on the homepage and the <img> used on
   subpages, which otherwise renders at its intrinsic 810px. */
.site-header__logo :is(svg, img) {
  /* 165px keeps the full lockup well above the 120px minimum (brand-guide §2) */
  width: 165px;
  height: auto;
  transition: width var(--speed) var(--ease);
}
.site-header.is-scrolled .site-header__logo :is(svg, img) { width: 150px; }

/* --- Desktop nav -------------------------------------------------------- */
.site-nav { display: flex; align-items: center; gap: var(--sp-6); }
.site-nav__list { display: flex; align-items: center; gap: var(--sp-5); }

.site-nav__link {
  position: relative;
  display: inline-block;
  padding-block: var(--sp-2);
  color: var(--navy);
  font-size: var(--fs-small);
  font-weight: 600;
  text-decoration: none;
  transition: color var(--speed) var(--ease);
}
/* Underline wipes in from the left, and stays put for the active section. */
.site-nav__link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: var(--coral);
  border-radius: 2px;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--speed) var(--ease-out);
}
.site-nav__link:hover { color: var(--teal); }
.site-nav__link:hover::after,
.site-nav__link[aria-current="true"]::after { transform: scaleX(1); }
.site-nav__link[aria-current="true"] { color: var(--teal); }

@media (prefers-reduced-motion: reduce) {
  .site-nav__link::after { transition: none; }
}

/* --- Hamburger ---------------------------------------------------------- */
.nav-toggle {
  display: none;
  flex: none;
  width: 44px;                 /* 44px touch target */
  height: 44px;
  place-items: center;
  border-radius: var(--radius-sm);
  transition: background-color var(--speed) var(--ease);
}
.nav-toggle:hover { background: var(--mist); }

.nav-toggle__bars { position: relative; display: block; width: 22px; height: 14px; }
.nav-toggle__bars i {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--navy);
  border-radius: 2px;
  transition: transform var(--speed) var(--ease-out), opacity var(--speed-fast) linear;
}
.nav-toggle__bars i:nth-child(1) { top: 0; }
.nav-toggle__bars i:nth-child(2) { top: 6px; }
.nav-toggle__bars i:nth-child(3) { top: 12px; }

/* Bars converge and cross into an X */
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(2) { opacity: 0; transform: scaleX(0.4); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* --------------------------------------------------------------------------
   Mobile nav panel
   -------------------------------------------------------------------------- */
@media (max-width: 860px) {
  .nav-toggle { display: grid; }

  .site-nav {
    /* Absolute against the sticky header (not fixed to the viewport), so the
       panel always sits directly under the bar whatever height it currently
       is. Avoids depending on backdrop-filter making the header a containing
       block, which is what was holding the old `fixed` version up. */
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    /* A short landscape phone scrolls the menu instead of clipping it. */
    max-height: calc(100vh - var(--header-h));
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--sp-5) var(--gutter) var(--sp-7);
    background: var(--white);
    border-bottom: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    /* Hidden from pointer AND keyboard when closed */
    visibility: hidden;
    opacity: 0;
    transform: translateY(-12px);
    transition:
      opacity    var(--speed) var(--ease),
      transform  var(--speed) var(--ease-out),
      visibility 0s linear var(--speed);
  }
  .site-nav.is-open {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition-delay: 0s;
  }

  .site-nav__list { flex-direction: column; align-items: stretch; gap: 0; }

  .site-nav__link {
    display: block;
    padding: var(--sp-4) 0;
    font-size: 1.125rem;
    border-bottom: 1px solid var(--border);
    /* Each link starts slightly low and rises in, staggered. */
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease-out), color var(--speed) var(--ease);
  }
  .site-nav__link::after { display: none; }
  .site-nav__link[aria-current="true"] { color: var(--teal); }

  .site-nav.is-open .site-nav__link { opacity: 1; transform: none; }
  .site-nav.is-open li:nth-child(1) .site-nav__link { transition-delay: 60ms;  }
  .site-nav.is-open li:nth-child(2) .site-nav__link { transition-delay: 110ms; }
  .site-nav.is-open li:nth-child(3) .site-nav__link { transition-delay: 160ms; }
  .site-nav.is-open li:nth-child(4) .site-nav__link { transition-delay: 210ms; }

  .site-nav__cta {
    justify-content: center;
    margin-top: var(--sp-5);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease-out), background-color var(--speed) var(--ease);
  }
  .site-nav.is-open .site-nav__cta { opacity: 1; transform: none; transition-delay: 260ms; }

}

@media (max-width: 400px) {
  .site-header__logo :is(svg, img),
  .site-header.is-scrolled .site-header__logo :is(svg, img) { width: 140px; }
}

@media (prefers-reduced-motion: reduce) {
  .site-nav, .site-nav__link, .site-nav__cta, .nav-toggle__bars i,
  .site-header, .site-header__inner, .site-header__logo svg { transition: none !important; }
  .site-nav__link, .site-nav__cta { opacity: 1 !important; transform: none !important; }
}

/* Locks background scrolling while the mobile panel is open */
body.nav-open { overflow: hidden; }

/* ==========================================================================
   11. Hero
   ========================================================================== */
.hero {
  position: relative;
  overflow: hidden;
  padding-block: clamp(3rem, 1.5rem + 6vw, 6rem) clamp(3.5rem, 2rem + 6vw, 7rem);
  /* A soft Mist wash behind the artwork so the right side has some weight
     without introducing a hard section edge. */
  background:
    radial-gradient(60% 70% at 88% 34%, rgba(232, 243, 242, 0.95) 0%, rgba(232, 243, 242, 0) 70%),
    var(--white);
}

.hero__inner {
  position: relative;
  /* Creates a stacking context so the artwork's z-index:-1 (mobile) drops
     behind the copy but stays ABOVE the section background, rather than
     disappearing underneath it. */
  isolation: isolate;
  display: grid;
  gap: var(--sp-5);
  justify-items: start;
}

/* --- Copy --------------------------------------------------------------- */
.hero__title {
  /* Tagline type: SemiBold 600, never bolder than the wordmark (§5). */
  font-weight: 600;
  font-size: clamp(2.25rem, 1.30rem + 4.2vw, 4rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  color: var(--navy);
  max-width: 14ch;
}
.hero__title span { display: inline-block; }

.hero__lead {
  max-width: 54ch;
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--slate);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin-top: var(--sp-3);
}

/* --- Artwork ------------------------------------------------------------ */
.hero__art {
  pointer-events: none;
  user-select: none;
}
.hero__svg { width: 100%; height: auto; }

/* Mobile: the motif becomes its own small illustration below the copy.
   Floating it behind the text put dots on top of the body copy, which cost
   more in legibility than the texture was worth. */
@media (max-width: 899px) {
  .hero__art {
    width: min(74%, 320px);
    justify-self: end;
    margin-top: var(--sp-5);
    margin-right: calc(var(--gutter) * -0.5);
  }
}

/* Desktop: a proper two-column hero, artwork in its own column. */
@media (min-width: 900px) {
  .hero__inner {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    grid-template-areas:
      "eyebrow art"
      "title   art"
      "lead    art"
      "actions art";
    align-content: center;
    column-gap: var(--sp-8);
    min-height: min(74svh, 620px);
  }
  .hero__eyebrow { grid-area: eyebrow; }
  .hero__title   { grid-area: title;   }
  .hero__lead    { grid-area: lead;    }
  .hero__actions { grid-area: actions; }

  .hero__art {
    position: relative;
    grid-area: art;
    align-self: center;
    justify-self: end;
    width: 100%;
    max-width: 520px;
    opacity: 1;
  }
}

/* ==========================================================================
   12. Hero motion
   Entrance runs on load (the hero is above the fold, so there is nothing to
   scroll into). Scoped to html.js: without JS the hero renders at rest.
   ========================================================================== */
@keyframes pe-rise {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: none; }
}
@keyframes pe-draw   { to { stroke-dashoffset: 0; } }
@keyframes pe-pop {
  0%   { opacity: 0; transform: scale(0.2); }
  65%  { opacity: 1; transform: scale(1.06); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes pe-halo {
  0%   { opacity: 0.30; transform: scale(0.6); }
  70%  { opacity: 0;    transform: scale(1.5); }
  100% { opacity: 0;    transform: scale(1.5); }
}
@keyframes pe-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}
@keyframes pe-arcs { from { opacity: 0; } to { opacity: 0.09; } }

.js .hero__eyebrow,
.js .hero__title span,
.js .hero__lead,
.js .hero__actions {
  animation: pe-rise 0.75s var(--ease-out) both;
}
.js .hero__eyebrow                  { animation-delay: 60ms;  }
.js .hero__title span:nth-child(1)  { animation-delay: 150ms; }
.js .hero__title span:nth-child(2)  { animation-delay: 225ms; }
.js .hero__title span:nth-child(3)  { animation-delay: 300ms; }
.js .hero__title span:nth-child(4)  { animation-delay: 375ms; }
.js .hero__lead                     { animation-delay: 480ms; }
.js .hero__actions                  { animation-delay: 580ms; }

/* Arcs fade up to the 6–10% the brand guide calls for (§6). */
.hero__arcs { opacity: 0.09; }
.js .hero__arcs { animation: pe-arcs 1.2s var(--ease) 200ms both; }

/* The trail draws itself — pathLength="1" means the dash maths is
   independent of the path's real length. */
.hero__trail { opacity: 0.22; stroke-dasharray: 1; }
.js .hero__trail { stroke-dashoffset: 1; animation: pe-draw 1.5s var(--ease-in-out) 350ms both; }

/* Dots climb in behind the drawing line, each a little later. */
.hero__dot { transform-box: fill-box; transform-origin: center; }
.hero__dot:nth-child(1) { opacity: 0.38; }
.hero__dot:nth-child(2) { opacity: 0.52; }
.hero__dot:nth-child(3) { opacity: 0.68; }
.hero__dot:nth-child(4) { opacity: 0.85; }
.js .hero__dot { animation: pe-pop 0.6s var(--ease-out) both; animation-delay: calc(700ms + var(--i) * 130ms); }

/* The goal: coral dot arrives last, then breathes. One ripple on arrival. */
.hero__goal-dot  { transform-box: fill-box; transform-origin: center; }
.hero__goal-halo { transform-box: fill-box; transform-origin: center; opacity: 0; }
.js .hero__goal-dot  { animation: pe-pop 0.7s var(--ease-out) 1240ms both; }
.js .hero__goal-halo { animation: pe-halo 1.6s var(--ease-out) 1340ms both; }
.js .hero__goal      { animation: pe-float 6s var(--ease-in-out) 2.4s infinite; }

/* Everything above is decoration. Under reduced motion the hero renders
   in its final state with no movement at all. */
@media (prefers-reduced-motion: reduce) {
  .js .hero__eyebrow,
  .js .hero__title span,
  .js .hero__lead,
  .js .hero__actions,
  .js .hero__arcs,
  .js .hero__dot,
  .js .hero__goal-dot,
  .js .hero__goal {
    animation: none !important;
    opacity: 1;
    transform: none;
  }
  .js .hero__arcs  { opacity: 0.09; }
  .js .hero__trail { animation: none !important; stroke-dashoffset: 0; }
  .js .hero__goal-halo { animation: none !important; opacity: 0; }
  .js .hero__dot:nth-child(1) { opacity: 0.38; }
  .js .hero__dot:nth-child(2) { opacity: 0.52; }
  .js .hero__dot:nth-child(3) { opacity: 0.68; }
  .js .hero__dot:nth-child(4) { opacity: 0.85; }
}

/* ==========================================================================
   13. Cards — shared primitive, used by About and later sections
   ========================================================================== */
.card {
  padding: var(--sp-6);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition:
    transform  var(--speed) var(--ease-out),
    box-shadow var(--speed) var(--ease-out),
    border-color var(--speed) var(--ease);
}
.card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow);
  border-color: #BFDAD7;
}

.card__icon { display: block; width: 40px; height: 40px; margin-bottom: var(--sp-4); }
.card__icon svg { width: 100%; height: 100%; }
.card__title { margin-bottom: var(--sp-2); color: var(--navy); }
.card__body  { color: var(--slate); }

@media (prefers-reduced-motion: reduce) {
  .card:hover { transform: none; }
}

/* ==========================================================================
   14. About
   ========================================================================== */
.about__inner { display: grid; gap: var(--sp-8); align-items: start; }

@media (min-width: 900px) {
  .about__inner {
    grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
    column-gap: var(--sp-9);
  }
}

.about__copy > * + * { margin-top: var(--sp-4); }
.about__copy p { max-width: 56ch; color: var(--slate); }

.about__lead {
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--navy) !important;
}

.about__team {
  margin-top: var(--sp-6) !important;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
}

.about__cards { display: grid; gap: var(--sp-5); }

/* ==========================================================================
   15. Scroll motion — site-wide layer
   ========================================================================== */

/* --- Directional reveal variants ---------------------------------------- */
.js .reveal--left  { transform: translate3d(-28px, 0, 0); }
.js .reveal--right { transform: translate3d(28px, 0, 0); }
.js .reveal--scale { transform: scale(0.96); }
.js .reveal--left.is-visible,
.js .reveal--right.is-visible,
.js .reveal--scale.is-visible { transform: none; }

/* Horizontal entrances only make sense where there is room for them.
   On narrow screens they become the standard rise. */
@media (max-width: 720px) {
  .js .reveal--left,
  .js .reveal--right { transform: translate3d(0, 26px, 0); }
}

/* --- Read-progress bar --------------------------------------------------
   A hairline of coral across the bottom edge of the header. Decorative:
   aria-hidden in the markup, and it duplicates the scrollbar's information.
   ------------------------------------------------------------------------ */
.scroll-progress {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 2px;
  background: var(--coral);
  transform: scaleX(var(--scroll-progress, 0));
  transform-origin: left center;
  opacity: 0;
  transition: opacity var(--speed) var(--ease);
  pointer-events: none;
}
.site-header.is-scrolled .scroll-progress { opacity: 1; }

/* --- Parallax drift on decorative artwork -------------------------------
   Native scroll-driven animation where supported (Chrome/Edge/Safari 26+):
   runs off the compositor, costs no JS, and simply does not apply
   elsewhere — the artwork just sits still, which is a fine outcome.
   ------------------------------------------------------------------------ */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    @media (min-width: 900px) {
      @keyframes pe-parallax {
        from { transform: translateY(28px); }
        to   { transform: translateY(-28px); }
      }
      .hero__art {
        animation: pe-parallax linear both;
        animation-timeline: view();
        animation-range: entry 0% exit 100%;
      }
    }
  }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-progress { display: none; }
  .js .reveal--left,
  .js .reveal--right,
  .js .reveal--scale { transform: none !important; }
}

/* ==========================================================================
   16. Services
   ========================================================================== */
.services__intro {
  max-width: 44ch;
  margin-inline: auto;
  margin-bottom: var(--sp-8);
  text-align: center;
}
.services__lead {
  margin-top: var(--sp-4);
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--slate);
}

.services__grid {
  display: grid;
  gap: var(--sp-5);
  grid-template-columns: 1fr;
}
/* 2x2 rather than auto-fit: with four cards, auto-fit lands on an
   awkward 3 + 1 orphan at container width. */
@media (min-width: 640px)  { .services__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1080px) { .services__grid { grid-template-columns: repeat(4, 1fr); } }

/* Cards in this section carry more copy, so they get a little more room
   and their body text a slightly tighter measure. */
.service { display: flex; flex-direction: column; }
.service .card__body { max-width: 38ch; }
@media (min-width: 1080px) {
  .service { padding: var(--sp-5); }
  .service .card__body { font-size: var(--fs-small); }
}

/* ==========================================================================
   17. How it works
   ========================================================================== */
.steps__intro {
  max-width: 48ch;
  margin-bottom: var(--sp-8);
}
@media (min-width: 900px) {
  /* Centred to match the steps below it, so the section reads as one
     composition rather than a left-aligned intro over a centred row. */
  .steps__intro { margin-inline: auto; text-align: center; }
}
.steps__lead {
  margin-top: var(--sp-4);
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--slate);
}

.steps__wrap { position: relative; }

.steps__list {
  display: grid;
  gap: var(--sp-6);
}

.step { position: relative; display: grid; gap: var(--sp-4); }

/* --- Marker ------------------------------------------------------------- */
.step__marker {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  flex: none;
  background: var(--white);
  border: 2px solid var(--teal);
  border-radius: 50%;
  color: var(--teal);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* The final step is the goal — coral fill with a navy numeral (5.6:1).
   Mirrors the coral dot that ends the rising trail. */
.step__marker--goal {
  background: var(--coral);
  border-color: var(--coral);
  color: var(--navy);
}

.step__title { margin-bottom: var(--sp-2); color: var(--navy); }
.step__body  { color: var(--slate); }

/* --- Connector ---------------------------------------------------------- */
.steps__line {
  position: absolute;
  background: var(--teal);
  opacity: 0.22;
  border-radius: 2px;
  pointer-events: none;
}

/* --- Mobile: vertical timeline ------------------------------------------ */
@media (max-width: 899px) {
  .step {
    grid-template-columns: 52px minmax(0, 1fr);
    align-items: start;
    column-gap: var(--sp-5);
  }
  .steps__line {
    top: 26px;
    bottom: 26px;
    left: 25px;
    width: 2px;
  }
  .js .steps__line.reveal {
    opacity: 0.22;
    transform: scaleY(0);
    transform-origin: center top;
    transition: transform 1.1s var(--ease-in-out);
  }
  .js .steps__line.reveal.is-visible { transform: scaleY(1); }
}

/* --- Desktop: four across, connector running through the markers --------- */
@media (min-width: 900px) {
  .steps__list {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--sp-5);
  }
  .step {
    justify-items: center;
    text-align: center;
    gap: var(--sp-5);
    /* Without this, grid distributes the row leftover into the marker row
       by different amounts per column (their text heights differ), so the
       titles land at different heights. */
    align-content: start;
  }
  .step__text { max-width: 30ch; }

  /* Spans centre-of-first-marker to centre-of-last: each column is 25% wide,
     so both ends sit 12.5% in. */
  .steps__line {
    top: 25px;
    left: 12.5%;
    right: 12.5%;
    height: 2px;
  }
  .js .steps__line.reveal {
    opacity: 0.22;
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 1.1s var(--ease-in-out);
  }
  .js .steps__line.reveal.is-visible { transform: scaleX(1); }
}

@media (prefers-reduced-motion: reduce) {
  .js .steps__line.reveal,
  .js .steps__line.reveal.is-visible {
    transform: none !important;
    transition: none !important;
  }
}

/* ==========================================================================
   18. Why work with us — on Deep Navy
   ========================================================================== */

/* Teal eyebrows fail against navy; Seafoam clears 9.0:1. */
.section--dark .eyebrow { color: var(--seafoam); }

.why__intro { max-width: 46ch; margin-bottom: var(--sp-8); }
.why__lead {
  margin-top: var(--sp-4);
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--seafoam) !important;
}

.why__grid {
  display: grid;
  gap: var(--sp-6);
}
@media (min-width: 760px) {
  .why__grid { grid-template-columns: repeat(2, 1fr); column-gap: var(--sp-8); }
}

.why__point {
  position: relative;
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border-on-dark);
}

.why__dot {
  position: absolute;
  top: -5px;
  left: 0;
  width: 10px;
  height: 10px;
  background: var(--coral);
  border-radius: 50%;
}

.why__title {
  margin-bottom: var(--sp-3);
  color: var(--white);
  font-size: var(--fs-h3);
  font-weight: 600;
}
.why__body { color: var(--seafoam); max-width: 46ch; }

/* ==========================================================================
   19. FAQ
   Built on <details>/<summary>: open/close, keyboard and screen-reader
   support are native, so it works with JS disabled. The name attribute
   makes it an exclusive accordion in browsers that support it.
   ========================================================================== */
.faq__inner { display: grid; gap: var(--sp-7); align-items: start; }

@media (min-width: 900px) {
  .faq__inner {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    column-gap: var(--sp-9);
  }
  /* The heading holds position while the answers scroll past it. */
  .faq__intro {
    position: sticky;
    top: calc(var(--header-h) + var(--sp-6));
  }
}

.faq__lead {
  margin-top: var(--sp-4);
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--slate);
}

.faq__item { border-bottom: 1px solid var(--border); }
.faq__item:first-child { border-top: 1px solid var(--border); }

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-4);
  padding: var(--sp-5) 0;
  color: var(--navy);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.4;
  cursor: pointer;
  list-style: none;                 /* hide the default triangle */
  transition: color var(--speed) var(--ease);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { color: var(--teal); }
.faq__q:focus-visible { outline-offset: -3px; }

.faq__chev {
  flex: none;
  color: var(--teal);
  transition: transform var(--speed) var(--ease-out);
}
.faq__item[open] .faq__chev { transform: rotate(180deg); }

.faq__a { padding: 0 0 var(--sp-5); }
.faq__a p { max-width: 62ch; color: var(--slate); }

/* Answers ease in rather than snapping open. */
.faq__item[open] .faq__a { animation: pe-rise 0.35s var(--ease-out) both; }

@media (prefers-reduced-motion: reduce) {
  .faq__chev { transition: none; }
  .faq__item[open] .faq__a { animation: none; }
}

/* ==========================================================================
   20. Contact
   ========================================================================== */
.contact__inner { display: grid; gap: var(--sp-8); align-items: start; }

@media (min-width: 900px) {
  .contact__inner {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    column-gap: var(--sp-9);
  }
}

.contact__lead {
  margin-top: var(--sp-4);
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--slate);
}

.contact__direct {
  margin-top: var(--sp-6);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
}
.contact__direct-label {
  font-size: var(--fs-small);
  color: var(--slate);
  margin-bottom: var(--sp-2);
}
.contact__email {
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--teal);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  word-break: break-word;
}

/* --- Form --------------------------------------------------------------- */
.contact__formwrap {
  padding: clamp(1.5rem, 1rem + 2vw, 2.5rem);
  background: var(--white);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.field { margin-bottom: var(--sp-5); }

.field__label {
  display: block;
  margin-bottom: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 600;
  color: var(--navy);
}
.field__optional { font-weight: 500; color: var(--slate); }

.field__input {
  display: block;
  width: 100%;
  padding: 0.75rem 0.875rem;
  font-size: var(--fs-body);
  font-family: inherit;
  color: var(--navy);
  background: var(--white);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-sm);
  transition: border-color var(--speed) var(--ease), box-shadow var(--speed) var(--ease);
}
.field__input::placeholder { color: #93A6AC; }
.field__input:hover { border-color: #BFDAD7; }
.field__input:focus {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(14, 94, 111, 0.12);
  outline: none;                 /* replaced by the ring above + :focus-visible below */
}
.field__input:focus-visible { outline: 3px solid var(--coral); outline-offset: 2px; }

.field__input--area { resize: vertical; min-height: 120px; line-height: 1.5; }

/* Invalid state. Never colour alone — the message text carries the meaning. */
.field__input[aria-invalid="true"] {
  border-color: #B4462F;
  box-shadow: 0 0 0 3px rgba(180, 70, 47, 0.10);
}
.field__error {
  margin-top: var(--sp-2);
  font-size: var(--fs-small);
  font-weight: 500;
  color: #8C3520;                /* 5.9:1 on white */
}

/* Honeypot: off-screen, not display:none */
.form__hp {
  position: absolute !important;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form__submit { margin-top: var(--sp-2); }
.form__submit[disabled] { opacity: 0.65; cursor: progress; transform: none; }

.form__status {
  margin-top: var(--sp-5);
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  font-weight: 500;
  border: 1px solid transparent;
}
.form__status--ok {
  background: var(--mist);
  border-color: #BFDAD7;
  color: var(--navy);
}
.form__status--error {
  background: #FDF0EC;
  border-color: #F0C4B7;
  color: #8C3520;
}
.form__status--notice {
  background: #FFF6E8;
  border-color: #FFDFAE;
  color: #6B4A12;
}
.form__status a { color: inherit; font-weight: 600; }

.form__privacy {
  margin-top: var(--sp-5);
  font-size: var(--fs-caption);
  color: var(--slate);
  line-height: 1.5;
}

/* ==========================================================================
   21. Footer
   ========================================================================== */
.site-footer {
  padding-top: clamp(3rem, 2rem + 4vw, 4.5rem);
  background: var(--navy);
  color: var(--seafoam);
}

.site-footer__inner {
  display: grid;
  gap: var(--sp-7);
  padding-bottom: var(--sp-8);
}
@media (min-width: 720px) {
  .site-footer__inner { grid-template-columns: 1.5fr 1fr 1.2fr; gap: var(--sp-6); }
}

.site-footer__logo { width: 190px; height: auto; }
.site-footer__tagline {
  margin-top: var(--sp-4);
  color: var(--white);
  font-weight: 600;
  font-size: 1.0625rem;
}

.site-footer__heading {
  margin-bottom: var(--sp-4);
  color: var(--white);
  font-size: var(--fs-caption);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.site-footer__nav li + li,
.site-footer__contact li + li { margin-top: var(--sp-3); }

.site-footer a {
  color: var(--seafoam);
  text-decoration: none;
  transition: color var(--speed) var(--ease);
}
.site-footer a:hover { color: var(--white); text-decoration: underline; text-underline-offset: 0.2em; }

.site-footer__contact li { word-break: break-word; }

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  padding-top: var(--sp-5);
  padding-bottom: var(--sp-6);
  border-top: 1px solid var(--border-on-dark);
}
/* Legal line stays small print, per brand-guide §9. */
.site-footer__legal { font-size: var(--fs-caption); color: var(--seafoam); opacity: 0.8; }
.site-footer__meta {
  display: flex;
  gap: var(--sp-5);
  font-size: var(--fs-caption);
  color: var(--seafoam);
  opacity: 0.8;
}

/* ==========================================================================
   22. Prose pages (privacy, 404)
   ========================================================================== */
.prose .container { max-width: 68ch; }
.prose h1 { margin-bottom: var(--sp-4); }
.prose h2 {
  margin-top: var(--sp-8);
  margin-bottom: var(--sp-3);
  font-size: var(--fs-h3);
  font-weight: 600;
}
.prose p { color: var(--slate); }
.prose p + p { margin-top: var(--sp-4); }
.prose__lead {
  font-size: var(--fs-lead);
  line-height: 1.5;
  color: var(--navy) !important;
}
.prose__updated {
  margin-top: var(--sp-8);
  padding-top: var(--sp-5);
  border-top: 1px solid var(--border);
  font-size: var(--fs-caption);
}
/* Subpages have no nav to collapse, so the header is just logo + back. */
.prose ~ * .site-header__inner,
body:has(.prose) .site-header__inner { gap: var(--sp-4); }

/* --- Select + hint (contact form) --------------------------------------- */
.field__hint {
  margin-top: -2px;
  margin-bottom: var(--sp-3);
  font-size: var(--fs-caption);
  color: var(--slate);
  line-height: 1.5;
}

.field__selectwrap { position: relative; }

.field__select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.75rem;
  cursor: pointer;
}
/* Until something is chosen the placeholder option shows, so grey it to
   match an empty text input rather than reading as a real answer. */
.field__select:invalid { color: #93A6AC; }
.field__select option { color: var(--navy); }

.field__chev {
  position: absolute;
  top: 50%;
  right: 0.875rem;
  transform: translateY(-50%);
  color: var(--teal);
  pointer-events: none;
}

/* 404 */
.notfound__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  margin-top: var(--sp-7);
}

/* --- Consent checkbox ---------------------------------------------------- */
.field--consent { margin-top: var(--sp-6); margin-bottom: var(--sp-5); }

.consent { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: var(--sp-3); align-items: start; }

/* A real checkbox, restyled — not a hidden input with a fake box, so it
   keeps native keyboard, focus and form semantics. */
.consent__input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 22px;
  height: 22px;
  margin: 1px 0 0;
  background: var(--white);
  border: 1.5px solid var(--border);
  border-radius: 6px;
  cursor: pointer;
  display: grid;
  place-content: center;
  transition: background-color var(--speed) var(--ease), border-color var(--speed) var(--ease);
}
.consent__input:hover { border-color: #BFDAD7; }
.consent__input::before {
  content: "";
  width: 12px;
  height: 12px;
  transform: scale(0);
  transform-origin: center;
  transition: transform var(--speed-fast) var(--ease-out);
  background: var(--white);
  clip-path: polygon(14% 45%, 0 60%, 40% 100%, 100% 22%, 85% 8%, 38% 71%);
}
.consent__input:checked { background: var(--teal); border-color: var(--teal); }
.consent__input:checked::before { transform: scale(1); }
.consent__input[aria-invalid="true"] { border-color: #B4462F; }

.consent__label {
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--slate);
  cursor: pointer;
}
.consent__label a { color: var(--teal); }

@media (prefers-reduced-motion: reduce) {
  .consent__input, .consent__input::before { transition: none; }
}
