*,
*::before,
*::after {
  box-sizing: border-box;
}

:root {
  --bg: #0b0b0d;
  --fg: #f4f4f5;
  --muted: #a1a1aa;
  /* sampled from the gate's glow at the center of assets/images/bg.png */
  --gold: #ffb600;
}

html,
body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
}

/* Lenis's own reset (html.lenis height, scroll-behavior:auto, [data-lenis-prevent],
   .lenis-stopped) comes from the lenis.css <link> in index.html — don't restate it here. */

/* ---------- hero ---------- */

/* Height above 100vh is the distance the stage stays pinned for. */
.hero {
  position: relative;
  height: 200vh;
}

.hero__stage {
  position: sticky;
  top: 0;
  height: 100vh;
  overflow: hidden;
  display: grid;
  place-items: center;
}

/* Scaled by hero.js via --scroll-scale. will-change is applied only while the
   hero is near the viewport (.is-near, set in hero.js) — promoting every
   full-viewport layer for the page's whole life costs hundreds of MB of
   compositor memory and buys nothing for heroes nowhere near the screen. */
.hero__media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(var(--scroll-scale, 1));
  transform-origin: center;
}

/* Sits on top of the base .hero__media and fades in with scroll progress. */
.hero__media--overlay {
  opacity: var(--scroll-progress, 0);
}

.is-near .hero__media {
  will-change: transform;
}

.is-near .hero__media--overlay {
  will-change: transform, opacity;
}

/* Video hero: dissolves to the still within the first 30% of the pin (STILL_AT in hero.js),
   then hero.js hides the video so only one layer is composited for the rest of the scroll. */
.hero__media--still {
  opacity: calc(var(--scroll-progress, 0) / 0.3);
}

/* Intro -> loop dissolve. Opacity only, so it never competes with the scroll transforms. */
.hero__media--out {
  opacity: 0;
  transition: opacity 0.8s ease-in-out;
}

.is-still video.hero__media {
  visibility: hidden;
}

.hero__stage::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(11, 11, 13, 0.25), rgba(11, 11, 13, 0.85));
}

/* Gradient fades away as the title leaves, so the bg.png it crosses into shows undimmed. */
.hero__stage--clear::after {
  opacity: calc(1 - var(--scroll-progress, 0));
}

.is-near .hero__stage--clear::after,
.is-near .hero__stage--band::after {
  will-change: opacity;
}

/* Faded and lifted by hero.js via --scroll-progress on the way OUT.
   --enter (default 1, harmless no-op) additionally drives a fade IN on the
   way in for any .hero__content that also carries the .hero__content--enter
   marker (see hero.js) — the crossfade content bands opt into this so
   their text doesn't just pop in fully visible before fading out; the plain
   tagline hero__content is unaffected. Deliberately NOT reusing the plain
   `.reveal` class here: that rule sets its own opacity/transform outright
   and, being defined later in this file, would win the cascade and
   silently discard this combined formula. */
.hero__content {
  position: relative;
  z-index: 1;
  text-align: center;
  padding: 0 1.5rem;
  opacity: calc((1 - var(--scroll-progress, 0)) * var(--enter, 1));
  transform: translateY(calc(var(--scroll-progress, 0) * -6rem + (1 - var(--enter, 1)) * 2rem));
}

.is-near .hero__content {
  will-change: transform, opacity;
}

.hero__content h1 {
  margin: 0 0 1rem;
  font-size: clamp(2.5rem, 8vw, 6rem);
  line-height: 1;
  letter-spacing: -0.03em;
}

.hero__content p {
  margin: 0;
  font-size: clamp(2rem, 4vw, 2.2rem);
}

.hero__content p[data-config="SLOGAN"] {
  font-weight: 700;
}

/* Load-in: hero.js adds .is-titled; the backwards fill hides text during each delay. */
.hero__word {
  display: inline-block;
}

.hero__letter {
  display: inline-block;
}

.is-titled .hero__letter {
  animation: letter-in 1.8s cubic-bezier(0.2, 0.7, 0.2, 1) both;
  animation-delay: calc(var(--i) * 90ms);
}

.is-titled p[data-config="SLOGAN"] {
  animation: slogan-in 1.8s ease-out 1.8s both;
}

@keyframes letter-in {
  from {
    opacity: 0;
    transform: translateY(0.4em);
    filter: blur(12px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes slogan-in {
  from {
    opacity: 0;
    transform: translateY(0.6rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.hero__hint {
  position: absolute;
  bottom: 2rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1;
  color: var(--muted);
  font-size: 0.8125rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  opacity: calc(1 - var(--scroll-progress, 0) * 2);
}

/* ---------- sections below the hero ---------- */

.section {
  position: relative;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 6rem 1.5rem;
  background: #000;
}

.section::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(11, 11, 13, 0.72);
}

/* min-width:0 defeats the grid item's automatic minimum size; without it the
   financials table's min-content width forces the whole page 50px wider than
   the phone viewport and .table-wrap's overflow-x never engages. */
.section__inner {
  position: relative;
  z-index: 1;
  max-width: 40rem;
  min-width: 0;
}

.section h2 {
  margin: 0 0 1rem;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  color: var(--gold);
}

.section p {
  margin: 0 0 2rem;
  color: var(--fg);
  font-size: 1.375rem;
  line-height: 1.6;
}

/* ---------- scroll reveal (plain, non-pinned sections) ---------- */

/* Continuous scroll-driven reveal — see prototype/hero.js. Tied directly
   to scroll position (like the rest of this prototype), not a fire-once
   transition, so fast scrolling can't skip past it. */
.reveal {
  opacity: var(--enter, 0);
  transform: translateY(calc((1 - var(--enter, 0)) * 2rem));
  will-change: transform, opacity;
}

/* ---------- content-heavy sections (assets/content.json expansion) ---------- */

/* Wider variant for sections carrying phases/tables instead of one column of text. */
.section__inner--wide {
  max-width: 56rem;
}

/* ---------- mission section (logo + text side by side) ---------- */

.mission__layout {
  display: flex;
  align-items: center;
  gap: 3rem;
}

.mission__logo {
  flex: 0 0 auto;
  width: clamp(120px, 20vw, 220px);
  height: auto;
}

.mission__text {
  flex: 1 1 auto;
  min-width: 0;
}

.mission__text h2 {
  margin: 0 0 1rem;
  font-size: clamp(1.75rem, 4vw, 2.75rem);
  color: var(--gold);
}

.mission__text p {
  margin: 0 0 2rem;
  color: var(--fg);
  font-size: 1.375rem;
  line-height: 1.6;
}

/* Longer descriptive copy inside a pinned hero — smaller than the tagline text. */
.hero__content p.hero__subtitle {
  font-size: 1.375rem;
  font-weight: 400;
  line-height: 1.6;
  color: var(--fg);
  margin: 0 0 2rem;
}

.hero__content p.hero__subtitle--highlight {
  color: var(--gold);
  font-weight: 700;
}

.hero__content h2 {
  margin: 0 0 1rem;
  font-size: clamp(2rem, 6vw, 3.5rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
}

/* Content-heavy crossfade heroes (columns/points) need more than the
   centered-tagline width the default .hero__content is sized for. */
.hero__content--content {
  width: 100%;
  max-width: 64rem;
}

/* "safe center" centers when the content fits, and falls back to a
   scrollable top alignment when it doesn't — plain "center" would center
   it beyond the pinned/overflow:hidden stage's edges with no way to
   scroll to the clipped part.
   The scrollbar is given zero width on purpose: .hero__content's translateY
   inflates this container's scrollHeight as the pin progresses, so a normal
   scrollbar pops in the instant the zoom starts, steals ~15px of width and
   rewraps the text — a visible jump at exactly the hand-off. Hiding it keeps
   the overflow escape hatch without ever changing the content width. */
.hero__stage--content {
  align-items: safe center;
  overflow-y: auto;
  scrollbar-width: none;
}

.hero__stage--content::-webkit-scrollbar {
  display: none;
}

/* Darkens the entire pinned viewport (flat, not gradient) while keeping the
   text constrained to .hero__content--content's readable max-width.
   Flat overlay only — no local card/box behind the text — so it has to be
   dark enough on its own to stay readable over bright source photos.
   Opacity mirrors .hero__content's own formula: --enter (set directly on
   this element by hero.js) fades the band IN alongside the content as the
   section scrolls into view, and --scroll-progress fades it back OUT at the
   end of the pin, instead of staying a permanent flat dark layer.
   will-change promotes it while the hero is near the viewport (.is-near):
   without it, fading a full-viewport layer repaints everything underneath it
   every frame. */
.hero__stage--band::after {
  background: rgba(0, 0, 0, 0.75);
  opacity: calc((1 - var(--scroll-progress, 0)) * var(--enter, 1));
}

.hero__content--band {
  position: relative;
  padding: 3rem 1.5rem;
}

.hero__stage--content .hero__content--band {
  margin: 4rem 0;
}

.content-columns {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 2rem;
  text-align: left;
}

.content-column h3 {
  margin: 0 0 1rem;
  font-size: 1.5rem;
}

.content-column h3 span {
  display: block;
  margin-bottom: 2rem;
  color: var(--gold);
}

.point {
  text-align: left;
  margin: 0 0 1.25rem;
}

.point strong {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--fg);
  font-size: 1.25rem;
}

.point p {
  margin: 0;
  color: var(--fg);
  font-size: 1.125rem;
  line-height: 1.6;
}

.phase-list {
  display: grid;
  gap: 1.5rem;
  text-align: left;
}

.phase h3 {
  margin: 0 0 0.5rem;
  font-size: 1.5rem;
}

.phase h3 span {
  color: var(--gold);
}

.point--gold strong {
  color: var(--gold);
}

.phase p {
  margin: 0;
  color: var(--fg);
  font-size: 1.1875rem;
  line-height: 1.6;
}

.table-wrap {
  overflow-x: auto;
  text-align: left;
}

.table-wrap table {
  width: 100%;
  border-collapse: collapse;
  font-size: 1.125rem;
  color: var(--fg);
}

.table-wrap th,
.table-wrap td {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid #27272a;
}

.table-wrap th {
  color: var(--gold);
  font-weight: 700;
  text-transform: uppercase;
  font-size: 0.9375rem;
  letter-spacing: 0.05em;
}

/* ---------- section rail ---------- */

.rail {
  position: fixed;
  top: 50%;
  right: 1rem;
  z-index: 10;
  display: flex;
  flex-direction: column;
  transform: translateY(-50%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.4s;
}

.rail.is-visible {
  opacity: 1;
  pointer-events: auto;
}

/* Padding is the hit area; the visible dot is the ::before. */
.rail a {
  position: relative;
  display: block;
  padding: 0.5rem;
}

.rail a::before {
  content: "";
  display: block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--fg);
  opacity: 0.3;
  transition: opacity 0.25s, transform 0.25s, background 0.25s;
}

.rail a[aria-current]::before {
  background: var(--gold);
  opacity: 1;
  transform: scale(1.6);
}

.rail a:hover::before,
.rail a:focus-visible::before {
  opacity: 1;
}

.rail a::after {
  content: attr(data-label);
  position: absolute;
  top: 50%;
  right: 100%;
  transform: translateY(-50%);
  color: var(--fg);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s;
}

.rail a:hover::after,
.rail a:focus-visible::after {
  opacity: 0.85;
}

.rail a:focus-visible {
  outline: none;
}

/* ---------- contact tab ---------- */

/* Always visible (the rail is hidden on the hero); ghost outline at rest so it
   is findable without competing with the artwork. */
.contact-tab {
  position: fixed;
  right: 1.5rem;
  bottom: 1.5rem;
  z-index: 10;
  padding: 0.7rem 1.4rem;
  color: var(--gold);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  background: rgba(11, 11, 13, 0.55);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 182, 0, 0.55);
  border-radius: 999px;
  transition: background 0.25s, color 0.25s;
  animation: contact-pulse 2s ease-out 3s 1;
}

.contact-tab:hover,
.contact-tab:focus-visible {
  color: var(--bg);
  background: var(--gold);
  outline: none;
}

@keyframes contact-pulse {
  from { box-shadow: 0 0 0 0 rgba(255, 182, 0, 0.6); }
  to { box-shadow: 0 0 0 18px rgba(255, 182, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
  .contact-tab {
    animation: none;
  }
}

@media (max-width: 767px) {
  .rail {
    display: none;
  }

  .contact-tab {
    right: 1rem;
    bottom: 1rem;
  }

  .mission__layout {
    flex-direction: column;
    gap: 1.5rem;
    text-align: center;
  }

  /* These stages carry up to 2.2x the viewport height on a phone. Pinned, the
     overflow sits behind a deliberately hidden scrollbar that Lenis also
     swallows, so the copy is simply unreachable. Let them scroll normally. */
  .hero:has(.hero__stage--content) {
    height: auto;
  }

  .hero__stage--content {
    position: relative;
    top: auto;
    display: block;
    height: auto;
    min-height: 100vh;
    overflow: visible;
  }

  /* Unpinned, pinRange collapses to 1px and --scroll-progress snaps to 1, which
     would zero out every formula below. Pin them to their end state instead. */
  .hero__stage--content .hero__media {
    transform: none;
  }

  .hero__stage--content .hero__media--overlay {
    opacity: 0;
  }

  .hero__stage--content.hero__stage--band::after {
    opacity: 1;
  }

  .hero__stage--content .hero__content {
    opacity: 1;
    transform: none;
  }

  .hero__stage--content .hero__hint {
    display: none;
  }

  .table-wrap table {
    font-size: 0.9375rem;
  }

  .table-wrap th,
  .table-wrap td {
    padding: 0.5rem 0.625rem;
  }
}

/* ---------- large screens (wider than a small 1366px laptop) ---------- */

/* Bigger type and narrower side margins for the subsections; the first hero (h1 + slogan) is untouched. */
@media (min-width: 1367px) {
  /* Side margins are a share of the viewport, so they shrink with the screen instead of vanishing. */
  .section,
  .hero__stage--content {
    padding-inline: 5vw;
  }

  .section {
    padding-block: 6rem;
  }

  .section__inner,
  .section__inner--wide,
  .hero__content--content {
    width: 100%;
    max-width: 88rem;
  }

  /* Sized to sit level with the mission paragraph block on large screens. */
  .mission__logo {
    width: clamp(280px, 22vw, 412px);
  }

  .hero__content--band {
    padding: 3rem 0;
  }

  /* Scales with the viewport, reaching the 4rem / 1.7rem targets at ~1920px. */
  .section h2,
  .hero__content h2 {
    font-size: clamp(3rem, 4.2vw, 4rem);
  }

  .section p,
  .hero__content p.hero__subtitle,
  .content-column h3,
  .phase h3,
  .point strong,
  .point p,
  .phase p,
  .table-wrap table {
    font-size: clamp(1.4rem, 1.67vw, 1.7rem);
  }

  .table-wrap th {
    font-size: clamp(1.1rem, 1.25vw, 1.5rem);
  }
}

/* ---------- contact page ---------- */

.contact-page {
  background:
    linear-gradient(rgba(11, 11, 13, 0.8), rgba(11, 11, 13, 0.8)),
    var(--bg) url("/assets/images/bg.webp") center / cover fixed;
}

.contact {
  max-width: 34rem;
  min-height: 100vh;
  margin: 0 auto;
  padding: 4rem 1.5rem;
}

.contact__back {
  color: #fff;
  font-size: 0.875rem;
  text-decoration: none;
}

.contact__back:hover {
  color: var(--gold);
}

.contact h1 {
  margin: 2rem 0 0.5rem;
  color: var(--gold);
  font-size: clamp(2rem, 5vw, 3rem);
}

.contact__lead {
  margin: 0 0 2rem;
  color: #fff;
  line-height: 1.6;
}

.contact__form {
  display: grid;
  gap: 1.25rem;
  padding: 2rem;
  background: rgba(11, 11, 13, 0.8);
  backdrop-filter: blur(8px);
  border: 1px solid rgba(255, 182, 0, 0.25);
  border-radius: 12px;
}

.contact__form label {
  display: grid;
  gap: 0.4rem;
  color: var(--muted);
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.contact__form input,
.contact__form select,
.contact__form textarea {
  padding: 0.75rem;
  /* tells the browser to paint autofill + dropdown popups in dark theme */
  color-scheme: dark;
  color: var(--fg);
  font: inherit;
  font-size: 1rem;
  letter-spacing: normal;
  text-transform: none;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.15);
  border-radius: 6px;
}

.contact__form input::placeholder,
.contact__form textarea::placeholder {
  color: var(--muted);
}

/* the native option list is painted by the OS, so it needs opaque colours */
.contact__form select option {
  color: var(--fg);
  background: #1a1a1f;
}

/* Chrome paints autofilled fields itself; only these two properties win */
.contact__form input:-webkit-autofill,
.contact__form input:-webkit-autofill:hover,
.contact__form input:-webkit-autofill:focus,
.contact__form textarea:-webkit-autofill,
.contact__form select:-webkit-autofill {
  -webkit-text-fill-color: var(--fg);
  box-shadow: inset 0 0 0 100px #1a1a1f;
  caret-color: var(--fg);
  transition: background-color 9999s ease-in-out 0s;
}

.contact__form input:focus,
.contact__form select:focus,
.contact__form textarea:focus {
  border-color: var(--gold);
  outline: none;
}

.contact__form button {
  padding: 0.9rem;
  color: var(--bg);
  font: inherit;
  font-weight: 700;
  background: var(--gold);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

.contact__form button:hover {
  filter: brightness(1.1);
}

.contact__form button:disabled {
  opacity: 0.6;
  cursor: wait;
}

.contact__status {
  margin: 0;
  min-height: 1.25rem;
  color: var(--gold);
  font-size: 0.9375rem;
}

.contact__trap {
  position: absolute;
  left: -9999px;
}

