/* ============================================================
   Faber House — homepage
   Implemented from "Faber House Homepage.dc.html" (Claude Design)
   ============================================================ */

:root {
  --ink: #141414;
  --paper: #F5F5F5;
  --white: #ffffff;
  --accent: #FF825C;
  --accent-hover: #ffa183;

  --muted-dark: #9a9a9a;   /* labels on dark */
  --muted-body: #8f8f8f;   /* body copy on dark */
  --muted-hero: #b7b7ba;   /* hero subcopy */
  --muted-light: #6b6b6b;  /* labels on light */
  --muted-mid: #555555;    /* body copy on white */
  --rule-light: #d8d8d8;
  --rule-white: #e4e4e4;

  --gutter: 40px;
  --ease: cubic-bezier(.2, .7, .2, 1);

  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-display: 'Cal Sans', 'Inter', -apple-system, sans-serif;
}

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

html, body {
  margin: 0;
  padding: 0;
  background: var(--ink);
}

body {
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  color: var(--paper);
}

h1, h2, h3 { font-family: var(--font-display); }

a { color: inherit; text-decoration: none; }
a:hover { color: var(--accent); }
img { max-width: 100%; }

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

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

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.page {
  background: var(--ink);
  color: var(--paper);
  overflow: clip; /* clip, not hidden — keeps the sticky CTA anchored to the viewport */
}

/* Sections stack above the sticky CTA so it reveals from behind them. */
.hero, .manifesto, .why, .values-section {
  position: relative;
  z-index: 1;
}

/* ---------- animations ---------- */

@keyframes riseUp {
  from { opacity: 0; transform: translateY(40px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes bounceY {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(5px); }
}

/* Scroll-reveal: JS adds .is-revealed once the element enters the viewport.
   The primed state only applies when JS is running, so the page stays
   fully readable without it. */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(34px);
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}
.js [data-reveal].is-revealed {
  opacity: 1;
  transform: translateY(0);
}

/* ---------- buttons ---------- */

.btn {
  display: inline-block;
  border-radius: 60px;
  font-weight: 600;
  white-space: nowrap;
}

.btn--solid {
  background: var(--accent);
  color: var(--ink);
  padding: 10px 20px;
  font-size: 14px;
  transition: background .2s, transform .2s;
}
.btn--solid:hover {
  background: var(--accent-hover);
  color: var(--ink);
  transform: translateY(-2px);
}

.btn--submit {
  align-self: center;
  margin-top: clamp(14px, 2.2vh, 22px);
  background: var(--accent);
  color: var(--ink);
  border: none;
  padding: 14px 34px;
  font-size: 14px;
  font-family: inherit;
  font-weight: 600;
  cursor: pointer;
  transition: background .2s, transform .2s;
}
.btn--submit:hover {
  background: var(--accent-hover);
  transform: translateY(-2px);
}

/* ============================================================
   HERO
   ============================================================ */

/* min-height rather than a fixed height: the four-line headline plus the
   description, button and countdown can exceed a short viewport, and a
   fixed height would push the countdown out through the bottom. */
.hero {
  /* Same body width as every section below, set by "How Faber House
     works" - see the note on .how. The portraits and the background are
     absolutely positioned against the hero's padding box, so they stay
     flush to the edges and this only moves the nav and the copy. */
  --inset: clamp(40px, 8vw, 120px);
  background: var(--ink);
  min-height: max(720px, 100svh);
  display: flex;
  flex-direction: column;
  padding: 0 var(--inset);
}

/* ---------- drifting contour backdrop ----------
   A viewport-tall canvas that stays put while its section scrolls over
   it, so the hero, "How Faber House works" and "What we build" share one
   continuous ground rather than three separate ones. Each section carries
   its own copy; main.js paints the same field into all of them.

   overflow is `clip`, not `hidden`: `hidden` would make this element the
   scrollport for the pin inside it, and the pin would stop sticking. The
   pin is also naturally held inside this box, so it never spills into the
   section below. */
.section-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: clip;
  pointer-events: none;
}
.section-bg__pin {
  position: sticky;
  top: 0;
  height: 100vh;
}
.section-bg canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.nav, .hero__body { position: relative; z-index: 2; }

/* The dark band. It holds the ground colour and the one pinned backdrop
   for both sections inside it, which are themselves transparent so the
   backdrop shows through. The band has to stay opaque: the contact
   section is sticky behind the whole page and would otherwise show
   through here. */
.dark-band {
  position: relative;
  /* Above the contact section, which is sticky at z-index 0 behind the
     whole page. The two sections in here used to block it with their own
     backgrounds; now that they are transparent, the band has to. */
  z-index: 1;
  background: #0a0a0a;
}
.dark-band > .section-bg { z-index: 0; }
.dark-band > .how,
.dark-band > .values-section,
.dark-band .build { background: transparent; }

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 28px 0;
  font-size: 14px;
  font-weight: 500;
  animation: fadeIn 1s .1s both;
}
.nav__logo { display: flex; align-items: center; }
.nav__logo img { height: 21px; width: auto; display: block; }

.hero__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-top: 6vh;
}

.hero__headline {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(34px, 6.6vw, 92px);
  line-height: 0.92;
  letter-spacing: 0.01em;
  font-weight: 500;
  text-transform: uppercase;
  text-wrap: pretty;
  animation: riseUp .9s var(--ease) .25s both;
}
/* ---------- liquid hover distortion (hero-fluid.js) ----------
   Shared by every display heading. The canvas mirrors its heading
   pixel-for-pixel and sits exactly over it, inside the heading itself.
   Once it is live the DOM text goes transparent: it keeps doing layout,
   SEO and screen-reader duty, and the canvas does the pixels. */
.fluid-canvas {
  position: absolute;
  z-index: 1;
  pointer-events: none;
}
.is-fluid-live {
  position: relative;   /* containing block for the canvas */
  color: transparent;
}
.is-fluid-live ::selection { background: transparent; }

/* One block per line locks the break points. */
.hero__line { display: block; }
@media (max-width: 900px) {
  .hero__line { display: inline; }
}

.hero__sub {
  margin: 32px 0 0;
  /* Wide enough to hold the copy on two lines at the 20px cap (it needs
     1144px laid out flat, so a hair over half). */
  max-width: 620px;
  font-size: clamp(16px, 1.6vw, 20px);
  line-height: 1.35;
  letter-spacing: -0.015em;
  font-weight: 400;
  color: var(--muted-hero);
  text-wrap: pretty;
  animation: riseUp .9s var(--ease) .25s both;
}

/* Pushed to the foot of the hero copy column and held a fixed distance
   off the bottom, so it keeps the reference's low-left position instead
   of riding up under the subcopy as the viewport grows. */
.hero__cta {
  margin-top: 28px;
  /* Guarantees a gap even when the copy column is full and the
     countdown's auto top margin collapses to zero. */
  margin-bottom: 32px;
  animation: riseUp .9s var(--ease) .35s both;
}

.countdown {
  margin-top: auto;
  margin-bottom: clamp(40px, 16vh, 190px);
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: fit-content;
  max-width: 100%;
  animation: riseUp .9s var(--ease) .4s both;
}
.countdown__label {
  max-width: 360px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted-dark);
  letter-spacing: 0.02em;
  line-height: 1.5;
}
.countdown__clock {
  display: flex;
  align-items: flex-start;
  gap: 22px;
}
.countdown__unit {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.countdown__value {
  font-size: clamp(32px, 3.4vw, 48px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.countdown__caption {
  font-size: 12px;
  color: var(--muted-dark);
}
.countdown__sep {
  font-size: clamp(26px, 3vw, 40px);
  line-height: 1.1;
  color: var(--accent);
  font-weight: 300;
}

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

.hero__people {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 1; /* above the canvas, below the copy */
  display: flex;
  align-items: flex-end;
  max-width: 62%;
  animation: riseUp 1.1s var(--ease) .45s both;
}

.hero-person {
  margin: 0;
  position: relative;
  flex: 0 0 auto;
}
/* Kas sits slightly taller than Jack, as set in the canvas. Kept in vh so
   the pair still scales with the viewport rather than being pinned to the
   px values the editor wrote. */
.hero-person img {
  display: block;
  width: auto;
}
.hero-person--kas img { height: clamp(340px, 60vh, 600px); }
.hero-person--jack img { height: clamp(326px, 57vh, 574px); }
/* The two portraits overlap slightly, with Kas in front of Jack as in
   the reference. Kas needs the explicit z-index because Jack comes later
   in the DOM and would otherwise paint on top. */
.hero-person--kas { z-index: 1; }
.hero-person--jack { margin-left: clamp(-90px, -6vw, -40px); }

.hero-person__label {
  position: absolute;
  left: 18%;
  bottom: 9%;
  z-index: 2; /* above the neighbouring portrait, which overlaps this one */
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-left: 12px;
  border-left: 2px solid rgba(245, 245, 245, 0.55);
  white-space: nowrap;
}
.hero-person__name {
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
}
.hero-person__role {
  font-size: 13px;
  color: #d4d4d4;
}

/* ============================================================
   MANIFESTO + STATS
   ============================================================ */

.manifesto {
  /* Body width, as set by "How Faber House works". The heading, the lede
     and the leading rule of the first stat all start on that edge. */
  --inset: clamp(40px, 8vw, 120px);
  background: var(--paper);
  color: var(--ink);
  padding: 110px var(--inset) 56px;
}

.manifesto__title {
  margin: 0;
  max-width: 742px;
  font-size: clamp(30px, 4.2vw, 54px);
  line-height: 1.14;
  font-weight: 550;
  letter-spacing: 0.01em;
  text-wrap: pretty;
}

.manifesto__lede {
  margin: 28px 0 0;
  max-width: 622px;
  font-size: 16px;
  line-height: 1.6;
  letter-spacing: -0.02em;
  font-weight: 300;
  color: var(--muted-light);
  text-wrap: pretty;
}

.stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 32px;
  margin-top: 150px;
}

.stat {
  border-left: 1px solid var(--rule-light);
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 32px;
  min-height: 220px;
}
.stat__label {
  margin: 0;
  font-size: 18px;
  line-height: 1.5;
  color: var(--muted-light);
  max-width: 250px;
}
.stat__value {
  font-size: clamp(38px, 4.4vw, 60px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.section-meta {
  display: flex;
  justify-content: space-between;
  margin-top: 64px;
  font-size: 11px;
  color: var(--muted-dark);
}

/* ============================================================
   THE PROBLEM / HOW IT WORKS
   ============================================================ */

.how {
  position: relative;
  z-index: 1;
  /* The deeper black the reference sits on is carried by .dark-band, so
     this and "What we build" can share one backdrop. */
  color: var(--paper);
  /* The reference uses a wider inset than the site's 40px gutter:
     ~9.5% of the frame. */
  --inset: clamp(40px, 8vw, 120px);
  padding: 110px var(--inset) 130px;
}

/* Two-column armature shared by the problem block and the steps. Equal
   columns on a shared gap, which opens the second column at the page
   centre plus half that gap - the same edge .build__head and
   .why__standard use, so the right-hand copy lines up all the way down
   the page. The steps override the tracks below to hold their 460px
   measure while staying on this gap. */
.how__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(48px, 6vw, 120px);
}

.how__label {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
}
/* The label wipes in left-to-right instead of fading up. The clip lives
   on an inner span: fully clipping the observed element itself would
   zero its visual rect and IntersectionObserver would never fire. */
.js .how__label[data-reveal] { opacity: 1; transform: none; transition: none; }
.how__label-inner { display: inline-block; }
.js .how__label .how__label-inner {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1s var(--ease);
}
.js .how__label.is-revealed .how__label-inner { clip-path: inset(0 -5% 0 0); }

.how__problem-copy {
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* Sized so the opening line sits on one line and the paragraph under
     it runs to three. */
  max-width: 520px;
}
.how__problem-copy p {
  margin: 0;
  font-size: 17px;
  line-height: 1.55;
  color: #a3a3a6;
  text-wrap: pretty;
}
.how__problem-copy .how__stance {
  margin-top: 26px;
  font-size: 18px;
  color: var(--paper);
}
.how__stance strong { font-weight: 600; }
/* A sentence per line. They go back to inline on small screens, where
   the forced break would leave a very short second line. */
.how__stance-line { display: block; }

/* ---------- display title ---------- */

.how__title {
  margin: 150px 0 180px;
  font-size: clamp(48px, 9vw, 130px);
  line-height: 0.98;
  font-weight: 600;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}
/* The whole heading sits against the right edge: "HOW FABER HOUSE" on one
   line with a word space between the two masks, "WORKS" tucked under it.
   column-gap rather than gap, so the mobile rule below - which turns this
   row into a column - does not inherit it as vertical space. */
.how__title-row {
  display: flex;
  justify-content: flex-end;
  column-gap: 0.25em;
}
.how__mask {
  display: block;
  overflow: hidden;
}
.how__mask--works {
  text-align: right;
  margin-top: -0.02em;
}
/* The reveal: each phrase rises out of its mask and its tracking
   settles as it lands. Width changes stay anchored to the pinned
   edges, so the composition holds during the motion. */
.how__mask-inner {
  display: block;
  will-change: transform;
}
.js .how__title .how__mask-inner {
  transform: translateY(115%);
  letter-spacing: 0.06em;
  transition: transform 1.15s var(--ease), letter-spacing 1.15s var(--ease);
}
.js .how__title .how__title-row .how__mask:last-child .how__mask-inner { transition-delay: .12s; }
.js .how__title .how__mask--works .how__mask-inner { transition-delay: .24s; }
.js .how__title.is-revealed .how__mask-inner {
  transform: translateY(0);
  letter-spacing: 0.01em;
}
/* The h2 is only the trigger — it must not fade as a block. */
.js .how__title[data-reveal] { opacity: 1; transform: none; transition: none; }

/* ---------- numbered steps ---------- */

/* The steps break out of .how__grid's 1.55fr/1fr split. That split gave
   the left column nearly twice the width its 460px of content used, so
   the two columns sat at opposite edges with a void between them. Here
   each track is the content width and the pair is centred as a group. */
.how__steps {
  row-gap: 96px;
  grid-template-columns: repeat(2, minmax(0, 460px));
  column-gap: clamp(48px, 6vw, 120px);
  justify-content: center;
}

.step { max-width: 460px; }
.step__num {
  display: block;
  margin-bottom: 40px;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.step__title {
  margin: 0 0 24px;
  font-size: 27px;
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.2;
  text-wrap: pretty;
}
.step__copy {
  margin: 0;
  max-width: 430px;
  font-size: 17px;
  line-height: 1.55;
  color: #a3a3a6;
  text-wrap: pretty;
}

/* Each step reveals as number → title → copy, cascading inside the
   step's own trigger; the four steps themselves stagger left to right
   via their data-reveal delays. */
.js .how .step[data-reveal] { opacity: 1; transform: none; transition: none; }
.js .step .step__num,
.js .step .step__title,
.js .step .step__copy {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity .8s var(--ease), transform .8s var(--ease);
}
.js .step.is-revealed .step__num { opacity: 1; transform: none; }
.js .step.is-revealed .step__title { opacity: 1; transform: none; transition-delay: .12s; }
.js .step.is-revealed .step__copy { opacity: 1; transform: none; transition-delay: .24s; }

@media (max-width: 1024px) {
  .how__grid { grid-template-columns: 1fr; row-gap: 40px; }
  .how__stance-line { display: inline; }
  .how__steps { row-gap: 64px; }
  .how__title { margin: 100px 0 110px; }
}

@media (max-width: 760px) {
  .how { --inset: 20px; padding: 72px var(--inset) 80px; }
  .how__title { font-size: clamp(40px, 11.5vw, 64px); }
  .how__title-row { flex-direction: column; }
  .how__mask--works { text-align: left; margin-top: 0; }
}

/* ============================================================
   VALUES + WHAT WE DO
   ============================================================ */

.values-section {
  background: #fafafa;
  color: var(--ink);
}

/* ---------- What We Build ---------- */

/* The whole section is the dark surface now - no inner panel. */
.build {
  --inset: clamp(40px, 8vw, 120px);
  color: var(--paper);
}

/* Heading left, intro on the right and centred against it.

   Equal columns on the same gap as .how__steps, which puts this second
   column on exactly the same edge as that section's second column: both
   grids sit in a content box of the same width, so the column starts at
   the page centre plus half the gap either way. Keep the two gaps equal
   and the edge holds. */
.build__head {
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: clamp(48px, 6vw, 120px);
  align-items: center;
}

.build__title {
  margin: 0;
  /* Capped against viewport height too, so the pinned block (heading +
     box) still fits on a short screen. */
  font-size: min(clamp(48px, 8.6vw, 124px), 16vh);
  line-height: 0.9;
  font-weight: 600;
  letter-spacing: 0.005em;
  text-transform: uppercase;
}
.build__mask { display: block; overflow: hidden; }
.build__mask-inner { display: block; will-change: transform; }
/* Rises out of the mask with its tracking settling in, matching the
   How Faber House Works heading. */
.js .build__title .build__mask-inner {
  transform: translateY(115%);
  letter-spacing: 0.06em;
  transition: transform 1.15s var(--ease), letter-spacing 1.15s var(--ease);
}
.js .build__title .build__mask:last-child .build__mask-inner { transition-delay: .12s; }
.js .build__title.is-revealed .build__mask-inner {
  transform: translateY(0);
  letter-spacing: 0.005em;
}
.js .build__title[data-reveal] { opacity: 1; transform: none; transition: none; }

.build__intro {
  margin: 0;
  max-width: 440px;   /* breaks the sentence over two lines */
  font-size: 17px;
  line-height: 1.5;
  color: #c9c9cc;
  text-wrap: pretty;
}

/* The runway. main.js sets its height to one scroll step per card past
   the pinned screen. The pin is a full-height black screen holding the
   heading, intro, card and timeline, so all of it stays put until the
   last card is done. Without JS the stage is auto height and the cards
   simply stack. */
.build__stage {
  position: relative;
}
.build__pin {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  padding: clamp(56px, 11vh, 120px) var(--inset) 0;
  box-sizing: border-box;
  overflow: hidden;
}

/* The card sits low on the screen and centred on the page. .build__pin is
   a column flex container, so the auto side margins absorb the free space
   either side; its content box is symmetric about the page centre, so
   centring in it centres on the page. margin-top stays auto to keep
   pushing the card down the pinned screen.

   width, not max-width: auto margins on the cross axis stop a flex item
   stretching, and the cards inside are absolutely positioned, so they
   lend it no intrinsic width - with max-width alone the deck collapses
   to nothing. */
.build__deck {
  position: relative;
  margin: auto auto clamp(90px, 17vh, 190px);
  width: min(520px, 100%);
}

.build__cards {
  position: relative;
  z-index: 1;
  /* Tall enough for the longest card - a two-line title over three
     lines of copy - since the cards are absolutely positioned and would
     otherwise spill past the container toward the timeline. */
  min-height: 240px;
}
.build__card { margin: 0; }
/* Cards stack in one slot. Cards not yet reached wait below the visible
   position; cards already passed (.is-above) wait above it, so scrolling
   back brings them down from the top. The leaving card exits upward
   going forward and downward going back. Title and copy move as a short
   cascade so the change reads as one motion, not two. */
.js .build__card {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.js .build__card.is-active { pointer-events: auto; }
.js .build__card-title,
.js .build__card-copy {
  opacity: 0;
  transform: translateY(40px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.js .build__card.is-above .build__card-title,
.js .build__card.is-above .build__card-copy { transform: translateY(-40px); }
.js .build__card.is-active .build__card-title { opacity: 1; transform: none; transition-delay: .06s; }
.js .build__card.is-active .build__card-copy { opacity: 1; transform: none; transition-delay: .16s; }
.js .build__card.is-leaving .build__card-title,
.js .build__card.is-leaving .build__card-copy {
  opacity: 0;
  transform: translateY(-32px);
  transition-delay: 0s;
}
.js .build__card.is-leaving-down .build__card-title,
.js .build__card.is-leaving-down .build__card-copy {
  opacity: 0;
  transform: translateY(32px);
  transition-delay: 0s;
}

.build__card-title {
  margin: 0 0 44px;
  max-width: 460px;
  font-size: clamp(26px, 2.6vw, 37px);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.08;
  text-wrap: pretty;
}
.build__card-copy {
  margin: 0;
  max-width: 440px;
  font-size: 17px;
  line-height: 1.45;
  color: var(--paper);
  text-wrap: pretty;
}

/* The orange timeline along the bottom edge. main.js scales it from 0 to
   1 with scroll progress through the runway; transform rather than
   width so it never triggers layout. */
/* Full-bleed across the screen, with the unfilled remainder showing as
   a dim track. */
.build__timeline {
  position: absolute;
  left: 0;
  right: 0;
  bottom: clamp(40px, 9vh, 96px);
  z-index: 2;
  height: 4px;
  background: rgba(245, 245, 245, 0.14);
  pointer-events: none;
}
.build__bar {
  position: absolute;
  inset: 0;
  background: var(--accent);
  transform-origin: left center;
  transform: scaleX(0);
  will-change: transform;
}

.what-we-do {
  --inset: clamp(40px, 8vw, 120px);
  padding: clamp(80px, 13vh, 150px) var(--inset) clamp(90px, 15vh, 170px);
}
.what-we-do__title {
  margin: 0;
  font-size: clamp(38px, 8vw, 112px);
  font-weight: 600;
  letter-spacing: 0.005em;
  line-height: 0.95;
  text-transform: uppercase;
}
.wwd__mask { display: block; overflow: hidden; }
.wwd__mask-inner { display: block; will-change: transform; }
.js .what-we-do__title .wwd__mask-inner {
  transform: translateY(115%);
  letter-spacing: 0.06em;
  transition: transform 1.15s var(--ease), letter-spacing 1.15s var(--ease);
}
.js .what-we-do__title .wwd__mask:nth-child(2) .wwd__mask-inner { transition-delay: .12s; }
.js .what-we-do__title .wwd__mask:nth-child(3) .wwd__mask-inner { transition-delay: .24s; }
.js .what-we-do__title .wwd__mask:nth-child(4) .wwd__mask-inner { transition-delay: .36s; }
.js .what-we-do__title.is-revealed .wwd__mask-inner {
  transform: translateY(0);
  letter-spacing: 0.005em;
}
.js .what-we-do__title[data-reveal] { opacity: 1; transform: none; transition: none; }

/* Lede on the left, the caveat and the link offset to the right and
   dropped below it, as in the reference. */
.what-we-do__cols {
  margin-top: clamp(48px, 9vh, 100px);
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 48px;
  align-items: start;
}
/* Everything sits in the right-hand column, under the heading's second
   half. Explicitly placed, because it is the only child left and would
   otherwise fall into column one. */
.what-we-do__aside { grid-column: 2; }
.what-we-do__lede,
.what-we-do__caveat {
  margin: 0;
  max-width: 400px;
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted-mid);
  text-wrap: pretty;
}
/* After the shared reset above, or it just gets zeroed again. */
.what-we-do__caveat { margin-top: clamp(24px, 3.4vh, 36px); }
.what-we-do__link {
  display: inline-block;
  margin-top: clamp(32px, 5vh, 52px);
  font-size: 16px;
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 6px;
  transition: color .2s;
}

/* ============================================================
   CTA / CONTACT  (sticky — revealed from behind the sections above)
   ============================================================ */

.cta {
  position: sticky;
  bottom: 0;
  z-index: 0;
  background: var(--ink);
  color: var(--paper);
  min-height: 92vh;
  display: flex;
  flex-direction: column;
  padding: clamp(30px, 4vh, 44px) var(--gutter) 24px;
}

.cta__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

/* Same treatment as the other section headings: uppercase, weight 600,
   tight leading, each line rising out of its own mask. */
.cta__title {
  margin: 0 0 clamp(18px, 2.8vh, 30px);
  font-size: min(clamp(32px, 6vw, 84px), 9.5vh);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 0.95;
  text-align: center;
  text-transform: uppercase;
  text-wrap: pretty;
}
.cta__mask { display: block; overflow: hidden; }
.cta__mask-inner { display: block; will-change: transform; }
.js .cta__title .cta__mask-inner {
  transform: translateY(115%);
  letter-spacing: 0.06em;
  transition: transform 1.15s var(--ease), letter-spacing 1.15s var(--ease);
}
.js .cta__title .cta__mask:last-child .cta__mask-inner { transition-delay: .12s; }
.js .cta__title.is-revealed .cta__mask-inner {
  transform: translateY(0);
  letter-spacing: 0.01em;
}
.js .cta__title[data-reveal] { opacity: 1; transform: none; transition: none; }

.cta__intro {
  margin: 0 0 clamp(24px, 3.4vh, 38px);
  max-width: 760px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  text-align: center;
}
.cta__intro p {
  margin: 0;
  font-size: 16px;
  line-height: 1.55;
  color: var(--muted-body);
  text-wrap: pretty;
}

.contact-form {
  display: flex;
  flex-direction: column;
  gap: clamp(17px, 2.4vh, 24px);
  width: 100%;
  max-width: 440px;
}
.field { display: flex; flex-direction: column; }
.contact-form input,
.contact-form textarea {
  border: none;
  border-bottom: 1px solid var(--muted-body);
  background: transparent;
  padding: 0 0 12px;
  font-size: 15px;
  font-family: inherit;
  line-height: 1.5;
  color: var(--paper);
  outline: none;
  border-radius: 0;
  transition: border-color .2s;
}
.contact-form textarea {
  resize: vertical;
  min-height: 3.6em;
}
.contact-form input::placeholder,
.contact-form textarea::placeholder { color: var(--muted-body); }
.contact-form input:focus,
.contact-form textarea:focus { border-bottom-color: var(--paper); }

.form-status {
  margin: 0;
  min-height: 1em;
  font-size: 13px;
  text-align: center;
  color: var(--muted-dark);
}

.footer {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted-dark);
  padding-top: clamp(20px, 3vh, 34px);
  text-align: center;
}

/* ============================================================
   WHY FABER HOUSE
   ============================================================ */

.why {
  --inset: clamp(40px, 8vw, 120px);
  background: #fafafa;
  color: var(--ink);
  padding: clamp(72px, 12vh, 140px) 0 clamp(80px, 14vh, 160px);
}

/* WHY sits left, FABER HOUSE is pushed to the right edge. */
/* "WHY", "FABER HOUSE" and the description share this block and are all
   left-aligned in it, so the three start on one edge - the section's own
   inset, the same edge [ THE STANDARD ] below them uses. */
.why__head {
  padding: 0 var(--inset);
}
.why__title {
  margin: 0;
  font-size: min(clamp(48px, 8.6vw, 122px), 15vh);
  line-height: 0.95;
  font-weight: 600;
  letter-spacing: 0.005em;
  text-transform: uppercase;
}
.why__mask { display: block; overflow: hidden; }
.why__mask-inner { display: block; will-change: transform; }
.js .why__title .why__mask-inner {
  transform: translateY(115%);
  letter-spacing: 0.06em;
  transition: transform 1.15s var(--ease), letter-spacing 1.15s var(--ease);
}
.js .why__title .why__mask:last-child .why__mask-inner { transition-delay: .12s; }
.js .why__title.is-revealed .why__mask-inner {
  transform: translateY(0);
  letter-spacing: 0.005em;
}
.js .why__title[data-reveal] { opacity: 1; transform: none; transition: none; }

/* Sits under the right-hand end of the heading. */
.why__intro {
  margin: clamp(28px, 5vh, 58px) 0 0;
  max-width: 470px;   /* breaks the sentence over two lines */
  font-size: 17px;
  line-height: 1.5;
  color: var(--muted-light);
  text-wrap: pretty;
}
.why__intro strong { font-weight: 600; color: var(--ink); }

/* Label left, list right, their first lines on the same baseline. */
/* Equal columns on the same gap as .what-we-do__cols, so this list and
   the "We work with companies" copy below it start on the same edge -
   both grids span a content box of the same width, so the second column
   opens at the page centre plus half the gap in each. */
.why__standard {
  margin-top: clamp(60px, 13vh, 150px);
  padding: 0 var(--inset);
  display: grid;
  grid-template-columns: 1fr 1fr;
  column-gap: 48px;
  align-items: start;
}

.why__label {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--accent);
}
.why__label-inner { display: inline-block; }
.js .why__label[data-reveal] { opacity: 1; transform: none; transition: none; }
.js .why__label .why__label-inner {
  clip-path: inset(0 100% 0 0);
  transition: clip-path 1s var(--ease);
}
.js .why__label.is-revealed .why__label-inner { clip-path: inset(0 -5% 0 0); }

.why__list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.why-item {
  padding-bottom: clamp(22px, 3vh, 30px);
  border-bottom: 1px solid #dcdcdc;
}
.why-item + .why-item { padding-top: clamp(26px, 3.6vh, 36px); }
.why-item__title {
  margin: 0;
  font-size: clamp(18px, 1.45vw, 21px);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1.25;
  text-wrap: pretty;
}
.why-item__copy {
  margin: 14px 0 0;
  max-width: 600px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted-light);
  text-wrap: pretty;
}

@media (max-width: 760px) {
  .why { --inset: 20px; padding: 72px 0 80px; }
  .why__title { font-size: clamp(38px, 12vw, 60px); }
  .why__intro { max-width: none; }
  .why__standard { grid-template-columns: 1fr; row-gap: 32px; }
}

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

/* Between tablet and desktop the portraits would crowd the copy, so they
   step back before the layout reflows entirely at 760px. */
@media (max-width: 1024px) {
  .hero__people { max-width: 52%; }
  .hero-person img { height: clamp(260px, 34vh, 340px); }
  /* Portraits are narrower here, so the overlap shrinks to keep Jack's
     image clear of Kas's caption. */
  .hero-person--jack { margin-left: -28px; }
  .hero-person__label { left: 8%; bottom: 7%; }
  .hero-person__role { font-size: 12px; }
  .hero__headline { font-size: clamp(34px, 6.4vw, 64px); }
}

@media (max-width: 1024px) {
  .stats {
    grid-template-columns: repeat(2, 1fr);
    gap: 48px 32px;
    margin-top: 100px;
  }
}

@media (max-width: 760px) {
  :root { --gutter: 20px; }

  .hero, .manifesto { --inset: 20px; }

  .hero {
    height: auto;
    min-height: 100svh;
    padding-bottom: 8px;
  }
  .hero__body { padding-top: 48px; padding-bottom: 64px; }
  /* The hero grows with its content here, so the auto push-down has
     nothing to push against — go back to normal flow spacing. */
  .countdown {
    margin-top: 40px;
    margin-bottom: 0;
  }
  .countdown__clock { gap: 16px; }

  /* Portraits move below the copy and shrink so the headline keeps the
     full width of a phone screen. Labels drop beneath each portrait
     rather than overlaying it — overlaid they clip at this size. */
  .hero__people {
    position: static;
    max-width: none;
    align-items: stretch;
    gap: 16px;
    margin-top: 48px;
  }
  .hero-person {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
  }
  .hero-person--jack { margin-left: 0; }
  .hero-person img {
    height: auto;
    width: 100%;
  }
  .hero-person__label {
    position: static;
    white-space: normal;
    margin-top: 12px;
  }
  .hero-person__name { font-size: 13px; }
  .hero-person__role { font-size: 12px; line-height: 1.4; }

  .manifesto { padding: 72px var(--inset) 40px; }
  .stats { grid-template-columns: 1fr; margin-top: 64px; gap: 40px; }
  .stat { min-height: 0; }
  .stat__label { max-width: none; }

  .build { --inset: 20px; }
  .build__pin { padding-top: 64px; }
  .build__head { grid-template-columns: 1fr; row-gap: 24px; align-items: start; }
  .build__title { font-size: clamp(40px, 13vw, 64px); }
  .build__intro { margin: 0; max-width: none; }
  .build__deck {
    margin: auto 0 clamp(64px, 14vh, 120px);
    width: 100%;
  }
  .build__cards { min-height: 260px; }
  .build__timeline { bottom: clamp(28px, 7vh, 64px); }
  .what-we-do { --inset: 20px; padding: 72px var(--inset) 80px; }
  .what-we-do__title { font-size: clamp(34px, 11.5vw, 58px); }
  .what-we-do__cols { grid-template-columns: 1fr; row-gap: 32px; }
  /* One column here, so the explicit placement has to be released or it
     would conjure a second one. */
  .what-we-do__aside { grid-column: auto; }
  .what-we-do__lede,
  .what-we-do__caveat { max-width: none; }

  .cta { padding: 32px var(--gutter) 24px; }
  .cta__title { margin-bottom: 18px; font-size: clamp(28px, 8.4vw, 40px); }
  .cta__mask { display: inline; }
  .cta__intro { margin-bottom: 24px; gap: 12px; }
  .cta__intro p { font-size: 15px; }
  .contact-form { gap: 18px; }
  .footer { padding-top: 24px; }
}

/* Respect the OS-level motion preference. main.js also strips the entrance
   animations and freezes the hero canvas on a single frame. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
