/* ═══════════════════════════════════════════════════════════════════════
   SOLARA — built to redesign-B.png
   The page is one day in the high desert: dawn → material → roofline →
   the plan → the room → the residences → night. It is the same house the
   whole way down, and the horizon never leaves the screen.
   ═══════════════════════════════════════════════════════════════════════ */

/* Newsreader, not a garamond. The display face has to hold white type over a
   photograph and set a strip of coordinates in the same breath — Cormorant
   could do neither: hairline stems that dissolve over bright stone, and
   old-style figures that made "33.8734°N" and a ticking clock read as fussy
   rather than surveyed. Newsreader carries an optical-size axis, so one file
   stays fine at 130px and gains weight where the type is 11px. */
@font-face{
  font-family:'Newsreader';
  src:url('fonts/Newsreader.woff2') format('woff2-variations'),
      url('fonts/Newsreader.woff2') format('woff2');
  font-weight:200 800; font-style:normal; font-display:swap;
}
/* the latin subset as woff2, not the 856KB full variable TTF — on a 3G
   connection that single file was four seconds of the loader all by itself */
@font-face{
  font-family:'InterLocal';
  src:url('fonts/Inter-latin.woff2') format('woff2');
  font-weight:100 900; font-style:normal; font-display:swap;
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,
                U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,
                U+2212,U+2215,U+FEFF,U+FFFD;
}

:root{
  /* sampled from the comp, not invented */
  --cream:#E4DDD4;        /* the ledger panel */
  --cream-rule:#CBC5BE;
  --ink:#241E18;          /* type on cream */
  --ink-soft:#6B6058;
  --brown:#12100D;        /* the footer's base — the darkest ground on the page */
  --night:#171B24;
  --ember:#C87A3C;        /* the one accent — desert light */
  --paper:#EFEAE1;

  --display:'Newsreader', 'Iowan Old Style', 'Palatino Linotype', Georgia, serif;
  --ui:'InterLocal', ui-sans-serif, -apple-system, 'Helvetica Neue', Arial, sans-serif;

  --pad:clamp(22px, 4.9vw, 70px);     /* measured: 50/1024 of the comp */
  --maxw:1440px;

  /* the chapter's ground colour. Every section writes it; the transition on
     :root is what makes the temperature bleed across a boundary instead of
     cutting. See direction.md §4, "colour bleed". */
  --ground:#8E8A80;
}
:root[data-chapter="dawn"]      {--ground:#9A8E77}
:root[data-chapter="commission"]{--ground:var(--paper)}
:root[data-chapter="material"]  {--ground:#4A3A2C}
:root[data-chapter="roof"]      {--ground:#5A5B60}
:root[data-chapter="plan"]      {--ground:#544032}
:root[data-chapter="interior"]  {--ground:#171009}
:root[data-chapter="residences"]{--ground:var(--cream)}
:root[data-chapter="night"]     {--ground:#242B36}
:root[data-chapter="inquire"]   {--ground:#1B1F27}
:root[data-chapter="foot"]      {--ground:var(--brown)}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%; scroll-behavior:auto}
body{
  position:relative;      /* the through-line layer measures against THIS */
  margin:0; background:var(--ground); color:#F3EFE8;
  font-family:var(--ui); font-size:16px; line-height:1.6;
  overflow-x:clip;                       /* clip, never hidden — see pitfalls */
  transition:background-color 1.1s cubic-bezier(.4,0,.2,1);
  -webkit-font-smoothing:antialiased;
}
img{display:block; max-width:100%}
a{color:inherit; text-decoration:none}
table{border-collapse:collapse}

/* ── the loader: hides decode and the first paint ───────────────────── */
.load{
  position:fixed; inset:0; z-index:90; display:grid; place-content:center; gap:26px;
  background:#12100E; transition:opacity .8s ease, visibility .8s;
}
.load.done{opacity:0; visibility:hidden}
.load__mark{
  font-family:var(--display); font-size:clamp(20px,2.4vw,30px);
  letter-spacing:.42em; color:#EFE7DA; text-indent:.42em; text-align:center;
}
.load__bar{width:min(210px,42vw); height:1px; background:rgba(239,231,218,.22); overflow:hidden}
.load__bar i{
  display:block; height:100%; width:100%; background:#EFE7DA;
  transform:scaleX(var(--lp,0)); transform-origin:left; transition:transform .35s ease;
}

/* ── the through-line ───────────────────────────────────────────────────
   One page-level SVG spanning the document. It is drawn to the FOLD, so its
   leading edge is always a viewport behind the reader and never seen arriving.
   The layer stretches non-uniformly, so it is revealed by clipping rather than
   dashing, and the stroke is non-scaling so its width stays even. */
.tl{
  position:absolute; inset:0; width:100%; height:100%;
  z-index:2; pointer-events:none;
  clip-path:inset(0 0 calc((1 - var(--tlp,0)) * 100%) 0);
  /* This SVG is as tall as the whole document, and the clip above moves every
     frame. Un-promoted, each step re-rasterises the full 10,000px box, which
     is why the bottom of the page — where the most line is revealed — ran at
     ~11fps and got worse the further you scrolled. On its own layer the clip
     is a compositor operation instead: same drawing, ~54fps. */
  will-change:transform;
}
/* At half opacity in overlay this was a claim the page made in the code and
   never on the screen. It is the one device the whole design is built on, so
   it is drawn plainly, with a shadow that keeps it legible over sunlit stone
   and a dark counter-stroke for the two light chapters. */
.tl__p{
  fill:none; stroke:rgba(247,241,229,.68); stroke-width:1.1;
  filter:drop-shadow(0 1px 1.5px rgba(16,10,4,.55));
}
:root[data-chapter="commission"] .tl__p,
:root[data-chapter="residences"] .tl__p{
  stroke:rgba(36,30,24,.34); filter:none;
}
.tl__p{transition:stroke .9s ease}

/* ── nav: hit-tests what is actually painted, inverts over the light panel ── */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:40;
  display:flex; align-items:center; justify-content:space-between;
  padding:clamp(20px,2.6vw,34px) var(--pad);
  color:#F3EFE8; mix-blend-mode:normal;
  transition:color .5s ease, transform .5s cubic-bezier(.22,.9,.24,1), opacity .4s;
}
.nav__mark.is-light,.nav__links.is-light{color:var(--ink)}
.nav__mark.is-light{opacity:.9}
.nav.is-hidden{transform:translateY(-104%); opacity:0}
/* The bar sets in the UI face, not the display serif. At 11-18px a high
   contrast serif tracked out to .4em has almost no stem left to see — over a
   photograph it reads as grey confetti. A grotesque holds its weight at that
   size, so the bar stays legible on its own and needs nothing painted behind
   it. */
.nav__mark{
  font-family:var(--ui); font-size:clamp(14px,1.15vw,17px);
  letter-spacing:.26em; text-indent:.26em; font-weight:500;
}
/* data-theme describes a section, but the nav sits over one corner of it —
   and the material chapter's top-left corner is sunlit stone, where white type
   disappears. Each nav group needs its own protection, which lifts the moment
   that group inverts to ink over the ledger.

   This used to be a radial-gradient box behind each group. Over an open sky
   the two boxes read as two dark smudges floating in the picture — there is
   no edge for them to belong to. A shadow carried by the glyphs does the same
   legibility job and has no shape of its own to notice. */
.nav__mark,.nav__links{position:relative}

.nav__mark,.nav__links a{
  /* a hairline dark edge, not a cloud: at 11px a blurred shadow creeps into
     the counters and the type reads grey no matter how white it is */
  paint-order:stroke fill;
  -webkit-text-stroke:2.2px rgba(10,6,3,.5);
  text-shadow:0 1px 2px rgba(10,6,3,.55);
  transition:text-shadow .45s ease;
}
.nav__mark.is-light,.nav__links.is-light a{-webkit-text-stroke:0}
.nav__mark.is-light,.nav__links.is-light a{text-shadow:none}
.nav__links{display:flex; gap:clamp(20px,3.1vw,46px)}
.nav__links a{
  font-family:var(--ui); font-size:clamp(10.5px,.8vw,12px); font-weight:500;
  letter-spacing:.15em; text-transform:uppercase; position:relative; padding-bottom:3px;
  color:#FFFDF9;
  transition:color .28s cubic-bezier(.22,1,.36,1), opacity .28s ease;
}
.nav__links a:hover,.nav__links a:focus-visible{color:#fff}
.nav__links.is-light a{color:color-mix(in oklab, var(--ink) 82%, transparent)}
.nav__links.is-light a:hover{color:var(--ink)}
.nav__links a::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:currentColor; transform:scaleX(0); transform-origin:right;
  transition:transform .45s cubic-bezier(.22,.9,.24,1);
}
.nav__links a:hover::after{transform:scaleX(1); transform-origin:left}
@media (max-width:720px){ .nav__links{display:none} }

/* ══ a chapter ═══════════════════════════════════════════════════════════ */
.ch{
  position:relative; min-height:100svh;      /* min-height, never height */
  display:grid; align-items:center;
  padding:clamp(124px,15vh,176px) var(--pad) clamp(96px,11vh,150px);
  overflow:clip;
}
.ch__media{position:absolute; inset:0; overflow:clip; z-index:0}
.ch__media img{
  width:100%; height:100%; object-fit:cover;
  transform:scale(var(--z,1.08)) translate3d(var(--mx,0),var(--my,0),0);
  will-change:transform;
}
.ch__copy{
  position:relative; z-index:3;
  max-width:min(680px, 54%);
  justify-self:start;
}
.ch__copy--right{justify-self:end; text-align:right}

.d1{
  font-family:var(--display); font-weight:300;
  font-size:clamp(38px, 5.3vw, 76px); line-height:1.04;
  letter-spacing:-.006em; margin:0;
  text-shadow:0 2px 40px rgba(20,14,8,.34);
}
.eyebrow{
  font-family:var(--ui); font-size:11px; font-weight:400;
  letter-spacing:.3em; text-transform:uppercase;
  color:rgba(243,239,232,.72); margin:0 0 clamp(14px,1.6vw,20px);
}
.lede{
  font-family:var(--ui); font-size:clamp(13px,1.03vw,15px); font-weight:300;
  line-height:1.72; color:rgba(243,239,232,.82);
  margin:clamp(18px,2.2vw,28px) 0 0; max-width:36ch;
}
.ch__copy--right .lede{margin-left:auto}

/* the link: a rule that draws, and an arrow that leaves before it returns */
.cta{
  display:inline-flex; align-items:center; gap:12px;
  margin-top:clamp(20px,2.6vw,32px); padding-bottom:7px; position:relative;
  font-family:var(--ui); font-size:10.5px; font-weight:400;
  letter-spacing:.24em; text-transform:uppercase; color:inherit;
}
.cta span{position:relative; padding-bottom:7px}
.cta span::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:currentColor; opacity:.5; transition:opacity .3s;
}
.cta:hover span::after{opacity:1}
.cta__r{
  width:26px; height:1px; background:currentColor; position:relative; flex:none;
  transition:transform .45s cubic-bezier(.22,.9,.24,1);
}
.cta__r::after{
  content:""; position:absolute; right:0; top:-2.5px;
  width:6px; height:6px; border-top:1px solid currentColor; border-right:1px solid currentColor;
  transform:rotate(45deg); transform-origin:right center;
}
.cta:hover .cta__r{transform:translateX(7px)}
.cta--ink{color:var(--ink)}

/* ── the colour bleed ──────────────────────────────────────────────────
   A join, not a cut: every chapter opens in the temperature of the one
   before it and clears within a screen-sixth, so the palette changes while
   you are still reading the previous frame. --ground alone could not do this
   — every chapter is full-bleed, so the body colour behind them is never
   actually seen. */
.ch::before{
  content:""; position:absolute; inset:0 0 auto 0; height:17vh;
  z-index:1; pointer-events:none;
  background:linear-gradient(180deg, var(--from, transparent), transparent);
}
.hero::before,.res::before{display:none}       /* first frame; and the ledger wipes */
.mat  {--from:rgba(154,142,119,.60)}           /* dawn bleeds in */
.roof {--from:rgba(74,58,44,.66)}              /* the stone */
.plan {--from:rgba(90,91,96,.58)}              /* the sky */
.int  {--from:rgba(84,64,50,.66)}              /* the ground */
.night{--from:rgba(214,206,196,.30)}           /* the last of the light */
.foot{position:relative}
/* the join is carried by the footer's own gradient now, over its whole height
   rather than as a 120px wash sitting on a lighter ground */
.foot__top,.foot__bar{position:relative; z-index:1}

/* ── 01 hero ────────────────────────────────────────────────────────── */
.hero{align-content:center}
.hero__media::after{               /* generated in-camera empty sky + one scrim */
  content:""; position:absolute; inset:0;
  background:linear-gradient(105deg, rgba(24,18,12,.5) 0%, rgba(24,18,12,.14) 42%, transparent 66%);
}
.hero__copy{max-width:min(820px,62%)}
/* The fold has to carry the whole practice. At 92px it was a section
   heading that happened to be first; this is a title page. */
.hero .d1{font-size:clamp(46px,9.1vw,158px); line-height:.94; letter-spacing:-.022em}
.hero__copy{max-width:min(1180px,88%)}
.hero .lede{font-size:clamp(14px,1.18vw,18px); max-width:34ch}
.hero__scroll{
  position:absolute; left:var(--pad); bottom:clamp(28px,4.4vh,54px); z-index:3;
  display:flex; align-items:center; gap:13px;
  font-size:9.5px; letter-spacing:.3em; text-transform:uppercase;
  color:rgba(243,239,232,.7);
}
.hero__scroll i{
  width:1px; height:36px; background:linear-gradient(180deg,currentColor,transparent);
  animation:drop 2.4s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes drop{0%{transform:scaleY(0); transform-origin:top}
                45%{transform:scaleY(1); transform-origin:top}
                46%{transform:scaleY(1); transform-origin:bottom}
                100%{transform:scaleY(0); transform-origin:bottom}}

/* ── 02 material — the copy sits in the dark right third of the frame ── */
.mat__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(270deg, rgba(16,11,7,.78) 0%, rgba(16,11,7,.5) 26%, rgba(16,11,7,.12) 50%, transparent 68%);
}

/* ── 03 roofline — copy in the empty sky at left ─────────────────────── */
.roof__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(100deg, rgba(22,24,30,.5) 0%, rgba(22,24,30,.08) 46%, transparent 68%);
}

/* ── 04 the plan — the page's one pinned scene ───────────────────────────
   story.js moves every child into a sticky .pin-inner, so the gutter, the
   alignment and the positioning context all belong to that element now —
   not to the section, which is only the scroll distance the pin spends. */
.plan{padding:0}
.plan > .pin-inner{
  padding:clamp(124px,15vh,176px) var(--pad) clamp(96px,11vh,150px);
  align-content:center; justify-items:start;
}
.plan__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(96deg, rgba(28,18,10,.8) 0%, rgba(28,18,10,.42) 40%, rgba(28,18,10,.5) 100%);
}
.plan__copy{max-width:min(460px,38%)}
.plan__svg{
  position:absolute; z-index:2; pointer-events:none;
  right:clamp(14px,3.4vw,66px); top:50%; transform:translateY(-50%);
  width:min(52vw, 640px); height:auto;
  overflow:visible;
  filter:drop-shadow(0 1px 2.5px rgba(16,9,3,.95));  /* so it reads on gravel */
}
/* The generated ground came back far busier and hotter than the comp's, and a
   0.5px hairline cannot survive that. Rather than dulling the whole photograph,
   lay one pool of shade exactly where the drawing lands — the frame keeps its
   texture everywhere else. */
.plan__media::before{
  content:""; position:absolute; z-index:1; right:-6%; top:50%;
  width:min(92vw,1180px); height:min(96vh,860px); transform:translateY(-50%);
  background:radial-gradient(closest-side, rgba(22,13,5,.8), rgba(22,13,5,.42) 52%, rgba(22,13,5,0) 82%);
}
.plan__svg .dr{
  fill:none; stroke:#F7EFE0; stroke-width:1.15; vector-effect:non-scaling-stroke;
  stroke-dasharray:var(--len,1200); stroke-dashoffset:calc(var(--len,1200) * (1 - var(--draw,0)));
}
.plan__svg .roofline{
  stroke-dasharray:7 6 !important; stroke-dashoffset:0 !important;
  stroke:rgba(247,239,224,.42);
  opacity:var(--draw,0);          /* a dashed line can't dash-reveal — fade it */
}
.plan__svg .faint{stroke:rgba(247,239,224,.5)}
.plan__svg .tick{stroke:rgba(247,239,224,.6)}
.plan__svg .grade{stroke:rgba(247,239,224,.42)}
.plan__dim .dr{stroke:rgba(247,239,224,.62); stroke-width:1}
.plan__dim text{
  fill:rgba(247,239,224,.9); font-family:var(--ui); font-size:11.5px;
  letter-spacing:.08em; text-anchor:middle;
  opacity:var(--dim,0); transition:opacity .5s ease;
  paint-order:stroke; stroke:rgba(16,9,3,.75); stroke-width:2.5px;
}
.plan__dim text.rot{transform:rotate(-90deg); transform-origin:604px 163px}
.plan__dim text.lbl{
  text-anchor:start; font-size:9.5px; letter-spacing:.22em;
  fill:rgba(247,239,224,.62);
}
.plan__stats{
  position:absolute; left:var(--pad); bottom:clamp(40px,7vh,86px); z-index:3;
  display:flex; gap:clamp(26px,4vw,64px); flex-wrap:wrap;
  opacity:var(--stats,0); transform:translateY(calc((1 - var(--stats,0)) * 16px));
  transition:opacity .5s ease, transform .6s cubic-bezier(.22,.9,.24,1);
}
.plan__stats div{display:flex; flex-direction:column; gap:7px}
.plan__stats b{
  font-family:var(--display); font-weight:300; font-size:clamp(28px,3.1vw,44px);
  line-height:1; font-variant-numeric:tabular-nums;
}
.plan__stats span{
  font-size:9.5px; letter-spacing:.22em; text-transform:uppercase;
  color:rgba(243,239,232,.6);
}

/* ── 05 interior — the view opens ────────────────────────────────────── */
.int__media{background:#0A0704}
.int__media img{clip-path:inset(0 var(--open,0) 0 var(--open,0))}
.int__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(270deg, rgba(6,4,3,.93) 0%, rgba(6,4,3,.86) 17%, rgba(6,4,3,.48) 36%, rgba(6,4,3,.1) 58%, transparent 72%);
}

/* ── 06 the residences — the one light panel on the page ─────────────── */
.res{
  min-height:auto; padding:0; display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1fr); align-items:stretch;
  background:var(--night);
}
.res__panel{
  background:var(--cream); color:var(--ink); position:relative; z-index:3;
  display:flex; align-items:center;
  padding:clamp(56px,7.4vw,104px) 0 clamp(56px,7.4vw,104px) var(--pad);
  clip-path:inset(0 0 var(--wipe,100%) 0);     /* wipes UP over the dark */
  transition:clip-path 1.15s cubic-bezier(.22,.9,.24,1);
}
.res.in .res__panel{--wipe:0%}
.res__inner{width:100%; max-width:640px; padding-right:clamp(28px,3.6vw,56px)}
.res__h{
  font-family:var(--display); font-weight:300; margin:0 0 clamp(28px,3.4vw,46px);
  font-size:clamp(32px,3.9vw,56px); line-height:1.06; letter-spacing:-.004em;
}
/* The photograph is portrait, so once it decoded its intrinsic 2:3 pushed the
   grid row from 751px to 1080px — a 329px shift after load, and the reason the
   page briefly could not be scrolled to its own footer. Out of flow it goes. */
.res__photo{position:relative; overflow:clip; min-height:clamp(380px,46vw,620px)}
.res__photo img{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:cover;
  transform:scale(1.1) translate3d(0,var(--my,0),0);
}

.led{width:100%; font-family:var(--ui); font-variant-numeric:tabular-nums}
.led th{
  text-align:left; font-weight:400; font-size:9.5px; letter-spacing:.22em;
  text-transform:uppercase; color:var(--ink-soft);
  padding:0 14px 13px 0; border-bottom:1px solid var(--cream-rule);
}
.led td{
  font-family:var(--display); font-size:clamp(15px,1.32vw,19px); font-weight:400;
  padding:clamp(13px,1.5vw,19px) 14px clamp(13px,1.5vw,19px) 0;
  border-bottom:1px solid rgba(203,197,190,.5); color:var(--ink);
}
.led tbody tr:last-child td{border-bottom:0}
.led td:first-child{color:var(--ink-soft); font-family:var(--ui); font-size:12px; letter-spacing:.1em}
.led th:nth-child(n+4),.led td:nth-child(n+4){width:12%}
/* each row arrives on its own beat, and lights on hover */
.led tbody tr{
  opacity:0; transform:translateY(9px);
  transition:opacity .5s ease, transform .6s cubic-bezier(.22,.9,.24,1), background-color .3s;
}
.res.in .led tbody tr{opacity:1; transform:none}
.res.in .led tbody tr:nth-child(1){transition-delay:.42s}
.res.in .led tbody tr:nth-child(2){transition-delay:.50s}
.res.in .led tbody tr:nth-child(3){transition-delay:.58s}
.res.in .led tbody tr:nth-child(4){transition-delay:.66s}
.res.in .led tbody tr:nth-child(5){transition-delay:.74s}
.led tbody tr:hover td{color:var(--ember)}
@media (max-width:900px){
  .res{grid-template-columns:1fr}
  .res__photo{min-height:56vw; order:-1}
  .res__panel{padding:clamp(48px,9vw,80px) var(--pad)}
  .res__inner{padding-right:0}
}
/* ── the ledger, narrow ────────────────────────────────────────────────
   Six columns cannot hold their meaning at 390px — the place names wrap and
   the headers break mid-word. Each residence becomes two lines instead: who
   and how much, then the specification under it, labelled in place of a
   header row that is no longer there. */
@media (max-width:640px){
  .led thead{display:none}
  .led tbody tr{
    display:grid; grid-template-columns:auto 1fr auto;
    column-gap:14px; row-gap:7px; align-items:baseline;
    padding:clamp(15px,4vw,20px) 0;
    border-bottom:1px solid rgba(203,197,190,.55);
  }
  .led tbody tr:last-child{border-bottom:0}
  .led td{border:0; padding:0}
  /* both rows share the same three columns, and every cell is nowrap — the
     column then sizes to the wider of the two things stacked in it, which is
     what stops "3,024 SQ FT" breaking across three lines. */
  .led td{white-space:nowrap}
  .led td:nth-child(1){grid-area:1/1}
  .led td:nth-child(2){grid-area:1/2; font-size:19px}
  .led td:nth-child(3){grid-area:1/3; text-align:right}
  .led td:nth-child(n+4){
    font-family:var(--ui); font-size:9.5px; font-weight:400;
    letter-spacing:.2em; text-transform:uppercase; color:var(--ink-soft);
  }
  .led td:nth-child(4){grid-area:2/1}
  .led td:nth-child(4)::after{content:" BD"}
  .led td:nth-child(5){grid-area:2/2}
  .led td:nth-child(5)::after{content:" BA"}
  .led td:nth-child(6){grid-area:2/3; text-align:right}
  .led td:nth-child(6)::after{content:" SQ FT"}
}

/* ── 07 night — the last frame answers the first ─────────────────────── */
.night__media::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(100deg, rgba(10,13,20,.66) 0%, rgba(10,13,20,.2) 44%, transparent 70%);
}
.stars{
  position:absolute; inset:0 0 42% 0; z-index:1; pointer-events:none;
  opacity:var(--st,0); transition:opacity 1.6s ease;
  background-image:
    radial-gradient(1.1px 1.1px at 12% 24%, rgba(255,250,240,.9), transparent),
    radial-gradient(1px 1px at 31% 12%, rgba(255,250,240,.75), transparent),
    radial-gradient(1.2px 1.2px at 47% 31%, rgba(255,250,240,.85), transparent),
    radial-gradient(1px 1px at 63% 9%,  rgba(255,250,240,.7), transparent),
    radial-gradient(1.3px 1.3px at 76% 26%, rgba(255,250,240,.9), transparent),
    radial-gradient(1px 1px at 88% 15%, rgba(255,250,240,.7), transparent),
    radial-gradient(1px 1px at 22% 40%, rgba(255,250,240,.55), transparent),
    radial-gradient(1px 1px at 56% 45%, rgba(255,250,240,.5), transparent);
}

/* ── footer ──────────────────────────────────────────────────────────── */
/* The footer used to be a flat mid-brown (#544639) with the invitation's cool
   near-black laid over its top 120px. Warm mid-tone under cool dark is how you
   make mud, and it arrived as a band lighter than the section above it — the
   page got brighter at the exact moment it should have settled. It is now the
   darkest ground on the page, carrying the night's blue into the brand's warmth
   over the full height rather than in a 120px overlay. */
.foot{
  position:relative; z-index:3; color:#E8DFD2;
  background:linear-gradient(180deg,#1B1F27 0%,#191712 42%,#12100D 100%);
  padding:clamp(48px,5.6vw,78px) var(--pad) 0;
}
.foot__top{
  display:flex; align-items:flex-start; justify-content:space-between; gap:36px;
  flex-wrap:wrap; padding-bottom:clamp(34px,4.4vw,58px);
}
.foot__brand{display:flex; align-items:baseline; gap:clamp(14px,2vw,30px); flex-wrap:wrap}
.foot__mark{
  font-family:var(--display); font-size:clamp(15px,1.32vw,19px);
  letter-spacing:.4em; text-indent:.4em; position:relative;
}
.foot__mark::after{      /* where the through-line comes to rest */
  content:""; position:absolute; left:0; right:.4em; bottom:-9px; height:1px;
  background:currentColor; opacity:.55;
  transform:scaleX(var(--sign,0)); transform-origin:left;
  transition:transform 1.1s cubic-bezier(.22,.9,.24,1);
}
.foot__brand em{
  font-family:var(--display); font-style:italic; font-size:13.5px;
  color:rgba(232,223,210,.72);
}
.foot__nav,.foot__soc{display:flex; gap:clamp(16px,2.4vw,36px); flex-wrap:wrap}
.foot__nav a,.foot__soc a{
  font-size:9.5px; letter-spacing:.22em; text-transform:uppercase;
  color:rgba(232,223,210,.8); transition:color .3s;
}
.foot__nav a:hover,.foot__soc a:hover{color:var(--ember)}
.foot__bar{
  display:flex; justify-content:space-between; gap:20px; flex-wrap:wrap;
  border-top:1px solid rgba(232,223,210,.16);
  padding:18px 0 22px; font-size:9.5px; letter-spacing:.16em; text-transform:uppercase;
  color:rgba(232,223,210,.5);
}
.foot__bar a{margin-left:16px}

/* ── reveals ─────────────────────────────────────────────────────────── */
.rv{opacity:0; transform:translateY(16px);
    transition:opacity .7s cubic-bezier(.22,.9,.24,1), transform .8s cubic-bezier(.22,.9,.24,1)}
.rv.in{opacity:1; transform:none}
.d1s{transition-delay:.08s}.d3{transition-delay:.30s}.d4{transition-delay:.42s}.d5{transition-delay:.56s}

@media (max-width:760px){
  .ch__copy,.hero__copy,.plan__copy{max-width:none; justify-self:start; text-align:left}
  .ch__copy--right{justify-self:start; text-align:left}
  .ch__copy--right .lede{margin-left:0}
  .plan__svg{position:relative; right:auto; top:auto; transform:none;
             width:100%; margin-top:34px; order:2}
  .plan{align-content:end}
  .plan__stats{position:relative; left:auto; bottom:auto; margin-top:32px}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important; animation-iteration-count:1 !important;
                       transition-duration:.01ms !important; scroll-behavior:auto !important}
  .rv{opacity:1; transform:none}
  .ch__media img{transform:scale(1.02)}
  .res__panel{clip-path:none}
  .led tbody tr{opacity:1; transform:none}
  .plan__svg .dr{stroke-dashoffset:0}
  .plan__dim text{opacity:1}
  .plan__stats{opacity:1; transform:none}
  .stars{opacity:.8}
  .foot__mark::after{transform:scaleX(1)}
  .tl{clip-path:none}
  .hero__scroll i{animation:none}
}

/* ═══════════════════════════════════════════════════════════════════════
   THE SECOND PASS
   The page was seven photographs with a serif headline in the corner of
   each. What follows is what turns that stack into a document: a light
   beat, materials that are named, a drawing that says which stage it is
   at, an index you can actually move through, and somewhere to land.
   ═══════════════════════════════════════════════════════════════════════ */

/* ── the site datum, under the fold ─────────────────────────────────── */
.datum{
  position:absolute; right:var(--pad); bottom:clamp(28px,4.4vh,54px); z-index:3;
  display:flex; gap:clamp(20px,3vw,52px); margin:0; flex-wrap:wrap;
  justify-content:flex-end; max-width:min(660px,60vw);
  padding-left:26px; border-left:1px solid rgba(243,239,232,.22);
}
.datum div{display:flex; flex-direction:column; gap:5px}
.datum dt{
  font-size:8.5px; letter-spacing:.26em; text-transform:uppercase;
  color:rgba(243,239,232,.58);
}
.datum dd,.datum dt,.key dt,.plan__stats b,.plan__stats .num,.inv__meta dd{
  /* the clock reruns every 15s; tabular figures keep the row from shuffling */
  font-variant-numeric:lining-nums tabular-nums;
  font-feature-settings:"lnum" 1,"tnum" 1;
}
.datum dd{
  margin:0; font-family:var(--display); font-size:clamp(12px,1.05vw,15px);
  letter-spacing:.06em; color:rgba(243,239,232,.9);
  font-variant-numeric:tabular-nums;
}
@media (max-width:860px){ .datum{display:none} }

/* ── 02 the commission: the light beat ──────────────────────────────── */
.comm{
  background:var(--paper); color:var(--ink);
  min-height:auto; padding:clamp(72px,8.4vw,124px) var(--pad) clamp(64px,7vw,104px);
  align-content:start;
}
.comm::before{display:none}
.eyebrow--ink{color:var(--ink-soft)}
.d1--ink{color:var(--ink); text-shadow:none}
/* three columns that collapse to one: lead / body / schedule, with the
   photograph spanning the full measure underneath them */
.comm__grid{
  width:100%; max-width:var(--maxw); margin:0 auto;
  display:grid; gap:clamp(30px,4vw,64px);
  grid-template-columns:minmax(0,1.15fr) minmax(0,1.25fr) minmax(0,.8fr);
  align-items:start;
}
.comm__lead .d1{font-size:clamp(30px,3.5vw,54px); line-height:1.02}
.comm__body p{
  font-family:var(--ui); font-size:clamp(13.5px,1.02vw,15.5px); font-weight:300;
  line-height:1.78; color:#4B4139; margin:0 0 1.15em; max-width:44ch;
}
/* one drop cap, on one paragraph — the monograph tell */
.drop::first-letter{
  float:left; font-family:var(--display); font-weight:300;
  font-size:3.55em; line-height:.82; padding:.06em .14em 0 0; color:var(--ink);
}
.sched{margin:0; display:grid; gap:0; border-top:1px solid var(--cream-rule)}
.sched div{
  display:flex; align-items:baseline; justify-content:space-between; gap:16px;
  padding:11px 0; border-bottom:1px solid rgba(203,197,190,.55);
}
.sched dt{
  font-size:9px; letter-spacing:.22em; text-transform:uppercase; color:var(--ink-soft);
  flex:none;
}
.sched dd{
  margin:0; font-family:var(--display); font-size:clamp(13px,1.1vw,16px);
  text-align:right; color:var(--ink);
}
.comm__fig{grid-column:1 / -1; margin:clamp(20px,3vw,44px) 0 0}
.comm__fig img{width:100%; height:clamp(240px,34vw,440px); object-fit:cover}
.comm__fig figcaption{
  margin-top:12px; font-size:9.5px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ink-soft);
}
.rvs{opacity:0; transform:translateY(24px) scale(.985);
     transition:opacity .9s cubic-bezier(.22,.9,.24,1), transform 1s cubic-bezier(.22,.9,.24,1)}
.rvs.in{opacity:1; transform:none}
@media (max-width:1000px){
  .comm__grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
  .sched{grid-column:1 / -1}
}
@media (max-width:680px){ .comm__grid{grid-template-columns:1fr} }

/* ── the specimen rail on the material frame ────────────────────────── */
.spec{
  position:absolute; left:var(--pad); bottom:clamp(30px,5vh,62px); z-index:3;
  display:flex; gap:clamp(14px,1.8vw,28px); margin:0; padding:0; list-style:none;
}
.spec li{
  display:flex; align-items:center; gap:11px;
  padding:9px 14px 9px 9px; border:1px solid rgba(243,239,232,.22);
  /* the frame behind this rail is direct sun on pale stone — at a third
     opacity the labels were simply not there */
  background:rgba(14,10,7,.66); backdrop-filter:blur(9px);
  transition:border-color .4s ease, background-color .4s ease, transform .5s cubic-bezier(.22,.9,.24,1);
}
.spec li:hover{border-color:rgba(243,239,232,.55); background:rgba(14,10,7,.78);
               transform:translateY(-3px)}
/* each swatch is the same photograph, framed on a different part of it —
   the specimen genuinely is a piece of the wall behind it */
.spec i{
  width:clamp(34px,3.4vw,46px); aspect-ratio:1; flex:none; display:block;
  /* magnified 4.2x, so it wants the cleanest source there is */
  background:url('img/material@2x.webp') var(--ox) var(--oy) / 420% 420% no-repeat;
}
.spec b{
  font-family:var(--ui); font-size:9px; font-weight:400; letter-spacing:.2em;
  color:rgba(243,239,232,.5); align-self:flex-start; padding-top:2px;
}
.spec span{display:flex; flex-direction:column; gap:3px;
           font-family:var(--display); font-size:clamp(12px,1.05vw,15px)}
.spec s{
  text-decoration:none; font-family:var(--ui); font-size:8.5px; color:rgba(243,239,232,.72);
  letter-spacing:.16em; text-transform:uppercase; color:rgba(243,239,232,.56);
  white-space:nowrap;
}
@media (max-width:900px){ .spec{display:none} }

/* ── roof annotation ───────────────────────────────────────────────────
   Leader lines drawn at a fixed angle pointed at whatever happened to be
   there, which on this photograph was sky. A numbered anchor sits on the
   thing itself and the key reads them off in the corner — how the practice
   would annotate the drawing anyway. */
/* The callouts are controls, not decoration: pointing at the photograph is
   the natural thing to try, so it has to answer. Each one lights its own line
   in the key. A 23px dot is under the 44px touch minimum, so the hit area is
   grown with a pseudo-element rather than by drawing a bigger circle. */
.notes{position:absolute; inset:0; z-index:3; pointer-events:none}
.note{
  position:absolute; left:var(--x); top:var(--y);
  transform:translate(-50%,-50%) scale(var(--ns,1));
  width:23px; height:23px; border-radius:50%; padding:0;
  display:grid; place-items:center; pointer-events:auto; cursor:pointer;
  font-family:var(--ui); font-weight:400; font-size:9px; letter-spacing:.06em;
  color:#F3EFE8; border:1px solid rgba(243,239,232,.62);
  background:rgba(14,12,10,.34); backdrop-filter:blur(3px);
  -webkit-tap-highlight-color:transparent;
  opacity:0; transition:opacity .8s cubic-bezier(.22,.9,.24,1) var(--d,0s),
             transform .4s cubic-bezier(.22,1,.36,1),
             background .35s ease, border-color .35s ease, box-shadow .35s ease;
}
.note::after{content:""; position:absolute; inset:-12px; border-radius:50%}
.note:hover,.note:focus-visible{--ns:1.22;
  background:rgba(200,122,60,.5); border-color:rgba(243,239,232,.95);
  box-shadow:0 0 0 4px rgba(200,122,60,.16)}
.note:focus-visible{outline:2px solid #F3EFE8; outline-offset:3px}
.note[aria-current="true"]{--ns:1.22;
  background:var(--ember,rgba(200,122,60,.72)); border-color:rgba(243,239,232,.95);
  box-shadow:0 0 0 4px rgba(200,122,60,.2)}
/* the paired line in the key answers back */
.key div{transition:opacity .5s ease, transform .5s cubic-bezier(.22,1,.36,1),
                    border-color .35s ease}
.key div[aria-current="true"] dd{color:#fff}
.key div[aria-current="true"] dt{color:var(--ember,rgba(200,122,60,.95))}
@media (hover:none){ .note::after{inset:-14px} }
@media (prefers-reduced-motion:reduce){ .note{transition:opacity .01s} }
.roof.in .note{opacity:1}
.note:nth-child(2){--d:.16s} .note:nth-child(3){--d:.32s}
.key{
  position:absolute; right:var(--pad); bottom:clamp(30px,5vh,62px); margin:0;
  padding:14px 18px; border-left:1px solid rgba(243,239,232,.28);
  opacity:0; transform:translateY(10px);
  transition:opacity .9s cubic-bezier(.22,.9,.24,1) .44s,
             transform 1s cubic-bezier(.22,.9,.24,1) .44s;
}
.roof.in .key{opacity:1; transform:none}
.key div{display:flex; gap:14px; align-items:baseline; padding:4px 0}
.key dt{
  font-size:8.5px; letter-spacing:.2em; color:rgba(243,239,232,.5); flex:none;
}
.key dd{
  margin:0; font-family:var(--display); font-size:clamp(12px,1.05vw,15px);
  color:rgba(243,239,232,.94); text-shadow:0 1px 10px rgba(12,14,20,.85);
  white-space:nowrap;
}
@media (max-width:900px){ .notes{display:none} }

/* ── the drawing's stage readout ─────────────────────────────────────── */
.stage{
  position:absolute; right:var(--pad); top:clamp(112px,15vh,168px); z-index:4;
  display:flex; flex-direction:column; align-items:flex-end; gap:12px;
  opacity:var(--stg,0); transition:opacity .6s ease;
}
.stage__list{list-style:none; margin:0; padding:0; display:flex; gap:clamp(12px,1.5vw,22px)}
.stage__list li{
  font-size:9px; letter-spacing:.24em; text-transform:uppercase;
  color:rgba(243,239,232,.36); transition:color .45s ease;
}
.stage__list li.on{color:rgba(243,239,232,.95)}

@media (max-width:900px){ .stage{display:none} }

/* ── 06 the index ────────────────────────────────────────────────────── */
.idx{list-style:none; margin:0 0 clamp(26px,3vw,40px); padding:0;
     border-top:1px solid var(--cream-rule)}
.idx__row{
  display:grid; grid-template-columns:auto 1fr auto; align-items:baseline;
  gap:clamp(14px,2vw,28px);
  padding:clamp(13px,1.7vw,22px) 0;
  border-bottom:1px solid rgba(203,197,190,.55);
  cursor:pointer; position:relative;
  opacity:0; transform:translateY(9px);
  transition:opacity .5s ease, transform .6s cubic-bezier(.22,.9,.24,1),
             padding-left .5s cubic-bezier(.22,.9,.24,1);
}
.res.in .idx__row{opacity:1; transform:none}
.res.in .idx__row:nth-child(1){transition-delay:.40s}
.res.in .idx__row:nth-child(2){transition-delay:.48s}
.res.in .idx__row:nth-child(3){transition-delay:.56s}
.res.in .idx__row:nth-child(4){transition-delay:.64s}
.res.in .idx__row:nth-child(5){transition-delay:.72s}
.idx__row b{
  font-family:var(--ui); font-weight:400; font-size:10.5px; letter-spacing:.2em;
  color:var(--ink-soft); transition:color .4s ease;
}
.idx__n{
  font-family:var(--display); font-weight:300;
  font-size:clamp(24px,2.9vw,42px); line-height:1.02; color:var(--ink);
  transition:color .4s ease;
}
.idx__row s{
  text-decoration:none; font-family:var(--display); font-size:clamp(12px,1.05vw,15px);
  letter-spacing:.08em; color:var(--ink-soft); font-variant-numeric:tabular-nums;
  transition:color .4s ease;
}
.idx__row.is-on s{color:var(--ember)}
/* a rule that runs out from the left as the row takes over, so the pointer's
   position is legible without a fill or a box appearing */
.idx__row::before{
  content:""; position:absolute; left:0; top:50%; width:clamp(14px,2vw,26px); height:1px;
  background:var(--ember); transform:scaleX(0); transform-origin:left;
  transition:transform .5s cubic-bezier(.22,.9,.24,1);
}
.idx__row.is-on{padding-left:clamp(24px,3.2vw,42px)}
.idx__row.is-on::before{transform:scaleX(1)}
.idx__row.is-on .idx__n{color:var(--ember)}
.idx__row.is-on b{color:var(--ember)}
.idx__row:focus-visible{outline:1px solid var(--ember); outline-offset:5px}

.res__photo img{transition:opacity .85s cubic-bezier(.22,.9,.24,1)}
.res__b{opacity:0}
.res__photo img.is-on{opacity:1}
.res__photo img:not(.is-on){opacity:0}
/* the record for whichever residence is up, over the bottom of the frame */
.res__card{
  position:absolute; left:0; right:0; bottom:0; z-index:2;
  padding:clamp(22px,3vw,40px) clamp(20px,2.6vw,38px);
  background:linear-gradient(0deg, rgba(10,10,13,.86), rgba(10,10,13,.45) 55%, transparent);
  color:#F3EFE8; display:flex; align-items:baseline; gap:clamp(14px,2vw,30px);
  flex-wrap:wrap;
}
.res__yr{margin:0; font-size:9px; letter-spacing:.24em; color:rgba(243,239,232,.6)}
.res__pr{margin:0; font-family:var(--display); font-size:clamp(20px,2.2vw,32px); font-weight:300}
.res__sp{margin:0 0 0 auto; font-size:9.5px; letter-spacing:.16em;
         text-transform:uppercase; color:rgba(243,239,232,.72)}
@media (max-width:900px){
  .res__card{position:relative; background:rgba(10,10,13,.8)}
}

/* ── 07 night, louder ────────────────────────────────────────────────── */
.night__h{font-size:clamp(44px,7.4vw,124px); line-height:.96; letter-spacing:-.018em}

/* ── 08 the invitation ───────────────────────────────────────────────── */
.inv{
  background:#1B1F27; min-height:auto;
  padding:clamp(86px,11vw,168px) var(--pad);
  align-content:center; justify-items:center; text-align:center;
}
.inv__in{max-width:min(900px,100%); display:flex; flex-direction:column; align-items:center}
.inv__h{font-size:clamp(38px,6.2vw,104px); line-height:.98; letter-spacing:-.018em}
.inv .lede{margin-left:auto; margin-right:auto; text-align:center; max-width:48ch}
.inv__mail{
  font-family:var(--display); font-weight:300;
  font-size:clamp(20px,2.5vw,38px); letter-spacing:-.005em;
  margin-top:clamp(26px,3.4vw,46px); padding-bottom:8px; position:relative;
  color:#F3EFE8;
}
.inv__mail::after{
  content:""; position:absolute; left:0; right:0; bottom:0; height:1px;
  background:var(--ember); transform:scaleX(0); transform-origin:right;
  transition:transform .55s cubic-bezier(.22,.9,.24,1);
}
.inv__mail:hover::after{transform:scaleX(1); transform-origin:left}
.inv__meta{
  margin:clamp(40px,5vw,74px) 0 0; display:flex; gap:clamp(26px,4.6vw,74px);
  flex-wrap:wrap; justify-content:center; text-align:left;
}
.inv__meta dt{
  font-size:8.5px; letter-spacing:.26em; text-transform:uppercase;
  color:rgba(243,239,232,.45); margin-bottom:7px;
}
.inv__meta dd{
  margin:0; font-family:var(--display); font-size:clamp(13px,1.15vw,16.5px);
  line-height:1.5; color:rgba(243,239,232,.92);
}

@media (prefers-reduced-motion:reduce){
  .idx__row,.note,.rvs{opacity:1 !important; transform:none !important}
  .stage{opacity:1}
}

/* ═══════════════════════════════════════════════════════════════════════
   THE THIRD PASS — atmosphere, and type that survives a photograph
   ═══════════════════════════════════════════════════════════════════════ */

/* ── legibility ────────────────────────────────────────────────────────
   Light type over a photograph is only as readable as its darkest patch,
   and a desert frame has no dark patches to spare. A shadow in the frame's
   own shadow colour costs nothing on the dark half and rescues the rest —
   a scrim big enough to do the same job would flatten the picture. */
.lede,.eyebrow,.cta,.datum dd,.datum dt,.hero__scroll,.key dd,.key dt,
.plan__stats b,.plan__stats span,.stage__list li,.inv__mail,.inv__meta dd,.inv__meta dt{
  text-shadow:0 1px 3px rgba(12,8,4,.62), 0 0 18px rgba(12,8,4,.5),
              0 0 46px rgba(12,8,4,.34);
}
/* The display face gets a drop-shadow on the heading rather than a text-shadow
   on the text. Split text lives in per-word masks with overflow:hidden — a
   text-shadow is clipped at each word's box and paints as a row of grey
   rectangles. A filter is applied to the heading after its children are
   clipped, so the shadow follows the letterforms and nothing else. */
.d1{filter:drop-shadow(0 1px 3px rgba(12,8,4,.55))
           drop-shadow(0 0 24px rgba(12,8,4,.45));}
/* …except on the two light chapters, where there is nothing to protect */
.comm .d1,.comm .lede,.comm .eyebrow,.comm .cta,
.res .res__h,.res .eyebrow,.res .cta,.idx__row *{text-shadow:none}
.comm .d1{filter:none}
.eyebrow{color:rgba(243,239,232,.86)}
.lede{color:rgba(243,239,232,.92); font-size:clamp(14px,1.12vw,17px)}
.cta{font-size:11px; letter-spacing:.22em}
.hero__scroll{color:rgba(243,239,232,.86)}

/* the datum sat on scrub with nothing behind it — it gets a ground of its own */
.datum{
  background:linear-gradient(90deg, rgba(12,9,5,.30), rgba(12,9,5,.72) 22%, rgba(12,9,5,.80));
  backdrop-filter:blur(9px) saturate(1.05);
  -webkit-backdrop-filter:blur(9px) saturate(1.05);
  padding:14px 18px 14px 26px; border-left:1px solid rgba(243,239,232,.42);
}
/* The values were a light display serif at 12px on a photograph — the ground
   helped, but the type itself was the problem: too small, too fine, too little
   letter-spacing to survive at that size. */
.datum dt{color:rgba(243,239,232,.82); font-weight:500}
.datum dd{
  color:#FBF8F2; font-size:clamp(14px,1.24vw,18px);
  letter-spacing:.045em;
  text-shadow:0 1px 3px rgba(8,6,4,.75);
}
.key{background:rgba(14,12,10,.42); backdrop-filter:blur(6px)}

/* ── the atmosphere layer ───────────────────────────────────────────── */
.atmos{position:fixed; inset:0; z-index:60; pointer-events:none}
.atmos i{position:absolute; inset:0; display:block}
/* grain, drawn once as an SVG turbulence and nudged so it never sits still —
   a static grain reads as a dirty screen, a moving one reads as film */
.atmos__grain{
  /* The animation below shifts this layer by up to 3% of the viewport. At
     inset:0 that walks its own edge into frame four times a second, and the
     strip with no grain on it reads as a shadow pulsing down the left and
     right sides. Oversize it so there is always grain past the edge.
     Written against .atmos because `.atmos i{inset:0}` above is a class plus a
     type selector and would otherwise outrank a bare class here. */
  opacity:.055; mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 1.1s steps(4) infinite;
}
.atmos .atmos__grain{inset:-8%}
@keyframes grain{
  0%{transform:translate3d(0,0,0)}   25%{transform:translate3d(-3%,2%,0)}
  50%{transform:translate3d(2%,-3%,0)} 75%{transform:translate3d(-2%,-2%,0)}
  100%{transform:translate3d(0,0,0)}
}
/* the vignette closes in as the day does */
.atmos__vig{
  background:radial-gradient(120% 88% at 50% 46%, transparent 42%,
             rgba(8,6,4,var(--vigA,.30)) 100%);
  transition:opacity 1.2s ease;
}
:root[data-chapter="commission"] .atmos__vig,
:root[data-chapter="residences"] .atmos__vig{opacity:.25}
:root[data-chapter="night"] .atmos__vig{--vigA:.62}
:root[data-chapter="inquire"] .atmos__vig{--vigA:.5}

/* ── motion under speed ────────────────────────────────────────────────
   story.js publishes the smoothed scroll velocity; the media leans into it
   a little, which is the difference between a page that scrolls and a page
   that has weight. */
.ch__media img{
  transform:scale(var(--z,1.08))
            translate3d(var(--mx,0), calc(var(--my,0px) + var(--velAbs,0) * -6px), 0)
            skewY(calc(var(--vel,0) * .28deg));
}
/* the specimen chips and the annotation key arrive in sequence */
.spec li{opacity:0; transform:translateY(14px);
         transition:opacity .7s cubic-bezier(.22,.9,.24,1) var(--d,0s),
                    transform .8s cubic-bezier(.22,.9,.24,1) var(--d,0s),
                    border-color .4s ease, background-color .4s ease}
.mat.in .spec li{opacity:1; transform:none}
.spec li:nth-child(2){--d:.12s} .spec li:nth-child(3){--d:.24s}
.spec li:hover i{transform:scale(1.08)}
.spec i{transition:transform .6s cubic-bezier(.22,.9,.24,1)}
.key div{opacity:0; transform:translateX(10px);
         transition:opacity .6s ease var(--d,0s), transform .7s cubic-bezier(.22,.9,.24,1) var(--d,0s)}
.roof.in .key div{opacity:1; transform:none}
.key div:nth-child(2){--d:.1s} .key div:nth-child(3){--d:.2s}
.sched div{opacity:0; transform:translateY(10px);
           transition:opacity .55s ease var(--d,0s), transform .65s cubic-bezier(.22,.9,.24,1) var(--d,0s)}
.comm.in .sched div{opacity:1; transform:none}
.sched div:nth-child(1){--d:.05s} .sched div:nth-child(2){--d:.11s}
.sched div:nth-child(3){--d:.17s} .sched div:nth-child(4){--d:.23s}
.sched div:nth-child(5){--d:.29s} .sched div:nth-child(6){--d:.35s}
/* the index photograph pushes in as it cross-fades, so the swap has depth */
.res__photo img.is-on{animation:pushin 7s cubic-bezier(.2,.6,.3,1) forwards}
@keyframes pushin{from{transform:scale(1.10) translate3d(0,var(--my,0),0)}
                  to{transform:scale(1.17) translate3d(0,var(--my,0),0)}}
/* the stars drift, very slowly, the way they actually do */
.stars{animation:wheel 210s linear infinite}
@keyframes wheel{from{background-position:0 0}to{background-position:-160px 26px}}
/* the hero's headline words rise out of their own mask */
.hero .sp-word,.mat .sp-word,.night .sp-word,.inv .sp-word{transition-duration:1.1s}

@media (prefers-reduced-motion:reduce){
  .atmos__grain,.stars,.res__photo img.is-on{animation:none}
  .ch__media img{transform:scale(1.04)}
  .spec li,.key div,.sched div{opacity:1 !important; transform:none !important}
}

