@font-face { font-family: "General Sans"; src: url("/founding-membership/fonts/GeneralSans-400.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "General Sans"; src: url("/founding-membership/fonts/GeneralSans-500.woff2") format("woff2"); font-weight: 500; font-display: swap; }
@font-face { font-family: "General Sans"; src: url("/founding-membership/fonts/GeneralSans-600.woff2") format("woff2"); font-weight: 600; font-display: swap; }
@font-face { font-family: "Raleway"; src: url("/founding-membership/fonts/Raleway-var.woff2") format("woff2"); font-weight: 300 700; font-display: swap; }

/* Scoped to .fm-page, not :root — scrollcraft.css's own token defaults are
   now scoped there too (see its own note), and a rule that only inherits
   in from :root loses to one declared directly on the element it's for.
   Fixed hex, not the site's "cinematic family" tokens: every act here is
   either a full-bleed photo or its own hardcoded dark fill (never the flat
   canvas fill those tokens are for), so wiring --sc-canvas/--sc-ink to the
   site's light/dark toggle was tried and reverted — it left the close
   section's darkening scrim washed out and its FAQ text low-contrast in
   light mode, precisely the section flagged as "not very legible." /ig
   (public/ig/page.css), the only other scroll-craft photo build in this
   family, makes the same call: fixed hex, permanently cinematic-dark,
   regardless of site theme. Only the header-clash bug was ever a real
   light-mode defect, and that's a scoping problem (fixed above and in
   scrollcraft.css), not a palette one. */
.fm-page {
  --sc-canvas:     #120D08;
  --sc-surface:    #1F160D;
  --sc-ink:        #F5EBDD;
  --sc-ink-soft:   #A99A85;
  --sc-accent:     #E8A33D;
  --sc-accent-ink: #17110A;
  --sc-font-display: "General Sans", system-ui, sans-serif;
  --sc-font-text:    "Raleway", system-ui, sans-serif;
}

/* ---- page-only classes. Never touch .sc-stage / .sc-copy / [data-sc-*]. ---- */

/* Engine gap, not a page bug: the engine's own @media (max-width: 860px)
   resets .sc-copy's inset-inline to gutter-anchored full-width but never
   cancels .sc-copy--center's horizontal translate(-50%), so a centered
   copy block renders shifted a full half-width off-screen on every phone.
   Re-declared here (same 860px cutover as the engine) rather than in
   scrollcraft.css, which this build never edits directly. Vertical
   translate is untouched — only the horizontal half was ever wrong. */
@media (max-width: 860px) {
  .sc-copy--center { translate: 0 -50%; }
}

/* scrollcraft.css's own mobile block re-points .sc-scrim--trail at a
   full-width band, with a comment saying "both corner anchors become"
   this shape below 860px — but only wrote the override for --trail, not
   --lead. Act 2 pairs .sc-copy--lead with .sc-scrim--lead per the
   engine's documented pairing, so it inherits the exact failure the
   --trail comment describes: the corner scrim still darkens the corner
   the now-full-width copy just left, guaranteeing low contrast over a
   bright frame (measured 2.07:1 on mobile, verify.md's shoot.mjs).
   Mirrors the engine's own --trail fix verbatim, mirrored lead-to-trail. */
@media (max-width: 860px) {
  .sc-scrim--lead {
    background: linear-gradient(to top,
      color-mix(in oklab, var(--sc-canvas) 94%, transparent) 0%,
      color-mix(in oklab, var(--sc-canvas) 74%, transparent) 22%,
      color-mix(in oklab, var(--sc-canvas) 30%, transparent) 42%,
      transparent 58%);
  }
}

.fm-media { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

/* Blend between hard-cut scenes. This grammar's own spec calls for hard
   cuts ("no drift interpolation"), but the family's standing instruction
   (_family-lessons-learned.md #8) overrides a grammar's literal text on
   this specific point: every page in this family softens its cuts, even
   ones whose grammar argues for hard ones. Technique is the same
   mask-dissolve tenseats-homepage-refit's own .frame--follow uses: the
   incoming section overlaps the outgoing one by --seam (negative
   margin-top), and its own photo layer is masked on its top edge so it
   fades in over that overlap instead of appearing in one swap. Only
   applied where two full-bleed photo pins actually swap (acts 2, 3 and 6)
   — acts 4/5a/5b scroll away rather than hard-swap, so there's no discrete
   cut there to soften. The section's own solid background is dropped (not
   just backgrounded-over) for exactly these three sections: an opaque
   fill sitting behind the masked layer defeats the fade, because the
   "transparent" band in the mask would reveal that fill instead of the
   previous scene actually showing through. */
.fm-blend { margin-top: calc(-1 * var(--seam, 22svh)); }
.fm-blend [data-sc-stage] { background: transparent; }
.fm-blend .fm-media,
.fm-blend .fm-peak__ground {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, rgba(0,0,0,.4) calc(var(--seam, 22svh) * .45), rgba(0,0,0,.82) calc(var(--seam, 22svh) * .8), #000 var(--seam, 22svh));
          mask-image: linear-gradient(to bottom, transparent 0, rgba(0,0,0,.4) calc(var(--seam, 22svh) * .45), rgba(0,0,0,.82) calc(var(--seam, 22svh) * .8), #000 var(--seam, 22svh));
}

/* Missing base style, not an engine gap: every sibling build in this
   family defines its own .cta (the class is page-authored convention per
   the skill's own template.html, never part of scrollcraft.css) and this
   page never did, so the request-invite buttons were rendering with zero
   button styling at all — just plain inline text. */
.cta {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 52px; padding: 0 1.8rem; border-radius: var(--sc-radius-lg, 14px);
  font-family: var(--sc-font-display); font-weight: 600; font-size: 1rem; letter-spacing: -0.005em;
  color: var(--sc-accent-ink); background: var(--sc-accent); text-decoration: none;
  box-shadow: 0 8px 20px rgba(232, 163, 61, .25);
  transition: background-color 140ms var(--sc-ease-out), transform 110ms var(--sc-ease-out);
}
.cta:hover { background: color-mix(in srgb, var(--sc-accent) 88%, white 12%); }
.cta:active { transform: scale(.98); }
.cta:focus-visible { outline: 2px solid var(--sc-ink); outline-offset: 3px; }

/* Act 3 — the peak: signature move, "the circle completes" */
.fm-peak { position: relative; width: 100%; height: 100%; }
/* Was opacity:0.55 directly on the img. That made the ground translucent
   everywhere, not just where the mask fades it in at the seam — combined
   with .fm-blend dropping this section's own solid backing (needed so the
   seam's transparent band shows the actual previous scene, not a flat
   fill), a translucent ground would show act 2 bleeding through for the
   WHOLE act, not just the brief blend-in. Ground now stays fully opaque
   (only the mask controls transparency, and only at the top edge); the
   dimmed-ambient look moves to its own scrim layered on top instead. */
.fm-peak__ground { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fm-peak__scrim { position: absolute; inset: 0; background: color-mix(in oklab, var(--sc-canvas) 45%, transparent); }
.fm-peak__frame { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; gap: clamp(0.5rem, 2vw, 1.25rem); }
.fm-peak__figure { position: relative; width: clamp(4.5rem, 13vw, 9rem); aspect-ratio: 3/4; border-radius: var(--sc-radius-md, 10px);
  overflow: hidden; box-shadow: 0 18px 40px -12px rgba(0,0,0,0.55); border: 1px solid color-mix(in srgb, var(--sc-ink) 14%, transparent);
  will-change: transform, opacity; }
.fm-peak__figure img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fm-peak__figure {
  --fx: 0px; --fy: 0px; --fr: 0deg;
  opacity: calc(0.15 + 0.85 * var(--sc-p));
  transform: translate(calc(var(--fx) * (1 - var(--sc-p))), calc(var(--fy) * (1 - var(--sc-p))))
             rotate(calc(var(--fr) * (1 - var(--sc-p))))
             scale(calc(0.82 + 0.18 * var(--sc-p)));
}
.fm-peak__figure:nth-child(1) { --fx: -46vw; --fy: -18vh; --fr: -9deg; }
.fm-peak__figure:nth-child(2) { --fx: -24vw; --fy: 16vh;  --fr: 6deg; }
.fm-peak__figure:nth-child(3) { --fx: 0vw;   --fy: -22vh; --fr: -3deg; }
.fm-peak__figure:nth-child(4) { --fx: 24vw;  --fy: 18vh;  --fr: 7deg; }
.fm-peak__figure:nth-child(5) { --fx: 46vw;  --fy: -14vh; --fr: -6deg; }
/* left:0/right:0 alone fought .sc-copy--center's own left:50%/translate at
   every width, not just mobile (measured -368px off-screen at 1440). This
   element also carries data-sc-cue, and the engine's cue reveal rewrites
   .style.transform on every frame (scrollcraft.js ~L929) — so `transform`
   is a dead channel here too, not just `translate`. Neither can be used
   for centering. Fall back to the one channel the engine never touches:
   fit-content + left/right:0 + auto margins. Also clear .sc-copy--center's
   inherited top:50%, which combined with bottom below to stretch this to
   a 374px-tall box instead of a bottom-anchored line (measured live). */
.fm-peak__caption { position: absolute; left: 0; right: 0; top: auto; bottom: var(--sc-6);
  width: fit-content; margin-inline: auto; translate: none; text-align: center;
  max-width: min(90vw, 34rem); }
@media (prefers-reduced-motion: reduce) {
  .fm-peak__figure { opacity: 1; transform: none; }
}

/* Act 4 — what founding means */
.fm-means__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sc-6); margin-top: var(--sc-7); }
.fm-means__item h3 { font-family: var(--sc-font-display); font-size: 1.05rem; font-weight: 600; margin: 0 0 var(--sc-2); }
.fm-means__item p { color: var(--sc-ink-soft); margin: 0; }
.fm-early-link { display: inline-flex; align-items: center; gap: var(--sc-2); margin-top: var(--sc-6);
  color: var(--sc-accent); font-family: var(--sc-font-text); font-weight: 600; text-decoration: none; }
.fm-early-link:hover { text-decoration: underline; }
@media (max-width: 860px) { .fm-means__grid { grid-template-columns: 1fr; gap: var(--sc-5); } }

/* Act 5 — cities (pan) */
.fm-rail { display: flex; align-items: stretch; gap: var(--sc-5); padding: 0 var(--sc-gutter); }
.fm-rail__lead { flex: 0 0 clamp(16rem, 30vw, 22rem); display: flex; flex-direction: column; justify-content: center; }
.fm-city { flex: 0 0 clamp(18rem, 34vw, 26rem); position: relative; border-radius: var(--sc-radius-lg, 14px); overflow: hidden;
  aspect-ratio: 3/4; }
.fm-city img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.fm-city__scrim { position: absolute; inset: 0; background: linear-gradient(to top, rgba(10,7,4,0.82), rgba(10,7,4,0) 55%); }
.fm-city__label { position: absolute; left: var(--sc-4); right: var(--sc-4); bottom: var(--sc-4); }
.fm-city__label h3 { font-family: var(--sc-font-display); font-size: 1.2rem; margin: 0 0 0.2em; }
.fm-city__label p { font-size: 0.88rem; color: var(--sc-ink-soft); margin: 0; }

/* the request form, flow section right after the cities */
.fm-form { max-width: 34rem; }
.fm-form__row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sc-4); }
.fm-form label { display: block; font-size: 0.82rem; color: var(--sc-ink-soft); margin-bottom: var(--sc-1); }
.fm-form input, .fm-form select, .fm-form textarea {
  width: 100%; background: color-mix(in srgb, var(--sc-surface) 88%, black 4%); border: 1px solid color-mix(in srgb, var(--sc-ink) 16%, transparent);
  border-radius: var(--sc-radius-sm, 8px); color: var(--sc-ink); font-family: var(--sc-font-text); font-size: 0.95rem;
  padding: 0.7em 0.85em; margin-bottom: var(--sc-4); }
.fm-form input:focus, .fm-form select:focus, .fm-form textarea:focus { outline: 2px solid var(--sc-accent); outline-offset: 2px; }
.fm-form button { width: 100%; }
.fm-form__note { font-size: 0.82rem; color: var(--sc-ink-soft); margin-top: var(--sc-3); }
.fm-form__status { font-size: 0.9rem; margin-top: var(--sc-3); min-height: 1.2em; }
@media (max-width: 640px) { .fm-form__row { grid-template-columns: 1fr; } }

/* Act 6 — close */
.fm-close { position: relative; width: 100%; height: 100%; display: flex; flex-direction: column; }
/* .sc-scrim--band darkens from the bottom up, fading to transparent by
   58% up the frame — built for bottom-anchored copy (.sc-copy--lead /
   --trail). .fm-close__inner instead centers its content vertically
   (flex, justify-content:center) and the FAQ list runs on well past
   center, so the band's own fade left the heading and FAQ answers over
   the photo's bright window/wood areas with poor contrast (flagged live:
   "the bottom of the page is not very legible"). This covers the whole
   frame at a contrast-adequate level instead of assuming the copy hugs
   one edge. Also carries the same opacity-vs-scrim fix as
   .fm-peak__scrim above: the source image lost its own opacity:0.5 (see
   the img's own style) so it stays fully opaque for .fm-blend's mask to
   work against, and this scrim does the dimming instead. */
.fm-close__scrim { position: absolute; inset: 0; background: radial-gradient(120% 100% at 50% 62%,
  color-mix(in oklab, var(--sc-canvas) 58%, transparent) 0%,
  color-mix(in oklab, var(--sc-canvas) 80%, transparent) 65%,
  color-mix(in oklab, var(--sc-canvas) 90%, transparent) 100%); }
.fm-close__inner { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: var(--sc-4); }
/* Normal flex-flow child, not .sc-copy's absolute-over-stage positioning —
   .sc-copy--center's left:50%/translate assumes position:absolute and
   fights a position:relative flex item instead of centering it. */
.fm-close__caption { max-width: 34rem; }
.fm-close__faq { max-width: 40rem; margin: var(--sc-6) auto 0; text-align: left; display: grid; gap: var(--sc-4); }
.fm-close__faq h3 { font-family: var(--sc-font-display); font-size: 1rem; font-weight: 600; margin: 0 0 0.3em; }
.fm-close__faq p { color: var(--sc-ink-soft); margin: 0; font-size: 0.92rem; }
