/* Self-hosted so the two families are not a third-party, render-blocking
   request chain on every page. Faces lifted verbatim from the Google
   Fonts css2 response, with the woff2 files alongside in assets/fonts. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url('../fonts/k3kQo8UDI-1M0wlSfdboLnnA.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url('../fonts/k3kQo8UDI-1M0wlSfdfoLnnA.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: 'Archivo';
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url('../fonts/k3kQo8UDI-1M0wlSfdnoLg.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: 'Newsreader';
  font-style: italic;
  font-weight: 300 500;
  font-display: swap;
  src: url('../fonts/cY9CfjOCX1hbuyalUrK439vCgYhCFpY.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 300 500;
  font-display: swap;
  src: url('../fonts/cY9CfjOCX1hbuyalUrK439vCgIhCFpY.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: 'Newsreader';
  font-style: italic;
  font-weight: 300 500;
  font-display: swap;
  src: url('../fonts/cY9CfjOCX1hbuyalUrK439vCjohC.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;
}

/* ============================================================
   Genly design system
   Brand palette is fixed by the design brief. The *-ink tokens
   are darkened variants used wherever the colour carries text on
   a light ground, because the brand values themselves fall under
   4.5:1 there (gold is 1.93:1 on white). Fills, rules and UI keep
   the exact brand values.
   ============================================================ */

:root {
  /* Brand — exact values from the brief */
  --navy:      #062B59;
  --ocean:     #1685C1;
  --teal:      #16A897;
  --gold:      #F2AE2E;
  --gray:      #F2F4F7;
  --white:     #FFFFFF;

  /* Text-safe variants */
  --ocean-ink: #1375AA;  /* 4.59:1 on --gray */
  --teal-ink:  #107D70;  /* 4.55:1 on --gray */
  --gold-ink:  #976609;  /* 4.52:1 on --gray */
  --ocean-lift:#1A9BE1;  /* 4.55:1 on --navy */

  /* Surfaces + text roles */
  --ink:        var(--navy);
  --ink-muted:  #4A6485;
  --ink-onnavy: #C7D6E8;
  --rule:       #D8DFE9;
  --rule-navy:  #1B4478;

  /* Type */
  --font: "Archivo", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-quote: "Newsreader", Georgia, "Times New Roman", serif;

  --t-xs:   0.8125rem;
  --t-sm:   0.9375rem;
  --t-base: 1.0625rem;
  --t-md:   1.1875rem;
  --t-lg:   1.5rem;
  --t-xl:   clamp(1.75rem, 2.4vw, 2.25rem);
  --t-2xl:  clamp(2.125rem, 4vw, 3.25rem);
  --t-3xl:  clamp(2.75rem, 6vw, 5rem);

  /* Space — 4px base */
  --s2: 0.5rem;   --s3: 0.75rem;  --s4: 1rem;
  --s5: 1.5rem;   --s6: 2rem;     --s7: 3rem;     --s8: 4rem;
  --s9: 6rem;     --s10: 8rem;

  --measure: 52ch;
  --page: 1280px;
  --gutter: clamp(1.25rem, 5vw, 4.5rem);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--t-base);
  line-height: 1.6;
  color: var(--ink);
  background: var(--white);
  font-variation-settings: "wdth" 100;
  -webkit-font-smoothing: antialiased;
}
img, svg { max-width: 100%; height: auto; display: block; }
a { color: var(--ocean-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.08; letter-spacing: -0.02em; }
p { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; }

:focus-visible {
  outline: 3px solid var(--ocean);
  outline-offset: 3px;
  border-radius: 2px;
}
.on-navy :focus-visible { outline-color: var(--gold); }

.skip {
  position: absolute; left: var(--s4); top: -4rem; z-index: 100;
  background: var(--gold); color: var(--navy);
  padding: var(--s3) var(--s5); font-weight: 600; border-radius: 3px;
  transition: top 0.15s var(--ease);
}
.skip:focus { top: var(--s4); }

/* ---------- layout ---------- */
.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.section { padding-block: clamp(4rem, 9vw, 8rem); position: relative; }
.section--tight { padding-block: clamp(3rem, 6vw, 5rem); }
.section--navy { background: var(--navy); color: var(--white); }
.section--gray { background: var(--gray); }

.measure { max-width: var(--measure); }
.lede { font-size: var(--t-md); line-height: 1.55; color: var(--ink-muted); }
.section--navy .lede { color: var(--ink-onnavy); }

/* Display headings use Archivo's width axis — wider as they get larger.
   This is the one place the family is allowed to shout. */
.h-display {
  font-size: var(--t-3xl);
  font-weight: 600;
  font-variation-settings: "wdth" 112;
  letter-spacing: -0.035em;
  line-height: 0.95;
}
.h-section {
  font-size: var(--t-2xl);
  font-weight: 600;
  font-variation-settings: "wdth" 108;
  letter-spacing: -0.03em;
  line-height: 1.02;
  max-width: 20ch;
}
.h-sub { font-size: var(--t-xl); font-weight: 600; font-variation-settings: "wdth" 104; }
.h-card { font-size: var(--t-lg); font-weight: 600; line-height: 1.15; }

/* Justine, 2026-09-08: no single word left dangling on its own line.
   `balance` evens the lines of a heading; `pretty` pulls a widow up out of
   the last line of a paragraph. Both are ignored where unsupported, so the
   fallback is ordinary wrapping, never a broken layout. */
h1, h2, h3, h4, h5, h6,
.h-display, .h-section, .h-sub, .h-card, .lede, .stat__num, .step__n {
  text-wrap: balance;
}
p, li, dd, figcaption, blockquote, summary { text-wrap: pretty; }

/* Small labels stay sentence case; the brief's palette carries the
   signal instead of tracked-out capitals. */
.label {
  font-size: var(--t-sm);
  font-weight: 500;
  color: var(--ocean-ink);
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s5);
}
.label::before {
  content: "";
  width: 22px; height: 2px;
  background: var(--gold);
  flex: none;
}
.section--navy .label { color: var(--gold); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.9rem 1.6rem;
  font-size: var(--t-base); font-weight: 600;
  border: 2px solid transparent; border-radius: 2px;
  cursor: pointer; text-decoration: none;
  transition: background-color 0.18s var(--ease), color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.btn--primary { background: var(--gold); color: var(--navy); }
.btn--primary:hover { background: #FFC356; }
.btn--ghost { border-color: currentColor; color: var(--navy); background: transparent; }
.btn--ghost:hover { background: var(--navy); color: var(--white); border-color: var(--navy); }
.section--navy .btn--ghost, .hero .btn--ghost { color: var(--white); }
.section--navy .btn--ghost:hover, .hero .btn--ghost:hover { background: var(--white); color: var(--navy); border-color: var(--white); }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--s4); margin-top: var(--s6); }

/* ============================================================
   Header — matched to the current genly.com header: white ground,
   logo left, nav right, a Resources dropdown, then an outlined
   Login and a filled Get Started. Structure is the live one; the
   two colour values are the new brand palette rather than the old
   #eeb633 / #003f5c, so the header doesn't clash with the pages
   under it.
   ============================================================ */
.site-header {
  position: sticky; top: 0; z-index: 50;
  background: var(--white);
  border-bottom: 1px solid var(--rule);
}
.site-header .wrap {
  display: flex; align-items: center; gap: var(--s5);
  min-height: 80px;
}
.brand { display: flex; align-items: center; margin-right: auto; }
.brand img { height: 33px; width: auto; }
@media (min-width: 941px) {
  .brand img { height: 40px; width: auto; }
}

.nav { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2rem); margin-left: auto; }
.nav a, .nav__dropbtn {
  color: var(--navy);
  text-decoration: none;
  font-size: var(--t-sm);
  font-weight: 500;
  white-space: nowrap;
  background: none; border: 0; padding: var(--s2) 0; cursor: pointer;
  border-bottom: 2px solid transparent;
}
.nav a:hover, .nav__dropbtn:hover { color: var(--ocean-ink); }
.nav a[aria-current="page"] { border-bottom-color: var(--gold); }

/* Resources dropdown. A button, not a hover-only menu, so it works
   from the keyboard and on touch. */
.nav__drop { position: relative; display: flex; align-items: center; }
.nav__dropbtn::after {
  content: ""; display: inline-block; margin-left: 7px;
  border: 4px solid transparent; border-top-color: currentColor;
  transform: translateY(2px);
}
.nav__menu {
  position: absolute; top: calc(100% + 14px); left: 50%;
  transform: translateX(-50%);
  min-width: 190px;
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: 4px;
  box-shadow: 0 8px 24px rgba(6, 43, 89, 0.12);
  padding: var(--s2) 0;
  display: grid;
}
.nav__menu[hidden] { display: none; }
.nav__menu a {
  padding: var(--s3) var(--s5);
  border-bottom: 0;
  font-weight: 400;
}
.nav__menu a:hover { background: var(--gray); }

/* Nav buttons keep the live site's pill shape and proportions.
   Scoped as `.nav a.btn--nav` so they outrank the plain `.nav a`
   rules above, which otherwise strip the background and border. */
.nav a.btn--nav {
  border-radius: 999px;
  padding: 0.5rem 1.5rem;
  font-size: var(--t-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  border: 2px solid var(--gold);
  background: var(--gold);
  color: var(--navy);
}
.nav a.btn--nav:hover { background: #FFC356; border-color: #FFC356; color: var(--navy); }
/* Justine, 2026-09-09: Login steps back so "Request a demo" is unmistakably
   the primary action. A quiet link, not a second button competing with it. */
.nav a.btn--nav-ghost {
  background: transparent;
  color: var(--ink-muted);
  border-color: transparent;
  font-weight: 600;
  letter-spacing: 0.02em;
  padding-inline: 0.5rem;
}
.nav a.btn--nav-ghost:hover { background: transparent; color: var(--navy); border-color: transparent; text-decoration: underline; text-underline-offset: 4px; }

.nav-toggle { display: none; background: none; border: 0; color: var(--navy); padding: var(--s2); cursor: pointer; }

@media (max-width: 940px) {
  .nav-toggle { display: block; }
  .nav {
    position: absolute; inset-inline: 0; top: 100%;
    flex-direction: column; align-items: stretch; gap: 0;
    background: var(--white); border-bottom: 1px solid var(--rule);
    box-shadow: 0 10px 24px rgba(6, 43, 89, 0.1);
    padding: var(--s4) var(--gutter) var(--s6);
    /* Landscape phones are ~390px tall; without this the panel runs past
       the fold and Get Started becomes unreachable, because an absolute
       child of a sticky header does not scroll with the page. */
    max-height: calc(100vh - 96px);
    max-height: calc(100svh - 96px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .nav[hidden] { display: none; }
  .nav > a, .nav__dropbtn { padding-block: var(--s4); border-bottom: 1px solid var(--rule); width: 100%; text-align: left; }
  .nav__drop { display: block; }
  .nav__menu {
    position: static; transform: none; border: 0; box-shadow: none;
    padding: 0 0 0 var(--s5); min-width: 0;
  }
  .nav a.btn--nav { margin-top: var(--s4); text-align: center; }
}

/* Oz, 2026-10-08: the header goes dark on every page (StackAdapt-style),
   replacing the white header matched to the old genly.com. Layered over
   the rules above at the same specificity so the structure, breakpoints
   and button shapes are untouched — only the ground and ink change.
   The logo swaps to logo-genly-light.svg (white wordmark) in the markup. */
.site-header { background: var(--navy); border-bottom-color: var(--rule-navy); }
.site-header :focus-visible { outline-color: var(--gold); }
.nav a, .nav__dropbtn { color: var(--ink-onnavy); }
.nav a:hover, .nav__dropbtn:hover { color: var(--white); }
.nav__menu { background: var(--navy); border-color: var(--rule-navy); box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35); }
.nav__menu a:hover { background: var(--rule-navy); }
.nav a.btn--nav-ghost { color: var(--ink-onnavy); }
.nav a.btn--nav-ghost:hover { color: var(--white); }
.nav-toggle { color: var(--white); }
@media (max-width: 940px) {
  .nav { background: var(--navy); border-bottom-color: var(--rule-navy); box-shadow: 0 12px 28px rgba(0, 0, 0, 0.35); }
  .nav > a, .nav__dropbtn { border-bottom-color: var(--rule-navy); }
  .nav__menu { background: transparent; box-shadow: none; }
}

/* ============================================================
   The thread — one continuous line down the left gutter that
   fills as you scroll and moves through the palette. It is the
   site's single piece of ambient motion; everything else responds
   to a click. Hidden below 1080px, where the gutter disappears.
   ============================================================ */
.thread { display: none; }

@media (min-width: 1080px) {
  .thread {
    display: block;
    position: fixed;
    /* Percentages resolve against the scrollbar-excluded containing
       block; 100vw does not, and pushed this ~8px off the gutter. */
    left: calc(50% - (var(--page) / 2) + 1.75rem);
    top: 96px; bottom: 96px;
    width: 2px;
    background: rgba(6, 43, 89, 0.12);
    z-index: 5;
    pointer-events: none;
  }
  .thread__fill {
    position: absolute; inset-inline: 0; top: 0;
    height: 0;
    background: linear-gradient(180deg, var(--navy) 0%, var(--ocean) 45%, var(--teal) 78%, var(--gold) 100%);
    will-change: height;
  }
  .thread__dot {
    position: absolute; left: 50%; width: 9px; height: 9px;
    transform: translate(-50%, -50%);
    border-radius: 50%; background: var(--gold);
  }
  /* The thread has nothing to say until you have started reading. */
  .thread { opacity: 0; transition: opacity 0.4s var(--ease); }
  .thread.is-on { opacity: 1; }
}
@media (min-width: 1080px) and (max-width: 1420px) {
  .thread { left: 1.75rem; }
}

/* ---------- hero ---------- */
.hero {
  position: relative;
  background: var(--navy);
  color: var(--white);
  overflow: hidden;
  isolation: isolate;
}
.hero__media {
  position: absolute; inset: 0;
  background-image: url("../img/hero-placeholder.jpg");
  background-size: cover;
  background-position: 72% center;
  z-index: -3;
}
/* The canvas replaces the flat image once it can paint. Without JS
   or canvas the background image behind it simply stays visible. */
.hero__canvas {
  position: absolute; inset: 0; z-index: -2;
  width: 100%; height: 100%;
  opacity: 0;
  transition: opacity 0.5s var(--ease);
}
.hero__canvas.is-ready { opacity: 1; }

/* Keeps the headline legible over the particle field without
   flattening the image behind it. */
.hero__scrim {
  position: absolute; inset: 0; z-index: -1;
  /* An ellipse over the headline block rather than a wash across the
     left half, so the tight start of the wave still reads underneath
     the copy instead of being erased by the scrim. */
  background:
    radial-gradient(88% 72% at 2% 34%,
      rgba(6,43,89,0.97) 0%, rgba(6,43,89,0.92) 34%,
      rgba(6,43,89,0.58) 56%, rgba(6,43,89,0.14) 76%, rgba(6,43,89,0) 92%),
    linear-gradient(180deg, rgba(6,43,89,0.5) 0%, transparent 22%);
}
.hero .wrap {
  min-height: min(92vh, 840px);
  min-height: min(92svh, 840px);
  display: flex; flex-direction: column; justify-content: center;
  padding-block: clamp(4rem, 10vw, 7rem);
}
/* Above the mobile breakpoint the headline sits roughly halfway between
   centred and the header, per Oz and Justine. Top-aligned with a fixed
   inset rather than centred, so the distance from the header does not
   drift with viewport height. Starts at 761px so there is no band where
   neither this nor the mobile rule applies. */
@media (min-width: 761px) {
  .hero .wrap {
    justify-content: flex-start;
    padding-top: clamp(2.75rem, 7vh, 4.25rem);
    padding-bottom: clamp(3rem, 8vh, 5rem);
  }
}
.hero__inner { max-width: 52rem; }
.hero__eyebrow {
  font-size: var(--t-sm); font-weight: 500; color: var(--gold);
  margin-bottom: var(--s5);
}
.hero h1 { margin-bottom: var(--s5); }
.hero .lede { max-width: 62ch; color: #DCE7F3; }
@media (min-width: 761px) {
  .home .hero__inner { max-width: 64rem; }
  .home .hero .lede,
  .home .hero__tagline { max-width: min(40vw, 36rem); }
  .home .hero__nowrap { white-space: nowrap; }
}
@media (min-width: 761px) and (max-width: 1079px) {
  .home .hero__inner {
    width: 65vw;
    max-width: 65vw;
    margin-left: 0;
    margin-right: auto;
  }
}

@media (max-width: 760px) {
  .hero__media { background-position: 66% center; }
  /* Copy sits directly under the header, ~20px of air, and the two
     buttons stay on one row. */
  .hero .wrap {
    justify-content: flex-start;
    padding-top: 20px;
    padding-bottom: var(--s8);
    /* Taller than the copy needs, so the bubbles have somewhere to
       live below it instead of being squeezed off the bottom. */
    min-height: min(100vh, 820px);
    min-height: min(100svh, 820px);
  }
  .hero .btn-row { flex-wrap: nowrap; gap: var(--s3); }
  .hero .btn-row .btn {
    padding: 0.8rem 0.9rem;
    font-size: var(--t-sm);
    flex: 1 1 0;
    white-space: nowrap;
  }
  /* The copy now sits at the top, so the scrim does too. Below it the
     ground clears and the bubbles read. The canvas separately fades
     anything that lands on the words, so this can stay light. */
  .hero__scrim {
    background: linear-gradient(180deg,
      rgba(6,43,89,0.90) 0%, rgba(6,43,89,0.82) 40%,
      rgba(6,43,89,0.40) 64%, rgba(6,43,89,0.08) 100%);
  }
}

/* ---------- proof bar ---------- */
.proof { border-bottom: 1px solid var(--rule); }
.proof__intro { font-size: var(--t-sm); color: var(--ink-muted); margin-bottom: var(--s5); }
/* Customer logos ride a single non-wrapping row that scrolls forever.
   The track holds the set twice, so translating by exactly -50% lands
   on an identical frame and the loop has no visible seam. */
.logos {
  overflow: hidden;
  /* Fade the ends rather than cutting logos off mid-mark. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.logos__track {
  display: flex; align-items: center; width: max-content;
  gap: clamp(2.5rem, 6vw, 4.5rem);
  animation: logo-marquee 42s linear infinite;
}
.logos:hover .logos__track,
.logos:focus-within .logos__track { animation-play-state: paused; }
.logos img {
  height: 30px; width: auto; flex: none;
  /* Grayscale keeps eight different brand palettes from fighting the
     page, but 0.62 read as unfinished — these are real customers. */
  opacity: 0.85;
  filter: grayscale(1) contrast(1.15);
}
/* Oz, 2026-10-08: the logos travel right to left. */
@keyframes logo-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  /* No crawl, and the row becomes swipeable instead. */
  .logos { overflow-x: auto; }
  .logos__track { animation: none; }
}
.stats {
  display: grid; gap: var(--s6);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  margin-top: var(--s8);
  padding-top: var(--s7);
  border-top: 1px solid var(--rule);
}
.stat__num {
  font-size: var(--t-xl); font-weight: 700;
  font-variation-settings: "wdth" 108;
  letter-spacing: -0.03em; line-height: 1;
  color: var(--navy);
}
.stat__label { font-size: var(--t-sm); color: var(--ink-muted); margin-top: var(--s2); }
.section--navy .stat__num { color: var(--white); }
.section--navy .stat__label { color: var(--ink-onnavy); }

/* ---------- 95/5 ---------- */
.constraint__grid {
  display: grid; gap: clamp(2.5rem, 6vw, 5rem);
  grid-template-columns: 1fr;
  align-items: start;
}
@media (min-width: 900px) {
  .constraint__grid { grid-template-columns: 1fr 1fr; }
}
.field {
  margin-top: var(--s6);
  display: grid;
  grid-template-columns: repeat(20, 1fr);
  gap: 6px;
  max-width: 420px;
}
.field span {
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(157,195,228,0.30);
  transition: background-color 0.6s var(--ease);
}
/* Same radius as every other dot: the point is the proportion, not the size. */
.field span.is-active { background: var(--gold); }
.field__key {
  display: flex; flex-wrap: wrap; gap: var(--s5);
  margin-top: var(--s6); font-size: var(--t-sm); color: var(--ink-onnavy);
}
.field__key i { font-style: normal; display: flex; align-items: center; gap: var(--s2); }
.field__key i::before {
  content: ""; width: 10px; height: 10px; border-radius: 50%;
  background: rgba(157,195,228,0.30);
}
.field__key i.gold::before { background: var(--gold); }

.big-stat {
  font-size: clamp(3rem, 7vw, 5.5rem);
  font-weight: 700; font-variation-settings: "wdth" 118;
  letter-spacing: -0.04em; line-height: 0.9;
  color: var(--gold);
  margin-bottom: var(--s5);
}
.source { font-size: var(--t-xs); color: #9DB3CC; margin-top: var(--s6); }
/* Sits right under the statistic it backs, not adrift at the foot of the column. */
.source--tight { margin-top: var(--s3); max-width: 38ch; }
.source a { color: #9DB3CC; }

/* Section intro: heading left, standfirst right. Keeps the eye
   moving across the full measure instead of hugging one edge. */
.intro { display: grid; gap: clamp(1.5rem, 4vw, 4rem); align-items: end; }
@media (min-width: 900px) { .intro { grid-template-columns: 1.05fr 0.95fr; } }
.intro .lede { margin: 0; }
/* Two paragraphs in the right column: bottom-aligning the headline against
   them opens a hole above it, so this variant hangs both columns from the top. */
.intro--top { align-items: start; }

/* ---------- methodology: a path, not a funnel ---------- */
.stages {
  display: grid; gap: var(--s5);
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  margin-top: var(--s7);
  position: relative;
}
/* The bar above each stage. All four are ocean; exactly one is gold,
   and which one is driven by scroll position through the pin. */
.stage { padding-top: var(--s6); border-top: 2px solid var(--rule); position: relative; }
.stage::before {
  content: ""; position: absolute; top: -2px; left: 0;
  height: 2px; width: 0; background: var(--ocean);
  transition: width 0.7s var(--ease) var(--d, 0ms), background-color 0.35s var(--ease) 0s;
}
.is-revealed .stage::before, html:not(.js) .stage::before { width: 100%; }
.stage:nth-child(1) { --d: 0ms; }
.stage:nth-child(2) { --d: 140ms; }
.stage:nth-child(3) { --d: 280ms; }
.stage:nth-child(4) { --d: 420ms; }

.stages[data-active="0"] .stage:nth-child(1)::before,
.stages[data-active="1"] .stage:nth-child(2)::before,
.stages[data-active="2"] .stage:nth-child(3)::before,
.stages[data-active="3"] .stage:nth-child(4)::before { background: var(--gold); height: 4px; top: -3px; }

/* Inactive stages stay fully readable. The active one is marked three ways —
   the gold bar, a tinted ground and a lifted heading — never by fading the
   other three out. */
.js .stages[data-stages] .stage {
  transition: background-color 0.35s var(--ease), color 0.35s var(--ease);
  padding-inline: var(--s4);
  margin-inline: calc(var(--s4) * -1);
  border-radius: 0 0 3px 3px;
}
.stages[data-active="0"] .stage:nth-child(1),
.stages[data-active="1"] .stage:nth-child(2),
.stages[data-active="2"] .stage:nth-child(3),
.stages[data-active="3"] .stage:nth-child(4) {
  background: rgba(242, 174, 46, 0.10);
}
.stages[data-active="0"] .stage:nth-child(1) h3,
.stages[data-active="1"] .stage:nth-child(2) h3,
.stages[data-active="2"] .stage:nth-child(3) h3,
.stages[data-active="3"] .stage:nth-child(4) h3 { color: var(--gold-ink); }
.stages[data-active="0"] .stage:nth-child(1) p,
.stages[data-active="1"] .stage:nth-child(2) p,
.stages[data-active="2"] .stage:nth-child(3) p,
.stages[data-active="3"] .stage:nth-child(4) p { color: var(--navy); }

/* The message the audience would actually see at the live stage. */
.echoes { margin-top: var(--s7); }
.echo {
  max-width: 62ch;
  border-left: 3px solid var(--gold);
  padding-left: var(--s5);
  font-size: var(--t-md);
  line-height: 1.5;
  color: var(--navy);
}
.echo__kind {
  display: block;
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: var(--s3);
}

/* The pin. Four stage-lengths of scroll, desktop only — on a phone a
   240vh pin would just feel like the page had frozen. */
.methodology { padding-block: 0; }
@media (min-width: 761px) {
  .methodology__pin { height: 200vh; }
  .methodology__sticky {
    position: sticky;
    top: 88px;
    padding-block: clamp(2rem, 4.5vw, 3.75rem);
  }
}
@media (max-width: 760px) {
  .methodology__sticky { padding-block: clamp(3rem, 7vw, 5rem); }
}
@media (prefers-reduced-motion: reduce) {
  /* No pin, and every stage reads at full strength. */
  .methodology__pin { height: auto; }
  .methodology__sticky { position: static; }
}
.stage__n {
  font-size: var(--t-sm); font-weight: 600; color: var(--ocean-ink);
  margin-bottom: var(--s3);
}
.stage h3 { margin-bottom: var(--s3); font-size: var(--t-md); }
.stage p { font-size: var(--t-sm); color: var(--ink-muted); }

/* ---------- platform tabs ---------- */
.tabs {
  display: flex; gap: var(--s2);
  border-bottom: 1px solid var(--rule-navy);
  margin-top: var(--s7);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  flex: none;
  background: rgba(255,255,255,0.04); border: 0;
  border-bottom: 3px solid transparent;
  border-radius: 4px 4px 0 0;
  padding: var(--s4) var(--s6);
  font-size: var(--t-md); font-weight: 600;
  color: #CFE0F0;
  cursor: pointer; white-space: nowrap;
  transition: color 0.18s var(--ease), background-color 0.18s var(--ease), border-color 0.18s var(--ease);
}
.tab:hover { color: var(--white); background: rgba(255,255,255,0.09); }
/* Active state carries three signals, so it never depends on colour
   alone: weight, an underline bar, and a leading marker. */
.tab[aria-selected="true"] {
  color: var(--white);
  font-weight: 700;
  background: rgba(255,255,255,0.12);
  border-bottom-color: var(--gold);
}
/* How long is left before the next tab takes over. Removed the moment
   someone interacts, because nothing is advancing after that. */
.tabs[data-auto="on"] .tab[aria-selected="true"]::after {
  content: "";
  position: absolute; left: 0; bottom: -3px;
  height: 3px; width: 100%;
  background: var(--white);
  transform-origin: left center;
  animation: tab-progress var(--tab-dwell, 7s) linear forwards;
}
.tab { position: relative; }
@keyframes tab-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@media (prefers-reduced-motion: reduce) {
  .tabs[data-auto="on"] .tab[aria-selected="true"]::after { animation: none; }
}
.tab[aria-selected="true"]::before {
  content: "";
  display: inline-block; vertical-align: middle;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--gold); margin-right: var(--s3);
}

.panel {
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  padding-top: clamp(2.5rem, 5vw, 4rem);
  align-items: center;
}
@media (min-width: 900px) { .panel { grid-template-columns: 0.9fr 1.1fr; } }
.panel[hidden] { display: none; }
.panel h3 { margin-bottom: var(--s4); }
/* Holds a self-framed product artifact — no second box around it. */
.panel__viz svg { width: 100%; height: auto; }

/* ---------- testimonials ---------- */
.quotes { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); margin-top: var(--s8); }
@media (min-width: 860px) { .quotes { grid-template-columns: 1fr 1fr; } }
.quote { margin: 0; }
.quote blockquote {
  margin: 0;
  font-family: var(--font-quote);
  font-style: italic;
  font-size: clamp(1.375rem, 2.4vw, 1.75rem);
  line-height: 1.35;
  letter-spacing: -0.01em;
  color: var(--navy);
}
.section--navy .quote blockquote { color: var(--white); }
.quote figcaption {
  margin-top: var(--s5); padding-top: var(--s4);
  border-top: 1px solid var(--rule);
  font-size: var(--t-sm); color: var(--ink-muted);
}
.section--navy .quote figcaption { border-top-color: var(--rule-navy); color: var(--ink-onnavy); }

/* ---------- resources: an editorial list, not cards ---------- */
.res { margin-top: var(--s7); border-top: 1px solid var(--rule); }
.res a {
  display: grid; gap: var(--s2) var(--s6);
  grid-template-columns: 1fr;
  padding: var(--s6) 0;
  border-bottom: 1px solid var(--rule);
  text-decoration: none; color: var(--navy);
  transition: padding-left 0.2s var(--ease), color 0.2s var(--ease);
}
@media (min-width: 760px) { .res a { grid-template-columns: 140px 1fr; align-items: baseline; } }
.res a:hover { padding-left: var(--s4); color: var(--ocean-ink); }
.res__kind { font-size: var(--t-sm); color: var(--ink-muted); }
.res__title { font-size: var(--t-lg); font-weight: 600; line-height: 1.2; letter-spacing: -0.02em; }

/* ---------- audiences ---------- */
/* Justine, 2026-09-08: seven examples laid out 4 then 3, every card the same
   size, so no category is ever left dangling alone on a line. Flex rather than
   grid: the short last row centres under the full one instead of hanging left. */
.aud {
  margin-top: var(--s8);
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(2.5rem, 5vw, 4rem) var(--s6);
}
.aud__item {
  flex: 0 1 100%;
  min-width: 0;
}
@media (min-width: 620px)  { .aud__item { flex-basis: calc((100% - var(--s6)) / 2); } }
@media (min-width: 1040px) { .aud__item { flex-basis: calc((100% - 3 * var(--s6)) / 4); } }
.aud__img {
  aspect-ratio: 1 / 1;
  background: var(--navy);
  border-radius: 2px;
  margin-bottom: var(--s5);
  position: relative;
  overflow: hidden;
}
.aud__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.aud__img::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 46px; height: 3px; background: var(--teal);
}
.aud h3 { margin-bottom: var(--s3); }
.aud p { font-size: var(--t-sm); color: var(--ink-muted); }

/* ---------- the investment model ----------
   One media investment activating the whole system. Deliberately not a
   pricing table: no tiers, no ticks, no struck-through "value". The rail
   does the work — one source, five things it switches on. */
.invest__card {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  padding: clamp(1.75rem, 4vw, 2.75rem);
  border: 1px solid rgba(22, 168, 151, 0.32);
  border-left: 4px solid var(--teal);
  border-radius: 3px;
  background: linear-gradient(180deg, rgba(22, 168, 151, 0.07), rgba(22, 168, 151, 0.02));
}
@media (min-width: 900px) { .invest__card { grid-template-columns: 1fr 1fr; } }
.invest__copy h2 { margin-bottom: var(--s4); }
.invest__copy p { color: var(--ink-muted); max-width: 44ch; }

.invest__seed {
  display: inline-block;
  font-weight: 700;
  font-size: var(--t-sm);
  color: var(--navy);
  background: var(--gold);
  border-radius: 999px;
  padding: 0.55rem 1.35rem;
}
.invest__gets {
  list-style: none;
  margin: 0;
  padding: var(--s4) 0 0 2rem;
  position: relative;
}
/* The rail drops out of the seed and stops at the last item. */
.invest__gets::before {
  content: "";
  position: absolute;
  left: 0.5rem; top: 0; bottom: 1.35rem;
  width: 2px;
  background: var(--teal);
  opacity: 0.5;
}
.invest__gets li {
  position: relative;
  padding: 0.55rem 0;
  font-size: var(--t-sm);
  font-weight: 600;
  color: var(--navy);
}
.invest__gets li::before {
  content: "";
  position: absolute;
  left: -1.69rem; top: 1.05rem;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--teal);
}

/* ---------- how it works sequence ---------- */
.step {
  display: grid; gap: clamp(1.75rem, 5vw, 4rem);
  grid-template-columns: 1fr;
  padding-block: clamp(3rem, 7vw, 6rem);
  border-top: 1px solid var(--rule);
}
@media (min-width: 900px) { .step { grid-template-columns: 0.85fr 1.15fr; } }
.step__n {
  font-size: var(--t-sm); font-weight: 600; color: var(--ocean-ink);
  display: flex; align-items: center; gap: var(--s3);
}
.step__n::after { content: ""; flex: 1; height: 1px; background: var(--rule); }
.step h2 { margin: var(--s5) 0 var(--s4); }
.step p { color: var(--ink-muted); }
.ticks { margin-top: var(--s6); display: grid; gap: var(--s3); }
.ticks li {
  font-size: var(--t-sm);
  padding-left: var(--s6); position: relative;
}
.ticks li::before {
  content: ""; position: absolute; left: 0; top: 0.55em;
  width: 14px; height: 2px; background: var(--teal);
}
/* Holds a product artifact, which brings its own frame — no second
   box around it. */
.step__viz { display: grid; align-content: center; }
.step__viz svg { width: 100%; height: auto; }

/* Justine, 2026-09-09: the stacked formula made the page feel longer than it
   is, so the artifact changes sides step by step. Same grid, different
   reading rhythm — nothing here reflows on a phone, where it is one column. */
@media (min-width: 900px) {
  .step:nth-child(even) { grid-template-columns: 1.15fr 0.85fr; }
  .step:nth-child(even) > :first-child { order: 2; }
  .step:nth-child(even) .step__viz { order: 1; }
}

/* Says what you are looking at, so a real product view is never mistaken for
   a concept diagram, or the other way round. */
.viz__kind {
  margin-top: var(--s4);
  font-size: var(--t-xs);
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
  display: flex; align-items: center; gap: var(--s3);
}
.viz__kind::before {
  content: ""; flex: none;
  width: 8px; height: 8px; border-radius: 2px;
  background: var(--ocean);
}
.viz__kind--concept::before { background: var(--gold); border-radius: 50%; }
.on-navy .viz__kind { color: var(--ink-onnavy); }
/* Tracked-out caps wrap to four shouting lines on a phone. Below the fold of
   a narrow screen the label reads as sentence case instead. */
@media (max-width: 620px) {
  .viz__kind { text-transform: none; letter-spacing: 0.01em; font-size: var(--t-sm); }
}

/* The five-part loop is 620px wide at its narrowest legible size, so on a
   phone it scrolls. Without a cue the reader sees two boxes and assumes that
   is the whole diagram, which loses the one point the section makes. */
.diagram__hint { display: none; }
@media (max-width: 760px) {
  .diagram__hint {
    display: block;
    margin-top: var(--s3);
    font-size: var(--t-xs);
    color: var(--ink-muted);
  }
}

/* A persistent, quiet marker of where you are in the five stages. Hidden
   from assistive tech: the numbered headings already say the same thing. */
.rail {
  position: fixed; z-index: 4;
  right: max(1rem, calc(50% - (var(--page) / 2) + 1.5rem));
  top: 50%; transform: translateY(-50%);
  display: none; gap: 0.85rem;
  flex-direction: column;
}
@media (min-width: 1180px) { .js .rail { display: flex; } }
@media (prefers-reduced-motion: no-preference) { .rail { transition: opacity 0.3s var(--ease); } }
.rail span {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--navy); opacity: 0.22;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), background-color 0.3s var(--ease);
}
.rail span.is-on { opacity: 1; background: var(--gold); transform: scale(1.5); }

/* ---------- values row ---------- */
.values { display: flex; flex-wrap: wrap; gap: var(--s4); margin-top: var(--s7); }
.values li {
  border: 1px solid var(--rule-navy);
  border-radius: 999px;
  padding: var(--s3) var(--s5);
  font-size: var(--t-sm);
  color: var(--white);
}

/* ---------- footer ---------- */
.site-footer {
  background: var(--navy); color: var(--ink-onnavy);
  border-top: 1px solid var(--rule-navy);
  padding-block: var(--s7);
  font-size: var(--t-sm);
}
.site-footer .wrap { display: flex; flex-wrap: wrap; gap: var(--s5); align-items: center; }
.site-footer nav { display: flex; flex-wrap: wrap; gap: var(--s5); margin-left: auto; }
.site-footer a { color: var(--ink-onnavy); text-decoration: none; }
.site-footer a:hover { color: var(--white); text-decoration: underline; }

/* ---------- reveal ---------- */
.js .reveal { opacity: 0; transform: translateY(14px); transition: opacity 0.6s var(--ease), transform 0.6s var(--ease); }
.reveal.is-revealed { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  /* The thread is not animated in, so it must not start hidden. */
  .thread { opacity: 1; }
  /* The 95/5 field and the stage rules still read at rest, so the
     information survives with motion switched off. */
  .is-revealed .stage::before, .stage::before { width: 100%; }
  .thread__fill { height: 100% !important; }
}

/* ============================================================
   Operating model — partnership, not opposition.
   Two contributions converge into one line rather than sitting
   either side of a divider.
   ============================================================ */
.model { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: start; margin-top: var(--s8); }
@media (min-width: 940px) { .model { grid-template-columns: 0.85fr 1.15fr; } }

.model__photo { margin: 0; }
.model__photo img { border-radius: 3px; width: 100%; }
.model__photo figcaption {
  margin-top: var(--s4); font-size: var(--t-sm); color: var(--ink-muted);
}
.section--navy .model__photo figcaption { color: var(--ink-onnavy); }

.merge { --arm: #A8B8CC; }   /* --rule is too faint to read as a drawing */
.section--navy .merge { --arm: var(--rule-navy); }
.merge__arms { display: grid; gap: var(--s5); }
@media (min-width: 620px) { .merge__arms { grid-template-columns: 1fr 1fr; gap: var(--s6); } }
.merge__arm {
  position: relative;
  padding-top: var(--s5);
  padding-bottom: var(--s6);
  border-top: 3px solid var(--ocean);
}
.merge__arm:last-child { border-top-color: var(--teal); }
.merge__arm h3 { margin-bottom: var(--s3); }
.merge__arm p { font-size: var(--t-sm); color: var(--ink-muted); }
.section--navy .merge__arm p { color: var(--ink-onnavy); }

/* Each arm drops a stem; the stems meet on one bar and continue as a
   single line. Drawn with borders so it reflows with the copy rather
   than needing a fixed-height drawing. */
.merge__arm::after {
  content: "";
  position: absolute; left: 50%; bottom: 0;
  width: 2px; height: var(--s6);
  background: var(--arm);
  transform: translateX(-50%);
}
/* Used on its own, without a weave underneath — no dangling stems. */
.merge--plain .merge__arm { padding-bottom: 0; }
.merge--plain .merge__arm::after { display: none; }
/* Stacked, the converging drawing has nothing to converge — the
   outcome line carries it on its own. */
@media (max-width: 619px) {
  .merge__arm { padding-bottom: 0; }
  .merge__arm::after { display: none; }
}
.merge__out {
  margin-top: calc(var(--s5) + var(--s5));
  display: flex; align-items: center; gap: var(--s3);
  font-size: var(--t-md); font-weight: 600;
}
@media (max-width: 619px) { .merge__out { margin-top: var(--s6); } }
.merge__out::before {
  content: ""; flex: none;
  width: 12px; height: 12px; border-radius: 50%; background: var(--gold);
}

/* ============================================================
   Product artifacts — the fragments of real product surface that
   section 7 asks to enter and resolve as each capability is
   explained. Numbers are illustrative and labelled as such.
   ============================================================ */
.ui {
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow: hidden;
  font-size: var(--t-sm);
  box-shadow: 0 1px 2px rgba(6, 43, 89, 0.06);
}
.ui__bar {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s5);
  background: var(--gray);
  border-bottom: 1px solid var(--rule);
  font-weight: 600; color: var(--navy);
}
.ui__bar span { margin-left: auto; font-weight: 500; color: var(--ink-muted); }
.ui__body { padding: var(--s5); display: grid; gap: var(--s3); }

.ui__row {
  display: grid; grid-template-columns: 8.5rem 1fr;
  gap: var(--s4); align-items: baseline;
  padding-block: var(--s2);
}
.ui__row + .ui__row { border-top: 1px solid var(--rule); }
.ui__row dt { color: var(--ink-muted); }
.ui__row dd { margin: 0; font-weight: 500; }

.ui__total {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: var(--s4);
  padding: var(--s4) var(--s5);
  border-top: 1px solid var(--rule);
  background: var(--gray);
}
.ui__total b { font-size: var(--t-md); font-variation-settings: "wdth" 106; }

.ui table { width: 100%; border-collapse: collapse; }
.ui th, .ui td { text-align: left; padding: var(--s3) var(--s5); }
.ui th { font-weight: 500; color: var(--teal-ink); border-bottom: 1px solid var(--rule); }
.ui td { border-bottom: 1px solid var(--rule); }
.ui tr:last-child td { border-bottom: 0; }
.ui td:last-child, .ui th:last-child { text-align: right; }

.pill {
  display: inline-block;
  padding: 2px 8px; border-radius: 3px;
  font-size: var(--t-xs); font-weight: 600;
  background: rgba(22, 168, 151, 0.14); color: var(--teal-ink);
}
.pill--ocean { background: rgba(22, 133, 193, 0.14); color: var(--ocean-ink); }
.pill--gold  { background: rgba(151, 102, 9, 0.14); color: var(--gold-ink); }

.ui__note {
  padding: var(--s4) var(--s5);
  border-top: 1px solid var(--rule);
  color: var(--ink-muted);
  display: flex; gap: var(--s3);
}
.ui__note::before { content: ""; flex: none; width: 3px; background: var(--gold); border-radius: 2px; }

.shift { display: grid; gap: var(--s3) var(--s4); grid-template-columns: 1fr auto 1fr; align-items: center; }
.shift + .shift { border-top: 1px solid var(--rule); padding-top: var(--s3); }
.shift q { color: var(--ink-muted); font-style: italic; }
.shift b { font-weight: 600; }
.shift i { font-style: normal; color: var(--teal-ink); }

.disclaimer { font-size: var(--t-xs); color: var(--ink-muted); margin-top: var(--s5); }

/* ============================================================
   Culture strip — real, candid photography used as an editorial
   layer. Deliberately not repeated on every section.
   ============================================================ */
.strip {
  display: grid; gap: var(--s4);
  grid-template-columns: repeat(2, 1fr);
  margin-top: var(--s8);
}
@media (min-width: 780px) { .strip { grid-template-columns: 1.4fr 1fr 1fr; } }
.strip figure { margin: 0; }
.strip img { width: 100%; border-radius: 3px; object-fit: cover; }
.strip figure:nth-child(1) img { aspect-ratio: 4 / 3; }
.strip figure:nth-child(2) img { aspect-ratio: 1 / 1; }
.strip figure:nth-child(3) img { aspect-ratio: 1 / 1; }
.strip figcaption { margin-top: var(--s3); font-size: var(--t-sm); color: var(--ink-muted); }
.section--navy .strip figcaption { color: var(--ink-onnavy); }

.feature { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; margin-top: var(--s8); }
@media (min-width: 900px) { .feature { grid-template-columns: 1fr 1fr; } }
.feature img { width: 100%; border-radius: 3px; }
.feature figcaption { margin-top: var(--s4); font-size: var(--t-sm); color: var(--ink-muted); }
.section--navy .feature figcaption { color: var(--ink-onnavy); }
.feature > figure { margin: 0; }
.contact__lead { font-size: var(--t-md); color: var(--ink-muted); }
.contact__mail { margin-top: var(--s3); font-size: var(--t-xl); font-weight: 600; letter-spacing: -0.02em; }
.contact__mail a { color: var(--ocean-ink); text-decoration: none; border-bottom: 2px solid rgba(22,133,193,0.35); }
.contact__mail a:hover { border-bottom-color: var(--ocean); }

/* ============================================================
   Design system reference page
   ============================================================ */
.ds-nav {
  display: flex; flex-wrap: wrap; gap: var(--s3);
  margin-top: var(--s6);
}
.ds-nav a {
  border: 1px solid var(--rule-navy); border-radius: 999px;
  padding: var(--s2) var(--s5);
  color: var(--white); text-decoration: none; font-size: var(--t-sm);
}
.ds-nav a:hover { background: rgba(255,255,255,0.08); }

.swatches { display: grid; gap: var(--s5); grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); margin-top: var(--s7); }
.swatch__chip { height: 92px; border-radius: 3px; border: 1px solid var(--rule); }
.swatch h3 { margin: var(--s4) 0 var(--s2); font-size: var(--t-base); }
.swatch code { font-size: var(--t-sm); color: var(--ink-muted); }
.swatch p { font-size: var(--t-sm); color: var(--ink-muted); margin-top: var(--s2); }

.specs { width: 100%; border-collapse: collapse; margin-top: var(--s6); font-size: var(--t-sm); }
.specs th, .specs td { text-align: left; padding: var(--s3) var(--s4); border-bottom: 1px solid var(--rule); vertical-align: top; }
.specs th { font-weight: 600; color: var(--navy); white-space: nowrap; }
.specs td:first-child { white-space: nowrap; font-weight: 500; }
.specs code { font-size: 0.9em; color: var(--ocean-ink); }
.specs-scroll { overflow-x: auto; }

.scale-row { display: flex; align-items: baseline; gap: var(--s5); padding-block: var(--s4); border-bottom: 1px solid var(--rule); }
.scale-row span { flex: none; width: 9rem; font-size: var(--t-sm); color: var(--ink-muted); }

.two-col { display: grid; gap: clamp(2rem, 5vw, 4rem); margin-top: var(--s7); }
@media (min-width: 820px) { .two-col { grid-template-columns: 1fr 1fr; } }
.rules { display: grid; gap: var(--s3); }
.rules li { padding-left: var(--s6); position: relative; font-size: var(--t-sm); }
.rules li::before {
  content: ""; position: absolute; left: 0; top: 0.5em;
  width: 14px; height: 2px; background: var(--teal);
}
.rules--avoid li::before { background: #C0392B; }

.demo-box {
  margin-top: var(--s6); padding: clamp(1.25rem, 3vw, 2rem);
  border: 1px dashed var(--rule); border-radius: 4px;
}
.section--navy .demo-box { border-color: var(--rule-navy); }

/* ============================================================
   Capture vs creation.
   The two are not equals, and the layout should not pretend they
   are: capture gets a narrow outlined column, creation gets the
   wider filled one. The proportion is the argument.
   ============================================================ */
.scales { display: grid; gap: var(--s5); margin-top: var(--s9); }
@media (min-width: 860px) { .scales { grid-template-columns: 1fr 1.75fr; gap: var(--s6); } }

.scales__side {
  padding: clamp(1.5rem, 3vw, 2.25rem);
  border-radius: 4px;
  display: flex; flex-direction: column;
}
.scales__side--capture {
  border: 1px solid var(--rule-navy);
  color: var(--ink-onnavy);
}
.scales__side--create {
  background: linear-gradient(135deg, #0B3B74 0%, #0A3568 100%);
  border: 1px solid #1D5390;
  color: var(--white);
}
.scales__kind { font-size: var(--t-sm); font-weight: 500; margin-bottom: var(--s4); color: #8FA9C6; }
.scales__side--create .scales__kind { color: var(--gold); }
.scales__side h3 { margin-bottom: var(--s3); color: var(--white); }
.scales__side--create h3 { font-size: var(--t-xl); font-variation-settings: "wdth" 104; }
.scales__side p { font-size: var(--t-sm); }
.scales__side--create p { font-size: var(--t-base); color: #D8E5F3; max-width: 60ch; }
.scales__viz { margin-top: auto; padding-top: var(--s6); }
.scales__viz svg { width: 100%; height: auto; }

/* ============================================================
   Audiences: the page's whole argument, drawn once.
   ============================================================ */
.diagram {
  margin-top: var(--s8);
  padding: clamp(1.25rem, 3vw, 2.5rem);
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: 4px;
  overflow-x: auto;
}
.section--navy .diagram { background: rgba(255,255,255,0.04); border-color: var(--rule-navy); }
.diagram svg { width: 100%; min-width: 620px; height: auto; display: block; }
.diagram figcaption { margin-top: var(--s5); font-size: var(--t-sm); color: var(--ink-muted); }

/* Justine, 2026-09-09: the outcome closes the five steps, so it sits tight to
   step 05 and carries a teal concept frame rather than the flat product-panel
   look the steps above it use. */
.outcome { padding-top: clamp(1.5rem, 3vw, 2.5rem); }
.diagram--concept {
  border-color: rgba(22, 168, 151, 0.35);
  border-left-width: 3px;
  border-left-color: var(--teal);
  background: linear-gradient(180deg, rgba(22, 168, 151, 0.05), rgba(255,255,255,0));
}

/* The buying window: where Genly works versus where everyone else does. */
.window { margin-top: var(--s8); }
.window__track {
  position: relative; height: 6px; border-radius: 3px;
  background: var(--rule);
}
.window__early, .window__late {
  position: absolute; top: 0; height: 100%; border-radius: 3px;
}
.window__early { left: 0; width: 72%; background: var(--teal); }
.window__late  { right: 0; width: 22%; background: var(--gold); }
.window__marks {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--s4);
  margin-top: var(--s4); font-size: var(--t-sm);
}
.window__marks b { display: block; font-weight: 600; color: var(--navy); }
.window__marks span { color: var(--ink-muted); }
.window__marks div:last-child { text-align: right; }
@media (max-width: 559px) {
  .window__marks { grid-template-columns: 1fr; }
  .window__marks div:last-child { text-align: left; }
}

/* ============================================================
   Closing call to action.
   The hero opens from one point into many people; this closes the
   other way, many back into one. Same motif, other direction.
   ============================================================ */
.close { text-align: center; }
.close__band { max-width: 720px; margin: 0 auto var(--s7); }
.close__band svg { width: 100%; height: auto; display: block; }
.close .h-display { max-width: 18ch; margin-inline: auto; }
.close .lede { margin: 0 auto var(--s5); max-width: 34ch; }
.close__over { order: -1; }
/* Justine, 2026-09-10: each page's setup line reads as one line. The 34ch
   measure that keeps the closing headline tight was breaking them in two.
   Held back to wide viewports — on a phone it has to wrap or it overflows. */
@media (min-width: 700px) {
  .close .close__over {
    max-width: none;
    text-wrap: nowrap;
    white-space: nowrap;
  }
}
.close .btn-row { justify-content: center; margin-top: var(--s7); }
/* Justine, 2026-09-09: say what happens after the form is sent, right where
   the visitor decides whether to send it. */
.close__expect {
  max-width: 58ch;
  margin: var(--s6) auto 0;
  font-size: var(--t-sm);
  color: var(--ink-onnavy);
}
.form__opt {
  font-weight: 400;
  font-size: var(--t-xs);
  color: var(--ink-onnavy);
  opacity: 0.8;
  margin-left: 0.4em;
}

/* ============================================================
   Long-form legal copy. One narrow column, generous leading, and
   headings that stay quiet — this is read, not scanned.
   ============================================================ */
/* Archivo runs ~1.27 characters per ch here, so 68ch measured 86-96
   characters. 53ch lands at roughly 67. */
.prose { max-width: 53ch; margin-top: var(--s8); }
.prose > * + * { margin-top: var(--s5); }
.prose p { line-height: 1.68; }
.prose h2 {
  margin-top: var(--s9);
  font-size: var(--t-xl);
  font-variation-settings: "wdth" 104;
  padding-top: var(--s5);
  border-top: 1px solid var(--rule);
}
/* A kicker inside its heading, so it can't inherit the heading's own
   top rule and 96px of air and read as a section of its own. */
.prose__eyebrow {
  display: block;
  font-size: var(--t-sm);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ocean-ink);
  margin-bottom: var(--s3);
}
.prose h3 { margin-top: var(--s7); font-size: var(--t-lg); }
.prose h4 { margin-top: var(--s6); font-size: var(--t-md); }
.prose ul, .prose ol { display: grid; gap: var(--s3); padding-left: var(--s6); }
.prose ul li { list-style: disc; }
.prose ol li { list-style: decimal; }
.prose li { line-height: 1.6; }
.prose li::marker { color: var(--ocean-ink); }
/* Long policy URLs must not push the page sideways. */
.prose a { color: var(--ocean-ink); overflow-wrap: anywhere; }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--t-sm); }
.prose th, .prose td { text-align: left; padding: var(--s3) var(--s4); border-bottom: 1px solid var(--rule); vertical-align: top; }

/* ============================================================
   Demo request. The one thing every page drives toward, so it
   sits at the convergence point rather than behind another click.
   ============================================================ */
.form {
  max-width: 620px;
  margin: var(--s7) auto 0;
  text-align: left;
}
.form__grid { display: grid; gap: var(--s5); }
@media (min-width: 620px) { .form__grid { grid-template-columns: 1fr 1fr; } }

.form__field { display: grid; gap: var(--s2); }
.form__field label { font-size: var(--t-sm); font-weight: 500; }
.section--navy .form__field label { color: var(--ink-onnavy); }
.form__field input {
  font: inherit;
  color: var(--navy);
  background: var(--white);
  border: 1px solid var(--rule);
  border-radius: 3px;
  padding: 0.8rem 0.9rem;
  width: 100%;
}
.form__field input::placeholder { color: #7C8DA3; }
.form__field input:hover { border-color: #AFBED0; }
.form__field input:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; border-color: var(--gold); }
/* Errors are announced, marked with a colour AND an icon-free prefix, and
   never rely on the red alone. */
.form__field input[aria-invalid="true"] { border-color: #E06A5A; border-width: 2px; }
.form__error { font-size: var(--t-sm); color: #FFC7BE; font-weight: 500; }
.form__error:empty { display: none; }
.form__error::before { content: "— "; }
.section:not(.section--navy) .form__error { color: #B3311E; }

.form__actions { margin-top: var(--s6); display: grid; gap: var(--s4); justify-items: start; }
@media (min-width: 620px) { .form__actions { justify-items: center; } }
.form__note { font-size: var(--t-sm); color: var(--ink-onnavy); max-width: 46ch; }
.section:not(.section--navy) .form__note { color: var(--ink-muted); }
.form__note a { color: inherit; }

.form__status {
  margin-top: var(--s5);
  font-size: var(--t-sm);
  min-height: 1.2em;
}
.form__done {
  border: 1px solid var(--rule-navy);
  border-left: 4px solid var(--teal);
  border-radius: 3px;
  padding: clamp(1.5rem, 3vw, 2.25rem);
  text-align: left;
  max-width: 620px;
  margin: var(--s7) auto 0;
}
.form__done h3 { margin-bottom: var(--s3); }
.form__done p { color: var(--ink-onnavy); }
.section:not(.section--navy) .form__done { border-color: var(--rule); }
.section:not(.section--navy) .form__done p { color: var(--ink-muted); }

/* ============================================================
   Genlypedia index. Cards here are justified: every item is the
   same kind of thing, and the image is the only differentiator.
   ============================================================ */
.posts {
  display: grid; gap: clamp(1.75rem, 3.5vw, 2.75rem);
  grid-template-columns: 1fr;
}
@media (min-width: 620px)  { .posts { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .posts { grid-template-columns: repeat(3, 1fr); } }

.post { text-decoration: none; color: var(--navy); display: block; }
.post__img {
  aspect-ratio: 16 / 10;
  background: var(--gray);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: var(--s5);
  position: relative;
}
.post__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.post__img::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 46px; height: 3px; background: var(--teal);
}
.post__kind { font-size: var(--t-sm); color: var(--ink-muted); margin-bottom: var(--s2); }
.post__title {
  font-size: var(--t-lg); font-weight: 600; line-height: 1.18;
  letter-spacing: -0.02em;
}
.post:hover .post__title { color: var(--ocean-ink); }

/* ============================================================
   FAQ. Native details/summary — open/close with no JavaScript,
   and the keyboard behaviour comes free.
   ============================================================ */
.faq { max-width: 46rem; margin-top: var(--s8); border-top: 1px solid var(--rule); }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
  list-style: none;
  cursor: pointer;
  padding: var(--s5) var(--s7) var(--s5) 0;
  font-size: var(--t-md); font-weight: 600; line-height: 1.3;
  position: relative;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary:hover { color: var(--ocean-ink); }
.faq summary::after {
  content: ""; position: absolute; right: 4px; top: 50%;
  width: 12px; height: 12px;
  border-right: 2px solid var(--ocean); border-bottom: 2px solid var(--ocean);
  transform: translateY(-70%) rotate(45deg);
  transition: transform 0.2s var(--ease);
}
.faq details[open] summary::after { transform: translateY(-30%) rotate(-135deg); }
.faq details > *:not(summary) { margin: 0 0 var(--s5); max-width: var(--measure); color: var(--ink-muted); line-height: 1.65; }

/* ============================================================
   Ad specs. A reference table of numbers, so it reads as one.
   ============================================================ */
.specs-group { margin-top: var(--s8); }
.specs-group h2 { padding-bottom: var(--s4); border-bottom: 2px solid var(--navy); }
.specs-group h3 { margin-top: var(--s7); font-size: var(--t-md); }
.specs-group p { color: var(--ink-muted); max-width: var(--measure); margin-top: var(--s3); }
.specs-group img { margin-top: var(--s5); border: 1px solid var(--rule); border-radius: 3px; }


/* ============================================================
   How It Works — colour and movement.
   Justine asked for each section to light up as you reach it, in the
   spirit of keplergrp.com but quieter. The whole run sits on Light Gray
   with white artifacts, so the page has ground instead of being an
   unbroken white column, and the step you are reading is the only one
   at full strength.
   ============================================================ */
.steps { position: relative; overflow: hidden; }
.steps::before {
  /* One slow wash of brand colour behind the run. */
  content: "";
  position: absolute; inset: -20% -10% auto -10%; height: 70%;
  background: radial-gradient(60% 60% at 20% 0%, rgba(22,133,193,0.10), transparent 70%),
              radial-gradient(50% 50% at 85% 30%, rgba(22,168,151,0.10), transparent 70%);
  pointer-events: none;
}
.steps .step { border-top-color: #DDE3EC; }

.js .step[data-step] {
  opacity: 0.48;
  transform: translateY(10px);
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease);
}
.step[data-step].is-active { opacity: 1; transform: none; }

.step__n { transition: color 0.4s var(--ease); }
.step[data-step].is-active .step__n { color: var(--gold-ink); }
.step__n::after { transition: background-color 0.4s var(--ease), width 0.6s var(--ease); }
.step[data-step].is-active .step__n::after { background: var(--gold); }

.js .step[data-step] .ui {
  transition: box-shadow 0.5s var(--ease), transform 0.5s var(--ease);
  transform: translateY(8px);
}
.step[data-step].is-active .ui {
  transform: none;
  box-shadow: 0 18px 40px -24px rgba(6, 43, 89, 0.45);
}
.step[data-step] .ticks li::before { background: #A9BACD; transition: background-color 0.4s var(--ease); }
.step[data-step].is-active .ticks li::before { background: var(--teal); }

@media (prefers-reduced-motion: reduce) {
  .step[data-step] { opacity: 1; transform: none; }
  .step[data-step] .ui { transform: none; }
}


/* ============================================================
   Operating model: two strands that weave.
   The bracket said "these two things join". The weave says they run
   through each other the whole way and arrive as one — which is what
   "AI-powered, expert-guided" actually means.
   ============================================================ */
.weave { margin-top: var(--s5); }
.weave svg { width: 100%; height: auto; display: block; overflow: visible; }
.js .weave path {
  stroke-dasharray: 900;
  stroke-dashoffset: 900;
  transition: stroke-dashoffset 1.4s var(--ease);
}
.is-revealed .weave path { stroke-dashoffset: 0; }
.is-revealed .weave path:last-of-type { transition-delay: 0.18s; }
.js .weave circle { opacity: 0; transition: opacity 0.5s var(--ease) 1.1s; }
.is-revealed .weave circle { opacity: 1; }
.section--navy .weave circle[fill="#F2F4F7"] { fill: #0B3B72; }

@media (prefers-reduced-motion: reduce) {
  .weave path { stroke-dashoffset: 0; }
  .weave circle { opacity: 1; }
}


/* Dark variant of the product artifact, for the navy Platform section.
   Same component as How It Works so the product reads as one surface
   across the site rather than two different visual languages. */
.ui--dark {
  background: #093366;
  border-color: #1D5390;
  box-shadow: 0 18px 44px -28px rgba(0,0,0,0.7);
  color: var(--white);
}
.ui--dark .ui__bar { background: #0B3B74; border-bottom-color: #1D5390; color: var(--white); }
.ui--dark .ui__bar span { color: #9DB8D6; }
.ui--dark .ui__row + .ui__row,
.ui--dark .ui__total,
.ui--dark .ui__note,
.ui--dark th, .ui--dark td { border-color: #1D5390; }
.ui--dark .ui__row dt { color: #9DB8D6; }
.ui--dark .ui__total { background: #0B3B74; }
.ui--dark th { color: #5FD9C7; }
.ui--dark .ui__note { color: #C7D6E8; }
.ui--dark .pill { background: rgba(22,133,193,0.28); color: #BFE1F7; }
.ui--dark .pill--teal { background: rgba(22,168,151,0.28); color: #A6EADF; }
.ui--dark .pill--gold { background: rgba(242,174,46,0.24); color: #FFD98A; }
.ui--dark .bars rect.track { fill: #12406F; }
.ui__chart { padding: var(--s5); }
.ui__chart svg { width: 100%; height: auto; display: block; }


/* ============================================================
   Inner-page hero.
   Every page but the homepage opened on a flat navy band. Carrying a
   quiet echo of the hero wave through them ties the set together
   without repeating the photographic composition five times.
   ============================================================ */
.section--navy.on-navy { position: relative; overflow: hidden; }
.section--navy.on-navy > .wrap { position: relative; z-index: 1; }
.pagehero::before {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(70% 120% at 88% 18%, rgba(22,133,193,0.30), transparent 62%),
    radial-gradient(50% 90% at 62% 92%, rgba(22,168,151,0.16), transparent 66%);
  pointer-events: none;
}
.pagehero__wave {
  position: absolute; inset: 0; z-index: 0;
  pointer-events: none;
  opacity: 0.5;
}
.pagehero__wave svg { width: 100%; height: 100%; display: block; }


/* Justine's AI + Human graphic. Source PNG was 1027KB; trimmed of its
   white margin and re-encoded to WebP it is 53KB, with a JPEG fallback. */
.aihuman { margin: var(--s8) 0 0; }
.aihuman picture { display: block; }
.aihuman img { width: 100%; height: auto; display: block; }
@media (max-width: 700px) {
  /* Below this the eight labels stop being legible, so the graphic
     scrolls at a readable size rather than shrinking into mush. */
  .aihuman { overflow-x: auto; }
  .aihuman img { min-width: 640px; }
  /* Same reason as the loop diagram: scrolled-off content a reader cannot
     tell is there reads as a cropped image, not a wide one. */
  .aihuman .diagram__hint { display: block; }
}


/* Case study: five headline results, using the same .stats component the
   About page uses, so the biggest numbers on the page stop being the
   smallest type on it. Sits outside .prose so it can use the full wrap. */
.stats--results { margin-top: var(--s8); border-top: 0; padding-top: 0; }
.stats--results .stat__icon { width: 40px; height: 40px; margin-bottom: var(--s3); opacity: 0.9; }

/* A quote inside long-form copy: the house Newsreader treatment, with the
   portrait as a circle rather than a raw square. */
.quote--inline {
  display: grid; gap: var(--s5);
  grid-template-columns: 72px 1fr;
  align-items: start;
  max-width: 46rem;
  margin: var(--s8) 0;
  padding-left: var(--s5);
  border-left: 3px solid var(--teal);
}
.quote--inline .quote__face { border-radius: 50%; width: 72px; height: 72px; object-fit: cover; }
.quote--inline blockquote { font-size: clamp(1.25rem, 2vw, 1.5rem); }
@media (max-width: 560px) {
  .quote--inline { grid-template-columns: 1fr; }
}

/* ============================================================
   Print. Without this every navy section prints white-on-white —
   worst on the privacy policy, which is the page people actually
   print or save as PDF.
   ============================================================ */
@media print {
  :root { --ink-muted: #333; --ink-onnavy: #333; }
  body { background: #fff; color: #000; font-size: 11pt; }

  /* Chrome, navigation and anything interactive has no business on paper. */
  .site-header, .nav, .nav-toggle, .thread, .skip, .hero__canvas,
  .form, .close__band, .btn-row, .btn, .logos, .aud__img,
  .pagehero__wave, .site-footer nav { display: none !important; }

  /* Dark sections invert rather than disappearing. */
  .section--navy, .hero, .section--gray, .ui--dark {
    background: #fff !important;
    color: #000 !important;
  }
  .section--navy *, .hero *, .ui--dark * { color: #000 !important; }
  .section, .step, .methodology__sticky { padding-block: 12pt !important; }
  .methodology__pin { height: auto !important; }
  .methodology__sticky { position: static !important; }
  .stages[data-stages] .stage, .step[data-step], .reveal { opacity: 1 !important; transform: none !important; }
  .prose { max-width: none; }

  /* Show where a link actually goes, since it can't be clicked. */
  .prose a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; word-break: break-all; }

  h1, h2, h3 { break-after: avoid; }
  img, figure, .ui, .diagram { break-inside: avoid; max-width: 100% !important; }
}

/* Wireframe puts the Audiences hero centred with two CTAs, unlike the other
   inner pages whose heroes are a left heading and a right standfirst. */
.pagehero--centered .wrap { text-align: center; }
.pagehero--centered .label { justify-content: center; }
.pagehero--centered .h-section { max-width: 22ch; margin-inline: auto; }
.pagehero--centered .lede { max-width: 60ch; margin: var(--s5) auto 0; }
.pagehero--centered .btn-row { justify-content: center; }

/* The precision list stands alone in its own section now, so it reads as
   three parallel criteria rather than a footnote to a paragraph. */
.ticks--wide {
  margin-top: var(--s7);
  display: grid; gap: var(--s5);
  grid-template-columns: 1fr;
}
@media (min-width: 760px) { .ticks--wide { grid-template-columns: repeat(3, 1fr); } }
.ticks--wide li {
  padding: var(--s5) 0 0;
  padding-left: 0;
  border-top: 2px solid var(--ocean);
  font-size: var(--t-md);
  color: var(--navy);
}
.ticks--wide li::before { display: none; }
