/* ══════════════════════════════════════════════════════════════════════════
   KNOWPORT Gateway
   ══════════════════════════════════════════════════════════════════════════
   1.  Fonts
   2.  Tokens
   3.  Reset & base
   4.  Shared primitives
   5.  Header & navigation
   6.  Hero
   7.  About
   8.  Sectors
   9.  Partners
   10. Team
   11. Contact
   12. Footer
   13. Motion — reveals & keyframes
   14. Reduced motion
   ══════════════════════════════════════════════════════════════════════════ */


/* ── 1. Fonts ──────────────────────────────────────────────────────────────
   Heebo is a variable font, so one file per unicode subset covers every
   weight. Google is the primary source; the bundled copy in /fonts is the
   fallback the browser reaches for only if gstatic.com cannot be reached. */

@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('https://fonts.gstatic.com/s/heebo/v28/NGS6v5_NC0k9P9H2TbE.woff2') format('woff2'),
       url('../fonts/heebo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('https://fonts.gstatic.com/s/heebo/v28/NGS6v5_NC0k9P9H4TbFzsQ.woff2') format('woff2'),
       url('../fonts/heebo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Heebo';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('https://fonts.gstatic.com/s/heebo/v28/NGS6v5_NC0k9P9H0TbFzsQ.woff2') format('woff2'),
       url('../fonts/heebo-hebrew.woff2') format('woff2');
  unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}


/* ── 2. Tokens ─────────────────────────────────────────────────────────── */

:root {
  --aqua:         #09bbc9;
  --ink:          #021f41;
  --surface-deep: #001d3f;
  --paper:        #ffffff;
  --mist:         #e9eaea;
  --team-band:    #bcd9ee;
  --form-error:   #ff8a8a;

  --font-sans: 'Heebo', system-ui, sans-serif;

  --shell:   80rem;   /* max-w-7xl */
  --gutter:  1.5rem;
  --header-h: 5rem;   /* scroll offset for anchor targets */

  --ease-out-quint: cubic-bezier(0, 0, .2, 1);
}


/* ── 3. Reset & base ───────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Backstop against sideways drift. `clip` rather than `hidden` because it
     does not turn the page into a scroll container, and unlike `hidden` on
     <body> it is honoured by mobile Safari. */
  overflow-x: clip;
}

body {
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

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

a { color: inherit; text-decoration: none; }

button, input {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

ul { list-style: none; padding: 0; }

h1, h2, h3 { font-size: inherit; font-weight: inherit; }

[hidden] { display: none !important; }

::selection { background: var(--aqua); color: var(--ink); }


/* ── 4. Shared primitives ──────────────────────────────────────────────── */

.icon-4 { width: 1rem;    height: 1rem; }
.icon-5 { width: 1.25rem; height: 1.25rem; }
.icon-6 { width: 1.5rem;  height: 1.5rem; }
.icon-8 { width: 2rem;    height: 2rem; }

/* Buttons ---------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  padding: .75rem 1.5rem;
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.25rem;
  transition: background-color .15s cubic-bezier(.4, 0, .2, 1),
              border-color .15s cubic-bezier(.4, 0, .2, 1),
              color .15s cubic-bezier(.4, 0, .2, 1);
}

.btn--aqua {
  background: var(--aqua);
  color: var(--ink);
}
.btn--aqua:hover { background: rgb(9 187 201 / .9); }

.btn--outline {
  border: 1px solid var(--paper);
  color: var(--paper);
}
.btn--outline:hover { background: rgb(255 255 255 / .1); }

/* Sections --------------------------------------------------------------- */

.section {
  position: relative;
  padding-block: 6rem;
  scroll-margin-top: var(--header-h);
}

.section--paper { background: var(--paper); }
.section--ink   { background: var(--ink); }
.section--band  { background: var(--team-band); }
.section--deep  { background: var(--surface-deep); }

/* Full-bleed texture layer sitting behind a section's content. */
.section__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}

.section__inner {
  position: relative;
  z-index: 10;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Sectors and Team nest a second centred container inside the first, which
   doubles the horizontal gutter. Reproduced here as a single wider inset. */
.sectors .section__inner,
.team .section__inner { padding-inline: calc(var(--gutter) * 2); }

.section__title {
  text-wrap: balance;
  font-size: 1.875rem;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.025em;
  text-transform: uppercase;
}

.section__title--aqua  { color: var(--aqua); }
.section__title--paper { color: var(--paper); }
.section__title--ink   { color: var(--ink); }

/* Short aqua keyline used under headings and between paragraphs. */
.rule {
  height: .125rem;
  width: 3rem;
  background: var(--aqua);
}
.rule--center { margin-inline: auto; margin-top: 1.5rem; }

/* The KNOWPORT arch, drawn as a watermark behind several sections. */
.arch-svg {
  width: 100%;
  height: 100%;
  color: var(--aqua);
}


/* ── 5. Header & navigation ────────────────────────────────────────────── */

.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color .3s cubic-bezier(.4, 0, .2, 1),
              border-color .3s cubic-bezier(.4, 0, .2, 1);
}

.site-header.is-scrolled {
  background: rgb(255 255 255 / .95);
  backdrop-filter: blur(8px);
  border-bottom-color: var(--mist);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: var(--shell);
  margin-inline: auto;
  padding: 1rem var(--gutter);
}

.nav__logo {
  display: inline-flex;
  align-items: center;
  height: 2.25rem;
  width: auto;
}

/* Over the hero the bar is transparent and the hero shows its own, larger
   lockup, so the bar's mark is a duplicate — it fades in with the bar instead.
   It keeps its place in the layout: removing it would let `space-between` slide
   the burger and the nav links sideways on every scroll past 80px. The mobile
   menu has its own copy of .nav__logo, which this selector deliberately misses. */
.site-header .nav__logo {
  opacity: 0;
  visibility: hidden;
  transition: opacity .3s cubic-bezier(.4, 0, .2, 1),
              visibility .3s cubic-bezier(.4, 0, .2, 1);
}

.site-header.is-scrolled .nav__logo {
  opacity: 1;
  visibility: visible;
}

.nav__logo-img {
  height: 100%;
  width: auto;
  object-fit: contain;
}

/* The mark flips from the white lockup to the navy one once the bar fills in. */
.nav__logo-img--navy { display: none; }
.is-scrolled .nav__logo-img--white { display: none; }
.is-scrolled .nav__logo-img--navy  { display: block; }

.nav__links {
  display: none;
  align-items: center;
  gap: 2rem;
}

.nav__item { position: relative; }

.nav__link {
  font-size: 1.075rem;   /* 0.875rem + 0.2 */
  line-height: 1.43;
  font-weight: 500;
  letter-spacing: .025em;
  color: var(--paper);
  transition: color .15s cubic-bezier(.4, 0, .2, 1);
}
.is-scrolled .nav__link { color: var(--ink); }
.nav__link:hover { color: var(--aqua); }

.nav__item.is-active .nav__link { color: var(--aqua); }

/* Underline on the section currently in view. */
.nav__item.is-active::after {
  content: '';
  position: absolute;
  inset: auto 0 -.25rem 0;
  height: .125rem;
  border-radius: 9999px;
  background: var(--aqua);
}

.nav__cta { display: none; padding: .625rem 1.25rem; }

.nav__burger {
  border-radius: .375rem;
  padding: .5rem;
  color: var(--paper);
}
.is-scrolled .nav__burger { color: var(--ink); }

@media (min-width: 768px) {
  .nav__links { display: flex; }
  .nav__cta   { display: inline-flex; }
  .nav__burger { display: none; }
}

/* Mobile menu ------------------------------------------------------------ */

.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--surface-deep);
  animation: fade-in .25s ease-out both;
}
.mobile-menu.is-closing { animation: fade-out .25s ease-out both; }

.mobile-menu__inner {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 1rem var(--gutter);
}

.mobile-menu__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.mobile-menu__close {
  border-radius: .375rem;
  padding: .5rem;
  color: var(--paper);
}

.mobile-menu__nav {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2rem;
}

.mobile-menu__link {
  font-size: 1.5rem;
  line-height: 2rem;
  font-weight: 500;
  color: var(--paper);
  transition: color .15s cubic-bezier(.4, 0, .2, 1);
}
.mobile-menu__link:hover { color: var(--aqua); }

.mobile-menu__cta {
  margin-top: 1rem;
  padding: .75rem 2rem;
  font-size: 1.125rem;
  line-height: 1.75rem;
}


/* ── 6. Hero ───────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  overflow: hidden;
  background: var(--surface-deep);
  padding-top: 5rem;
  scroll-margin-top: var(--header-h);
}

/* --parallax is written by js/main.js on every scroll frame. */
.hero__backdrop {
  position: absolute;
  inset: 0;
  transform: translateY(var(--parallax, 0%)) scale(1.1);
}

.hero__backdrop-svg { width: 100%; height: 100%; }

.hero__arches { animation: arch-breathe 20s ease-in-out infinite; }

.hero__wire {
  stroke-dasharray: 0 1;
  animation: wire-draw calc(3s + var(--i) * .6s) ease-in-out infinite alternate;
}

.hero__nodes circle {
  opacity: 0;
  animation: node-pulse calc(4s + var(--i) * .8s) ease-in-out infinite;
  animation-delay: calc(var(--i) * .15s);
}
/* The original cycles the pulse length over five values, not sixteen. */
.hero__nodes circle:nth-child(5n+1) { animation-duration: 4.0s; }
.hero__nodes circle:nth-child(5n+2) { animation-duration: 4.8s; }
.hero__nodes circle:nth-child(5n+3) { animation-duration: 5.6s; }
.hero__nodes circle:nth-child(5n+4) { animation-duration: 6.4s; }
.hero__nodes circle:nth-child(5n+5) { animation-duration: 7.2s; }

/* The film sits at z-index 5 — above the line-work, below the scrim at 10. The
   photograph it replaced sat at 15, above both, which is why it stayed bright
   on the right; the video wants the opposite, so the wash and the left-hand
   darkening keep the headline readable over whatever frame is on screen.

   Inset vertically past the edges to give the parallax somewhere to travel
   without exposing a seam at the top. */
.hero__video {
  position: absolute;
  inset: -5% 0;
  z-index: 5;
  opacity: 0;
  transform: translateY(var(--parallax, 0px));
  transition: opacity 1.4s cubic-bezier(.4, 0, .2, 1);
}

.hero__video.is-ready { opacity: 1; }

.hero__video-el {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  /* The footage averages 20% brightness already; a touch of saturation and
     contrast keeps it from going muddy once the navy goes over the top. */
  filter: saturate(1.12) contrast(1.06);
}

/* The wash that sets the film inside the brand colour rather than letting it
   read as a video pasted behind the text. Kept light — heavier than this and
   footage this dark disappears altogether. */
.hero__tint {
  position: absolute;
  inset: 0;
  z-index: 8;
  background: var(--surface-deep);
  opacity: .34;
}

/* The middle stop is heavier than the .40 the photograph needed. Moving film can
   put a bright frame anywhere, and the tagline is aqua — a mid-luminance colour
   that loses contrast against a light ground, unlike the white headline. At .40
   a pure-white frame would drop it to 2.81:1, under the 3:1 WCAG asks for large
   text. The clear zone still opens at 65%, so the picture is untouched where it
   actually shows. */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: 10;
  background: linear-gradient(90deg,
    rgb(0 29 63 / .88) 0%,
    rgb(0 29 63 / .62) 55%,
    transparent 65%);
}

.hero__vignette {
  position: absolute;
  inset: 0;
  z-index: 10;
  background: radial-gradient(circle at 70% 50%,
    transparent 0%,
    rgb(0 29 63 / .55) 70%,
    rgb(0 29 63 / .92) 100%);
}

.hero__content {
  position: relative;
  z-index: 20;
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding: 3rem var(--gutter);
  transform: translateY(var(--parallax, 0px));
  opacity: var(--hero-fade, 1);
}

.hero__copy { max-width: 620px; }

.hero__logo { height: 4rem; width: auto; }
.hero__logo-img { height: 100%; width: auto; object-fit: contain; }

.hero__title {
  margin-top: 2rem;
  text-wrap: balance;
  font-size: clamp(2.75rem, 5vw, 4.5rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -.025em;
  color: var(--paper);
}

.hero__tagline {
  margin-top: 1rem;
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.375;
  color: var(--aqua);
}

.hero__actions {
  margin-top: 2.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.hero__scroll-cue {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  z-index: 20;
  translate: -50% 0;
  color: var(--aqua);
  opacity: 0;
  animation: fade-in .6s var(--ease-out-quint) 1.2s forwards;
}

.hero__scroll-bob {
  display: block;
  animation: bob 2s ease-in-out infinite;
}

/* The film on phones. Three things have to change together, or it is there but
   nobody sees it — which is what a full-width wash over a full-width column
   amounts to.

   1. Framing. A 16:9 frame cropped into a portrait box shows only about 29% of
      its width, so which 29% is a real choice. Centred, on the author's call.
   2. Room. Vertically centred, the copy ran 23%–88% of the hero and left 210px
      of dead space above it. Pinning it to the top frees a real band of picture
      below the buttons instead of a sliver.
   3. Direction of the wash. The desktop scrim runs left-to-right because the
      copy sits in the left half; on a phone the copy spans the full width, so a
      horizontal gradient can only bury the picture. Top-to-bottom protects the
      text where it actually is and opens the band that step 2 just made. */
@media (max-width: 767px) {
  .hero { align-items: flex-start; }
  .hero__content { padding-top: 1.5rem; }

  /* Stated rather than left to the base rule, so the phone framing is one line
     to change: `left center` shows the lit arcade instead. */
  .hero__video-el { object-position: center center; }

  /* Below the copy the wash is gone entirely — only the 34% brand tint is left,
     so the film reads at close to full strength in that band.

     Above 62% it stays heavy, and the reason is the tagline rather than the
     headline: aqua is a mid-luminance colour, so it loses contrast against a
     bright frame far faster than white does. Measured against a pure white
     frame, dropping this plateau to .74 puts the tagline at 4.00:1 and to .68
     puts it at 3.49 — still legal for large text, but no longer a comfortable
     margin. At .80 every element clears 4.5:1. */
  .hero__scrim {
    background: linear-gradient(180deg,
      rgb(0 29 63 / .80) 0%,
      rgb(0 29 63 / .76) 62%,
      rgb(0 29 63 / .08) 82%,
      rgb(0 29 63 / 0)   100%);
  }

  .hero__vignette {
    background: radial-gradient(ellipse at 50% 78%,
      transparent 0%,
      rgb(0 29 63 / .08) 65%,
      rgb(0 29 63 / .34) 100%);
  }
}


/* ── 7. About ──────────────────────────────────────────────────────────── */

.about__grid {
  display: grid;
  align-items: center;
  gap: 3rem;
}

@media (min-width: 1024px) {
  .about__grid {
    grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr);
  }
}

.about__lede {
  margin-top: 1.5rem;
  max-width: 70ch;
  font-size: 1.125rem;
  line-height: 1.625;
  color: rgb(2 31 65 / .8);
}
.about__lede--tight { margin-top: 0; }

.about .rule { margin-block: 1.5rem; }

.about__list {
  margin-top: 2rem;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.about__item {
  display: flex;
  gap: 1rem;
}

/* The icons scale with the list: the stroke is set in viewBox units, so a larger
   box draws a proportionally heavier line and they read a little stronger. */
.about__icon {
  margin-top: .125rem;
  width: 1.5rem;
  height: 1.5rem;
  flex-shrink: 0;
  color: var(--aqua);
}

.about__item-title {
  font-size: 1.125rem;
  font-weight: 600;
  color: var(--ink);
}

.about__item-line {
  font-size: 1rem;
  line-height: 1.625;
  color: rgb(2 31 65 / .7);
}

/* The commercialization wheel -------------------------------------------- */

/* Height drives how large the wheel draws, since the view box is taller than it
   is wide relative to this box. 680/526.4 is 680/470 opened up by just enough
   that, against the 448-unit view box, the wheel renders at 1.25× the size it
   had at 680/470 against 500 units — and it holds at every viewport width. */
.about__wheel {
  position: relative;
  width: 100%;
  max-width: 42rem;
  margin-inline: auto;
  aspect-ratio: 680 / 526.4;
}

@media (min-width: 1024px) {
  .about__wheel {
    max-width: none;
    margin-right: -4rem;
  }
}

/* On a phone the wheel was losing size twice over. Its own artwork is nearly
   square (viewBox 432×448) while this frame is wide, so `meet` scaled the SVG
   down to fit the height and left an empty column of about 40px on either side;
   and the frame itself stopped at the section gutter. Matching the frame to the
   artwork reclaims the first, and half the gutter reclaims most of the second.

   Only half: the view box hugs the wheel's own bounds, so its side labels —
   "Commercialization", "Knowledge & IP" — sit almost on the edge of the artwork.
   Spanning the full viewport left them 4px from the edge of the screen. */
@media (max-width: 767px) {
  .about__wheel {
    aspect-ratio: 432 / 448;
    width: calc(100% + var(--gutter));
    max-width: none;
    margin-inline: calc(var(--gutter) / -2);
  }
}

.about__wheel-arch {
  position: absolute;
  inset: 0;
  opacity: .04;
  pointer-events: none;
}

.wheel { width: 100%; height: 100%; }

/* The ring carries pathLength="1", so dash lengths are fractions of the
   circumference (2π × 174 ≈ 1093.27 user units):
     16 units of dash/gap → 16 / 1093.27   = 0.014635
     1000 units of travel → 1000 / 1093.27 = 0.914684
   It sweeps in solid over 1.2s, then the dash pattern marches round the ring
   once every ~33s. */
.wheel__ring {
  stroke-dasharray: 0 1;
  stroke-dashoffset: 0;
}
.is-in .wheel__ring {
  animation: ring-draw 1.2s ease-in-out forwards,
             ring-march 30s linear 1.2s infinite;
}

.wheel__node {
  opacity: 0;
  transition: opacity .5s cubic-bezier(.4, 0, .2, 1);
}
.is-in .wheel__node          { opacity: .55; }
.is-in .wheel__node.is-active { opacity: 1; }

.wheel__node-dot {
  fill: var(--aqua);
  transition: r .5s cubic-bezier(.4, 0, .2, 1);
}
.wheel__node.is-active .wheel__node-dot { r: 10; }

.wheel__node-label {
  fill: var(--ink);
  font-size: 17px;
  font-weight: 800;
  letter-spacing: 0;
}

/* Marker that runs the circumference once every cycle. */
.wheel__orbiter {
  fill: var(--aqua);
  stroke: var(--ink);
  offset-path: path('M 200 26 A 174 174 0 1 1 199.99 26');
  offset-distance: 0%;
}
.is-in .wheel__orbiter { animation: orbit 18s linear infinite; }

.wheel__center {
  opacity: 0;
  transform-box: view-box;
  transform-origin: 200px 200px;
}
.is-in .wheel__center {
  animation: fade-in .6s ease-out .3s forwards,
             center-breathe 14s ease-in-out infinite;
}

/* (206, 202) is the centre of the arrows' hole and of the photo clip alike, so
   the graphic turns on the spot instead of orbiting. */
.wheel__arrows {
  transform-box: view-box;
  transform-origin: 206px 202px;
}
.is-in .wheel__arrows { animation: arrows-spin 80s linear infinite; }

/* Both layers hold a photograph; only the top one is opaque, so the composite
   never dips in the middle of a cross-fade. */
.wheel__photo {
  opacity: 0;
  transition: opacity .7s cubic-bezier(.4, 0, .2, 1);
}
.wheel__photo.is-shown { opacity: 1; }


/* ── 8. Sectors ────────────────────────────────────────────────────────── */

.sectors__sparks {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.sectors__sparks span {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--s);
  height: var(--s);
  border-radius: 9999px;
  background: rgb(9 187 201 / .7);
  box-shadow: 0 0 14px rgb(9 187 201 / .7);
  opacity: .3;
  animation: spark var(--dur) ease-in-out infinite;
  animation-delay: var(--delay);
}

.sectors__head { margin-bottom: 3.5rem; text-align: center; }

/* minmax(0, 1fr) rather than the implicit `auto`: an auto track cannot shrink
   below its content's minimum, which is how a single long word was widening
   the page. */
.sectors__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2.5rem;
}

@media (min-width: 768px) {
  .sectors__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Each card carries its own accent. It marks the card — the bullets and the rule
   under the heading — while all the type stays white. The rule below is the
   fallback for a card without an accent of its own. */
/* --arch-inset is each artwork's own transparent left margin, as a fraction of
   its width. Pulling the figure left by that much puts the drawn arch — not the
   file's edge — on the same line as the heading. Measured per file; they differ. */
.sector                  { --sector-accent: var(--paper); --arch-inset: 0; }
.sector--hls             { --sector-accent: #1fb6c5; --arch-inset: .0503; }
.sector--manufacturing   { --sector-accent: #a6a6a6; --arch-inset: .0521; }
.sector--climate         { --sector-accent: #30a3d6; --arch-inset: .0648; }

/* Flush left, so the arch starts on the same line as the heading beneath it.
   The offset is a fraction of the figure's rendered width, which is the column
   until the 300px cap takes over — hence min(), not a bare percentage, which
   would resolve against the wider column and overshoot on desktop. */
.sector__figure {
  --arch-max: 300px;
  position: relative;
  width: 100%;
  max-width: var(--arch-max);
  margin-inline: calc(-1 * var(--arch-inset) * min(100%, var(--arch-max))) 0;
  aspect-ratio: 3 / 4;
  transition: transform .2s cubic-bezier(.4, 0, .2, 1);
}
.sector__figure:hover { transform: translateY(-3px); }

.sector__glow {
  position: absolute;
  inset: 18% 8% 3% 8%;
  border-radius: 9999px;
  background: rgb(9 187 201 / .25);
  filter: blur(64px);
}

.sector__glow-base {
  position: absolute;
  inset: auto 0 0 0;
  height: 66.6667%;
  background: linear-gradient(to top,
    rgb(9 187 201 / .2) 0%,
    rgb(9 187 201 / .05) 50%,
    transparent 100%);
  filter: blur(40px);
}

.sector__img {
  position: relative;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.sector__body {
  position: relative;
  z-index: 10;
  margin-top: -2.5rem;
}

@media (min-width: 768px) {
  .sector__body { margin-top: -3.5rem; }
}

/* "MANUFACTURING" is one unbreakable word 8.31em wide, so at a fixed size it sets
   a floor on the column and pushes the page sideways on anything narrower than a
   laptop. These sizes keep the longest word inside its column: one column below
   768px, three above, levelling off at the 40px cap once there is room for it. */
.sector__title {
  text-align: left;
  font-size: clamp(1.4rem, calc(11vw - 10.6px), 40px);
  font-weight: 800;
  line-height: .95;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--paper);
}

/* From 768px the row splits into three, so each column is a third as wide and
   the heading has to come down with it. Must sit after the base rule above —
   same specificity, so source order decides. */
@media (min-width: 768px) {
  .sector__title { font-size: min(calc(3.7vw - 2.6px), 40px); }
}

.sector__hr {
  margin-top: 1rem;
  height: 2px;
  width: 100%;
  background: var(--sector-accent);
}

.sector__list {
  margin-top: 1rem;
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.sector__list li {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  font-size: 17px;
  line-height: 1.625;
  color: var(--paper);
}

.sector__bullet {
  margin-top: .5rem;
  width: .375rem;
  height: .375rem;
  flex-shrink: 0;
  border-radius: 9999px;
  background: var(--sector-accent);
}


/* ── 9. Certification & value ──────────────────────────────────────────── */

/* Two blocks on one dark field: the IIA endorsement, then the four things
   KNOWPORT does for industry.

   The top padding is trimmed back from the 6/8rem the other sections use. This
   one follows the sectors, whose own bottom padding already supplies most of
   the separation, and the two together were leaving a gap wide enough to read
   as a break in the page. What remains still clears the motes drifting up
   behind the mark.

   Written as .section.certified rather than .certified alone: the responsive
   `.section { padding-block }` rule sits further down the file at equal
   specificity, so a single class here would lose to it on source order. */
.section.certified { padding-top: 2rem; }

@media (min-width: 768px) { .section.certified { padding-top: 3rem; } }

.certified__intro {
  display: grid;
  align-items: center;
  gap: 2rem;
  max-width: 60rem;
  margin-inline: auto;
}

/* The text column used to be 1fr, which swallowed every spare pixel: the grid
   box centred correctly while the words stopped 224px short of its right edge,
   throwing the block that everyone actually sees 111px to the left. Sizing the
   column to its content and letting the grid shrink-wrap centres what is inked
   rather than what is merely occupied. */
@media (min-width: 768px) {
  .certified__intro {
    width: fit-content;
    grid-template-columns: 260px minmax(0, max-content);
    gap: 3.5rem;
  }
}

/* Capped so the frame stays a mark rather than a hero image once the layout
   stacks on a phone; on desktop the grid column is already this wide. */
.certified__mark {
  position: relative;
  max-width: 260px;
}

.certified__frame {
  width: 100%;
  height: auto;
}

/* The supplied logo is navy, which would vanish against this background.
   brightness(0) crushes every colour to black and invert(1) lifts it to white,
   leaving the transparency untouched — so one filter recolours the artwork
   without needing a second version of the file. */
.certified__logo {
  position: absolute;
  left: 30%;
  top: 50%;
  width: 74%;
  height: auto;
  transform: translateY(-50%);
  filter: brightness(0) invert(1);
}

.certified__title {
  font-size: 40px;
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: -.01em;
  text-transform: uppercase;
  color: var(--paper);
}

.certified__lede {
  margin-top: 1rem;
  max-width: 42ch;
  font-size: 1.125rem;
  line-height: 1.6;
  color: var(--paper);
}

.value { margin-top: 5rem; }

@media (min-width: 768px) { .value { margin-top: 7rem; } }

.value__title {
  margin-bottom: 3rem;
  text-align: center;
  text-wrap: balance;
  font-size: 40px;
  line-height: 1.2;
  font-weight: 800;
  letter-spacing: -.01em;
  text-transform: uppercase;
  color: var(--aqua);
}

@media (min-width: 768px) { .value__title { margin-bottom: 3.5rem; } }

.value__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2.5rem;
}

@media (min-width: 640px)  { .value__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .value__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 2rem; } }

.value__icon {
  width: 3rem;
  height: 3rem;
  object-fit: contain;
}

/* Same idea as the drifting motes over the sectors, dialled up: fourteen rather
   than nine, roughly a third quicker, and travelling further, so the block reads
   as alive rather than merely not-static. */
.certified__sparks {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.certified__sparks span {
  position: absolute;
  left: var(--x);
  top: var(--y);
  width: var(--s);
  height: var(--s);
  border-radius: 9999px;
  background: rgb(9 187 201 / .8);
  box-shadow: 0 0 16px rgb(9 187 201 / .8);
  opacity: .35;
  animation: spark-strong var(--dur) ease-in-out infinite;
  animation-delay: var(--delay);
}

@keyframes spark-strong {
  0%, 100% { opacity: .35; transform: translate(0, 0); }
  50%      { opacity: .95; transform: translate(var(--dx), -74px); }
}

.value__name {
  margin-top: 1.25rem;
  font-size: 1.125rem;
  line-height: 1.25;
  font-weight: 800;
  letter-spacing: .01em;
  text-transform: uppercase;
  color: var(--aqua);
}

.value__rule {
  width: 1.75rem;
  height: 2px;
  margin: 1rem 0;
  background: var(--paper);
}

.value__text {
  font-size: 17px;
  line-height: 1.55;
  color: var(--paper);
}

/* The whole block reads from one left edge on a phone. In a narrow single column
   centred text starts every line in a different place, which is harder to scan
   than a straight margin. Set at the same breakpoint the grid stacks, so the two
   never disagree. */
@media (max-width: 639px) {
  .value__title { text-align: left; }

  /* Icon beside the heading rather than above it. Stacked in a single column the
     icon sat marooned on its own line and pushed the reading matter down the
     page; paired, each entry reads as one unit and the list gets shorter. */
  .value__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 1rem;
    align-items: center;
    text-align: left;
  }

  .value__icon { grid-column: 1; grid-row: 1; }

  .value__name {
    grid-column: 2;
    grid-row: 1;
    margin-top: 0;
    /* Two lines for all four headings. Measured: 18ch–20ch all give 2,2,2,2;
       16ch pushes the longest to three lines and 22ch collapses the other three
       to one. 19ch sits in the middle of the working range, so the result holds
       if font metrics shift a little. */
    max-width: 19ch;
    text-wrap: balance;
  }

  /* The divider goes. With the icon already marking where each entry starts, a
     second separator was doing a job nothing needed doing twice. Its 1rem
     margins were carrying the gap under the heading, so that moves to the text. */
  .value__rule { display: none; }

  .value__text {
    grid-column: 1 / -1;
    margin-top: .75rem;
  }
}


/* ── 10. Partners ──────────────────────────────────────────────────────── */

.partners {
  overflow: hidden;
  padding-block: 4rem;
}

.partners__head {
  margin-bottom: 3.5rem;
  text-align: center;
}

.marquee {
  --marquee-gap: 2.5rem;
  --marquee-slot: 210px;
  position: relative;
  display: flex;
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent 0, black 120px, black calc(100% - 120px), transparent 100%);
  -webkit-mask-image: linear-gradient(90deg, transparent 0, black 120px, black calc(100% - 120px), transparent 100%);
}

@media (min-width: 768px) { .marquee { --marquee-gap: 3.5rem; } }

.marquee__track {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  animation: marquee 40s linear infinite;
}

/* Faster on a phone. The lap time is fixed but the track is not: the narrower
   gap on small screens makes it 1855px against 2015px, so the same 40s already
   ran slower there — 23.2 px/s against 25.2. 26s brings it to 35.7 px/s, which
   is mid-range for a logo strip rather than at the sluggish end of it. */
@media (max-width: 767px) {
  .marquee__track { animation-duration: 26s; }
}

.marquee:hover .marquee__track { animation-play-state: paused; }

/* Each cell hugs its logo and carries half the spacing on either side, so the
   space between any two neighbours is always one --marquee-gap. Fixed-width
   slots made it uneven instead: a wide wordmark filled its slot edge to edge
   while a narrow mark left a wide margin, and two narrow marks side by side
   drifted more than twice as far apart as two wide ones.

   Spacing also has to live in padding rather than a flex `gap`: a gap puts 2N
   cells but only 2N−1 gaps on the track, so travelling exactly −50% stops half
   a gap short of where copy two lines up with copy one — the jolt once a lap.
   The two copies stay identical, so −50% is still exactly one copy. */
.marquee__cell {
  display: flex;
  flex-shrink: 0;
  padding-inline: calc(var(--marquee-gap) / 2);
  height: 5rem;
  align-items: center;
  justify-content: center;
}

.marquee__cell img {
  max-height: 3.5rem;
  width: auto;
  max-width: var(--marquee-slot);
  object-fit: contain;
  filter: grayscale(1);
  transition: filter .3s cubic-bezier(.4, 0, .2, 1);
}
/* The wordmarks are wide and run out of width before height; a square emblem
   held to the same height covers about a third of their area and reads as an
   afterthought. Squarer marks get the extra height instead. */
.marquee__cell--mark img { max-height: 4.75rem; }

.marquee__cell:hover img { filter: grayscale(0); }


/* ── 10. Team ──────────────────────────────────────────────────────────── */

.team__wrap { position: relative; }

/* A fixed 40rem watermark hanging 5rem off the left edge reaches past the right
   edge of a phone. Capping it at the container's width keeps it decorative
   instead of load-bearing. */
.team__arch {
  position: absolute;
  left: -5rem;
  top: 25%;
  width: min(40rem, 100%);
  aspect-ratio: 1;
  opacity: .05;
  pointer-events: none;
}

.team__head {
  position: relative;
  z-index: 10;
  margin-bottom: 3.5rem;
  text-align: center;
}

.team__lede {
  margin-inline: auto;
  margin-top: 1rem;
  max-width: 42rem;
  font-size: 1.125rem;
  line-height: 1.625;
  color: rgb(2 31 65 / .7);
}

.team__rows {
  position: relative;
  z-index: 10;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3rem;
}

.team__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2rem;
}

.member { flex: 0 1 240px; }

.member__card {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: 1.5rem;
  transition: transform .3s cubic-bezier(.4, 0, .2, 1);
}
.member:hover .member__card { transform: translateY(-.25rem); }

.member__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  filter: grayscale(1);
  transition: filter .5s cubic-bezier(.4, 0, .2, 1);
}
.member:hover .member__photo { filter: grayscale(0); }

.member__veil {
  position: absolute;
  inset: auto 0 0 0;
  height: 55%;
  background: linear-gradient(to top, rgb(2 31 65 / .92), transparent);
}

.member__meta {
  position: absolute;
  inset: auto 0 0 0;
  padding: 1rem;
}

.member__name {
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--paper);
}

.member__role {
  margin-top: .25rem;
  font-size: .75rem;
  line-height: 1.375;
  color: rgb(233 234 234 / .8);
}

.member__underline {
  position: absolute;
  bottom: 0;
  left: 0;
  height: .125rem;
  width: 0;
  background: var(--aqua);
  transition: width .25s cubic-bezier(.4, 0, .2, 1);
}
.member:hover .member__underline { width: 100%; }

/* ── Team, phones: two to a row ─────────────────────────────────────────────
   Thirteen full-width cards ran to 4,713px — 44% of the page, near seven
   screens of scrolling. Two per row roughly halves that.

   The gutter has to come down first. The section inherited a doubled gutter
   from the original's nested containers; at 48px a side that is a quarter of a
   375px screen, and paired cards would land at 116px — too small to hold a name
   like "Shirley Sheffer Hoffman". At 24px they come out around 155px, which
   carries the type comfortably once it is scaled to match.

   Self-contained on purpose: delete this block, and the section returns to
   exactly what it was.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width: 767px) {
  .team .section__inner { padding-inline: var(--gutter); }

  .team__rows { gap: 1rem; }
  .team__row  { gap: 1rem; }
  .member     { flex: 0 1 calc((100% - 1rem) / 2); }

  /* The type comes down with the card so the names still fit on two lines. */
  .member__meta { padding: .75rem; }
  .member__name { font-size: .9375rem; }
  .member__role { margin-top: .125rem; font-size: .6875rem; }

  /* Longer job titles now run taller than the old 55% scrim and would sit on
     bare photo; the gradient grows to keep them legible. */
  .member__veil { height: 70%; }

  /* On a 320px screen the pair is only ~121px each, and the caption starts to
     crowd out the face. One more step down gives the photograph its room back. */
  @media (max-width: 360px) {
    .member__meta { padding: .5rem; }
    .member__name { font-size: .875rem; line-height: 1.2; }
    .member__role { font-size: .625rem; }
  }
}


/* ── 11. Contact ───────────────────────────────────────────────────────── */

.contact { overflow: hidden; }

.contact__wrap {
  position: relative;
  z-index: 10;
  max-width: 48rem;
  margin-inline: auto;
}

.contact__head { text-align: center; }

.contact__lede {
  margin-inline: auto;
  margin-top: 1rem;
  max-width: 36rem;
  font-size: 1.125rem;
  line-height: 1.625;
  color: var(--mist);
}

.contact__panel {
  margin-top: 3rem;
  border-radius: 1rem;
  border: 1px solid rgb(255 255 255 / .12);
  background: rgb(255 255 255 / .05);
  backdrop-filter: blur(12px);
  padding: 1.5rem;
}

@media (min-width: 768px) { .contact__panel { padding: 3rem; } }

.contact__step { animation: step-in .2s ease-out both; }
.contact__step[data-step='audience'] { animation-name: step-in-left; }

.contact__step-label {
  margin-bottom: 1.5rem;
  text-align: center;
  font-size: 1.125rem;
  line-height: calc(1.75 / 1.125);
  font-weight: 600;
  color: rgb(255 255 255 / .7);
}

/* Audience picker -------------------------------------------------------- */

.audience {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

@media (min-width: 640px) {
  .audience { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.audience__option {
  position: relative;
  border-radius: 1rem;
  border: 1px solid rgb(255 255 255 / .15);
  background: transparent;
  padding: 1.5rem;
  text-align: left;
  transition: transform .2s cubic-bezier(.4, 0, .2, 1),
              border-color .2s cubic-bezier(.4, 0, .2, 1),
              background-color .2s cubic-bezier(.4, 0, .2, 1);
}
.audience__option:hover {
  transform: translateY(-2px);
  border-color: var(--aqua);
}
.audience__option:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--aqua);
}
.audience__option.is-selected {
  border-color: var(--aqua);
  background: rgb(9 187 201 / .1);
}

.audience__check {
  position: absolute;
  right: .75rem;
  top: .75rem;
  display: none;
  width: 1.25rem;
  height: 1.25rem;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: var(--aqua);
  color: var(--ink);
}
.audience__check svg { width: .875rem; height: .875rem; }
.audience__option.is-selected .audience__check { display: flex; }

.audience__icon {
  display: inline-block;
  color: var(--aqua);
  animation: bob-sm var(--dur) ease-in-out infinite alternate;
  animation-delay: var(--delay);
}

.audience__label {
  display: block;
  margin-top: 1rem;
  font-size: 1rem;
  font-weight: 600;
  color: var(--paper);
}

/* Chip summarising the chosen audience ----------------------------------- */

.chip {
  margin-bottom: 1.5rem;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  border-radius: 9999px;
  border: 1px solid var(--aqua);
  background: rgb(9 187 201 / .1);
  padding: .5rem 1rem;
  font-size: .875rem;
  line-height: calc(1.25 / .875);
  font-weight: 500;
  color: var(--paper);
}

.chip__icon { display: inline-flex; color: var(--aqua); }
.chip__icon svg { width: 1rem; height: 1rem; }

.chip__clear {
  margin-left: .25rem;
  border-radius: 9999px;
  padding: .125rem;
  color: rgb(255 255 255 / .7);
  transition: background-color .15s cubic-bezier(.4, 0, .2, 1),
              color .15s cubic-bezier(.4, 0, .2, 1);
}
.chip__clear:hover {
  background: rgb(9 187 201 / .2);
  color: var(--paper);
}

/* Fields ----------------------------------------------------------------- */

.fields {
  display: grid;
  gap: 1.25rem;
}

@media (min-width: 768px) {
  .fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .field--wide { grid-column: span 2; }
}

.field { display: block; }

.field__label {
  margin-bottom: .375rem;
  display: block;
  font-size: .875rem;
  line-height: calc(1.25 / .875);
  font-weight: 500;
  color: rgb(255 255 255 / .8);
}

.field__input {
  width: 100%;
  border-radius: .75rem;
  border: 1px solid rgb(255 255 255 / .2);
  background: transparent;
  padding: .75rem 1rem;
  color: var(--paper);
  transition: border-color .15s cubic-bezier(.4, 0, .2, 1),
              box-shadow .15s cubic-bezier(.4, 0, .2, 1);
}
.field__input::placeholder { color: rgb(255 255 255 / .4); }
.field__input:focus {
  outline: none;
  border-color: var(--aqua);
  box-shadow: 0 0 0 1px var(--aqua);
}

.field__error {
  margin-top: .375rem;
  display: block;
  font-size: .875rem;
  line-height: calc(1.25 / .875);
  color: var(--form-error);
}
.field__error--center { margin-top: 1rem; text-align: center; }

.contact__submit {
  margin-top: 2rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .75rem;
}

@media (min-width: 640px) {
  .contact__submit { flex-direction: row; align-items: center; }
}

.btn--submit {
  width: 100%;
  padding-inline: 2rem;
  font-weight: 700;
}
.btn--submit:disabled { opacity: .6; }

@media (min-width: 640px) { .btn--submit { width: auto; } }

/* Confirmation ----------------------------------------------------------- */

.thanks {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-block: 2.5rem;
  text-align: center;
  animation: thanks-in .4s ease-out both;
}

.thanks__badge {
  display: flex;
  width: 4rem;
  height: 4rem;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: rgb(9 187 201 / .1);
  color: var(--aqua);
}

.thanks__tick {
  stroke-dasharray: 1 1;
  stroke-dashoffset: 1;
  animation: tick-draw .5s ease-out .1s forwards;
}

.thanks__title {
  margin-top: 1.5rem;
  font-size: 1.5rem;
  line-height: calc(2 / 1.5);
  font-weight: 700;
  color: var(--paper);
}

.thanks__line {
  margin-top: .75rem;
  max-width: 28rem;
  color: rgb(255 255 255 / .7);
}

.thanks__again {
  margin-top: 2rem;
  border-radius: 9999px;
  border: 1px solid rgb(255 255 255 / .3);
  padding: .625rem 1.5rem;
  font-size: .875rem;
  line-height: calc(1.25 / .875);
  font-weight: 600;
  color: var(--paper);
  transition: background-color .15s cubic-bezier(.4, 0, .2, 1),
              color .15s cubic-bezier(.4, 0, .2, 1);
}
.thanks__again:hover { background: var(--paper); color: var(--ink); }


/* ── 12. Footer ────────────────────────────────────────────────────────── */

.footer {
  position: relative;
  overflow: hidden;
  background: var(--paper);
  padding-block: 4rem;
}

.footer__arch {
  position: absolute;
  inset: 0;
  opacity: .03;
  pointer-events: none;
}

.footer__inner {
  position: relative;
  z-index: 10;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.footer__grid {
  display: grid;
  gap: 3rem;
}

@media (min-width: 768px) {
  .footer__grid { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .footer__brand   { grid-column: span 5; }
  .footer__nav     { grid-column: span 3; }
  .footer__contact { grid-column: span 4; }
}

.footer__logo {
  display: inline-block;
  height: 2.5rem;
  width: auto;
}
.footer__logo img { height: 100%; width: auto; object-fit: contain; }

.footer__blurb {
  margin-top: 1rem;
  max-width: 24rem;
  font-size: .875rem;
  line-height: 1.625;
  color: rgb(2 31 65 / .7);
}

.footer__list {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  color: rgb(2 31 65 / .7);
}

.footer__list a { transition: color .15s cubic-bezier(.4, 0, .2, 1); }
.footer__list a:hover { color: var(--aqua); }

.footer__social {
  display: inline-flex;
  color: var(--aqua);
  transition: transform .15s cubic-bezier(.4, 0, .2, 1);
}
.footer__social:hover { transform: translateY(-2px); }

.footer__divider {
  margin-block: 2.5rem;
  height: 1px;
  width: 100%;
  background: rgb(2 31 65 / .1);
}

.footer__legal {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  font-size: .75rem;
  line-height: calc(1 / .75);
  color: rgb(2 31 65 / .5);
}
.footer__legal a { transition: color .15s cubic-bezier(.4, 0, .2, 1); }
.footer__legal a:hover { color: var(--aqua); }

@media (min-width: 768px) {
  .footer__legal { flex-direction: row; align-items: center; }
}


/* ── 13. Dialogs, consent & accessibility ──────────────────────────────── */

.footer__legal-links {
  display: flex;
  align-items: center;
  gap: .5rem;
}

.footer__legal-link {
  padding: 0;
  font-size: .75rem;
  line-height: calc(1 / .75);
  color: rgb(2 31 65 / .5);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color .15s cubic-bezier(.4, 0, .2, 1);
}
.footer__legal-link:hover { color: var(--aqua); }

.footer__legal-sep { color: rgb(2 31 65 / .3); }

/* Policy modals ---------------------------------------------------------
   Native <dialog> carries the focus trap, the Escape handler and the inert
   background itself, which is both less code and better behaved than a
   hand-rolled equivalent. */

.modal {
  width: min(52rem, calc(100vw - 2rem));
  max-height: min(80vh, 52rem);
  /* Restored explicitly: the browser centres a modal <dialog> with margin:auto,
     and the `* { margin: 0 }` reset at the top of this file wipes that out,
     dropping the dialog into the top-left corner. */
  margin: auto;
  padding: 0;
  border: 1px solid var(--mist);
  border-radius: 1rem;
  background: var(--paper);
  color: var(--ink);
  overflow: hidden;
}

.modal::backdrop {
  background: rgb(2 31 65 / .6);
  backdrop-filter: blur(3px);
}

.modal[open] {
  display: flex;
  flex-direction: column;
  animation: modal-in .25s cubic-bezier(.4, 0, .2, 1);
}

.modal__bar {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.25rem 1.5rem;
  border-bottom: 1px solid var(--mist);
  background: var(--paper);
}

.modal__title {
  font-size: 1.25rem;
  line-height: 1.4;
  font-weight: 800;
  letter-spacing: -.015em;
  text-transform: uppercase;
  color: var(--ink);
}

.modal__close {
  display: inline-flex;
  padding: .5rem;
  margin: -.5rem;
  border-radius: .5rem;
  color: rgb(2 31 65 / .55);
  transition: background-color .15s, color .15s;
}
.modal__close:hover { background: var(--mist); color: var(--ink); }

.modal__body {
  overflow-y: auto;
  padding: 1.5rem;
}

/* Long-form legal copy --------------------------------------------------- */

.prose { font-size: .9375rem; line-height: 1.7; color: rgb(2 31 65 / .82); }
.prose p  { margin-bottom: 1rem; }
.prose ul { margin: 0 0 1rem; padding-left: 1.125rem; list-style: disc; }
.prose li { margin-bottom: .375rem; }
.prose strong { font-weight: 600; color: var(--ink); }

.prose h3 {
  margin: 1.75rem 0 .625rem;
  font-size: 1rem;
  line-height: 1.4;
  font-weight: 700;
  color: var(--ink);
}
.prose > h3:first-of-type { margin-top: 1.25rem; }

.prose a,
.prose__link {
  padding: 0;
  font: inherit;
  color: var(--aqua);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.prose a:hover,
.prose__link:hover { color: var(--ink); }

.prose__meta {
  font-size: .8125rem;
  color: rgb(2 31 65 / .5);
}

/* Marks the gaps a lawyer still has to fill in. */
.prose__note {
  margin-top: 1.75rem;
  padding: .875rem 1rem;
  border-left: 3px solid var(--aqua);
  border-radius: 0 .375rem .375rem 0;
  background: rgb(9 187 201 / .07);
  font-size: .8125rem;
  color: rgb(2 31 65 / .7);
}

/* Cookie notice ---------------------------------------------------------- */

.cookies {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 70;
  padding: 1rem;
  animation: cookies-in .35s cubic-bezier(.4, 0, .2, 1) .4s both;
}

.cookies__inner {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: 64rem;
  margin-inline: auto;
  padding: 1.25rem 1.5rem;
  border: 1px solid rgb(255 255 255 / .14);
  border-radius: 1rem;
  background: var(--surface-deep);
  box-shadow: 0 18px 48px rgb(2 31 65 / .45);
}

@media (min-width: 768px) {
  .cookies__inner { flex-direction: row; align-items: center; gap: 1.5rem; }
}

.cookies__text {
  font-size: .875rem;
  line-height: 1.6;
  color: rgb(255 255 255 / .78);
}

.cookies__link {
  padding: 0;
  font: inherit;
  color: var(--aqua);
  text-decoration: underline;
  text-underline-offset: 2px;
  white-space: nowrap;
}
.cookies__link:hover { color: var(--paper); }

.cookies__actions {
  display: flex;
  flex-shrink: 0;
  flex-wrap: wrap;
  gap: .75rem;
}

.cookies__btn { padding: .625rem 1.25rem; white-space: nowrap; }

.btn--ghost {
  border: 1px solid rgb(255 255 255 / .3);
  color: var(--paper);
}
.btn--ghost:hover { background: rgb(255 255 255 / .1); }

/* Accessibility panel ---------------------------------------------------- */

/* Sits above the cookie notice and steps up by however tall that notice is, so
   the two never overlap on a phone where the notice spans the full width.
   --cookie-height is written by js/main.js and cleared once it is dismissed. */
.a11y {
  position: fixed;
  left: 1rem;
  bottom: calc(1rem + var(--cookie-height, 0px));
  z-index: 80;
  display: flex;
  align-items: flex-end;
  gap: .5rem;
  transition: bottom .3s cubic-bezier(.4, 0, .2, 1);
}

.a11y__toggle {
  display: inline-flex;
  flex-shrink: 0;
  width: 2.75rem;
  height: 2.75rem;
  align-items: center;
  justify-content: center;
  border-radius: 9999px;
  background: var(--aqua);
  color: var(--ink);
  box-shadow: 0 6px 20px rgb(2 31 65 / .35);
  transition: transform .2s cubic-bezier(.4, 0, .2, 1);
}
.a11y__toggle:hover { transform: scale(1.06); }

.a11y__panel {
  width: 15rem;
  /* Height has to leave room for the cookie notice the widget is sitting on
     top of, or a tall stacked notice on a phone pushes the panel off-screen. */
  max-height: min(32rem, calc(100vh - 2rem - var(--cookie-height, 0px)));
  max-height: min(32rem, calc(100dvh - 2rem - var(--cookie-height, 0px)));
  overflow-y: auto;
  padding: 1rem;
  border: 1px solid var(--mist);
  border-radius: .875rem;
  background: var(--paper);
  color: var(--ink);
  box-shadow: 0 18px 48px rgb(2 31 65 / .3);
  animation: a11y-in .2s cubic-bezier(.4, 0, .2, 1);
}

.a11y__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: .875rem;
}

.a11y__title {
  font-size: .875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink);
}

.a11y__close {
  display: inline-flex;
  padding: .25rem;
  margin: -.25rem;
  border-radius: .375rem;
  color: rgb(2 31 65 / .5);
}
.a11y__close:hover { background: var(--mist); color: var(--ink); }

.a11y__group { margin-bottom: .875rem; }

.a11y__label {
  display: block;
  margin-bottom: .375rem;
  font-size: .75rem;
  font-weight: 600;
  color: rgb(2 31 65 / .6);
}

.a11y__steps { display: flex; gap: .375rem; }

.a11y__step {
  flex: 1;
  padding: .375rem 0;
  border: 1px solid var(--mist);
  border-radius: .375rem;
  font-weight: 700;
  line-height: 1;
  color: rgb(2 31 65 / .7);
  transition: border-color .15s, background-color .15s, color .15s;
}
.a11y__step:nth-child(1) { font-size: .75rem; }
.a11y__step:nth-child(2) { font-size: .875rem; }
.a11y__step:nth-child(3) { font-size: 1rem; }
.a11y__step:nth-child(4) { font-size: 1.125rem; }
.a11y__step:hover { border-color: var(--aqua); }
.a11y__step[aria-pressed="true"] {
  border-color: var(--aqua);
  background: var(--aqua);
  color: var(--ink);
}

.a11y__list { display: flex; flex-direction: column; gap: .375rem; }

.a11y__opt {
  width: 100%;
  padding: .5rem .625rem;
  border: 1px solid var(--mist);
  border-radius: .375rem;
  text-align: left;
  font-size: .8125rem;
  color: rgb(2 31 65 / .8);
  transition: border-color .15s, background-color .15s, color .15s;
}
.a11y__opt:hover { border-color: var(--aqua); }
.a11y__opt[aria-pressed="true"] {
  border-color: var(--aqua);
  background: rgb(9 187 201 / .12);
  color: var(--ink);
  font-weight: 600;
}

.a11y__reset {
  width: 100%;
  margin-top: .875rem;
  padding: .5rem;
  border-radius: .375rem;
  background: var(--ink);
  font-size: .8125rem;
  font-weight: 600;
  color: var(--paper);
  transition: opacity .15s;
}
.a11y__reset:hover { opacity: .88; }

@media (max-width: 767px) {
  .a11y__panel { width: min(15rem, calc(100vw - 5.5rem)); }
}

/* What the accessibility options actually do ----------------------------- */

html[data-a11y-text="1"] { font-size: 112.5%; }
html[data-a11y-text="2"] { font-size: 125%; }
html[data-a11y-text="3"] { font-size: 140%; }

/* Inverting the page rather than restyling it keeps every element covered,
   including the photographs; the panel itself is inverted back so its own
   controls stay recognisable.

   The filter goes on <html>, never on <body>. A filter makes its element the
   containing block for `position: fixed` descendants, so filtering <body>
   quietly unsticks this very panel — click one option and the control you
   need to undo it scrolls away. The root element is exempt. */
html[data-a11y-contrast="on"] { filter: invert(1) hue-rotate(180deg); }
html[data-a11y-grayscale="on"] { filter: grayscale(1); }
html[data-a11y-contrast="on"][data-a11y-grayscale="on"] { filter: invert(1) hue-rotate(180deg) grayscale(1); }

html[data-a11y-contrast="on"] .a11y__panel,
html[data-a11y-contrast="on"] .modal,
html[data-a11y-contrast="on"] .cookies__inner { filter: invert(1) hue-rotate(180deg); }

html[data-a11y-links="on"] a { text-decoration: underline !important; text-underline-offset: 2px; }

html[data-a11y-readable="on"] body,
html[data-a11y-readable="on"] .modal,
html[data-a11y-readable="on"] .a11y__panel {
  font-family: Verdana, Tahoma, "DejaVu Sans", sans-serif !important;
}

html[data-a11y-spacing="on"] body {
  letter-spacing: .045em;
  word-spacing: .14em;
  line-height: 1.85;
}

html[data-a11y-still="on"] *,
html[data-a11y-still="on"] *::before,
html[data-a11y-still="on"] *::after {
  animation-play-state: paused !important;
  transition: none !important;
}

@keyframes modal-in {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to   { opacity: 1; transform: none; }
}

@keyframes cookies-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@keyframes a11y-in {
  from { opacity: 0; transform: translateY(8px) scale(.97); }
  to   { opacity: 1; transform: none; }
}


/* ── 14. Motion ────────────────────────────────────────────────────────── */

/* Scroll reveals. js/main.js adds .is-in once the block enters the viewport;
   --y and --t vary the travel and duration, --d the stagger. */
[data-reveal] {
  opacity: 0;
  transform: translateY(var(--y, 16px));
  transition: opacity var(--t, .5s) ease-out var(--d, 0s),
              transform var(--t, .5s) ease-out var(--d, 0s);
}
[data-reveal].is-in {
  opacity: 1;
  transform: none;
}

.sector,
.member { --y: 24px; }
.member { --t: .4s; }

/* Hero copy animates on load rather than on scroll. */
.reveal-up { animation: reveal-up .4s var(--ease-out-quint) var(--d, 0s) both; }

@keyframes reveal-up {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}

@keyframes fade-in  { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }

@keyframes arch-breathe {
  0%, 100% { opacity: .04; }
  50%      { opacity: .07; }
}

@keyframes wire-draw {
  from { stroke-dasharray: 0 1; }
  to   { stroke-dasharray: 1 1; }
}

@keyframes node-pulse {
  0%, 100% { opacity: .2; }
  50%      { opacity: .55; }
}

}

}

}

@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(8px); }
}

@keyframes bob-sm {
  from { transform: translateY(0); }
  to   { transform: translateY(-2px); }
}

@keyframes ring-draw {
  from { stroke-dasharray: 0 1; }
  to   { stroke-dasharray: 1 1; }
}

@keyframes ring-march {
  from { stroke-dasharray: 0.014635 0.014635; stroke-dashoffset: 0; }
  to   { stroke-dasharray: 0.014635 0.014635; stroke-dashoffset: -0.914684; }
}

@keyframes orbit {
  from { offset-distance: 0%; }
  to   { offset-distance: 100%; }
}

@keyframes center-breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.03); }
}

@keyframes arrows-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes spark {
  0%, 100% { opacity: .3; transform: translate(0, 0); }
  50%      { opacity: .9; transform: translate(var(--dx), -52px); }
}

@keyframes marquee {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}

@keyframes step-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes step-in-left {
  from { opacity: 0; transform: translateX(-16px); }
  to   { opacity: 1; transform: none; }
}

@keyframes thanks-in {
  from { opacity: 0; transform: scale(.96); }
  to   { opacity: 1; transform: none; }
}

@keyframes tick-draw {
  to { stroke-dashoffset: 0; }
}


/* ── 14. Larger viewports ──────────────────────────────────────────────── */

@media (min-width: 768px) {
  .section        { padding-block: 8rem; }
  .partners       { padding-block: 5rem; }
  .footer         { padding-block: 5rem; }
  .section__title { font-size: 2.25rem; }
}

@media (min-width: 1024px) {
  .section__title { font-size: 3rem; line-height: 1.05; }
}


/* ── 15. Reduced motion ────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }

  [data-reveal],
  .reveal-up,
  .hero__scroll-cue { opacity: 1; transform: none; }

  .hero__nodes circle { opacity: .35; }
  .wheel__node        { opacity: 1; }
  .wheel__center      { opacity: 1; }
  .wheel__ring        { stroke-dasharray: 0.014635 0.014635; }
  .hero__wire         { stroke-dasharray: 1 1; }
  .sectors__sparks span,
  .certified__sparks span { opacity: .35; }
}
