/* Self-hosted brand fonts. Only Regular (400) weights are provided
   for now — the browser synthesizes heavier weights from these files
   until additional cuts are added to /fonts. */
@font-face {
  font-family: "PP Mori";
  src: url("fonts/PPMori-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Feature Display";
  src: url("fonts/FeatureDisplay-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #301111;
  --ink: #0f1419;
  --ink-pill: #ffffff;
  --paper: #ffffff;
  --glow: #c8a8ff;

  --col: 720px;
  --prose-col: 600px;

  --pad-x: clamp(20px, 5vw, 48px);
  --pad-top: clamp(28px, 5vw, 56px);

  --t-logo: clamp(20px, 2.2vw, 28px);
  --t-nav: clamp(13px, 1vw, 15px);
  --t-h1: clamp(22px, 3.2vw, 36px);
  /* Flat 16px — don't scale paragraph text up at wider viewports;
     use the smaller size everywhere. */
  --t-body: 16px;

  --font-sans: "PP Mori", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-serif: "Feature Display", "Times New Roman", serif;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

/* Reserve gutter for the scrollbar so toggling overflow on body
   (when an overlay opens) doesn't cause horizontal layout shift.
   overflow-x: clip suppresses any rogue horizontal scroll at the
   viewport level without turning <html> into a scroll container —
   `hidden` here would force the implicit overflow-y to behave as
   auto, which on iOS Safari breaks every `position: sticky` inside
   the page (the Perspectives + Investments filter bars). */
html {
  scrollbar-gutter: stable;
  overflow-x: clip;
}

body {
  background-color: var(--bg);
  /* Initial color for the cover; the section tracker writes
     background-color + color on body when the active section
     changes, and this transition smoothly crossfades both. */
  color: #e7ecf3;
  font-family: var(--font-sans);
  font-size: var(--t-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  position: relative;
  /* Prevent rogue horizontal scroll on mobile (e.g. iPhone 14 Pro).
     `clip` is preferable to `hidden` here because it doesn't create
     a scroll container, so position: sticky inside the page (site-
     nav, invest sidebar) keeps working. */
  overflow-x: clip;
  transition: background-color 0.6s ease, color 0.6s ease;
}

/* Upper-right pill callout. Fixed to the viewport, fades in over
   2s on page load. Default top matches the FORERUNNER wordmark's
   top (var(--pad-top), same value used by .site-header padding);
   once the nav becomes sticky, the pill slides up to share the
   nav's top offset. */
/* Respect the [hidden] attribute. The .join-pill rule below sets
   display: inline-flex, which has equal specificity to [hidden]'s
   UA default — author styles win on ties, so the pill would render
   even with [hidden]. This higher-specificity rule restores the
   "really hidden" behavior used by the #humans URL-gate. */
.join-pill[hidden] {
  display: none;
}

.join-pill {
  position: fixed;
  bottom: clamp(16px, 3vw, 32px);
  right: clamp(16px, 3vw, 32px);
  z-index: 55;
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 15px 22px;
  background: linear-gradient(180deg, #1a2236 0%, #0b1020 100%);
  border-radius: 999px;
  color: #fff;
  font-size: var(--t-nav);
  font-weight: 400;
  letter-spacing: 0.01em;
  text-decoration: none;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.4),
              0 1px 0 rgba(255, 255, 255, 0.06) inset;
  /* Snappy pop-in from the bottom-right corner — quick fade + a
     slight scale overshoot ("back out" curve) so the pill announces
     itself rather than easing in. transform-origin anchors the
     scale to the corner the pill lives in. */
  opacity: 0;
  transform: scale(0.7) translateY(12px);
  transform-origin: bottom right;
  animation: joinPillPopIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) 0.2s forwards;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.join-pill:hover {
  /* Lift the pill on hover so it reads as clickable. Repeat scale(1)
     so the hover transform doesn't drop the value held by the
     animation's `forwards` fill-mode. */
  transform: scale(1) translateY(-5px);
  box-shadow: 0 18px 38px rgba(0, 0, 0, 0.5),
              0 1px 0 rgba(255, 255, 255, 0.08) inset;
}

.join-pill__label {
  color: rgba(255, 255, 255, 0.7);
  font-size: var(--t-nav);
  white-space: nowrap;
}

/* Pill itself never line-breaks. Without nowrap, narrow centered
   placements on mobile can compress the flex container and force
   the label to stack vertically next to the logo. */
.join-pill {
  white-space: nowrap;
}

.join-pill__logo {
  height: 17px;
  width: auto;
  display: block;
}

/* ── Pill color variants ───────────────────────────────────────
   Background palette + text tone per Sanity selection. The .label
   override re-tones the secondary label inside each variant — on
   the dark variants it stays the existing 70% white; on the light
   variants it flips to a dark tone with reduced opacity. */
.join-pill--navy {
  background: linear-gradient(180deg, #1a2236 0%, #0b1020 100%);
  color: #fff;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.4),
              0 1px 0 rgba(255, 255, 255, 0.06) inset;
}
.join-pill--navy .join-pill__label { color: rgba(255, 255, 255, 0.7); }

.join-pill--oxblood {
  background: linear-gradient(180deg, #3a1414 0%, #1a0808 100%);
  color: #fff;
  box-shadow: 0 10px 28px rgba(58, 20, 20, 0.5),
              0 1px 0 rgba(255, 220, 220, 0.06) inset;
}
.join-pill--oxblood .join-pill__label { color: rgba(255, 220, 220, 0.75); }

.join-pill--chartreuse {
  background: linear-gradient(180deg, #e1f56e 0%, #c5e63a 100%);
  color: var(--ink);
  box-shadow: 0 10px 28px rgba(120, 140, 30, 0.3),
              0 1px 0 rgba(255, 255, 255, 0.5) inset;
}
.join-pill--chartreuse .join-pill__label { color: rgba(15, 20, 25, 0.9); }

.join-pill--lavender {
  background: linear-gradient(180deg, #dac4ff 0%, #b893f5 100%);
  color: var(--ink);
  box-shadow: 0 10px 28px rgba(120, 90, 200, 0.35),
              0 1px 0 rgba(255, 255, 255, 0.5) inset;
}
.join-pill--lavender .join-pill__label { color: rgba(15, 20, 25, 0.9); }

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

/* Center the pill horizontally on narrow viewports — bottom-right
   has very little breathing room next to thumbs on a phone. Uses
   the modern `translate` property so it doesn't compete with the
   `transform`-based pop-in / hover animations above. */
@media (max-width: 600px) {
  /* Redefine the pop-in animation with translateX(-50%) baked in so
     the transform never loses the horizontal centering. Using the
     standalone `translate` property (original approach) causes an
     iOS Safari hit-test bug where the tap target stays at the
     pre-translated position, making the pill untappable. */
  @keyframes joinPillPopIn {
    from {
      opacity: 0;
      transform: translateX(-50%) scale(0.7) translateY(12px);
    }
    to {
      opacity: 1;
      transform: translateX(-50%) scale(1) translateY(0);
    }
  }
  .join-pill {
    left: 50%;
    right: auto;
    transform-origin: bottom center;
  }
  .join-pill:hover {
    transform: translateX(-50%) scale(1) translateY(-5px);
  }
}

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

/* --- Header ---------------------------------------------------- */

/* Header holds only the logo and scrolls away with the page. The nav
   is a sibling that becomes a sticky pill at the top of the viewport. */

.site-header {
  position: relative;
  display: flex;
  justify-content: center;
  /* Bottom padding governs the gap between the FORERUNNER wordmark
     and the .site-nav row that follows in flow. Kept tight so the
     nav reads as part of the masthead at page top. */
  padding: var(--pad-top) var(--pad-x) clamp(8px, 1.2vw, 16px);
}


.logo {
  position: relative;
  z-index: 1;
  display: inline-flex;
  line-height: 0;
}

.logo__svg {
  width: clamp(150px, 16vw, 230px);
  height: auto;
  display: block;
  /* Plain white wordmark — the SVG filter is still wired up but the
     white-on-white inner shadow is effectively invisible. */
  color: #fff;
}

/* Sticky pill that floats at the top of the viewport on scroll. Sized
   to its content (links only), centered, with a translucent backdrop
   that fades in once any scrolling happens — so at the very top of
   the page it's invisible, and once content starts sliding underneath
   it picks up its blurred-pill background. */

.site-nav {
  position: sticky;
  top: clamp(12px, 2vw, 20px);
  z-index: 50;
  display: flex;
  align-items: center;
  width: fit-content;
  margin: 0 auto clamp(28px, 4vw, 44px);
  --pill-pad-y: 5px;
  --pill-pad-x: 5px;
  padding: var(--pill-pad-y) var(--pill-pad-x);
  border-radius: 999px;
  font-size: var(--t-nav);
  background: transparent;
  transition:
    background 0.35s ease,
    backdrop-filter 0.35s ease,
    box-shadow 0.35s ease;
}

.site-nav.is-stuck {
  /* --nav-tint is set per section by the section tracker (see app.js).
     Defaults to the cover bg so the navy hero hands off cleanly. */
  background: color-mix(in srgb, var(--nav-tint, var(--bg)) 78%, transparent);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 4px 18px rgba(15, 20, 25, 0.08);
}

/* Light-section theme. Applied to the nav whenever it sits over a
   section with a light background (About, Ideas). Flips text, pill,
   and F icon back to a dark-on-light treatment. */
.site-nav.is-over-light .site-nav__link {
  color: var(--ink);
}

.site-nav.is-over-light .site-nav__link.is-active {
  color: #fff;
}

.site-nav:not(.is-over-light):has(.site-nav__home.is-active) .site-nav__pill {
  background: #efe9e1;
}

.site-nav.is-over-light .site-nav__pill {
  background: var(--ink);
}

.site-nav.is-over-light .site-nav__home-icon {
  filter: brightness(0);
}

.site-nav.is-over-light .site-nav__link.is-active .site-nav__home-icon {
  filter: brightness(0) invert(1);
}

.site-nav.is-stuck.is-over-light {
  background: color-mix(in srgb, #efe9e1 85%, transparent);
}

/* Inner active-link pill. Hugs the link's bounds (top/height inset by
   the nav's pill padding so it doesn't overlap the outer pill's
   blurred ring). JS drives left/width on click. */

.site-nav__pill {
  position: absolute;
  top: var(--pill-pad-y);
  left: 0;
  height: calc(100% - var(--pill-pad-y) * 2);
  width: 0;
  background: rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  pointer-events: none;
  z-index: 0;
  transform-origin: 50% 50%;
}

.site-nav__link {
  position: relative;
  z-index: 1;
  padding: 10px 16px;
  border-radius: 999px;
  text-decoration: none;
  color: rgba(255, 255, 255, 0.80);
  transition: color 0.35s ease;
  white-space: nowrap;
}

.site-nav__link.is-active {
  color: rgba(255, 255, 255, 0.92);
}

.site-nav__link:not(.is-active):hover {
  opacity: 0.7;
}

/* Home (F icon) — the active-page indicator. Hidden at page top
   (width 0, padding 0, opacity 0) and grows into place via GSAP when
   the nav becomes sticky. The OUTER active pill tracks it during the
   expand, so the dark pill appears around the F as it slides in. */

.site-nav__link.site-nav__home {
  width: 0;
  padding: 0;
  overflow: hidden;
  opacity: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.site-nav__home-icon {
  width: 16px;
  height: auto;
  display: block;
  flex-shrink: 0;
  /* Default state: F is white against the navy cover (when the active
     pill has moved to another link). */
  filter: brightness(0) invert(1);
  transition: filter 0.35s ease;
}

/* When the home is the active link, the white pill sits behind it —
   flip the icon to dark so it reads against that pill. */
.site-nav__link.is-active .site-nav__home-icon {
  filter: brightness(0);
}

/* --- Page column ----------------------------------------------- */

.page {
  position: relative;
  max-width: var(--col);
  margin: 0 auto;
  padding: clamp(80px, 12vw, 160px) var(--pad-x) clamp(80px, 10vw, 140px);
  display: flex;
  flex-direction: column;
  gap: clamp(48px, 8vw, 96px);
}

/* --- Hero ------------------------------------------------------ */

.hero h1 {
  margin: 0 auto;
  font-family: var(--font-serif);
  /* Hits the 52px cap at ~1155px viewport and scales smoothly down
     to phones (clamped at 28px). */
  font-size: clamp(28px, 4.5vw, 52px);
  line-height: 1.15;
  letter-spacing: -0.01em;
  font-weight: 500;
  text-align: center;
  /* No text-wrap: balance — the headline already has an explicit
     <br> separating the two halves, and balance was over-breaking
     each half into two short lines on wider viewports where the
     natural single line would have fit fine. */
  /* Break out of the .page 720px column so the lead headline can
     breathe at larger viewports. Side gutter equals var(--pad-x) on
     each side — same as .page itself — so the headline aligns with
     the natural content column instead of getting extra inset that
     looked like a "weird uneven margin" on mobile. */
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: min(1200px, calc(100vw - var(--pad-x) * 2));
  max-width: 100vw;
}

/* --- Card stage ------------------------------------------------ */

/* Perspective is set on `.stage` so the 3D math is scoped here. Every
   ancestor between the perspective container and the 3D-transformed
   `.card` needs `transform-style: preserve-3d`, otherwise the browser
   flattens the chain back to 2D and rotateX/rotateY become shears. */

.stage {
  position: relative;
  /* Tightened — cards now stack centrally so the stage doesn't need to
     be as tall as the spread layout required. */
  min-height: clamp(320px, 42vw, 460px);
  /* Pull the stage up toward the lead headline. The .page flex-gap is
     48-96px between siblings; this negative top margin cancels most
     of that gap above the stage while leaving the gap below alone. */
  margin-top: clamp(-72px, -5vw, -32px);

  perspective: 1100px;
  perspective-origin: 50% 50%;
}

/* Hero-mode visibility ─ driven by body.has-cards / body.has-video.
   Either, both, or neither can be on. */
.stage,
.video-scroll {
  display: none;
}
body.has-cards .stage {
  display: block;
}
body.has-video .video-scroll {
  display: block;
}

/* Video module ─ a normal section in the page flow. The video scales
   from 1.0 to 1.3x as the section enters the viewport, auto-plays
   once it's mostly visible, and pauses when it leaves. User can
   scroll past it freely — no pinning. */
.video-scroll {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(40px, 6vh, 80px) 0;
  /* Modest top margin — the video peeks above the fold but the
     headline-to-video gap stays tight. */
  margin-top: clamp(20px, 5vh, 60px);
  overflow: visible;
}

.video-pin {
  display: block;
}

.video-el {
  /* Match the prose column width — the video reads as part of the
     same vertical rhythm as the body copy. */
  width: min(var(--prose-col), calc(100vw - var(--pad-x) * 2));
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  border-radius: 24px;
  /* Match the cover section bg so the placeholder is invisible while
     the video loads rather than showing a gray/blue box. */
  background: #301111;
  transform-origin: center center;
  /* Scale is written inline by JS on every scroll frame. */
  opacity: 0;
  transition: opacity 0.8s ease;
}

/* Both clusters occupy the entire stage area as overlapping layers so
   every card's top/left percentages reference the full landing pad. */

.cluster {
  position: absolute;
  inset: 0;
  z-index: 1;
  transform-style: preserve-3d;
}

/* `.card-pose` owns the resting position and Z-rotation.
   `.card` owns the drop animation (3D rotation + Z-translation + opacity).
   The split prevents the static rest transform from fighting the animated
   transform on the same element. */

.card-pose {
  position: absolute;
  transform-style: preserve-3d;
  will-change: transform;

  /* Centering offset so the card sits on its top/left position point
     rather than starting from it. Independent CSS `translate` property
     so it doesn't fight GSAP's `transform` writes (which carry the
     drop animation + fan-out tween). */
  translate: -50% -50%;
}

/* Ground shadow — a separate element behind the card that stays at the
   resting position regardless of the card's translateZ. Animated
   independently with the same bounce ease, so it tightens on every
   impact. This is the visual anchor for "the card is landing on the
   page surface" rather than on some abstract floor. */

.card-shadow {
  position: absolute;
  inset: 0;
  border-radius: 24px;
  background: rgba(15, 20, 25, 0.55);
  pointer-events: none;
  z-index: -1;
  will-change: transform, opacity, filter;
}

.card {
  --w: clamp(170px, 22vw, 240px);
  --h: clamp(200px, 26vw, 280px);

  position: relative;
  width: var(--w);
  height: var(--h);
  background: #b8c4d4;
  border-radius: 24px;
  overflow: hidden;
  transform-origin: 50% 50%;
  backface-visibility: hidden;
  will-change: transform, opacity;
  /* Hidden until the JS drop timeline animates them in. Prevents a
     flash of cards at their resting position before app.js runs. */
  opacity: 0;
}

.card__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Card's `overflow: hidden` clips to the rounded border. */
}

.card__label {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--paper);
  padding: 12px 14px;
  font-size: clamp(13px, 1.1vw, 15px);
  font-weight: 700;
  /* Label is white-on-light by default since body color cascades in;
     force ink so the company name reads against the white panel. */
  color: var(--ink);
  z-index: 1;
}

/* Per-card layout (top/left, resting rotation, entry tumble) is now
   generated by app.js with a seeded PRNG. The .card-pose elements get
   inline styles applied at boot and on every Tilt / Randomness slider
   change. Card sizes are uniform — no `.card--lg` variant. */

/* The drop animation is driven entirely by JS (Web Animations API) — see
   app.js. CSS just declares the resting state of the cards; JS pauses
   the animation at currentTime = 0 (above the page, invisible) until the
   scroll trigger fires, then plays it in real time. */

/* ─── Debug panel ─────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  /* JS bails out in reduced-motion mode; cards remain in CSS rest state. */
}

/* ─── Page sections (normal flow) ───────────────────────────────── */

.page-overlay {
  position: relative;
  width: 100%;
  /* Each section is at least one viewport tall so the layout reads
     as discrete sections that scroll into each other. Their internal
     content can extend further. */
  min-height: 100vh;
  /* No per-section bg or color — the section tracker writes both on
     <body>, which transitions between section palettes smoothly as
     the active section changes. Sections are transparent canvases. */
  color: inherit;
  background-color: transparent;
}

/* Investments paints its OWN navy surface instead of riding the body
   palette, so it scrolls up over the cream About/photo-ribbon as a
   discrete navy block — no whole-page crossfade (the tracker keeps
   bg/ink null for this section). Opaque bg covers the cream behind it;
   the fixed light ink themes the list text without a transition flash. */
.page-overlay[data-page="2"] {
  background-color: #001633;
  color: #e7ecf3;
}

/* Ideas paints its OWN dark surface so it scrolls up over the navy
   Investments section as a discrete block — same technique as
   Investments over About. Prevents the body palette crossfade
   (cream → dark) from flashing through as the section enters. */
.page-overlay[data-page="3"] {
  background-color: #071121;
  color: #e8e1d4;
}

/* Tight bottom padding on Our ideas so the carousel sits right
   under the lead, not 80-160px below it. */
.page-overlay[data-page="3"] .page-overlay__inner {
  padding-bottom: clamp(8px, 1vw, 16px);
}

/* A single hairline rule between the hero prose and the About section.
   It draws itself outward from the center as the section scrolls into
   view (JS adds .is-revealed; see app.js). */
.section-mark {
  /* Lives between .page and the first .page-overlay in document flow;
     the surrounding section padding centers it in the gap. Match
     .page's column so the line spans the same edges as the prose. */
  max-width: var(--col);
  margin: 0 auto;
  padding: 0 var(--pad-x);
}

.section-mark__line {
  display: block;
  width: 100%;
  height: 1px;
  /* Derive from the current ink so it reads on the navy About surface
     (light ink) as well as the cream sections. */
  background-color: color-mix(in srgb, currentColor 16%, transparent);
  /* Drawn out from the center on reveal. */
  transform: scaleX(0);
  transform-origin: center;
  transition: transform 0.85s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}

.section-mark.is-revealed .section-mark__line {
  transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
  .section-mark__line {
    transition: none;
    transform: scaleX(1);
  }
}

/* Both overlay titles inherit the body color and crossfade with it as
   the palette transitions, rather than carrying a fixed color that
   would flash against the still-changing background. (The About title
   rides the navy ink, the Investments title the cream ink.) */
.page-overlay[data-page="1"] .page-overlay__title,
.page-overlay[data-page="2"] .page-overlay__title {
  color: inherit;
  transition: color 0.6s ease;
}

.page-overlay__inner {
  max-width: 720px;
  margin: 0 auto;
  padding: clamp(80px, 12vw, 160px) var(--pad-x) clamp(80px, 12vw, 160px);
  text-align: left;
}

/* Investments runs a slightly wider column than the rest of the
   site so the list of companies has more breathing room. The 80px
   right-shift (only when the viewport is wide enough to fit the
   880 column without touching the edges) pins its left edge to the
   same rail as the 720px column used by About + Ideas, so the
   section reads as aligned with the others below. */
.page-overlay[data-page="2"] .page-overlay__inner {
  max-width: 880px;
}

@media (min-width: 1100px) {
  .page-overlay[data-page="2"] .page-overlay__inner {
    transform: translateX(80px);
  }
}

.page-overlay__title {
  margin: 0 0 clamp(20px, 2.5vw, 32px);
  font-family: var(--font-serif);
  font-size: var(--t-h1);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.18;
}

.page-overlay__lead {
  margin: 0 0 clamp(20px, 3vw, 36px);
  font-family: var(--font-sans);
  /* One click smaller than --t-body (16–19) so the lead sits a hair
     under the body baseline on the homepage's overlay sections. */
  font-size: clamp(15px, 1.2vw, 17px);
  line-height: 1.5;
  text-wrap: balance;
}

/* "View all perspectives" link beneath the Our ideas lead.
   Wraps the shared .invest__all chip in a positioned paragraph so
   the link sits cleanly between the lead and the carousel below. */
.page-overlay__more {
  margin: 0 0 clamp(20px, 3vw, 36px);
}

/* Shared eyebrow component — small sentence-case label (no caps, no
   tracking) used above section content (people column heading,
   "Select investments:" above the homepage list, etc.). Typography
   lives here; each
   place applies its own positional margin/padding through its
   container class. The selector is doubled (.eyebrow.eyebrow) to
   raise specificity to (0,2,0) so it outranks .page-overlay p
   (0,1,1) without needing !important. */
.eyebrow.eyebrow {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: normal;
  line-height: 1.4;
  color: inherit;
  opacity: 0.5;
}

/* Positional only — typography comes from the shared .eyebrow
   class that lives alongside this on the <p>. Top margin mirrors
   the .invest grid's margin-top below so the eyebrow sits centered
   between the lead above and the list below. */
/* .page-overlay p (0,1,1) zeroes out vertical margins on every p
   inside an overlay, so we anchor the eyebrow's spacing with a
   matched-specificity selector that comes later in source order. */
.page-overlay p.page-overlay__eyebrow {
  margin: clamp(40px, 5vw, 72px) 0 clamp(14px, 1.6vw, 22px);
}

/* "· View all investments →" appended to the eyebrow — inherits the
   eyebrow's small sentence-case styling; underlines on hover and the
   arrow nudges right to read as a link. */
.page-overlay__eyebrow-dot {
  margin: 0 9px;
}

.page-overlay__eyebrow-link {
  color: inherit;
  text-decoration: none;
}

.page-overlay__eyebrow-link:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.page-overlay__eyebrow-arrow {
  display: inline-block;
  margin-left: 5px;
  transition: transform 0.2s ease;
}

.page-overlay__eyebrow-link:hover .page-overlay__eyebrow-arrow {
  transform: translateX(3px);
}

.page-overlay p {
  margin: 0 0 1.1em;
  font-size: var(--t-body);
  line-height: 1.55;
}

/* Stats ─ three panels in a row, sharing the same rounded corners and
   treatment as the ribbon below. On the cream About surface they read
   as a white fill with a subtle dark-ink hairline outline. */
.stats {
  list-style: none;
  margin: clamp(40px, 5vw, 64px) 0 clamp(24px, 3vw, 32px);
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(12px, 1.5vw, 18px);
}

.stats__item {
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(15, 20, 25, 0.1);
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: clamp(22px, 2.6vw, 32px) clamp(12px, 1.6vw, 20px);
  text-align: center;
  transition:
    box-shadow 0.7s ease,
    border-color 0.7s ease;
}
.stats__item:hover {
  border-color: rgba(15, 20, 25, 0.18);
  box-shadow:
    0 14px 36px rgba(15, 20, 25, 0.08),
    0 4px 10px rgba(15, 20, 25, 0.04);
}

.stats__icon {
  width: clamp(16px, 1.4vw, 20px);
  height: clamp(16px, 1.4vw, 20px);
  color: rgba(15, 20, 25, 0.35);
  margin-bottom: clamp(6px, 0.8vw, 10px);
}

.stats__value {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 4px;
  font-family: var(--font-serif);
  font-size: clamp(36px, 4.6vw, 56px);
  font-weight: 500;
  line-height: 1;
  color: inherit;
  letter-spacing: -0.01em;
}

/* Reveal values ($3B, Early) start hidden + nudged down and animate in
   when the stats row scrolls into view (JS adds .is-revealed on the
   row). "$3B" comes in first; "Early" (data-stat-delay="1") trails it. */
.stats__value[data-stat-reveal] {
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.5s ease, transform 0.5s ease;
  transition-delay: 0.1s;
}

.stats__value[data-stat-reveal][data-stat-delay="1"] {
  transition-delay: 0.45s;
}

.stats.is-revealed .stats__value[data-stat-reveal] {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .stats__value[data-stat-reveal] {
    transition: none;
  }
}

.stats__label {
  margin-top: clamp(10px, 1.2vw, 14px);
  font-size: clamp(11px, 0.95vw, 13px);
  font-weight: 500;
  letter-spacing: normal;
  color: rgba(15, 20, 25, 0.5);
}

/* Ribbon ─ single panel, column-width, matching the stats cards:
   white fill + subtle dark-ink outline on cream. Heading sits at
   the top; logos slide horizontally below it. */
.ribbon {
  background: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(15, 20, 25, 0.1);
  border-radius: 14px;
  margin: 0 0 clamp(48px, 7vw, 80px);
  padding: clamp(20px, 2.4vw, 28px) 0 clamp(24px, 2.8vw, 32px);
  overflow: hidden;
}

.ribbon__heading {
  margin: 0 0 clamp(16px, 2vw, 22px);
  font-size: clamp(11px, 0.95vw, 13px);
  font-weight: 500;
  letter-spacing: normal;
  color: rgba(15, 20, 25, 0.5);
  text-align: center;
}

/* Viewport masks the track so logos crop in/out at the panel edges. */
.ribbon__viewport {
  overflow: hidden;
}

.ribbon__track {
  display: flex;
  align-items: center;
  gap: clamp(48px, 6vw, 88px);
  width: max-content;
  /* Extra left padding so the first logo (Hims) is fully visible
     once the parallax has carried the track inward by the time the
     ribbon is fully on-screen. */
  padding: 0 clamp(32px, 4vw, 56px) 0 clamp(96px, 10vw, 140px);
  will-change: transform;
}

.ribbon__logo {
  height: clamp(20px, 1.8vw, 28px);
  width: auto;
  flex: 0 0 auto;
  /* Logos are dark monochrome marks; render black on the cream panel. */
  filter: brightness(0);
  opacity: 0.65;
}

/* People section ─ secondary headline copy + horizontally
   scrolling card rows for each team. The intros live inside
   .page-overlay__inner; the card rows below break out of that
   column via a position trick (see .people). */
.people__intro {
  margin: clamp(40px, 5vw, 64px) 0 0;
  font-size: clamp(20px, 2.2vw, 28px);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.005em;
  /* No text-wrap: balance — lines should fill to the right edge so
     this paragraph reads with the same line economy as the lead p
     at the top of the section, instead of evenly-distributed short
     lines. */
}

.people__intro + .people__intro {
  margin-top: clamp(20px, 2.4vw, 28px);
}

/* Team directory ─ two stacked groups, each a horizontally
   scrolling row of portrait cards. The cards break out of the
   720px page column to full viewport width so additional cards
   are reachable via scroll/swipe. Headings stay aligned with the
   text column above via matching padding. */
.people {
  /* Break out of the .page-overlay__inner 720px column to span the
     full viewport, then re-pad horizontally so headings and the
     first card align with the text column above. */
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: 100vw;
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2.5vw, 32px);
  margin: clamp(40px, 5vw, 64px) 0 clamp(48px, 6vw, 72px);
}

/* Each group: heading + scrolling row of cards. --col-gutter is the
   inset that aligns heading text and the first card's left edge
   with the .page-overlay__inner column above. */
.people__col {
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 2vw, 24px);
  --col-gutter: max(
    var(--pad-x),
    calc((100vw - var(--col)) / 2 + var(--pad-x))
  );
}

/* Positional only — typography comes from the shared .eyebrow
   class that lives alongside this on the <h3>. */
.people__heading {
  margin: 0;
  padding: 0 var(--col-gutter);
}

.people__list {
  list-style: none;
  margin: 0;
  /* First card aligns to the column's left edge; row extends to the
     viewport's right edge (cards beyond are reachable via scroll).
     Generous vertical padding so the cards' drop-shadow isn't
     clipped — `overflow-x: auto` below forces `overflow-y` to behave
     like auto too (CSS spec quirk), so any shadow outside the box
     gets sliced. Padding here = shadow y-offset (8px) + blur (22px)
     with a touch of headroom. */
  padding: 8px var(--col-gutter) 32px;
  display: flex;
  gap: clamp(14px, 1.5vw, 20px);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  /* Click-and-drag + scroll-snap + momentum is wired up in app.js
     (the same handler as the Ideas carousel). scroll-padding-left
     keeps the snap point aligned with the column's left edge. */
  scroll-snap-type: x mandatory;
  scroll-padding-left: var(--col-gutter);
  cursor: grab;
}

.people__list.is-dragging {
  cursor: grabbing;
  user-select: none;
}

/* CTA pill below a people column. Sized via col-gutter so it spans
   from the column's left edge to its right edge — same rail the
   first card and the heading align to. Transparent fill with a
   hairline border (same alpha + ink mix used by .section-mark's
   horizontal rules) reads as a quiet "next step" button against
   the cream About surface; hover fills to solid white. */
.people__cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 var(--col-gutter);
  padding: clamp(16px, 1.8vw, 22px) clamp(22px, 2.4vw, 32px);
  background: transparent;
  /* Inherit the section ink (light on the navy About palette) and
     derive the border from it so the pill adapts across palettes. */
  color: inherit;
  border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: clamp(14px, 1.05vw, 16px);
  font-weight: 500;
  text-decoration: none;
  transition: background 0.18s ease, border-color 0.18s ease,
    color 0.18s ease, transform 0.18s ease;
}
.people__cta:hover {
  background: #ffffff;
  border-color: #ffffff;
  color: #0f1419;
}
.people__cta-arrow {
  font-size: 18px;
  transition: transform 0.18s ease;
}
.people__cta:hover .people__cta-arrow {
  transform: translateX(4px);
}

/* While dragging, neutralize click navigation on the underlying
   anchors so releasing on a card doesn't follow a link. */
.people__list.is-dragging a {
  pointer-events: none;
}

.people__list::-webkit-scrollbar {
  display: none;
}

.people__card {
  position: relative; /* containing block for .people__card-link */
  flex: 0 0 clamp(140px, 13vw, 180px);
  /* Photo fills the whole portrait tile; the info overlays the bottom.
     Source headshots are square, so a tile only slightly taller than
     square keeps cover's upscale (and the side crop / zoom) modest. */
  aspect-ratio: 4 / 5;
  scroll-snap-align: start;
  scroll-snap-stop: always;
  border-radius: 12px;
  overflow: hidden;
  box-shadow:
    0 8px 22px rgba(15, 20, 25, 0.07),
    0 2px 5px rgba(15, 20, 25, 0.04);
  /* Text sits over the image now, so default to light. */
  color: #fff;
  transition: transform 0.32s cubic-bezier(0.2, 1, 0.36, 1);
}

.people__card:hover {
  transform: translateY(-3px);
}

/* Portrait area. Photos live in /img/people/{slug}.jpg — set the
   matching --photo-url variable per-card below to swap in a real
   image. The gradient is the fallback / placeholder. */
.people__photo {
  /* Fills the entire tile behind the info overlay. */
  position: absolute;
  inset: 0;
  background-color: #2a3340;
  background-image: var(--photo-url);
  background-size: cover;
  background-position: center top;
}

/* Name + title/links overlay the bottom of the photo, sitting on a
   dark scrim that fades up so the light text stays legible over any
   portrait. */
.people__info {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: clamp(40px, 6vw, 60px) clamp(12px, 1.2vw, 16px)
    clamp(12px, 1.4vw, 16px);
  background: linear-gradient(
    to top,
    rgba(8, 12, 22, 0.88) 0%,
    rgba(8, 12, 22, 0.55) 45%,
    rgba(8, 12, 22, 0) 100%
  );
}

.people__card .people__name {
  margin: 0 0 3px;
  font-family: var(--font-sans);
  font-size: clamp(13px, 1vw, 15px);
  font-weight: 500;
  line-height: 1.2;
  color: inherit;
}

/* Title and links overlap in the same grid cell so the hover swap
   doesn't move the name above them. Title shows at rest; on card
   hover, title fades out and links fade in to occupy the same slot.
   min-height reserves 2 lines so cards with fewer/shorter links
   match the height of cards whose links wrap to 2 lines, keeping
   all names at the same vertical position across the row. */
.people__meta {
  display: grid;
  grid-template-areas: "stack";
  font-size: clamp(10px, 0.85vw, 12px);
  min-height: calc(2 * 1.3em);
}

.people__card .people__title,
.people__card .people__links {
  grid-area: stack;
  margin: 0;
  font-size: clamp(10px, 0.85vw, 12px);
  line-height: 1.3;
  color: inherit;
  transition: opacity 0.25s ease;
}

.people__card .people__title {
  opacity: 0.8;
}

.people__card .people__links {
  list-style: none;
  padding: 0;
  opacity: 0;
  pointer-events: none;
  /* Lift the whole links group above the card-link overlay (z-index 1).
     The group already forms a stacking context via opacity, so the
     inner .people__link z-index couldn't escape it — positioning the
     group itself is what puts the social links on top and keeps them
     clickable (the rest of the card still triggers the bio link). */
  position: relative;
  z-index: 2;
}

.people__card:hover .people__title {
  opacity: 0;
}

.people__card:hover .people__links {
  opacity: 1;
  pointer-events: auto;
}

/* Links render inline as a comma-separated underlined run. */
.people__links li {
  display: inline;
}

.people__links li:not(:last-child)::after {
  content: ", ";
}

.people__link {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Per-card photo URLs. Files dropped into img/people/{slug}.jpg
   will populate these automatically. */
.people__photo--kirsten-green   { --photo-url: url("img/people/kirsten-green.jpg"); }
.people__photo--eurie-kim       { --photo-url: url("img/people/eurie-kim.jpg"); }
.people__photo--nicole-johnson  { --photo-url: url("img/people/nicole-johnson.jpg"); }
.people__photo--jason-bornstein { --photo-url: url("img/people/jason-bornstein.jpg"); }
.people__photo--fawzi-itani     { --photo-url: url("img/people/fawzi-itani.jpg"); }
.people__photo--sam-o-donnell   { --photo-url: url("img/people/sam-odonnell.jpg"); }
.people__photo--tess-krensky    { --photo-url: url("img/people/tess-krensky.jpg"); }
.people__photo--jennifer-mariska { --photo-url: url("img/people/jennifer-mariska.jpg"); }
.people__photo--kira-mccroden   { --photo-url: url("img/people/kira-mccroden.jpg"); }
.people__photo--tandis-moeni    { --photo-url: url("img/people/tandis-moeni.jpg"); }
.people__photo--anthony-perez   { --photo-url: url("img/people/anthony-perez.jpg"); }
.people__photo--alicia-prodromou { --photo-url: url("img/people/alicia-prodromou.jpg"); }

.people__arrow {
  display: none;
}

/* ─── Photo ribbon (subtle parallax marquee) ──────────────────────
   Single-row strip of photos at the end of the About section, just
   under the people rows. The section sits in normal flow at the
   height of the photos themselves; app.js translates .photo-ribbon
   __track horizontally by a small fraction as the section moves
   through the viewport, producing a quiet drift rather than a full
   horizontal scroll takeover. */
.photo-ribbon {
  position: relative;
  width: 100%;
  height: clamp(280px, 48vh, 480px);
  margin-top: clamp(8px, 1vw, 16px);
  overflow: hidden;
}

@media (min-width: 2200px) {
  .photo-ribbon {
    height: clamp(480px, 26vw, 800px);
  }
}

.photo-ribbon__track {
  list-style: none;
  margin: 0;
  /* No edge padding — first photo's left edge sits at the viewport's
     left edge when the ribbon enters the bottom of the viewport. */
  padding: 0;
  display: flex;
  gap: 0;
  height: 100%;
  align-items: stretch;
  will-change: transform;
}

.photo-ribbon__track > li {
  flex: 0 0 auto;
  height: 100%;
  display: block;
}

/* Each photo keeps its natural aspect ratio. Height is normalized
   to the track height; width is auto from the intrinsic dimensions
   so widths vary naturally and photos sit flush against each other. */
.photo-ribbon__img {
  height: 100%;
  width: auto;
  display: block;
  object-fit: cover;
}

/* --- Prose ----------------------------------------------------- */

.prose {
  /* No max-width / padding here — the parent .page already pins to
     720px and applies var(--pad-x) horizontal padding. Adding either
     of those properties on .prose would double-inset the block
     relative to .page-overlay__inner (also 720px / pad-x), pushing
     the hero prose visibly to the right of the section headings
     further down the page. */
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: clamp(36px, 5vw, 56px);
}

.prose p {
  margin: 0;
  line-height: 1.45;
  /* No text-wrap: pretty — it rebalances the rag into a narrower
     effective measure, so the short hero paragraph read as a narrower
     column than the "About us" copy below (plain greedy wrap). Let it
     fill to the right edge to match. */
}

/* Soften body-copy paragraphs on the dark sections — the oxblood cover
   prose and the navy About intros. The full-strength light ink reads
   too harsh at paragraph size; dimming to ~75% keeps the hue but takes
   the glare off. Serif leads + headings keep full ink. */
.prose p:not(.prose__lead),
.page-overlay[data-page="1"] .page-overlay__inner > p {
  opacity: 0.75;
}

/* Two-word emphasis line that opens the prose block. Bigger than
   body copy, set in the serif so it reads as a statement rather
   than a paragraph. Selector is doubled (.prose .prose__lead) so
   it outranks .prose p on line-height. */
.prose .prose__lead {
  font-family: var(--font-serif);
  /* Match the section headings (e.g. "About us" / .page-overlay__title). */
  font-size: var(--t-h1);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.005em;
  text-align: center;
}

/* ─── Investments page ────────────────────────────────────────────
   Two-column layout: sticky filter sidebar on the left, scrolling
   company list on the right. Lives inside the wide overlay variant
   so it gets up to 1320px to breathe. Color tokens are scoped to
   the maroon palette via the [data-page="2"] block above. */

.invest {
  position: relative;
  display: grid;
  /* Sidebar on the right, list on the left. */
  grid-template-columns: 1fr 140px;
  gap: clamp(24px, 3.5vw, 48px);
  margin-top: clamp(40px, 5vw, 72px);
}

/* Cursor-anchored hover image for invest rows. Sits at z-index 0
   inside .invest (which is position: relative); the row text is
   raised to z-index 1 via the .invest__list rule so the image
   paints behind it. JS translates the image to mouse position on
   row hover and fades it in. */
.invest__hover-image {
  position: absolute;
  top: 0;
  left: 0;
  width: clamp(132px, 14.4vw, 216px);
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 10px;
  pointer-events: none;
  user-select: none;
  z-index: 0;
  opacity: 0;
  transform: translate3d(-9999px, -9999px, 0);
  transition: opacity 0.18s ease;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.55);
  will-change: transform, opacity;
}

.invest__hover-image.is-active {
  opacity: 1;
}

/* Hover chip — appears OVER specific rows (those with
   data-invest-quote) instead of the hover image. A compact chip with
   the plain string in Mori (sans), no quote formatting. GSAP drives
   its transform on hover (position + a goopy pop-in scale animation);
   the static rule keeps it invisible and off-screen at rest. */
.invest__quote {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  width: max-content;
  max-width: clamp(220px, 24vw, 300px);
  padding: 11px 16px;
  background: var(--paper);
  color: var(--ink);
  border-radius: 12px;
  pointer-events: none;
  user-select: none;
  opacity: 0;
  transform: translate3d(-9999px, -9999px, 0);
  transform-origin: 0 0;
  box-shadow:
    0 12px 30px rgba(15, 20, 25, 0.18),
    0 2px 6px rgba(15, 20, 25, 0.08);
  will-change: transform, opacity;
}

/* Plain string in Mori at ~15px — no serif, no quote marks. Selector
   is prefixed with .invest__quote so it outranks .page-overlay p
   (specificity 0,1,1), which would otherwise force var(--t-body). */
.invest__quote .invest__quote-text {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 15px;
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: normal;
}

/* Drop the attribution — the chip is just the text string. */
.invest__quote .invest__quote-attr {
  display: none;
}

/* Shown via GSAP on the homepage; toggled by class on content pages. */
.invest__quote.is-active {
  opacity: 1;
  transition: opacity 0.15s ease;
}

/* Raise the list and sidebar above the hover video so text reads
   on top of the playing clip. */
.invest__list,
.invest__side {
  position: relative;
  z-index: 1;
}

/* Both items are explicitly placed in row 1 so the grid auto-flow
   doesn't push the list (declared second in HTML) into row 2. */
.invest__list {
  grid-column: 1;
  grid-row: 1;
}

.invest__side {
  grid-column: 2;
  grid-row: 1;
}

.invest__side {
  display: flex;
  flex-direction: column;
  gap: clamp(22px, 2.4vw, 32px);
  /* Stays in view while the list scrolls past, anchored below the
     pinned nav (which sits at clamp(12px, 2vw, 20px) + its own height). */
  position: sticky;
  top: clamp(80px, 9vw, 110px);
  align-self: start;
  /* Inherits the body color so the sidebar themes correctly when
     the palette crossfades. Individual children handle their own
     dimming via opacity (rather than parent-level opacity, which
     would also dim the active filter pill). */
  color: inherit;
}

.invest__search input {
  width: 100%;
  padding: 8px 14px;
  background: color-mix(in srgb, currentColor 5%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  border-radius: 999px;
  color: inherit;
  font: inherit;
  font-size: 12px;
}

.invest__search input::placeholder {
  color: currentColor;
  opacity: 0.5;
}

.invest__search input:focus {
  outline: none;
  border-color: color-mix(in srgb, currentColor 50%, transparent);
  /* background-COLOR only — the shorthand `background:` would reset
     background-repeat to its default (repeat), tiling the inline
     magnifying-glass icon across the expanded mobile input. */
  background-color: color-mix(in srgb, currentColor 8%, transparent);
}

.invest__group-label {
  margin: 0 0 12px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: normal;
  color: inherit;
  opacity: 0.5;
}

.invest__filters {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.invest__filters button {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  font-size: 12px;
  color: inherit;
  text-align: left;
  cursor: pointer;
  /* Single-line at rest and active — labels like "Platforms &
     Infrastructure" extend visually past the 140px sidebar rather
     than wrapping, so toggling active doesn't change the row's
     vertical rhythm. */
  white-space: nowrap;
  /* Dim at rest so labels read as a secondary surface; full
     opacity on hover and when active (active state overrides via
     its own rule below). */
  opacity: 0.7;
  transition: opacity 0.2s ease;
}

.invest__filters button:hover {
  opacity: 1;
}

/* Active filter renders as a chartreuse pill with an x on the
   right. Negative left margin keeps the text x-position aligned
   with the non-active buttons in the same column so toggling on/off
   doesn't shift the label sideways. */
.invest__filters button.is-active {
  background: #d1ef59;
  color: var(--ink);
  padding: 4px 24px 4px 10px;
  margin-left: -10px;
  border-radius: 999px;
  position: relative;
  align-self: flex-start;
  opacity: 1;
}

.invest__filters button.is-active::after {
  content: "×";
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-52%);
  font-size: 14px;
  font-weight: 300;
  line-height: 1;
  opacity: 0.55;
  transition: opacity 0.2s ease;
}

.invest__filters button.is-active:hover {
  opacity: 1;
}

.invest__filters button.is-active:hover::after {
  opacity: 1;
}

/* The Sort group is a toggle (one mode always active), not a
   clearable filter — drop the trailing × and use symmetric padding
   while keeping the chartreuse active pill. */
.invest__group--sort .invest__filters {
  flex-direction: row;
  gap: 6px;
}

.invest__group--sort .invest__filters button.is-active {
  padding: 4px 12px;
  /* Neutralize the negative margin from .invest__filters
     button.is-active — that rule was designed for the vertical filter
     lists where the pill needs to align flush with the label rail.
     In the sort toggle the buttons are horizontal siblings, so the
     negative margin pulls the active pill over the previous button. */
  margin-left: 0;
}

.invest__group--sort .invest__filters button.is-active::after {
  content: none;
}

/* Company list ─ two columns: name+year on the left, with the
   description and tag line stacked in the right column. Grid areas
   let the head cell span both implicit rows without a wrapper. */
.invest__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.invest__row[hidden] {
  display: none;
}


.invest__row {
  display: grid;
  grid-template-columns: minmax(120px, 1fr) 2fr;
  grid-template-areas:
    "head desc"
    "head tags";
  column-gap: clamp(20px, 2.4vw, 40px);
  row-gap: clamp(6px, 0.8vw, 10px);
  padding: clamp(20px, 2.4vw, 32px) 0;
  /* Hairline divider derived from the current text color so it reads
     correctly across palettes (dark on cream, light on maroon). */
  border-bottom: 1px solid color-mix(in srgb, currentColor 16%, transparent);
  align-items: start;
}

.invest__row > .invest__head { grid-area: head; }
.invest .invest__desc { grid-area: desc; }
.invest .invest__tags { grid-area: tags; }

.invest__row:first-child {
  padding-top: 0;
}

.invest__row:last-child {
  border-bottom: 0;
}

/* CTA row at the end of the homepage's invest list — links to the
   full /investments/ index. Single full-width link, serif label,
   arrow that translates on hover. Inherits the row's border-top
   from the standard row rule above (no extra rule needed). */
.invest__row--all {
  display: block;
}

.invest__all {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  line-height: 1.2;
  color: inherit;
  text-decoration: none;
  transition: opacity 0.2s ease;
}

.invest__all:hover {
  opacity: 0.7;
}

.invest__all-arrow {
  display: inline-block;
  transition: transform 0.25s ease;
}

.invest__all:hover .invest__all-arrow {
  transform: translateX(6px);
}

.invest__head {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* Year + visit link share a row beneath the company name. The visit
   link is hidden at rest and fades in when the row is hovered, with
   a north-east arrow appended via ::after — matches the channels
   pattern in the Ideas section. */
.invest__meta {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.invest__visit {
  font-size: 11px;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: 0;
  transition: opacity 0.22s ease;
}

.invest__visit::after {
  content: "↗";
  margin-left: 3px;
  display: inline-block;
}

.invest__row:hover .invest__visit {
  opacity: 0.8;
}

.invest__visit:hover {
  opacity: 1;
}

.invest__ticker {
  font-size: 11px;
  opacity: 0;
  transition: opacity 0.22s ease;
  letter-spacing: 0.02em;
}

.invest__row:hover .invest__ticker {
  opacity: 0.55;
}

.invest__name {
  margin: 0;
  font-size: clamp(22px, 2.4vw, 32px);
  font-weight: 400;
  line-height: 1.15;
  /* Inherits the body color so it crossfades with the palette. The
     homepage Investments section now rides the cream palette (dark
     ink); the standalone /investments page is cream too. */
  color: inherit;
  transition: color 0.6s ease;
}

/* Row text dims at rest and brightens on row hover. Each row's name is
   the anchor; the rest of the row reads as a secondary layer until
   the user engages. Opacity drives the dim/bright shift so the
   underlying color stays inherited (and themes across palettes). */
.invest .invest__year,
.invest .invest__desc,
.invest .invest__tags {
  color: inherit;
  transition: opacity 0.32s ease;
}

.invest .invest__row:hover .invest__year {
  opacity: 0.6;
}
.invest .invest__row:hover .invest__desc {
  opacity: 0.95;
}
.invest .invest__row:hover .invest__tags {
  opacity: 0.7;
}

.invest__year {
  font-size: 13px;
  opacity: 0.3;
}

/* Selectors are prefixed with .invest so they outrank .page-overlay p
   (which would otherwise force these back to the body type scale). */
.invest .invest__desc {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  opacity: 0.55;
}

.invest .invest__tags {
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  opacity: 0.4;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Cascade fade-in for filter/search updates. The JS sets this
   animation (with a per-row delay) on every visible row after a
   filter change so the result set washes in instead of snapping. */
@keyframes investRowIn {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Collapse to single column on narrow viewports. */
/* ─── Mobile (≤820px) layout overrides ────────────────────────────
   Restructures three sections for phone-sized viewports:
     • People — two team columns stack; each card flips to a compact
       horizontal layout (name+title left, links right).
     • Invest — sidebar moves to the top of the section and becomes
       a sticky chip-bar with a search icon (expands on focus) and
       two tap-to-open filter dropdowns.
     • Ideas carousel — one card fills most of the viewport with a
       slim peek of the next card on the right.
   Touch devices don't hover meaningfully, so the ideas excerpt is
   shown by default at this size. */
@media (max-width: 820px) {
  /* People cards are already horizontal-scroll on all viewports;
     shrink the card on small screens so two cards plus a peek of a
     third fit per view — the peek communicates the swipe affordance
     more obviously than a half-card. */
  .people__card {
    flex-basis: clamp(140px, 40vw, 200px);
  }

  /* ── Invest: sticky filter bar at the top, dropdown filters ──
     Use plain block layout on phones instead of grid. The desktop
     grid (filter aside in col 2, list in col 1) traps each item in
     its own cell — a cell that, on mobile, is exactly the aside's
     own height, leaving position: sticky with zero scroll room. In
     block flow the aside lives at the top of its parent in normal
     document order and sticky pins to the viewport on scroll. */
  .invest {
    display: block;
  }
  .invest__side {
    /* Sticks below the floating site-nav. The nav itself sits at
       clamp(12px, 2vw, 20px) and is ~50px tall when stuck; this top
       value clears it. */
    position: sticky;
    /* Clears the floating site-nav (sits at clamp(12, 2vw, 20) with
       a ~50px content height) so the filter bar doesn't overlap it. */
    top: clamp(70px, 13vw, 84px);
    z-index: 20;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    padding: 10px 0;
    margin: 0 calc(var(--pad-x) * -1);
    padding-left: var(--pad-x);
    padding-right: var(--pad-x);
    /* Translucent navy backdrop matching the investments section
       palette (palette-2 = #001633). List rows scroll under cleanly
       via the blur. */
    background: color-mix(in srgb, #001633 92%, transparent);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-bottom: 1px solid rgba(240, 224, 220, 0.1);
    /* Subtle drop shadow below the bar so content scrolling under it
       has a visible "edge" to slide past — without this the bar reads
       as flush with the page surface. */
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.18);
    /* Breathing room below the bar at rest, so the first card isn't
       pinned to the bar's bottom border. */
    margin-bottom: clamp(20px, 3vw, 36px);
    color: #f0e0dc;
  }
  /* Homepage filter bar — a plain, full-column-width row that lives in
     the Investments section and simply scrolls away under the floating
     nav (NOT sticky). The search field is exposed with the Category +
     AI lens chips beside it; each element carries its own surface, so
     the row container is transparent. */
  .page-overlay[data-page="2"] .invest__side {
    position: static;
    top: auto;
    width: auto;
    max-width: none;
    margin: 0 0 clamp(20px, 3vw, 32px);
    padding: 0;
    background: transparent;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
    color: inherit;
    flex-direction: row;
    align-items: center;
    gap: 8px;
  }
  /* Homepage search behaves like the investments page mobile:
     collapses to an icon, expands on tap. This frees up space for
     the Category + AI Lens chips to appear beside it. */
  .page-overlay[data-page="2"] .invest__search {
    flex: 0 0 auto;
  }
  .page-overlay[data-page="2"] .invest__group {
    flex: 0 0 auto;
  }
  /* Standalone cream-palette pages (/investments, /perspectives)
     tint the sticky bar to match the page bg instead of leaking
     navy onto a light surface. Nearly-solid bg (98%) so card text
     scrolling under the bar is masked rather than visible through
     it — at 92% the content beneath bled through and read as a
     broken overlap rather than a clean sticky bar.

     The default top: clamp(70,13vw,84) was sized for the homepage's
     floating site-nav. Content pages don't have that nav, so park
     the bar flush against the top safe area instead — otherwise the
     previous card scrolls through the gap above the bar. */
  .content-page--investments .invest__side,
  .content-page--perspectives .invest__side {
    background: color-mix(in srgb, #efe9e1 98%, transparent);
    border-bottom-color: rgba(15, 20, 25, 0.15);
    color: var(--ink);
    top: env(safe-area-inset-top, 0px);
    /* Softer shadow on the cream surface — the dark default reads
       too heavy on a light bg. Same shape, lower alpha. */
    box-shadow: 0 6px 14px rgba(15, 20, 25, 0.07);
  }
  /* Search input + filter chips on cream pages need ink-on-cream
     contrast — the default treatment was cream-on-navy and rendered
     invisible against the light bg. Flip the surface tints, border
     colors, and the inline-SVG icon stroke. */
  /* Force collapsed width on high-specificity homepage selector. */
  .page-overlay[data-page="2"] .invest__search input {
    width: 36px;
  }
  /* Cream-palette pages: flip search to dark-on-light colours. */
  .content-page--investments .invest__search input,
  .content-page--perspectives .invest__search input {
    width: 36px;
    background-color: rgba(15, 20, 25, 0.04);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%230f1419' stroke-width='1.8'><circle cx='9' cy='9' r='6'/><path d='m13.5 13.5 4 4' stroke-linecap='round'/></svg>");
  }
  .content-page--investments .invest__search input:focus,
  .content-page--investments .invest__search input:not(:placeholder-shown),
  .content-page--perspectives .invest__search input:focus,
  .content-page--perspectives .invest__search input:not(:placeholder-shown) {
    background-color: rgba(15, 20, 25, 0.07);
  }
  /* Cream-palette content pages: flip chip colours to dark-on-light. */
  .content-page--investments .invest__group-label,
  .content-page--perspectives .invest__group-label {
    background: rgba(15, 20, 25, 0.04);
    border-color: rgba(15, 20, 25, 0.18);
    color: var(--ink);
  }
  /* No grid-row/column needed in block flow — both elements lay out
     in document order beneath the sticky aside. */
  .invest__row {
    /* Stack head / description / tags vertically on phones — the
       desktop two-column layout (head on left, desc + tags on right)
       leaves the name column too narrow for names like "Monarch
       Money" or "Hims Hers Health" to sit on one line, which makes
       the right edge of the head column read as ragged from row to
       row. Stacking gives every row the same right-edge rhythm.
       Resetting grid-template-areas alongside the column count is
       required: leaving the desktop "head desc / head tags" template
       in place forces an implicit second column even with
       grid-template-columns: 1fr. */
    grid-template-columns: 1fr;
    grid-template-areas:
      "head"
      "desc"
      "tags";
    gap: clamp(8px, 1.2vw, 12px);
    padding: clamp(16px, 2vw, 22px) 0;
  }
  /* Search collapses to a 36×36 icon; expands when focused or while
     it holds a query. The magnifying-glass icon is an inline SVG
     data URI so no asset roundtrip is needed. */
  .invest__search {
    flex: 0 0 auto;
  }
  .invest__search input {
    width: 36px;
    height: 36px;
    padding: 0 10px 0 32px;
    background-color: rgba(255, 255, 255, 0.04);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%23f0e0dc' stroke-width='1.8'><circle cx='9' cy='9' r='6'/><path d='m13.5 13.5 4 4' stroke-linecap='round'/></svg>");
    background-repeat: no-repeat;
    background-position: 10px center;
    background-size: 14px;
    /* iOS Safari auto-zooms any input whose computed font-size is
       below 16px when it gains focus. Pin to 16px on phones so the
       page doesn't yank into a zoomed-in view when the user taps
       the search field — the keyboard still opens, the input still
       expands, just without the zoom. */
    font-size: 16px;
    transition: width 0.28s ease, background-color 0.2s ease;
  }
  .invest__search input:focus,
  .invest__search input:not(:placeholder-shown) {
    /* Cap the expanded search at ~38vw so the Category + Year chips
       to its right still fit inside the viewport — at 50vw the chips
       got pushed off the right edge on focus. */
    width: clamp(120px, 38vw, 180px);
    background-color: rgba(255, 255, 255, 0.08);
  }
  /* Each filter group becomes a tappable chip that toggles a popup
     list of filters. JS toggles data-open on click; outside taps
     close the popup. */
  .invest__group {
    position: relative;
    /* Don't shrink beside the search field — keeps the chip from
       collapsing and wrapping its label ("AI lens" → two lines). */
    flex: 0 0 auto;
  }
  .invest__group-label {
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 36px;
    padding: 0 14px 0 14px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(240, 224, 220, 0.18);
    border-radius: 999px;
    color: #f0e0dc;
    font-size: 12px;
    letter-spacing: normal;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  .invest__group-label::after {
    content: "";
    width: 8px;
    height: 8px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    opacity: 0.7;
    transition: transform 0.2s ease;
  }
  .invest__group[data-open="true"] .invest__group-label::after {
    transform: rotate(-135deg) translate(-2px, -2px);
  }
  .invest__group .invest__filters {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    min-width: 220px;
    max-width: calc(100vw - 32px);
    z-index: 21;
    padding: 14px 16px;
    background: #001633;
    border: 1px solid rgba(240, 224, 220, 0.14);
    border-radius: 14px;
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.5);
    display: none;
    gap: 8px;
  }
  .content-page--investments .invest__group .invest__filters,
  .content-page--perspectives .invest__group .invest__filters,
  .page-overlay[data-page="2"] .invest__group .invest__filters {
    background: #efe9e1;
    border-color: rgba(15, 20, 25, 0.14);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18);
  }
  .invest__group[data-open="true"] .invest__filters {
    display: flex;
  }
  /* Active filters render as labels (no white pill) inside the popup
     so they fit the menu treatment. Active state is conveyed via
     opacity + the × indicator. */
  .invest__filters button.is-active {
    margin-left: 0;
    padding: 4px 24px 4px 10px;
  }

}

/* On touch-primary devices (phones/tablets) the hover image and quote
   panel are hidden entirely — iOS fires mouseover on tap but never
   mouseout, leaving panels stuck on screen. */
@media (hover: none) {
  .invest__hover-image,
  .invest__quote {
    display: none !important;
  }
}

@media (max-width: 820px) {
  /* ── Ideas carousel (mobile size lives below the desktop rules
     so source order lets it actually win — leaving it here would
     get overridden by the unscoped .ideas-card rule further down) ── */
  .ideas-carousel {
    margin: clamp(12px, 3vw, 24px) 0 clamp(60px, 10vw, 100px);
    padding: 8px 0 20px;
  }
  .ideas-carousel__track {
    /* Edge gutter matches the rest of the page; gap is the air
       between cards. */
    padding-left: var(--pad-x);
    padding-right: var(--pad-x);
    gap: 12px;
  }
  .ideas-carousel {
    scroll-padding-left: var(--pad-x);
  }
}

/* ─── Our Ideas carousel ─────────────────────────────────────────
   Horizontal scroll-snap row of article cards at the end of the
   Ideas overlay. Snaps each card to the left edge of the viewport
   with intro/outro padding so the first card aligns with the
   page's content gutter and the last has space on the right. */

.ideas-carousel {
  /* Sits tight to the lead — only a hair of breath. */
  margin: clamp(2px, 0.4vw, 6px) 0 clamp(80px, 10vw, 140px);
  padding: clamp(8px, 1.5vw, 16px) 0 clamp(20px, 3vw, 32px);
  overflow-x: auto;
  overflow-y: hidden;
  /* Proximity (not mandatory) so the user can scroll past the last
     card into the right-side runway. Mandatory snap would yank the
     scroll back to the final card no matter how much padding-right
     the track has. */
  scroll-snap-type: x proximity;
  /* Align snap point and first card with the left edge of the text
     column above. The calc mirrors the column's left edge so the
     first card lines up exactly with where the headline starts.
     Uses --content-col when set (article pages override it to 880px
     via .content-page--article), falling back to --col (720) for
     the homepage's narrower Ideas section. */
  scroll-padding-left: max(var(--pad-x), calc((100vw - var(--content-col, var(--col))) / 2 + var(--pad-x)));
  overscroll-behavior-x: contain;
  /* Hide the native scrollbar — drag/momentum/touch are the only
     scrolling affordances here. */
  scrollbar-width: none;
  /* Click-and-drag scrolling (mouse only — touch keeps native swipe). */
  cursor: grab;
}

.ideas-carousel.is-dragging {
  cursor: grabbing;
  user-select: none;
  /* Snap is suspended during drag so motion is smooth; the JS clears
     scrollSnapType inline on pointerdown and restores it on release. */
}

/* While dragging, neutralize click navigation on the underlying
   anchors so releasing on top of a card doesn't follow the link. */
.ideas-carousel.is-dragging .ideas-card__link {
  pointer-events: none;
}

.ideas-carousel::-webkit-scrollbar {
  display: none;
}

.ideas-carousel__track {
  list-style: none;
  margin: 0;
  /* First card's left edge sits at the column's left edge (matches
     scroll-padding-left on the carousel). The generous right
     padding leaves enough scroll runway that the last card can
     glide into the viewport's center rather than getting stuck at
     the right gutter. */
  padding-left: max(var(--pad-x), calc((100vw - var(--content-col, var(--col))) / 2 + var(--pad-x)));
  padding-right: 150vw;
  display: flex;
  gap: clamp(16px, 2vw, 24px);
}

/* Cards mirror the 9:16 portrait of the cover image. Sized at ~70%
   of the previous footprint while keeping the same aspect ratio. */
.ideas-card {
  flex: 0 0 clamp(154px, 18.2vw, 224px);
  aspect-ratio: 9 / 16;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

.ideas-card__link {
  position: relative;
  display: block;
  height: 100%;
  border-radius: 14px;
  overflow: hidden;
  color: #fff;
  text-decoration: none;
  background: #1a1a1a;
  box-shadow: 0 10px 30px rgba(15, 20, 25, 0.08),
              0 2px 6px rgba(15, 20, 25, 0.04);
  transition: transform 0.32s cubic-bezier(0.2, 1, 0.36, 1),
              box-shadow 0.32s ease;
}

.ideas-card__link:hover {
  transform: translateY(-6px);
  box-shadow: 0 18px 40px rgba(15, 20, 25, 0.18),
              0 4px 10px rgba(15, 20, 25, 0.08);
}

/* Cover art fills the entire card; text sits on top. */
.ideas-card__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  user-select: none;
  pointer-events: none;
}

/* Text overlay sits at the bottom of the card with a soft dark
   scrim that fades up into the image so the copy stays readable
   regardless of what the background image is doing in that region. */
.ideas-card__body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: clamp(40px, 5vw, 56px) clamp(16px, 1.8vw, 20px)
    clamp(18px, 2vw, 24px);
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.7) 0%,
    rgba(0, 0, 0, 0.4) 55%,
    rgba(0, 0, 0, 0) 100%
  );
}

/* Selectors are prefixed with .ideas-card so they outrank
   .page-overlay p / .page-overlay h3 rules, which would otherwise
   force the cards back to the body type scale. */
/* Category label suppressed across breakpoints — the date carries
   the meta strip alone. */
.ideas-card .ideas-card__category {
  display: none;
}

.ideas-card .ideas-card__meta {
  display: flex;
  /* Date sits alone on the left — the category is hidden everywhere
     so flex-start lines the date up with the title rail below. */
  justify-content: flex-start;
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: normal;
  color: rgba(255, 255, 255, 0.75);
}

.ideas-card .ideas-card__title {
  margin: 0;
  font-size: clamp(15px, 1.4vw, 19px);
  font-weight: 500;
  line-height: 1.2;
  color: #fff;
  text-wrap: balance;
}

/* Hidden at rest; the excerpt fades + expands in only when the card
   is hovered. max-height (rather than display) is animated so the
   reveal is smooth — the title slides up a touch as the excerpt
   opens beneath it, since the body is bottom-anchored. */
.ideas-card .ideas-card__excerpt {
  margin: 0;
  font-size: 10px;
  line-height: 1.4;
  color: rgba(255, 255, 255, 0.85);
  opacity: 0;
  max-height: 0;
  overflow: hidden;
  transition:
    opacity 0.32s ease,
    max-height 0.32s ease,
    margin-top 0.32s ease;
}

/* No excerpt reveal on hover — the card just lifts. The excerpt stays
   collapsed (and is display:none on mobile); the title carries the
   card. */

/* CTA variant — no photo, currentColor outline + centered serif
   call-to-action. The override to `color: inherit` lets the body's
   active palette flow in: light on the homepage's dark Ideas bg,
   ink on the cream article-bottom bg. */
.ideas-card--cta .ideas-card__link {
  background: transparent;
  border: 1px solid color-mix(in srgb, currentColor 35%, transparent);
  box-shadow: none;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(24px, 4vw, 40px);
  color: inherit;
  transition:
    transform 0.32s cubic-bezier(0.2, 1, 0.36, 1),
    background-color 0.25s ease,
    border-color 0.25s ease;
}

.ideas-card--cta .ideas-card__link:hover {
  transform: translateY(-6px);
  background: color-mix(in srgb, currentColor 6%, transparent);
  border-color: currentColor;
  box-shadow: none;
}

.ideas-card__cta {
  font-family: var(--font-serif);
  font-size: clamp(18px, 1.8vw, 24px);
  font-weight: 500;
  line-height: 1.2;
  color: inherit;
  letter-spacing: -0.005em;
  text-wrap: balance;
  transition: opacity 0.25s ease;
}

.ideas-card--cta .ideas-card__link:hover .ideas-card__cta {
  opacity: 0.8;
}

/* ── Ideas carousel — mobile sizing ──────────────────────────────
   Placed AFTER the desktop .ideas-card rules so source order lets
   this win when the media query matches. ~58vw cards (~70% of the
   previous near-full-viewport size) with the next card peeking on
   the right so the swipe affordance reads. Meta strip shows only
   the date (category hidden); excerpt hidden so the card reads as
   a tighter title-only tile. */
@media (max-width: 820px) {
  .ideas-card {
    flex: 0 0 calc(58vw - var(--pad-x));
    aspect-ratio: 9 / 14;
  }
  /* Excerpt is hidden on mobile — the title carries the card alone
     at this size. */
  .ideas-card .ideas-card__excerpt {
    display: none;
  }
  /* Title scales with the smaller card footprint. (Meta strip date
     left-align + category hide live in the base rules now, since
     they apply at every breakpoint.) */
  .ideas-card .ideas-card__title {
    font-size: clamp(15px, 3.6vw, 19px);
  }
}

/* --- Ideas footer (subscribe + channels) ----------------------- */

/* Tighten the carousel-to-newsletter gap on the Ideas section.
   The carousel's default bottom margin was sized for an empty
   section terminus; with content below, the newsletter row
   provides its own top padding via .ideas-foot__inner. */
.page-overlay[data-page="3"] .ideas-carousel {
  margin-bottom: clamp(20px, 3vw, 36px);
}

.ideas-foot__inner {
  /* Matches .page-overlay__inner's column so the subscribe module
     sits on the same left rail as the headline above and the first
     idea card to its left. The narrower .newsletter inside is then
     left-anchored within that column. */
  max-width: 720px;
  margin: 0 auto;
  padding: clamp(24px, 3vw, 40px) var(--pad-x) clamp(60px, 8vw, 100px);
}

/* Compact subscribe block. Left-aligned inside the page column. */
.newsletter {
  max-width: 360px;
}

.newsletter__heading {
  margin: 0 0 4px;
  font-size: clamp(15px, 1.3vw, 18px);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: inherit;
  text-wrap: balance;
}

/* Stacked list of subscribe-row + channels, separated by hairline
   borders. Each row inherits its color from the body so it
   transitions cleanly when the section palette crossfades. */
.newsletter__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.newsletter__row {
  padding: clamp(16px, 1.6vw, 22px) 0;
  /* Hairline derived from currentColor so it reads correctly on
     whatever palette is active behind the newsletter module. */
  border-bottom: 1px solid color-mix(in srgb, currentColor 22%, transparent);
}

.newsletter__row:last-child {
  border-bottom: 0;
}

.newsletter__row > a {
  position: relative;
  display: block;
  color: inherit;
  text-decoration: none;
  text-underline-offset: 4px;
  font-size: clamp(14px, 1.2vw, 16px);
  line-height: 1.3;
  transition: opacity 0.2s ease;
}

.newsletter__row > a:hover {
  opacity: 0.7;
}

/* Outbound social links (Substack, LinkedIn, X) — underline + a
   north-east arrow that both reveal on hover. The arrow is rendered
   via ::after so no DOM change is needed; opacity-and-translate
   animates it in for a gentle "departing" feel. */
.newsletter__out::after {
  content: "↗";
  margin-left: 6px;
  display: inline-block;
  opacity: 0;
  transform: translate(-2px, 2px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.newsletter__out:hover {
  text-decoration: underline;
  opacity: 1;
}

.newsletter__out:hover::after {
  opacity: 1;
  transform: translate(0, 0);
}

/* The input row — input fills the row's height, the subscribe pill
   sits at the right edge and slides in once the field has content.
   Reduced top padding so the email sits visually adjacent to the
   "Subscribe to our newsletter" overline rather than floating below
   it with a full row's worth of gap. */
.newsletter__row--input {
  display: flex;
  align-items: center;
  padding-top: 0;
}

.newsletter__form {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
}

.newsletter__input {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  outline: 0;
  background: transparent;
  font: inherit;
  font-size: clamp(14px, 1.2vw, 16px);
  line-height: 1.3;
  color: inherit;
}

.newsletter__input::placeholder {
  color: currentColor;
  opacity: 0.45;
}

/* Subscribe pill — hidden by default, slides in when the input has
   content. `input:placeholder-shown` is true when the field is
   empty, so the negated form drives the visible state. */
.newsletter__submit {
  flex: 0 0 auto;
  padding: 8px 18px;
  border: 0;
  border-radius: 999px;
  background: var(--ink);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.01em;
  cursor: pointer;
  /* Hidden state. transform feels nicer than a hard fade. */
  opacity: 0;
  transform: scale(0.92) translateX(8px);
  pointer-events: none;
  transition:
    opacity 0.22s ease,
    transform 0.22s cubic-bezier(0.2, 1, 0.36, 1),
    background 0.2s ease;
}

.newsletter__input:not(:placeholder-shown) ~ .newsletter__submit,
.newsletter__input:focus:not(:placeholder-shown) ~ .newsletter__submit {
  opacity: 1;
  transform: scale(1) translateX(0);
  pointer-events: auto;
}

.newsletter__submit:hover {
  background: rgba(15, 20, 25, 0.82);
}

.newsletter__submit:active {
  transform: scale(0.98);
}


/* --- Site footer ----------------------------------------------- */

/* Navy endcap that mirrors the cover treatment. Min-height 100vh
   ensures the footer is tall enough to scroll fully into. The
   section tracker registers this as a dark section so the sticky
   nav snaps back to its light-on-navy theme on entry. Content is
   pinned to the bottom-row: copyright on the left, utility links
   on the right. */
.site-footer {
  /* Transparent so the body's transitioning bg color shows through
     when scrolling into the footer (avoids a hard edge between the
     fading body and a fixed-navy footer during the crossfade). */
  background: transparent;
  color: inherit;
  display: flex;
  flex-direction: column;
  padding: clamp(28px, 3vw, 48px) var(--pad-x);
  /* One click below --t-nav (13–15) so the footer reads as a quiet
     utility row rather than competing with body type above. */
  font-size: clamp(11px, 0.85vw, 13px);
}

.site-footer__bottom {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(12px, 1.6vw, 24px);
  flex-wrap: wrap;
}

.site-footer__left {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: clamp(10px, 1.2vw, 16px);
}

.site-footer__copy {
  margin: 0;
  color: inherit;
  opacity: 0.85;
}


.site-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(10px, 1.2vw, 16px);
}

.site-footer__links a {
  color: inherit;
  opacity: 0.85;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 0.2s ease;
}

.site-footer__links a:hover {
  opacity: 1;
}


/* ─── Content pages ────────────────────────────────────────────────
   Shared design system for the static content pages (perspectives,
   privacy policy, content index, individual articles). Lives on the
   About-section cream palette so these pages feel like editorial
   extensions of the About surface rather than the cover. */

.content-page {
  background-color: #efe9e1;
  color: var(--ink);
  min-height: 100vh;
  /* Skip the homepage palette-crossfade transition on body — these
     pages don't change palettes mid-document. */
  transition: none;
}

/* ── Header ─────────────────────────────────────────────────── */
/* Header sits inside the same column as the page content below it,
   so the FORERUNNER wordmark's left edge lines up with the eyebrow
   and headline. Each page (via its body modifier class) sets
   --content-col to its column width — 1120 for the perspectives
   index, 880 for individual articles, 720 elsewhere. */
.content-page {
  --content-col: 1120px;
}
.content-page--article,
.content-page--investments,
.content-page--perspectives,
.content-page--legal,
.content-page--index {
  --content-col: 880px;
}
.content-page--error {
  background: #001633;
  color: #f0e0dc;
}
.content-page--error .content-header,
.content-page--error .content-header__back,
.content-page--error .content-header__sections a {
  color: #f0e0dc;
}
.content-page--error .content-header__sections {
  background: rgba(240, 224, 220, 0.1);
  box-shadow: none;
}
.content-page--error .content-header__sections a[aria-current="page"] {
  background: rgba(240, 224, 220, 0.18);
  color: #f0e0dc;
}
.content-page--error .content-footer {
  margin-top: 0;
  border-top: 1px solid rgba(240, 224, 220, 0.12);
  color: #f0e0dc;
}
.content-page--error .content-footer__left a,
.content-page--error .content-footer__links a {
  color: inherit;
}

.error-page {
  max-width: 720px;
  margin: 0 auto;
  /* Pull the block up near the header so the story cards stay in view;
     tight bottom keeps them close beneath the copy. */
  padding: clamp(8px, 1.5vw, 20px) var(--pad-x) clamp(20px, 2.5vw, 32px);
  text-align: center;
}
.error-page__headline {
  margin: 0 0 clamp(12px, 1.5vw, 20px);
  font-family: var(--font-serif);
  font-size: var(--t-h1);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.18;
}
.error-page__body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: clamp(15px, 1.2vw, 17px);
  line-height: 1.5;
  opacity: 0.65;
}
/* Spinning, draggable 3D "404" sitting above the copy, tucked tight to
   the headline. Transparent background so it floats; grab cursor
   signals the orbit. */
.error-page__model {
  display: block;
  width: 100%;
  height: clamp(200px, 30vh, 320px);
  margin: 0 auto clamp(8px, 1.2vw, 16px);
  background-color: transparent;
  --poster-color: transparent;
  cursor: grab;
}
.error-page__model:active {
  cursor: grabbing;
}
.error-page__carousel-header {
  margin-bottom: clamp(4px, 0.5vw, 8px);
}

/* Wrapper that gives the homepage's .invest module the right
   column width when it lives standalone on the /investments page.
   The invest-hero header sits at the same 880 column, so its title
   left-aligns with the company list below. */
.invest-page,
.perspectives-page,
.legal-page {
  max-width: var(--content-col, 880px);
  margin: 0 auto;
  padding: clamp(80px, 12vw, 160px) var(--pad-x) clamp(60px, 8vw, 100px);
}

/* Pages that open with a .page-hero navy band already get their
   breathing room from the hero block's bottom padding. Drop the
   wrapper's top padding AND zero out the .invest grid's top margin
   (originally sized for the homepage's "Select investments:"
   eyebrow above it) so the cream content sits flush against the
   navy edge — only the count's natural top margin separates them. */
.content-page--investments .invest-page,
.content-page--perspectives .perspectives-page {
  /* Breathing room between the navy/image hero above and the cream
     content list below — was too tight at clamp(16,2vw,28). */
  padding-top: clamp(40px, 5vw, 72px);
}
.content-page--investments .invest-page .invest,
.content-page--perspectives .perspectives-page .invest {
  margin-top: 0;
}
@media (max-width: 820px) {
  /* On phones the sticky filter bar carries its own vertical
     padding (10px top/bottom inside the bar) and the hero opens
     with a generous min-height. Drop the wrapper's top padding
     entirely so the chips sit right under the hero edge — the
     bar's own padding is the only breath needed. */
  .content-page--investments .invest-page,
  .content-page--perspectives .perspectives-page {
    padding-top: 0;
  }
}

/* Privacy policy body — sits below the .invest-hero header with the
   same column the header uses. Spacing between header and prose
   matches the rhythm on the other interior pages. */
.legal-page__body {
  margin-top: clamp(40px, 5vw, 72px);
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.65;
  color: rgba(15, 20, 25, 0.85);
}
.legal-page__body p { margin: 0 0 clamp(14px, 1.6vw, 22px); }
.legal-page__body h2 {
  margin: clamp(36px, 4vw, 56px) 0 clamp(12px, 1.4vw, 18px);
  font-family: var(--font-serif);
  font-size: clamp(20px, 2.2vw, 28px);
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink);
}
.legal-page__body h3 {
  margin: clamp(24px, 3vw, 36px) 0 clamp(10px, 1.2vw, 14px);
  font-family: var(--font-sans);
  font-size: clamp(15px, 1.2vw, 17px);
  font-weight: 500;
  color: var(--ink);
}
.legal-page__body ul {
  margin: 0 0 clamp(14px, 1.6vw, 22px);
  padding-left: 22px;
}
.legal-page__body li { margin: 0 0 8px; }
.legal-page__body a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}


/* Perspectives reuses the .invest grid (1fr 140px with a sticky
   right sidebar) so it inherits the search + filter sidebar shell.
   The list column wraps the count + list together so the count
   aligns with the article rows below. */
.perspectives-col {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  z-index: 1;
  min-width: 0;
}

.invest-hero {
  max-width: 600px;
}

.invest-hero__title {
  margin: 0 0 clamp(10px, 1.2vw, 16px);
  font-family: var(--font-serif);
  font-size: var(--t-h1);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.005em;
  color: var(--ink);
}

.invest-hero__lead {
  margin: 0;
  font-size: clamp(15px, 1.2vw, 18px);
  line-height: 1.5;
  color: rgba(15, 20, 25, 0.7);
}

.content-header {
  display: flex;
  align-items: center;
  width: 100%;
  max-width: var(--content-col);
  margin: 0 auto;
  padding: clamp(12px, 2vw, 20px) var(--pad-x);
  box-sizing: border-box;
}

/* ── Page hero (Investments / Perspectives splash) ───────────────
   Full-width navy band at the top of the page that holds the
   FORERUNNER wordmark plus the page title and short lead, all
   reversed out in white. Sits in normal document flow so it
   scrolls away as the user moves down into the filterable list
   beneath. */
.page-hero {
  background: #001633;
  color: #f0e0dc;
  padding-bottom: clamp(80px, 10vw, 140px);
}
.page-hero .content-header {
  /* Wordmark inherits the hero's light color; the back link's
     existing color: var(--ink) is overridden here. Keep the
     shared centered 880px column so the wordmark sits on the
     same left rail as the content list below, and the section
     nav lines up with the right edge of the filter sidebar. */
  color: #f0e0dc;
  justify-content: space-between;
}
.page-hero .content-header__back {
  color: inherit;
}
/* Image-driven hero variant — fills the section with a cover photo
   (e.g. /investments). Bypasses the navy fill. Title + lead, when
   provided, sit at the bottom of the hero over a soft dark scrim
   so they stay legible regardless of the photo content. */
.page-hero--image {
  position: relative;
  display: flex;
  flex-direction: column;
  background-color: #001633;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  min-height: clamp(360px, 50vh, 560px);
  padding-bottom: clamp(16px, 2.5vw, 36px);
}

/* Both /perspectives and /investments use a dark/ink FORERUNNER
   wordmark — the cream default disappears against the bright
   counter on /perspectives, and on /investments the dark ink
   sits above the dark scrim so it stays readable. The
   .page-hero .content-header { color: cream } rule above is more
   specific than the .content-page--* block, so override the back-
   link color directly too. */
.content-page--perspectives .page-hero .content-header,
.content-page--perspectives .page-hero .content-header__back,
.content-page--investments .page-hero .content-header,
.content-page--investments .page-hero .content-header__back {
  color: var(--ink);
}
.content-page--perspectives .page-hero__title {
  color: #fff;
}
.content-page--perspectives .page-hero__lead {
  color: rgba(255, 255, 255, 0.82);
}
/* Dark gradient at the bottom keeps the white type readable. */
.page-hero--image::after {
  content: "";
  position: absolute;
  inset: auto 0 0 0;
  height: 60%;
  background: linear-gradient(
    180deg,
    transparent,
    rgba(0, 0, 0, 0.55)
  );
  pointer-events: none;
  z-index: 0;
}
.page-hero--image .content-header,
.page-hero--image .page-hero__inner {
  position: relative;
  z-index: 1;
}
.page-hero--image .page-hero__inner {
  /* Push title block to the bottom of the hero. Keeps the shared
     centered 880px column so the title's left edge sits on the
     same rail as the wordmark above and the content list below. */
  margin-top: auto;
  padding-top: 0;
}
.page-hero__inner {
  width: 100%;
  max-width: var(--content-col, 880px);
  margin: 0 auto;
  padding: clamp(48px, 7vw, 112px) var(--pad-x) 0;
  box-sizing: border-box;
}
.page-hero__title {
  /* Matches the previous .invest-hero__title (--t-h1 22-36px) — the
     reverse-out treatment shouldn't change the type size. */
  margin: 0 0 clamp(10px, 1.2vw, 16px);
  font-family: var(--font-serif);
  font-size: var(--t-h1);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.005em;
  color: #fff;
}
.page-hero__lead {
  margin: 0;
  max-width: 720px;
  font-family: var(--font-sans);
  /* Pulled down from 15–18px so the lead fits comfortably on a
     single line at most viewport widths. */
  font-size: clamp(13px, 1vw, 15px);
  line-height: 1.5;
  color: rgba(240, 224, 220, 0.78);
}

.content-header__back {
  position: relative;
  display: inline-flex;
  align-items: center;
  color: var(--ink);
  text-decoration: none;
}

/* Back-affordance: a ← that fades in to the LEFT of the wordmark on
   hover, signalling the click returns to the home page. Absolutely
   positioned outside the link's box (right: 100%) so it never shifts
   the wordmark — whose left edge stays on the page text rail. It
   starts nudged right + invisible and settles into place on hover. */
.content-header__back::before {
  content: "\2190";   /* ← */
  position: absolute;
  right: 100%;
  top: 50%;
  margin-right: 10px;
  font-family: var(--font-sans);
  font-size: 13px;
  line-height: 1;
  color: inherit;
  opacity: 0;
  transform: translateY(-50%) translateX(6px);
  transition: transform 0.25s ease, opacity 0.25s ease;
}
.content-header__back:hover::before {
  opacity: 0.55;
  transform: translateY(-50%) translateX(0);
}

.content-header__wordmark {
  /* Bumped min so the FORERUNNER mark has presence on phones — at
     84px it read too small relative to the body type beneath. */
  width: clamp(128px, 11vw, 160px);
  height: auto;
  display: block;
  /* The glyph paths run flush to the viewBox edges (the "F" stem is at
     x=0, letter tops at y=0), so SVG's default overflow:hidden shaves
     the boundary anti-aliasing and the mark looks clipped. Let it
     paint past the box edge. */
  overflow: visible;
}

/* Section crumb sitting to the right of the wordmark on pages more
   than one level deep (perspective articles, explore companies +
   thematic). The right-pointing arrow acts as a breadcrumb separator,
   so the header reads as a path: FORERUNNER → Perspectives. The CSS
   pseudo-element draws the arrow so the source HTML stays clean. */
.content-header__crumb {
  margin-left: clamp(16px, 2vw, 28px);
  font-family: var(--font-sans);
  font-size: 13px;
  color: rgba(15, 20, 25, 0.6);
  text-decoration: none;
  transition: color 0.18s ease;
}
.content-header__crumb::before {
  content: "\2192";   /* → */
  margin-right: 8px;
  display: inline-block;
  transition: transform 0.3s ease;
}
.content-header__crumb:hover {
  color: var(--ink);
}
/* On hover the separator twirls a half-turn to face left, hinting the
   link takes you back to that section. */
.content-header__crumb:hover::before {
  transform: rotate(180deg);
}

/* Section nav (Perspectives / Investments) — a single pill module
   pushed to the right edge of the content-header. Mirrors the
   homepage's .site-nav treatment: cream outer pill with the active
   link as a dark inner chip. Sized small + right-aligned via
   margin-left: auto on the flex parent. */
.content-header__sections {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0;
  padding: 5px;
  background: rgba(255, 255, 255, 0.92);
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: var(--t-nav);
  letter-spacing: 0.02em;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.4) inset,
    0 4px 14px rgba(15, 20, 25, 0.08);
}
.content-header__sections a {
  font-size: inherit;
  color: var(--ink);
  opacity: 0.65;
  text-decoration: none;
  padding: 10px 16px;
  border-radius: 999px;
  transition: opacity 0.18s ease, background 0.18s ease, color 0.18s ease;
}
.content-header__sections a:hover {
  opacity: 1;
}
.content-header__sections a[aria-current="page"] {
  opacity: 1;
  background: var(--ink);
  color: #fff;
}

/* Right-side group: section pill + (mobile-only) hamburger trigger.
   Lets the page-hero header keep its space-between distribution
   without breaking the existing pill alignment. */
.content-header__right {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.content-header__right .content-header__sections {
  margin-left: 0;
}

/* Hamburger trigger — hidden on desktop, replaces the secondary
   nav links on mobile by sitting next to a stripped-down pill that
   shows only the active section. */
.mobile-nav-trigger {
  display: none;
}
.mobile-nav-trigger__line {
  display: block;
  width: 16px;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
  transition: transform 0.22s ease, opacity 0.18s ease;
}
/* While the overlay is open, the three lines collapse into an X
   centered in the same 36px circle so the hamburger reads as a
   close affordance. translateY values = (line gap + line height)
   ≈ 5.5px to slide outer lines into the middle row's center. */
body.mobile-nav-open .mobile-nav-trigger__line:nth-child(1) {
  transform: translateY(5.5px) rotate(45deg);
}
body.mobile-nav-open .mobile-nav-trigger__line:nth-child(2) {
  opacity: 0;
}
body.mobile-nav-open .mobile-nav-trigger__line:nth-child(3) {
  transform: translateY(-5.5px) rotate(-45deg);
}

/* Keep the content-header (FORERUNNER wordmark + close trigger)
   above the mobile-nav overlay so they stay visible / tappable
   when the menu is open. .page-hero doesn't create a stacking
   context (no z-index of its own), so the content-header inside
   shares the body's stacking context — z-index: 95 lands it just
   above the overlay's z-index: 90. */
body.mobile-nav-open .content-header {
  position: relative;
  z-index: 95;
}

@media (max-width: 820px) {
  /* Hide the section pill / breadcrumb entirely on mobile — the
     hamburger is the only nav affordance on small screens. */
  .content-header__sections,
  .content-header__crumb {
    display: none;
  }
  .mobile-nav-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    flex-direction: column;
    width: 36px;
    height: 36px;
    border-radius: 999px;
    /* Ink (black) circle with cream lines. */
    background: var(--ink);
    border: 0;
    color: #f0e0dc;
    cursor: pointer;
    padding: 0;
    box-shadow: 0 4px 14px rgba(15, 20, 25, 0.18);
    /* Sit above any scrim or absolutely-positioned hero pseudo so
       taps always land on the button. */
    position: relative;
    z-index: 5;
  }
}

/* ── Mobile nav overlay ─────────────────────────────────────────
   Full-screen menu that slides over the page when the hamburger
   is tapped. Stays hidden on desktop. Items use PP Mori for the
   primary stack, with utility links + legal links as smaller
   secondary tiers below. */
.mobile-nav {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: #efe9e1;
  color: var(--ink);
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  /* visibility delay until the opacity transition finishes so the
     overlay isn't clickable in its faded-out state. */
  transition: opacity 0.28s ease, visibility 0s linear 0.28s;
}
/* Hide before content.js runs (in case the [hidden] attribute is
   stripped late). */
.mobile-nav[hidden] {
  display: none;
}
/* Open state is driven by body.mobile-nav-open so the toggle is a
   single class flip — no juggling of element attributes or rAF
   timing. */
body.mobile-nav-open .mobile-nav {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 0.28s ease, visibility 0s linear 0s;
}
.mobile-nav__inner {
  /* Horizontal padding matches the content-header's var(--pad-x) so the
     menu items' left edge lines up with the FORERUNNER wordmark above. */
  padding: clamp(90px, 16vw, 130px) var(--pad-x) clamp(40px, 8vw, 64px);
  display: flex;
  flex-direction: column;
  gap: clamp(32px, 5vw, 48px);
  min-height: 100%;
}
.mobile-nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.mobile-nav__main {
  display: flex;
  flex-direction: column;
  gap: clamp(14px, 2.4vw, 22px);
}
.mobile-nav__main a {
  font-family: var(--font-sans);
  font-size: clamp(28px, 6vw, 40px);
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
}
.mobile-nav__main a[aria-current="page"] {
  font-weight: 500;
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 6px;
}
.mobile-nav__secondary {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.mobile-nav__secondary a {
  font-family: var(--font-sans);
  font-size: 14px;
  color: var(--ink);
  opacity: 0.75;
  text-decoration: none;
}
.mobile-nav__legal {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  font-size: 11px;
  color: rgba(15, 20, 25, 0.55);
}
.mobile-nav__legal a {
  color: inherit;
  text-decoration: none;
}
@media (min-width: 821px) {
  .mobile-nav {
    display: none;
  }
}
/* When the nav is open, freeze body scroll. */
body.mobile-nav-open {
  overflow: hidden;
}

/* ── Page hero ──────────────────────────────────────────────── */
.content-main {
  padding-bottom: clamp(80px, 10vw, 140px);
}

/* ── Prose blocks (privacy + article body) ──────────────────── */
.content-prose {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 var(--pad-x);
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.65;
  color: rgba(15, 20, 25, 0.85);
}

.content-prose--wide {
  max-width: 880px;
}

.content-prose p {
  margin: 0 0 clamp(14px, 1.6vw, 22px);
}

.content-prose ul {
  margin: 0 0 clamp(14px, 1.6vw, 22px);
  padding-left: 22px;
}

.content-prose li {
  margin: 0 0 8px;
}

.content-prose h2 {
  margin: clamp(36px, 4.5vw, 56px) 0 clamp(12px, 1.4vw, 18px);
  font-family: var(--font-serif);
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 500;
  line-height: 1.18;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-wrap: balance;
}

.content-prose h3 {
  margin: clamp(24px, 3vw, 40px) 0 clamp(8px, 1vw, 14px);
  font-family: var(--font-sans);
  font-size: clamp(15px, 1.2vw, 18px);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink);
}

.content-prose strong {
  color: var(--ink);
  font-weight: 500;
}

.content-prose a {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.content-prose a:hover {
  color: var(--ink);
}

/* ── Content index ──────────────────────────────────────────── */
.explore-group {
  margin: clamp(40px, 5vw, 64px) 0;
}

.explore-group__heading {
  margin: 0 0 clamp(6px, 0.8vw, 12px);
  font-family: var(--font-serif);
  font-size: clamp(20px, 2.2vw, 28px);
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink);
}

.explore-group__lead {
  margin: 0 0 clamp(20px, 2.4vw, 28px);
  font-style: italic;
  color: rgba(15, 20, 25, 0.55);
  font-size: clamp(13px, 1vw, 15px);
}

.explore-group__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  border-top: 1px solid rgba(15, 20, 25, 0.12);
}

.explore-group__list li {
  border-bottom: 1px solid rgba(15, 20, 25, 0.12);
}

.explore-group__list a,
.explore-group__list > li > span {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: clamp(12px, 1.4vw, 16px) 0;
  color: inherit;
  text-decoration: none;
  font-size: clamp(14px, 1vw, 16px);
}

.explore-group__list a:hover {
  opacity: 0.6;
}

.explore-group__arrow {
  opacity: 0.5;
  font-size: 14px;
}

.explore-group__list a:hover .explore-group__arrow {
  opacity: 1;
}

/* ── Perspectives index ─────────────────────────────────────── */
/* Count sits just above the article list, aligned with the list's
   left edge inside the .invest grid's column 1. */
.perspective-count {
  /* Margin-top kept small on desktop (filter is in a side column,
     no sticky bar above the count to clear). The mobile @media
     block bumps it up so the count clears the sticky filter bar. */
  margin: 0 0 clamp(14px, 1.6vw, 20px);
  font-size: 12px;
  letter-spacing: normal;
  color: rgba(15, 20, 25, 0.5);
}
@media (max-width: 820px) {
  .perspective-count {
    margin-top: clamp(32px, 4vw, 56px);
  }
}

.perspective-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid rgba(15, 20, 25, 0.12);
}

/* Padding lives on the card itself (not an inner link) so the borders
   span the full list width and only the headline is interactive. */
.perspective-card {
  border-bottom: 1px solid rgba(15, 20, 25, 0.12);
  padding: clamp(36px, 4.5vw, 64px) 0;
}

.perspective-card[hidden] {
  display: none;
}

/* Eyebrow at the top of each tease — date · category. Matches the
   shared .eyebrow component used on the homepage ("Select investments"
   etc.): 12px, uppercase, 0.14em tracking, 50% ink. */
.perspective-card__eyebrow {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0 0 clamp(12px, 1.4vw, 20px);
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: normal;
  line-height: 1.4;
  color: var(--ink);
  opacity: 0.5;
}

.perspective-card__title {
  margin: 0 0 clamp(14px, 1.6vw, 22px);
  font-family: var(--font-serif);
  font-size: clamp(24px, 3vw, 40px);
  font-weight: 500;
  line-height: 1.12;
  letter-spacing: -0.005em;
  color: var(--ink);
  text-wrap: balance;
}

/* Only the headline is the link / hover target. On hover it gets a
   full-ink underline — text-decoration is animatable in modern
   browsers; older ones just snap. */
.perspective-card__link {
  color: inherit;
  text-decoration: underline transparent;
  text-underline-offset: 5px;
  text-decoration-thickness: 1.5px;
  transition: text-decoration-color 0.18s ease;
}

.perspective-card__link:hover {
  text-decoration-color: var(--ink);
}

.perspective-card__author {
  margin: 0 0 clamp(22px, 2.6vw, 36px);
  display: flex;
  gap: 14px;
  /* Match the eyebrow size (13px) above the title. */
  font-size: 13px;
  color: rgba(15, 20, 25, 0.7);
}

.perspective-card__author-title {
  color: rgba(15, 20, 25, 0.45);
}

/* Body row: excerpt on the left, optional image on the right. The
   right track is only reserved when an image is present. */
.perspective-card__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(220px, 26%, 320px);
  gap: clamp(28px, 4vw, 72px);
  align-items: start;
}

/* No image → the body collapses to a single column so the excerpt
   fills the full content width instead of leaving an empty image gap. */
.perspective-card__body:not(:has(.perspective-card__media)) {
  display: block;
}
.perspective-card__body:not(:has(.perspective-card__media)) .perspective-card__excerpt {
  max-width: none;
}

.perspective-card__excerpt {
  margin: 0;
  font-size: clamp(14px, 1vw, 15px);
  line-height: 1.55;
  color: rgba(15, 20, 25, 0.85);
  max-width: 52ch;
}

/* Image hugs the right edge of its track and runs a touch smaller
   than the full track width. Rounded corners + overflow: hidden
   match the homepage's .ideas-card 14px radius so the image
   treatment reads consistently across the site. */
.perspective-card__media {
  grid-column: 2;
  justify-self: end;
  width: 100%;
  margin: 0;
  border-radius: 14px;
  overflow: hidden;
}

.perspective-card__media img {
  display: block;
  width: 100%;
  height: auto;
}

/* Stack the body on narrow screens — image drops below the excerpt. */
@media (max-width: 720px) {
  .perspective-card__body {
    grid-template-columns: 1fr;
    gap: clamp(18px, 4vw, 28px);
  }
  .perspective-card__media {
    grid-column: 1;
  }
}

/* ── Individual perspective article ─────────────────────────── */
.perspective-article {
  max-width: 880px;
  margin: 0 auto;
  padding: clamp(24px, 3vw, 40px) var(--pad-x) clamp(60px, 8vw, 100px);
}

.perspective-article__header {
  margin: 0 0 clamp(32px, 4vw, 56px);
}

.perspective-article__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  letter-spacing: normal;
  color: rgba(15, 20, 25, 0.55);
  margin-bottom: clamp(14px, 1.6vw, 22px);
}

.perspective-article__title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(30px, 4.8vw, 52px);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.015em;
  text-wrap: balance;
  color: var(--ink);
}

.perspective-article__byline {
  margin: clamp(14px, 1.6vw, 22px) 0 0;
  font-size: 13px;
  color: rgba(15, 20, 25, 0.7);
}

.perspective-article__byline-title {
  opacity: 0.6;
  margin-left: 10px;
}

.perspective-article__figure {
  margin: 0 0 clamp(28px, 3.5vw, 48px);
  border-radius: 14px;
  overflow: hidden;
}

.perspective-article__figure img {
  display: block;
  width: 100%;
  height: auto;
}

.perspective-article__body {
  margin: 0;
  padding: 0;
  max-width: 720px;
}
/* PP Mori only ships a regular weight, so the browser has nothing
   to swap in for the default font-weight: bolder on <strong>. Force
   font-synthesis: weight so the browser synthesizes a heavier face,
   and bump the explicit weight to 700 so the synthetic stroke is
   pronounced. Also deepen the color to fully-opaque ink so strong
   text reads heavier against the 70% body color. */
.perspective-article__body strong,
.person-page__body strong {
  font-weight: 700;
  font-synthesis: weight;
  color: var(--ink);
}

.perspective-article__body h5,
.perspective-article__body h6,
.person-page__body h5,
.person-page__body h6 {
  font-size: inherit;
  font-weight: 700;
  font-synthesis: weight;
  color: var(--ink);
  margin: 0;
}

.perspective-article__body ul,
.perspective-article__body ol,
.person-page__body ul,
.person-page__body ol {
  padding-left: 1.5em;
  margin: 0.75em 0;
}

.perspective-article__body li,
.person-page__body li {
  margin: 0.35em 0;
}

.perspective-article__body blockquote,
.person-page__body blockquote {
  margin: 1.5em 0;
  padding-left: 0;
  border-left: none;
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 21px;
  opacity: 0.85;
}

.perspective-article__body blockquote p,
.person-page__body blockquote p {
  margin: 0;
}

.perspective-article__body code,
.person-page__body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875em;
  background: rgba(15, 20, 25, 0.06);
  padding: 0.15em 0.4em;
  border-radius: 3px;
}

.perspective-article__body pre,
.person-page__body pre {
  margin: 1.5em 0;
  padding: 1.25em 1.5em;
  background: rgba(15, 20, 25, 0.05);
  border-radius: 8px;
  overflow-x: auto;
}

.perspective-article__body pre code,
.person-page__body pre code {
  background: none;
  padding: 0;
  font-size: 0.85em;
}

.perspective-article__body hr,
.person-page__body hr {
  border: none;
  border-top: 1px solid rgba(15, 20, 25, 0.15);
  margin: 2em 0;
}

.perspective-article__footer {
  margin: clamp(40px, 5vw, 64px) 0 0;
  padding-top: clamp(20px, 2.4vw, 32px);
  border-top: 1px solid rgba(15, 20, 25, 0.15);
  display: flex;
  justify-content: flex-start;
  align-items: center;
  gap: 16px;
  font-size: 13px;
  color: rgba(15, 20, 25, 0.65);
}

.perspective-article__footer a {
  color: inherit;
  text-decoration: none;
}

.perspective-article__footer a:hover {
  color: var(--ink);
}

.perspective-article__pdf-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 clamp(20px, 2.5vw, 32px);
  padding: 9px 18px 9px 14px;
  border-radius: 999px;
  border: 1px solid rgba(15, 20, 25, 0.3);
  color: var(--ink);
  font-size: 13px;
  text-decoration: none;
  transition: border-color 0.2s ease, opacity 0.2s ease;
}

.perspective-article__pdf-cta:hover {
  border-color: var(--ink);
}

.perspective-article__pdf-icon {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  opacity: 0.7;
}

/* ── Footer ─────────────────────────────────────────────────── */
/* Matches the homepage's footer layout: single bottom row with
   copyright + email on the left, utility links + LP login on the
   right. */
.content-footer {
  margin-top: clamp(40px, 5vw, 80px);
  padding: clamp(28px, 3vw, 48px) var(--pad-x);
  /* Matches .site-footer — one click below --t-nav so the footer
     reads as a quiet utility row. */
  font-size: clamp(11px, 0.85vw, 13px);
}

.content-footer__inner {
  max-width: 1120px;
  margin: 0 auto;
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(12px, 1.6vw, 24px);
  flex-wrap: wrap;
}

.content-footer__left {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: clamp(10px, 1.2vw, 16px);
}

.content-footer__copy {
  margin: 0;
  opacity: 0.85;
}

/* All anchor children of the footer's left + right groups share the
   same underlined link treatment so Privacy/Cookie/Content Index/etc
   all read as a single link group regardless of which side they sit on. */
.content-footer__left a,
.site-footer__left a {
  color: inherit;
  opacity: 0.85;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 0.2s ease;
}
.content-footer__left a:hover,
.site-footer__left a:hover { opacity: 1; }

/* Contact-us reveal — clicking once swaps the "Contact us" label for
   the email address with a quick slide-up + fade, then becomes a
   regular mailto on subsequent clicks. The overflow clip + inline-
   block on the text keep the slide tidy without affecting baseline. */
.content-footer__contact,
.site-footer__contact {
  position: relative;
  display: inline-block;
  overflow: hidden;
  vertical-align: baseline;
}
.content-footer__contact-text,
.site-footer__contact-text {
  display: inline-block;
  transition: opacity 0.14s ease, transform 0.14s ease;
}
.content-footer__contact.is-revealing .content-footer__contact-text,
.site-footer__contact.is-revealing .site-footer__contact-text {
  opacity: 0;
  transform: translateY(-110%);
}
.content-footer__contact.is-revealed .content-footer__contact-text,
.site-footer__contact.is-revealed .site-footer__contact-text {
  animation: contact-reveal 0.18s ease;
}
@keyframes contact-reveal {
  from { opacity: 0; transform: translateY(110%); }
  to   { opacity: 1; transform: translateY(0); }
}

.content-footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(10px, 1.2vw, 16px);
}

.content-footer__links a {
  color: inherit;
  opacity: 0.85;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 0.2s ease;
}

.content-footer__links a:hover {
  opacity: 1;
}

@media (max-width: 640px) {
  .perspective-article__footer {
    flex-direction: column;
    align-items: flex-start;
  }
}


/* ─── Article bottom (cards + subscribe on detail pages) ──────────
   Lives at the foot of every perspective article, just above the
   content-footer. Mirrors the homepage's "Our ideas" section but
   sits on the article page's cream palette (no own background). */
.article-bottom {
  /* Tight pairing with the article footer above — both margin-top
     and the section's own top padding were generous when the
     "Our ideas" treatment was a full hero block with its own
     headline + lead. With the simplified "Read more" eyebrow it
     reads as just an anchor before the carousel, so drop both. */
  margin-top: clamp(20px, 3vw, 36px);
  padding: clamp(20px, 3vw, 36px) 0 clamp(40px, 5vw, 64px);
}

.article-bottom__header {
  max-width: var(--content-col, 880px);
  margin: 0 auto clamp(16px, 2vw, 24px);
  padding: 0 var(--pad-x);
}

.article-bottom__title {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: 1.4;
  color: rgba(15, 20, 25, 0.55);
}

/* The carousel + subscribe inside .article-bottom use the existing
   .ideas-carousel and .newsletter components verbatim. They already
   work on the cream palette (newsletter borders use ink-tinted
   rgba; card images carry their own dark scrim). */

/* ── Cookie consent banner ─────────────────────────────────────
   Fixed-bottom modal injected by cookie-consent.js. Three-category
   prefs (Necessary always-on, Analytics, Marketing). Persists to
   localStorage["cookie-preferences"]; reopens via the
   "open-cookie-preferences" custom event (footer link). */
.cookie-consent {
  position: fixed;
  inset: auto 0 0 0;
  z-index: 9999;
  padding: clamp(16px, 2.4vw, 24px);
  display: flex;
  justify-content: center;
  pointer-events: none;
}

.cookie-consent__panel {
  pointer-events: auto;
  width: 100%;
  max-width: 560px;
  background: #fff;
  color: #0f1419;
  border-radius: 14px;
  padding: clamp(20px, 2.4vw, 28px);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25),
              0 4px 12px rgba(0, 0, 0, 0.08);
  font-family: var(--font-sans);
  transform: translateY(16px);
  opacity: 0;
  transition: transform 0.25s ease, opacity 0.25s ease;
}

.cookie-consent.is-visible .cookie-consent__panel {
  transform: translateY(0);
  opacity: 1;
}

.cookie-consent__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 12px;
}

.cookie-consent__title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 20px;
  font-weight: 500;
  letter-spacing: -0.005em;
}

.cookie-consent__close {
  background: none;
  border: 0;
  padding: 0;
  font-size: 22px;
  line-height: 1;
  color: rgba(15, 20, 25, 0.45);
  cursor: pointer;
  transition: color 0.18s ease;
}
.cookie-consent__close:hover { color: #0f1419; }

.cookie-consent__lead {
  margin: 0 0 18px;
  font-size: 13px;
  line-height: 1.55;
  color: rgba(15, 20, 25, 0.65);
}

.cookie-consent__categories {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  border-top: 1px solid rgba(15, 20, 25, 0.1);
}

.cookie-consent__category {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 0;
  border-bottom: 1px solid rgba(15, 20, 25, 0.1);
}

.cookie-consent__category-info h3 {
  margin: 0 0 4px;
  font-size: 13px;
  font-weight: 500;
  color: #0f1419;
}

.cookie-consent__category-info p {
  margin: 0;
  font-size: 12px;
  line-height: 1.45;
  color: rgba(15, 20, 25, 0.55);
}

/* Toggle switch — simple checkbox styled as a pill. */
.cookie-consent__switch {
  flex: 0 0 auto;
  position: relative;
  display: inline-block;
  width: 36px;
  height: 20px;
  margin-top: 2px;
}
.cookie-consent__switch input {
  position: absolute;
  opacity: 0;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}
.cookie-consent__switch input:disabled { cursor: not-allowed; }
.cookie-consent__switch span {
  position: absolute;
  inset: 0;
  background: rgba(15, 20, 25, 0.18);
  border-radius: 999px;
  transition: background 0.18s ease;
}
.cookie-consent__switch span::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 16px;
  height: 16px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
  transition: transform 0.2s ease;
}
.cookie-consent__switch input:checked + span { background: #0f1419; }
.cookie-consent__switch input:checked + span::after { transform: translateX(16px); }
.cookie-consent__switch input:disabled:checked + span { background: rgba(15, 20, 25, 0.4); }

.cookie-consent__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.cookie-consent__btn {
  flex: 1 1 auto;
  min-width: 0;
  padding: 10px 14px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  border: 1px solid rgba(15, 20, 25, 0.18);
  border-radius: 999px;
  background: #fff;
  color: #0f1419;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}
.cookie-consent__btn:hover { border-color: rgba(15, 20, 25, 0.4); }

.cookie-consent__btn--primary {
  background: #0f1419;
  color: #fff;
  border-color: #0f1419;
}
.cookie-consent__btn--primary:hover { background: #2a2f33; border-color: #2a2f33; }

@media (max-width: 480px) {
  .cookie-consent { padding: 12px; }
  .cookie-consent__actions { flex-direction: column; }
  .cookie-consent__btn { width: 100%; }
}

/* ── Thematic explore pages ────────────────────────────────────
   Three ported editorial pages at /explore/forerunner-ventures-ai,
   /explore/pitch-forerunner-ventures, /explore/the-cq-newsletter.
   Inherit content-page--article column width (880); these styles
   add the section rhythm, CTA button, and related-links footer. */
.explore-page {
  max-width: var(--content-col, 880px);
  margin: 0 auto;
  padding: clamp(80px, 12vw, 160px) var(--pad-x) clamp(60px, 8vw, 100px);
}

.explore-page__hero {
  max-width: 720px;
  margin-bottom: clamp(28px, 4vw, 48px);
  padding-bottom: clamp(28px, 4vw, 48px);
  border-bottom: 1px solid rgba(15, 20, 25, 0.12);
}

.explore-page__body {
  /* Each section gets generous breathing room between answers.
     Typography mirrors what .content-prose used to provide before
     this body broke out of that wrapper to share the parent's
     left rail. */
  display: flex;
  flex-direction: column;
  gap: clamp(40px, 5vw, 64px);
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.65;
  color: rgba(15, 20, 25, 0.85);
}

.explore-page__section h2 {
  margin: 0 0 clamp(12px, 1.4vw, 18px);
  font-family: var(--font-serif);
  font-size: clamp(20px, 2.2vw, 28px);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.005em;
  color: var(--ink);
}

.explore-page__section p {
  margin: 0 0 clamp(10px, 1.1vw, 14px);
}
.explore-page__section p:last-child { margin-bottom: 0; }

/* CTA button below content (used on the CQ newsletter page). */
.explore-page__cta {
  margin-top: clamp(8px, 1.2vw, 16px);
}
.explore-page__cta-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 22px;
  background: var(--ink);
  color: var(--paper);
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.18s ease, transform 0.18s ease;
}
.explore-page__cta-link:hover {
  background: #2a2f33;
  transform: translateY(-1px);
}
.explore-page__cta-arrow {
  transition: transform 0.18s ease;
}
.explore-page__cta-link:hover .explore-page__cta-arrow {
  transform: translate(2px, -2px);
}

/* Related links footer — small uppercase eyebrow + linked list. */
.explore-page__related {
  margin-top: clamp(56px, 7vw, 88px);
  padding-top: clamp(28px, 3vw, 40px);
  border-top: 1px solid rgba(15, 20, 25, 0.12);
}
.explore-page__related h3 {
  margin: 0 0 clamp(14px, 1.6vw, 22px);
}
.explore-page__related ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.explore-page__related a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: rgba(15, 20, 25, 0.75);
  font-size: 14px;
  text-decoration: none;
  transition: color 0.18s ease;
}
.explore-page__related a:hover { color: var(--ink); }
.explore-page__related-arrow {
  font-size: 12px;
  opacity: 0.55;
  transition: transform 0.18s ease, opacity 0.18s ease;
}
.explore-page__related a:hover .explore-page__related-arrow {
  transform: translate(2px, -2px);
  opacity: 1;
}

/* ── Explore index page ────────────────────────────────────────
   Wrapper styling for the /explore/ hub page. Reuses .invest-hero
   for the title block and the existing .explore-group components
   for each grouping below. */
.explore-index {
  max-width: var(--content-col, 720px);
  margin: 0 auto;
  padding: clamp(80px, 12vw, 160px) var(--pad-x) clamp(60px, 8vw, 100px);
}

.explore-index__hero {
  max-width: 600px;
  margin-bottom: clamp(36px, 5vw, 60px);
  padding-bottom: clamp(28px, 4vw, 48px);
  border-bottom: 1px solid rgba(15, 20, 25, 0.12);
}

.explore-index__body {
  display: flex;
  flex-direction: column;
  gap: clamp(32px, 4vw, 56px);
  font-size: clamp(15px, 1.1vw, 17px);
  line-height: 1.65;
  color: rgba(15, 20, 25, 0.85);
}

/* ── Explore company page facts block ──────────────────────────
   Year/Stage/AI Lens/Lead Partner caption that sits below the hero
   title on each /explore/<slug> company page. Renders inline,
   wrapping on narrow viewports. */
.explore-company__facts {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(16px, 2vw, 28px);
  margin-top: clamp(16px, 2vw, 24px);
  font-family: var(--font-sans);
  font-size: 12px;
  color: rgba(15, 20, 25, 0.6);
}

.explore-company__fact {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
}

.explore-company__fact-label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: normal;
  opacity: 0.65;
}

.explore-company__fact-value {
  font-size: 13px;
  color: var(--ink);
}

/* ── Person card link + bio page ──────────────────────────────
   Each person card on the homepage has an invisible absolute-
   positioned anchor that covers the full card so clicking anywhere
   navigates to the bio page. The social-link anchors below raise
   themselves above this overlay (z-index 2) so they remain their
   own click targets. HTML doesn't allow nested anchors, so we use
   this overlay pattern instead. */
.people__card-link {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* No visible content — the link is purely a click surface.
     aria-label on the anchor describes the destination. */
}
.people__link {
  position: relative;
  z-index: 2; /* keeps social links clickable above the overlay */
}

/* "Bio coming soon" placeholder used on stub person pages while
   the real content is being written. */
.explore-page__placeholder {
  margin: 0;
  font-style: italic;
  opacity: 0.6;
}

/* ── Person bio — split layout ──────────────────────────────────
   Desktop: content (name + role + links + bio sections) lives in
   the LEFT half and scrolls; the editorial portrait fills the
   RIGHT half, sticky to the top of the viewport.
   Mobile: photo sits centered above the name, in normal flow.

   Layout depends on getting the .person-page grid to start at the
   very top of the viewport so the sticky photo can pin to top: 0
   without a gap. On the content-page shell, .content-header sits
   in normal flow above .content-main — we float it out to the
   left half via absolute positioning on person pages only, leaving
   .content-main free to start at y=0. */
.content-page--person .content-header {
  position: absolute;
  top: 0;
  left: 0;
  width: 50%;
  z-index: 2;
  /* Strip the shared centered-column treatment so the back link
     positions itself directly against the viewport. Vertical
     padding gives the wordmark room above the page. */
  max-width: none;
  margin: 0;
  padding: clamp(24px, 3vw, 36px) 0;
}
/* Stay compact (just wraps the wordmark) so the arrow ::before —
   anchored at right: 100% of this element — sits right next to
   the wordmark's left edge. Position the whole link via margin-
   left so its left edge tracks .person-page__content's text rail
   at every viewport width:
     margin-left = max(col-pad, 50vw − col-box + col-pad)
   where col-box is the bio's outer box (max-width 620 + padding
   64 on each side = 748). At narrow viewports the column has no
   excess room, so margin-left collapses to col-pad. At wide
   viewports the bio is right-aligned within the half-column, so
   the wordmark inherits the same right-aligned offset. */
.content-page--person .content-header__back {
  display: inline-flex;
  align-items: center;
  /* Global box-sizing: border-box means the bio's max-width: 620
     is the TOTAL box width, not its content area. Element's
     margin-left = max(0, 50vw - 620), and the text content sits
     padding-left further in. Mirror that exactly here so the
     wordmark tracks the bio text's left rail. */
  margin-left: max(
    clamp(24px, 4vw, 64px),
    calc(50vw - 620px + clamp(24px, 4vw, 64px))
  );
}
.content-page--person .content-main {
  padding-top: 0;
  padding-bottom: 0;
}

/* Pull the footer up so it visually overlaps the bottom of the
   photo column. Negative margin-top + matching extra bottom padding
   on the content column keeps the text from being hidden by the
   footer row. The right-side links sit over the photo (reversed
   out to white below), the left-side items stay on the cream
   content surface. */
.content-page--person .content-footer {
  margin-top: clamp(-160px, -10vw, -80px);
  position: relative;
  z-index: 3;
}
.content-page--person .person-page__content {
  /* Extra room at the bottom so the last paragraph doesn't slide
     under the footer's overlap. */
  padding-bottom: clamp(120px, 14vw, 200px);
}
.content-page--person .content-footer__links a,
.content-page--person .content-footer__links a:hover {
  color: #fff;
}

.person-page {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
}

/* Explicit column placement so source order can stay photo-first
   (mobile single-column reads as FORERUNNER → photo → name) while
   desktop renders content on the left and photo on the right. */
.person-page__content {
  grid-column: 1;
  grid-row: 1;
  /* Top padding clears the absolute FORERUNNER header above. */
  padding:
    clamp(120px, 14vw, 200px)
    clamp(24px, 4vw, 64px)
    clamp(80px, 10vw, 140px);
  max-width: 620px;
  margin-left: auto;
  margin-right: 0;
  width: 100%;
}

.person-page__photo {
  grid-column: 2;
  grid-row: 1;
  /* Sticky inside the grid — at scroll: 0 the photo's natural
     position is the top of .person-page (which sits at the top of
     content-main with no padding above), so it already aligns with
     viewport top. Once the user scrolls past, top: 0 keeps it
     pinned until the bottom of .person-page passes the viewport. */
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  overflow: hidden;
}

.person-page__photo-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center top;
}

/* ── Fun-fact pills (1–4 floating bubbles around the portrait) ──
   Mirrors the homepage promo-pill treatment (rounded white pill,
   soft drop-shadow, snappy pop-in animation with a slight scale
   overshoot) but in white-on-ink for readability against the
   photo. Slot numbers map to fixed corner positions; cards with
   fewer than 4 facts just leave later slots empty. */
.person-page__facts {
  position: absolute;
  inset: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  pointer-events: none;
}

.person-page__fact {
  position: absolute;
  max-width: clamp(180px, 22vw, 280px);
  padding: 12px 20px;
  background: #fff;
  color: var(--ink);
  border-radius: 999px;
  font-family: var(--font-sans);
  font-size: clamp(13px, 0.95vw, 15px);
  line-height: 1.35;
  letter-spacing: 0.005em;
  box-shadow:
    0 12px 28px rgba(15, 20, 25, 0.22),
    0 2px 4px rgba(15, 20, 25, 0.1),
    0 1px 0 rgba(255, 255, 255, 0.7) inset;
  pointer-events: auto;
  cursor: pointer;
  /* Pop-in: same snappy back-out curve as .join-pill but slower so
     each pill takes its time settling in. Each slot uses its own
     delay below to stagger the entrance with ~0.6s of dwell between
     pills. */
  opacity: 0;
  transform: scale(0.7) translateY(12px);
  animation: factPopIn 0.8s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.person-page__fact--1 {
  top: 6%;
  left: 4%;
  animation-delay: 0.5s;
  transform-origin: bottom left;
}
.person-page__fact--2 {
  top: 38%;
  right: 4%;
  animation-delay: 1.1s;
  transform-origin: bottom right;
}
.person-page__fact--3 {
  top: 70%;
  left: 4%;
  animation-delay: 1.7s;
  transform-origin: top left;
}
.person-page__fact--4 {
  /* Sit above the footer's overlap zone (footer's margin-top is
     clamp(-160, -10vw, -80) plus its own ~80–110px height). Using
     px on bottom keeps this clearance fixed regardless of how tall
     the viewport is. */
  bottom: clamp(160px, 18vw, 240px);
  right: 4%;
  animation-delay: 2.3s;
  transform-origin: top right;
}

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

/* Click-to-dismiss — fades the pill out with a faster ease-in so
   the gesture feels responsive. !important on animation-delay
   neutralizes the staggered delay from the slot rule above so the
   dismissal fires immediately on click rather than reusing the
   stagger offset. */
.person-page__fact.is-dismissed {
  animation: factPopOut 0.45s cubic-bezier(0.45, 0, 0.55, 1) forwards;
  animation-delay: 0s !important;
  pointer-events: none;
}

@keyframes factPopOut {
  from {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
  to {
    opacity: 0;
    transform: scale(0.7) translateY(8px);
  }
}

.person-page__hero {
  margin-bottom: clamp(28px, 4vw, 48px);
  padding-bottom: clamp(20px, 3vw, 36px);
  border-bottom: 1px solid rgba(15, 20, 25, 0.12);
}

.person-page__name {
  margin: 0 0 clamp(8px, 1vw, 14px);
  font-family: var(--font-serif);
  font-size: clamp(28px, 3.4vw, 44px);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.person-page__role {
  margin: 0;
  font-size: clamp(15px, 1.1vw, 17px);
  color: rgba(15, 20, 25, 0.6);
}

.person-page__body {
  /* Tighter rhythm than .explore-page__body's defaults — bio prose
     is denser than the explore Q&A blocks. */
  gap: clamp(24px, 3vw, 36px);
}

@media (max-width: 820px) {
  /* Single column on phones: FORERUNNER header back in normal flow,
     photo centered above the name (not sticky), content below.
     Footer drops the overlap + white-link treatment since there's
     no photo behind it at this width. */
  .content-page--person .content-header {
    position: static;
    width: auto;
    /* Restore the shared header's centered-column treatment. */
    max-width: var(--content-col);
    margin: 0 auto;
    padding: clamp(24px, 3vw, 36px) var(--pad-x);
  }
  .content-page--person .content-header__back {
    /* Drop the column-rail margin; let the back link sit at the
       natural left of the centered header again. */
    margin-left: 0;
  }
  .content-page--person .content-main {
    padding-top: 0;
    padding-bottom: clamp(40px, 8vw, 80px);
  }
  .content-page--person .content-footer {
    margin-top: 0;
  }
  .content-page--person .content-footer__links a {
    color: inherit;
  }
  .content-page--person .person-page__content {
    padding-bottom: clamp(60px, 10vw, 100px);
  }
  .person-page {
    grid-template-columns: 1fr;
  }
  .person-page__photo,
  .person-page__content {
    grid-column: auto;
    grid-row: auto;
  }
  .person-page__photo {
    position: static;
    height: auto;
    margin: clamp(8px, 2vw, 20px) auto clamp(24px, 4vw, 40px);
    width: clamp(220px, 70vw, 360px);
    aspect-ratio: 4 / 5;
    border-radius: 12px;
  }
  .person-page__photo-img {
    border-radius: inherit;
  }
  /* Pills can't float around a small phone-sized portrait — restack
     them as a centered list below the photo. Same pop-in stagger
     still fires; positions just collapse to flow. */
  .person-page__facts {
    position: static;
    margin: clamp(16px, 3vw, 24px) auto 0;
    padding: 0 var(--pad-x);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
  }
  .person-page__fact,
  .person-page__fact--1,
  .person-page__fact--2,
  .person-page__fact--3,
  .person-page__fact--4 {
    position: static;
    inset: auto;
    top: auto;
    right: auto;
    bottom: auto;
    left: auto;
    max-width: min(340px, 100%);
  }
  .person-page__content {
    padding:
      0
      clamp(20px, 5vw, 32px)
      clamp(60px, 10vw, 100px);
    max-width: none;
    margin: 0 auto;
  }
}

/* Row of off-site links (LinkedIn, Substack, X, …) under the title
   in a person's bio hero. Smaller font + larger margin-top than the
   rest of the hero so it reads as a quiet secondary row, well
   separated from the title block above it. */
.person-page__links {
  list-style: none;
  margin: clamp(16px, 2vw, 24px) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(14px, 1.8vw, 24px);
  font-size: 12px;
}
.person-page__links a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  opacity: 0.6;
  transition: opacity 0.18s ease;
}
.person-page__links a:hover { opacity: 1; }

/* ── Portrait lock (phones) ──────────────────────────────────────
   The layout is designed for portrait, and a web page can't truly
   lock orientation on iOS Safari (no Screen Orientation API for
   browser tabs, and the PWA manifest only applies when installed).
   So when a phone is held in landscape we cover the viewport with a
   "rotate to portrait" prompt. Scoped to short + landscape + touch
   viewports so it never fires on desktops (mouse = pointer: fine) or
   tablets (landscape height > 500px). */
@media (orientation: landscape) and (max-height: 500px) and (pointer: coarse) {
  body::before {
    content: "Please rotate your device\A to portrait.";
    white-space: pre-line;
    position: fixed;
    inset: 0;
    z-index: 100000;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 24px;
    background: #301111;
    color: #f0e0dc;
    font-family: var(--font-sans);
    font-size: clamp(15px, 4.8vw, 20px);
    line-height: 1.5;
    letter-spacing: 0.01em;
  }
}

/* ── Visually hidden utility ──────────────────────────────────────
   Hides content visually while keeping it accessible to screen
   readers. Use on labels, hints, and off-screen announcements that
   should not affect visual layout. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* ── Focus indicators ─────────────────────────────────────────────
   Keyboard-visible outlines for interactive elements that rely on
   custom styling (links, buttons, filter chips). Uses :focus-visible
   so mouse users are not affected. */
.invest__row a:focus-visible,
.ideas-card__link:focus-visible,
.perspective-card__link:focus-visible,
.site-nav__link:focus-visible,
.content-header__sections a:focus-visible,
.content-header__back:focus-visible,
.invest__all:focus-visible,
[data-filter-slot]:focus-visible,
[data-sort-mode]:focus-visible,
[data-mobile-nav-trigger]:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

/* ── Reduced-motion ───────────────────────────────────────────────
   Disable animations and transitions for users who prefer reduced
   motion. This block intentionally uses !important to override any
   per-component animation declarations. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
