/* ==========================================================================
   Galaxy Vast — site stylesheet
   1. Tokens & reset
   2. Base typography & helpers
   3. Header / nav / search
   4. Hero
   5. Home sections (about, values, reach, partners)
   6. Sub-page components (page hero, panels, cards, timeline, form, news)
   7. Footer
   8. Motion & responsive
   ========================================================================== */

/* 1. Tokens & reset -------------------------------------------------------- */

:root {
  color-scheme: light;

  --navy-950: #03071a;
  --navy-900: #050b1f;
  --ink: #101a2e;
  --ink-soft: #334155;
  /* AA floor, not taste: body copy sits on --surface/--surface-2, and #5b6b83 is the
     nearest muted tone that clears 4.5:1 there (the old #64748b measured 4.44 / 4.24). */
  --muted: #5b6b83;
  --muted-light: #94a3b8;
  /* Rating ink, not decoration amber: #c87200 is the brightest gold that still clears 3:1 against
     the white card, and the dark theme inverts to a lighter one rather than reusing this. */
  --star: #c87200;
  --surface: #f5f7fb;
  --surface-2: #eef2f8;
  --card: #ffffff;
  --band: #ffffff;
  --line: #e3e8f0;
  --line-dark: rgba(255, 255, 255, 0.12);
  --danger: #dc2626;

  --accent: #4f46e5;
  --accent-2: #8b5cf6;
  --accent-3: #22d3ee;
  --accent-text: #4f46e5;
  --grad: linear-gradient(120deg, var(--accent-3), var(--accent) 45%, var(--accent-2));
  --grad-text: linear-gradient(120deg, var(--accent-3), var(--accent) 45%, var(--accent-2));

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 22px;
  --radius-pill: 999px;

  /* Everything below is measured off the mockup (1254px wide): the design column spans
     87.2% of the viewport there (88px margins, 1094px of content), the hero band is 38.9%
     of the width tall, and the headline / tagline / body sizes are 2.7 / 1.8 / 1.06vw.
     Repeating those as viewport fractions keeps the page proportional on every screen
     instead of pinning a fixed strip in the middle of a wide display. */
  --container: min(2560px, 100vw);
  --gutter: clamp(22px, 6.4vw, 164px);
  --section-y: clamp(34px, 3.1vw, 92px);
  --brand-mark: clamp(38px, 4.5vw, 88px);
  /* 82px is the mockup's band, but the mark is fluid, so the band has to track it — at 1.34×
     the box, not 1×. The logo SVG carries transparent padding, and the mockup's brand ink
     clears the top by about half its own height (21px above a 43px mark at 1254). Padding the
     box rather than max()-ing it against 82px is what fixes the inversion that left the mark
     12px from the edge at 1920 and 2560 while still growing. */
  --header-h: max(82px, calc(var(--brand-mark) * 1.34));
  --measure: 62ch;

  --fs-display: clamp(26px, 2.7vw, 62px);
  --fs-h3: clamp(16px, 1.5vw, 32px);
  --fs-lead: clamp(13.5px, 1.06vw, 22px);
  --fs-body: clamp(12.5px, 1vw, 20px);
  --fs-meta: clamp(11px, 0.88vw, 18px);

  --shadow-sm: 0 1px 2px rgba(16, 26, 46, 0.06), 0 8px 24px rgba(16, 26, 46, 0.06);
  --shadow-md: 0 18px 48px rgba(16, 26, 46, 0.14);
  --shadow-glow: 0 0 0 1px rgba(255, 255, 255, 0.08), 0 24px 70px rgba(79, 70, 229, 0.35);

  --font-head: "Poppins", "Segoe UI", "Microsoft YaHei", system-ui, sans-serif;
  --font-body: "Inter", "Segoe UI", "Microsoft YaHei", system-ui, sans-serif;
}

/* Dark theme. The header, hero and footer already paint themselves with the
   navy variables and white text, so only the content tokens flip here. */
[data-theme="dark"] {
  color-scheme: dark;

  --ink: #e9eefb;
  --ink-soft: #c4cee1;
  --muted: #94a2bd;
  --muted-light: #76839e;
  --star: #f5b342;
  --surface: #070d20;
  --surface-2: #111d3e;
  --card: #0e1a37;
  --band: #040a1a;
  --line: #223257;
  --danger: #f87171;
  --accent-text: #93a4fc;
  --grad-text: linear-gradient(120deg, #22d3ee, #93a4fc 45%, #c4b5fd);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45), 0 8px 24px rgba(0, 0, 0, 0.35);
  --shadow-md: 0 18px 48px rgba(0, 0, 0, 0.55);
}

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

/* Author `display:` rules otherwise outrank the UA sheet's [hidden] rule. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--font-head);
  font-weight: 600;
  line-height: 1.22;
  margin: 0 0 0.6em;
  letter-spacing: -0.01em;
}

p { margin: 0 0 1.1em; }
ul { margin: 0; padding: 0; list-style: none; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
address { font-style: normal; }
button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; background: none; border: 0; }

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

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

.skip-link {
  position: fixed;
  top: 12px; left: 12px;
  z-index: 100;
  padding: 10px 18px;
  background: var(--card);
  color: var(--ink);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-md);
  transform: translateY(-160%);
  transition: transform 0.2s ease;
}
.skip-link:focus-visible { transform: translateY(0); }

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

.eyebrow {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 clamp(12px, 1.5vw, 28px);
  font-family: var(--font-head);
  font-size: var(--fs-meta);
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow i {
  width: clamp(40px, 5vw, 96px); height: 1px;
  background: linear-gradient(90deg, var(--muted-light), transparent);
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 13px 28px;
  border-radius: var(--radius-pill);
  font-family: var(--font-head);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: 0.01em;
  transition: transform 0.25s ease, box-shadow 0.25s ease, background-color 0.25s ease, color 0.25s ease;
}
.btn svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 1.8; fill: none; }
.btn:hover { transform: translateY(-2px); }
.btn-ghost {
  border: 1px solid rgba(255, 255, 255, 0.55);
  color: #fff;
  background: rgba(255, 255, 255, 0.06);
  backdrop-filter: blur(6px);
}
.btn-ghost:hover { background: rgba(255, 255, 255, 0.16); box-shadow: 0 14px 34px rgba(3, 7, 26, 0.4); }
.btn-solid {
  /* Same three brand hues as --grad, but the cyan only survives across the left padding:
     white text on the label's real ink span measured 3.34:1 with --grad's 45% indigo stop,
     and a *percentage* stop still left 4.26:1 on the wider contact submit. A fixed 26px
     ramp keeps the light cyan off the glyphs whatever the label width or language. */
  background: linear-gradient(120deg, var(--accent-3), var(--accent) 26px, var(--accent-2));
  color: #fff;
  box-shadow: 0 14px 32px rgba(79, 70, 229, 0.32);
}
.btn-solid:hover { box-shadow: 0 18px 44px rgba(79, 70, 229, 0.45); }

.text-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-head);
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
  padding-block: 4px;
}
.text-link svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 1.9; fill: none; transition: transform 0.25s ease; }
.text-link:hover { color: var(--accent-text); }
.text-link:hover svg { transform: translateX(5px); }

/* 2. Header ---------------------------------------------------------------- */

.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: 60;
  color: #fff;
  transition: background-color 0.3s ease, box-shadow 0.3s ease, backdrop-filter 0.3s ease;
}
.site-header.is-solid {
  background: rgba(5, 11, 31, 0.92);
  backdrop-filter: blur(14px);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.07), 0 12px 34px rgba(3, 7, 26, 0.35);
}

section[id] { scroll-margin-top: calc(var(--header-h) + 20px); }

.header-inner {
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  min-height: var(--header-h);
}

.brand { display: inline-flex; align-items: center; gap: clamp(10px, 1.4vw, 26px); }
.brand-mark { width: var(--brand-mark); height: var(--brand-mark); flex: none; filter: drop-shadow(0 4px 14px rgba(139, 92, 246, 0.45)); }
.brand-text { display: grid; gap: 1px; }
.brand-name {
  font-family: var(--font-head);
  font-size: clamp(15px, 1.5vw, 30px);
  font-weight: 600;
  letter-spacing: 0.005em;
  line-height: 1.2;
}
.brand-sub {
  font-size: clamp(9px, 0.85vw, 17px);
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.62);
  line-height: 1.4;
}

.main-nav { margin-inline: auto; }
.main-nav > ul { display: flex; align-items: center; gap: clamp(18px, 3.4vw, 62px); }
.main-nav a {
  position: relative;
  display: block;
  padding: 6px 0;
  font-family: var(--font-head);
  font-size: 14.5px;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.82);
  transition: color 0.2s ease;
}
.main-nav a::after {
  content: "";
  position: absolute;
  left: 0; right: 100%; bottom: 0;
  height: 2px;
  border-radius: 2px;
  background: var(--grad);
  transition: right 0.3s ease;
}
.main-nav a:hover { color: #fff; }
.main-nav a:hover::after,
.main-nav a[aria-current="page"]::after { right: 0; }
.main-nav a[aria-current="page"] { color: #fff; }

.header-tools { display: flex; align-items: center; gap: 0; }
.header-tools .lang-switch { margin-right: 8px; }

.lang-switch { display: flex; align-items: center; gap: 8px; font-size: 13px; color: rgba(255, 255, 255, 0.55); }
.lang-switch button {
  padding: 4px 2px;
  font-family: var(--font-head);
  font-size: 13px;
  color: rgba(255, 255, 255, 0.7);
  transition: color 0.2s ease;
}
.lang-switch button:hover { color: #fff; }
.lang-switch button[aria-pressed="true"] { color: #fff; font-weight: 600; }
.lang-switch--mobile { display: none; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 40px; height: 40px;
  border-radius: 50%;
  color: rgba(255, 255, 255, 0.85);
  transition: background-color 0.2s ease, color 0.2s ease;
}
.icon-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
.icon-btn:hover { background: rgba(255, 255, 255, 0.14); color: #fff; }
.nav-toggle { display: none; }

.theme-toggle .icon-sun { display: none; }
[data-theme="dark"] .theme-toggle .icon-sun { display: block; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* Search overlay ---------------------------------------------------------- */

.search-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  justify-items: center;
  align-content: start;
  padding: clamp(70px, 14vh, 140px) 20px 40px;
  background: rgba(3, 7, 26, 0.78);
  backdrop-filter: blur(10px);
  animation: fade-in 0.22s ease both;
}
.search-overlay[hidden] { display: none; }
.search-panel { width: min(640px, 100%); }
.search-form {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 6px 10px 6px 22px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: var(--radius-pill);
  color: #fff;
}
.search-form svg { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.8; opacity: 0.75; }
.search-form input {
  flex: 1;
  min-width: 0;
  padding: 14px 0;
  background: none;
  border: 0;
  color: #fff;
  font-size: 16px;
}
.search-form input::placeholder { color: rgba(255, 255, 255, 0.5); }
.search-form input::-webkit-search-cancel-button { display: none; }
.search-form input:focus-visible { outline: none; }
.search-form:focus-within { border-color: rgba(255, 255, 255, 0.55); box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.4); }
.search-close { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; color: #fff; }
.search-close svg { width: 18px; height: 18px; stroke: currentColor; stroke-width: 2; fill: none; }
.search-close:hover { background: rgba(255, 255, 255, 0.14); }

.search-results { margin-top: 18px; display: grid; gap: 8px; }
.search-results a {
  display: grid;
  gap: 2px;
  padding: 14px 22px;
  border-radius: var(--radius);
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: #fff;
  transition: background-color 0.2s ease, transform 0.2s ease;
}
.search-results a:hover,
.search-results a:focus-visible { background: rgba(139, 92, 246, 0.24); transform: translateX(4px); }
.search-results strong { font-family: var(--font-head); font-size: 15px; font-weight: 500; }
.search-results span { font-size: 13px; color: rgba(255, 255, 255, 0.6); }
.search-empty { padding: 14px 22px; font-size: 14px; color: rgba(255, 255, 255, 0.6); }

/* 3. Hero ------------------------------------------------------------------ */

.hero {
  position: relative;
  display: flex;
  align-items: center;
  min-height: clamp(400px, min(38.9vw, 72vh), 900px);
  padding-block: calc(var(--header-h) + 2vw) 4vw;
  overflow: hidden;
  color: #fff;
  background: var(--navy-950);
}
.hero-media { position: absolute; inset: 0; }
.hero-bg-img { width: 100%; height: 100%; object-fit: cover; object-position: 62% center; }
.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(3, 7, 26, 0.88) 0%, rgba(3, 7, 26, 0.6) 45%, rgba(3, 7, 26, 0.12) 75%),
    linear-gradient(0deg, rgba(3, 7, 26, 0.55), transparent 42%);
}
.hero-inner { position: relative; z-index: 1; max-width: var(--container); }
.hero-inner > * { max-width: clamp(320px, 56vw, 1300px); }

.hero-title {
  margin-bottom: clamp(14px, 1.6vw, 30px);
  font-size: var(--fs-display);
  font-weight: 600;
  line-height: 1.18;
  letter-spacing: -0.015em;
  text-shadow: 0 6px 30px rgba(3, 7, 26, 0.55);
}
.hero-tagline {
  margin-bottom: clamp(18px, 2.1vw, 40px);
  font-family: var(--font-head);
  font-size: clamp(15px, 1.8vw, 42px);
  font-weight: 300;
  letter-spacing: 0.16em;
  color: rgba(255, 255, 255, 0.9);
  text-shadow: 0 2px 18px rgba(3, 7, 26, 0.75);
}
.hero-lede {
  margin-bottom: clamp(20px, 2.3vw, 44px);
  /* The mockup's lede sets three lines and ours wrapped to four, which also pushed the hero
     band past the design's 488px. 24vw is the measure that carries "technology," up to line 2
     in our (wider) body face, and the 500px cap makes it top out where --fs-lead does, so the
     measure holds ~22.6em instead of narrowing under the growing type. */
  max-width: clamp(250px, 24vw, 500px);
  font-size: var(--fs-lead);
  line-height: 1.75;
  color: rgba(255, 255, 255, 0.78);
}

/* 4. Home: about + values -------------------------------------------------- */

.about {
  padding-block: var(--section-y);
  background: linear-gradient(180deg, var(--band) 0%, var(--surface) 100%);
}
.about-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.62fr) minmax(0, 1fr);
  gap: clamp(24px, 4.8vw, 100px);
  align-items: center;
}
.about-copy h2 { font-size: clamp(19px, 2.05vw, 42px); line-height: 1.2; }
.about-copy .lead {
  max-width: var(--measure);
  font-size: var(--fs-body);
  line-height: 1.75;
  color: var(--muted);
}

.about-figure {
  --cap-top: clamp(20px, 3.2vw, 46px);
  --cap-fs: clamp(12.5px, 1.2vw, 22px);
  /* The band has to clear two caption lines, and the banner is only ~2.4:1 tall, so its depth
     is derived from the caption's own metrics rather than a share of the box: a percentage band
     faded out above the second line on narrow screens (measured 4.99:1 at a 414x170 box). */
  --cap-flat: calc(var(--cap-top) + var(--cap-fs) * 3.4);
  --cap-fade: calc(var(--cap-fs) * 2.2);
  position: relative;
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
  aspect-ratio: 2.44 / 1;
}
/* Box is 2.44:1, the photo 2.62:1 — anchor right so the glass tower survives the crop. */
.about-figure img { width: 100%; height: 100%; object-fit: cover; object-position: 100% 50%; }
/* The waterfront shot keeps its story in the middle: sun at 50%, skyline 60-90%. */
.about-figure--waterfront img { object-position: 84% 50%; }
/* The caption sits over bright cloud and the sun sits just below it, so darken a top band
   that clears before the horizon instead of scrimming the whole photo. Eased stops keep the
   band edge invisible; measured worst caption line is 7.47:1 across both photos' language,
   page and width combinations, with the sun's own luminance untouched. */
.about-figure::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg,
      rgba(13, 25, 58, 0.74) 0,
      rgba(13, 25, 58, 0.74) var(--cap-flat),
      rgba(13, 25, 58, 0.55) calc(var(--cap-flat) + var(--cap-fade) * 0.45),
      rgba(13, 25, 58, 0.22) calc(var(--cap-flat) + var(--cap-fade) * 0.78),
      rgba(13, 25, 58, 0) calc(var(--cap-flat) + var(--cap-fade)));
}
.about-figure figcaption {
  position: absolute;
  z-index: 1;
  top: var(--cap-top);
  left: var(--cap-top);
  display: grid;
  gap: 2px;
  color: #fff;
  font-family: var(--font-head);
  font-size: var(--cap-fs);
  font-weight: 400;
  line-height: 1.45;
  text-shadow: 0 2px 14px rgba(3, 7, 26, 0.5);
}

.values { padding-block: clamp(28px, 4.4vw, 92px) var(--section-y); }
.values-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* The mockup's four value columns are ~215px set in ~77px gutters at 1254 — the wide
     gutters are most of why its row reads airy where ours read cramped. 96px caps the
     gutter at roughly a fifth of the column so the row stays a row on huge screens. */
  column-gap: clamp(20px, 6.1vw, 96px);
  row-gap: 0;
}
.value-card {
  display: grid;
  /* One parent track per part: the four descriptions then share a baseline even when a
     longer title takes a second line (Poppins is ~15% wider than the mockup's face, so
     EN's "Technology for a Better Future" always does). */
  grid-row: span 3;
  grid-template-rows: subgrid;
  padding: 6px;
}
.value-icon {
  display: grid;
  place-items: center;
  width: clamp(26px, 2.55vw, 50px);
  height: clamp(26px, 2.55vw, 50px);
  margin-bottom: clamp(12px, 1.4vw, 26px);
  color: var(--tint, var(--accent));
}
.value-icon svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.value-card h3 { font-size: var(--fs-h3); font-weight: 600; margin-bottom: clamp(6px, 0.7vw, 14px); }
.value-card p { margin: 0; font-size: var(--fs-body); line-height: 1.75; color: var(--muted); }

/* Two navy bands close the home page. Painting the reach map's band --navy-950 matches the artwork's
   own sky, which measures rgb(1,3,20) to rgb(1,10,34), so its top edge disappears into the band
   instead of showing a seam. Only the stat row sits on the art, over the dark southern-ocean strip;
   the heading stays on plain navy. The partners band below it is theme-aware — see the next rule. */
.reach {
  padding-top: clamp(24px, 2.5vw, 60px);
  padding-bottom: var(--section-y);
  color: #fff;
  background: var(--navy-950);
}

/* Of the two bands that close the home page, the partner orbit is the one that follows the theme
   toggle. Light mode flips it to the site's own --band with navy pills; dark mode keeps the navy
   island it has always had, because --navy-950 is deliberately *not* redefined under
   [data-theme="dark"] — that is why one rule used to paint both themes identically. Two dark-mode
   colours moved by intent, not by accident: the eyebrow/lede alphas (0.72 / 0.76) collapsed onto
   one --band-soft at 0.74, and the eyebrow bar now falls through to `.eyebrow i`'s --muted-light
   instead of pinning 0.45 white, which matches every other section head in this theme.
   Reach stays navy either way, so in light mode the two bands meet at a hard edge: the map is art
   on navy, the orbit is a light band. */
.partners {
  --band-bg: var(--band);
  --band-ink: var(--ink);
  --band-soft: var(--muted);
  --pill-bg: var(--navy-900);
  --pill-ink: #fff;
  --pill-line: rgba(255, 255, 255, 0.16);
  --pill-shadow: var(--shadow-md);
  /* The fetched marks bake --navy-900 ink because they sit inside a pill, so in light mode the
     whole pill inverts and the ink has to be pushed back to white. brightness(0) first so any
     stray non-navy pixel in a mark joins the inversion instead of surviving as a tint. */
  --pill-mark: brightness(0) invert(1);
  --ring: rgba(16, 26, 46, 0.14);
  --dot: rgba(16, 26, 46, 0.34);
  --field-glow: rgba(79, 70, 229, 0.09);
  /* The spiral's ink, deliberately heavier than --ring: that is the plane's background weight, and
     at 0.14 nothing drawn with it reads as a figure. Still decorative, never text. */
  --fib: rgba(16, 26, 46, 0.3);

  padding-top: clamp(24px, 2.5vw, 60px);
  padding-bottom: var(--section-y);
  /* Clips .partners-field, which is deliberately wider than the viewport so its arcs run off the
     edge of the band instead of closing into a visible ellipse. relative is not optional: the flank
     scales position against this section, and overflow alone makes a static element no containing
     block for absolutely positioned children. */
  position: relative;
  overflow: hidden;
  color: var(--band-ink);
  background: var(--band-bg);
}
[data-theme="dark"] .partners {
  --band-bg: var(--navy-950);
  --band-ink: #fff;
  --band-soft: rgba(255, 255, 255, 0.74);
  --pill-bg: #fff;
  --pill-ink: #101a2e;
  --pill-line: rgba(16, 26, 46, 0.12);
  --pill-shadow: 0 12px 30px rgba(3, 7, 26, 0.5);
  --pill-mark: none;
  --ring: rgba(255, 255, 255, 0.1);
  --dot: rgba(255, 255, 255, 0.5);
  --field-glow: rgba(79, 70, 229, 0.22);
  --fib: rgba(255, 255, 255, 0.3);
}
.reach-head,
.partners-head { text-align: center; }
.reach-head .eyebrow,
.partners-head .eyebrow { justify-content: center; }
.reach-head .eyebrow { color: rgba(255, 255, 255, 0.72); }
.partners-head .eyebrow { color: var(--band-soft); }
/* Only reach pins its rule to white; the orbit's eyebrow bar falls through to `.eyebrow i`, whose
   --muted-light already flips with the theme. */
.reach-head .eyebrow i { background: linear-gradient(90deg, rgba(255, 255, 255, 0.45), transparent); }
.reach-head h2,
.partners-head h2 { font-size: clamp(20px, 2.3vw, 48px); line-height: 1.2; }
.reach-lede,
.partners-lede {
  max-width: var(--measure);
  margin: clamp(10px, 1.4vw, 24px) auto 0;
  font-size: var(--fs-lead);
  line-height: 1.75;
}
.reach-lede { color: rgba(255, 255, 255, 0.76); }
.partners-lede { color: var(--band-soft); }
.reach-map { position: relative; margin-top: clamp(22px, 3vw, 60px); }
.reach-map img {
  display: block;
  width: 100%;
  height: auto;
  /* Wide viewports would otherwise run the 2:1 map past a screenful; cropping the near-black
     sky and ocean keeps every continent in frame. */
  max-height: clamp(360px, 62vh, 900px);
  object-fit: cover;
  object-position: 50% 46%;
}
.reach-map::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 9%;
  background: linear-gradient(180deg, var(--navy-950), rgba(3, 7, 26, 0));
  pointer-events: none;
}
.reach-map::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 44%;
  background: linear-gradient(180deg, rgba(3, 7, 26, 0) 0%, rgba(3, 7, 26, 0.62) 52%, rgba(3, 7, 26, 0.92) 100%);
  pointer-events: none;
}
.reach-stats {
  position: absolute;
  /* The scrim is a ::after of .reach-map, i.e. the last box in its originator's tree, so with both
     layers positioned at z-index:auto it paints *over* the dl and buries the numbers at 29/255.
     The markup gives no hint of that — keep the stats one level above every scrim layer. */
  z-index: 1;
  inset: auto 0 clamp(14px, 2.1vw, 44px);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(18px, 4.6vw, 96px);
  padding-inline: var(--gutter);
  margin: 0;
  text-align: center;
}
.reach-stats dt {
  font-family: var(--font-head);
  font-size: clamp(22px, 2.7vw, 58px);
  font-weight: 600;
  line-height: 1.12;
  color: #fff;
}
.reach-stats dd {
  margin: clamp(2px, 0.5vw, 10px) 0 0;
  font-size: var(--fs-meta);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.78);
}

/* Partner orbit: one square stage, two faint tracks, the company mark at the centre and the pills
   revolving on the outer one. Every colour here comes from the band's tokens, so the whole system
   inverts with the theme: white pills on the navy island in dark mode, navy pills with white labels
   on the light band (a light pill on a light band would vanish, and a navy pill on navy reads as a
   hole — each theme gets the opposite treatment for exactly that reason). The brand marks ship
   baked with --navy-900 ink (scratch/fetch-partner-icons.mjs) and invert on the pill, not the band.
   --orbit-n is the pill count: add or remove an <li> and this is the only number to change. */
.partners-stage {
  --stage: clamp(520px, 46vw, 860px);
  --orbit-r: calc(var(--stage) * 0.33);
  --orbit-dur: 42s;
  --orbit-n: 7;
  position: relative;
  width: var(--stage);
  aspect-ratio: 1;
  margin: clamp(26px, 3.6vw, 72px) auto 0;
}

/* The stage is a centred square; the band is full-bleed. Above ~1200px that leaves the orbit
   marooned: 417px of bare band per side at 1545, 850px at 2560. This layer is the same orbital
   plane drawn past the disc — one wide flat ellipse carrying the ring language into the flanks, the
   dashed axis that plane runs along, a violet seat under the centre mass, and four satellites on the
   track so the far ends are not bare hairlines. Static on purpose: the pills own all motion, and a
   second rotating layer would need its own phase in the orbit harness.
   Two numbers are load-bearing, both against --orbit-r (0.33 of the stage):
   - height is 80%, so the ellipse's ry is 0.40 of the stage — clear of the pill circle plus half a
     pill (~0.36). A nested second ellipse would dip *inside* that, and crossing orbits read as error.
   - width is vw, never px, and wider than any screen, so the ellipse's apexes land outside the
     viewport and the arcs run off the edge of the band instead of closing into a visible oval.
   The satellites sit on the ellipse, so their coordinates come from that path directly:
   x = 50% ± 50%·cos θ, y = 50% ± 50%·sin θ, mirrored at θ = ±52°. Both values are percentages of
   this box, so they stay on the curve whatever the box resolves to. */
.partners-field {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 132vw;
  height: 80%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(46% 58% at 50% 50%, var(--field-glow), transparent 74%),
    radial-gradient(circle at 80.8% 89.4%, var(--dot) 0 2.5px, transparent 3px),
    radial-gradient(circle at 80.8% 10.6%, var(--dot) 0 2.5px, transparent 3px),
    radial-gradient(circle at 19.2% 89.4%, var(--dot) 0 2.5px, transparent 3px),
    radial-gradient(circle at 19.2% 10.6%, var(--dot) 0 2.5px, transparent 3px);
}
.partners-field::before,
.partners-field::after {
  content: "";
  position: absolute;
}
.partners-field::before {
  inset: 0;
  border: 1px solid var(--ring);
  border-radius: 50%;
}
/* The axis passes behind the core and the pills, both of which are opaque, so on screen it only
   ever shows out in the flanks — which is where the emptiness is. */
.partners-field::after {
  inset: 50% 0 auto;
  border-top: 1px dashed var(--ring);
}

/* The honeycomb, out in the left flank: 27 rhombi filling a hexagon, drawn as the shared-wall
   lattice rather than filled cells (the construction and the area check are in index.html). It is
   the spiral's mirror partner, and the mirror is exact — same anchor measured from the stage centre
   (0.5 = the stage's own edge, here on the left), same min() width against the flank, same --fib ink,
   same vertical centring. So the two figures are one spread about the disc: change either anchor or
   either width factor and change the other with it, or the pair stops reading as a pair.
   The one asymmetry is intrinsic to the motifs: this viewBox is 7x6.2 against the spiral's 36x23, so
   at equal width the hexagon stands taller — half-height 0.443 of the width against 0.319. It still
   lands inside the plane ellipse's 0.40 of the stage, tightest just above the 1080px hide breakpoint
   where 62px of half-height has 208px to live in. */
.partners-hive {
  position: absolute;
  top: 50%;
  right: calc(50% + var(--stage) * 0.5);
  transform: translateY(-50%);
  width: min(var(--stage) * 0.5, (100vw - var(--stage)) * 0.25);
  height: auto;
  color: var(--fib);
  pointer-events: none;
}

/* One golden spiral, out in the right flank: the Fibonacci tiling's eight squares with the
   quarter-circle arc chain drawn through them, radii 1, 1, 2, 3, 5, 8, 13, 21. This is inline SVG
   rather than background gradients because a spiral is an *arc chain* — every term has to meet the
   next at a shared corner with its tangent already matched, which a path carries exactly (see the
   coordinates and the per-arc check in index.html) and stacked gradient layers cannot express.
   Three numbers hold it inside the flank it lives in, all measured from the stage centre:
   - its left edge lands on 0.5 — the stage's own edge — which puts it 0.064 of the stage clear of
     the orbit's outer edge (~0.436 once a pill's own half-width is counted): 33px at the 520px
     minimum, 45px at a 1545px viewport, 55px at the 860px cap. It used to be 0.46, which pulled it
     4% of the stage inward to meet a partner that has since been rebuilt at 0.5 on the left flank;
     the two now share one anchor across the disc, and 0.5 is what buys the wider gap to the pills.
     It never threads between them.
   - it stops short of the right-hand gauge scale, which stands clamp(28px, 9vw, 190px) in from the
     band's edge, by the same margin it always had — ~28px where the flank is tightest, just above
     the 1080px hide breakpoint, out to ~220px at 2560 — because stepping outward costs width: 0.29
     became 0.25 and the two moves cancel. That gap is not cosmetic: the chain's outermost point
     arrives with a vertical tangent, so were it to reach that vertical rule the two would visually
     fuse rather than cross. Hence min() against the flank, not just against --stage, and the factor
     staying under 0.3 because 100vw counts the scrollbar the content box does not have.
   - its half-height lands under the plane ellipse's 0.40 ry, so it sits inside the envelope that arc
     draws instead of crossing it.
   It inks --fib, not --ring: an earlier version of this figure drawn in --ring was reported as not
   visible at all, and that is what --ring's 0.14 buys. The tiling squares keep their own 0.45 of that
   ink (set in index.html), which puts them back at the plane's weight, so only the spiral reads as a
   figure and its construction lines stay construction lines. */
.partners-spiral {
  position: absolute;
  top: 50%;
  left: calc(50% + var(--stage) * 0.5);
  transform: translateY(-50%);
  width: min(var(--stage) * 0.5, (100vw - var(--stage)) * 0.25);
  height: auto;
  color: var(--fib);
  pointer-events: none;
}

/* The ellipse only dresses the middle of the band, so the corner thirds stay bare. These are the
   gauge scales: a faint spine with ticks pointing inwards at each end of the band, which is the
   other half of the same instrument language the dashed axis already speaks. Pseudo-elements on the
   section itself, because .partners-field has both of its own spent. */
.partners::before,
.partners::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 7px;
  height: 46%;
  transform: translateY(-50%);
  pointer-events: none;
  background-repeat: no-repeat;
  background-image:
    repeating-linear-gradient(180deg, var(--ring) 0 1px, transparent 1px 32px),
    linear-gradient(180deg, var(--ring), var(--ring));
  background-size: 6px 100%, 1px 100%;
  /* The fade has to live in a mask, not in the gradient stops: ticks and spine are two separate
     background layers, so easing the spine alone would leave the tick column running full height
     and ending on a hard cut. One mask fades the whole instrument, so neither end reads as a crop. */
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 26% 74%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 26% 74%, transparent);
}
.partners::before {
  left: clamp(28px, 9vw, 190px);
  background-position: right, left;
}
.partners::after {
  right: clamp(28px, 9vw, 190px);
  background-position: left, right;
}

.orbit-ring {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  border: 1px solid var(--ring);
  border-radius: 50%;
  pointer-events: none;
}
.orbit-ring--outer { width: calc(var(--orbit-r) * 2); height: calc(var(--orbit-r) * 2); border-style: dashed; }
.orbit-ring--inner { width: calc(var(--orbit-r) * 1.3); height: calc(var(--orbit-r) * 1.3); }
.partners-core {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: calc(var(--stage) * 0.15);
  height: auto;
  /* The swirl emblem is bright ink on transparency: it reads on navy and disappears on the light
     band, so it keeps a dark plate in both themes. --navy-900 against today's --navy-950 band is
     a 2/3/5 step, i.e. invisible where it already is; padding rather than a larger box leaves the
     artwork's own transparent margin intact. Absolute units, because --stage still resolves to its
     desktop clamp after the mobile override takes the picture out of the ring. */
  padding: clamp(4px, 0.6vw, 13px);
  border-radius: 50%;
  background: var(--navy-900);
}
.orbit-items { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; }

/* One keyframe with matched function lists — rotate to the bearing, step out to the ring, rotate
   back — so pills travel the circle but never tilt. --i feeds a *negative* delay, which is what
   spreads the pills evenly across one cycle; a positive one would leave the ring empty for the
   first pass. Both the bearing and the delay divide the cycle by --orbit-n rather than hard-coding
   a per-pill angle, so the ring stays gap-free at any count. --a is the same bearing, reused by the
   reduced-motion still. */
.orbit-item {
  position: absolute;
  top: 50%;
  left: 50%;
  --a: calc(var(--i) * 360deg / var(--orbit-n) - 90deg);
  animation: orbit var(--orbit-dur) linear infinite;
  animation-delay: calc(var(--orbit-dur) * var(--i) / var(--orbit-n) * -1);
}
@keyframes orbit {
  from { transform: translate(-50%, -50%) rotate(-90deg) translate(var(--orbit-r)) rotate(90deg); }
  to { transform: translate(-50%, -50%) rotate(270deg) translate(var(--orbit-r)) rotate(-270deg); }
}
.orbit-pill {
  display: inline-flex;
  align-items: center;
  gap: clamp(5px, 0.55vw, 10px);
  padding: clamp(7px, 0.75vw, 15px) clamp(11px, 1.2vw, 24px);
  border: 1px solid var(--pill-line);
  border-radius: var(--radius-pill);
  background: var(--pill-bg);
  box-shadow: var(--pill-shadow);
  font-family: var(--font-head);
  font-size: var(--fs-body);
  font-weight: 500;
  white-space: nowrap;
  color: var(--pill-ink);
}
.orbit-pill img { width: clamp(16px, 1.3vw, 26px); height: auto; filter: var(--pill-mark); }

/* Hovering the ring holds the whole system still. Pausing rather than clearing the animation is
   deliberate: every pill keeps its exact bearing and resumes in place instead of jumping. */
.partners-stage:hover .orbit-item { animation-play-state: paused; }

/* 5. Sub-page components --------------------------------------------------- */

.page-hero {
  position: relative;
  padding-block: calc(var(--header-h) + clamp(48px, 8vw, 92px)) clamp(48px, 7vw, 84px);
  color: #fff;
  background: var(--navy-950);
  overflow: hidden;
}
.page-hero .hero-bg-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.75; }
.page-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(3, 7, 26, 0.72), rgba(3, 7, 26, 0.9));
}
.page-hero .container { position: relative; z-index: 1; }
.page-hero h1 { font-size: clamp(26px, 3.2vw, 66px); margin-bottom: clamp(8px, 1vw, 20px); line-height: 1.18; }
.page-hero p { max-width: var(--measure); color: rgba(255, 255, 255, 0.76); font-size: var(--fs-lead); line-height: 1.75; }
.breadcrumb {
  display: flex;
  gap: 10px;
  margin-bottom: clamp(12px, 1.5vw, 28px);
  font-size: var(--fs-meta);
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.55);
}
.breadcrumb a:hover { color: #fff; }

.section { padding-block: var(--section-y); }
.section--tinted { background: var(--band); }
.section-head { max-width: var(--measure); margin-bottom: clamp(22px, 3.6vw, 72px); }
.section-head h2 { font-size: clamp(20px, 2.3vw, 48px); line-height: 1.2; }
.section-head p { color: var(--muted); font-size: var(--fs-lead); line-height: 1.75; }

.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 4.8vw, 100px);
  align-items: center;
}
.split p, .timeline p { max-width: var(--measure); }

.stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 18px;
  margin-top: clamp(28px, 4vw, 44px);
}
.stat {
  padding: 26px 22px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.stat b {
  display: block;
  font-family: var(--font-head);
  font-size: clamp(24px, 2.4vw, 52px);
  font-weight: 600;
  line-height: 1.1;
  background: var(--grad-text);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.stat span { font-size: var(--fs-meta); color: var(--muted); }

.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(255px, 1fr));
  gap: clamp(18px, 2.4vw, 44px);
}
.panel {
  position: relative;
  padding: clamp(22px, 2.6vw, 56px) clamp(20px, 2.4vw, 52px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: transform 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
}
.panel:hover { transform: translateY(-6px); box-shadow: var(--shadow-md); border-color: rgba(139, 92, 246, 0.4); }
.panel h3 { font-size: var(--fs-h3); margin-bottom: clamp(6px, 0.8vw, 14px); }
.panel p { margin: 0; font-size: var(--fs-body); line-height: 1.75; color: var(--muted); }
.panel .value-icon { width: clamp(28px, 2.9vw, 56px); height: clamp(28px, 2.9vw, 56px); margin-bottom: clamp(12px, 1.4vw, 26px); color: var(--tint, var(--accent)); }
/* Store badges reuse the chip look but are labels, not controls. */
.panel .chips { margin: 18px 0 0; }
.panel .chip { padding: 6px 14px; font-size: 12px; }
.panel .chip:hover { border-color: var(--line); color: var(--ink-soft); }
.panel-tag {
  display: inline-block;
  margin-bottom: 14px;
  padding: 4px 12px;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--ink-soft);
  font-family: var(--font-head);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* The review ticker: six cards walking left to right, forever. The track carries two identical sets
   and travels exactly -50%, and that is seamless only because each card supplies its own trailing
   margin — a flex gap would leave the seam between the two sets one gap wider than the distance the
   keyframe returns to, and every pass would hitch by that fraction of a card. The second set is
   aria-hidden in the markup, so the six reviews are announced once, not twice. */
.reviews-rail {
  --reviews-gap: clamp(16px, 1.7vw, 30px);
  overflow: hidden;
  padding-block: clamp(8px, 1vw, 18px);
  /* The rail runs full-bleed under a centred heading, so the fade is the only cue that the cards
     continue past the column rather than stopping at its edge. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 7%, #000 93%, transparent);
}
.reviews-track {
  display: flex;
  width: max-content;
  animation: reviews-drift 72s linear infinite;
}
.review-set { display: flex; }
@keyframes reviews-drift {
  from { transform: translateX(-50%); }
  to { transform: translateX(0); }
}
/* Reading a card that is moving is the one thing a ticker should get out of the way of, so both the
   pointer and the keyboard hold it — the same bargain the orbit makes on hover. */
.reviews-rail:hover .reviews-track,
.reviews-rail:focus-within .reviews-track { animation-play-state: paused; }
.review-card {
  flex: 0 0 clamp(268px, 27vw, 392px);
  margin: 0 var(--reviews-gap) 0 0;
  padding: clamp(20px, 2vw, 34px) clamp(19px, 1.9vw, 32px);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
/* Zoom on hover. Transform only, so the card keeps the box the -50% seam was measured against and the
   loop stays exact. 1.045 is the budget: sideways it is guaranteed, because the growth on each side is
   2.25% of a 27vw card (0.61vw) against a 1.7vw gap at every width where both clamps are still linear.
   Vertically it depends on content: these cards stand ~250px, so ~3px per side sits inside the rail's
   padding-block — a much longer quote would eat that padding and start to clip at top and bottom.
   z-index puts the grown card above the siblings that follow it in the track; flex items honour z-index
   without a position. */
.review-card:hover {
  transform: scale(1.045);
  box-shadow: var(--shadow-md);
  z-index: 1;
}
.review-who { display: flex; align-items: center; gap: clamp(9px, 0.9vw, 14px); }
.review-avatar {
  position: relative;
  isolation: isolate;
  display: grid;
  place-items: center;
  width: clamp(36px, 3.2vw, 46px);
  aspect-ratio: 1;
  border: 1px solid var(--tint);
  border-radius: 50%;
  color: var(--ink);
  font-family: var(--font-head);
  font-size: clamp(13px, 1.2vw, 17px);
  font-weight: 600;
  line-height: 1;
}
/* The tint goes on the disc and its ring, never on the initial: pale cyan or violet glyphs on
   --card are exactly the pair that would fall under the site's contrast floor, and the letter is the
   part anyone has to read. The ring is a border on the avatar rather than a shadow on this fill,
   because opacity below would fade it with the fill — and on white a 16% tint alone leaves the disc
   with no edge at all. Swap this whole span for an <img> and nothing else needs to move. */
.review-avatar::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--tint);
  opacity: 0.16;
}
.review-id { display: grid; gap: 2px; }
.review-name { font-family: var(--font-head); font-weight: 600; font-size: var(--fs-body); color: var(--ink); }
.review-product { font-size: var(--fs-meta); letter-spacing: 0.04em; color: var(--muted); }
.review-stars {
  display: flex;
  align-items: center;
  gap: clamp(2px, 0.3vw, 4px);
  margin: clamp(12px, 1.2vw, 18px) 0 clamp(10px, 1vw, 15px);
  color: var(--star);
}
.review-stars svg { width: clamp(12px, 1.05vw, 16px); height: clamp(12px, 1.05vw, 16px); fill: currentColor; }
.review-text { margin: 0; font-size: var(--fs-body); line-height: 1.72; color: var(--muted); }
/* Holds the #gv-star symbol the sixty <use> elements draw from; display:none still resolves them. */
.review-defs { display: none; }

.feature-banner {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: clamp(280px, 34vw, 420px);
  border-radius: var(--radius-lg);
  overflow: hidden;
  color: #fff;
  box-shadow: var(--shadow-glow);
}
.feature-banner img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.feature-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(14deg, rgba(3, 7, 26, 0.94) 10%, rgba(3, 7, 26, 0.5) 52%, rgba(3, 7, 26, 0.05) 82%);
}
.feature-banner .feature-banner-text {
  position: relative;
  z-index: 1;
  max-width: 52ch;
  padding: clamp(26px, 4vw, 48px);
}
.feature-banner h2 { font-size: clamp(19px, 2.3vw, 46px); margin-bottom: clamp(6px, 0.8vw, 14px); line-height: 1.2; }
.feature-banner p { margin: 0; font-size: var(--fs-body); line-height: 1.75; color: rgba(255, 255, 255, 0.8); }

.timeline { display: grid; gap: 0; border-left: 2px solid var(--line); padding-left: clamp(20px, 2.3vw, 44px); }
.timeline li { position: relative; padding-bottom: clamp(20px, 2.4vw, 46px); }
.timeline li::before {
  content: "";
  position: absolute;
  left: calc(-1 * clamp(20px, 2.3vw, 44px) - 7px); top: 8px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--grad);
  box-shadow: 0 0 0 4px var(--surface);
}
.timeline b { display: block; font-family: var(--font-head); font-size: var(--fs-h3); color: var(--accent-text); }
.timeline p { margin: 4px 0 0; font-size: var(--fs-body); line-height: 1.75; color: var(--muted); }

.news-list { display: grid; gap: 16px; }
.news-item {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr) auto;
  gap: clamp(16px, 3vw, 32px);
  align-items: center;
  padding: 24px 28px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}
.news-item:hover { transform: translateX(6px); box-shadow: var(--shadow-sm); }
.news-date {
  display: grid;
  place-content: center;
  padding: 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  text-align: center;
  font-family: var(--font-head);
}
.news-date b { font-size: 24px; line-height: 1; color: var(--ink); }
.news-date span { font-size: 12px; color: var(--muted); }
.news-item h3 { font-size: 17px; margin-bottom: 6px; }
.news-item p { margin: 0; font-size: 13.5px; color: var(--muted); }
.news-item .chev { width: 20px; height: 20px; stroke: var(--muted-light); stroke-width: 2; fill: none; }

.chips { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 28px; }
.chip {
  padding: 8px 18px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--line);
  background: var(--card);
  font-family: var(--font-head);
  font-size: 13px;
  color: var(--ink-soft);
  transition: all 0.2s ease;
}
.chip:hover { border-color: var(--accent-2); color: var(--accent-text); }
.chip[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: #fff; }
[data-theme="dark"] .chip[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 18px 20px;
}
.field { display: grid; gap: 8px; }
.field--full { grid-column: 1 / -1; }
.field label { font-family: var(--font-head); font-size: 13px; font-weight: 500; color: var(--ink-soft); }
.field input,
.field textarea,
.field select {
  width: 100%;
  padding: 13px 16px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14.5px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.field textarea { min-height: 132px; resize: vertical; }
.field input:focus,
.field textarea:focus,
.field select:focus { outline: none; border-color: var(--accent-2); box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.16); }
.field .error { font-size: 12.5px; color: var(--danger); min-height: 0; }
.field[data-invalid="true"] input,
.field[data-invalid="true"] textarea { border-color: var(--danger); }
.form-status { margin-top: 16px; font-size: 14px; color: var(--accent-text); min-height: 22px; }

.info-card {
  padding: clamp(26px, 4vw, 40px);
  background: var(--navy-900);
  color: #fff;
  border-radius: var(--radius-lg);
  overflow: hidden;
  position: relative;
}
.info-card h2 { font-size: 22px; }
.info-list { display: grid; gap: 20px; margin-top: 26px; }
.info-list li { display: grid; grid-template-columns: 34px minmax(0, 1fr); gap: 14px; align-items: start; font-size: 14px; }
.info-list svg { width: 20px; height: 20px; fill: none; stroke: var(--accent-3); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; margin-top: 3px; }
.info-list b { display: block; font-family: var(--font-head); font-size: 13px; font-weight: 500; color: rgba(255, 255, 255, 0.55); letter-spacing: 0.06em; text-transform: uppercase; }

/* Document pages: terms, privacy and the placeholder pages under Technologies and Resources. These
   are documents, not feature grids: one readable measure of prose, hairlines between parts instead of
   cards, and no display type — the section heading is the only weight step. The "legal-" prefix is the
   name these four classes had when only the two legal pages used them. */

/* Legal page layout: TOC sidebar on the right, content on the left */
.section:has(.legal-toc) .container {
  display: grid;
  grid-template-columns: 1fr minmax(220px, 280px);
  gap: clamp(24px, 3vw, 48px);
  align-items: start;
}

.section:has(.legal-toc) .legal-toc {
  position: sticky;
  top: clamp(20px, 3vh, 40px);
  max-height: calc(100vh - clamp(40px, 6vh, 80px));
  overflow-y: auto;
  margin: 0;
  padding: clamp(16px, 1.8vw, 28px);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  order: 2;
}

.section:has(.legal-toc) .legal-body {
  order: 1;
}

.legal-toc h2 {
  font-size: clamp(13px, 1.1vw, 18px);
  margin-bottom: clamp(10px, 1.3vw, 20px);
  color: var(--ink);
}
.legal-toc ol {
  margin: 0;
  padding-left: 1.5em;
  list-style: disc;
}
.legal-toc li {
  margin-bottom: clamp(5px, 0.7vw, 10px);
  line-height: 1.5;
  font-size: clamp(12px, 0.95vw, 16px);
}
.legal-toc a {
  color: var(--ink-soft);
  text-decoration: none;
  transition: color 0.2s ease;
}
.legal-toc a:hover {
  color: var(--accent);
  text-decoration: underline;
}

/* Responsive: stack TOC below content on smaller screens */
@media (max-width: 900px) {
  .section:has(.legal-toc) .container {
    grid-template-columns: 1fr;
  }
  .section:has(.legal-toc) .legal-toc {
    position: static;
    max-height: none;
    order: 0;
    margin-bottom: clamp(26px, 3vw, 48px);
  }
  .section:has(.legal-toc) .legal-body {
    order: 0;
  }
}

/* FAQ accordion styles */
.faq-item {
  border-bottom: 1px solid var(--line);
  border-top: 0 !important;
  padding: 0;
}
.faq-item:first-child {
  border-top: 0 !important;
  padding-top: 0 !important;
}
.faq-question {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: clamp(12px, 1.4vw, 18px) 0;
  margin: 0;
  cursor: pointer;
  user-select: none;
  font-size: clamp(16px, 1.3vw, 22px);
  font-weight: 500;
  color: var(--ink);
  transition: color 0.2s ease;
}
.faq-question:hover {
  color: var(--accent);
}
.faq-icon {
  font-size: clamp(18px, 1.5vw, 24px);
  font-weight: 300;
  color: var(--muted);
  transition: transform 0.2s ease;
  flex-shrink: 0;
  margin-left: 16px;
}
.faq-answer {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease, padding 0.3s ease;
}
.faq-answer p {
  margin: 0;
  padding-bottom: clamp(12px, 1.4vw, 18px);
  color: var(--ink-soft);
  font-size: var(--fs-body);
  line-height: 1.7;
}
.faq-item.is-open .faq-answer {
  max-height: 500px;
}
.faq-item.is-open .faq-icon {
  transform: rotate(0deg);
}
.faq-item:not(.is-open) .faq-icon {
  transform: rotate(0deg);
}
.page-hero .legal-meta {
  max-width: none;
  margin-top: clamp(6px, 0.7vw, 14px);
  font-size: var(--fs-meta);
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.55);
}
/* The amber is --star, already tuned per theme: a notice has to read as caution in both, and this
   is the only place outside the review band that uses it. */
.legal-notice {
  max-width: var(--measure);
  margin: 0 0 clamp(26px, 3vw, 48px);
  padding: clamp(14px, 1.5vw, 22px) clamp(16px, 1.7vw, 26px);
  border: 1px solid var(--line);
  border-left: 3px solid var(--star);
  border-radius: var(--radius-sm);
  background: var(--card);
  color: var(--muted);
  font-size: var(--fs-meta);
  line-height: 1.7;
}
.legal-body { width: 100%; max-width: 900px; margin: 0 auto; display: block; }
.legal-body > * + * { margin-top: clamp(22px, 2.6vw, 42px); }
.legal-part { padding-top: clamp(22px, 2.6vw, 42px); border-top: 1px solid var(--line); }
.legal-part:first-child { padding-top: 0; border-top: 0; }
.legal-part h2 { font-size: clamp(17px, 1.45vw, 28px); margin-bottom: clamp(8px, 0.9vw, 16px); }
.legal-part p { margin: 0; color: var(--muted); font-size: var(--fs-body); line-height: 1.85; }

/* Activities page - dark theme design -------------------------------------- */

/* Activities grid */
.activities-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: clamp(20px, 2.4vw, 32px);
  margin-top: clamp(24px, 3vw, 40px);
}

/* Activity card */
.activity-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
}
.activity-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12);
  border-color: var(--accent);
}
.activity-card-media {
  position: relative;
  height: 200px;
  overflow: hidden;
  background: linear-gradient(135deg, #1a2d5a 0%, #2d4a8a 100%);
}
.activity-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}
.activity-card:hover .activity-card-media img {
  transform: scale(1.05);
}
.activity-card-category {
  position: absolute;
  top: 12px;
  left: 12px;
  padding: 4px 12px;
  background: rgba(5, 11, 31, 0.85);
  backdrop-filter: blur(8px);
  border-radius: var(--radius-pill);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-3);
}
.activity-card-body {
  padding: clamp(18px, 2vw, 24px);
}
.activity-card-title {
  font-size: clamp(16px, 1.4vw, 20px);
  font-weight: 600;
  color: var(--ink);
  margin-bottom: clamp(10px, 1.2vw, 16px);
  line-height: 1.35;
}
.activity-card-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: clamp(10px, 1.2vw, 16px);
  font-size: 13px;
  color: var(--muted);
}
.activity-card-meta svg {
  width: 16px;
  height: 16px;
  stroke: var(--muted);
}
.activity-card-desc {
  font-size: var(--fs-body);
  color: var(--muted);
  line-height: 1.65;
  margin-bottom: clamp(14px, 1.6vw, 20px);
}
.activity-card-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
  transition: color 0.2s ease, gap 0.2s ease;
}
.activity-card-link:hover {
  color: var(--accent-hover);
  gap: 10px;
}

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

/* 6. Footer ---------------------------------------------------------------- */

.site-footer {
  position: relative;
  padding-block: clamp(24px, 2.2vw, 60px) clamp(26px, 3vw, 60px);
  background: var(--navy-900);
  color: rgba(255, 255, 255, 0.78);
  overflow: hidden;
}
.site-footer::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 88% 100%, rgba(79, 70, 229, 0.1), transparent 60%);
  pointer-events: none;
}
.footer-media {
  position: absolute;
  inset: 0;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 46%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 46%);
}
.footer-media img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 100%;
  /* The shortened mockup footer moved the legal row up over the fully revealed planet limb,
     where 0.30 dropped it to 4.42:1. Swept 390-2560px: 0.28 together with the 0.68 alpha on
     .footer-legal / .site-footer .brand-sub holds every footer string at >=5.2:1. */
  opacity: 0.28;
}
.footer-grid {
  position: relative;
  z-index: 1;
  display: grid;
  /* Brand plus four link columns: the columns take max-content tracks, the brand takes all the rest.
     An fr track always fills its share of the line, so sizing the columns in fr left the last one
     ending short of the container's right edge while the brand started exactly on the left edge.
     Hugged to their widest string — the heading, or a two-word label such as "Terms of Service" —
     the four columns finish flush against the right content edge, and because .container applies
     padding-inline: var(--gutter) on both sides, that inset then equals the left one. max-content is
     also the safe floor, not just the tight one: it is the width the longest label occupies without
     wrapping, so no column can spill into its neighbour. The brand track keeps minmax(0,…) because the
     tagline and the wrapping .social-list chips inside it are meant to reflow. */
  grid-template-columns: minmax(0, 1fr) repeat(4, max-content);
  /* Rows keep the original gap; columns take a wider one. Now that the tracks hug their content, the
     column gap is the entire distance between categories — under the old fr columns part of the
     breathing room was unused slack inside each track, and hugging that away made the four groups
     read as one dense block. */
  row-gap: clamp(24px, 4.8vw, 100px);
  column-gap: clamp(40px, 6.5vw, 175px);
  align-items: start;
}
/* 0.62 measured 4.42:1 over the art limb; 0.68 still reads as secondary under the 0.78 body. */
.site-footer .brand-sub { max-width: 24ch; color: rgba(255, 255, 255, 0.68); }
.footer-tagline {
  margin: clamp(16px, 2vw, 38px) 0 0;
  font-family: var(--font-head);
  font-size: var(--fs-lead);
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.86);
}
.footer-social { margin-top: clamp(18px, 2.2vw, 42px); }
/* Fluid chips, like the rest of the footer: fixed px would stop tracking --fs-body on 2560. */
.social-list { display: flex; flex-wrap: wrap; gap: clamp(8px, 0.8vw, 13px); }
.social-list a {
  display: grid;
  place-items: center;
  width: clamp(36px, 2.75vw, 52px);
  height: clamp(36px, 2.75vw, 52px);
  border: 1px solid var(--line-dark);
  border-radius: clamp(10px, 0.85vw, 15px);
  background: rgba(4, 10, 26, 0.3);
  transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
}
.social-list a:hover { transform: translateY(-2px); border-color: rgba(34, 211, 238, 0.6); background: rgba(79, 70, 229, 0.3); }
.social-list img { width: clamp(18px, 1.4vw, 26px); height: clamp(18px, 1.4vw, 26px); }
.footer-col h3, .footer-social h3 {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: clamp(12px, 1.7vw, 32px);
  font-family: var(--font-head);
  font-size: clamp(13px, 1.28vw, 26px);
  font-weight: 500;
  color: #fff;
}
.footer-col h3 svg, .footer-social h3 svg { width: 18px; height: 18px; fill: none; stroke: var(--accent-3); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }

/* The four link columns are plain stacked links. No icon track: the row is the label itself, and a
   20px column would only push the text out from under the heading that sits above it. The colour
   inherits rgba(255,255,255,0.78) from .site-footer through the global a { color: inherit } — the
   footer body value already measured against the art limb. */
.link-list { display: grid; gap: clamp(5px, 0.75vw, 14px); font-size: var(--fs-body); line-height: 1.75; }
.link-list a:hover { color: #fff; text-decoration: underline; text-underline-offset: 3px; }

.footer-legal {
  /* A full-width row of the grid now rather than the tail of the last column, so it lands bottom-left
     under the brand the way the reference footer does. The 32px indent it used to carry existed only
     to line this text up with the old scope rows' icon track. */
  grid-column: 1 / -1;
  margin: clamp(18px, 2.4vw, 46px) 0 0;
  display: grid;
  gap: 2px;
  font-size: var(--fs-meta);
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.68);
}

/* 7. Motion ---------------------------------------------------------------- */

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

/* The offset is `translate`, not `transform`, on purpose: an element that reveals and also has its own
   hover transform (.panel lifts, .review-card zooms) would otherwise lose the hover — [data-reveal].is-visible
   and .panel:hover tie at two class-level selectors, so whichever rule sits later in the file wins, and the
   reveal rule is later. The two properties compose instead, and the entrance looks exactly as it did. */
[data-reveal] {
  opacity: 0;
  translate: 0 22px;
  transition: opacity 0.7s ease, translate 0.7s cubic-bezier(0.16, 1, 0.3, 1);
}
[data-reveal].is-visible { opacity: 1; translate: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
  [data-reveal] { opacity: 1; translate: none; }
  /* The 0.001ms duration above would leave the orbit at an arbitrary phase that changes every
     frame. Freeze it into a static ring using --a, the same bearing the keyframe would show. */
  .orbit-item {
    animation: none;
    transform: translate(-50%, -50%) rotate(var(--a)) translate(var(--orbit-r)) rotate(calc(var(--a) * -1));
  }
  /* The ticker is the other animation that cannot simply be frozen: at 0.001ms it would tear through
     its whole loop in under a frame, and a stopped marquee is meaningless anyway — half the track is a
     duplicate held off-screen for the seam. So rebuild it as a plain wrapping grid, delete the
     duplicate set, and drop the mask that used to fade the cards cut off at each rail edge. */
  .reviews-rail {
    -webkit-mask-image: none;
    mask-image: none;
  }
  .reviews-track { animation: none; display: grid; width: auto; }
  .review-set {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(268px, 100%), 1fr));
    gap: var(--reviews-gap);
  }
  .review-set[aria-hidden="true"] { display: none; }
  /* No motion to get out of the way of, so the zoom that pays for the pause goes too — and in this
     rebuild the cards fill their tracks edge to edge, so a scaled card at either end of a row would
     simply be cut by the rail's overflow:hidden. */
  .review-card { margin: 0; }
  .review-card:hover { transform: none; }
}

/* 8. Responsive ------------------------------------------------------------ */

@media (max-width: 1080px) {
  .values-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 36px; }
  /* Two columns are wide enough that no title wraps, and the card's three spanned tracks
     would swallow this 36px row-gap inside each card instead of between card rows. */
  .value-card { display: block; grid-row: auto; }
  .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Five children now, so the brand takes the whole first row instead of leaving one link column
     stranded beside it; the four columns then fall into a clean two-by-two block underneath. */
  .footer-brand { grid-column: 1 / -1; }

  /* A 520px ring is the smallest one seven nowrap pills can share without touching (51° apart at
     0.33 × 520), so below that they flatten into a grid under the mark instead of orbiting.
     transform:none matters here: the reduced-motion still above would otherwise apply an orbit
     offset to grid items. */
  .partners-stage { width: auto; aspect-ratio: auto; }
  /* The whole decoration set goes with the ring. .partners-field, .partners-hive and
     .partners-spiral dress the flanks, and the ::before/::after scales stand clamp(28px, 9vw, 190px)
     in from each edge — below this width the stage spreads to the container and there are no flanks
     left to dress, so all five would land under the flattened pill grid rather than in the empty
     space they exist to fill. */
  .orbit-ring,
  .partners-field,
  .partners-hive,
  .partners-spiral,
  .partners::before,
  .partners::after { display: none; }
  .partners-core {
    position: static;
    transform: none;
    display: block;
    width: clamp(48px, 7.5vw, 60px);
    margin: 0 auto clamp(18px, 4vw, 32px);
  }
  .orbit-items {
    position: static;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(140px, 100%), 1fr));
    gap: clamp(8px, 1.5vw, 12px);
    max-width: 560px;
    margin-inline: auto;
  }
  .orbit-item { position: static; animation: none; transform: none; }
  .orbit-pill { width: 100%; justify-content: center; }
}

@media (max-width: 900px) {
  :root { --header-h: 70px; }

  .nav-toggle { display: grid; }
  .brand { margin-right: auto; }

  .main-nav {
    position: fixed;
    inset: var(--header-h) 0 auto;
    padding: 8px var(--gutter) 26px;
    background: rgba(5, 11, 31, 0.97);
    backdrop-filter: blur(14px);
    border-top: 1px solid var(--line-dark);
    transform: translateY(-105%);
    visibility: hidden;
    transition: transform 0.32s cubic-bezier(0.16, 1, 0.3, 1), visibility 0.32s;
  }
  .main-nav.is-open { transform: none; visibility: visible; }
  .main-nav > ul { flex-direction: column; align-items: stretch; gap: 0; }
  .main-nav li { border-bottom: 1px solid rgba(255, 255, 255, 0.08); }
  .main-nav a { padding: 15px 4px; font-size: 16px; }
  .main-nav a::after { display: none; }
  .main-nav .lang-switch--mobile { display: flex; padding-top: 18px; font-size: 15px; }

  .about-grid, .split { grid-template-columns: minmax(0, 1fr); }
  .about-figure { order: -1; aspect-ratio: 16 / 10; }
  .stat-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .hero { padding-block: calc(var(--header-h) + 34px) 48px; }
}

@media (max-width: 640px) {
  .header-tools .lang-switch { display: none; }
  .values-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 20px; column-gap: 12px; }
  .value-card { display: block; grid-row: auto; }
  .footer-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    row-gap: 18px;
    column-gap: 16px;
  }
  /* Brand row spans full width */
  .footer-brand {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
  }
  .footer-brand .brand { flex: 1 1 auto; min-width: 180px; }
  .site-footer .brand-sub { max-width: none; }
  .footer-tagline {
    order: 3;
    width: 100%;
    margin-top: 2px;
    font-size: 13px;
  }
  .footer-social {
    margin-top: 0;
    flex: 0 0 auto;
  }
  .footer-social h3 { display: none; }
  .social-list { gap: 6px; }
  .social-list a { width: 34px; height: 34px; }
  .footer-col h3 { margin-bottom: 8px; font-size: 13px; }
  .link-list { gap: 5px; font-size: 14px; }
  /* Legal spans full width at bottom */
  .footer-legal {
    grid-column: 1 / -1;
    margin-top: 10px;
    font-size: 12px;
  }
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .news-item { grid-template-columns: minmax(0, 1fr); }
  .news-item .chev { display: none; }
  .news-date { justify-items: start; }
  .footer-media img { object-position: 62% 100%; }
  /* Too little map left to overlay: the stat row reads better under it, on the band's own navy. */
  .reach-map::after { display: none; }
  .reach-stats { position: static; margin-top: clamp(20px, 6vw, 40px); }
}

/* Wide screens need no tier: --container, --gutter, --section-y and the --fs-* clamps are
   all viewport fractions measured off the mockup, so the page grows as one continuous scale.
   The previous ≥1500px / ≥2400px blocks re-pinned those tokens to the old fixed 1140px column
   and stepped the type, which fought the fluid base and made the layout jump at both edges. */
