/* =========================================================================
   ANINTERVAL — monochrome reel + zoom-to-white reveal
   Palette is deliberately black/white/grey only. The single bold moment is
   the reveal transition; everything else stays quiet.
   ========================================================================= */

:root {
  --ink:      #111111;   /* text on paper                */
  --ink-2:    #5a5a5a;   /* secondary text               */
  --ink-3:    #9a9a9a;   /* faint / captions             */
  --paper:    #ffffff;   /* the reveal background        */
  --night:    #0a0a0a;   /* video fallback / hero base   */
  --on-dark:  #ffffff;   /* text over the reel           */
  --hairline: rgba(17, 17, 17, 0.14);

  --ease: cubic-bezier(0.7, 0, 0.2, 1);          /* UI micro-interactions */
  /* reveal easing = Ease & Wizz "inoutExpo" sampled directly from the client's
     After Effects math (2^-10 correction included) so the web curve IS his curve,
     not a cubic-bezier approximation. Needs linear(): Chrome 113+/Safari 17.4+/FF 112+. */
  --ease-expo: linear(
    0, 0.0004 4.2%, 0.0011 8.3%, 0.0023 12.5%, 0.0044 16.7%, 0.0083 20.8%,
    0.0151 25%, 0.0274 29.2%, 0.0491 33.3%, 0.0879 37.5%, 0.157 41.7%,
    0.2801 45.8%, 0.5005 50%, 0.7199 54.2%, 0.843 58.3%, 0.9121 62.5%,
    0.9509 66.7%, 0.9726 70.8%, 0.9849 75%, 0.9917 79.2%, 0.9956 83.3%,
    0.9977 87.5%, 0.9989 91.7%, 0.9996 95.8%, 1
  );
  --flood-ms: 2000ms;                            /* circle grow (open) — trimmed: past ~65% it only grows off-screen */
  --flood-close-ms: 2000ms;                      /* circle recede (close) — mirrors open */
  --reveal-ms: 600ms;

  /* Hero geometry — single source of truth so the reveal origin tracks the logo. */
  --hero-pad: clamp(1.25rem, 3.5vw, 2.75rem);
  --logo-w: clamp(44px, 7.5vw, 95px);

  --display: "Space Grotesk", system-ui, sans-serif;
  --mono: "Space Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  background: var(--night);
  color: var(--on-dark);
  font-family: var(--display);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow: hidden;                 /* hero locks scroll; content scrolls itself */
}

body.is-open { overflow: hidden; }

/* ============================ BACKGROUND REEL ============================ */

.video-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: var(--night);
}

/* 16:9 cover: scale to whichever dimension leaves no letterboxing. */
.video-bg iframe {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 100vw;
  height: 56.25vw;      /* 100vw * 9/16 */
  min-height: 100vh;
  min-width: 177.78vh;  /* 100vh * 16/9 */
  transform: translate(-50%, -50%);
  border: 0;
  pointer-events: none; /* let clicks reach the UI, not the Vimeo chrome */
}

/* ================================ HERO ================================== */
/* Corner-anchored UI over a full-bleed reel — no overlay; the video is the
   hero. A soft drop-shadow keeps text/logo readable over bright frames
   without a scrim; it's expected to fade against light footage at times. */

.hero {
  position: fixed;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: var(--hero-pad);
  color: var(--on-dark);
}

.hero__row {
  display: flex;
  justify-content: space-between;
  gap: 1.5rem;
}
.hero__row--top { align-items: flex-start; }
.hero__row--bottom { align-items: flex-end; justify-content: flex-end; }

.logo svg { display: block; }
.logo svg path { fill: currentColor; }

.logo--hero {
  color: var(--on-dark);
  width: var(--logo-w);
  filter: drop-shadow(0 6px 24px rgba(0, 0, 0, 0.4));
}

.cta {
  /* -webkit-appearance is NOT redundant: iOS Safari before 15.4 only honours the
     prefixed form, and without it the native button styling wins — its own small
     corner radius and grey gradient, ignoring border-radius/background below. */
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  padding: 0.95rem 1.6rem;
  /* Always paint a scrim. The blur is an enhancement, never the thing that makes
     the label legible: iOS drops backdrop-filter under Low Power Mode and Reduce
     Transparency, and frequently won't sample a cross-origin <iframe> backdrop at
     all — which is exactly what the Vimeo reel is. A transparent background left
     the label floating on bare footage whenever that happened. */
  background: rgba(10, 10, 10, 0.32);
  color: var(--on-dark);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 0.82rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  /* Same trick the hero logo uses to survive bright frames without a full scrim. */
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.45);
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.22);
  -webkit-tap-highlight-color: transparent;  /* kill the iOS grey tap flash */
  transition: background 300ms ease, border-color 300ms ease, color 300ms ease, transform 300ms var(--ease);
}

/* Blur is added only where it renders, and the scrim above is deliberately NOT
   lightened to compensate. @supports answers "does this build know the property",
   which stays true on iOS even when Low Power Mode / Reduce Transparency disables
   the effect at runtime — so anything that leans on the blur for contrast fails
   exactly there. The pill reads identically with or without it; the blur only
   softens what shows through. */
@supports ((-webkit-backdrop-filter: blur(6px)) or (backdrop-filter: blur(6px))) {
  .cta {
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
}

/* Pointer-only. iOS leaves :hover stuck on whatever you last tapped until you
   tap something else, so on a phone this invert survived the entire open/close
   cycle and the pill came back solid white instead of frosted. */
@media (hover: hover) {
  .cta:hover {
    background: var(--on-dark);
    color: var(--night);
    border-color: var(--on-dark);
    transform: translateY(-2px);
    text-shadow: none;   /* dark label on a solid white pill needs no lift */
  }
}

/* Focus deliberately does NOT reuse the invert above. close() hands focus back
   to this button (js/main.js) so keyboard users don't lose their place, which
   means every single close left the pill wearing its hover skin — and because
   the invert flips `color` to --night, the global focus ring below inherited it
   via currentColor and came back black. Ring only; the frost stays put. */
.cta:focus-visible {
  outline: 2px solid var(--on-dark);
  outline-offset: 3px;
}

/* ============================= REVEAL WIPE ============================== */

/* A white circle scales up from the logo's corner to take over the screen. */
.flood {
  position: fixed;
  /* Origin = the CIRCLE inside the logo, not the mark's bounding-box center.
     The circle's center in the SVG viewBox (0 0 1835.14 1131.73) is (919.76, 300.98).
     As fractions of the rendered logo WIDTH: x = 919.76/1835.14 = 0.5012;
     y = (300.98/1131.73) * (1131.73/1835.14) = 300.98/1835.14 = 0.1640.
     Tied to --logo-w, so it stays locked to the circle at every viewport. */
  left: calc(var(--hero-pad) + var(--logo-w) * 0.5012);
  top: calc(var(--hero-pad) + var(--logo-w) * 0.164);
  width: 300vmax;
  height: 300vmax;
  z-index: 3;
  background: var(--paper);
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%) scale(0);
  transition: transform var(--flood-close-ms) var(--ease-expo);   /* close */
  will-change: transform;
}

body.is-open .flood {
  transform: translate(-50%, -50%) scale(1);
  transition: transform var(--flood-ms) var(--ease-expo);         /* open, slower */
}

/* Don't pre-fade the hero — let the flood wipe over it, so the logo stays put
   and the white grows straight out of the logo dot. Just make it inert. */
body.is-open .hero {
  pointer-events: none;
}

/* =============================== CONTENT ================================ */

.content {
  position: fixed;
  inset: 0;
  z-index: 4;
  background: var(--paper);
  color: var(--ink);
  overflow-y: auto;
  overflow-x: hidden;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--reveal-ms) ease, visibility 0s linear var(--flood-ms);
}

body.is-open .content {
  opacity: 1;
  visibility: visible;
  /* Fade in the moment the wipe has covered the screen (~65% into the flood),
     not at the very end — the rest of the circle's growth is off-screen. */
  transition: opacity var(--reveal-ms) ease calc(var(--flood-ms) * 0.65);
}

.content__inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(1.25rem, 3.5vw, 2.75rem);
  min-height: 100%;
  display: flex;
  flex-direction: column;
}

/* Content rises slightly as it fades in. */
.masthead,
.content__grid,
.colophon {
  transform: translateY(14px);
  transition: transform 700ms var(--ease);
}
body.is-open .masthead,
body.is-open .content__grid,
body.is-open .colophon { transform: none; }
body.is-open .content__grid { transition-delay: 60ms; }
body.is-open .colophon { transition-delay: 120ms; }

/* --- Masthead --- */
.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding-bottom: clamp(2rem, 6vw, 4rem);
}
.logo--mark { color: var(--ink); width: 60px; }

.close {
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  background: transparent;
  border: 0;
  padding: 0.4rem 0.2rem;
  color: var(--ink);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.close svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.5; }
.close:hover .close__x, .close:hover { color: var(--ink-2); }

/* --- Grid --- */
.content__grid {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  grid-template-areas:
    "intro connect"
    "farm  farm";
  column-gap: clamp(2rem, 6vw, 5rem);
  row-gap: clamp(3rem, 7vw, 5rem);
  flex: 1;
  padding-bottom: clamp(3rem, 8vw, 6rem);
}
.block--intro { grid-area: intro; }
.block--connect { grid-area: connect; }
.block--farm { grid-area: farm; }
/* Let grid columns shrink below content min-size instead of overflowing. */
.block { min-width: 0; }

/* Each column flows independently; the bio fills the left to roughly
   match the right, so the farm starts on a clean line. */
.block--intro { display: flex; flex-direction: column; gap: clamp(1.5rem, 3vw, 2.25rem); }

.bio {
  max-width: 42ch;
  font-size: clamp(1rem, 1.3vw, 1.12rem);
  line-height: 1.65;
  color: var(--ink-2);
  margin: 0;
}

/* --- Type --- */
.eyebrow {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 1.25rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--hairline);
}
.eyebrow--spaced { margin-top: 2.75rem; }

.statement {
  font-weight: 700;
  font-size: clamp(2.2rem, 5.6vw, 4rem);
  line-height: 1.02;
  letter-spacing: -0.03em;
  overflow-wrap: break-word;
  margin: 0;
}

/* --- Info list + social --- */
.info-list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--hairline); }

.info-link {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--hairline);
  text-decoration: none;
  color: var(--ink);
  transition: padding-left 260ms var(--ease), color 200ms ease;
}
.info-link:hover, .info-link:focus-visible { padding-left: 0.5rem; color: var(--ink-2); }
.info-link__k {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-3);
  min-width: 4.5rem;
}
.info-link__v { font-size: clamp(1.05rem, 1.6vw, 1.3rem); font-weight: 500; min-width: 0; overflow-wrap: anywhere; }

/* Social sits inline as a list row, matching the email/phone rows. */
.info-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--hairline);
}
.info-row .info-link__k { align-self: center; }

.social-icons { display: flex; gap: 1.1rem; }
.social-icon {
  display: inline-flex;
  color: var(--ink);
  transition: color 200ms ease, transform 200ms var(--ease);
}
.social-icon svg { width: 26px; height: 26px; display: block; }
.social-icon:hover, .social-icon:focus-visible { color: var(--ink-2); transform: translateY(-2px); }

/* --- Logo farm --- */
/* 21 marks — 7 columns x 3 rows, so the last row is never ragged.
   (The only clean divisors of 21 are 7 and 3; the mobile rule below uses 3.) */
.logo-farm {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: clamp(0.5rem, 1vw, 0.75rem);
}
.logo-farm__cell {
  aspect-ratio: 16 / 10;
  background: #f5f5f5;
  border-radius: 4px;
  overflow: hidden;
}
/* Every mark is pre-normalized to a shared 320x200 (16:10) viewBox with the art
   scaled to a constant geometric mean, so wide wordmarks and square marks read
   at the same optical weight — the tile aspect matches, so `contain` never
   letterboxes. The source SVGs are monochrome #111, so the hover move is weight,
   not colour: dimmed at rest, full ink on hover. */
.logo-farm__cell img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0.55;
  transition: opacity 350ms var(--ease);
}
.logo-farm__cell:hover img { opacity: 1; }
/* Touch devices can't hover — show every mark at full weight so none read as disabled. */
@media (hover: none) {
  .logo-farm__cell img { opacity: 1; }
}

/* --- Form --- */
.form { display: flex; flex-direction: column; gap: 1.4rem; max-width: 30rem; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.field { display: flex; flex-direction: column; gap: 0.5rem; }
.field label {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.field input, .field textarea {
  /* Same prefix story as the buttons — iOS otherwise gives inputs (and especially
     <textarea>) a native inset border and its own corner radius. font-size must
     stay >= 16px or iOS zooms the page in on focus. */
  -webkit-appearance: none;
  appearance: none;
  font-family: var(--display);
  font-size: 1rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  padding: 0.65rem 0;
  border-radius: 0;
  transition: border-color 220ms ease;
  resize: vertical;
}
.field input:focus, .field textarea:focus {
  outline: none;
  border-color: var(--ink);
}
.field input:user-invalid, .field textarea:user-invalid { border-color: #b23b3b; }

/* --- Solid pill (shared by "View reel" and the form's Send) --- */
.btn-solid, .submit {
  -webkit-appearance: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  padding: 0.95rem 2.2rem;
  background: var(--ink);
  color: var(--paper);
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background 220ms ease, color 220ms ease, transform 220ms var(--ease);
}
/* Pointer-only, same sticky-tap reason as the hero CTA: tapping "View reel" or
   "Send" on iOS would otherwise leave the pill inverted after the finger lifts. */
@media (hover: hover) {
  .btn-solid:hover, .submit:hover {
    background: var(--paper); color: var(--ink); transform: translateY(-2px);
  }
}
/* These two keep the invert on focus, but the ring colour is set explicitly rather
   than left to currentColor: on the white content page an un-inverted pill has
   white text, so a currentColor ring would be white-on-white and invisible. Naming
   --ink means the ring shows whether or not the invert lands. No transform — focus
   shouldn't nudge the button. */
.btn-solid:focus-visible, .submit:focus-visible {
  background: var(--paper); color: var(--ink);
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}
.submit { align-self: flex-start; margin-top: 0.5rem; }
.submit[disabled] { opacity: 0.5; cursor: default; transform: none; }

/* "View the work" sits under the bio; the intro column's gap handles the
   space above it, so only kill the default paragraph margins. */
.work-cta { margin: 0; }

.form__status {
  min-height: 1.2em;
  margin: 0.25rem 0 0;
  font-family: var(--mono);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
}
.form__status.is-ok  { color: #2f7d4f; }
.form__status.is-err { color: #b23b3b; }

/* --- Colophon --- */
.colophon {
  display: flex;
  justify-content: space-between;
  padding-top: 1.75rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ============================== A11Y + FOCUS ============================ */

/* No border-radius here. It used to set 2px to round the ring on square targets,
   but :focus-visible and a class both weigh the same and this rule sits later in
   the file — so it silently overrode every pill's radius, squaring the CTA and
   both solid buttons whenever they held focus. Outlines already follow the
   element's own radius, so the ring rounds itself. */
:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
}

/* =============================== RESPONSIVE ============================= */

@media (max-width: 760px) {
  .content__grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "intro"
      "connect"
      "farm";
  }
  /* 7 -> 3 only once the content is single-column: at tablet widths the farm
     still spans the full grid, so 3 columns there would blow the tiles up to
     ~275px. 3 and 7 are the only divisors of 21 that keep the last row full. */
  .logo-farm { grid-template-columns: repeat(3, 1fr); }
}

/* ============================ REDUCED MOTION ============================ */

@media (prefers-reduced-motion: reduce) {
  .logo--hero,
  .flood,
  .content,
  .masthead,
  .content__grid,
  .colophon,
  .cta,
  .submit,
  .btn-solid,
  .logo-farm__cell img,
  .info-link { transition-duration: 1ms !important; transition-delay: 0s !important; }

  body.is-open .logo--hero { opacity: 0; transform: none; }
}
