/*
Theme Name: Fortunity Capital v3
Theme URI: https://fortunitycapital.com
Author: Fortunity Capital
Author URI: https://fortunitycapital.com
Description: Deep-tech venture capital marketing theme — Fortunity Capital. Cipher-style minimal layouts on a deep-blue base, with GSAP-driven scroll choreography (typewriter thesis, horizontal Forge·Fulfil·Fortify, lightsaber stat table) and a halftone dot-grid team page. Four pages — Home, Team, Contact and an unlisted Pitch form — each editable in its own Customizer panel. Self-hosted fonts and GSAP: no external calls.
Version: 3.7.0
Requires at least: 6.0
Tested up to: 6.6
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: fortunity-capital
*/
/* =================================================================
   FORTUNITY CAPITAL — v3 home
   Fortunity deep-blue base · Cipher-style minimal layouts.
   All colour / type / spacing tokens live in :root.
================================================================= */

/* ===== FONTS — self-hosted woff2 (no external calls, GDPR) =======
   Variable faces; one file each covers the full weight range.
   Orbitron = titles, Plus Jakarta Sans = body.
================================================================= */
@font-face {
  font-family: "Orbitron";
  src: url("assets/fonts/orbitron-latin.woff2") format("woff2");
  font-weight: 400 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "Plus Jakarta Sans";
  src: url("assets/fonts/plusjakartasans-latin.woff2") format("woff2");
  font-weight: 300 700; font-style: normal; font-display: swap;
}

:root {
  /* --- Brand ---------------------------------------------------- */
  --deep-blue:  #001540;
  --near-black: #000000;
  --off-white:  #f2f2f4;
  --light-blue: #c0d6eb;
  --lime:       #daff8c;

  /* Surfaces */
  --page:          #00060f;   /* near-black blue — the single page backdrop */
  --surface:       #001540;   /* Fortunity deep blue — used for raised blocks */
  --surface-deep:  #000c26;
  --surface-raised:#001a4d;   /* lifted deep-blue for expanded blocks */
  --block-blue:    #001338;   /* filter block backdrop over the dot-grid */

  /* Tints */
  --hairline:      rgba(192, 214, 235, 0.16);
  --hairline-soft: rgba(192, 214, 235, 0.09);
  --ow-80: rgba(242, 242, 244, 0.80);
  --ow-65: rgba(242, 242, 244, 0.65);
  --ow-55: rgba(242, 242, 244, 0.55);  /* quiet fine-print — AA-safe (≥5.4:1) */
  --ow-50: rgba(242, 242, 244, 0.50);
  --ow-40: rgba(242, 242, 244, 0.40);  /* decorative only — not for text */

  /* --- Type ----------------------------------------------------- */
  --font-title: "Orbitron", "Arial Narrow", sans-serif;
  --font-body:  "Plus Jakarta Sans", system-ui, sans-serif;

  /* --- Layout --------------------------------------------------- */
  --max-w: 1440px;
  --pad-x: clamp(20px, 5vw, 80px);
  --section-y: clamp(96px, 13vh, 190px);

  /* --- Motion --------------------------------------------------- */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --reveal-dur: 750ms;

  /* --- Texture (brand dot-grid, drawn in CSS — no asset) -------- */
  --dotgrid: radial-gradient(rgba(192, 214, 235, 0.11) 1px, transparent 1.6px);
  --dotgrid-size: 30px 30px;
}

/* ================= Base ======================================== */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--page);
  color: var(--off-white);
  font-family: var(--font-body);
  font-weight: 400;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, p { margin: 0; }
:focus-visible { outline: 1px solid var(--lime); outline-offset: 2px; }

/* Skip link — first focusable; slides in only when focused */
.skip-link {
  position: fixed; top: 12px; left: 12px; z-index: 100;
  transform: translateY(-150%);
  background: var(--lime); color: var(--deep-blue);
  font-family: var(--font-title); font-size: 12px; font-weight: 500;
  letter-spacing: 0.08em; text-transform: uppercase;
  padding: 12px 20px; border-radius: 2px;
  transition: transform 250ms var(--ease-out);
}
.skip-link:focus { transform: none; }

/* ================= Helpers ==================================== */
.container {
  width: 100%;
  max-width: var(--max-w);
  margin-inline: auto;
  padding-inline: var(--pad-x);
}
.section-label {
  font-family: var(--font-title);
  font-weight: 500;
  font-size: 11px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--light-blue);
}
.section-title {
  font-family: var(--font-title);
  font-weight: 700;
  font-size: clamp(32px, 4.6vw, 72px);
  line-height: 1.04;
  letter-spacing: -0.025em;
  color: var(--off-white);
}

/* ================= Buttons =================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-title);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 14px 30px;
  border-radius: 2px;
  transition: background 300ms var(--ease-out), color 300ms var(--ease-out),
              border-color 300ms var(--ease-out), transform 300ms var(--ease-out);
}
.btn--lime-solid { background: var(--lime); color: var(--deep-blue); border: 1px solid var(--lime); }
.btn--lime-solid:hover { background: transparent; color: var(--lime); }
.btn--ghost { background: transparent; color: var(--off-white); border: 1px solid var(--hairline); }
.btn--ghost:hover { border-color: var(--light-blue); color: var(--light-blue); }

/* ================= 00 NAV ==================================== */
.site-header {
  position: fixed; inset: 0 0 auto 0; z-index: 50;
  border-bottom: 1px solid transparent;
  transition: background 400ms var(--ease-out), border-color 400ms var(--ease-out);
}
.site-header.is-scrolled {
  background: rgba(0, 12, 38, 0.82);
  backdrop-filter: blur(10px);
  border-bottom-color: var(--hairline);
}
.nav { display: flex; align-items: center; justify-content: space-between; height: 82px; }
.nav__logo img { height: 38px; width: auto; }
.nav__menu { display: flex; align-items: center; gap: clamp(22px, 3vw, 48px); }
.nav__links { display: flex; gap: clamp(20px, 2.6vw, 40px); }
.nav__links a {
  font-family: var(--font-title); font-weight: 400; font-size: 13px;
  letter-spacing: 0.06em; color: var(--ow-80);
  transition: color 250ms var(--ease-out);
}
.nav__links a:hover { color: var(--off-white); }
.nav__toggle {
  display: none; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  width: 44px; height: 44px; padding: 0; margin-right: -9px; border: 0; background: transparent;
  cursor: pointer; z-index: 60;
}
.nav__toggle span { display: block; height: 1.5px; width: 26px; background: var(--light-blue);
  transition: transform 300ms var(--ease-out), opacity 300ms var(--ease-out); }

/* ================= 01 HERO =================================== */
.hero {
  position: relative; min-height: 100svh;
  display: flex; align-items: flex-end;
  padding-bottom: clamp(48px, 9vh, 110px);
  overflow: hidden;
}
.hero__media { position: absolute; inset: 0; z-index: -1; background: var(--surface-deep); opacity: 0.33; }
.hero__video { width: 100%; height: 100%; object-fit: cover; }
/* Inverted flow field layered over the dimmed media, below the content */
.hero__field { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; pointer-events: none; }
/* GRADIENT — hero overlay (deep blue → near-black + light-blue sweep) */
.hero__overlay {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(192,214,235,0.16), transparent 55%),
    linear-gradient(180deg, rgba(0,21,64,0.45) 0%, rgba(0,12,38,0.72) 55%, rgba(0,0,0,0.90) 100%);
}
.hero__inner { position: relative; z-index: 1; max-width: 1100px; }
.hero__eyebrow {
  font-family: var(--font-title); font-weight: 500; font-size: clamp(10px, 1vw, 12px);
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--light-blue);
  margin-bottom: 1.6rem;
}
.hero__title {
  font-family: var(--font-title); font-weight: 800;
  font-size: clamp(48px, 9vw, 132px);
  line-height: 0.94; letter-spacing: -0.03em; color: var(--off-white);
}
.hero__lede {
  max-width: 44ch; margin-top: 1.8rem;
  font-size: clamp(15px, 1.4vw, 18px); color: var(--ow-80);
}
.hero__cta { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 2.4rem; }
.hero__scroll {
  position: absolute; left: 50%; bottom: 26px; width: 1px; height: 56px;
  background: var(--hairline); overflow: hidden;
}
.hero__scroll span {
  position: absolute; inset: 0; background: var(--light-blue);
  transform: translateY(-100%); animation: scrollfill 2s var(--ease-out) infinite;
}
@keyframes scrollfill { 0%{transform:translateY(-100%)} 60%,100%{transform:translateY(100%)} }
/* Registered trademark mark on the Fortunity wordmark.
   Sized down and raised to the cap-height top-right of the word; line-height 0
   keeps it from stretching the line box in headings and body copy alike. */
.tm {
  font-size: 0.42em;
  vertical-align: super;
  line-height: 0;
  letter-spacing: 0;
  margin-left: 0.06em;
}

/* ================= 02 THESIS (typewriter) =================== */
.thesis { background: var(--surface-deep); }
.thesis__pin {
  min-height: 100svh; display: flex; align-items: center;
}
.thesis__statement {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(30px, 5vw, 80px);
  line-height: 1.08; letter-spacing: -0.025em; color: var(--off-white);
  max-width: 20ch; margin-top: 1.5rem;
}
.thesis__statement .word { display: inline-block; transition: opacity 120ms linear; }
.thesis__body {
  padding-bottom: var(--section-y);
  padding-top: clamp(20px, 5vh, 60px);
}
.thesis__body p {
  max-width: 60ch; margin-left: auto;
  font-size: clamp(18px, 1.9vw, 27px); line-height: 1.4; font-weight: 600;
  letter-spacing: -0.01em; color: var(--off-white);
}

/* ================= 03 FORGE·FULFIL·FORTIFY (horizontal) ===== */
.fff { background: var(--surface-deep); }
.fff__pin { overflow: hidden; }
.fff__track {
  display: flex; align-items: stretch;
  height: 100svh; width: max-content;
}
.fff__intro {
  flex: 0 0 auto; width: clamp(320px, 42vw, 620px);
  display: flex; flex-direction: column; justify-content: center;
  padding-inline: var(--pad-x);
}
.fff__heading {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(40px, 6vw, 92px); line-height: 1.12; letter-spacing: -0.03em;
  color: var(--off-white); margin-top: 1.2rem;
}
.fff__hint {
  margin-top: 2rem; font-family: var(--font-title); font-size: 12px;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--lime);
}
.panel {
  flex: 0 0 auto; width: clamp(320px, 40vw, 560px);
  display: flex; flex-direction: column; justify-content: center;
  padding: clamp(40px, 7vh, 90px) clamp(36px, 4vw, 72px);
}
.panel__index {
  font-family: var(--font-title); font-size: 13px; letter-spacing: 0.2em;
  color: var(--lime); display: inline-flex; align-items: center;
}
.panel__index::before {
  content: ""; display: inline-block; width: 8px; height: 8px;
  background: var(--lime); margin-right: 14px;
}
.panel__name {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(44px, 5.6vw, 88px); line-height: 0.98; letter-spacing: -0.03em;
  color: var(--off-white); margin: 1.4rem 0 0.8rem;
}
.panel__role {
  font-family: var(--font-title); font-size: 11px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--light-blue); margin-bottom: 1.6rem;
}
.panel__desc { font-size: clamp(15px, 1.3vw, 18px); color: var(--ow-65); max-width: 40ch; }

/* ================= 04 WHY ISRAEL (cinematic sequence) ======= */
/* Default (mobile + no-JS): a clean, readable stacked layout. The pinned
   cinematic below only switches on when JS adds `.is-cinematic` (desktop). */
.israel { padding-block: var(--section-y); }
.israel__title { max-width: 20ch; margin-top: 1.4rem; }
.israel__para {
  margin-top: 1.6rem; max-width: 68ch;
  color: var(--off-white); font-size: clamp(16px, 1.4vw, 20px); line-height: 1.5;
}
/* image one — FCF logo particle animation */
.israel__anim {
  position: relative; margin-top: clamp(28px, 5vh, 56px);
  width: 100%; aspect-ratio: 16 / 10; overflow: hidden;
}
.israel__anim-canvas { display: block; width: 100%; height: 100%; }
/* image two — finale photo (shown in the desktop cinematic only) */
.israel__visual {
  position: relative; width: 100%; aspect-ratio: 16 / 10; overflow: hidden;
  border: 1px solid var(--hairline); display: none;
  background: var(--surface-deep);
}
/* image two — flipped vertically (scaleY) per brief */
.israel__img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transform: scaleY(-1);
}
.israel__scrim {
  position: absolute; inset: 0; opacity: 0;
  background: linear-gradient(180deg, rgba(0,6,15,0.30), rgba(0,6,15,0.72));
}

/* ---- Cinematic (desktop, JS on): pinned stage, absolute layers ---- */
.israel.is-cinematic { padding-block: 0; }
.israel.is-cinematic .israel__pin { position: relative; min-height: 100svh; overflow: hidden; }
.israel.is-cinematic .israel__scene { position: absolute; inset: 0; max-width: none; padding: 0; }
.israel.is-cinematic .israel__copy {
  position: absolute; left: var(--pad-x); top: 0; height: 100%; margin: 0;
  width: min(44vw, 640px);
  display: flex; flex-direction: column; justify-content: center;
  clip-path: inset(0 0 0 0);   /* JS wipes the whole block (label + title) bottom→top */
}
.israel.is-cinematic .israel__title { margin-top: 1.2rem; }
/* Deliberately NOT a flex container. As `display: flex` this <p> blockified
   every inline child: the ® became a full-width flex row and broke the
   paragraph into three stacked blocks. Any <em>/<strong>/<a> added here later
   would have done the same.

   Centred with the auto-margin trick — top:0 + bottom:0 + a definite height,
   so the leftover space splits evenly — rather than a transform. GSAP owns
   this element's transform for the slide-in, and it writes `translate: none`
   inline when it takes over, which silently kills `translate: 0 -50%`. */
.israel.is-cinematic .israel__para {
  position: absolute; right: var(--pad-x);
  top: 0; bottom: 0; height: fit-content; margin-block: auto;
  width: min(42vw, 560px);
  font-size: clamp(18px, 1.5vw, 24px); max-width: none;
}
.israel.is-cinematic .israel__anim {
  position: absolute; margin: 0; z-index: 2;
  left: 52%; top: 16%; width: 40%; height: 58%;   /* box is FIXED; JS only transforms it */
  will-change: transform;
}
.israel.is-cinematic .israel__visual {
  display: block; position: absolute; margin: 0; border: 0; z-index: 1;
  left: 0; top: 0; width: 100%; height: 100%;     /* fullscreen from the start — image ONE
                                                     does the growing; JS only fades this in */
}
.israel.is-cinematic .statgrid {
  position: absolute; left: var(--pad-x); right: var(--pad-x); bottom: 9%;
  margin: 0; z-index: 3;
}
/* Cipher-style framed stat table — lines draw in L→R (lightsaber),
   boxes expand-but-stay-attached on hover, and the box's OWN lines move. */
.statgrid {
  position: relative; display: flex; flex-wrap: nowrap;
  margin-top: clamp(56px, 9vh, 104px);
}
/* --- the frame lines (animatable) --- */
.statgrid__hline, .statcell__vline, .statgrid__vedge {
  position: absolute; background: var(--light-blue); opacity: 0.6; pointer-events: none;
}
.statgrid__hline { left: 0; right: 0; height: 1px; transform: scaleX(0);
  transform-origin: left center; transition: transform 750ms var(--ease-out); }
.statgrid__hline--top { top: 0; }
.statgrid__hline--bottom { bottom: 0; }
.statcell__vline, .statgrid__vedge {
  top: 0; bottom: 0; width: 1px; transform: scaleY(0);
  transform-origin: top center; transition: transform 600ms var(--ease-out) 480ms;
}
.statcell__vline { left: 0; } .statgrid__vedge { right: 0; }
/* draw-in on scroll */
.statgrid.is-drawn .statgrid__hline { transform: scaleX(1); }
.statgrid.is-drawn .statgrid__hline--bottom { transition-delay: 130ms; }
.statgrid.is-drawn .statcell__vline,
.statgrid.is-drawn .statgrid__vedge { transform: scaleY(1); }
/* corner nodes at every line intersection (Cipher's little ticks) */
.statcell__vline::before, .statcell__vline::after,
.statgrid__vedge::before, .statgrid__vedge::after {
  content: ""; position: absolute; left: 50%; width: 6px; height: 6px;
  border-radius: 50%;                  /* dots, not squares */
  background: var(--light-blue);
  transform: translate(-50%, -50%) scale(0);
  transition: transform 380ms var(--ease-out) 700ms, background-color 300ms var(--ease-out);
}
.statcell__vline::before, .statgrid__vedge::before { top: 0; }
.statcell__vline::after,  .statgrid__vedge::after  { top: 100%; }
.statgrid.is-drawn .statcell__vline::before,
.statgrid.is-drawn .statcell__vline::after,
.statgrid.is-drawn .statgrid__vedge::before,
.statgrid.is-drawn .statgrid__vedge::after { transform: translate(-50%, -50%) scale(1); }

.statcell {
  position: relative; flex: 1 1 0; min-width: 0;
  padding: clamp(30px, 3vw, 50px) clamp(24px, 2.4vw, 42px);
  transition: flex-grow 550ms var(--ease-out), background 400ms var(--ease-out);
}
.statcell__cat {
  font-family: var(--font-title); font-size: 10px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--light-blue);
}
.statcell__value {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(38px, 4.3vw, 66px); line-height: 1; letter-spacing: -0.02em;
  color: var(--off-white); margin: 22px 0 16px; white-space: nowrap;
}
.statcell__unit { font-size: 0.4em; font-weight: 500; margin-left: 0.12em; color: var(--light-blue); letter-spacing: 0.04em; }
.statcell__note { font-size: 14px; color: var(--ow-65); max-width: 24ch; }
.statcell__src { margin-top: 18px; font-size: 10px; letter-spacing: 0.04em; color: var(--ow-55); }
/* hover: box expands a touch (stays attached); its lines brighten + shift with it */
.statgrid:hover .statcell { flex-grow: 1; }
.statgrid .statcell:hover { flex-grow: 1.55; background: rgba(192, 214, 235, 0.045); }
.statcell:hover .statcell__vline { opacity: 1; }
.statcell:hover .statcell__vline::before,
.statcell:hover .statcell__vline::after { background: var(--off-white); }

/* ================= 05 THE FILTER (expanding blocks) ========= */
.filter { background: var(--surface-deep); padding-block: var(--section-y); }
.filter__title { max-width: 24ch; margin-top: 1.4rem; margin-bottom: clamp(40px, 7vh, 72px); }
.filter__blocks {
  position: relative;
  display: flex; gap: 14px;
  padding-inline: var(--pad-x);
  max-width: var(--max-w); margin-inline: auto;
  height: clamp(340px, 46vh, 460px);
}
/* each block has its OWN particle dot-grid canvas, above its background,
   below its content — so it fills and expands with that block. */
.fblock__dots {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%; pointer-events: none;
}
.fblock {
  position: relative; z-index: 1; flex: 1 1 0; min-width: 0;
  border: 1px solid rgba(192, 214, 235, 0.6);   /* light-blue outline, matches
                                          the stat frame's effective 60% */
  background: transparent;             /* blue block removed — only the flow field shows */
  padding: clamp(22px, 2vw, 34px);
  display: flex; flex-direction: column; justify-content: flex-end;
  overflow: hidden; cursor: default;
  /* slower + subtler expansion */
  transition: flex-grow 820ms var(--ease-out);
}
/* first block expanded by default (square-ish) */
.fblock:first-of-type { flex-grow: 2.2; }
/* hovering the group resets, hovered one expands */
.filter__blocks:hover .fblock { flex-grow: 1; }
.filter__blocks .fblock:hover,
.filter__blocks .fblock:focus-visible { flex-grow: 2.2; }
.fblock__body { position: relative; z-index: 1; }
/* X pinned to its corner — spins in place, never translates into frame */
.fblock__x {
  position: absolute; z-index: 1; top: clamp(22px, 2vw, 34px); left: clamp(22px, 2vw, 34px);
  font-size: 22px; color: var(--light-blue); line-height: 1; opacity: 0.85;
  transform-origin: center;
  transition: color 500ms var(--ease-out), transform 900ms var(--ease-out);
}
/* lime marks the ACTIVE block: the first by default, the hovered one otherwise */
.fblock:first-of-type .fblock__x { color: var(--lime); }
.filter__blocks:hover .fblock__x { color: var(--light-blue); }   /* hovering the group resets all (incl. the first) */
.filter__blocks .fblock:hover .fblock__x,
.filter__blocks .fblock:focus-visible .fblock__x { color: var(--lime); }
/* hover: the lime X spins twice, in place */
.filter__blocks .fblock:hover .fblock__x,
.filter__blocks .fblock:focus-visible .fblock__x { transform: rotate(720deg); }
.fblock__title {
  font-family: var(--font-title); font-weight: 500;
  font-size: clamp(16px, 1.5vw, 21px); line-height: 1.15; letter-spacing: -0.01em;
  color: var(--off-white); white-space: normal;
}
.fblock__reason {
  margin-top: 14px; font-size: 14px; color: var(--ow-65); max-width: 34ch;
  opacity: 0; transform: translateY(8px);
  transition: opacity 450ms var(--ease-out) 120ms, transform 450ms var(--ease-out) 120ms;
}
.fblock:first-of-type .fblock__reason,
.filter__blocks .fblock:hover .fblock__reason,
.filter__blocks .fblock:focus-visible .fblock__reason { opacity: 1; transform: none; }
.fblock__body { align-self: flex-start; }

/* ================= 06 WHY FORTUNITY (mission) =============== */
.mission { background: var(--surface-deep); padding-block: clamp(120px, 20vh, 240px); }
.mission__grid {
  display: grid; grid-template-columns: 240px 1fr; gap: clamp(30px, 5vw, 80px);
}
.mission__eyebrow { padding-top: 12px; }
.mission__main { max-width: 900px; }
.mission__statement {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(32px, 4.8vw, 76px); line-height: 1.02; letter-spacing: -0.025em;
  color: var(--off-white);
}
.mission__slide { margin-top: clamp(60px, 12vh, 150px); } /* JS translates this up on scroll */
.mission__body { max-width: 60ch; font-size: clamp(15px, 1.35vw, 18px); color: var(--ow-65); }
.mission__entities {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px, 3vw, 44px);
  margin-top: clamp(40px, 6vh, 64px);
  padding-top: clamp(28px, 4vh, 40px); border-top: 1px solid var(--hairline);
}
.entity__role {
  font-family: var(--font-title); font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--lime);
  transition: color 250ms var(--ease-out);
}
.entity__name { margin-top: 12px; font-size: 15px; color: var(--off-white); font-weight: 500; }
.entity__meta { margin-top: 8px; font-size: 12px; color: var(--ow-50); }

/* ================= CLOSING FOOTER (CTA + footer merged) ===== */
.footer { position: relative; overflow: hidden; }
/* Backdrop = the inverted FCF flow field; #00060f is the attachment ground. */
.footer__bg { position: absolute; inset: 0; z-index: 0; background: #00060f; }
.footer__field { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* Scrim sits above the canvas (::after paints last). Lighter than the old
   photo scrim (0.72→0.90) so the field stays visible; raise if text needs more. */
.footer__bg::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0,6,15,0.25) 0%, rgba(0,6,15,0.60) 100%);
}
.footer__grid {
  position: relative; z-index: 1;
  display: grid; grid-template-columns: 1.5fr 1fr 1fr;
  gap: clamp(32px, 5vw, 80px);
  padding-block: clamp(72px, 13vh, 160px);
  align-items: start;
}
.footer__brand { display: flex; flex-direction: column; align-items: flex-start; margin-top: clamp(-44px, -3vw, -18px); }
.footer__brand a { display: block; }          /* block: no baseline leading under the mark */
.footer__brand img { display: block; width: clamp(180px, 19vw, 272px); height: auto; margin-bottom: clamp(40px, 4.4vw, 64px); }
.footer__tagline {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(30px, 3.9vw, 60px); line-height: 1.05; letter-spacing: -0.02em;
  color: var(--off-white); max-width: 15ch;
}
/* buttons + links sit at the bottom of the footer; brand stays at the top */
.footer__cta, .footer__links { align-self: end; }
.footer__cta { display: flex; flex-direction: column; gap: 14px; align-items: flex-start; padding-top: 10px; }
.footer__cta .btn { width: 100%; max-width: 280px; }
.footer__links { display: flex; flex-direction: column; gap: 12px; }
.footer__links a {
  font-family: var(--font-title); font-size: 13px; letter-spacing: 0.06em; color: var(--ow-80);
  transition: color 250ms var(--ease-out);
}
.footer__links a:hover { color: var(--lime); }
.footer__legal {
  margin-top: clamp(22px, 4vh, 44px); display: flex; flex-direction: column; gap: 6px;
  font-size: 11px; color: var(--ow-55); max-width: 42ch;
}

/* AFM exemption banner (home page only).
   Official regulatory artwork — it is reproduced as-is, at full width, and is
   deliberately NOT tinted, inverted or blended into the dark footer: altering
   it would break the disclosure. It sits above the flow-field canvas, so it
   needs the same z-index lift as .footer__grid. */
.footer__afm {
  position: relative; z-index: 1;
  padding-bottom: clamp(28px, 5vh, 56px);
}
.footer__afm img {
  display: block; width: 100%; height: auto;
}

/* ================= Reveal utility ========================= */
[data-reveal] {
  opacity: 0; transform: translateY(26px);
  transition: opacity var(--reveal-dur) var(--ease-out), transform var(--reveal-dur) var(--ease-out);
}
[data-reveal].is-visible { opacity: 1; transform: none; }

/* Line-wipe reveal — echoes the stat-frame lightsaber draw. */
[data-wipe] {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 900ms var(--ease-out);
}
[data-wipe].is-visible { clip-path: inset(0 0 0 0); }

/* ================= SEAMLESS BACKDROP ====================== */
/* One continuous near-black-blue across the whole page — no dot-grid,
   no directional glows, no seams between sections. Reads as one page. */
.thesis, .fff, .israel, .filter, .mission {
  background: var(--page);
  border-top: 0;
}

/* Buttons — a little more tactile. */
.btn:hover  { transform: translateY(-1px); }
.btn:active { transform: translateY(0) scale(0.99); }

/* Nav links — a lime signal wipes in under the hovered item. */
.nav__links a { position: relative; }
.nav__links a::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -6px;
  height: 1px; background: var(--lime); transition: right 320ms var(--ease-out);
}
.nav__links a:hover::after { right: 0; }

/* Stat values resolve into focus, staggered, as the frame draws.
   Keep the blur small so the halo never bleeds into the neighbouring cell. */
.statcell__value {
  filter: blur(6px); opacity: 0; transform: translateY(10px);
  transition: filter 600ms var(--ease-out), opacity 600ms var(--ease-out),
              transform 600ms var(--ease-out);
}
.statgrid.is-drawn .statcell__value { filter: none; opacity: 1; transform: none; }
.statgrid.is-drawn .statcell:nth-of-type(1) .statcell__value { transition-delay: 240ms; }
.statgrid.is-drawn .statcell:nth-of-type(2) .statcell__value { transition-delay: 380ms; }
.statgrid.is-drawn .statcell:nth-of-type(3) .statcell__value { transition-delay: 520ms; }
.statgrid.is-drawn .statcell:nth-of-type(4) .statcell__value { transition-delay: 660ms; }

/* Mission entities — quiet hover lift, tonal not shadowed. */
.entity { transition: transform 420ms var(--ease-out); }
.entity:hover { transform: translateY(-3px); }
.entity:hover .entity__role { color: var(--light-blue); }

/* Framework — horizontal scroll progress rail (lime = meaningful signal). */
.fff__progress {
  position: absolute; left: var(--pad-x); right: var(--pad-x); bottom: 34px;
  height: 2px; background: var(--hairline); z-index: 3; overflow: hidden;
}
.fff__progress i {
  display: block; height: 100%; width: 100%; background: var(--lime);
  transform: scaleX(0); transform-origin: left center;
}

/* Desktop only: dim non-centered panels so the active one leads. */
@media (min-width: 901px) {
  .fff__track .panel { opacity: 0.5; transition: opacity 480ms var(--ease-out); }
  .fff__track .panel.is-active { opacity: 1; }
  /* Trailing space equal to (half viewport − half panel) so the LAST panel
     scrolls all the way to viewport centre — otherwise the track right-aligns
     and Fortify never reaches centre (so it never becomes the active panel). */
  .fff__track { padding-right: calc(50vw - clamp(160px, 20vw, 280px)); }
}

/* ================= Responsive ============================= */
@media (max-width: 1100px) {
  .mission__grid { grid-template-columns: 1fr; gap: 24px; }
  .mission__entities { grid-template-columns: 1fr; }
}
@media (max-width: 900px) {
  /* stat table stacks; framed lines/nodes are a desktop delight */
  .statgrid { flex-direction: column; }
  .statgrid__hline, .statcell__vline, .statgrid__vedge { display: none; }
  .statcell { border-top: 1px solid var(--hairline); padding-inline: 0; }
  .statgrid:hover .statcell, .statgrid .statcell:hover { flex-grow: 1; background: transparent; }
  /* Filter: stack vertically, each block expands open */
  .filter__blocks { flex-direction: column; height: auto; }
  .fblock, .fblock:first-of-type, .filter__blocks:hover .fblock { flex: 1 1 auto; }
  /* The X is absolutely placed in the block's top-left corner and the body is
     pushed down by justify-content: flex-end. On desktop the block is
     340-460px tall so the two never meet; stacked here the block shrinks to
     its content and the X lands on the title. Put it back in the flow. */
  .fblock__x { position: static; align-self: flex-start; margin-bottom: 14px; }
  .fblock__reason { opacity: 1; transform: none; }
  .fblock__dots { display: none; }   /* stacked blocks; skip the per-block canvases */
  .footer__grid { grid-template-columns: 1fr; }

  /* Forge·Fulfil·Fortify: horizontal → vertical stack (no pin on mobile) */
  .fff__pin { overflow: visible; }
  .fff__track { flex-direction: column; width: 100%; height: auto; }
  .fff__intro { width: 100%; padding-block: clamp(64px, 12vh, 110px); }
  .fff__hint { display: none; }
  .fff__progress { display: none; }
  .panel {
    width: 100%; border-left: 0; border-top: 1px solid var(--hairline);
    min-height: 66svh;
  }

  /* Thesis: no pin — statement just reads normally */
  .thesis__pin { min-height: auto; padding-block: clamp(80px, 16vh, 160px); }
  .thesis__body p { margin-left: 0; }
}
@media (max-width: 640px) {
  .nav__toggle { display: flex; }
  .nav__menu {
    position: fixed; inset: 0; flex-direction: column; justify-content: center; gap: 30px;
    background: var(--surface-deep); transform: translateX(100%);
    transition: transform 400ms var(--ease-out);
  }
  .nav__menu.is-open { transform: none; }
  .nav__links { flex-direction: column; align-items: center; gap: 10px; }
  .nav__links a { font-size: 30px; }
  body.menu-open { overflow: hidden; }
  .nav__toggle.is-open span:first-child { transform: translateY(3.75px) rotate(45deg); }
  .nav__toggle.is-open span:last-child { transform: translateY(-3.75px) rotate(-45deg); }
  .hero__scroll { left: var(--pad-x); }
  .footer__bar { flex-direction: column; gap: 10px; }

  /* The hero bottom-aligns its content inside 100svh, and the site header is
     fixed — outside the flow, so nothing reserves the 82px it covers. On a
     tall screen the hero is much taller than its content and the two never
     meet; on a short one the content fills the height, rides up to y=0 and
     sits behind the logo and the burger. Padding the top reserves that room
     and lets the section grow past 100svh when the copy needs it, instead of
     sliding underneath. */
  .hero { padding-top: calc(82px + clamp(18px, 4vh, 40px)); }
  /* The eyebrow is already at its clamp floor, so the width comes back from
     the tracking rather than the size — three items and two separators do not
     fit one line at this width whatever we do, but two tidy lines beat three. */
  .hero__eyebrow { letter-spacing: 0.12em; margin-bottom: 1.15rem; }
  .hero__lede { margin-top: 1.25rem; font-size: 14.5px; }
  .hero__cta { margin-top: 1.7rem; gap: 12px; }
}

/* ================= Reduced motion ========================= */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
  [data-wipe] { clip-path: none !important; }
  .statcell__value { filter: none !important; opacity: 1 !important; transform: none !important; }
  .fff__track .panel { opacity: 1 !important; }
  .hero__scroll span { animation: none; }
}


/* =================================================================
   TEAM PAGE (team.html)
   Card / detail / row language follows the reference screenshots:
   dark cards, a small lime crosshair mark, a spec-table detail panel,
   and full-bleed rows that flood lime on hover.
   ================================================================= */

/* ---- page hero (shorter than the home hero) ---- */
.pagehero {
  position: relative; min-height: 74svh; display: flex; align-items: flex-end;
  padding-block: clamp(140px, 22vh, 240px) clamp(56px, 10vh, 120px);
  overflow: hidden; background: var(--surface-deep);
}
.pagehero__field { position: absolute; inset: 0; z-index: 0; }
.pagehero__canvas { display: block; width: 100%; height: 100%; pointer-events: none; }
.pagehero__overlay {
  position: absolute; inset: 0; z-index: 1;
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(192,214,235,0.14), transparent 55%),
    linear-gradient(180deg, rgba(0,21,64,0.40) 0%, rgba(0,12,38,0.70) 55%, rgba(0,0,0,0.88) 100%);
}
.pagehero__inner { position: relative; z-index: 2; max-width: 1100px; }
.pagehero__title { font-size: clamp(40px, 7.2vw, 104px); }

/* ---- section rhythm ---- */
.team, .network, .infra { padding-block: var(--section-y); }
.team__head { margin-bottom: clamp(76px, 11vh, 148px); }   /* matches .infra__head */
.team__title { max-width: 22ch; margin-top: 0; }

/* ---- the team cards, three across ---- */
.team__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 26px);
}
/* A roster that does not divide by three leaves the last row short. One card
   stranded under the left column reads as a missing card rather than the end
   of the list, so centre it. Only fires on a last card that starts a row by
   itself — at six or nine the rule never matches. */
.team__grid > .tcard:last-child:nth-child(3n + 1) { grid-column: 2; }
.tcard {
  position: relative; display: flex; flex-direction: column;
  text-align: left; padding: 0; cursor: pointer;
  background: linear-gradient(180deg, #0a1024 0%, #05070f 100%);
  border: 1px solid var(--hairline);
  /* transition lives with the torch variables further down, so the two
     animated properties are declared together rather than in two places. */
}
/* No transform-based lift here: GSAP owns this card's transform for the scroll
   move and writes `translate: none` inline, which would kill it. Lime border. */
.tcard:hover, .tcard:focus-visible { border-color: rgba(218,255,140,0.55); }
/* The portrait is three stacked layers:
     .tcard__field     animated flow field, always running, at the back
     .tcard__photo     the portrait, fades OUT on hover
     .tcard__halftone  halftone render, fades IN on hover
   The halftone is drawn with transparent gaps between its dots, so on hover
   the live field shows through them — the portrait dissolves into the grid
   rather than being covered by a flat pattern. */
.tcard__portrait {
  position: relative; display: block; width: 100%; aspect-ratio: 4 / 5; overflow: hidden;
  background: #04060d;
}
.tcard__field,
.tcard__halftone {
  position: absolute; inset: 0; display: block;
  width: 100%; height: 100%; pointer-events: none;
}
.tcard__field { z-index: 0; }
.tcard__photo {
  position: relative; z-index: 1;
  display: block; width: 100%; height: 100%;
  /* Top-aligned, not centred. The portraits are tall cut-outs, so centring a
     cover crop in this 4:5 frame sliced the top of the head off. Anchoring to
     the top keeps every face intact and trims the jacket instead.
     drawHalftone() in main.js mirrors this, or the two layers drift apart. */
  object-fit: cover; object-position: center top;
}
/* No opacity transition here on purpose. The mask is what reveals this layer
   now, so fading it in as well would delay the torch behind the pointer.
   .is-ready is set by JS once the halftone has actually been rendered —
   without it, hovering early would reveal an empty canvas. */
.tcard__halftone { z-index: 2; opacity: 0; }
/* The reveal is a liquid pool, not a switch: a short chain of overlapping
   blobs that trails the pointer, stringing out when you move and settling
   round when you stop. main.js writes the gradient lists per frame.

   --torch-in  : the blobs, opaque inside  -> unioned to SHOW the halftone
   --torch-out : the same blobs, inverted  -> intersected to HIDE the photo
   --torch-out1: the head blob only, for the two-layer fallback below

   The photo uses `intersect` of the inverses rather than `add`: the inverse
   of a union is the intersection of the inverses (De Morgan). Compositing
   per blob instead of flattening avoids a visible seam where blobs overlap,
   and keeps the two layers exactly complementary — no double-exposure.

   No transition on any of this. The easing lives in the rAF loop, which is
   what lets the pool keep settling after the pointer stops; a CSS transition
   would fight it and lag the head behind the cursor. */
.tcard {
  --torch-in:   radial-gradient(circle 0px at 50% 50%, #000 52%, transparent 100%);
  /* The trailing opaque layer is not decoration — see the note on the photo
     rule below. It is what stops `intersect` collapsing to an empty mask. */
  --torch-out:  radial-gradient(circle 0px at 50% 50%, transparent 52%, #000 100%),
                linear-gradient(#000, #000);
  --torch-out-op: intersect, add;
  --torch-out1: radial-gradient(circle 0px at 50% 50%, transparent 52%, #000 100%);
  transition: border-color 320ms var(--ease-out);
}

/* The whole effect is gated on mask-composite, and the legacy
   -webkit-mask-composite keywords are deliberately gone.

   They were actively dangerous. WebKit's legacy model composites the
   bottom-most mask layer against nothing, so `source-in` on the photo — a
   single layer — intersects with emptiness and yields a mask that hides
   EVERYTHING. Chrome, reading the standard `mask-composite: intersect`
   below it, was fine; Safari could take the -webkit- line and blank the
   portrait outright. A missing flourish is a cosmetic bug, a missing face
   is not, so this now fails closed: no mask-composite support means no
   mask at all, the halftone stays hidden, and the photo is simply itself. */
@supports (mask-composite: intersect) {
  .tcard.is-ready .tcard__halftone {
    opacity: 1;
    mask-image: var(--torch-in);
    mask-repeat: no-repeat;
    mask-composite: add;
  }
  /* Two deliberate details here, both learned the hard way in Safari.

     1. The mask stack ends in an opaque linear-gradient, and the composite
        list ends in `add` rather than `intersect`. Per the CSS Masking spec
        the BOTTOM layer composites against a transparent backdrop, so
        `intersect` on it means "overlap with nothing" — an empty mask, and a
        completely invisible portrait. Chrome quietly ignores the operator on
        the bottom layer; Safari follows the spec. The opaque base gives the
        intersections something real to bite on, and matches both engines.
        main.js keeps the composite list the same length as the layer list.

     2. Gated on .is-lit, not .is-ready. .is-ready only means the halftone has
        been drawn, which happens on scroll — so any mask trouble used to take
        the faces out just from scrolling past. .is-lit is set only while the
        pool is actually open under the pointer, so the worst any future
        regression here can do is misbehave during a hover. */
  .tcard.is-lit .tcard__photo {
    mask-image: var(--torch-out);
    mask-repeat: no-repeat;
    mask-composite: var(--torch-out-op);
  }
}

/* Fallback when the halftone canvas cannot be read back. Opening the page
   from file:// gives the document an opaque origin, which taints any canvas
   an image has been drawn into, so getImageData throws and the rendered
   halftone never appears — invisible on a localhost preview, but exactly the
   case for the shared zip. This needs no pixel access: a repeating
   radial-gradient mask punches a dot screen straight through the photo, so
   the live field still shows between the dots. Uniform dots instead of
   luminance-varying ones, but the effect is never silently absent.

   Two mask layers unioned with `add`: the dot screen, plus the INVERSE of the
   torch disc. Union means fully opaque everywhere outside the disc, and only
   the dots inside it — the same torch behaviour, without pixel access. */
.tcard.is-dotmask .tcard__photo {
  -webkit-mask-image:
    radial-gradient(circle, #000 1.7px, transparent 2px),
    var(--torch-out1);
  mask-image:
    radial-gradient(circle, #000 1.7px, transparent 2px),
    var(--torch-out1);
  -webkit-mask-size: 6px 6px, 100% 100%;
  mask-size: 6px 6px, 100% 100%;
  -webkit-mask-repeat: repeat, no-repeat;
  mask-repeat: repeat, no-repeat;
  /* `add` is the default, so an engine without mask-composite still unions
     these two layers correctly. No -webkit- legacy keyword here either. */
  mask-composite: add;
}

/* The pool is pointer-driven, so it is not motion the visitor cannot escape.
   Its easing lives in the rAF loop, not in a transition, so there is nothing
   to disable here beyond the card's own border fade. */
@media (prefers-reduced-motion: reduce) {
  .tcard { transition-duration: 1ms; }
}
.tcard__initials {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-title); font-weight: 700; letter-spacing: 0.04em;
  font-size: clamp(34px, 4.6vw, 62px); color: rgba(192,214,235,0.16);
}
.tcard__foot {
  display: block; padding: 16px 18px 20px; border-top: 1px solid var(--hairline);
}
.tcard__name {
  display: block; font-family: var(--font-title); font-weight: 700;
  font-size: clamp(13px, 1.15vw, 16px); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--off-white);
}
.tcard__role {
  display: block; margin-top: 7px; font-size: 13px; line-height: 1.35;
  letter-spacing: 0; color: var(--ow-55);
}
/* the bio travels with the card but only shows in the overlay (or with no JS) */
.tcard__bio { display: none; }

/* ---- detail overlay ---- */
.tdetail { position: fixed; inset: 0; z-index: 90; display: flex; align-items: center; justify-content: center; }
.tdetail[hidden] { display: none; }
.tdetail__scrim { position: absolute; inset: 0; background: rgba(0,4,12,0.82); border: 0; }
.tdetail__panel {
  position: relative; z-index: 1;
  width: min(420px, calc(100vw - 2 * var(--pad-x)));
  max-height: min(88svh, 900px);
  display: flex; flex-direction: column; overflow: hidden;
  background: #05070f; border: 1px solid var(--hairline);
}
/* Only the content scrolls. The bar keeps its full width (so the centred logo
   is truly centred) and Close stays put while a long bio is being read. */
.tdetail__body { flex: 1 1 auto; overflow-y: auto; }
.tdetail__bar {
  position: relative; flex: none; display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px; border-bottom: 1px solid var(--hairline);
}
.tdetail__eyebrow, .tdetail__close {
  font-family: var(--font-title); font-size: 10px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ow-65);
}
/* There is no global button reset, so the UA background made this unreadable. */
.tdetail__close {
  background: none; border: 0; padding: 0; cursor: pointer;
  transition: color 250ms var(--ease-out);
}
.tdetail__close:hover { color: var(--lime); }
/* the lime FCF mark, sized to sit where the old crosshair did */
.tdetail__logo {
  position: absolute; left: 50%; transform: translateX(-50%);
  height: 12px; width: auto; display: block;
}
.tdetail__figure {
  position: relative; aspect-ratio: 4 / 5; overflow: hidden;
  background: #04060d;
}
/* Live field behind the portrait, matching the card treatment. */
.tdetail__field {
  position: absolute; inset: 0; z-index: 0;
  display: block; width: 100%; height: 100%; pointer-events: none;
}
.tdetail__figure img {
  position: relative; z-index: 1;
  display: block; width: 100%; height: 100%;
  /* Must match .tcard__photo, or the portrait jumps when the overlay opens. */
  object-fit: cover; object-position: center top;
}
/* [hidden] needs to beat the rule above, which is more specific than the attr */
.tdetail__photo[hidden] { display: none; }
.tdetail__initials {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-title); font-weight: 700; font-size: 72px;
  color: rgba(192,214,235,0.16);
}
/* Same trap as .tdetail__photo above: `display: flex` outranks the UA's
   [hidden] rule, so JS setting .hidden did nothing and the initials stayed in
   the layer stack behind every portrait. Harmless while all six have photos,
   wrong the moment one does not. */
.tdetail__initials[hidden] { display: none; }
/* spec table */
.tdetail__spec { margin: 0; padding: 0; }
.specrow {
  display: grid; grid-template-columns: 62px 1fr; gap: 14px; align-items: baseline;
  padding: 13px 16px; border-bottom: 1px solid var(--hairline);
}
.specrow dt {
  font-family: var(--font-title); font-size: 9px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ow-50);
}
.specrow dd {
  margin: 0; font-family: var(--font-title); font-weight: 700;
  font-size: 15px; letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--off-white); text-align: center;
}
.specrow__role { font-weight: 400; color: var(--ow-65); font-size: 13px; }
.specrow--bio { grid-template-columns: 1fr; gap: 10px; }
.specrow--bio dd {
  font-family: var(--font-body); font-weight: 400; font-size: 13.5px; line-height: 1.55;
  letter-spacing: 0; text-transform: none; text-align: left; color: var(--ow-80);
}
.tdetail__link {
  display: block; padding: 16px; text-align: center;
  font-family: var(--font-title); font-size: 13px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--off-white);
  transition: background 280ms var(--ease-out), color 280ms var(--ease-out);
}
.tdetail__link:hover { background: var(--lime); color: var(--deep-blue); }
.tdetail__link[hidden] { display: none; }

/* ---- the network: title left, body right ---- */
.network__head {
  display: block;
  margin-bottom: clamp(96px, 15vh, 190px);   /* breathing room before the rows */
}
.network__title { max-width: 34ch; margin-top: 0; }   /* spread wider across the page */
/* typed in word-by-word on scroll (see initTeamMotion) */
.network__title .word { display: inline-block; transition: opacity 120ms linear; }
.network__body {
  max-width: 45ch; margin-left: auto;                      /* underneath, on the right */
  margin-top: clamp(38px, 6vh, 76px);
  font-size: clamp(15px, 1.3vw, 18px); line-height: 1.6; color: var(--ow-80);
}
/* full-bleed venture-partner rows — flood lime on hover */
.vplist { border-top: 1px solid var(--hairline); }
.vprow {
  position: relative; display: flex; align-items: baseline; gap: clamp(10px, 1.4vw, 22px);
  padding: clamp(14px, 2.2vh, 26px) var(--pad-x);
  border-bottom: 1px solid var(--hairline);
  transition: background 300ms var(--ease-out);
}
.vprow__name {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(26px, 4.4vw, 62px); line-height: 1.05; letter-spacing: -0.02em;
  text-transform: uppercase; color: var(--off-white);
  transition: color 300ms var(--ease-out);
}
.vprow__tag {
  margin-left: auto;   /* sits at the row's right edge, so all three line up */
  font-family: var(--font-title); font-size: clamp(11px, 0.95vw, 13px);
  letter-spacing: 0.01em; color: var(--ow-55);
  transition: color 300ms var(--ease-out);
}
.vprow:hover { background: var(--lime); }
.vprow:hover .vprow__name, .vprow:hover .vprow__tag { color: var(--deep-blue); }

/* ---- institutional infrastructure: centred head + partner cards ----
   Vertical cards in the same language as the team grid: mark on top, role
   beneath it, firm name on its own bar at the foot. Two partners now rather
   than three.

   Each card keeps the width it had in the three-up grid, (100% - 2 gaps) / 3,
   so nothing about the card's proportions changes with the count; the pair is
   centred, which splits the leftover third either side instead of leaving it
   trailing off to the right. Fill the Auditor slot and the third card drops
   straight into that gap. */
.infra__head { text-align: center; margin-bottom: clamp(64px, 9vh, 120px); }
.infra__title { max-width: 30ch; margin: 0 auto; }

.infra__grid {
  --icard-gap: clamp(14px, 1.6vw, 24px);
  display: grid;
  grid-template-columns: repeat(2, calc((100% - 2 * var(--icard-gap)) / 3));
  gap: var(--icard-gap);
  justify-content: center;
}

.icard {
  display: flex; flex-direction: column;
  border: 1px solid var(--hairline); background: #05070f;
  transition: border-color 320ms var(--ease-out);
}
.icard:hover { border-color: rgba(192, 214, 235, 0.34); }

/* width: 100% is load-bearing. As a stretched grid item the media's height
   comes from the row, and with only aspect-ratio to go on the browser derives
   the WIDTH from that height — so the legal card, taller in copy than Apex,
   grew a wider logo box. Pinning the width to the track over-constrains the
   ratio, which is what we want: identical boxes whatever the copy does. */
.icard__media {
  position: relative; width: 100%; aspect-ratio: 16 / 11;
  background-color: #04060d;
  background-image: radial-gradient(rgba(192, 214, 235, 0.20) 1px, transparent 1px);
  background-size: 12px 12px; background-position: center;
}
.icard__media--anim { background-image: none; }
.icard__canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }

.icard__role {
  padding: 18px 18px 0; text-align: center;
  font-family: var(--font-title); font-size: clamp(12px, 1.05vw, 15px);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--light-blue);
}
/* Optional named contact, tight under the role so the two read as one block.
   The row is always rendered, blank where a partner has no named contact
   (--spacer below), so the supporting line sits at the same height in every
   card instead of riding up into the gap the missing name would leave. */
.icard__meta {
  padding: 7px 18px 0; text-align: center;
  font-size: clamp(13px, 1vw, 14.5px); line-height: 1.4; color: var(--off-white);
}
/* A no-break space rather than a min-height: the reserved row is then exactly
   one line of THIS text, whatever the clamp resolves to at this width. */
.icard__meta--spacer::before { content: "\00a0"; }
.icard__note {
  padding: 11px 20px 22px; text-align: center;
  font-size: clamp(12.5px, 0.95vw, 14px); line-height: 1.6; color: var(--off-white);
}
/* margin-top: auto pins the bar to the foot, so the name bars stay on one
   line across the row however much copy sits above them. */
.icard__namebar {
  margin-top: auto; display: block; padding: 17px 16px; text-align: center;
  border-top: 1px solid var(--hairline);
  font-family: var(--font-title); font-weight: 700; font-size: clamp(13px, 1.1vw, 16px);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--off-white);
  transition: background 280ms var(--ease-out), color 280ms var(--ease-out);
}
/* The whole card is the link now, not just the bar, so it lights from a
   hover anywhere on the card. */
.icard:hover .icard__namebar { background: var(--lime); color: var(--deep-blue); }

/* ---- responsive ---- */
@media (max-width: 980px) {
  .team__grid { grid-template-columns: repeat(2, 1fr); }
  /* Centring the odd card out only makes sense over three columns; below that
     it would push a lone card into the right-hand track, or invent a second
     track in the single-column layout. */
  .team__grid > .tcard:last-child:nth-child(3n + 1) { grid-column: auto; }
  .infra__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .network__body { margin-left: 0; }
  .pagehero { min-height: 62svh; }
}
@media (max-width: 640px) {
  .team__grid { grid-template-columns: 1fr; }
  .infra__grid { grid-template-columns: minmax(0, 1fr); }
  .tdetail__panel { width: 100vw; max-height: 100svh; height: 100svh; border: 0; }
  .vprow { flex-direction: column; gap: 6px; }
  .vprow__tag { margin-left: 0; }   /* stacked: no right-edge push */
}


/* =================================================================
   CONTACT PAGE (contact.html)
   Hero is deliberately compact (small uppercase eyebrow over a
   mid-size title) per the reference. The three cards use the numbered
   01/02/03 idiom from that same reference, drawn in the Fortunity card
   language already established by .icard on the team page.
   ================================================================= */

/* ---- compact hero ---- */
.pagehero--compact { min-height: 56svh; padding-block: clamp(130px, 20vh, 210px) clamp(44px, 8vh, 92px); }
.pagehero__title--compact { font-size: clamp(34px, 5.4vw, 76px); }

/* ---- the three contact cards ---- */
.contact { padding-block: var(--section-y); }
.contact__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 24px);
  align-items: stretch;
}
.ccard {
  display: flex; flex-direction: column;
  padding: clamp(22px, 2.2vw, 34px);
  border: 1px solid var(--hairline);
  background: linear-gradient(180deg, #0a1024 0%, #05070f 100%);
  transition: border-color 320ms var(--ease-out);
}
.ccard:hover { border-color: rgba(218,255,140,0.45); }
.ccard__top { padding-bottom: clamp(16px, 2.4vh, 26px); }
.ccard__tag {
  font-family: var(--font-title); font-size: 10px; letter-spacing: 0.2em;
  text-transform: uppercase; color: var(--ow-55);
}
.ccard__title {
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(20px, 1.9vw, 27px); line-height: 1.12; letter-spacing: -0.02em;
  color: var(--off-white); margin: 0 0 0.9rem;
}
.ccard__body {
  margin: 0; font-size: clamp(14px, 1.05vw, 15.5px); line-height: 1.6; color: var(--ow-80);
}
/* spec rows — same label/value rhythm as the team detail panel */
.ccard__meta { margin: auto 0 0; padding: clamp(20px, 3vh, 30px) 0 0; }
.ccard__row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 11px 0; border-top: 1px solid var(--hairline);
}
.ccard__row dt {
  font-family: var(--font-title); font-size: 9px; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--ow-50); flex: none;
}
.ccard__row dd {
  margin: 0; font-size: 13px; color: var(--ow-80); text-align: right; word-break: break-word;
}
.ccard__row dd a { color: var(--light-blue); transition: color 250ms var(--ease-out); }
.ccard__row dd a:hover { color: var(--lime); }
/* locations stack label above value, since the values are long */
.ccard__row--block { flex-direction: column; align-items: flex-start; gap: 6px; }
.ccard__row--block dd { text-align: left; font-family: var(--font-title); font-size: 13px; letter-spacing: 0.02em; color: var(--off-white); }
.ccard__place { display: block; margin-top: 4px; font-family: var(--font-body); font-size: 12px; color: var(--ow-55); }
/* full-width action bar, like the team institutional cards */
.ccard__action {
  margin-top: clamp(20px, 3vh, 30px); display: block; padding: 15px 16px; text-align: center;
  border: 1px solid var(--hairline);
  font-family: var(--font-title); font-weight: 700; font-size: 12px;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--off-white);
  transition: background 280ms var(--ease-out), color 280ms var(--ease-out), border-color 280ms var(--ease-out);
}
.ccard__action:hover { background: var(--lime); border-color: var(--lime); color: var(--deep-blue); }

/* ---- governance + sustainability + disclaimer, three up ---- */
.legal { padding-bottom: var(--section-y); }
.legal__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 1.6vw, 24px); align-items: stretch;
}
.lcard {
  padding: clamp(22px, 2.2vw, 34px);
  border: 1px solid var(--hairline); background: #05070f;
}
/* Promoted from a tracked-caps eyebrow: these two words are the only thing
   identifying each block, so they need to read as headings, not as chips. */
.lcard__title {
  margin: 0 0 clamp(14px, 2vh, 22px);
  font-family: var(--font-title); font-weight: 700;
  font-size: clamp(17px, 1.5vw, 21px); line-height: 1.15; letter-spacing: -0.01em;
  color: var(--off-white);
}
.lcard__body {
  margin: 0 0 0.9rem; max-width: 46ch;   /* was uncapped -> rendered 84 chars/line */
  font-size: clamp(13px, 1vw, 14.5px); line-height: 1.65; color: var(--ow-65);
}
.lcard__body:last-child { margin-bottom: 0; }
.lcard__body em { font-style: italic; color: var(--ow-80); }

/* ---- responsive ---- */
@media (max-width: 980px) {
  .contact__grid { grid-template-columns: 1fr; }
  .legal__grid { grid-template-columns: repeat(2, 1fr); }
  /* Three cards in two columns leaves the last one stranded at half width on
     its own row. Let it take the whole row instead. */
  .legal__grid .lcard:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .pagehero--compact { min-height: 48svh; }
}
@media (max-width: 700px) {
  .legal__grid { grid-template-columns: 1fr; }
}

/* ================= PITCH FORM (founders) ==================== *
 * Used by pitch.html as the design reference, and applied on WordPress to
 * whatever markup the form plugin outputs — hence the generous selector
 * lists: each plugin wraps fields in its own classes, so the shared rules
 * target our own .pfield markup AND the common plugin field wrappers.
 * ------------------------------------------------------------------- */
.pform { padding-block: clamp(56px, 9vh, 110px); background: var(--surface-deep); }
.pform__wrap { max-width: 860px; }
.pform__note {
  margin: 0 0 clamp(26px, 4vh, 40px);
  font-size: 12.5px; line-height: 1.6; color: var(--ow-55);
}
.pform__note a { color: var(--light-blue); }

.pform__grid {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(18px, 2.4vw, 28px);
}
.pfield { margin: 0; display: flex; flex-direction: column; gap: 7px; }
.pfield--wide { grid-column: 1 / -1; }

.pfield__label {
  font-family: var(--font-title); font-size: 11px; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--ow-80);
}
.pfield__req { color: var(--lime); margin-left: 2px; }
.pfield__hint { font-size: 12px; line-height: 1.55; color: var(--ow-55); }

/* The input surface. Deliberately flat and hairline-bordered to match the
   stat/filter blocks rather than introducing a new rounded control style. */
.pfield__input,
.pform input[type="text"], .pform input[type="url"], .pform input[type="email"],
.pform input[type="tel"], .pform textarea, .pform select {
  width: 100%; padding: 12px 14px;
  font-family: inherit; font-size: 14.5px; line-height: 1.5;
  color: var(--off-white); background: rgba(0, 12, 38, 0.55);
  border: 1px solid var(--hairline); border-radius: 2px;
  transition: border-color 220ms var(--ease-out), background 220ms var(--ease-out);
  -webkit-appearance: none; appearance: none;
}
.pfield__input::placeholder { color: var(--ow-35, rgba(242,242,244,0.35)); }
.pfield__input:hover,
.pform input:hover, .pform textarea:hover, .pform select:hover { border-color: var(--ow-55); }
.pfield__input:focus-visible,
.pform input:focus, .pform textarea:focus, .pform select:focus {
  outline: none; border-color: var(--lime);
  background: rgba(0, 12, 38, 0.8);
}
.pfield__input--area { resize: vertical; min-height: 120px; }

/* Native select arrow, drawn rather than imported so it inherits the palette. */
.pfield__input--select {
  background-image:
    linear-gradient(45deg, transparent 50%, var(--light-blue) 50%),
    linear-gradient(135deg, var(--light-blue) 50%, transparent 50%);
  background-position: right 18px center, right 13px center;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 38px; cursor: pointer;
}
.pfield__input--select option { background: #05070f; color: var(--off-white); }

/* File input: the button half is restyled, the filename half inherits. */
.pfield__input--file { padding: 9px 12px; cursor: pointer; font-size: 13px; }
.pfield__input--file::file-selector-button {
  margin-right: 12px; padding: 8px 14px; cursor: pointer;
  font-family: var(--font-title); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--light-blue); background: transparent;
  border: 1px solid var(--hairline); border-radius: 2px;
  transition: color 220ms var(--ease-out), border-color 220ms var(--ease-out);
}
.pfield__input--file:hover::file-selector-button {
  color: var(--lime); border-color: var(--lime);
}

.pform__actions {
  display: flex; flex-wrap: wrap; gap: 14px;
  margin-top: clamp(28px, 4vh, 44px);
}

/* Screen-reader-only text (the "required" word behind the asterisk). */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

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

/* WordPress-only states for the pitch page. The setup checklist is shown to
   administrators when no form shortcode is set yet; the fallback is what a
   visitor sees in that window, so nobody ever meets an empty section. */
.pform__setup {
  padding: clamp(22px, 3vw, 34px);
  border: 1px solid var(--hairline); border-radius: 2px;
  background: rgba(0, 12, 38, 0.55);
}
.pform__setup-title {
  margin: 0 0 0.9rem;
  font-family: var(--font-title); font-size: 12px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--lime);
}
.pform__setup-steps {
  margin: 0; padding-left: 1.2em; list-style: decimal;
  font-size: 13.5px; line-height: 1.7; color: var(--ow-65);
}
.pform__setup-steps li { margin-bottom: 0.5rem; }
.pform__setup-steps code {
  font-size: 0.92em; color: var(--light-blue);
  background: rgba(192, 214, 235, 0.08); padding: 1px 5px; border-radius: 2px;
}
.pform__fallback { font-size: 15px; line-height: 1.7; color: var(--ow-80); }
.pform__fallback a { color: var(--lime); }

/* ================= FULL-PAGE BACKDROP ====================== *
 * Opt-in via <body class="fullbg">. Carries the hero treatment — the animated
 * flow field plus the deep-blue light-to-dark wash — across the entire
 * document instead of stopping at the end of the hero. Used by the pitch page.
 *
 * The canvas is FIXED rather than document-height on purpose. The field paints
 * a dot every 10px, so a full-document canvas on a ~3000px page is roughly
 * 43,000 dots per frame against ~13,000 for a viewport-sized one — over three
 * times the per-frame cost. Fixed keeps it identical to the hero, and because
 * the field is abstract there is no seam as the page scrolls past it.
 *
 * The gradient, by contrast, IS document-height and absolutely positioned, so
 * it scrolls with the content: the page genuinely runs light at the top to
 * near-black at the bottom rather than repeating the hero ramp every viewport.
 * ------------------------------------------------------------------- */
body.fullbg { position: relative; background: var(--surface-deep); }

.pagebg { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.pagebg__canvas { position: fixed; inset: 0; width: 100%; height: 100%; display: block; }
.pagebg__overlay {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 55% at 12% 0%, rgba(192, 214, 235, 0.16), transparent 55%),
    linear-gradient(180deg,
      rgba(0, 21, 64, 0.38) 0%,
      rgba(0, 12, 38, 0.68) 45%,
      rgba(0, 0, 0, 0.90) 100%);
}

/* Content rides above the backdrop. .site-header is deliberately excluded —
   it is position:fixed with its own stacking, and giving it position:relative
   would drop the sticky nav. */
body.fullbg main,
body.fullbg .footer { position: relative; z-index: 1; }

/* Sections go transparent so the one backdrop shows through continuously. */
body.fullbg .pagehero,
body.fullbg .pform { background: transparent; }

/* ---- Contact Form 7 ------------------------------------------------
   CF7 forms are authored as markup, so the pitch form emits this theme's
   own .pfield / .pform classes and inherits nearly everything above. Only
   CF7's own wrappers and messages need styling, and they are what this block
   covers. Kept generic (no form id) so a rebuilt form keeps its look.
   ------------------------------------------------------------------- */

/* CF7 wraps every control in an inline <span>. Inside .pfield's flex column
   that leaves the input at shrink-to-fit width instead of filling the row. */
.pform .wpcf7-form-control-wrap { display: block; }

/* Inline validation message under a field. */
.pform .wpcf7-not-valid-tip {
  display: block; margin-top: 6px;
  font-size: 12px; line-height: 1.5; color: #ff9d9d;
}
.pform .wpcf7-not-valid { border-color: rgba(255, 157, 157, 0.65); }

/* Form-level response banner: CF7 reuses one element for success, validation
   failure and mail failure, so it is coloured by the state class it carries. */
.pform .wpcf7-response-output {
  margin: clamp(20px, 3vh, 30px) 0 0; padding: 14px 16px;
  border: 1px solid var(--hairline); border-radius: 2px;
  font-size: 13.5px; line-height: 1.6; color: var(--ow-80);
  background: rgba(0, 12, 38, 0.55);
}
.pform .wpcf7f-mail-sent-ok .wpcf7-response-output,
.pform form.sent .wpcf7-response-output {
  border-color: rgba(218, 255, 140, 0.5); color: var(--lime);
}
.pform form.invalid .wpcf7-response-output,
.pform form.unaccepted .wpcf7-response-output,
.pform form.failed .wpcf7-response-output,
.pform form.aborted .wpcf7-response-output {
  border-color: rgba(255, 157, 157, 0.5); color: #ff9d9d;
}

/* Submit button — CF7 emits a bare <input type="submit">, so it needs the
   .btn treatment restated rather than inherited. */
.pform input[type="submit"] {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-title); font-weight: 500; font-size: 12px;
  letter-spacing: 0.1em; text-transform: uppercase;
  padding: 14px 30px; border-radius: 2px; cursor: pointer;
  background: var(--lime); color: var(--deep-blue); border: 1px solid var(--lime);
  transition: background 300ms var(--ease-out), color 300ms var(--ease-out);
  -webkit-appearance: none; appearance: none;
}
.pform input[type="submit"]:hover { background: transparent; color: var(--lime); }
.pform input[type="submit"]:disabled { opacity: 0.55; cursor: default; }

/* The submitting spinner, which CF7 injects next to the button. */
.pform .wpcf7-spinner { margin-left: 14px; background-color: var(--light-blue); }

/* CF7 renders the file control as a plain input; match the styled one. */
.pform input[type="file"] {
  width: 100%; padding: 9px 12px; cursor: pointer;
  font-family: inherit; font-size: 13px; color: var(--off-white);
  background: rgba(0, 12, 38, 0.55);
  border: 1px solid var(--hairline); border-radius: 2px;
}
.pform input[type="file"]::file-selector-button {
  margin-right: 12px; padding: 8px 14px; cursor: pointer;
  font-family: var(--font-title); font-size: 11px; letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--light-blue); background: transparent;
  border: 1px solid var(--hairline); border-radius: 2px;
  transition: color 220ms var(--ease-out), border-color 220ms var(--ease-out);
}
.pform input[type="file"]:hover::file-selector-button {
  color: var(--lime); border-color: var(--lime);
}

/* ---- aspect-ratio fallback (Safari < 15, Chrome < 88) ---------------
   Every image box on the site sizes itself with aspect-ratio. Where that is
   unsupported the boxes fall back to the intrinsic height of whatever is
   inside them — which happens to work for a loaded photo and fails for
   anything else: an empty figure, a canvas, or a portrait whose image has
   not arrived. The classic padding-bottom ratio gives them a real height
   regardless. Costs nothing on browsers that support aspect-ratio, because
   the whole block is skipped.
   ------------------------------------------------------------------- */
@supports not (aspect-ratio: 1 / 1) {
  .tcard__portrait,
  .tdetail__figure {
    height: 0; padding-bottom: 125%;          /* 4:5 */
  }
  .icard__media {
    height: 0; padding-bottom: 68.75%;        /* 16:11 */
  }
  /* Children stack in the box rather than defining it. */
  .tcard__portrait > *,
  .tdetail__figure > *,
  .icard__media > * {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
  }
}
