/* =========================================================
   Alveus — Components & layout
   (loaded after style.css which holds tokens + base)
   ========================================================= */

/* ---------------------------------------------------------
   Page transition overlay (Barba parallax)
   --------------------------------------------------------- */
.transition {
  z-index: 100;
  pointer-events: none;
  position: fixed;
  inset: 0;
  overflow: clip;
}
.transition__dark {
  opacity: 0;
  background-color: var(--c-navy-dark, #00114c);
  width: 100%;
  height: 100%;
  position: absolute;
  inset: 0;
  will-change: opacity;
}

/* ---------------------------------------------------------
   Dynamic background canvas (driven by scroll-bg.js)
   --------------------------------------------------------- */
.bg-canvas {
  position: fixed;
  inset: 0;
  z-index: -2;
  background-color: var(--bg);
  /* No CSS transition here: scroll-bg.js sets the colour every frame,
     so the smoothness comes from scroll position, not a timed tween. */
  pointer-events: none;
}

/* Fixed video background layer; opacity is scroll-driven (set by scroll-bg.js)
   so the change from blue -> video -> white is part of the background system. */
.bg-video {
  position: fixed;
  inset: 0;
  z-index: -1;
  opacity: var(--bg-video-opacity, 0);
  pointer-events: none;
  will-change: opacity;
  transform: translateZ(0); /* own GPU layer -> stable, jank-free opacity blend */
  backface-visibility: hidden;
  isolation: isolate; /* contain the multiply blend to this layer only */
}
.bg-video__media {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Soft grade over the footage (matches Figma): the video stays natural and
   bright (greens stay green) with only a gentle cool wash + edge vignette, plus
   a subtle local scrim on the left so the white heading stays legible. The blue
   at the very top of the section comes from the scroll background blend, not
   from a heavy overlay here. */
.bg-video__tint {
  position: absolute;
  inset: 0;
  background: #c4cee0; /* light cool wash: cools/desaturates without going blue */
  mix-blend-mode: multiply;
}
.bg-video__shade {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(98deg, rgba(0, 17, 76, 0.34) 0%, rgba(0, 17, 76, 0) 52%),
    radial-gradient(135% 115% at 50% 40%, rgba(0, 0, 0, 0) 50%, rgba(2, 14, 52, 0.55) 100%);
}

/* =========================================================
   HEADER
   ========================================================= */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  /* Figma: logo at x=80 (5%), top ~60px; side gutter 80px. */
  padding: clamp(1.5rem, 3.75vw, 3.75rem) clamp(1.25rem, 5.55vw, 80px);
  color: var(--text-on-dark);
  /* Gentle hide/show slide: longer + softer curve than --ease-osmo. */
  transition: color 0.4s linear, transform 0.7s cubic-bezier(0.45, 0.05, 0.2, 1);
}
/* When over light background the header text flips to navy (set by JS via body
   class). Brand Blue (#042e7b), not navy-dark: it must match the blue the page
   body copy uses on light sections, and the hamburger pill already uses it. */
body.header-dark .site-header { color: var(--c-brand, #042e7b); }

/* Hide-on-scroll: header-scroll.js adds .header-hide while scrolling down and
   removes it on any scroll up; the .site-header transform transition
   (0.4s --ease-osmo) animates both ways. Menu open always keeps it visible. */
.site-header.header-hide { transform: translateY(-110%); }
body.overflow-hidden .site-header { transform: none; }

/* Scrim behind the re-shown header. Past the hero zone the header floats over
   arbitrary page content, so header-scroll.js adds .header-scrim and this
   gradient gives the strip its own backdrop. It reads the live canvas colour
   (--bg-rgb, set every frame by scroll-bg.js), so it is navy over blue
   sections, white over light ones, and stays correct inside the blend bands
   between them. Over the video section the canvas is covered by footage, so
   the scrim fades out with the video (1 - video opacity). */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: calc(100% + clamp(1.5rem, 3vw, 3rem));
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(var(--bg-rgb, 0, 17, 76), 1) 0%,
    rgba(var(--bg-rgb, 0, 17, 76), 0.96) 30%,
    rgba(var(--bg-rgb, 0, 17, 76), 0.78) 55%,
    rgba(var(--bg-rgb, 0, 17, 76), 0.45) 75%,
    rgba(var(--bg-rgb, 0, 17, 76), 0.16) 90%,
    rgba(var(--bg-rgb, 0, 17, 76), 0) 100%
  );
  opacity: 0;
  transition: opacity 0.4s linear;
}
.site-header.header-scrim::before {
  /* --scrim-strength (scroll-bg.js): 1 on light canvases, ~0.7 on navy —
     the dark gradient otherwise reads heavier than the white one. */
  opacity: calc((1 - var(--bg-video-opacity, 0)) * var(--scrim-strength, 1));
}
/* Hidden header: the scrim is a touch taller than the strip, so translateY(-110%)
   leaves a thin gradient sliver at the very top — invisible over a dark canvas
   but a visible white band once the canvas has blended to a light section. Fade
   it out together with the header. (After .header-scrim::before so it wins at
   equal specificity.) */
.site-header.header-hide::before { opacity: 0; }
/* Menu open: the fullscreen overlay owns the backdrop, keep the strip clean. */
body.overflow-hidden .site-header::before { opacity: 0; }
/* Barba transition: while both pages slide, the scroll position (and thus the
   scrim state + canvas colour) still belong to the OLD page — a stale white
   gradient would float over the ride. Hide it for the duration; afterEnter
   resets scroll and re-syncs the scrim on the new page. */
html.is-transitioning .site-header::before { opacity: 0; }

/* Anchor targets (blocks/rows with an Anchor field): keep the fixed header
   clear of the target on native hash jumps; careers.js applies its own offset
   for the smooth Lenis glide. */
.section[id],
.program-row[id] { scroll-margin-top: 100px; }

.site-logo { display: inline-flex; align-items: center; }
.site-logo svg { height: 50px; width: auto; }
.site-logo img { height: 50px; width: auto; }
/* Dark logo state: letters follow currentColor and thus the header's Brand
   Blue RAJ (client 2026-07: no longer the Figma asset's purple) — the mark's
   turquoise-purple gradient swirls stay as designed in both states. */
body.header-dark .site-header .site-logo { color: var(--brand-blue-raj, #042e7b); }
/* The droplet body ships twice in logo.svg: a currentColor copy (white over
   dark canvas) and a purple-turquoise gradient copy per the Figma dark
   variant. Cross-fade between them in sync with the header colour flip.
   Footer logo never sets header-dark, so it keeps the solid white droplet. */
.site-logo .logo-drop--solid,
.site-logo .logo-drop--gradient { transition: opacity 0.4s linear; }
.site-logo .logo-drop--gradient { opacity: 0; }
body.header-dark .site-header .site-logo .logo-drop--solid { opacity: 0; }
body.header-dark .site-header .site-logo .logo-drop--gradient { opacity: 1; }

.main-nav {
  display: flex;
  align-items: center;
  gap: 30px; /* Figma */
}
.nav-link {
  position: relative;
  font-size: 18px;      /* Figma: Body 18/28 */
  line-height: 28px;
  font-weight: 400;
  padding-bottom: 8px;  /* 6px gap + 2px underline */
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0; right: 100%;
  bottom: 0;
  height: 2px;
  background: var(--accent);
  transition: right 0.35s var(--ease-osmo);
}
.nav-link:hover::after,
.nav-link[aria-current="page"]::after { right: 0; }

/* =========================================================
   HAMBURGER + MOBILE MENU  (ported from the original Alveus site)
   ========================================================= */
.hamburger {
  z-index: 10;
  display: none;
  cursor: pointer;
  transition-property: opacity, filter;
  transition-duration: 0.15s;
  transition-timing-function: linear;
  font: inherit;
  color: inherit;
  text-transform: none;
  background-color: transparent;
  border: 0;
  margin: 0;
  padding: 0;
  overflow: visible;
  -webkit-tap-highlight-color: transparent;
}
@media only screen and (max-width: 1024px) {
  .main-nav { display: none; }
  .hamburger { display: inline-block; }
}

.hamburger:hover { opacity: 1; }
.hamburger.is-active:hover { opacity: 1; }
.hamburger.is-active .hamburger-inner,
.hamburger.is-active .hamburger-inner::before,
.hamburger.is-active .hamburger-inner::after { background-color: #1F0778; }

/* Menu open: the full-screen purple overlay takes over, so the pill returns to
   its white default with the dark X bars, even on light (header-dark) sections
   where the resting pill is navy. Without this the dark X sits on a navy pill. */
.hamburger.is-active .hamburger-box,
body.header-dark .hamburger.is-active .hamburger-box { background: #ffffff; }
.hamburger.is-active .hamburger-inner,
.hamburger.is-active .hamburger-inner::before,
.hamburger.is-active .hamburger-inner::after,
body.header-dark .hamburger.is-active .hamburger-inner,
body.header-dark .hamburger.is-active .hamburger-inner::before,
body.header-dark .hamburger.is-active .hamburger-inner::after { background-color: #1F0778; }

.hamburger.is-active .hamburger-box { position: relative; }
.hamburger.is-active .hamburger-box:before {
  position: relative;
  z-index: -1;
  background-color: rgba(31, 7, 120, 0.9);
  background-image: radial-gradient(circle, rgba(0, 17, 76, 0.4) 0%, rgba(54, 0, 153, 0.4) 100%);
  transform: scale(60);
}

.hamburger-box {
  width: 50px;
  height: 50px;
  border-radius: 100px;
  position: relative;
  background: white;
  display: flex;
  justify-content: center;
  align-items: center;
  -webkit-tap-highlight-color: transparent;
  transition: all 0.5s ease-in-out;
}
.hamburger-box:before {
  transition: all 0.5s ease-in-out;
  content: "";
  width: 50px;
  height: 50px;
  border-radius: 100px;
  position: relative;
  background: white;
}

/* Adaptive pill: like the logo, the hamburger follows the section background.
   Default (dark section) = white pill with navy bars. On light sections the
   header goes dark (body.header-dark), so flip to a navy pill with white bars.
   The .box transition (0.5s) makes the colour swap glide as you scroll. */
body.header-dark .hamburger-box,
body.header-dark .hamburger-box:before {
  background: var(--c-brand, #042e7b);
}
body.header-dark .hamburger-inner,
body.header-dark .hamburger-inner::before,
body.header-dark .hamburger-inner::after {
  background-color: #ffffff;
}

.hamburger-inner {
  display: block;
  top: 50%;
  margin-top: -2px;
}
.hamburger-inner,
.hamburger-inner::before,
.hamburger-inner::after {
  width: 24px;
  height: 2px;
  background-color: #1F0778;
  border-radius: 4px;
  position: absolute;
  transition-property: transform, background-color;
  transition-duration: 0.15s, 0.5s;
  transition-timing-function: ease, ease-in-out;
}
.hamburger-inner::before,
.hamburger-inner::after { content: ""; display: block; }
.hamburger-inner::before { top: -6px; }
.hamburger-inner::after { bottom: -6px; }

/* Spin. NB: each bar keeps a background-color transition so the navy<->white
   colour swap (driven by body.header-dark on scroll) glides on all three bars
   together, matching the pill box. Without it the ::before/::after shorthands
   would drop background-color and the top/bottom bars would snap. */
.hamburger--spin .hamburger-inner {
  transition-property: transform, background-color;
  transition-duration: 0.22s, 0.5s;
  transition-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19), ease-in-out;
}
.hamburger--spin .hamburger-inner::before { transition: top 0.1s 0.25s ease-in, opacity 0.1s ease-in, background-color 0.5s ease-in-out; }
.hamburger--spin .hamburger-inner::after { transition: bottom 0.1s 0.25s ease-in, transform 0.22s cubic-bezier(0.55, 0.055, 0.675, 0.19), background-color 0.5s ease-in-out; }
.hamburger--spin.is-active .hamburger-inner {
  transform: rotate(225deg);
  transition-delay: 0.12s;
  transition-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
.hamburger--spin.is-active .hamburger-inner::before { top: 0; opacity: 0; transition: top 0.1s ease-out, opacity 0.1s 0.12s ease-out; }
.hamburger--spin.is-active .hamburger-inner::after { bottom: 0; transform: rotate(-90deg); transition: bottom 0.1s ease-out, transform 0.22s 0.12s cubic-bezier(0.215, 0.61, 0.355, 1); }

/* Mobile menu panel */
.mobile-menu {
  width: 100vw;
  height: calc(100dvh - 100px);
  background: transparent;
  position: fixed;
  z-index: 9999;
  left: 0;
  top: 100px;
  padding-inline: 20px;
  box-sizing: border-box;
  display: flex;
  visibility: hidden;
  align-items: center;
  opacity: 0;
  transition: visibility 0s 0.3s, opacity 0.3s;
  flex-direction: column;
  justify-content: center;
  gap: 20px;
}
.mobile-menu .links-wrapper {
  justify-content: center;
  display: flex;
  align-items: center;
  flex-direction: column;
  gap: 22px; /* was 30px; tightened when Home joined so 7 links fit nicely */
  width: 100vw;
  height: calc(100dvh - 100px);
  box-sizing: border-box;
  /* The panel starts 100px below the screen top, so centring inside it lands
     50px below screen centre. The asymmetric padding compensates (20 top /
     120 bottom = exact screen centre) and the extra 30px bottom lifts the
     links ~15px above geometric centre: optical centring, the menu read as
     sitting too low on iOS (client feedback 2026-07). */
  padding: 20px 20px 150px;
}
.mobile-menu a {
  margin-left: -10px;
  font-size: 28px;
  color: white;
  text-decoration: none;
  border-bottom: 4px solid transparent;
  border-radius: 2px;
  opacity: 0;
  transform: translateY(30px);
}
.mobile-menu a.active {
  border-radius: 0;
  color: white;
  border-bottom: 2px solid #00FFEC;
}
.mobile-menu.is-active { visibility: visible; opacity: 1; }

@keyframes alveusFadeInUp { to { opacity: 1; transform: translateY(0); } }

.mobile-menu.is-active .links-wrapper a {
  animation-name: alveusFadeInUp;
  animation-duration: 0.3s;
  animation-fill-mode: forwards;
  animation-timing-function: ease-out;
}
.mobile-menu.is-active .links-wrapper a:nth-child(1) { animation-delay: 0.2s; }
.mobile-menu.is-active .links-wrapper a:nth-child(2) { animation-delay: 0.4s; }
.mobile-menu.is-active .links-wrapper a:nth-child(3) { animation-delay: 0.6s; }
.mobile-menu.is-active .links-wrapper a:nth-child(4) { animation-delay: 0.8s; }
.mobile-menu.is-active .links-wrapper a:nth-child(5) { animation-delay: 1s; }
.mobile-menu.is-active .links-wrapper a:nth-child(6) { animation-delay: 1.2s; }
.mobile-menu.is-active .links-wrapper a:nth-child(7) { animation-delay: 1.4s; }
.mobile-menu.is-active .links-wrapper a:nth-child(8) { animation-delay: 1.6s; }
.mobile-menu .links-wrapper a { transition: opacity 0.2s, transform 0.2s; }

body.overflow-hidden { overflow: hidden; }

/* The CookieYes consent banner (z-index 9999999) otherwise sits on top of the
   fullscreen menu (z-index 9999) and swallows taps on the menu links. Hide it
   while the menu is open; it returns as soon as the menu closes. */
body.overflow-hidden .cky-consent-container { visibility: hidden !important; }

/* =========================================================
   HERO (Figma node 1:190) — video + blue gradient overlay
   ========================================================= */
.hero {
  position: relative;
  overflow: hidden;
  color: #fff;
  isolation: isolate;
  /* Height is content-driven: 200px breathing room above, 150px below. */
  display: flex;
  align-items: flex-end;
  padding-block: 200px 150px; /* override .section padding */
}
/* Homepage hero only: fill the viewport (stop growing past 1400px). Content
   stays pinned to the bottom, 150px up (the .hero padding), with the animated
   scroll cue centred 30px from the bottom edge. */
.hero--full {
  min-height: min(100vh, 1400px);
  min-height: min(100svh, 1400px); /* stable height on mobile browser chrome */
  /* Chrome/Firefox on iOS overlay their bottom bar on the page, so 100svh is
     taller than what is actually visible and the bottom-pinned content sat
     behind the bar (client 2026-08). --vvh is the measured visible height,
     set inline in header.php before first paint; like svh it ignores
     height-only changes from collapsing browser chrome. */
  min-height: min(var(--vvh, 100svh), 1400px);
}
.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: 30px;
  color: #fff;
  line-height: 0;
  transform: translate(-50%, 0);
  animation: hero-scroll-bob 2.6s cubic-bezier(0.45, 0, 0.55, 1) infinite;
  /* Now an interactive button that scrolls to the first section. */
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  padding: 12px; /* larger hit area around the 17x32 arrow */
  cursor: pointer;
}
/* The arrow path ships at opacity 0.6; lift it to full on hover/focus so the
   cue reads as clickable without changing the resting look. */
.hero__scroll svg path { transition: opacity 0.3s ease; }
.hero__scroll:hover svg path,
.hero__scroll:focus-visible svg path { opacity: 1; }
/* (Focus outline removed sitewide per client 2026-07 — see style.css.) */
@keyframes hero-scroll-bob {
  0%, 100% { transform: translate(-50%, 0); }
  50%      { transform: translate(-50%, 8px); }
}
@media (prefers-reduced-motion: reduce) {
  .hero__scroll { animation: none; }
}
.hero__media,
.hero__media video,
.hero__media img,
.hero__fallback {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -2;
}
.hero__fallback {
  background: radial-gradient(120% 120% at 70% 20%, #09007b 0%, #02225e 45%, #00114c 100%);
}
/* Blue gradient OVER the video (not baked into the video) */
.hero__overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(120deg, rgba(9,0,123,0.5) 0%, rgba(4,46,123,0.3) 60%, rgba(0,255,236,0.05) 100%);
}
.hero__inner {
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}
/* Figma: eyebrow / title / text stacked with a 30px gap, bottom-left */
.hero__content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 30px;
}
.eyebrow--hero { opacity: 0.6; }
.hero__title {
  /* The 7.2vw cap keeps the longest line ("Solving for what happens",
     ~11.6em) on a single line down to a 320px viewport. */
  font-size: min(var(--fs-h1), 7.2vw);
  line-height: 1;          /* Figma: 60/60 */
  max-width: none; /* line breaks are set by the editor (<br>) */
  margin: 0;
}
.hero__title strong { font-weight: 700; }
.hero__text {
  font-size: var(--fs-body);   /* 18/28 */
  line-height: 1.55;
  max-width: 626px;            /* Figma */
  margin: 0;
}
.hero__buttons { display: flex; flex-wrap: wrap; gap: 1rem; margin: 0; }

/* ---- Legal / editor pages (the_content prose) ------------- */
.entry-content {
  max-width: 780px;
  color: #33405c;
  font-size: 1rem;
  line-height: 1.7;
}
/* Legal / plain content pages: centre the text column and align the heading to it. */
.entry-page .section__head,
.entry-page .entry-content {
  max-width: 780px;
  margin-left: auto;
  margin-right: auto;
}
.entry-content > :first-child { margin-top: 0; }
.entry-content h2 {
  margin: clamp(2rem, 4vw, 3rem) 0 0.75rem;
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
  font-weight: 400;
  line-height: 1.25;
  color: #02225e;
}
.entry-content h3 {
  margin: 2rem 0 0.5rem;
  font-size: 1.2rem;
  font-weight: 700;
  color: #02225e;
}
.entry-content p { margin: 0 0 1.1em; }
.entry-content ul, .entry-content ol { margin: 0 0 1.2em; padding-left: 1.4em; }
.entry-content ul { list-style: disc; }
.entry-content ol { list-style: decimal; }
.entry-content li { margin: 0 0 0.5em; }
.entry-content a {
  color: var(--c-brand, #042e7b);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}
.entry-content strong { font-weight: 700; color: #02225e; }
.entry-content hr { border: 0; border-top: 1px solid #d9e2f4; margin: 2.5rem 0; }

/* ---- Inline text links in editor content --------------------------- */
/* The base reset strips link styling (a { color: inherit; text-decoration:
   none }), so a link an editor dropped into an ACF WYSIWYG rendered exactly
   like the copy around it - the "team" link in the Our Science cards read as
   plain text (client 2026-07). Rich-text blocks sit on backgrounds that
   interpolate between white, navy and video, so the colour is inherited on
   purpose: a fixed action blue sinks into the dark sections. The underline
   carries the signal instead, the way .page-banner__text a already did.
   Buttons that happen to sit inside rich text keep their own styling.

   The underline is drawn as two stacked background layers instead of
   text-decoration: a hairline in currentColor that is always there, and on top
   of it the brand gradient filling in from left to right on hover - the same
   gesture, gradient and timing as the team card's bottom rule and the USP card
   bar, so a hovered link belongs to the same family. text-decoration is not
   used because it can only thicken in place; background-size is the one
   underline property that can be animated across the width. */
.rich-text a:not(.button-040),
.page-banner__text a,
.benefits__card a:not(.button-040),
.article a:not(.button-040),
.article__text a:not(.button-040),
.article__list a:not(.button-040),
.entry-content a,
.notice-pill__link {
  text-decoration: none;
  background-image:
    /* fills in on hover, same ramp as .team-card__fill / .usp-card__bar */
    linear-gradient(90deg, var(--numab-blue, #479ff3) 0%, var(--ice, #00ffec) 100%),
    linear-gradient(currentColor, currentColor);   /* always-on hairline */
  background-size: 0% 2px, 100% 1px;
  background-position: 0 100%, 0 100%;
  background-repeat: no-repeat;
  /* Each wrapped line gets its own pair of lines, instead of one background
     box stretched across the whole inline run: without this a link that breaks
     over two lines wipes at the wrong width and skips a fragment. */
  -webkit-box-decoration-break: clone;
          box-decoration-break: clone;
  padding-bottom: 0.12em;   /* drops both lines clear of the descenders */
  /* 0.6s matches .team-card__fill, so both fills read as one gesture. */
  transition: background-size 0.6s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1)),
              color 0.25s ease;
}
.rich-text a:not(.button-040):hover,
.rich-text a:not(.button-040):focus-visible,
.page-banner__text a:hover,
.page-banner__text a:focus-visible,
.benefits__card a:not(.button-040):hover,
.benefits__card a:not(.button-040):focus-visible,
.article a:not(.button-040):hover,
.article a:not(.button-040):focus-visible,
.article__text a:not(.button-040):hover,
.article__text a:not(.button-040):focus-visible,
.article__list a:not(.button-040):hover,
.article__list a:not(.button-040):focus-visible,
.entry-content a:hover,
.entry-content a:focus-visible,
.notice-pill__link:hover,
.notice-pill__link:focus-visible {
  background-size: 100% 2px, 100% 1px;
}

/* Rich-text links inherit the section's own colour, because those blocks sit
   on backgrounds that interpolate between white, navy and video and a fixed
   action blue sinks into the dark ones. */
.rich-text a:not(.button-040),
.page-banner__text a,
.benefits__card a:not(.button-040) { color: inherit; }

/* Links that always sit on a light background rest in the same navy as the
   copy (the hairline is the signal) and take the action blue while the line
   wipes across - the same rest/hover gesture as .news-card__title and
   .news-item__title (client 2026-08: inactive tekst-blauw met underline,
   hover "paars" met lijnanimatie, followed conform inactive; visited links
   simply fall back to the rest rule, there is no :visited style). The science
   cards qualify: the section background is video, but the cards themselves
   are always white (client 2026-08). */
.article a:not(.button-040):hover,
.article a:not(.button-040):focus-visible,
.article__text a:not(.button-040):hover,
.article__text a:not(.button-040):focus-visible,
.science-card__text a:not(.button-040):hover,
.science-card__text a:not(.button-040):focus-visible,
.article__list a:not(.button-040):hover,
.article__list a:not(.button-040):focus-visible,
.entry-content a:hover,
.entry-content a:focus-visible,
.notice-pill__link:hover,
.notice-pill__link:focus-visible {
  color: var(--c-action, #3660eb);
}

@media (prefers-reduced-motion: reduce) {
  .rich-text a:not(.button-040),
  .page-banner__text a,
  .benefits__card a:not(.button-040),
  .article a:not(.button-040),
  .article__text a:not(.button-040),
  .article__list a:not(.button-040),
  .entry-content a,
  .notice-pill__link { transition: color 0.25s ease; }
}

/* ---- 404 -------------------------------------------------- */
.error-404 {
  position: relative;
  isolation: isolate;
  min-height: 100vh;
  display: flex;
  align-items: center;
  overflow: hidden;
  padding-block: clamp(6rem, 18vh, 11rem);
}
/* Optional editor-set photo/video takes over from the decorative swirl. */
.error-404--has-media .error-404__swirl { display: none; }
.error-404__swirl {
  position: absolute;
  top: 50%;
  left: 62%;
  transform: translate(-50%, -50%);
  width: clamp(720px, 118vw, 1600px);
  aspect-ratio: 1500 / 1493;
  /* Sharp 1920px brand mark; replaced the 1200px hero-swirl.webp (client 2026-07). */
  background: url('../img/careers/brand-mark-bg.webp') center / contain no-repeat;
  opacity: 0.4;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(115deg, transparent 4%, rgba(0, 0, 0, 0.5) 34%, #000 68%);
          mask-image: linear-gradient(115deg, transparent 4%, rgba(0, 0, 0, 0.5) 34%, #000 68%);
}
.error-404__inner { position: relative; z-index: 1; max-width: 640px; }
.error-404__code {
  display: flex;
  align-items: center;
  gap: 0.04em;
  margin: clamp(1rem, 3vw, 1.75rem) 0 clamp(1rem, 2.5vw, 1.5rem);
  font-size: clamp(6rem, 21vw, 15rem);
  line-height: 0.82;
  font-weight: 400;
  letter-spacing: -0.02em;
  color: #fff;
}
.error-404__drop { display: inline-flex; width: 0.52em; }
.error-404__drop svg { width: 100%; height: auto; display: block; }
.error-404__drop svg path { fill: var(--accent, #00ffec); }
.error-404__title {
  font-size: clamp(1.75rem, 3.4vw, 2.75rem);
  line-height: 1.12;
  font-weight: 400;
  margin: 0 0 1rem;
}
.error-404__text {
  font-size: var(--fs-body);
  line-height: 1.55;
  opacity: 0.82;
  max-width: 46ch;
  margin: 0 0 clamp(1.75rem, 4vw, 2.5rem);
}
.error-404__actions { display: flex; flex-wrap: wrap; gap: 1rem; }

/* Centre-aligned hero variant (Settings > Content alignment = Centre). */
.hero--center .hero__content { align-items: center; text-align: center; margin-inline: auto; }
.hero--center .hero__title,
.hero--center .hero__text { max-width: none; margin-inline: auto; }
.hero--center .hero__buttons { justify-content: center; }

/* =========================================================
   GENERIC SECTION HELPERS
   ========================================================= */
.section__head { max-width: 60ch; margin-bottom: clamp(2rem, 5vw, 3.5rem); }
.section__head .eyebrow { margin-bottom: 1.25rem; }

.grid { display: grid; gap: clamp(1rem, 2vw, 1.5rem); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 900px) { .grid--3, .grid--4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .grid--3, .grid--4 { grid-template-columns: 1fr; } }

.card {
  background: rgba(255,255,255,0.6);
  border: 1px solid rgba(0,17,76,0.08);
  border-radius: var(--radius);
  padding: clamp(1.5rem, 2.5vw, 2.25rem);
  backdrop-filter: blur(4px);
}

/* =========================================================
   FOOTER
   ========================================================= */
.site-footer {
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding-block: clamp(3.5rem, 7vw, 120px) clamp(1.75rem, 3vw, 40px);
  color: #fff;
  /* Opaque gradient: --footer-top is the page's own closing colour when that
     page ends on a dark section (set by footer-reveal.js), so footer and page
     read as one surface there; on light-ending pages it stays the vibrant
     blue and the reveal gets its contrast. Darkens to navy either way. */
  background: linear-gradient(to bottom, var(--footer-top, var(--c-blue-vibrant, #09007b)) 0%, var(--footer-top, var(--c-blue-vibrant, #09007b)) 42%, var(--brand-blue-dark, #00114c) 100%);
}
/* Footer reveal ("scrolls out from behind the page"): the wrapper reserves the
   footer's height in normal flow and clips its own box; the footer inside is
   fixed to the viewport bottom, so it stands still while the page slides up
   off it. clip-path is essential — unlike overflow it also clips position:
   fixed descendants, which keeps the footer invisible until the wrapper
   scrolls in. Armed by footer-reveal.js; without JS or with reduced motion
   the footer simply stays in flow. */
.site-footer-reveal { position: relative; }
.site-footer-reveal.is-armed {
  /* Razor-hard clip edge on light pages: the crisp white->blue line IS the
     reveal there (client choice 2026-07). */
  clip-path: inset(0);
  height: var(--footer-h);
}
/* Adopted (dark-ending) pages get .is-soft from footer-reveal.js: there the
   footer's navy bottom would otherwise draw a hard line against the page's
   blue, and dark-over-dark should melt. The mask feathers the top of the clip
   window from transparent to opaque and travels with the reveal edge; kept
   smaller than the footer's top padding so content never sits half-faded. */
.site-footer-reveal.is-armed.is-soft {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 clamp(48px, 7vw, 120px));
  mask-image: linear-gradient(to bottom, transparent 0, #000 clamp(48px, 7vw, 120px));
}
.site-footer-reveal.is-armed .site-footer {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
}
/* Faint droplet watermark, top-left (Figma logo mark). */
.site-footer__watermark {
  position: absolute;
  /* Sits behind the headline + logo mark in the brand column (Figma). */
  top: clamp(10px, 2vw, 36px);
  left: clamp(-30px, 0vw, 30px);
  width: clamp(300px, 28vw, 440px);
  aspect-ratio: 492 / 641;
  background: url('../img/footer/watermark.svg') no-repeat center / contain;
  /* The droplet SVG is white with a built-in fade-to-transparent gradient; this
     single opacity governs how present it reads (Figma watermark ~0.12-0.15). */
  opacity: 0.14;
  pointer-events: none;
  z-index: -1;
  /* Gently floats up and down so the brand mark feels alive. */
  animation: alveus-watermark-float 11s ease-in-out infinite;
  will-change: transform;
}
@keyframes alveus-watermark-float {
  0%, 100% { transform: translateY(-14px); }
  50%      { transform: translateY(14px); }
}
@media (prefers-reduced-motion: reduce) {
  .site-footer__watermark { animation: none; transform: none; }
}

.site-footer__main {
  display: grid;
  grid-template-columns: minmax(0, 2.4fr) repeat(4, minmax(0, 1fr));
  column-gap: clamp(1.25rem, 2vw, 30px);
  row-gap: clamp(2.5rem, 4vw, 64px);
}
.site-footer__brand { grid-column: 1; grid-row: 1 / span 2; }
/* Navigation + General always start a fresh row under the office columns
   (client request 2026-08-04: alle adressen naast elkaar, rest daaronder).
   Pinning them to column 2 makes grid auto-flow skip to the next row that
   still has column 2 free, so this keeps working if the number of offices
   in Theme Settings changes. */
.site-footer__main > .footer-col--break { grid-column: 2; }
.site-footer__headline {
  /* Pull up to optically align with the logo cap height beside it. */
  margin: -14px 0 clamp(1.75rem, 3vw, 40px);
  max-width: 470px;
  font-size: clamp(1.6rem, 2.3vw, 35px);
  line-height: 1.43;            /* 50 / 35 */
  font-weight: 400;
}
.site-footer__headline strong { font-weight: 700; }
.site-footer__brand .site-logo svg,
.site-footer__brand .site-logo img { height: 54px; }
/* Footer logo is always white — it never reacts to the header dark/light state. */
.site-footer .site-logo { color: #fff; }

.footer-col__title {
  margin: 0 0 18px;
  font-size: 19px;
  line-height: 1.37;
  font-weight: 600;
  color: #fff;
}
.footer-col__body {
  font-style: normal;
  font-size: 14px;
  line-height: 22px;
  color: #c9cbd1;
}
.footer-col__links { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0; }
.footer-col__links a {
  display: inline-block;
  padding: 0;
  font-size: 14px;
  line-height: 22px;
  color: #c9cbd1;
}
.footer-general { list-style: none; margin: 0; padding: 0; }
.footer-general__row { display: grid; grid-template-columns: minmax(56px, auto) 1fr; gap: 6px 16px; line-height: 22px; }
.footer-general__label { font-size: 14px; color: #c9cbd1; }
.footer-general__value { font-size: 14px; color: #fff; }
.footer-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  margin-top: 24px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.15);
  color: #fff;
  transition: background 0.3s ease;
}
.footer-social:hover { background: rgba(255, 255, 255, 0.28); }

.site-footer a { transition: color 0.3s ease, opacity 0.3s ease; }
.footer-col__links a:hover,
.footer-general__value:hover { color: var(--accent, #00ffec); }

.site-footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  margin-top: clamp(2.5rem, 6vw, 90px);
  font-size: 14px;
  line-height: 20px;
  color: #c9cbd1;
}
.site-footer__legal { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem clamp(1.25rem, 2.5vw, 40px); }
.site-footer__legal a { color: #c9cbd1; }
.site-footer__legal a:hover { color: var(--accent, #00ffec); }
.site-footer__credit { color: #fff; opacity: 0.3; }
.site-footer__credit a { color: inherit; }

@media (max-width: 1000px) {
  .site-footer__main { grid-template-columns: 1fr 1fr; }
  .site-footer__brand { grid-column: 1 / -1; grid-row: auto; margin-bottom: clamp(1rem, 3vw, 24px); }
  /* Two columns: let everything flow, otherwise the nav break leaves a hole. */
  .site-footer__main > .footer-col--break { grid-column: auto; }
}
@media (max-width: 560px) {
  .site-footer__main { grid-template-columns: 1fr; }
  .site-footer__bottom { flex-direction: column; align-items: flex-start; }
}

/* =========================================================
   BUTTON-040 (provided component, themed to Alveus turquoise)
   ========================================================= */
:root {
  --button-040-color: #00114c;
  --button-040-color-background: #00ffec;
  --button-040-color-arrow: #00114c;
  --button-040-color-arrow-background: #00ffec;
  --button-040-color-focus: #fff;
  --button-040-height: 3.125em;
  --button-040-padding-x: 1.25em;
  --button-040-border-radius: 2.5em;
  --button-040-gap: 0.375em;
  --button-040-focus-inset: -0.125em;
  --button-040-ease-hover: cubic-bezier(0.625, 0.05, 0, 1);
  --button-040-ease-focus: cubic-bezier(0.32, 0.72, 0, 1);
}

.button-040 {
  color: var(--button-040-color);
  -webkit-user-select: none;
  user-select: none;
  height: var(--button-040-height);
  grid-column-gap: var(--button-040-gap);
  grid-row-gap: var(--button-040-gap);
  background-color: #0000;
  outline-style: none;
  justify-content: center;
  align-items: center;
  padding: 0;
  line-height: 1;
  font-size: var(--fs-btn);
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  display: inline-flex;
  position: relative;
  --button-040-translate-x: calc((var(--button-040-height) + var(--button-040-gap, 0em)) * -1);
  -webkit-tap-highlight-color: transparent;
}
.button-040::after {
  content: '';
  display: block;
  position: absolute;
  inset: var(--button-040-focus-inset);
  border-radius: var(--button-040-border-radius);
  transition: box-shadow 0.3s var(--button-040-ease-focus);
  pointer-events: none;
  z-index: 1;
}
.button-040:is(:focus-visible)::after { box-shadow: 0 0 0 0.125em var(--button-040-color-focus); }
.button-040__icon-wrap {
  aspect-ratio: 1;
  background-color: var(--button-040-color-arrow-background);
  border-radius: var(--button-040-border-radius);
  justify-content: center;
  align-items: center;
  height: 100%;
  display: flex;
  will-change: transform;
  transform-origin: left center;
  scale: 0;
  transition: scale 0.6s var(--button-040-ease-hover);
}
.button-040__icon-wrap.is--duplicate {
  z-index: 1;
  position: absolute;
  right: 0;
  transform-origin: right center;
  scale: 1;
}
.button-040__icon {
  width: 1em;
  height: 1em;
  color: var(--button-040-color-arrow);
  transition: rotate 0.6s var(--button-040-ease-hover);
  rotate: 45deg;
}
.button-040__icon-wrap.is--duplicate .button-040__icon { rotate: 0deg; }
.button-040__text-wrap {
  height: 100%;
  padding: 0 var(--button-040-padding-x);
  background-color: var(--button-040-color-background);
  border-radius: var(--button-040-border-radius);
  justify-content: center;
  align-items: center;
  display: flex;
  translate: var(--button-040-translate-x) 0 0;
  transition: translate 0.6s var(--button-040-ease-hover);
}

/* Ghost variant (transparent, light outline) for the secondary hero button */
.button-040[data-theme="ghost"] {
  --button-040-color: #fff;
  --button-040-color-background: rgba(255,255,255,0.08);
  --button-040-color-arrow: #00114c;
  --button-040-color-arrow-background: #fff;
}

/* Filled variant: red "Position filled" state (non-interactive, cross icon).
   Pill and circle share one red, like the turquoise default does (client
   feedback 2026-07: the two-tone red read as a mistake; the lighter red is
   softer). */
.button-040[data-theme="filled"] {
  --button-040-color: #fff;
  --button-040-color-background: #e5484d;
  --button-040-color-arrow: #fff;
  --button-040-color-arrow-background: #e5484d;
  cursor: default;
}

@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .button-040:is(:hover, :focus-visible) .button-040__icon-wrap,
  [data-hover]:is(:hover, :focus-visible) .button-040 .button-040__icon-wrap {
    scale: 1;
    transition: scale 0.735s 0.05s var(--button-040-ease-hover);
  }
  .button-040:is(:hover, :focus-visible) .button-040__icon-wrap.is--duplicate,
  [data-hover]:is(:hover, :focus-visible) .button-040 .button-040__icon-wrap.is--duplicate {
    scale: 0;
    transition: scale 0.735s 0.05s var(--button-040-ease-hover);
  }
  .button-040:is(:hover, :focus-visible) .button-040__icon-wrap.is--duplicate .button-040__icon,
  [data-hover]:is(:hover, :focus-visible) .button-040 .button-040__icon-wrap.is--duplicate .button-040__icon {
    rotate: 45deg;
  }
  .button-040:is(:hover, :focus-visible) .button-040__icon,
  [data-hover]:is(:hover, :focus-visible) .button-040 .button-040__icon {
    rotate: 0deg;
    transition: rotate 0.735s 0.05s var(--button-040-ease-hover);
  }
  .button-040:is(:hover, :focus-visible) .button-040__text-wrap,
  [data-hover]:is(:hover, :focus-visible) .button-040 .button-040__text-wrap {
    translate: 0 0 0;
    transition: translate 0.735s 0.05s var(--button-040-ease-hover);
  }
}

/* The filled state's cross must never rotate into a plus — pin it at 0deg in
   every rest/hover selector combination above. */
.button-040[data-theme="filled"] .button-040__icon,
.button-040[data-theme="filled"]:is(:hover, :focus-visible) .button-040__icon,
[data-hover]:is(:hover, :focus-visible) .button-040[data-theme="filled"] .button-040__icon,
[data-hover]:is(:hover, :focus-visible) .button-040[data-theme="filled"] .button-040__icon-wrap.is--duplicate .button-040__icon {
  rotate: 0deg;
}





/* =========================================================
   BLOCK: Key insights (Figma 1:630) — 1/3-2/3 intro + stat row
   Section sits directly under the hero on a vibrant-blue field.
   ========================================================= */
.section--insights {
  /* Figma: section starts at hero bottom; intro 130px in, cards 100px below. */
  padding-block: clamp(4rem, 8.13vw, 130px) clamp(4rem, 9vw, 150px);
  color: #fff;
}

/* Intro: same head layout as the team block (about-team__head) — title left,
   larger lead right, both tracks pushed to the container edges. */
.insights-intro {
  display: grid;
  grid-template-columns: minmax(0, 530px) minmax(0, 642px);
  justify-content: space-between;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
.insights-intro__title {
  margin: 0;
  font-size: var(--fs-h2);
  line-height: 1.19;
  font-weight: 400;
}
.insights-intro__text {
  margin: 0;
  font-size: clamp(1.125rem, 1.6vw, 24px);
  line-height: 1.34;
}
/* Anti-flash: GSAP loads from a CDN, so on tall screens where the intro is
   already in view the copy would paint fully-formed before insights.js primes
   it -- then hide and re-reveal (a visible flash). Hold it hidden until JS takes
   over (armReveals sets inline opacity and reveals it). Reduced motion / no-JS
   skips the reveal, so it must stay visible. */
html.js .insights-intro__text { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  html.js .insights-intro__text { opacity: 1 !important; }
}

/* Stat cards: 4 x 246px with 110px gutters = 1314px container. */
.insights-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(2rem, 6.88vw, 110px);
  margin-top: clamp(3rem, 6.25vw, 100px);
}
.insight {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  text-align: center;
}
.insight__value {
  font-size: clamp(1.75rem, 2.13vw, 34px);
  line-height: 1.294;
  font-weight: 400;
}
.insight__line {
  width: 40px;
  height: 1px;
  background: var(--action, #3660eb);
}
.insight__label {
  font-size: 18px;
  line-height: 1.556;
  opacity: 0.7;
}

@media (max-width: 900px) {
  .insights-intro { grid-template-columns: 1fr; }
  .insights-grid { grid-template-columns: repeat(2, 1fr); row-gap: clamp(2.5rem, 7vw, 3.5rem); }
}
@media (max-width: 520px) {
  .insights-grid { grid-template-columns: 1fr; }
}

/* Premium reveal — added by insights.js (.is-armed). Without JS / with reduced
   motion the cards simply stay visible. */
.section--insights.is-armed .insight {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1),
              transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}
.section--insights.is-armed .insight.is-visible {
  opacity: 1;
  transform: none;
}
.section--insights.is-armed .insight__line {
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.85s 0.12s cubic-bezier(0.16, 1, 0.3, 1);
}
.section--insights.is-armed .insight.is-visible .insight__line {
  transform: scaleX(1);
}
/* The value resolves to its real text once visible; keep it crisp mid-count. */
.section--insights .insight__value .num { font-variant-numeric: tabular-nums; }

@media (prefers-reduced-motion: reduce) {
  .section--insights.is-armed .insight,
  .section--insights.is-armed .insight__line { opacity: 1; transform: none; transition: none; }
}

/* =========================================================
   BLOCK: Science (Figma 1:182/1:515/1:518) — video background,
   white intro + three white cards. Video itself = .bg-video layer.
   ========================================================= */
.section--science {
  padding-block: clamp(5rem, 11.25vw, 180px) clamp(5rem, 10vw, 160px);
  color: #fff;
}
.section--science .eyebrow--science {
  opacity: 0.6;
  margin-bottom: clamp(1.25rem, 1.9vw, 30px);
}
.science__head { max-width: 760px; }
.science__title {
  margin: 0;
  font-size: clamp(2rem, 2.6vw, 42px);
  line-height: 1.19; /* 50/42 */
  font-weight: 400;
}

.science__cards {
  margin-top: clamp(2.5rem, 4.4vw, 70px);
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 1.9vw, 30px);
  align-items: stretch;
}
.science-card {
  background: #fff;
  border-radius: 8px;
  /* No fixed min-height: the content decides - the grid's stretch makes the
     tallest card set the height of all three on desktop, and stacked (mobile)
     each card hugs its own content. Bottom padding runs 4px past the top as
     an optical correction (client 2026-08-13): mathematically equal reads as
     bottom-light under a text block. */
  padding: clamp(1.75rem, 2vw, 32px) clamp(1.75rem, 2.5vw, 40px) clamp(2rem, 2.25vw, 36px);
  color: var(--brand-blue-raj, #042e7b);
}
.science-card__title {
  margin: 0 0 0.75rem;
  font-size: clamp(1.5rem, 1.75vw, 28px);
  line-height: 1.43; /* 40/28 */
  font-weight: 400;
}
.science-card__text {
  margin: 0;
  font-size: 18px;
  line-height: 1.556; /* 28/18 */
}

/* Staggered, reversible reveal (added by insights.js via .js-reveal).
   Enter: cards rise up 1-by-1 (left -> right).
   Exit (scroll up): cards fade out downward 1-by-1 in right -> left order
   (rightmost first). Asymmetric, so it uses keyframes rather than a single
   transition. Without JS / reduced motion the cards are simply visible. */
.science__cards.js-reveal .science-card {
  opacity: 0; /* hidden until first revealed */
  will-change: opacity, transform;
}
.science__cards.js-reveal .science-card.is-in {
  /* Slower, softer entrance for a more premium feel. */
  animation: sciCardIn 1.3s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.science__cards.js-reveal .science-card.is-out {
  animation: sciCardOut 0.6s cubic-bezier(0.7, 0, 0.84, 0) both;
}
/* enter stagger: left -> right (wider spacing so they arrive 1-by-1) */
.science__cards.js-reveal .science-card.is-in:nth-child(1) { animation-delay: 0s; }
.science__cards.js-reveal .science-card.is-in:nth-child(2) { animation-delay: 0.18s; }
.science__cards.js-reveal .science-card.is-in:nth-child(3) { animation-delay: 0.36s; }
/* exit stagger: right -> left (rightmost leaves first) */
.science__cards.js-reveal .science-card.is-out:nth-child(3) { animation-delay: 0s; }
.science__cards.js-reveal .science-card.is-out:nth-child(2) { animation-delay: 0.08s; }
.science__cards.js-reveal .science-card.is-out:nth-child(1) { animation-delay: 0.16s; }

@keyframes sciCardIn {
  from { opacity: 0; transform: translateY(50px); }
  to   { opacity: 1; transform: none; }
}
@keyframes sciCardOut {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(60px); }
}

@media (prefers-reduced-motion: reduce) {
  .science__cards.js-reveal .science-card { opacity: 1; animation: none; transform: none; }
}

@media (max-width: 900px) {
  .science__cards { grid-template-columns: 1fr; }
}

/* =========================================================
   BLOCK: Our treatments — patient-journey infographic
   Desktop: positioned over an aspect-ratio stage (cqw text scaling).
   Figures = silhouette mask (assets/img/figure.svg) + colour gradient.
   ========================================================= */
.section--treatments { padding-block: clamp(4rem, 8vw, 130px); color: var(--brand-blue-raj, #042e7b); }
.tx-heading {
  margin: 0 auto clamp(2.5rem, 5vw, 80px);
  max-width: 48ch;          /* wide enough for the heading to sit on 2 lines */
  text-wrap: balance;       /* even out those 2 lines */
  text-align: center;
  font-size: clamp(1.75rem, 2.6vw, 42px);
  line-height: 1.2;
  font-weight: 400;
  /* Brand Blue, matching every other section heading (not the deeper navy). */
  color: var(--brand-blue-raj, #042e7b);
}

/* Inlined diagram SVG (assets/img/treatments-diagram-2.svg): scales fluidly
   with the container, but never taller than the viewport (aspect 1314:819
   ~ 1.604, minus breathing room). */
.tx-diagram {
  width: 100%;
  max-width: calc((100vh - 140px) * 1.604);
  max-width: calc((100svh - 140px) * 1.604);
  margin-inline: auto;
}
.tx-scroll { width: 100%; }
.tx-svg { display: block; width: 100%; height: auto; }
.tx-scroll__nav { display: none; }
.tx-mhead { display: none; }

/* Phones: the SAME full-size diagram in a horizontal scroll strip (client
   2026-08-13, replacing the earlier two-panel retelling): as big as on
   desktop, swipeable left/right. JS (armTxScroll in insights.js) centres the
   strip on the 1-year figure - the fold where the journey splits - so both
   scroll directions advertise themselves, and sways it once on first sight.
   The hint chip below sways like a before/after slider handle; both retire
   (.is-panned) the moment the strip is actually used. */
@media (max-width: 760px) {
  /* Full-bleed: break out of .container so the strip runs edge to edge. */
  .tx-diagram {
    max-width: none;
    width: 100vw;
    margin-inline: calc(50% - 50vw);
  }
  .tx-scroll {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Soften both edges so the cut-off reads as "this carries on". A mask and
       not a white gradient on top: the canvas behind this section can be
       video, and a white fade would show up as a bar over it. */
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
            mask-image: linear-gradient(to right, transparent 0, #000 24px, #000 calc(100% - 24px), transparent 100%);
  }
  .tx-scroll::-webkit-scrollbar { display: none; }
  /* Height-fitted drawing (client 2026-08-13): the whole graph is one phone
     screen high (viewport minus room for the section's edges and the swipe
     hint), so you only ever pan left/right - never both axes at once. The
     width follows from the SVG's intrinsic 1314:819 ratio. The strip's
     font-size IS the drawing scale: the Figma mobile mock (node 5810:3762)
     is 675px tall, so 1em = 10 mock-pixels and every overlay measurement
     below is its mock measurement divided by ten. The px floors keep tiny
     phones from shrinking the type below reading size (drawing and type
     share one scale, so both clamps use the same bounds). */
  .tx-strip {
    position: relative;
    width: max-content;
    padding-inline: 24px;      /* keeps the outer figures clear of the edge masks */
    font-size: clamp(7px, calc((100vh - 175px) / 67.5), 10px);
    font-size: clamp(7px, calc((100svh - 175px) / 67.5), 10px);
  }
  .tx-scroll .tx-svg {
    height: clamp(472.5px, calc(100vh - 175px), 675px);
    height: clamp(472.5px, calc(100svh - 175px), 675px);
    width: auto;
    max-width: none;
  }

  /* Phase header, phone edition (Figma 5810:3762). The desktop header in the
     SVG spans both halves (full-width lines, long labels), which the strip
     never shows at once, so those groups hide here and the compact cluster
     takes over: "PHASE 1 / WL <-" | dot | "-> WM / PHASE 2". It reuses the
     SVG's own centre dot (cx = 50% of the drawing, cy = 63/819 of the height
     = 5.19em): the row's vertical centre lands exactly on it. All sizes are
     measured off the mock - WL/WM 20px type, PHASE 11px, arrows and dashes
     40px long and 2px thick, 20px clear of the 14px dot - written /10 in em
     so they track the drawing on any phone. */
  .tx-svg #WL,
  .tx-svg #WM { display: none; }
  .tx-mhead {
    position: absolute;
    top: 0;
    left: 24px;                /* = the strip's padding-inline */
    right: 24px;
    height: 6.2em;             /* bottom edge = dot centre (5.19em) + row half */
    display: flex;
    justify-content: center;
    align-items: flex-end;
    gap: 5.4em;                /* 20px clear + 14px dot + 20px clear */
    pointer-events: none;
  }
  .tx-mhead__side { display: flex; flex-direction: column; align-items: center; gap: 1.4em; }
  .tx-mhead__phase {
    font-size: 1.1em;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: rgba(4, 46, 123, 0.5);  /* the SVG's own PHASE colour (navy at .5) */
  }
  .tx-mhead__row { display: flex; align-items: center; gap: 1.5em; height: 2em; color: #042e7b; }
  .tx-mhead__abbr { font-size: 2em; line-height: 1; font-weight: 400; }
  .tx-mhead__line { width: 4em; height: 0; border-top: 0.2em solid currentColor; }
  .tx-mhead__arrow { display: block; width: 4em; height: 0.87em; }

  .tx-scroll__nav {
    display: flex;
    justify-content: center;
    margin-top: 18px;
  }
  .tx-scroll__hint {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: #8aa0c9;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 1.2px;
    text-transform: uppercase;
    transition: opacity 0.4s ease;
  }
  .tx-scroll__hint svg { display: block; }
  @media (prefers-reduced-motion: no-preference) {
    .tx-scroll__hint { animation: txSway 2.8s ease-in-out infinite; }
  }
  .tx-diagram.is-panned .tx-scroll__hint { opacity: 0; animation: none; }
}

/* Idle sway on the swipe hint: a gentle push each way, mirroring the two
   directions the strip can go. */
@keyframes txSway {
  0%, 100% { transform: none; }
  30%      { transform: translateX(-7px); }
  70%      { transform: translateX(7px); }
}

/* Homepage on phones (client 2026-08-13): the team cards and the pipeline
   table are hidden - each block keeps its intro and its button, which is the
   route to the full version (About Us / Pipeline page). Scoped to .home so
   the About Us team and the Pipeline page keep everything. scroll-bg.js
   skips display:none [data-bg] elements (the team grid carries one). */
@media (max-width: 760px) {
  .home .section--team .team-card--featured,
  .home .section--team .team__grid { display: none; }
  /* The block's bottom padding lives on .team__grid, so hiding the grid left
     the intro button flush against the blue edge (client 2026-08-13) — give
     the section its own bottom padding here, mirroring its top. */
  .home .section--team { padding-bottom: 4.5rem; }
  .home .section--pipeline .pl-table { display: none; }
}

/* =========================================================
   BLOCK: Development pipeline (Figma 1:554) — animated table.
   Left intro (lead + button) + right table whose bars fill across
   the phase columns on scroll-in (insights.js -> armPipeline).
   ========================================================= */
.section--pipeline {
  /* Bottom tightened from 13vw/200px: the clinical-trial notice below hugs
     the table at ~50px total (client feedback 2026-07: "50px ofzo" — split
     32px here + 18px notice top padding). */
  padding-block: clamp(4.5rem, 9vw, 145px) 32px;
  color: #fff;
  /* Ticks in the LIVE canvas colour: the sections are transparent over the
     fixed canvas, so this renders as a true gap punched through track + fill
     (and tracks the colour mid-scroll-blend) instead of a painted line on a
     coloured surface (client feedback 2026-07). */
  --pl-divider: var(--bg, #00114c);
  --pl-fill: linear-gradient(90deg, #09007b 0%, #00ffec 100%);
  /* Track backdrop: a subtle transparency ramp instead of a flat tint (Figma
     1:503 "BG pill": white 40% -> 100% at 20% layer opacity). Desktop fades
     out toward the LEFT (most visible at the far end of the bars); the 600px
     block mirrors it for mobile (client 2026-07). */
  /* Punched up from the literal Figma 8%->20% (client 2026-07: "een tikkie
     extremer"): near-invisible start so the pill visibly grows to full
     presence. */
  --pl-track-bg: linear-gradient(90deg, rgba(255, 255, 255, 0.03) 0%, rgba(255, 255, 255, 0.22) 100%);
}
.pl-head { max-width: 1281px; margin-bottom: clamp(2.5rem, 5vw, 70px); }
.pl-head .eyebrow--pipeline { opacity: 0.6; margin-bottom: clamp(1.25rem, 1.9vw, 30px); }
/* No width cap: the editor controls the line breaks (Enter in the Title
   field, rendered as <br>), so the title must be free to fill pl-head. */
.pl-title {
  margin: 0;
  font-size: clamp(2rem, 2.6vw, 42px);
  line-height: 1.19;             /* 50/42 */
  font-weight: 400;
}

/* Two-column body: intro (left) + table (right) */
.pl-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  gap: clamp(2rem, 4vw, 4.5rem);
  align-items: start;
}
.pl-intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(1.75rem, 3vw, 2.75rem);
  max-width: 417px;
  margin-top: 115px;
}
.pl-lead { margin: 0; font-size: var(--fs-body); line-height: 1.556; opacity: 0.9; }

/* CTA: match Figma "Button Large" — 50px pill, 12px label, pill flush with
   the arrow circle (no gap), slightly wider padding. */
.button-040--large,
.button-040--pipeline {
  --button-040-height: 4.1667em;   /* 50px @ 12px (Figma "Button Large") */
  --button-040-gap: 0.166em;       /* ~2px: pill nearly flush with the arrow circle */
  --button-040-padding-x: 1.8em;   /* ~22px */
}

/* --- Table --- */
.pl-table { width: 100%; }
.pl-row {
  display: grid;
  grid-template-columns: minmax(150px, 0.45fr) 1fr;   /* Figma ~260 : 605 */
  align-items: center;
  column-gap: clamp(1rem, 2vw, 2rem);
  /* Every row as tall as the 2-line-descriptor case (28 name + 2 gap + 44
     desc), so the pill-to-pill rhythm is identical however long a program's
     descriptor happens to be — the top gap read smaller than the rest
     (client 2026-07). Reset in the stacked <=600px layout. */
  min-height: 74px;
}
/* Tightened from 22px when the rows got their uniform 74px height (that
   height already carries ~17px visual air around each pill); together this
   keeps the equalised rhythm ~46px pill-to-pill instead of 56px (client
   2026-07: "compacter"). Mobile restores 1rem in the 600px block. */
.pl-row + .pl-row { margin-top: clamp(0.75rem, 1vw, 12px); }

/* Header */
.pl-row--head { margin-bottom: clamp(1.25rem, 1.9vw, 25px); }
.pl-asset--head strong { font-size: 18px; }
.pl-cols {
  display: grid;
  grid-template-columns: repeat(var(--phases, 3), 1fr);
}
.pl-cols span {
  text-align: center;
  font-size: 18px;
  font-weight: 700;
  line-height: 1.4;
}

/* Program (left) cell */
.pl-asset { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pl-asset strong { font-size: 18px; font-weight: 700; line-height: 1.4; }
.pl-asset__desc { font-size: 14px; line-height: 1.43; opacity: 0.6; }

/* Bar track */
.pl-track {
  position: relative;
  height: 40px;
  border-radius: 20px;
  background: var(--pl-track-bg);
  overflow: hidden;
}
/* Phase ticks sit ON TOP of the fill (z-index above .pl-track__fill), so they
   stay visible however far a bar has progressed. */
.pl-track__dividers { position: absolute; inset: 0; z-index: 2; }
.pl-track__dividers i {
  position: absolute;
  top: 0; bottom: 0;
  width: 2px;
  margin-left: -1px;
  background: var(--pl-divider);
}
.pl-track__fill {
  position: absolute;
  left: 0; top: 0; bottom: 0;
  z-index: 1;
  width: 0;                       /* animated to var(--p) on .is-in */
  border-radius: 20px;
  background: var(--pl-fill);
  transition: width 1.4s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: calc(var(--row, 0) * 0.12s);
}
.pl-table.is-in .pl-track__fill { width: calc(var(--p, 0) * 1%); }

@media (prefers-reduced-motion: reduce) {
  .pl-track__fill { transition: none; }
}

/* --- Responsive --- */
@media (max-width: 1000px) {
  .pl-body { grid-template-columns: 1fr; }
  /* Stacked flow reorders to lead text -> table -> CTA: the button reads as
     the section's closing action under the graphic (client 2026-07). Via
     display:contents the intro's children join the pl-body grid directly
     (this also drops the intro's 50px desktop alignment offset, which only
     doubled the head-body gap when stacked). */
  .pl-intro { display: contents; }
  .pl-lead { order: 1; }
  .pl-table { order: 2; }
  .pl-intro .button-040 { order: 3; justify-self: start; }
}
@media (max-width: 600px) {
  /* Mirrored track fade on mobile: most visible at the left, where the fill
     starts (client 2026-07). The light variant mirrors too, further below. */
  .section--pipeline { --pl-track-bg: linear-gradient(90deg, rgba(255, 255, 255, 0.22) 0%, rgba(255, 255, 255, 0.03) 100%); }
  .pl-head { margin-bottom: 1.5rem; }
  .pl-row { grid-template-columns: 1fr; row-gap: 0.6rem; min-height: 0; }
  .pl-row + .pl-row { margin-top: 1rem; } /* stacked rows have no height-air to absorb the tightening */
  /* Compact phase scale above the bars: the desktop header row minus the
     "Program" cell (on mobile every bar already carries its program name).
     The labels line up with the track columns of all bars below. */
  .pl-row--head { display: grid; margin-bottom: 0.9rem; }
  .pl-row--head .pl-asset--head { display: none; }
  .pl-cols span { font-size: 12px; }
  .pl-asset { gap: 1px; }
  .pl-track { height: 34px; border-radius: 17px; }
  .pl-track__fill { border-radius: 17px; }
}

/* =========================================================
   BLOCK: Team (Figma 1:531) — leadership cards.
   Intro + featured card on the blue background; the member-card row sits on a
   full-bleed white band (soft fade from the blue) so the dark-blue names read,
   matching the design's colour transition into the next (white) section. Each
   photo is two layers (backdrop zooms, cut-out person rises) and the bottom
   border fills with a gradient on hover — all CSS.
   ========================================================= */
.section--team {
  padding-block: clamp(4.5rem, 9vw, 145px) 0;
  color: #fff;
  overflow-x: clip;            /* contain the full-bleed white band */
  /* Column gap of the member row; the featured card's column and the row
     gap below both derive from it, so the featured card lines up exactly
     with the fourth column of the slider. */
  --team-gap: clamp(1.25rem, 2vw, 30px);
}

/* Top: intro (left) + featured card (right). The featured card is the same
   card as the slider cards below and takes exactly one slider column, so it
   sits flush above the row's last column (client 2026-09-01: same size as
   the rest; the old 487px card with the name overlaid is gone). */
.team__top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc((100% - 3 * var(--team-gap)) / 4);
  gap: clamp(2rem, 5vw, 80px);
  align-items: start;
}
.team__intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(1.5rem, 2.6vw, 2.4rem);
  /* Wide enough for the title on a single line; the lead keeps its own
     narrower reading measure below. */
  max-width: 760px;
}
.eyebrow--team { opacity: 0.5; }
.team__title {
  margin: 0;
  font-size: clamp(2rem, 2.6vw, 42px);
  line-height: 1.19;
  font-weight: 400;
}
.team__lead { margin: 0; font-size: var(--fs-body); line-height: 1.556; max-width: 536px; }
.team__intro .button-040 { margin-top: clamp(0.5rem, 1vw, 1rem); }

/* --- Two-layer photo (shared by featured + member cards) --- */
/* display:block — the photo is a <span> inside the clickable card buttons. */
.tc-photo { display: block; position: relative; border-radius: 8px; overflow: hidden; isolation: isolate; }
.tc-photo__bg,
.tc-photo__person {
  position: absolute; inset: 0;
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
  will-change: transform;
  transition: transform 0.7s cubic-bezier(0.65, 0.05, 0, 1);
  backface-visibility: hidden;
}
.tc-photo__bg { background-color: #c9d4e8; }      /* placeholder until image set */
.tc-photo__person { background-position: center top; z-index: 2; }
/* Turquoise overlay that washes the backdrop layer on hover (sits behind the
   cut-out person, so only the background gets tinted) — Figma Card/People. */
.tc-photo__tint {
  position: absolute; inset: 0; z-index: 1;
  background: rgba(0, 255, 236, 0.2);
  opacity: 0;
  transition: opacity 0.5s cubic-bezier(0.65, 0.05, 0, 1);
  pointer-events: none;
}
/* Hover: backdrop zooms in, person lifts up, turquoise wash fades in. */
.team-card:hover .tc-photo__bg,
.people-card:hover .tc-photo__bg { transform: scale(1.08); }
/* Rise capped so the layer's bottom edge never lifts above the card edge:
   scale(1.05) extends the bottom by +2.5%, so any translateY beyond -2.5%
   opens a seam under the person where the blurred backdrop shows through. */
.team-card:hover .tc-photo__person,
.people-card:hover .tc-photo__person { transform: translateY(-2.2%) scale(1.05); }
.team-card:hover .tc-photo__tint,
.people-card:hover .tc-photo__tint,
.team-card:focus-visible .tc-photo__tint,
.people-card:focus-visible .tc-photo__tint { opacity: 1; }
/* Never show a focus ring on the team cards (client 2026-07). Keyboard users
   still get a signal: the tint overlay above lights up on :focus-visible —
   only the UA outline is dropped. */
.team-card:focus,
.people-card:focus { outline: none; }

/* --- Featured card: a plain .team-card placed in the top grid. It fills its
   grid column (one slider column wide), so it needs no sizing of its own on
   desktop; the breakpoints below match it to the row's card widths. --- */
.team-card--featured { width: 100%; }

/* --- Member slider: full-bleed white band with a soft fade from the blue --- */
.team__grid {
  position: relative;
  z-index: 1;
  /* Sits one row gap under .team__top (no top padding — the margin is the
     whole visual distance), the same distance as between wrapped rows in the
     track, so the featured card reads as part of the same grid. */
  margin-top: clamp(1.5rem, 2vw, 30px);
  /* No baked background: the scroll canvas resolves to white here (data-bg), so
     this just lays out the cards inside the container. */
  padding-block: 0 clamp(4rem, 8vw, 130px);
}
/* The track holds every published team member. Without JS (or with reduced
   motion) it wraps like the old grid — right-aligned rows on a 4-up width, so
   the first cards hug the right edge under the featured card (Figma). */
.team__track {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: clamp(1.5rem, 2vw, 30px) var(--team-gap);
}
/* Slider mode (about.js adds is-sliding): the track becomes one endless row,
   clipped by the grid, that JS nudges one card to the left every few seconds.
   The card that slides out is re-appended, so the row never runs dry. */
.team__grid.is-sliding { overflow: hidden; }
.team__grid.is-sliding .team__track {
  flex-wrap: nowrap;
  justify-content: flex-start;
  /* Soft, even ease-in-out: the card glides rather than snaps. The 1s run
     leaves 0.8s of rest inside the 1.8s step interval (about.js). */
  transition: transform 1s cubic-bezier(0.45, 0, 0.2, 1);
  will-change: transform;
}
/* Edge cross-fade: the card sliding out and the card sliding in get is-fading
   toggled by about.js, so their opacity animates in step with the 1s track
   movement — soft dissolve at both edges instead of a hard clip. */
.team__grid.is-sliding .team-card {
  transition: opacity 1s cubic-bezier(0.45, 0, 0.2, 1);
}
.team__grid.is-sliding .team-card.is-fading { opacity: 0; }
/* JS holds this class while priming the incoming card and during the
   snap-back after a slide, so re-appending the first card, resetting the
   transform and the opacity swaps all land in the same visual frame. */
.team__grid.is-sliding .team__track.no-anim,
.team__grid.is-sliding .team__track.no-anim .team-card { transition: none; }

/* --- Member card (a button: opens the shared resume pop-up) --- */
.team-card {
  display: flex; flex-direction: column; gap: 20px;
  flex: 0 0 calc((100% - 3 * var(--team-gap)) / 4);
  margin: 0; padding: 0; border: 0; background: none;
  font-family: inherit; text-align: left; cursor: pointer;
}
.team-card .tc-photo { aspect-ratio: 1 / 1; }
/* Card texts follow the live canvas, not the grid's static data-fg: white while
   the canvas behind the member row is still blue, flipping to brand blue once
   the scroll blend resolves to white. body.header-dark is that exact signal
   (scroll-bg.js toggles it on canvas luminance every frame), so the texts flip
   in sync with the header, with the same 0.4s ease. */
.team-card__info {
  display: flex; flex-direction: column; gap: 5px;
  padding-inline: 10px; color: #fff;
  transition: color 0.4s linear;
}
body.header-dark .team-card__info { color: var(--brand-blue-raj, #042e7b); }
.team-card__name { font-size: 22px; line-height: 1.18; transition: color 0.4s ease; }
/* Hover follows the live canvas (same header-dark signal as the base colour):
   turquoise while the canvas behind the cards is still blue, the action blue
   once it has resolved to white. */
.team-card:hover .team-card__name,
.team-card:focus-visible .team-card__name { color: var(--accent, #00ffec); }
body.header-dark .team-card:hover .team-card__name,
body.header-dark .team-card:focus-visible .team-card__name { color: var(--c-action, #3660eb); }
.team-card__role { font-size: 14px; line-height: 1.57; opacity: 0.6; }
.team-card__border {
  position: relative; display: block; width: 100%; height: 2px;
  /* Bottom-aligned across the row: cards stretch to equal height, so a card
     without a role would otherwise end its border higher than its neighbours. */
  margin-top: auto;
  background: rgba(255, 255, 255, 0.35); overflow: hidden;
  transition: background-color 0.4s linear;
}
body.header-dark .team-card__border { background: rgba(4, 46, 123, 0.3); }
.team-card__fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: linear-gradient(90deg, #479ff3 0%, #00ffec 100%);
  transition: width 0.6s cubic-bezier(0.65, 0.05, 0, 1);
}
.team-card:hover .team-card__fill { width: 100%; }

@media (prefers-reduced-motion: reduce) {
  .tc-photo__bg, .tc-photo__person, .team-card__fill, .team__track { transition: none; }
}

/* --- Responsive --- */
@media (max-width: 1000px) {
  .team__top { grid-template-columns: 1fr; }
  /* Same width as the 2-up cards below it. */
  .team-card--featured { width: calc((100% - var(--team-gap)) / 2); }
  .team__track { justify-content: flex-start; }
  .team-card { flex: 0 0 calc((100% - var(--team-gap)) / 2); }
}
@media (max-width: 560px) {
  .team-card--featured { width: 100%; }
  .team-card { flex: 0 0 100%; }
}

/* =========================================================
   FEATURE STATEMENT (Figma 1:615 / 1:616)
   Big molecule render bleeding off the left edge, statement
   set on the right, vertically centred. Background is white
   (the scroll canvas has already resolved back to white).
   ========================================================= */
.section--feature {
  position: relative;
  overflow: clip;                 /* clip the molecule's left bleed */
  padding-block: clamp(2.5rem, 6vw, 96px);
}
/* Two equal halves: the molecule in the left column, the statement in the right
   (client 2026-08-04 via Astrid: the render was far too tall and ran half off
   the left edge of the page — "netjes in beeld", fifty-fifty with the quote).
   It used to be absolutely positioned, anchored to the right of a wider-than-
   the-column box so it deliberately bled off the page; now it is an in-flow
   cell that always fits inside its own half. */
.feature__inner {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: center;
  gap: clamp(24px, 4vw, 72px);
}
/* "Zwarte omlijning" (client 2026-08-04, seen by some people and not others):
   the molecule file has no alpha. It is H.264 on an opaque matte, tagged
   colr/nclc Rec.709 with NO range flag, and the matte is encoded at the
   limited-range white point (~235). A browser that reads it as limited range
   expands that to 254 — one step off the page's white, effectively invisible.
   A browser that reads it as full range leaves it at ~235, and then the video's
   rectangle shows up as a grey frame around the molecule. Same file, same CSS,
   different browser: exactly the report.

   Mitigation until the file is re-exported: brightness() on the video lifts the
   matte past 255 so it clips to pure white under BOTH readings, and this
   section's canvas is white (data-bg #ffffff), so the rectangle disappears.
   Deliberately NOT mix-blend-mode: multiply — that hides the matte on any
   backdrop, but it also multiplies the molecule itself, so during a canvas
   transition (or on a jump-scroll that lands before the canvas has resolved)
   the molecule sinks into the navy and vanishes. A white box for those few
   frames is the better failure.

   The real fix is at the source: re-export as MP4 (this file is a QuickTime
   'qt  ' container served as video/quicktime, which Firefox does not accept at
   all) with a pure white matte, or with real alpha as VP9/WebM. The filter here
   can go once that lands. */
.feature__media {
  position: relative;
  display: flex;
  justify-content: center;
}
.feature__img {
  position: relative;
  display: block;
  /* Sized by height so the render stays comfortably shorter than before (480px
     instead of 760px at the 1600 frame); max-width keeps it inside its half on
     narrower viewports, where the height cap would otherwise make it wider than
     the column. object-fit: contain means that clamp never distorts it. */
  height: clamp(280px, 30vw, 480px);
  width: auto;
  max-width: 100%;
  object-fit: contain;
  /* --py is the scroll-linked parallax offset set by insights.js (armParallax).
     data-parallax is 30 on the element: the drift has to stay well inside the
     section's own padding-block, otherwise overflow: clip would shave the top or
     bottom off the molecule on the way in and out — the exact thing the client
     asked us to fix. */
  transform: translate3d(0, var(--py, 0px), 0);
  /* 255 / 235 = 1.085: the smallest gain that clips a full-range-read matte to
     pure white. See .feature__media. */
  filter: brightness(1.09);
  z-index: 0;
  pointer-events: none;
  will-change: transform;
}
/* iOS/iPadOS only (-webkit-touch-callout exists nowhere else): there the
   brightness() mitigation above backfires. iOS's own video pipeline already
   expands the limited-range matte to true white, and the extra gain on top can
   render ABOVE page white on EDR-capable screens (OLED iPhones) - the video
   then glows as a bright rectangle and the genuinely #ffffff section next to
   it reads grey by contrast (client 2026-08: "de video oogt witter en daardoor
   toont hij een wit vlak"). Without the filter, matte == page white and the
   rectangle disappears. Desktop Safari and every other browser keep the
   clip-to-white above for decoders that leave the matte at ~235. */
@supports (-webkit-touch-callout: none) {
  .feature__img { filter: none; }
}
/* Video variant: size, position, parallax and the mobile rules all come from
   .feature__img, so the video sits exactly where a still render would.

   The old horizontal nudge (--feature-video-shift) is gone with the bleed it
   compensated for: it existed only to re-centre the frame against the right: 0
   anchor of the absolutely positioned layout. Now the element is centred in its
   own column, so nothing has to be pushed back. object-fit: contain keeps a
   future file with different proportions letterboxed rather than stretched. */
.feature__video { object-fit: contain; }
.feature__statement {
  position: relative;
  z-index: 1;
  margin: 0;
  color: var(--brand-blue-raj, #042e7b);
  font-weight: 400;
  /* Was 42px at the 1600 frame; taken down a step on client request
     (2026-08-04) now that the column is half the row instead of 754px. */
  font-size: clamp(1.375rem, 2.25vw, 2.25rem);  /* 36px at the 1600 frame */
  line-height: 1.25;
  letter-spacing: 0;
}
/* Text link under the statement: same arrow link as the news block's "See all",
   so a text link reads the same wherever it turns up. */
.feature__link {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  margin-top: clamp(1.5rem, 2.2vw, 34px);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--brand-blue-raj, #042e7b);
}
.feature__link svg { color: var(--ice, #00ffec); transition: transform 0.4s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)); }
.feature__link:hover svg { transform: translateX(5px); }

@media (max-width: 860px) {
  .section--feature { padding-block: clamp(2rem, 7vw, 64px); }
  .feature__inner { display: block; }
  .feature__media {
    /* Stacked: centred and fully inside the gutter. The old negative margin
       mirrored the desktop left-bleed, which no longer exists. */
    justify-content: center;
    margin-bottom: clamp(16px, 4vw, 36px);
  }
  .feature__img {
    transform: none;
    height: auto;
    width: min(78vw, 420px);
    max-width: 100%;
  }
  .feature__statement {
    width: 100%;
    font-size: clamp(1.25rem, 4.8vw, 1.75rem);
  }

  /* White behind the molecule, always (client 2026-08-04: "op mobiel de
     achtergrond achter de quote met de molecule wit maken. Nu is die grijs en
     zie je dat de molecule movie wit is").

     Cause: the video has no alpha, it is the render on an opaque white matte
     (see .feature__media). Stacked on mobile the media is the FIRST thing in
     the section, so it enters the screen while the canvas is still blending out
     of the blue section above it - and against that in-between tint the matte
     reads as a white block around the molecule. Desktop does not show it
     because the molecule sits vertically centred in a much taller section, by
     which point the canvas has long resolved to white.

     Rather than chase the blend timing, the section paints its own white here
     and feathers it into the canvas across its padding, top and bottom, so the
     matte is on white from the first frame. Only when the block is actually set
     to a white background; a differently coloured pipeline of this block keeps
     the canvas. Can be dropped once the video is re-exported with real alpha. */
  /* Third attempt, and this time the dumbest thing that can possibly work: a
     flat opaque white, no gradient, no math functions, nothing a parser can
     choke on and silently drop. The soft join with the canvas is gone with it,
     which costs nothing here because the sections above and below this one are
     white as well. !important because the whole point is that nothing further
     down the cascade gets to make this grey again. */
  .section--feature[data-bg="#ffffff"] {
    padding-top: 84px;
    background-color: #ffffff !important;
    background-image: none !important;
  }
}

/* =========================================================
   USP CARDS (Figma 1:698) — "What separates Alveus from the rest"
   Four image cards on white. Reveal one by one on scroll-in
   (left -> right); fade out in reverse (right -> left) on the
   way out. The per-card stagger direction is set by insights.js
   (armUsp) via inline transition-delay; CSS owns the look.
   ========================================================= */
.section--usp {
  padding-block: clamp(3rem, 7vw, 130px) clamp(4rem, 9vw, 150px);
  color: var(--brand-blue-raj, #042e7b);
}
.usp__heading {
  margin: 0 0 clamp(2.5rem, 5vw, 80px);
  font-size: var(--fs-h2);
  line-height: 1.19;
  font-weight: 400;
  color: var(--brand-blue-raj, #042e7b);
}
.usp__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.25rem, 2vw, 30px);
}
.usp-card { display: flex; flex-direction: column; }
/* Photo box lifts 10px on hover with a soft drop shadow underneath (client
   2026-07); the gradient bar sits inside and travels along. The image keeps
   its own subtle zoom on top. */
.usp-card__media {
  position: relative;
  aspect-ratio: 306 / 393;
  border-radius: 8px;
  overflow: hidden;
  background: #cfe0f2;            /* placeholder tint while the image loads */
  box-shadow: 0 0 0 rgba(4, 46, 123, 0);
  transition: transform 0.55s cubic-bezier(0.65, 0.05, 0, 1),
              box-shadow 0.55s cubic-bezier(0.65, 0.05, 0, 1);
  will-change: transform;
}
/* Every hover/focus state below is scoped to --linked: a card without a link in
   Theme/ACF is not clickable, so it must stay completely inert under the mouse
   (client 2026-08-04). An inline text link inside the card body does not count
   as "a link on the block" and must not wake the card state either. */
.usp-card--linked:hover .usp-card__media,
.usp-card--linked:focus-within .usp-card__media {
  transform: translateY(-10px);
  box-shadow: 0 18px 34px rgba(4, 46, 123, 0.22);
}
.usp-card__img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1);
  transition: transform 0.75s cubic-bezier(0.65, 0.05, 0, 1);
  will-change: transform;
}
.usp-card--linked:hover .usp-card__img,
.usp-card--linked:focus-within .usp-card__img { transform: scale(1.06); }
/* 4px gradient bar pinned to the bottom of the image (Figma "Active" = hover
   state): hidden by default, fills left -> right on hover. clip-path reveals the
   full-width gradient progressively so the colours never squash. */
.usp-card__bar {
  position: absolute;
  /* 1px overdraw below the box: during the lift the card sits on fractional
     pixel positions and the bar rasterises on its own layer, which can open a
     hairline seam at the bottom edge. The box's overflow clip trims the extra
     pixel, so the visible bar stays exactly 4px. */
  left: 0; right: 0; bottom: -1px;
  height: 5px;
  background: linear-gradient(90deg, var(--numab-blue, #479ff3) 0%, var(--ice, #00ffec) 100%);
  /* No radius of its own: the box's 8px overflow clip shapes the corners, so
     the bar follows exactly the same curve as the card edge — an own (4px)
     radius mismatched the card's and left a sliver showing in the corners. */
  clip-path: inset(0 100% 0 0);   /* fully clipped from the right => 0 width, anchored left */
  transition: clip-path 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
}
.usp-card--linked:hover .usp-card__bar,
.usp-card--linked:focus-within .usp-card__bar { clip-path: inset(0 0 0 0); }
.usp-card__body {
  display: flex; flex-direction: column; gap: 20px;
  margin-top: clamp(1.25rem, 1.8vw, 30px);
}
.usp-card__title {
  margin: 0;
  font-size: 28px; line-height: 1.43;   /* 40 / 28 */
  font-weight: 400;
  color: var(--brand-blue-raj, #042e7b);
  transition: color 0.4s ease;
  /* Reserve two lines so the text under every card starts level, whether the
     title runs one line or two. */
  min-height: 2.86em;
}
/* Hover: recolour only (the slide-right is gone per client 2026-07). */
.usp-card--linked:hover .usp-card__title,
.usp-card--linked:focus-within .usp-card__title { color: var(--c-action, #3660eb); }
/* Optional whole-card link (ACF "Link" on the card, client 2026-07: internal
   linking). The anchor is a direct child of the card, stretched over all of it,
   and carries a screen-reader-only label. It must stay outside the title:
   insights.js wraps every h3 in SplitText line masks that are position:
   relative, so an overlay anchored inside the title takes a single line as its
   containing block and only covers the headline. */
.usp-card--linked { position: relative; }
.usp-card__link {
  position: absolute;
  inset: 0;
  z-index: 1;
  color: inherit;
  text-decoration: none;
}
/* Inline links an editor wrote in the card text stay reachable above that
   overlay, so turning a card into a link never swallows them. */
.usp-card--linked .usp-card__text a { position: relative; z-index: 2; }
.usp-card__text {
  margin: 0;
  font-size: 18px; line-height: 1.56;    /* 28 / 18 */
  color: var(--brand-blue-raj, #042e7b);
}

/* --- Reveal: hidden start, rise + fade; stagger via inline --d delay --- */
.usp__grid.js-reveal .usp-card {
  opacity: 0;
  transform: translateY(44px);
  transition: opacity 0.7s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)),
              transform 0.7s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
  transition-delay: var(--d, 0s);
  will-change: opacity, transform;
}
.usp__grid.js-reveal .usp-card.is-in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .usp__grid.js-reveal .usp-card { transition: none; opacity: 1; transform: none; }
  .usp-card__bar,
  .usp-card__img,
  .usp-card__media,
  .usp-card__title { transition: none; }
  .usp-card--linked:hover .usp-card__img,
  .usp-card--linked:hover .usp-card__media { transform: none; }
}

/* --- Responsive --- */
@media (max-width: 1000px) {
  .usp__grid { grid-template-columns: repeat(2, 1fr); gap: clamp(1.5rem, 3vw, 36px) clamp(1.25rem, 2vw, 30px); }
}
@media (max-width: 560px) {
  .usp__grid { grid-template-columns: 1fr; max-width: 420px; }
  /* Single column: no cross-card alignment to keep, so no reserved height. */
  .usp-card__title { font-size: 24px; min-height: 0; }
}

/* =========================================================
   LATEST NEWS (Figma 1:645 / 1:648-650) + NOTICE PILL (1:691)
   Heading + "See all" link, then real WP posts as text cards.
   ========================================================= */
.section--news {
  padding-block: clamp(3rem, 7vw, 130px) clamp(3.5rem, 8vw, 140px);
  color: var(--brand-blue-raj, #042e7b);
}
.news__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: clamp(2.5rem, 5vw, 85px);
}
.news__head-text { display: flex; flex-direction: column; align-items: flex-start; }
.news__head-text .eyebrow { margin-bottom: clamp(20px, 2.2vw, 30px); }   /* Figma: eyebrow -> title = 30px */
.news__heading {
  margin: 0;
  font-size: var(--fs-h2);
  line-height: 1.05;
  font-weight: 400;
  color: var(--brand-blue-raj, #042e7b);
}
.news__seeall {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  flex-shrink: 0;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--brand-blue-raj, #042e7b);
  white-space: nowrap;
}
.news__seeall svg { color: var(--ice, #00ffec); transition: transform 0.4s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)); }
.news__seeall:hover svg { transform: translateX(5px); }

.news__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px;
}
.news-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 31px;
  min-height: 310px;
  padding: 40px 30px 41px;
  border-radius: 8px;
  background: var(--blue-10, #e8f0ff);
  color: var(--brand-blue-raj, #042e7b);
  text-decoration: none;
  transition: transform 0.5s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)),
              box-shadow 0.5s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
}
/* Bottom accent bar (blue -> turquoise) that wipes in on hover (Figma 20:648). */
.news-card::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 4px;
  border-radius: 0 0 8px 8px;
  background: linear-gradient(90deg, var(--c-action, #3660eb) 0%, var(--accent, #00ffec) 100%);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
}
.news-card:hover {
  transform: translateY(-10px);
  box-shadow: 0 10px 40px 0 rgba(2, 34, 94, 0.3);
}
.news-card:hover::after { transform: scaleX(1); }
.news-card__meta { display: flex; align-items: center; gap: 20px; }
.news-card__tag {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 22px;
  border-radius: 505px;
  background: var(--brand-blue-raj, #042e7b);
  color: #fff;
  font-size: 12px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background 0.4s ease, color 0.4s ease;
}
/* Hover: the category tag flips to turquoise with navy text. */
.news-card:hover .news-card__tag {
  background: var(--accent, #00ffec);
  color: var(--brand-blue-raj, #042e7b);
}
.news-card__date { font-size: 14px; line-height: 1.57; color: var(--brand-blue-raj, #042e7b); }
.news-card__title {
  margin: 0;
  font-size: 18px;
  line-height: 1.56;            /* 28 / 18 */
  font-weight: 400;
  color: var(--brand-blue-raj, #042e7b);
  transition: color 0.4s ease;
  /* keep cards uniform: clamp long headlines */
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  overflow: hidden;
}
/* The headline takes the action colour on hover, like every other card title
   on the site (.news-item, .position, .usp-card). The news grid was the one
   clickable card that stayed navy (client 2026-07). */
.news-card:hover .news-card__title,
.news-card:focus-visible .news-card__title { color: var(--c-action, #3660eb); }
.news__empty { color: var(--brand-blue-raj, #042e7b); opacity: 0.7; }

/* --- Notice pill (managed in Theme Settings; reusable) --- */
.notice-pill {
  display: flex;
  align-items: center;
  gap: 26px;
  min-height: 80px;
  margin-top: clamp(2.5rem, 5vw, 70px);
  padding: 14px clamp(24px, 4.5vw, 60px);
  border-radius: 40px;
  background: var(--blue-10, #e8f0ff);
  color: var(--brand-blue-raj, #042e7b);
}
.notice-pill__label { font-size: 18px; font-weight: 700; line-height: 1.4; white-space: nowrap; }
.notice-pill__arrow { display: inline-flex; flex-shrink: 0; color: var(--brand-blue-raj, #042e7b); }
.notice-pill__text { margin: 0; font-size: 18px; line-height: 1.56; }
/* The thickness longhand has to sit here, after the `text-decoration`
   shorthand: the shorthand resets thickness to `auto`, so declaring it in the
   shared link block further up would be wiped by this rule. */
/* Underline comes from the shared inline-link rule near the top (a background
   pair that wipes on hover), so only the colour lives here. Rest = navy like
   the pill copy; hover recolours to action blue via the shared hover rule. */
.notice-pill__link { color: var(--brand-blue-raj, #042e7b); }

@media (prefers-reduced-motion: reduce) {
  .news-card, .news__seeall svg { transition: none; }
}

/* --- Responsive --- */
@media (max-width: 1024px) {
  .news__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 680px) {
  .news__head { flex-direction: column; align-items: flex-start; gap: 1.25rem; }
  .news__grid { grid-template-columns: 1fr; }
  .news-card { min-height: 0; }
  .notice-pill { flex-wrap: wrap; gap: 12px 18px; border-radius: 24px; padding: 22px clamp(20px, 5vw, 32px); }
  .notice-pill__arrow { display: none; }
}

/* =========================================================
   INVESTORS / PARTNERS (Figma 1:238) — white logo wall on blue
   ========================================================= */
.section--investors {
  padding-block: clamp(3.5rem, 8vw, 150px);
  color: #fff;
}
.investors__head { display: flex; flex-direction: column; align-items: flex-start; }
.investors__head .eyebrow { margin-bottom: clamp(20px, 2.2vw, 30px); opacity: 0.6; }
.investors__title {
  margin: 0;
  font-size: var(--fs-h2);
  line-height: 1.19;
  font-weight: 400;
  color: #fff;
}
.investors__subhead {
  margin: clamp(18px, 2.2vw, 30px) 0 0;
  font-size: clamp(1.25rem, 1.8vw, 1.75rem);   /* 28px */
  line-height: 1.43;
  color: #fff;
}
.investors__grid {
  list-style: none;
  margin: clamp(2.75rem, 6vw, 96px) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(2.5rem, 6vw, 88px) clamp(1.5rem, 3vw, 40px);
  align-items: center;
}
.investors__item { display: flex; align-items: center; justify-content: center; min-height: 84px; }
.investors__link { display: flex; width: 100%; align-items: center; justify-content: center; transition: opacity 0.3s ease; }
.investors__link:hover { opacity: 0.7; }
/* Fixed box + object-fit:contain — the logo letterboxes inside, centered both
   ways. The SVG sources carry only a viewBox (width/height = 100%), and auto
   sizing + max-* constraints can distort those; a fixed box cannot. */
.investors__logo {
  display: block;
  width: min(100%, 180px);
  height: clamp(40px, 4.4vw, 64px);
  object-fit: contain;
  object-position: center;
  /* Per-logo optical balance: --logo-scale comes from the Logo CPT's Scale
     field (inline style). Transform only — the grid layout is untouched. */
  transform: scale(var(--logo-scale, 1));
  transform-origin: center;
}

@media (max-width: 860px) {
  .investors__grid { grid-template-columns: repeat(2, 1fr); gap: clamp(2.25rem, 7vw, 56px) clamp(1.5rem, 4vw, 32px); }
  /* Mobile uses its OWN per-logo optical scale (--logo-scale-m, from the
     Logo CPT's "Scale (mobile)" field): the desktop factors are tuned for
     the large grid and read as oversized in the small 2-column boxes
     (client 2026-07). Unset for a logo = no scaling here. */
  .investors__logo { transform: scale(var(--logo-scale-m, 1)); }
}
@media (max-width: 420px) {
  .investors__logo { height: 44px; }
}

/* --- Reveal: logos rise + fade in one-by-one; stagger via inline --d delay
   (added by insights.js via .js-reveal). Reversible on scroll out. --- */
.investors__grid.js-reveal .investors__item {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 0.6s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)),
              transform 0.6s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
  transition-delay: var(--d, 0s);
  will-change: opacity, transform;
}
.investors__grid.js-reveal .investors__item.is-in {
  opacity: 1;
  transform: none;
}

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

/* =========================================================
   ABOUT US — hero / team directory / resume / mission
   (Figma 16:400 + 16:789). Pages are block-driven, so these
   blocks can be used on any page.
   ========================================================= */

/* ---- Eyebrow on dark photo backgrounds ------------------ */
.eyebrow--light { opacity: 0.7; }

/* ---- About hero: compact banner that scales with content - */
.about-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  isolation: isolate;
  overflow: clip;
  padding-top: 200px;
  padding-bottom: 150px;
  color: #fff;
}
@media (max-width: 820px) {
  .about-hero {
    padding-top: 150px;
    padding-bottom: 100px;
  }
}
.about-hero__bg { position: absolute; inset: 0; z-index: -1; }
/* Both photo AND video fill the banner and stay centered, so a source that is
   smaller than the hero is scaled up to cover it instead of sitting at its
   own (small) size in the top-left. */
.about-hero__bg img,
.about-hero__bg video { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }
.about-hero__overlay {
  position: absolute;
  inset: 0;
  /* Figma: #042e7b(.8) top -> #00114c(.85) bottom, plus a little extra
     darkening lower-left so the title stays crisp. */
  background:
    linear-gradient(180deg, rgba(4, 46, 123, 0.52) 0%, rgba(4, 46, 123, 0.5) 42%, rgba(0, 17, 76, 0.62) 100%),
    linear-gradient(75deg, rgba(0, 17, 76, 0.2) 0%, rgba(0, 17, 76, 0) 48%);
}
.about-hero__inner { position: relative; display: flex; flex-direction: column; align-items: flex-start; }
.about-hero__inner .eyebrow { margin-bottom: clamp(14px, 1.8vw, 22px); }
.about-hero__title {
  margin: 0;
  max-width: none; /* line breaks are set by the editor (<br>) */
  font-size: clamp(2.4rem, 5.2vw, 60px);
  line-height: 1.02;
  font-weight: 400;
  color: #fff;
}

/* ---- Meet the team -------------------------------------- */
/* No baked background here: the About hero keeps the scroll-bg canvas white
   (data-bg #fff), so this section is white at scroll-top AND can blend smoothly
   into the blue mission section below via the scroll background. */
.about-team__head {
  display: grid;
  grid-template-columns: minmax(0, 530px) minmax(0, 642px);
  justify-content: space-between;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: start;
}
.about-team__heading { margin: 0; font-size: var(--fs-h2); line-height: 1.19; font-weight: 400; }
.about-team__intro {
  margin: 0;
  font-size: clamp(1.125rem, 1.6vw, 24px);
  line-height: 1.34;
}

/* ---- Tab switcher: bordered track with a teal pill sliding INSIDE it ----
   (Figma 16:431 — Filter Pill: the active pill sits within a rounded, blue-
   bordered track and slides between options). */
.about-tabs {
  position: relative;
  display: inline-flex;
  padding: 5px;
  border: 1px solid rgba(54, 96, 235, 0.2);
  border-radius: 999px;
  margin-top: clamp(2.25rem, 5vw, 4.5rem);
}
.about-tabs__indicator {
  position: absolute;
  top: 50%;
  left: 0;
  height: calc(100% - 10px);
  border-radius: 999px;
  background: var(--accent, #00ffec);
  z-index: 0;
  transform: translate(5px, -50%); /* sits over the first tab until JS measures */
  transition: transform 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)),
              width 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
  will-change: transform, width;
}
.about-tab {
  position: relative;
  z-index: 1;
  appearance: none;
  margin: 0;
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 11px 30px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  line-height: 18px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--c-brand, #042e7b);
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.4s ease;
}
/* On phones the two default labels ("EXECUTIVE TEAM" / "BOARD OF DIRECTORS")
   run past the viewport at the desktop padding + letter-spacing. Let the pill
   span the row and shrink the type so both tabs fit without a horizontal
   scroll. Tabs share the width evenly (min-width:0 lets long labels ellipsize
   rather than force overflow). */
@media (max-width: 600px) {
  .about-tabs {
    display: flex;
    width: 100%;
    max-width: 420px;
    margin-top: clamp(1.75rem, 6vw, 2.5rem);
  }
  .about-tab {
    flex: 1 1 0;
    min-width: 0;
    padding: 10px clamp(10px, 3vw, 18px);
    font-size: clamp(10px, 2.8vw, 12px);
    letter-spacing: 0.4px;
    text-align: center;
    text-overflow: ellipsis;
    overflow: hidden;
  }
}

/* ---- Team grid + cards (Card/People) -------------------- */
.about-team__panels { position: relative; margin-top: clamp(2rem, 4.5vw, 3.75rem); }
.about-team__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(2.5rem, 4vw, 3.75rem) clamp(1.5rem, 2.3vw, 30px);
  transition: opacity 0.4s ease, transform 0.45s var(--ease-osmo, cubic-bezier(0.16, 1, 0.3, 1));
}
.about-team__grid[hidden] { display: none; }

.people-card {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  text-align: left;
  color: var(--c-brand, #042e7b);
  cursor: pointer;
}
.people-card .tc-photo { width: 100%; aspect-ratio: 306 / 300; }
.people-card__info { display: flex; flex-direction: column; gap: 5px; padding: 0 10px; }
.people-card__name { font-size: 22px; line-height: 26px; transition: color 0.35s ease; }
.people-card:hover .people-card__name,
.people-card:focus-visible .people-card__name { color: var(--c-action, #3660eb); }
.people-card__role { font-size: 14px; line-height: 22px; opacity: 0.6; }
.people-card__border {
  position: relative; display: block; width: 100%; height: 2px;
  /* Bottom-aligned across the row: grid items stretch to equal height, so a
     card without a role (or a shorter name) would end its border higher. */
  margin-top: auto;
  background: rgba(4, 46, 123, 0.3); overflow: hidden;
}
.people-card__fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0;
  background: linear-gradient(90deg, #479ff3 0%, #00ffec 100%);
  transition: width 0.6s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
}
.people-card:hover .people-card__fill,
.people-card:focus-visible .people-card__fill { width: 100%; }

/* ---- Resume pop-up -------------------------------------- */
.resume {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
}
.resume[hidden] { display: none; }
.resume__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(9, 0, 123, 0.95) 0%, rgba(0, 17, 76, 0.97) 100%);
  -webkit-backdrop-filter: blur(3px);
  backdrop-filter: blur(3px);
  opacity: 0;
  /* Exit: the gradient backdrop clears LAST, once the content has left. */
  transition: opacity 0.5s ease 0.3s;
  cursor: pointer;
}
.resume__dialog {
  position: relative;
  z-index: 1;
  width: 100%;
  max-height: 100dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  /* Deliberately NO align-items: center — a centred flex item taller than the
     dialog gets its top clipped beyond scroll reach. The layout's
     margin-block: auto centres it when it fits and lets it scroll naturally
     from the top when it doesn't (long bios on phones). */
}

/* Premium choreographed enter/exit. The overlay, photo, text and close button
   each run on their own timeline; the delays differ between enter (on .is-open)
   and exit (on the base rule), so OPEN builds up backdrop -> photo -> text ->
   close, and CLOSE plays it back the other way: the photo drops, then the text,
   then the close button slides off to the right, then the gradient fades out. */
.resume__media,
.resume__body {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity 0.45s ease, transform 0.6s var(--ease-osmo, cubic-bezier(0.16, 1, 0.3, 1));
  will-change: opacity, transform;
}
/* Exit order (when .is-open is removed): photo first, then the text just after. */
.resume__media { transition-delay: 0s; }
.resume__body  { transition-delay: 0.08s; }

.resume.is-open .resume__overlay { opacity: 1; transition-delay: 0s; }
.resume.is-open .resume__media { opacity: 1; transform: none; transition-delay: 0.18s; }
.resume.is-open .resume__body  { opacity: 1; transform: none; transition-delay: 0.28s; }

.resume__layout {
  display: grid;
  grid-template-columns: minmax(0, 418px) minmax(0, 1fr);
  column-gap: clamp(2rem, 3.4vw, 48px);
  align-items: center;
  padding-block: clamp(96px, 14vh, 140px);
  margin-block: auto; /* centres in the dialog while it fits, scrolls when not */
}
.resume__media {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 8px;
  overflow: hidden;
}
.resume__media img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Two-layer photo (same components as the cards: blurred backdrop + cut-out
   person); about.js copies the clicked card's layers in here. The single <img>
   above is the fallback when a member only has a flat pop-up photo. */
.resume__photo { width: 100%; height: 100%; }
.resume__media img[hidden],
.resume__photo[hidden] { display: none; }
.resume__body { color: #fff; }
.resume__name { margin: 0; font-size: clamp(1.5rem, 2.4vw, 28px); line-height: 1.43; font-weight: 400; }
.resume__role { margin: 4px 0 0; font-size: 18px; line-height: 28px; opacity: 0.6; }
.resume__bio { margin-top: clamp(20px, 2.4vw, 30px); font-size: 18px; line-height: 28px; }
.resume__bio p { margin: 0 0 1em; }
.resume__bio p:last-child { margin-bottom: 0; }

.resume__close {
  position: fixed;
  top: clamp(20px, 4vw, 62px);
  right: clamp(20px, 5vw, 80px);
  z-index: 2;
  width: 51px;
  height: 51px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  cursor: pointer;
  /* Exit: slides off to the right + fades, just after the text (delay 0.18s).
     Enter (on .is-open) it settles in last of all. */
  opacity: 0;
  transform: translateX(38px);
  transition: background 0.35s ease, opacity 0.4s ease 0.18s, transform 0.5s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)) 0.18s;
}
.resume.is-open .resume__close { opacity: 1; transform: none; transition-delay: 0s, 0.34s, 0.34s; }
.resume__close:hover { background: rgba(255, 255, 255, 0.18); }
/* Hover spins the X itself (the button transform is reserved for the slide). */
.resume__close:hover .resume__close-x { transform: rotate(90deg); }
.resume__close-x { position: relative; width: 27px; height: 27px; display: block; transition: transform 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)); }
.resume__close-x::before,
.resume__close-x::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 2px;
  background: var(--accent, #00ffec);
  border-radius: 2px;
}
.resume__close-x::before { transform: translateY(-50%) rotate(45deg); }
.resume__close-x::after { transform: translateY(-50%) rotate(-45deg); }
/* Reduced motion: no staggered slide/drop, the pop-up just appears and clears. */
@media (prefers-reduced-motion: reduce) {
  .resume__overlay,
  .resume__media,
  .resume__body,
  .resume__close,
  .resume__close-x { transition-duration: 0.001s; transition-delay: 0s; }
}

/* ---- Mission (floating brand mark) ---------------------- */
.section--mission {
  position: relative;
  overflow: clip;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: clamp(560px, 56vw, 860px);
  padding-block: clamp(4rem, 9vw, 140px);
}
.about-mission__mark {
  position: absolute;
  left: 50%;
  top: 50%;
  /* Figma Image Mark (16:404): 341.605 x 445.063, white droplet whose own
     gradient + this opacity render as the lighter blue-purple over the navy. */
  width: clamp(220px, 21vw, 342px);
  aspect-ratio: 341.605 / 445.063;
  background: url('../img/about/mission-mark.svg') no-repeat center / contain;
  opacity: 0.3;
  z-index: 0;
  pointer-events: none;
  transform: translate(-50%, -50%);
  animation: alveus-mission-float 11s ease-in-out infinite;
  will-change: transform;
}
@keyframes alveus-mission-float {
  0%, 100% { transform: translate(-50%, calc(-50% - 16px)); }
  50%      { transform: translate(-50%, calc(-50% + 16px)); }
}
@media (prefers-reduced-motion: reduce) {
  .about-mission__mark { animation: none; }
}
.about-mission__inner {
  position: relative;
  z-index: 1;
  max-width: 866px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 2vw, 20px);
}
.about-mission__heading { margin: 0; font-size: var(--fs-h2); line-height: 1.19; font-weight: 400; }
.about-mission__text { margin: 0; font-size: clamp(1.25rem, 2.2vw, 28px); line-height: 1.43; }

/* ---- Responsive ----------------------------------------- */
@media (max-width: 1024px) {
  .about-team__grid { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 820px) {
  .about-team__head { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .about-team__grid { grid-template-columns: repeat(2, 1fr); }
  /* Stacked pop-up: photo and text left-aligned, photo spans the full wrapper
     width (client 2026-07; was centred with a 320px photo cap). */
  .resume__layout { grid-template-columns: 1fr; justify-items: stretch; text-align: left; row-gap: clamp(1.5rem, 6vw, 2.25rem); }
  .resume__media { max-width: none; }
  .resume__role { font-size: 16px; }
}
@media (max-width: 460px) {
  .about-team__grid { grid-template-columns: 1fr; }
}

/* Lock background scroll while the resume pop-up is open */
/* Scroll lock. The shift-free part is html { scrollbar-gutter: stable } in
   style.css; --scroll-comp is the JS fallback for browsers without support
   (about.js / app.js measure the scrollbar width there, else it stays 0). The
   fixed header gets the same offset or its right-aligned content would still
   move into the vanished scrollbar's space. */
body.resume-open { overflow: hidden; }
body.resume-open,
body.overflow-hidden { padding-right: var(--scroll-comp, 0px); }
body.resume-open .site-header,
body.overflow-hidden .site-header { right: var(--scroll-comp, 0px); }

/* =========================================================
   SCIENCE PAGE  (Figma 23:963)
   Reusable inner-page blocks: page banner, program rows,
   mechanisms list, "why it matters" statement, notice.
   ========================================================= */

/* ---- Page banner (compact hero) ------------------------- */
.page-banner {
  position: relative;
  isolation: isolate;
  overflow: clip;
  display: flex;
  align-items: center;
  padding-top: 200px;   /* also clears the fixed header */
  padding-bottom: 150px;
  color: #fff;
  /* Navy base behind the molecule image (Figma reads navy with faint blobs). */
  background: radial-gradient(125% 120% at 58% 22%, #0a3f93 0%, #02256a 42%, #00114c 100%);
}
@media (max-width: 820px) {
  .page-banner {
    padding-top: 150px;
    padding-bottom: 120px;
  }
}
.page-banner__bg { position: absolute; inset: 0; z-index: -2; }
.page-banner__bg img,
.page-banner__bg video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}
.page-banner__bg img { opacity: var(--pb-media-opacity, 0.62); }
/* The banner video autoplays and loops (like the homepage hero). The poster is
   shown until the first frames decode, then it eases in. */
.page-banner__bg video { opacity: var(--pb-media-opacity, 0.62); transition: opacity 0.7s ease; }
.page-banner__overlay {
  position: absolute;
  inset: 0;
  z-index: -1;
  /* Darken left (behind the text) and the bottom edge; let the centre show.
     Strengths come from the block's Settings tab (page_banner.php sets the
     custom properties); the 34% mid-stop tracks the left value. */
  background:
    linear-gradient(90deg, rgba(0, 17, 76, var(--pb-overlay-left, 0.6)) 0%, rgba(0, 17, 76, calc(var(--pb-overlay-left, 0.6) * 0.53)) 34%, rgba(0, 17, 76, 0) 62%),
    linear-gradient(0deg, rgba(0, 17, 76, var(--pb-overlay-bottom, 0.38)) 0%, rgba(0, 17, 76, 0) 42%);
}
.page-banner__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 30px;
}
.page-banner__inner .eyebrow { margin: 0; }
.page-banner__title {
  margin: 0;
  max-width: none; /* line breaks are set by the editor (<br>) */
  font-size: var(--fs-h1);
  line-height: 1;            /* Figma 60/60 */
  font-weight: 400;
  color: #fff;
}
.page-banner__title strong { font-weight: 700; }
.page-banner__text {
  margin: 0;
  max-width: 626px;          /* Figma */
  font-size: var(--fs-body);
  line-height: 1.55;
}
.page-banner__text p { margin: 0 0 0.8em; }
.page-banner__text p:last-child { margin-bottom: 0; }
/* Underline handled by the shared inline-link rule near the top. */
.page-banner__text a { color: inherit; }
.page-banner__cta { margin: 0; }

/* ---- Program rows: alternating media / text ------------- */
.section--programs .container {
  display: flex;
  flex-direction: column;
  gap: clamp(56px, 7vw, 100px);
}
.program-row {
  display: grid;
  /* DOM order is media-first, so the default is media-left / text-right. */
  grid-template-columns: minmax(0, 642px) minmax(0, 530px);
  gap: clamp(40px, 8vw, 142px);
  align-items: center;
  justify-content: space-between;
}
.program-row--text-left { grid-template-columns: minmax(0, 530px) minmax(0, 642px); }
.program-row--text-left .program-row__media { order: 1; }   /* push media into the right column */
.program-row__media {
  aspect-ratio: 1;                 /* Figma media tile is square (1:1) */
  border-radius: 8px;             /* real CSS radius, not baked into the image */
  overflow: hidden;               /* clips any uploaded image to the rounded tile */
  background: var(--accent, #00ffec);   /* flat turquoise when no image is set */
}
/* Any uploaded image fills the square tile and is centre-cropped, whatever its
   own dimensions/ratio. */
.program-row__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}
.program-row__title {
  margin: 0 0 20px;
  font-size: clamp(1.75rem, 3vw, 34px);
  line-height: 1.29;          /* 34/44 */
  font-weight: 400;
  color: var(--c-brand, #042e7b);
}
.program-row__lead {
  margin: 0 0 20px;
  font-size: clamp(1.3rem, 2vw, 24px);
  line-height: 1.33;          /* 24/32 */
  color: var(--c-brand, #042e7b);
}
.program-row__body p {
  margin: 0 0 1em;
  font-size: var(--fs-body);
  line-height: 1.55;          /* 18/28 */
  color: var(--c-brand, #042e7b);
}
.program-row__body p:last-child { margin-bottom: 0; }

/* ---- Mechanisms: divided two-column list ---------------- */
.mechanisms { border-top: 1px solid rgba(4, 46, 123, 0.16); }
.mechanism {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 2.4vw, 30px);
  align-items: start;
  padding-block: clamp(28px, 3.4vw, 40px);
  border-bottom: 1px solid rgba(4, 46, 123, 0.16);
}
.mechanism__heading {
  margin: 0;
  font-size: clamp(1.75rem, 3vw, 34px);
  line-height: 1.29;
  font-weight: 400;
  color: var(--c-brand, #042e7b);
}
.mechanism__subtitle {
  margin: 10px 0 0;
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--c-brand, #042e7b);
}
.mechanism__text {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--c-brand, #042e7b);
}

/* ---- Why it matters: centred statement + droplet -------- */
.section--why .why {
  display: flex;
  justify-content: center;
  padding-block: clamp(64px, 10vw, 130px);
}
.why__inner {
  position: relative;
  max-width: 866px;
  text-align: center;
  color: var(--c-brand, #042e7b);
}
.why__mark {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: clamp(220px, 23vw, 341px);
  aspect-ratio: 341.605 / 445.063;
  background: url('../img/science/why-mark.svg') center / contain no-repeat;
  opacity: 0.85;
  z-index: 0;
  pointer-events: none;
  animation: alveus-why-float 11s ease-in-out infinite;
  will-change: transform;
}
@keyframes alveus-why-float {
  0%, 100% { transform: translate(-50%, calc(-50% - 14px)); }
  50%      { transform: translate(-50%, calc(-50% + 14px)); }
}
@media (prefers-reduced-motion: reduce) {
  .why__mark { animation: none; }
}
.why__subtitle,
.why__title,
.why__text { position: relative; z-index: 1; }
.why__subtitle {
  margin: 0 0 20px;
  font-size: 22px;
  line-height: 1.18;          /* 22/26 */
}
.why__title {
  margin: 0 0 20px;
  font-size: clamp(2rem, 4vw, 42px);
  line-height: 1.19;          /* 42/50 */
  font-weight: 400;
}
.why__text {
  margin: 0;
  font-size: clamp(1.4rem, 2.4vw, 28px);
  line-height: 1.43;          /* 28/40 */
}

/* ---- Notice placement ----------------------------------- */
.section--notice { padding-block: clamp(24px, 4vw, 48px); }
/* Directly before the notice bar: drop the why block's bottom padding so the
   two sit together (client feedback 2026-07). */
.section--why:has(+ .section--notice) .why { padding-bottom: 0; }
/* Directly after the pipeline table or the why block: sit close to the
   content above, keep clear of the footer (client feedback 2026-07). Scoped
   to these adjacencies so other placements of the notice block keep their
   symmetric spacing. */
.section--pipeline + .section--notice,
.section--why + .section--notice {
  padding-block: 18px clamp(64px, 9vw, 150px);
}

/* The whole page below the navy banner is white, with no blue section to blend
   into. Each of these blocks now paints its own solid background (from its ACF
   "Background colour" field, default white) via an inline style, so the short
   banner never bleeds the navy scroll-bg canvas down into them ("page begins
   blue") AND the colour stays editor-managed. */

/* ---- Science responsive --------------------------------- */
@media (max-width: 900px) {
  .program-row,
  .program-row--media-left { grid-template-columns: 1fr; gap: clamp(24px, 5vw, 40px); }
  .program-row__media { order: -1; max-width: 520px; }       /* media always on top */
  .mechanism { grid-template-columns: 1fr; gap: 12px; }
}

/* =========================================================
   PIPELINE PAGE  (Figma 27:900)
   Reuses page_banner (video) + a content/media block that
   scroll-blends from blue into the white pipeline table.
   ========================================================= */

/* ---- Content + media (text + landscape photo) ----------- */
.section--content-media { color: #fff; }
.section--content-media--light { color: var(--c-brand, #042e7b); }
.section--content-media .content-media {
  display: grid;
  grid-template-columns: minmax(0, 754px) minmax(0, 530px);
  gap: clamp(2rem, 3vw, 40px);
  align-items: center;
  justify-content: space-between;
}
.section--content-media--left .content-media { grid-template-columns: minmax(0, 530px) minmax(0, 754px); }
.section--content-media--left .content-media__media { order: -1; }
.content-media__text { display: flex; flex-direction: column; align-items: flex-start; gap: 30px; }
.content-media__text .eyebrow { margin: 0; }
.content-media__title {
  margin: 0;
  font-size: clamp(1.75rem, 3vw, 34px);
  line-height: 1.29;          /* 34/44 */
  font-weight: 400;
}
.content-media__lead {
  margin: 0;
  font-size: clamp(1.3rem, 2vw, 24px);
  line-height: 1.33;          /* 24/32 */
}
.content-media__body { display: flex; flex-direction: column; gap: 1em; }
.content-media__body p { margin: 0; font-size: var(--fs-body); line-height: 1.556; }
/* Photo: real CSS radius + object-fit so any upload fits the landscape tile. */
.content-media__media {
  aspect-ratio: 530 / 348;
  border-radius: 8px;
  overflow: hidden;
}
.content-media__media img { width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }

/* ---- Pipeline table: light (white background) variant ---- */
.section--pipeline--light {
  color: var(--c-brand, #042e7b);
  --pl-divider: var(--bg, #ffffff); /* live canvas colour = true "gap", see .section--pipeline */
  --pl-fill: linear-gradient(90deg, #09007b 0%, #00ffec 100%);
}
.section--pipeline--light {
  /* Same direction AND same ramp treatment as the dark homepage table
     (client 2026-07, overriding the Figma 1:926 direction): SEMI-transparent
     left (3%, a faint hint of the pill, exactly like the homepage's white
     3%) growing to full presence (22%) right on desktop; mirrored on mobile
     below. */
  --pl-track-bg: linear-gradient(90deg, rgba(4, 46, 123, 0.03) 0%, rgba(4, 46, 123, 0.22) 100%);
}
@media (max-width: 600px) {
  .section--pipeline--light { --pl-track-bg: linear-gradient(90deg, rgba(4, 46, 123, 0.22) 0%, rgba(4, 46, 123, 0.03) 100%); }
}
/* In the design the white phase dividers sit ON TOP of the coloured fill. */
.section--pipeline--light .pl-track__dividers { z-index: 2; }

/* ---- Pipeline page responsive --------------------------- */
@media (max-width: 900px) {
  .section--content-media .content-media,
  .section--content-media--left .content-media { grid-template-columns: 1fr; gap: clamp(24px, 5vw, 36px); }
  .content-media__media { order: -1; max-width: 560px; }     /* photo on top */
}

/* =========================================================
   NEWS ARCHIVE + SINGLE ARTICLE  (Figma 27:1215 / 27:1238)
   ========================================================= */

/* ---- Archive: filter bar (tabs + stay informed) --------- */
.section--news-archive {
  /* Solid background is painted inline from the block's "Background colour"
     field (default white), so the short banner never bleeds navy down. */
  padding-block: clamp(3rem, 6vw, 90px) clamp(4rem, 9vw, 130px);
}
.news-archive__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-bottom: clamp(2rem, 4vw, 54px);
}

/* tabs (mirror .about-tabs) */
.news-tabs {
  position: relative;
  display: inline-flex;
  padding: 5px;
  border: 1px solid rgba(54, 96, 235, 0.2);
  border-radius: 999px;
}
.news-tabs__indicator {
  position: absolute;
  top: 50%;
  left: 0;
  height: calc(100% - 10px);
  border-radius: 999px;
  background: var(--accent, #00ffec);
  z-index: 0;
  transform: translate(5px, -50%);
  transition: transform 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1)),
              width 0.55s var(--ease-osmo, cubic-bezier(0.65, 0.05, 0, 1));
  will-change: transform, width;
}
.news-tab {
  position: relative;
  z-index: 1;
  appearance: none;
  margin: 0;
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 11px 30px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  line-height: 18px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--c-brand, #042e7b);
  white-space: nowrap;
  cursor: pointer;
  transition: color 0.4s ease;
}

/* stay informed on LinkedIn */
.news-archive__stay {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  text-decoration: none;
  color: var(--c-brand, #042e7b);
  font-size: 18px;
  line-height: 1.5;
}
.news-archive__stay-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--c-brand, #042e7b);
  color: #fff;
  transition: background 0.3s ease;
}
.news-archive__stay:hover .news-archive__stay-icon { background: var(--c-action, #3660eb); }

/* ---- Archive: two-column post list ---------------------- */
.news-list {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(1.5rem, 2.3vw, 30px);
  row-gap: clamp(1.25rem, 1.7vw, 20px);
}
.news-item {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  /* Compact rows like the old site (client feedback 2026-07): no reserved
     min-height — a row is only as tall as its longest title. Cards stretch to
     their grid-row partner, so next to a longer-titled neighbour the meta
     stays bottom-aligned and the extra room sits between title and meta. */
  gap: clamp(0.75rem, 1.2vw, 16px);
  text-decoration: none;
  color: var(--c-brand, #042e7b);
}
.news-item.is-hidden { display: none; }
/* Anti-flash: when JS is on, hide the archive cards before first paint so the
   one-by-one entrance (news.js) never shows them, hides them, then re-shows.
   Lifted the instant news.js marks the list ready (or immediately if reduced-
   motion). No-JS users never get .js, so they always see the cards. */
html.js .news-list:not(.is-ready) .news-item:not(.is-hidden) {
  opacity: 0;
  transform: translateY(26px);
}
@media (prefers-reduced-motion: reduce) {
  /* Reduced-motion must always show the cards, even if JS never runs, so this
     overrides the pre-hide gate regardless of specificity. */
  html.js .news-list .news-item { opacity: 1 !important; transform: none !important; }
}
.news-item__title {
  margin: 0;
  font-size: clamp(1.25rem, 1.7vw, 24px);
  line-height: 1.33;              /* 32/24 */
  color: var(--c-brand, #042e7b);
  transition: color 0.3s ease;
}
.news-item:hover .news-item__title { color: var(--c-action, #3660eb); }
.news-item__meta { display: flex; flex-direction: column; gap: 14px; }
.news-item__line { display: flex; align-items: center; gap: 6px; font-size: 14px; line-height: 1.57; }
.news-item__dot { width: 5px; height: 5px; border-radius: 50%; background: var(--c-action, #3660eb); flex-shrink: 0; }
/* Internal items (Press Releases: they navigate within the site) show the
   arrow flat/horizontal; hover recolours it to the ice-turquoise accent
   without rotating (client 2026-07). */
.news-item__arrow {
  display: inline-flex;
  width: 14px;
  height: 14px;
  color: var(--c-action, #3660eb);
  transition: color 0.4s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1));
}
.news-item__arrow svg { width: 100%; height: 100%; }
.news-item:hover .news-item__arrow { color: var(--accent, #00ffec); }
/* External items (In the media: they carry target="_blank") announce the
   outbound link: arrow also lies flat at rest but tilts up (-45deg, points
   up-right) on hover (client feedback 2026-07, mirrors the old site). */
.news-item[target="_blank"] .news-item__arrow {
  transition: color 0.4s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1)),
              transform 0.4s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1));
}
.news-item[target="_blank"]:hover .news-item__arrow { transform: rotate(-45deg); }
/* Divider: a faint blue track that a blue-to-turquoise gradient sweeps across
   from left to right on hover (scaleX from origin left). */
.news-item__divider {
  position: relative;
  height: 2px;
  width: 100%;
  overflow: hidden;
}
.news-item__divider::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--c-action, #3660eb);
  opacity: 0.3;
}
.news-item__divider::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to right, var(--c-action, #3660eb), var(--accent, #00ffec));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1));
}
.news-item:hover .news-item__divider::after { transform: scaleX(1); }

/* ---- Single post: dark hero (title + tag + date) -------- */
.post-hero {
  padding-top: 200px;
  padding-bottom: 150px;
  align-items: flex-end;
}
.post-hero__inner { display: flex; flex-direction: column; align-items: flex-start; gap: 30px; }
.post-hero__title {
  margin: 0;
  max-width: 1314px;
  font-size: clamp(1.9rem, 3.4vw, 42px);
  line-height: 1.19;             /* 50/42 */
  font-weight: 400;
  color: #fff;
}
.post-hero__meta { display: flex; align-items: center; gap: 20px; }
.post-hero__tag {
  display: inline-flex;
  align-items: center;
  height: 30px;
  padding: 0 22px;
  border-radius: 505px;
  background: rgba(255, 255, 255, 0.6);
  color: #02225e;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 1px;
  text-transform: uppercase;
  line-height: 18px;
  white-space: nowrap;
}
.post-hero__date { font-size: 14px; color: #fff; opacity: 0.9; }

/* ---- Single post: centred article body ------------------ */
.section--article {
  background-color: #fff;
  padding-block: clamp(3rem, 6vw, 84px) clamp(4rem, 9vw, 130px);
}
.article {
  max-width: 866px;
  margin-inline: auto;
  color: var(--c-brand, #042e7b);
  font-size: var(--fs-body);
  line-height: 1.556;            /* 28/18 */
}
.article__text { margin: 0 0 1.556em; }
.article__text p { margin: 0 0 1.556em; }
.article__text p:last-child { margin-bottom: 0; }
.article__text strong { font-weight: 700; }
.article__text em { font-style: italic; }
/* Inline article links get the underline — but not component buttons
   (e.g. the "Apply now" button-040) that happen to sit inside the article. */
/* Underline handled by the shared inline-link rule near the top; only the
   colour lives here. Rest = the copy's navy, hover recolours to action blue
   (see the shared hover rule). */
.article a:not(.button-040),
.article__text a:not(.button-040),
.article__list a:not(.button-040) { color: var(--c-brand, #042e7b); }
.article .button-040,
.article .button-040:hover { text-decoration: none; }
.article__heading {
  margin: clamp(1.75rem, 3vw, 40px) 0 clamp(0.75rem, 1.4vw, 20px);
  font-size: clamp(1.4rem, 2vw, 28px);   /* H4 28/40 */
  line-height: 1.43;
  font-weight: 400;
  color: var(--c-brand, #042e7b);
}
.article__list { margin: 0 0 1.556em; padding-left: 1.4em; }
.article__list li { margin: 0 0 0.5em; }
.article__list li:last-child { margin-bottom: 0; }
.article__list--ol { list-style: decimal; }
.article__list--ul { list-style: disc; }

/* WYSIWYG article body: headings, lists, quotes and inline images now live
   inside .article__text (one rich editor), so mirror the standalone styles. */
.article__text h2 { margin: clamp(1.75rem, 3vw, 40px) 0 clamp(0.75rem, 1.4vw, 20px); font-size: clamp(1.5rem, 2.4vw, 32px); line-height: 1.3; font-weight: 400; color: var(--c-brand, #042e7b); }
.article__text h3 { margin: clamp(1.5rem, 2.4vw, 32px) 0 clamp(0.6rem, 1.2vw, 16px); font-size: clamp(1.25rem, 1.8vw, 24px); line-height: 1.35; font-weight: 500; color: var(--c-brand, #042e7b); }
.article__text h2:first-child, .article__text h3:first-child { margin-top: 0; }
.article__text ul, .article__text ol { margin: 0 0 1.556em; padding-left: 1.4em; }
.article__text li { margin: 0 0 0.5em; }
.article__text ul { list-style: disc; }
.article__text ol { list-style: decimal; }
.article__text blockquote { margin: clamp(1.5rem, 2.4vw, 32px) 0; padding-left: 1.1em; border-left: 3px solid var(--c-action, #3660eb); font-style: italic; color: var(--c-navy, #02225e); }
.article__text img { max-width: 100%; height: auto; border-radius: 8px; display: block; margin: clamp(1.5rem, 2.4vw, 32px) 0; }
.article__button { margin: clamp(1.75rem, 3vw, 40px) 0; }

.article__figure { margin: clamp(1.75rem, 3vw, 40px) 0; }
.article__figure img,
.article__figure video { width: 100%; height: auto; border-radius: 8px; display: block; }
.article__figure figcaption { margin-top: 12px; font-size: 14px; opacity: 0.6; }

/* ---- News responsive ------------------------------------ */
@media (max-width: 720px) {
  .news-list { grid-template-columns: 1fr; }
  .news-archive__bar { align-items: flex-start; }
  .news-tab { padding: 11px 22px; }
}

/* =====================================================================
   CAREERS (Figma 28:1807 landing, 28:1918 single, 28:1966 apply form)
   ===================================================================== */

/* ---- Career hero (single + apply): blue gradient banner ------------- */
.career-hero {
  position: relative;
  isolation: isolate;
  overflow: clip;
  display: flex;
  align-items: center;
  padding-block: 200px 150px;
  color: #fff;
}
.career-hero__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(120% 120% at 85% 0%, #123a9e 0%, rgba(18,58,158,0) 55%),
    radial-gradient(120% 130% at 0% 100%, #0a1f6b 0%, rgba(10,31,107,0) 60%),
    linear-gradient(120deg, #08205f 0%, #041a52 45%, #00114c 100%);
}
/* Large brand swirl (Figma "BANNER SMALL" hero visual). It bleeds off the top,
   right and bottom edges (the hero is clipped) and fades out toward the left via
   a mask so the heading stays clean and legible. */
.career-hero__mark {
  position: absolute;
  z-index: -1;
  top: 50%;
  left: 54%;
  transform: translate(-50%, -50%);
  width: clamp(900px, 128vw, 1900px);
  aspect-ratio: 1500 / 1493;
  /* Editable in Theme Settings (--career-swirl, set on .career-hero); falls back
     to the bundled asset when no swirl image is configured. */
  background: var(--career-swirl, url('../img/careers/brand-mark-bg.webp')) no-repeat center / contain;
  opacity: 0.5;
  -webkit-mask-image: linear-gradient(100deg, transparent 2%, rgba(0, 0, 0, 0.45) 26%, #000 55%);
          mask-image: linear-gradient(100deg, transparent 2%, rgba(0, 0, 0, 0.45) 26%, #000 55%);
  pointer-events: none;
}
@media (max-width: 767px) {
  .career-hero__mark { left: 62%; width: 175vw; opacity: 0.42; }
}
/* When an editor sets a hero photo/video (Theme Settings > Template heroes or a
   per-position override), the shared .page-banner__bg + .page-banner__overlay
   take over and the decorative brand gradient + swirl step aside. */
.career-hero--has-media .career-hero__bg,
.career-hero--has-media .career-hero__mark { display: none; }
/* The apply hero holds only an eyebrow and the job title, and the page itself
   is a functional form page, not a design page - on phones the banner shrinks
   to just clear the fixed header (~98px) and hug those two lines instead of
   keeping the tall banner padding (client 2026-08). */
@media (max-width: 820px) {
  .career-hero--apply { padding-block: 120px 44px; }
}
.career-hero__inner { position: relative; z-index: 1; }
.career-hero__title {
  margin: 0.35em 0 0;
  max-width: 14ch;
  font-size: var(--fs-h1);
  line-height: 1;
  color: #fff;
}
.career-hero__cta {
  margin-top: clamp(1.5rem, 2.5vw, 34px);
  /* Button and the "Apply before" note sit on one row; the note wraps under
     the button on narrow screens. */
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: clamp(1rem, 1.6vw, 22px);
}
.career-hero__meta {
  margin: 0;
  font-size: 14px;
  line-height: 1.57;
  color: rgba(255, 255, 255, 0.75);
}

/* ---- Career single body -------------------------------------------- */
.section--career-body { }
.article--career .lead {
  font-size: clamp(1.25rem, 1.7vw, 24px);
  line-height: 1.333;
  color: var(--c-brand, #042e7b);
  margin-bottom: 1.4em;
}
/* Droplet bullets on every article list - including plain WYSIWYG <ul>s inside
   .article__text, which don't carry the --ul modifier class. Was scoped to
   .article--career, which left news articles on default discs (client 2026-07);
   both article types share the same body styling, so the mark applies to both. */
.article .article__list--ul,
.article .article__text ul {
  list-style: none;
  padding-left: 0;
}
.article .article__list--ul li,
.article .article__text ul li {
  position: relative;
  padding-left: 34px;
  margin-bottom: 0.55em;
}
.article .article__list--ul li::before,
.article .article__text ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.18em;
  width: 14px;
  height: 19px;
  background: url('../img/icons/droplet-mark.svg') no-repeat center / contain;
}
/* A list nested inside a list item. The generic list rule only carries a bottom
   margin, so a sub-list sat flush against the line it belongs to (3px) while
   leaving a 28px hole underneath - lopsided in both directions, and the group
   read as if it were glued to the parent item (client 2026-07). Give it air
   above so it detaches from the parent's own text, and a slightly larger gap
   below so the sub-group visibly closes before the next top-level item. The
   sibling items themselves sit 0.55em apart, so both values stay above that. */
.article .article__text li > ul,
.article .article__text li > ol,
.article .article__list li > ul,
.article .article__list li > ol {
  margin-top: 0.75em;
  margin-bottom: 1em;
}
.career-body__apply {
  margin-top: clamp(2.5rem, 5vw, 72px);
  padding: clamp(1.75rem, 3vw, 40px) clamp(1.75rem, 3vw, 44px);
  background: var(--blue-10-fresh, #e8f0ff);
  border-radius: clamp(20px, 3vw, 40px);
}

/* ---- Perks tabs: "Built by people who care" (dark blue) ------------- */
.section--perks { padding-block: clamp(4rem, 8vw, 130px); color: #fff; }
.perks__intro {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.5rem, 4vw, 60px);
  justify-content: space-between;
  margin-bottom: clamp(2.5rem, 5vw, 72px);
}
.perks__heading {
  flex: 1 1 340px;
  max-width: 526px;
  margin: 0;
  font-size: clamp(2rem, 3.3vw, 42px);
  line-height: 1.19;
  color: #fff;
}
.perks__lead {
  flex: 1 1 340px;
  max-width: 530px;
  margin: 0;
  font-size: clamp(1.125rem, 1.7vw, 24px);
  line-height: 1.333;
  color: rgba(255, 255, 255, 0.82);
}
.perks-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(2rem, 4vw, 64px);
  /* Stretch: the visual column follows the content column's height, so the
     photo grows along when a tab's detail text expands. */
  align-items: stretch;
}
.perks-tabs__col { flex: 1 1 380px; min-width: 0; }
.perks-tabs__title {
  margin: 0 0 clamp(1.5rem, 2.5vw, 34px);
  font-size: clamp(1.75rem, 2.6vw, 34px);
  line-height: 1.1;
  color: #fff;
}
.perks-tabs__list {
  position: relative;
  display: flex;
  flex-direction: column;
}
/* Static top line so the first perk is closed off at the top and the whole
   stack reads as a box. Drawn like the per-tab progress track
   (.perks-tab__bottom: a 2px absolutely-positioned box) but never fills:
   decoration, not a progress indicator.
   Colour note: the track lines live inside .perks-tab, which sits at
   opacity: 0.5 while inactive, so their 0.2 white renders at an effective
   0.1 over the dark background. This line hangs off the list (no such
   halving), so it uses 0.1 directly to match the resting tracks — 0.2 read
   as noticeably whiter. */
.perks-tabs__list::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 2px;
  background: rgba(255, 255, 255, 0.1);
}
.perks-tab {
  position: relative;
  display: block;
  /* Tightened (was 2vw/28px): the whole tab block ran taller than a viewport
     (client feedback 2026-07 — smaller number circles + less padding). */
  padding-block: clamp(1rem, 1.5vw, 20px);
  color: #fff;
  text-decoration: none;
  opacity: 0.5;
  transition: opacity 0.3s ease;
  cursor: pointer;
}
.perks-tab.is-active { opacity: 1; }
.perks-tab__main {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 1.6vw, 24px);
}
.perks-tab__nr {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid var(--accent, #00ffec);
  color: var(--accent, #00ffec);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.5px;
  transition: background-color 0.4s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1)), color 0.4s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1));
}
.perks-tab.is-active .perks-tab__nr {
  background: var(--accent, #00ffec);
  color: var(--brand-blue-dark, #00114c);
}
.perks-tab__heading {
  margin: 0;
  font-size: clamp(1.25rem, 2vw, 28px);
  line-height: 1.1;
  color: #fff;
}
.perks-tab__detail {
  height: 0;
  overflow: hidden;
  /* Indent = circle width + the main row's gap, so the description aligns
     with the tab heading. Keep in sync with .perks-tab__nr. */
  padding-left: calc(34px + clamp(1rem, 1.6vw, 24px));
}
.perks-tab__spacer { padding-top: 0.9em; }
.perks-tab__desc {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 1.556;
  color: rgba(255, 255, 255, 0.78);
}
.perks-tab__bottom {
  position: absolute;
  inset: auto 0 0 0;
  height: 2px;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.2);
}
.perks-tab__progress {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--accent, #00ffec);
  transform: scaleX(0);
  transform-origin: left center;
}
.perks-visual { position: relative; width: 100%; height: 100%; }
.perks-visual__frame {
  position: relative;
  /* Side by side the frame fills the (stretched) column, matching the content
     column exactly; stacked (≤900px) the column height is auto, the 100% falls
     back to auto and the aspect-ratio takes over. */
  aspect-ratio: 1.3;
  width: 100%;
  height: 100%;
}
.perks-visual__item {
  position: absolute;
  inset: 0;
  opacity: 0;
  visibility: hidden;
}
.perks-visual__item.is-active { opacity: 1; visibility: visible; }
.perks-visual__inner {
  width: 100%;
  height: 100%;
  border-radius: 12px;
  overflow: hidden;
}
.perks-visual__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 12px;
  display: block;
}

/* ---- Development & Benefits: sticky title + soft-blue cards --------- */
.section--benefits { padding-block: clamp(4rem, 8vw, 130px); }
.benefits__heading {
  margin: 0 0 clamp(3rem, 6vw, 90px);
  text-align: center;
  font-size: var(--fs-h1);
  line-height: 1.1;
  color: var(--c-brand, #042e7b);
}
.benefits {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  column-gap: clamp(1.5rem, 3vw, 44px);
  align-items: start;
}
.benefits__aside {
  position: sticky;
  top: clamp(110px, 15vh, 170px);
  align-self: start;
}
.benefits__titles { display: grid; }
.benefits__title {
  grid-area: 1 / 1;
  margin: 0;
  font-size: clamp(1.75rem, 3.3vw, 42px);
  line-height: 1.19;
  /* Even out the lines instead of filling each one greedily. "Supporting you -
     wherever you are in life" otherwise left a stub last line ("are in life")
     hanging under a full-width first line (client 2026-07). Balanced wrapping
     keeps this true for whatever the editor types next, at any column width.
     Must be resolved before careers.js runs SplitText over these lines, which
     is why it lives here and not in an inline style. */
  text-wrap: balance;
  color: var(--c-brand, #042e7b);
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.5s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1)), transform 0.5s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1));
  pointer-events: none;
}
.benefits__title.is-active { opacity: 1; transform: translateY(0); pointer-events: auto; }
.benefits__steps { display: flex; flex-direction: column; gap: clamp(2.5rem, 5vw, 72px); }
/* Cards sit at natural spacing (just the gap between them). The sticky title
   swaps when a card crosses the viewport centre line, so it stays deliberate
   without needing large empty blocks. */
.benefits__step { display: flex; }
/* Per-step title: only rendered visible on the stacked mobile layout, where
   the sticky cross-fade column is hidden (see the 900px block below). */
.benefits__step-title { display: none; }
.benefits__card {
  width: 100%;
  padding: clamp(1.75rem, 2.6vw, 40px);
  background: var(--blue-10-fresh, #e8f0ff);
  border-radius: clamp(16px, 2vw, 26px);
  color: var(--c-brand, #042e7b);
}
.benefits__card > *:first-child { margin-top: 0; }
.benefits__card > *:last-child { margin-bottom: 0; }
.benefits__card p {
  margin: 0 0 1.1em;
  font-size: var(--fs-body);
  line-height: 1.556;
}
.benefits__card .lead {
  font-size: clamp(1.25rem, 1.7vw, 24px);
  line-height: 1.333;
  margin-bottom: 1.1em;
}
.benefits__card .sub {
  font-size: clamp(1.125rem, 1.5vw, 22px);
  line-height: 1.18;
  margin-bottom: 0.9em;
}
.benefits__card ul { list-style: none; margin: 0; padding: 0; }
.benefits__card ul li {
  position: relative;
  padding-left: 30px;
  margin-bottom: 0.5em;
  font-size: var(--fs-body);
  line-height: 1.556;
}
.benefits__card ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.22em;
  width: 14px;
  height: 19px;
  /* The brand droplet mark (already #042E7B). */
  background: url('../img/icons/droplet-mark.svg') no-repeat center / contain;
}
.benefits__quote {
  position: relative;
  max-width: 866px;
  margin: calc(clamp(4rem, 9vw, 150px) + 100px) auto 0;
  padding-block: clamp(2rem, 4vw, 60px);
  text-align: center;
}
.benefits__quote-mark {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(200px, 22vw, 300px);
  aspect-ratio: 341.605 / 445.063;
  z-index: 0;
  pointer-events: none;
  /* Same light-blue droplet as the "why it matters" mark, gently floating. */
  background: url('../img/science/why-mark.svg') no-repeat center / contain;
  opacity: 0.85;
  animation: benefits-float 7s ease-in-out infinite;
}
@keyframes benefits-float {
  0%, 100% { transform: translate(-50%, -54%); }
  50% { transform: translate(-50%, -46%); }
}
@media (prefers-reduced-motion: reduce) {
  .benefits__quote-mark { animation: none; transform: translate(-50%, -50%); }
}
.benefits__quote-text {
  position: relative;
  z-index: 1;
  margin: 0;
  font-size: clamp(1.25rem, 1.7vw, 24px);
  line-height: 1.333;
  color: var(--c-brand, #042e7b);
}

/* ---- Open positions: dynamic table --------------------------------- */
.section--positions { padding-block: clamp(3rem, 6vw, 90px); scroll-margin-top: clamp(90px, 12vh, 150px); }
.positions__heading {
  margin: 0 0 clamp(1.5rem, 2.5vw, 34px);
  font-size: clamp(1.75rem, 2.6vw, 34px);
  line-height: 1.1;
  color: var(--c-brand, #042e7b);
}
.positions__head,
.position {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(120px, auto);
  column-gap: clamp(1rem, 3vw, 48px);
  align-items: center;
}
.positions__head { padding-bottom: 12px; }
.positions__col {
  font-size: var(--fs-body);
  line-height: 1.556;
  color: var(--c-brand, #042e7b);
}
.positions__col--date { grid-column: 2; text-align: right; }
/* Head and rows are separate grids, so their auto-sized date/button columns
   each size to their own content and drift apart: the "Due date" header sat
   right of the dates (its row has no button, so column 3 collapsed to 120px).
   Share one set of tracks via subgrid — the widest button sizes column 3 for
   every row AND the header, and the dates line up across rows too. */
@supports (grid-template-columns: subgrid) {
  .positions {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(120px, auto);
    column-gap: clamp(1rem, 3vw, 48px);
  }
  .positions__head,
  .positions__list,
  .position {
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
  .positions__list { display: grid; }
}
.position {
  position: relative;
  min-height: 101px;
  padding-block: 12px;
  /* Faint track lines as borders (not pseudo backgrounds): the sweep pseudos
     below overlay them at -1px, and because border and pseudo belong to the
     same element they round to the same device pixel — no ghost track line
     peeking out next to the gradient. */
  border-top: 1px solid var(--brand-30-fresh, #a9bddf);
  border-bottom: 1px solid var(--brand-30-fresh, #a9bddf);
}
/* Adjacent rows overlap their borders into one shared line; the hovered row
   wins the paint order so its sweep is the one you see. */
.position + .position { margin-top: -1px; }
.position:hover { z-index: 1; }
/* Top + bottom sweep: a blue-to-turquoise gradient rolls across the track
   left-to-right on hover (Figma 28:2617) — scaleX like the news-list
   dividers, which animates reliably where the old background-size trick
   snapped in without rolling. */
.position::before,
.position::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: linear-gradient(to right, var(--c-action, #3660eb), var(--accent, #00ffec));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease-osmo, cubic-bezier(0.625, 0.05, 0, 1));
}
.position::before { top: -1px; }
.position::after { bottom: -1px; }
.position:hover::before,
.position:hover::after { transform: scaleX(1); }
/* The whole row is a link target: hovering the title still lights the row. */
.position:hover .position__title,
.position:hover .position__date { color: var(--c-action, #3660eb); }
.position__title {
  margin: 0;
  font-size: clamp(1.25rem, 1.9vw, 28px);
  line-height: 1.43;
  color: var(--c-brand, #042e7b);
  text-decoration: none;
  transition: color 0.3s ease;
}
.position__title:hover { color: var(--c-action, #3660eb); }
.position__date {
  font-size: var(--fs-body);
  line-height: 1.556;
  color: var(--c-brand, #042e7b);
  text-align: right;
  white-space: nowrap;
  transition: color 0.3s ease;
}
.position__cta { justify-self: end; }
.positions__spec { margin-top: clamp(2.5rem, 5vw, 72px); }
.positions__spec-heading {
  margin: 0 0 0.5em;
  font-size: clamp(1.25rem, 1.7vw, 24px);
  line-height: 1.333;
  color: var(--c-brand, #042e7b);
}
.positions__spec-text,
.positions__spec-text p {
  margin: 0;
  font-size: 14px;
  line-height: 1.57;
  color: var(--c-brand, #042e7b);
}
/* Inline links in the spec note: action blue + underline, like article links. */
/* Underline handled by the shared inline-link rule near the top (this block is
   rendered through alveus_rich, so it carries .rich-text). */
.positions__spec-text a:not(.button-040) {
  color: var(--c-action, #3660eb);
}

/* ---- Apply form (28:1966) ------------------------------------------ */
.form-section { padding-block: clamp(3rem, 6vw, 100px); }
.apply-form { max-width: 866px; margin-inline: auto; }
.apply-form__hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.apply-form__alert {
  margin: 0 0 1rem;
  padding: 12px 16px;
  border-radius: 8px;
  background: #fbe9e2;
  color: #c1512a;
  font-size: 14px;
}
/* Fields — Figma 28:1966: 60px tall, 8px radius, 30px inset, Blue 10 Fresh @50%
   fill with a Brand 30 Fresh border; active = white + action-blue border;
   error = white + #ff4000 border. Placeholder is brand blue at 30% opacity. */
.apply-field { margin-bottom: 20px; }
.apply-field input,
.apply-field select,
.apply-field textarea {
  width: 100%;
  padding: 15px 30px;
  font-family: inherit;
  font-size: var(--fs-body);
  line-height: 28px;
  color: var(--c-brand, #042e7b);
  background: rgba(232, 240, 255, 0.5);
  border: 1px solid var(--brand-30-fresh, #a9bddf);
  border-radius: 8px;
  outline: none;
  transition: border-color 0.25s ease, background-color 0.25s ease;
}
.apply-field input::placeholder,
.apply-field textarea::placeholder { color: var(--c-brand, #042e7b); opacity: 0.3; }
.apply-field select:invalid { color: rgba(4, 46, 123, 0.3); }
.apply-field input:focus,
.apply-field select:focus,
.apply-field textarea:focus {
  background: #fff;
  border-color: var(--c-action, #3660eb);
}
.apply-field.is-error input,
.apply-field.is-error select,
.apply-field.is-error textarea {
  background: #fff;
  border-color: #ff4000;
}
.apply-field__error { display: block; margin-top: 6px; font-size: 13px; color: #ff4000; }
.apply-field--select { position: relative; }
.apply-field--select select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M6 9l6 6 6-6' stroke='%23042e7b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 28px center;
  padding-right: 58px;
}
.apply-field--message textarea { min-height: 202px; line-height: 1.556; resize: vertical; }
/* Upload — Figma "Button/Upload": compact dark-blue 40px button, no helper text
   until a file is chosen (then the file name shows beside it). */
.apply-upload { display: inline-flex; align-items: center; gap: 16px; margin-bottom: 30px; cursor: pointer; }
.apply-upload input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.apply-upload__btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 40px;
  padding: 0 20px;
  border-radius: 8px;
  background: var(--c-brand, #042e7b);
  color: #fff;
  font-size: 18px;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
  transition: background-color 0.25s ease;
}
.apply-upload:hover .apply-upload__btn { background: #06246a; }
.apply-upload__plus { font-size: 20px; line-height: 1; margin-top: -2px; }
.apply-upload__name { font-size: 15px; color: var(--c-brand, #042e7b); opacity: 0.7; }
.apply-upload__name:empty { display: none; }
/* Consent — Figma 28:1987: 16px box, 2px radius, brand-blue border + 12px text. */
.apply-consent { display: flex; gap: 10px; margin-bottom: 30px; cursor: pointer; max-width: 866px; }
.apply-consent input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.apply-consent__box {
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 2px;
  border: 1px solid var(--c-brand, #042e7b);
  border-radius: 2px;
  background: #fff;
  position: relative;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.apply-consent input:checked + .apply-consent__box {
  background: var(--c-brand, #042e7b);
  border-color: var(--c-brand, #042e7b);
}
.apply-consent input:checked + .apply-consent__box::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 0px;
  width: 5px;
  height: 10px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.apply-consent input:focus-visible + .apply-consent__box { box-shadow: 0 0 0 3px rgba(54, 96, 235, 0.4); }
.apply-consent.is-error .apply-consent__box { border-color: #ff4000; }
.apply-consent__text { font-size: 12px; line-height: 19px; color: var(--c-brand, #042e7b); }
/* The submit reuses the button-040 look on a real <button>; strip UA chrome.
   NB: keep the button-040's own font-size (var(--fs-btn) = 12px) — a blanket
   `font: inherit` here would inherit 18px and blow the 50px pill up to ~75px. */
button.button-040.apply-form__submit {
  border: 0;
  background: none;
  font-family: inherit;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.apply-form__actions { margin-top: 0; }
.apply-thanks { max-width: 866px; margin-inline: auto; text-align: center; padding-block: clamp(2rem, 5vw, 60px); }
.apply-thanks__title { margin: 0 0 0.5em; font-size: clamp(1.75rem, 2.6vw, 34px); color: var(--c-brand, #042e7b); }
.apply-thanks__text { margin: 0 0 1.5em; font-size: var(--fs-body); line-height: 1.556; color: var(--c-brand, #042e7b); }
.apply-thanks__back { color: var(--c-action, #3660eb); text-decoration: none; font-weight: 600; }

/* ---- Gravity Forms shared form styling (Figma 28:1966 / 28:2648) -----
   Used by the careers apply form and the contact form. Gravity Forms' own CSS
   is disabled (see inc/gravity-forms.php); the theme styles the markup to match
   the design. Scoped to .form-section so no other Gravity Forms elsewhere on the
   site is affected. */
/* Contact page: "Get in touch with us" heading above the form. */
.form-section__inner { max-width: 866px; margin-inline: auto; }
.form-section__inner .gform_wrapper { max-width: none; }
.form-section__title {
  margin: 0 0 clamp(1.5rem, 3vw, 40px);
  font-weight: 400;
  font-size: clamp(2rem, 3.4vw, 42px);
  line-height: 1.19;
  color: #02225e;
}
.form-section .gform_wrapper { max-width: 866px; margin-inline: auto; }
.form-section .gform_required_legend { display: none; }
.form-section .gfield--type-honeypot,
.form-section .gform_validation_container { display: none !important; }
.form-section .gform_fields { display: block; margin: 0; padding: 0; }
.form-section .gfield { margin: 0 0 20px; }
/* The checkbox field is a <fieldset> — strip its default border/padding. */
.form-section fieldset.gfield { border: 0; padding: 0; min-width: 0; }
/* Labels are visually hidden — the design uses placeholders (kept for a11y). */
.form-section .gfield_label,
.form-section legend.gfield_label {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.form-section .ginput_container input:not([type="checkbox"]):not([type="file"]),
.form-section .ginput_container textarea,
.form-section .ginput_container select {
  width: 100%;
  padding: 15px 30px;
  font-family: inherit;
  font-size: var(--fs-body);
  line-height: 28px;
  color: var(--c-brand, #042e7b);
  background-color: rgba(232, 240, 255, 0.5);
  border: 1px solid var(--brand-30-fresh, #a9bddf);
  border-radius: 8px;
  outline: none;
  box-sizing: border-box;
  transition: border-color 0.25s ease, background-color 0.25s ease;
}
.form-section .ginput_container input::placeholder,
.form-section .ginput_container textarea::placeholder { color: var(--c-brand, #042e7b); opacity: 0.3; }
.form-section .ginput_container input:not([type="checkbox"]):not([type="file"]):focus,
.form-section .ginput_container textarea:focus,
.form-section .ginput_container select:focus { background-color: #fff; border-color: var(--c-action, #3660eb); }
.form-section .gfield_error .ginput_container input:not([type="checkbox"]):not([type="file"]),
.form-section .gfield_error .ginput_container textarea,
.form-section .gfield_error .ginput_container select { background-color: #fff; border-color: #ff4000; }
.form-section .ginput_container_textarea textarea { min-height: 202px; line-height: 1.556; resize: vertical; }
/* Position dropdown — lists every open vacancy; styled as the design's
   "Dropdown" with a chevron on the right (Figma 28:1966). */
.form-section .ginput_container_select { position: relative; }
.form-section .ginput_container select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  padding-right: 58px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none'%3E%3Cpath d='M6 9l6 6 6-6' stroke='%23042e7b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 28px center;
}
/* Field spacing accents from the design (message / upload / consent). */
.form-section .gfield--type-textarea,
.form-section .gfield--type-fileupload,
.form-section .gfield--type-checkbox { margin-bottom: 30px; }
.form-section .apply-upload { margin-bottom: 0; }
/* Validation feedback */
.form-section .gform_validation_errors {
  margin: 0 0 24px; padding: 12px 16px; border: 0; border-radius: 8px;
  background: #fbe9e2; color: #c1512a; box-shadow: none;
}
.form-section .gform_validation_errors > h2,
.form-section .gform_submission_error { margin: 0; font-size: 14px; font-weight: 600; color: #c1512a; }
.form-section .gfield_validation_message,
.form-section .validation_message { margin-top: 6px; padding: 0; border: 0; background: none; font-size: 13px; color: #ff4000; }
/* Consent checkbox (single required choice) */
.form-section .ginput_container_checkbox .gfield_checkbox { display: block; }
.form-section .gchoice { display: flex; align-items: flex-start; gap: 10px; }
.form-section .gchoice input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  flex: none; width: 16px; height: 16px; margin: 2px 0 0; padding: 0; box-sizing: border-box;
  border: 1px solid var(--c-brand, #042e7b); border-radius: 2px; background: #fff;
  cursor: pointer; position: relative;
  transition: background-color 0.2s ease, border-color 0.2s ease;
}
.form-section .gchoice input[type="checkbox"]:checked { background: var(--c-brand, #042e7b); border-color: var(--c-brand, #042e7b); }
.form-section .gchoice input[type="checkbox"]:checked::after {
  content: ""; position: absolute; left: 4px; top: 0; width: 5px; height: 10px;
  border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.form-section .gchoice input[type="checkbox"]:focus-visible { box-shadow: 0 0 0 3px rgba(54, 96, 235, 0.4); }
.form-section .gchoice label { font-size: 12px; line-height: 19px; color: var(--c-brand, #042e7b); cursor: pointer; }
.form-section .gfield_error.gfield--type-checkbox .gchoice input[type="checkbox"] { border-color: #ff4000; }
/* Footer / submit button (button-040 injected via gform_submit_button) */
.form-section .gform_footer { margin: 0; padding: 0; display: flex; }
.form-section .gform_ajax_spinner { margin-left: 14px; }

/* ---- Careers responsive -------------------------------------------- */
@media (max-width: 900px) {
  .benefits { grid-template-columns: 1fr; }
  /* Stacked layout: the sticky cross-fading title column sits above ALL the
     cards and has scrolled out of view by the time later steps activate, so
     titles 2+ swapped invisibly off-screen (client 2026-07). Hide the column
     and let every card carry its own title instead. */
  .benefits__aside { display: none; }
  .benefits__step { flex-direction: column; }
  .benefits__step-title {
    display: block;
    margin: 0 0 0.55em;
    font-size: clamp(1.5rem, 5.5vw, 1.75rem);
    line-height: 1.19;
    color: var(--c-brand, #042e7b);
    text-wrap: balance; /* same reason as the sticky title above */
  }
  .perks-tabs { flex-direction: column-reverse; }
  .perks-tabs__col { flex: 1 1 100%; width: 100%; }
}
@media (max-width: 720px) {
  .positions__head,
  .position { grid-template-columns: 1fr auto; row-gap: 10px; }
  .position__title { grid-column: 1 / -1; }
  .position__date { grid-column: 1; text-align: left; }
  .position__cta { grid-column: 2; grid-row: 2; }
  .positions__head { display: none; }
}
