/* ============================================================
   Vision Fund A LLC — landing
   No external requests. Fonts are self-hosted, latin subset.
   ============================================================ */

/* ---- Fonts ------------------------------------------------- */

/* Bodoni Moda ships as a variable font (optical size 6–96). */
@font-face {
  font-family: 'Bodoni Moda';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/bodoni-moda-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter is variable — one file covers the 300 and 400 we use. */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 300 400;
  font-display: swap;
  src: url('/fonts/inter-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/ibm-plex-mono-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- Tokens ------------------------------------------------ */

:root {
  --bg: #070D16;
  --brand: #0C2138;
  --ink: #E8ECF2;
  --ink-dim: #8B98A9;
  --accent: #C7B28A;
  --rule: rgba(232, 236, 242, 0.12);

  --font-display: 'Bodoni Moda', Didot, 'Times New Roman', serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --gut: clamp(20px, 5vw, 64px);   /* page gutter */
  --max: 1760px;                   /* content cap, keeps 4K sane */
}

/* ---- Reset ------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, p { margin: 0; }

a { color: inherit; }

::selection { background: var(--accent); color: var(--bg); }

:focus-visible {
  outline: 1px solid var(--accent);
  outline-offset: 4px;
}

.mono {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

/* The <defs> sprite carrying the V mark. Zero-sized, but taken out of flow
   so it can never affect layout. Lives here rather than in a style attribute:
   the CSP has no 'unsafe-inline', which covers style attributes too. */
.sprite { position: absolute; }

/* ---- Film grain -------------------------------------------- */

.grain {
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 160px 160px;
}

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

.hero {
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
}

.hero__inner {
  position: relative;
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding: clamp(24px, 4vw, 48px) var(--gut) clamp(24px, 4vw, 44px);
  display: grid;
  grid-template-rows: auto 1fr auto;
  row-gap: clamp(40px, 8vh, 96px);
}

.hero__top,
.hero__bot {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  gap: 16px;
}

.hero__top { align-items: flex-start; }
.hero__bot { align-items: flex-end; }

.hero__est { letter-spacing: 0.18em; text-align: right; }

.logo {
  display: block;
  height: 28px;
  width: auto;
  fill: var(--ink);
  flex: none;
}

.hero__mid {
  position: relative;
  z-index: 1;
  align-self: center;
  justify-self: start;
}

h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.8rem, 5vw, 4rem);
  line-height: 1.22;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* The <br> sets the two-line shape; no max-width, or it wraps to three. */
}

/* Layered V motif — five fanned echoes along the stroke diagonal */
.motif {
  position: absolute;
  z-index: 0;
  top: 50%;
  right: -5%;
  width: min(58%, 760px);
  aspect-ratio: 309.29 / 267.86;
  transform: translateY(calc(-54% + var(--py, 0px)));
  pointer-events: none;
}

.motif svg {
  width: 100%;
  height: 100%;
  overflow: visible;   /* echoes fan outside the viewBox */
}

.motif__e {
  --amp: 4;
  fill: #fff;
  opacity: var(--o);
  /* Resting offset. fanDrift overrides this while it runs; it stays as the
     static fallback for prefers-reduced-motion, where the animation is off. */
  transform: translate(var(--tx), var(--ty));
}

/* A slow breathing fan: each layer creeps along the logo's own stroke
   diagonal (x:y ≈ 154.65:267.86 — shallow x, steeper y) and back.

   --amp is the only knob. Percentages resolve against the viewBox
   (309.29 × 267.86), which the motif renders at ~2.5x, so one unit of --amp
   is only ~11 x 16 px on screen — below the threshold of perception on its
   own. 4 gives a drift you can notice without it reading as movement. */
@keyframes fanDrift {
  from { transform: translate(var(--tx), var(--ty)); }
  to   { transform: translate(calc(var(--tx) + var(--amp) * 1.4%),
                              calc(var(--ty) + var(--amp) * 2.4%)); }
}

/* Back to front. Mismatched durations and negative delays keep the layers
   out of phase, so the fan never visibly pulses in unison. */
.motif__e--1 { --o: 0.03;  --tx: -38%;   --ty: -33%;    --i: 0; animation: fanDrift 38s ease-in-out  -4s infinite alternate; }
.motif__e--2 { --o: 0.045; --tx: -28.5%; --ty: -24.75%; --i: 1; animation: fanDrift 32s ease-in-out -12s infinite alternate; }
.motif__e--3 { --o: 0.06;  --tx: -19%;   --ty: -16.5%;  --i: 2; animation: fanDrift 27s ease-in-out -20s infinite alternate; }
.motif__e--4 { --o: 0.08;  --tx: -9.5%;  --ty: -8.25%;  --i: 3; animation: fanDrift 23s ease-in-out  -8s infinite alternate; }
.motif__e--5 { --o: 0.10;  --tx: 0%;     --ty: 0%;      --i: 4; animation: fanDrift 20s ease-in-out -15s infinite alternate; }

@media (prefers-reduced-motion: reduce) {
  .motif__e { animation: none !important; }
}

/* On narrow screens the motif sits behind the type, cropped at the edge. */
@media (max-width: 720px) {
  .motif {
    right: -22%;
    width: 96%;
  }
}

/* ---- Mandate ----------------------------------------------- */

.mandate {
  position: relative;
  z-index: 1;
  padding-top: clamp(100px, 18vh, 200px);
  overflow: hidden;
}

.mandate__geo {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.mandate__ring {
  position: absolute;
  top: clamp(20px, 6vh, 60px);
  left: 50%;
  transform: translateX(-50%);
  width: min(70vw, 560px);
  aspect-ratio: 1;
  border: 1px solid rgba(139, 152, 169, 0.10);
  border-radius: 50%;
}

.mandate__diag {
  position: absolute;
  top: 0;
  left: 50%;
  width: 1px;
  height: clamp(300px, 60vh, 640px);
  background: rgba(139, 152, 169, 0.10);
  transform: translateX(-50%) rotate(30deg);
  transform-origin: top center;
}

.mandate__head {
  position: relative;
  padding-inline: var(--gut);
  text-align: center;
}

.eyebrow {
  font-size: 11px;
  letter-spacing: 0.32em;
  font-weight: 400;
}

.mandate__grid {
  position: relative;
  margin-top: clamp(72px, 12vh, 140px);
  max-width: var(--max);
  margin-inline: auto;
  display: grid;
  grid-template-columns: 1fr;
  border-top: 1px solid var(--rule);
}

.mandate__cell {
  display: flex;
  flex-direction: column;
  padding: clamp(40px, 6vh, 64px) clamp(28px, 3.5vw, 56px) clamp(48px, 8vh, 80px);
  border-bottom: 1px solid var(--rule);
}

@media (min-width: 900px) {
  .mandate__grid { grid-template-columns: repeat(3, 1fr); }
  .mandate__cell + .mandate__cell { border-left: 1px solid var(--rule); }
}

.mandate__num {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.14em;
  color: var(--accent);
}

.mandate__label {
  margin-top: 22px;
  font-family: var(--font-display);
  font-weight: 400;
  font-variant: small-caps;
  font-size: clamp(24px, 2.6vw, 32px);
  letter-spacing: 0.05em;
  line-height: 1.2;
}

.mandate__body {
  margin-top: auto;
  font-size: 14px;
  line-height: 2;
  color: var(--ink-dim);
}

/* Cell glyphs */
.glyph {
  --line: rgba(139, 152, 169, 0.18);
  display: block;
  width: 64px;
  height: 64px;
  margin: clamp(32px, 6vh, 56px) 0;
  flex: none;
}

.glyph--ring {
  border: 1px solid var(--line);
  border-radius: 50%;
}

.glyph--stack {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}
.glyph--stack i {
  height: 14px;
  border: 1px solid var(--line);
  border-radius: 50%;
}

.glyph--star { position: relative; }
.glyph--star i {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--line);
}
.glyph--star i:nth-child(2) { transform: rotate(60deg); }
.glyph--star i:nth-child(3) { transform: rotate(-60deg); }

/* ---- Contact ----------------------------------------------- */

.contact {
  position: relative;
  z-index: 1;
  padding: clamp(80px, 16vh, 180px) var(--gut);
  text-align: center;
}

.contact__h {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(24px, 3.2vw, 40px);
  letter-spacing: 0.02em;
  line-height: 1.3;
  margin-bottom: 20px;
}

.contact__sub {
  font-size: 14px;
  line-height: 1.8;
  color: var(--ink-dim);
  margin-bottom: clamp(32px, 5vh, 48px);
}

.contact__link {
  display: inline-block;
  font-size: 14px;
  letter-spacing: 0.12em;
  text-transform: none;
  color: var(--ink);
  text-decoration: none;
  padding-bottom: 5px;
  border-bottom: 1px solid transparent;
  transition: color 0.25s ease, border-color 0.25s ease;
}

.contact__link:hover,
.contact__link:focus-visible {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* ---- Footer ------------------------------------------------ */

.legal {
  position: relative;
  z-index: 1;
  border-top: 1px solid var(--rule);
  padding: clamp(28px, 4vh, 40px) var(--gut) clamp(32px, 5vh, 48px);
  max-width: var(--max);
  margin-inline: auto;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 400;
  line-height: 2;
  letter-spacing: 0.06em;
  color: var(--ink-dim);
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.legal__disclaimer { max-width: 72em; }

/* ============================================================
   Motion
   Initial (hidden) states apply only where scripting is on AND
   the visitor has not asked for reduced motion. So: fully
   readable with JS off, static final states under reduced
   motion — while the clock keeps ticking in both cases.
   ============================================================ */

@media (scripting: enabled) and (prefers-reduced-motion: no-preference) {

  /* 1 — motif echoes fade/slide in, 120ms stagger, 900ms total.
     The slide rides on the independent `translate` property, not on
     `transform`: fanDrift owns `transform`, and a running animation always
     beats a transition on the same property. The two compose instead. */
  .motif__e {
    transition:
      opacity 420ms cubic-bezier(0.22, 1, 0.36, 1),
      translate 420ms cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(var(--i) * 120ms);
  }

  .motif:not(.is-in) .motif__e {
    opacity: 0;
    translate: -6% -5.2%;
  }

  /* 2 — section reveals */
  .reveal {
    transition:
      opacity 600ms cubic-bezier(0.22, 1, 0.36, 1),
      transform 600ms cubic-bezier(0.22, 1, 0.36, 1);
  }

  .reveal:not(.is-in) {
    opacity: 0;
    transform: translateY(12px);
  }
}
