/* =====================================================================
   Equity Cheq
   Tokens are declared once here. Brass is governed by the brass law:
   kickers, section-title hairlines, numerals 01-04, the CTA button,
   one constellation node, one calendar block. Plus ::selection, which
   was added deliberately in the motion pass. Nothing else.

   The advantage icons and the stat numerals are ivory and stay ivory.
   The brand green lives only inside the logo and favicon images.

   MOTION: every animation runs once and never loops. The only repeats
   allowed anywhere are two single pulses (brass constellation node, the
   calendar marker dot) and one 40s texture drift, each of which runs
   exactly once. All of it is disabled under prefers-reduced-motion.
   ===================================================================== */

/* ------------------------------- fonts ------------------------------ */

@font-face {
  font-family: 'Playfair Display';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/fonts/playfair-400.woff2') format('woff2');
}
/* No italic face is declared on purpose. Playfair is a Didone: its thin
   strokes thin further when sloped, and they break up against navy at body
   sizes. Every former italic is now Playfair roman. Do not add an italic
   face back without re-testing legibility on the dark ground. */

@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('/fonts/inter-var.woff2') format('woff2');
}

/* ------------------------------ tokens ------------------------------ */

:root {
  --navy:        #131A26;
  --navy-tone:   #111722;   /* room-tone alternation, one step deeper */
  --navy-deep:   #0E141D;
  --ivory:       #F2EFE9;
  --slate:       #8A93A1;
  --brass:       #B4915C;
  --brass-hi:    #C29E69;
  --hairline:    rgba(242, 239, 233, 0.14);

  --tone: #131A26;          /* current section ground, see room-tone */

  --serif: 'Playfair Display', Georgia, 'Times New Roman', serif;
  --sans:  'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;

  --wrap:    1140px;
  --gutter:  clamp(20px, 5vw, 48px);
  --section: clamp(96px, 12vw, 180px);
  --nav-h:   68px;

  /* single easing for every entrance transform */
  --ease-entrance: cubic-bezier(0.22, 1, 0.36, 1);

  interpolate-size: allow-keywords;
}

/* ------------------------------- reset ------------------------------ */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

body {
  margin: 0;
  background: var(--navy);
  color: var(--ivory);
  font-family: var(--sans);
  font-size: 1.06rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* No overflow-x here on purpose: it would create a scroll container and
     break the sticky nav. Elements that bleed are clipped by their own
     sections instead. */
}

h1, h2 { margin: 0; font-family: var(--serif); font-weight: 400; }
p  { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

::selection {
  background: rgba(180, 145, 92, 0.35);
  color: var(--ivory);
}

:focus-visible {
  outline: 2px solid var(--ivory);
  outline-offset: 3px;
}

.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--navy-deep);
  color: var(--ivory);
  font-size: 0.9rem;
  letter-spacing: 0.04em;
  padding: 12px 20px;
  text-decoration: none;
}
.skip-link:focus { left: 12px; top: 12px; }

/* --------------------------- room tone ------------------------------ */

/* Alternating section grounds. --tone is inherited, so anything that has
   to match its section's background (the process rail pads) reads it
   rather than hard-coding a colour. */
.section { background: var(--tone); }
.tone-deep { --tone: var(--navy-tone); }

/* ---------------------------- shared type --------------------------- */

.kicker {
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--brass);
}

/* Masked headline wrapper. The mask carries the type scale so its padding
   can be expressed in em of the headline, which is what clears descenders
   without shifting anything: padding down, equal negative margin back. */
.h2mask {
  --mask-pad: 0.09em;
  font-size: clamp(2.2rem, 4.5vw, 3.4rem);
  overflow: hidden;
  padding-bottom: var(--mask-pad);
  margin-bottom: calc(var(--mask-pad) * -1);
}
.h2mask--center { font-size: clamp(2.6rem, 5.2vw, 4rem); }

.sec-head h2,
.h2mask h2 {
  font-size: inherit;
  line-height: 1.1;
  color: var(--ivory);
  margin-top: 22px;
  max-width: 20ch;
}

.sec-head .rule {
  display: block;
  width: 44px;
  height: 2px;
  background: var(--brass);
  margin-top: 34px;
  transform: scaleX(0);
  transform-origin: left center;
}

.sec-head--center { text-align: center; }
.sec-head--center h2 { margin-inline: auto; }
.sec-head--center .rule { margin-inline: auto; }

.section { padding-block: var(--section); }
.section--center { text-align: center; }

/* Pull-quote voice: Playfair roman, never italic, never bold. */
/* Pull-quote voice: Playfair roman, never italic, never bold. Two
   paragraphs split at the sentence boundary; em-based measure so it scales
   with the clamped type and each paragraph lands on about two lines. */
.pull {
  margin: 46px auto 0;
  /* One shared measure for both paragraphs, so they sit on identical left
     and right edges and each first line fills it. 35em is tuned: para 1
     runs ~1.45 measures and para 2 ~1.81, so both break to two natural
     lines and neither last line collapses to a single word. */
  max-width: 35em;
  font-family: var(--serif);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(1.3rem, 1.8vw, 1.55rem);
  line-height: 1.6;
  color: rgba(242, 239, 233, 0.94);
}
.pull p {
  font-weight: 400;
  /* pretty, not balance: balance narrows the effective measure per
     paragraph, which left the two paragraphs on visibly different widths.
     pretty keeps the full measure and only guards the last line. */
  text-wrap: pretty;
}
.pull p + p { margin-top: 0.9em; }

.what .sec-head h2,
.advantage .sec-head h2 { max-width: none; }

@media (min-width: 1100px) {
  .advantage .sec-head h2 { white-space: nowrap; }
}

/* Two deliberately stacked lines, same treatment as the pricing headline.
   The floor is lower than the shared H2 scale because "Real estate
   professionals." has to hold one line inside a 335px viewport. */
.what .h2mask { font-size: clamp(1.6rem, 4.5vw, 3.4rem); }
.what__title span { display: block; }

/* ------------------------------ button ------------------------------ */

.btn {
  display: inline-block;
  background: var(--brass);
  color: var(--navy);
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.06em;
  text-decoration: none;
  padding: 16px 34px;
  border-radius: 2px;
  transition: background-color 150ms ease-out,
              transform 150ms ease-out,
              box-shadow 150ms ease-out;
}
.btn:hover {
  background: var(--brass-hi);
  transform: translateY(-1px);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.25);
}

/* -------------------------------- nav ------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color 200ms ease-out, border-color 200ms ease-out;
}
.nav.is-scrolled {
  background: rgba(14, 20, 29, 0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom-color: var(--hairline);
}

.nav__inner {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.nav__logo { display: block; line-height: 0; }
.nav__logo img { height: 30px; width: auto; }

.nav__right { display: flex; align-items: center; gap: 36px; }

.nav__link {
  position: relative;
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--slate);
  text-decoration: none;
  transition: color 150ms ease-out;
}
.nav__link:hover { color: var(--ivory); }

/* hairline draws left to right under the link */
.nav__link::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -5px;
  height: 1px;
  background: var(--ivory);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 200ms ease-out;
}
.nav__link:hover::after,
.nav__link:focus-visible::after { transform: scaleX(1); }

/* ------------------------------- hero ------------------------------- */

.hero {
  position: relative;
  min-height: 86vh;
  display: flex;
  align-items: center;
  padding-block: clamp(56px, 7vw, 96px);
  margin-top: calc(var(--nav-h) * -1);
  padding-top: calc(var(--nav-h) + clamp(48px, 8vw, 96px));
  overflow: hidden;
}

/* Outer layer: edge fades only. The image and the wipe live on the inner
   layer so the two masks compose instead of one replacing the other. */
.hero__texture {
  position: absolute;
  inset: 0;
  mix-blend-mode: screen;
  opacity: 0;
  pointer-events: none;

  -webkit-mask-image:
    linear-gradient(to right, transparent 0%, rgba(0,0,0,0.30) 20%, #000 52%),
    linear-gradient(to bottom, transparent 0%, #000 16%, #000 74%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right, transparent 0%, rgba(0,0,0,0.30) 20%, #000 52%),
    linear-gradient(to bottom, transparent 0%, #000 16%, #000 74%, transparent 100%);
  mask-composite: intersect;
}

/* Inner layer: carries the artwork and the upward construction wipe. The
   mask is 2.5x the element height, opaque across its bottom 40% and
   feathered out by 50%, so travelling the mask position from top to bottom
   walks a soft edge upward. The feather is 10% of a 250% mask, which lands
   at ~25% of the viewport height. */
.hero__texture-in {
  position: absolute;
  inset: 0;
  background-image: url('/assets/web/hero-texture.jpg');
  background-repeat: no-repeat;
  background-position: right center;
  background-size: cover;

  --wipe: linear-gradient(to top, #000 0%, #000 40%, rgba(0, 0, 0, 0) 50%);
  -webkit-mask-image: var(--wipe);
  mask-image: var(--wipe);
  -webkit-mask-size: 100% 250%;
  mask-size: 100% 250%;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: 0% 0%;
  mask-position: 0% 0%;
}

.hero__inner { position: relative; z-index: 1; }

.hero__title {
  font-size: clamp(3rem, 7vw, 6rem);
  line-height: 1.05;
  color: var(--ivory);
  /* Holds the intended three-line break. Measured against the rendered
     face: "Capital-Ready" is 6.54em, "Capital-Ready LPs" is 8.26em, so a
     7.3em cap clears the first and forces the second to wrap. */
  max-width: 7.3em;
}

/* Each H1 line rides in its own mask. Padding clears the descenders, the
   equal negative margin puts the next line back where it was. */
.hline {
  display: block;
  overflow: hidden;
  padding-bottom: 0.1em;
  margin-bottom: -0.1em;
}
.hline__in { display: block; }

.nb { white-space: nowrap; }

.hero__sub {
  margin-top: 32px;
  font-size: 1.35rem;
  font-weight: 400;
  line-height: 1.55;
  color: var(--slate);
  max-width: 52ch;
}

.hero__cta { margin-top: 46px; }

/* ---------------------------- stat band ----------------------------- */

.stats__list {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: auto auto;
  column-gap: clamp(44px, 6vw, 88px);
  /* the caption datum: the numeral row's descent plus --mask-pad, plus
     this gap, lands every caption's first line ~26px under the shared
     baseline. One value, so the datum stays identical across all three. */
  row-gap: 10px;
  text-align: center;
}

/* Subgrid puts all three numerals into one shared row and all three
   captions into another, so the taller centre numeral cannot push its own
   caption down. Baseline alignment then gives the two datums: one shared
   numeral baseline, one shared caption top line. */
.stat {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: span 2;
  align-items: baseline;
}

.stat__mask {
  /* smaller than the headline masks: it doubles as the caption datum, and
     these numerals only have to clear the comma in "3,900+". */
  --mask-pad: 0.05em;
  display: block;
  font-size: clamp(3.2rem, 6vw, 4.5rem);
  /* clip-path rather than overflow: any overflow other than visible forces
     a box to report its bottom margin edge as its baseline, which would
     break the shared baseline. clip-path hides the pre-reveal translate
     without touching baseline calculation. */
  clip-path: inset(-100% 0 0 0);
  padding-bottom: var(--mask-pad);
}

.stat__num {
  display: block;
  font-family: var(--serif);
  font-weight: 400;
  font-size: inherit;
  line-height: 1.05;
  color: var(--ivory);
}

/* the centre stat carries one step more weight */
.stat--lead .stat__mask { font-size: clamp(3.8rem, 7vw, 5.4rem); }

.stat__cap {
  margin: 0 auto;
  max-width: 24ch;
  font-size: 0.95rem;
  line-height: 1.55;
  color: var(--slate);
}

/* --------------------- calendar vignette (pricing) ------------------ */

.vig { width: 100%; height: auto; display: block; }

.vig__grid line {
  stroke: var(--ivory);
  stroke-opacity: 0.3;
  stroke-width: 1;
}
.vig__day {
  fill: var(--slate);
  font-family: var(--sans);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-anchor: middle;
}
.vig__block rect {
  fill: var(--ivory);
  fill-opacity: 0.06;
  stroke: var(--ivory);
  stroke-opacity: 0.6;
  stroke-width: 1;
}
.vig__block text {
  fill: var(--ivory);
  fill-opacity: 0.55;
  font-family: var(--sans);
  font-size: 12.5px;
}
.vig__block .vig__t1 { font-weight: 500; }

.vig__block--brass rect {
  fill: var(--brass);
  fill-opacity: 0.1;
  stroke: var(--brass);
  stroke-opacity: 1;
}
.vig__block--brass text { fill: var(--brass); fill-opacity: 1; }
.vig__block--brass .vig__t2 { font-size: 10px; }
.vig__marker { fill: var(--brass); }

/* Two classes deep so it outranks `.vig__block--brass rect`, which would
   otherwise paint this backing rect brass along with the real one. */
.vig__block .vig__mask {
  fill: var(--tone);
  fill-opacity: 1;
  stroke: none;
}

/* ----------------------------- process ------------------------------ */

.steps {
  position: relative;
  margin-top: clamp(64px, 8vw, 96px);
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: clamp(24px, 3.5vw, 44px);
}

.steps::before {
  content: '';
  position: absolute;
  top: 30px;
  left: 12.5%;
  right: 12.5%;
  height: 1px;
  background: rgba(242, 239, 233, 0.35);
}

.step { text-align: center; }

.step__icon {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--tone);
  padding-inline: 18px;
}
.step__icon img { width: 60px; height: 60px; object-fit: contain; }

.step__num {
  display: block;
  margin-top: 22px;
  font-family: var(--serif);
  font-size: 1.8rem;
  line-height: 1;
  color: var(--brass);
}

.step__body {
  margin-top: 18px;
  font-size: 1rem;
  line-height: 1.6;
  color: rgba(242, 239, 233, 0.8);
  max-width: 32ch;
  margin-inline: auto;
}
.step__lead {
  display: block;
  margin-bottom: 6px;
  font-weight: 600;
  color: var(--ivory);
}

/* ---------------------------- advantage ----------------------------- */

.adv {
  margin-top: clamp(56px, 7vw, 88px);
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  column-gap: 48px;
  row-gap: clamp(48px, 5vw, 64px);
}

.adv__cell {
  font-size: 1.06rem;
  line-height: 1.65;
  color: rgba(242, 239, 233, 0.8);
  max-width: 44ch;
}

/* Fixed box with a common bottom line. The icons are area-normalised then
   nudged a few percent each so they read as equal weight rather than equal
   bounding boxes; the box holds the tallest of them. */
.adv__icon {
  display: flex;
  align-items: flex-end;
  height: 66px;
  margin-bottom: 22px;
}
.adv__icon img {
  opacity: 0.85;
  transition: opacity 200ms ease-out, transform 200ms ease-out;
}
.adv__cell:hover .adv__icon img {
  opacity: 1;
  transform: translateY(-2px);
}

.adv__lead {
  display: block;
  margin-bottom: 8px;
  font-weight: 600;
  color: var(--ivory);
}

/* ----------------------------- pricing ------------------------------ */

.pricing__inner {
  display: grid;
  grid-template-columns: minmax(0, 56fr) minmax(0, 42fr);
  column-gap: 4%;
  align-items: center;
}

.pricing__title span { display: block; }

.pricing__body {
  margin-top: 40px;
  max-width: 54ch;
  color: rgba(242, 239, 233, 0.88);
}

.pricing__vignette { width: 100%; min-width: 0; }

/* --------------------------- proof strip ---------------------------- */

.proof__band {
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  padding-block: clamp(76px, 9vw, 120px);
}

.proof__line {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  font-family: var(--serif);
  font-style: normal;
  font-weight: 400;
  /* Capped below the pull-quote's 1.9rem on purpose: the first line is 78
     characters, which needs ~1168px at 1.9rem against a 1044px content
     width. At 1.65rem it holds one line, which is the point of the strip. */
  font-size: clamp(1.2rem, 2.1vw, 1.65rem);
  line-height: 1.55;
  color: rgba(242, 239, 233, 0.94);
}
.proof__line span + span { margin-top: 0.5em; }

/* ------------------------------- faq -------------------------------- */

.faq__list {
  margin-top: clamp(48px, 6vw, 72px);
  max-width: 860px;
  border-top: 1px solid var(--hairline);
}

.faq__item { border-bottom: 1px solid var(--hairline); }

.faq__q {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 32px;
  padding-block: 26px;
  cursor: pointer;
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.5;
  color: rgba(242, 239, 233, 0.88);
  list-style: none;
  transition: color 200ms ease-out;
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q::marker { content: ''; }
.faq__q:hover { color: var(--ivory); }

/* Slate chevron, never brass. */
.faq__mark {
  flex: none;
  width: 9px;
  height: 9px;
  border-right: 1.5px solid var(--slate);
  border-bottom: 1.5px solid var(--slate);
  transform: rotate(45deg) translateY(-2px);
  transition: transform 250ms ease-out;
}
.faq__item[open] .faq__mark { transform: rotate(-135deg) translateY(-2px); }

.faq__a {
  padding-bottom: 30px;
  padding-right: 44px;
  max-width: 68ch;
  color: rgba(242, 239, 233, 0.8);
}

.faq__item::details-content {
  block-size: 0;
  overflow: hidden;
  transition: block-size 250ms ease-out, content-visibility 250ms allow-discrete;
}
.faq__item[open]::details-content { block-size: auto; }

/* ------------------------------ close ------------------------------- */

.close {
  position: relative;
  min-height: 70vh;
  display: flex;
  align-items: center;
  text-align: center;
  padding-block: var(--section);
  overflow: hidden;
}

.close__constellation {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(900px, 118%);
  opacity: 0.10;
  pointer-events: none;
}
.close__constellation svg { width: 100%; height: auto; display: block; }

.c-line { stroke: var(--ivory); stroke-width: 1; stroke-opacity: 0.3; }
.c-node { fill: var(--ivory); }
.c-node--brass { fill: var(--brass); }

.close__inner { position: relative; z-index: 1; }

.close__title {
  line-height: 1.1;
  color: var(--ivory);
  max-width: 18ch;
  margin-inline: auto;
}

.close__cta { margin-top: 48px; }

.close__note {
  margin-top: 30px;
  font-size: 1.05rem;
  color: rgba(242, 239, 233, 0.7);
}

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

/* Horizontal institutional footer: identity left, reach right, a hairline,
   then the quiet legal row. Collapses to a centred stack on small screens. */
.footer {
  background: var(--navy-deep);
  border-top: 1px solid var(--hairline);
  padding-top: 72px;
  padding-bottom: 48px;
}

.footer__top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 32px;
}

.footer__logo { height: 36px; width: auto; }

.footer__contact { text-align: right; }

.footer__reach {
  font-size: 0.95rem;
  line-height: 1.7;
  color: rgba(242, 239, 233, 0.85);
}

.footer__place {
  margin-top: 4px;
  font-size: 0.85rem;
  line-height: 1.7;
  color: var(--slate);
}

.footer__rule {
  height: 1px;
  background: var(--hairline);
  margin-block: 34px;
}

.footer__bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  font-size: 0.85rem;
  line-height: 1.7;
  color: rgba(138, 147, 161, 0.6);
}

.footer__reach a,
.footer__legal a {
  color: inherit;
  text-decoration: none;
  transition: color 150ms ease-out;
}
.footer__reach a:hover,
.footer__legal a:hover { color: var(--ivory); }

.footer__sep { padding-inline: 10px; }

/* ============================ legal pages =========================== */

.legal { padding-block: clamp(72px, 9vw, 132px); }

.legal__title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.2rem, 4.5vw, 3.4rem);
  line-height: 1.1;
  color: var(--ivory);
}

.legal__meta { margin-top: 20px; font-size: 0.9rem; color: var(--slate); }

.legal__body { margin-top: clamp(40px, 5vw, 56px); max-width: 68ch; }

.legal__body h2 {
  font-family: var(--sans);
  font-size: 1.05rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ivory);
  margin-top: 44px;
  max-width: none;
}
.legal__body h2:first-child { margin-top: 0; }

.legal__body p { margin-top: 14px; color: rgba(242, 239, 233, 0.8); }

.legal__body ul {
  margin-top: 14px;
  padding-left: 20px;
  list-style: disc;
  color: rgba(242, 239, 233, 0.8);
}
.legal__body li { margin-top: 6px; }
.legal__body a { color: var(--ivory); text-decoration: underline; }

.legal__back { margin-top: clamp(48px, 6vw, 72px); font-size: 0.9rem; color: var(--slate); }
.legal__back a { color: var(--slate); text-decoration: none; }
.legal__back a:hover { color: var(--ivory); }

/* ------------------------------- 404 -------------------------------- */

.nf {
  min-height: 68vh;
  display: flex;
  align-items: center;
  text-align: center;
  padding-block: clamp(72px, 10vw, 140px);
}
.nf__title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.4rem, 5vw, 3.8rem);
  line-height: 1.1;
  color: var(--ivory);
  max-width: 16ch;
  margin-inline: auto;
}
.nf__line {
  margin-top: 26px;
  font-size: 1.1rem;
  color: var(--slate);
}
.nf__cta { margin-top: 44px; }
.nf__home { margin-top: 26px; font-size: 0.9rem; color: var(--slate); }
.nf__home a { color: var(--slate); text-decoration: none; }
.nf__home a:hover { color: var(--ivory); }

/* =====================================================================
   MOTION
   Hero entrance is pure CSS so it plays with or without JS. Everything
   scroll-triggered is guarded on .js, so a no-JS page renders complete.
   Nothing here uses pointer-events or overlays, so scrolling and clicking
   are available from the first frame, mid-sequence included.
   ===================================================================== */

/* ------------------------- 1. hero entrance ------------------------- */

/* No will-change here on purpose. It was tried and measured under headless
   software rasterisation and did not reduce the 3-4 long frames during the
   entrance, so it is not worth the promoted-layer memory on speculation.
   If a trace on real hardware shows the same cluster, the fix with a known
   mechanism is baking the screen blend into the texture (costs ~177KB,
   because the baked image must be lossless). */

/* opacity ramps 0 -> 0.15 across the first 600ms of the wipe */
.hero__texture {
  animation-name: tex-in;
  animation-duration: 600ms;
  animation-timing-function: var(--ease-entrance);
  animation-fill-mode: forwards;
}
@keyframes tex-in { from { opacity: 0; } to { opacity: 0.15; } }

/* the wipe itself: ~2.2s, once, never re-triggered */
.hero__texture-in {
  animation: hero-wipe 2200ms var(--ease-entrance) forwards;
}
@keyframes hero-wipe {
  from { -webkit-mask-position: 0% 0%;   mask-position: 0% 0%; }
  to   { -webkit-mask-position: 0% 100%; mask-position: 0% 100%; }
}

/* 8. texture drift, starting only once the wipe has finished.
   Remove the `drift` class in the HTML to kill it. */
.hero__texture.drift {
  animation-name: tex-in, hero-drift;
  animation-duration: 600ms, 40s;
  animation-delay: 0ms, 2200ms;
  animation-timing-function: var(--ease-entrance), ease-out;
  animation-fill-mode: forwards, forwards;
}
@keyframes hero-drift {
  from { transform: scale(1); }
  to   { transform: scale(1.03); }
}

.hline__in {
  transform: translateY(115%);
  animation: line-rise 600ms var(--ease-entrance) forwards;
  animation-delay: calc(350ms + var(--i) * 90ms);
}
@keyframes line-rise { to { transform: none; } }

.hero__sub {
  opacity: 0;
  animation: rise-in 500ms var(--ease-entrance) 620ms forwards;
}
.hero__cta {
  opacity: 0;
  animation: rise-in 500ms var(--ease-entrance) 700ms forwards;
}
@keyframes rise-in {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* Scoped to pages that actually run the hero sequence, so the legal and
   404 pages show their nav immediately. Browsers without :has() drop the
   rule entirely, which also leaves the nav visible: a safe fallback. */
body:has(.hero) .nav {
  opacity: 0;
  animation: nav-in 500ms var(--ease-entrance) 780ms forwards;
}
@keyframes nav-in { to { opacity: 1; } }

/* -------------------- 2. section headline reveals ------------------- */

.js .reveal .kicker {
  opacity: 0;
  transition: opacity 500ms var(--ease-entrance);
}
.js .reveal.is-visible .kicker { opacity: 1; }

.js .reveal .h2mask h2 {
  transform: translateY(110%);
  transition: transform 650ms var(--ease-entrance) 150ms;
}
.js .reveal.is-visible .h2mask h2 { transform: none; }

.js .rule { transition: transform 600ms var(--ease-entrance) 850ms; }
.reveal.is-visible .rule { transform: scaleX(1); }
.no-js .rule { transform: scaleX(1); }

/* generic content riser */
.js .reveal .rise {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 550ms var(--ease-entrance) 450ms,
              transform 550ms var(--ease-entrance) 450ms;
}
.js .reveal .rise--late {
  transition-delay: 620ms;
}
.js .reveal.is-visible .rise { opacity: 1; transform: none; }

/* ---------------------- B. stat band entrance ----------------------- */

.js .stats .stat__num {
  transform: translateY(110%);
  transition: transform 650ms var(--ease-entrance);
  transition-delay: calc(var(--i) * 120ms);
}
.js .stats.is-visible .stat__num { transform: none; }

.js .stats .stat__cap {
  opacity: 0;
  transition: opacity 500ms var(--ease-entrance);
  transition-delay: calc(380ms + var(--i) * 120ms);
}
.js .stats.is-visible .stat__cap { opacity: 1; }

/* ------------------ A. directional scroll choreography -------------- */

/* Process, advantage and FAQ all use the same uniform fade + rise. Only
   their staggers differ: 90ms, 80ms, 60ms respectively. */
.js .reveal .step {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 550ms var(--ease-entrance),
              transform 550ms var(--ease-entrance);
  transition-delay: calc(400ms + var(--i) * 90ms);
}
.js .reveal.is-visible .step { opacity: 1; transform: none; }

.js .reveal .adv__cell {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 550ms var(--ease-entrance),
              transform 550ms var(--ease-entrance);
  transition-delay: calc(400ms + var(--i) * 80ms);
}
.js .reveal.is-visible .adv__cell { opacity: 1; transform: none; }

.js .reveal .faq__item {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 550ms var(--ease-entrance),
              transform 550ms var(--ease-entrance);
  transition-delay: calc(400ms + var(--i) * 60ms);
}
.js .reveal.is-visible .faq__item { opacity: 1; transform: none; }

/* The pricing two-column section is the only directional entrance left:
   copy from the left, vignette from the right. */
.js .pricing .pricing__copy {
  opacity: 0;
  transform: translateX(-14px);
  transition: opacity 600ms var(--ease-entrance) 200ms,
              transform 600ms var(--ease-entrance) 200ms;
}
.js .pricing .pricing__vignette {
  opacity: 0;
  transform: translateX(14px);
  transition: opacity 600ms var(--ease-entrance) 300ms,
              transform 600ms var(--ease-entrance) 300ms;
}
.js .pricing.is-visible .pricing__copy,
.js .pricing.is-visible .pricing__vignette { opacity: 1; transform: none; }

/* proof lines */
.js .proof .proof__line span {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 550ms var(--ease-entrance),
              transform 550ms var(--ease-entrance);
  transition-delay: calc(var(--i) * 120ms);
}
.js .proof.is-visible .proof__line span { opacity: 1; transform: none; }

/* ------------------- 4. calendar choreography ----------------------- */

.js .pricing .vig__block { opacity: 0; }
.js .pricing.is-visible .vig__block {
  animation: vig-land 420ms ease-out forwards;
  animation-delay: calc(500ms + var(--i) * 70ms);
}
@keyframes vig-land {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

/* the marker pulses exactly once, after the brass block has landed */
.js .pricing.is-visible .vig__marker {
  transform-box: fill-box;
  transform-origin: center;
  animation: vig-pulse 600ms ease-out forwards;
  animation-delay: 1350ms;
}
@keyframes vig-pulse {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.6); }
  100% { transform: scale(1); }
}

/* --------------- 3. constellation self-draw ------------------------- */

.js .close .c-node { opacity: 0; }
.js .close.is-visible .c-node {
  animation: c-node-in 400ms ease-out forwards;
  animation-delay: calc(var(--i) * 35ms);
}
@keyframes c-node-in { to { opacity: 1; } }

/* pathLength normalises every segment to 1, so one dash pair draws them
   all at the same rate regardless of their real length. */
.js .close .c-line {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.js .close.is-visible .c-line {
  animation: c-draw 400ms ease-out forwards;
  animation-delay: calc(300ms + var(--i) * 22ms);
}
@keyframes c-draw { to { stroke-dashoffset: 0; } }

/* brass node arrives last, with one soft pulse and then stillness */
.js .close.is-visible .c-node--brass {
  animation: c-brass-in 900ms ease-out forwards;
  animation-delay: 900ms;
}
@keyframes c-brass-in {
  0%   { opacity: 0; }
  30%  { opacity: 1; }
  60%  { opacity: 0.4; }
  100% { opacity: 1; }
}

/* ============================ responsive ============================ */

@media (max-width: 980px) {
  .pricing__inner {
    grid-template-columns: minmax(0, 1fr);
    row-gap: clamp(48px, 7vw, 72px);
  }
  .pricing__vignette { max-width: 460px; }
}

@media (max-width: 860px) {
  .nav__link { display: none; }

  /* stacked: drop the subgrid, give every stat the same internal gap */
  .stats__list {
    grid-template-columns: 1fr;
    grid-template-rows: none;
    row-gap: clamp(40px, 8vw, 56px);
  }
  .stat { display: block; }
  .stat__mask { margin-bottom: calc(var(--mask-pad) * -1); }
  .stat__cap { margin-top: 16px; }

  .steps { grid-template-columns: 1fr; row-gap: 48px; }
  .steps::before {
    top: 0;
    bottom: 0;
    left: 30px;
    right: auto;
    width: 1px;
    height: auto;
  }
  .step {
    display: grid;
    grid-template-columns: 60px 1fr;
    grid-template-areas:
      'icon num'
      'icon body';
    column-gap: 24px;
    text-align: left;
  }
  .step__icon { grid-area: icon; padding-inline: 0; padding-block: 8px; }
  .step__num { grid-area: num; margin-top: 4px; }
  .step__body { grid-area: body; margin-top: 12px; margin-inline: 0; max-width: none; }

  .adv { grid-template-columns: 1fr; row-gap: 44px; }
  .adv__cell { max-width: none; }

  .faq__a { padding-right: 0; }

  /* single column: the pricing directional entrance falls back to a rise */
  .js .pricing .pricing__copy,
  .js .pricing .pricing__vignette {
    transform: translateY(14px);
  }
}

@media (max-width: 720px) {
  /* centred stack: logo, contact, Miami, then legal */
  .footer__top {
    flex-direction: column;
    align-items: center;
    gap: 26px;
    text-align: center;
  }
  .footer__contact { text-align: center; }
  .footer__place { margin-top: 8px; }

  .footer__bottom {
    flex-direction: column-reverse;
    align-items: center;
    gap: 12px;
    text-align: center;
  }

  .footer__reach,
  .footer__place,
  .footer__copy,
  .footer__legal { line-height: 2; }
}

@media (max-width: 360px) {
  .hero__title { font-size: 2.6rem; }
}

@media (max-width: 480px) {
  .vig__day { font-size: 13px; }
  .vig__block text { font-size: 13px; }
  .vig__block--brass .vig__t2 { font-size: 10.5px; }
  .hero__sub { font-size: 1.2rem; }
}

/* =====================================================================
   REDUCED MOTION
   Everything renders in its final state, instantly. No animation, no
   transition, no transform, no dash offset, anywhere.
   ===================================================================== */

@media (prefers-reduced-motion: reduce) {

  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }

  .hero__texture,
  .hero__texture.drift {
    opacity: 0.15;
    transform: none;
  }
  /* wipe renders fully open, instantly */
  .hero__texture-in {
    -webkit-mask-position: 0% 100%;
    mask-position: 0% 100%;
  }

  .hline__in,
  .js .reveal .h2mask h2,
  .js .stats .stat__num { transform: none; }

  .hero__sub,
  .hero__cta,
  .nav,
  .js .reveal .kicker,
  .js .stats .stat__cap,
  .js .pricing .vig__block,
  .js .close .c-node,
  .js .close .c-line { opacity: 1; }

  .js .close .c-line { stroke-dashoffset: 0; }

  .js .reveal .rise,
  .js .reveal .step,
  .js .reveal .adv__cell,
  .js .reveal .faq__item,
  .js .proof .proof__line span,
  .js .pricing .pricing__copy,
  .js .pricing .pricing__vignette {
    opacity: 1;
    transform: none;
  }

  .rule,
  .js .rule { transform: scaleX(1); }

  .vig__marker { transform: none; }
  .adv__icon img { opacity: 0.85; transform: none; }
}
