*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
:root{
  --white:#fff;--black:#0a0a0a;--grey:#767676;--light:#f5f5f5;
  --serif:'Instrument Serif',serif;
  --sans:'Poppins',sans-serif;
  --nav-h:64px;
  --ease-out-expo:cubic-bezier(0.16,1,0.3,1);
}
html{font-size:16px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}
html.lenis,html.lenis body{height:auto}
.lenis.lenis-smooth{scroll-behavior:auto}
body{font-family:var(--sans);color:var(--black);background:#fff;overflow-x:hidden}

/* ACCESSIBILITY — skip link + keyboard focus ring (index loads styles.css,
   not shared.css, so these are defined locally to match the rest of the site) */
.skip-link{position:absolute;top:-100%;left:16px;z-index:10000;padding:12px 24px;background:var(--black);color:var(--white);font-family:var(--sans);font-size:.85rem;text-decoration:none;border-radius:0 0 6px 6px;transition:top .3s}
.skip-link:focus{top:0}
a:focus-visible,button:focus-visible{outline:2px solid currentColor;outline-offset:4px}

/* PRELOADER — black; the icon logo's flowing contour lines rise into the
   arch window as assets load (clip-path driven by real progress), then a
   white fill floods the arch and it scales up to BECOME the white page.
   The arch box ratio matches the icon's viewBox (115.06 x 146.45). */
#preloader{position:fixed;inset:0;background:#0a0a0a;z-index:1000;display:flex;align-items:center;justify-content:center}
.pre-stack{display:flex;flex-direction:column;align-items:center;gap:40px}
.pre-arch-svg{width:120px;height:155px}
.pre-arch-svg svg{width:100%;height:100%;overflow:visible}
.cl{fill:none;stroke:rgba(255,255,255,0.85);stroke-width:0.8;stroke-linecap:round;stroke-linejoin:round}
.pre-wordmark{width:min(240px,58vw);display:block;opacity:0;transform:translateY(12px)}
@media(max-width:768px){.pre-arch-svg{width:100px;height:130px}.pre-wordmark{width:min(200px,65vw)}}

/* FILM GRAIN OVERLAY — subtle animated texture over everything */
#grain-overlay{position:fixed;inset:-50px;z-index:300;pointer-events:none;opacity:.032;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");background-size:160px;animation:grainShift .9s steps(2) infinite}
@keyframes grainShift{0%{transform:translate(0,0)}50%{transform:translate(-32px,18px)}100%{transform:translate(18px,-26px)}}
@media(prefers-reduced-motion:reduce){#grain-overlay{animation:none}}

/* CUSTOM CURSOR — see cursor.css, loaded ahead of this sheet. */

/* NAV */
#nav{position:fixed;top:0;left:0;width:100%;display:flex;align-items:center;justify-content:space-between;padding:0 48px;height:var(--nav-h);z-index:200;transition:mix-blend-mode .3s}
#nav-logo{display:flex;align-items:center}
#nav-logo img{height:32px;filter:brightness(0);transition:filter .4s}
#nav-links{display:flex;gap:36px}
#nav-links{align-items:center}
#nav-links a{color:var(--black);text-decoration:none;font-size:.75rem;font-weight:400;letter-spacing:.1em;text-transform:uppercase;opacity:.5;transition:opacity .3s}
#nav-links a:hover{opacity:1}


/* MOBILE MENU */
#menu-btn{display:none;flex-direction:column;justify-content:center;gap:6px;background:none;border:0;padding:10px 0 10px 10px}
#menu-btn span{display:block;width:24px;height:1.5px;background:var(--black);transition:transform .4s var(--ease-out-expo),background .3s}
#menu-btn.open span:first-child{transform:translateY(3.75px) rotate(45deg);background:#fff}
#menu-btn.open span:last-child{transform:translateY(-3.75px) rotate(-45deg);background:#fff}
#menu-overlay{position:fixed;inset:0;background:#0a0a0a;z-index:195;display:flex;flex-direction:column;justify-content:center;padding:0 36px;clip-path:inset(0 0 100% 0);visibility:hidden}
#menu-overlay nav{display:flex;flex-direction:column;gap:8px}
#menu-overlay a{font-family:var(--serif);font-size:clamp(2.2rem,9vw,3.4rem);color:#fff;text-decoration:none;line-height:1.3;opacity:0}
#menu-overlay .menu-foot{position:absolute;bottom:34px;left:36px;font-size:.62rem;letter-spacing:.24em;text-transform:uppercase;color:rgba(255,255,255,.4)}

/* EXPERIENCE */
#experience{position:relative;width:100%;height:380vh;background:#fff}
#world{position:sticky;top:0;width:100%;height:100vh;height:100svh;overflow:hidden}
/* ══ THE GHOST ══
   One word, cut into the sheet as an outline rather than printed on it.
   It is the subject of the whole journey — it drifts behind the title,
   steps back while the work is being looked at, and returns at the end
   under the closing line, whose last word is that same word. Written by
   the ticker: --gh-o opacity, --gh-x drift, --gh-s scale. */
#ghost{
  --gh-o:0; --gh-x:0px; --gh-s:1;
  /* Above the sheet's white fill (z1) — at z0 it would be painted over and
     never seen — and below the type (z3), which is the whole point of it. */
  position:absolute;left:50%;top:50%;z-index:2;
  transform:translate(-50%,-50%) translateX(var(--gh-x)) scale(var(--gh-s));
  font-family:var(--serif);font-size:clamp(9rem,27vw,26rem);line-height:.8;
  letter-spacing:-.02em;white-space:nowrap;pointer-events:none;user-select:none;
  color:transparent;-webkit-text-stroke:1px rgba(10,10,10,.09);
  opacity:var(--gh-o);will-change:transform,opacity;
}
/* Where text-stroke is unavailable the outline would fall back to a solid
   black slab across the hero. A faint fill is the honest substitute. */
@supports not (-webkit-text-stroke:1px red){
  #ghost{color:rgba(10,10,10,.05);-webkit-text-stroke:0}
}
/* ══ THE DRAWING SHEET ══
   A white sheet with construction lines running edge to edge. One plate
   holds the work and reproportions itself for each project; the rules
   re-measure around it. --pw/--ph/--sheet/--plate-o are written by the
   ticker. Pure DOM/CSS — identical on every device. */
#stage{
  --pw:0px; --ph:0px; --cx:0px; --cy:0px; --sheet:0; --plate-o:0; --datum:0; --dx:0px;
  --plate-sh:0;
  position:absolute;inset:0;z-index:1;background:#fff;
}
/* the word the closing statement takes the image back into */
/* THE DATUM — one line runs the whole story. In the hero both horizontal
   rules sit at the centre, coincident: a single line the title is set on.
   As the journey begins they separate into the top and bottom edges of the
   plate (the verticals sweep in to close the frame), and at the end they
   converge back into one line and shrink into the rule beneath the closing
   statement. Same two elements throughout — the transitions ARE the story. */
.rule{position:absolute;background:rgba(10,10,10,.16);pointer-events:none}
.rule-top,.rule-bot{left:var(--dx);right:var(--dx);height:1px;opacity:var(--datum)}
.rule-left,.rule-right{top:0;bottom:0;width:1px;opacity:var(--sheet)}
.rule-top{top:calc(50% - var(--ph) / 2)}
.rule-bot{top:calc(50% + var(--ph) / 2)}
.rule-left{left:calc(50% - var(--pw) / 2)}
.rule-right{left:calc(50% + var(--pw) / 2)}

/* The plate inherits the pile's shadow while it is still sitting in the
   deck's box, and sheds it as it grows to centre stage — a drawing lifted
   off the table and then flattened onto the sheet. */
#plate-card{position:absolute;left:calc(50% + var(--cx));top:calc(50% + var(--cy));
  transform:translate3d(0,0,0);will-change:transform,left,top,width,height;
  margin-left:calc(var(--pw) / -2);margin-top:calc(var(--ph) / -2);
  width:var(--pw);height:var(--ph);opacity:var(--plate-o);
  box-shadow:0 20px 46px rgba(10,10,10,var(--plate-sh))}
.plate{position:absolute;inset:0;overflow:hidden;background:#f2f2f2}
.plate-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
  opacity:0;will-change:transform,opacity;
  transition:opacity 1s var(--ease-out-expo),transform 1.6s var(--ease-out-expo)}
.plate-label{position:absolute;left:0;top:calc(100% + 18px);display:flex;align-items:baseline;gap:18px;
  white-space:nowrap;opacity:var(--sheet)}
#plate-num{font-size:.62rem;letter-spacing:.24em;color:var(--grey);font-variant-numeric:tabular-nums}
#plate-name{font-family:var(--serif);font-size:clamp(1.1rem,2vw,1.7rem)}
#plate-meta{font-size:.6rem;letter-spacing:.22em;text-transform:uppercase;color:var(--grey)}
@media(max-width:768px){
  .plate-label{gap:10px;flex-wrap:wrap;white-space:normal;top:calc(100% + 12px)}
  #plate-meta{width:100%}
}

/* HERO — the sheet's title block: pure typography on blank paper. No image
   sits behind it (the plate is ruled in only after this leaves), so the
   type is always on clean white and always readable. */
/* ══ HERO — IMAGES LIVE INSIDE WORDS ══
   The key nouns are apertures: the letterforms are cut out of the ink and
   the studio's work shows through them, drifting slowly. Editorial and
   left-anchored — the asymmetry is what keeps it from reading as a stock
   centred title card. */
/* A GRID, not stacked absolute boxes. The text column and the image column
   are separate tracks, so they cannot overlap at any width — that was the
   cause of the index landing on top of the headline. */
#hero{position:absolute;inset:0;z-index:3;pointer-events:none;
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,auto);
  align-items:center;column-gap:clamp(28px,5vw,80px);
  padding:calc(var(--nav-h) + 3vh) clamp(22px,5vw,90px) 13vh}
#hero-row{position:relative;min-width:0;text-align:left;padding:0}
#hero-eyebrow{display:block;font-size:.62rem;font-weight:500;letter-spacing:.34em;text-transform:uppercase;color:var(--grey);margin-bottom:clamp(20px,3.4vh,40px)}
/* the title never runs under the index — on wide screens the type takes
   the left field and the index the right, with a real gutter between */
@media(min-width:1181px){#hero-sub{max-width:34ch}}
/* tablet: without this the closing statement broke to four lines, because
   13em of type no longer fits the narrower field */
@media(min-width:769px) and (max-width:1180px){
  .arrival-heading{font-size:clamp(2rem,4.5vw,3.2rem);max-width:min(680px,90vw)}
}
#hero-title{font-family:var(--serif);font-weight:400;font-size:clamp(2.9rem,9.6vw,9rem);letter-spacing:-.015em;line-height:.96;color:var(--black);max-width:11em}
#hero-title .hl{display:block;will-change:transform,opacity,filter}
#hero-title .hl:nth-child(2){padding-left:clamp(0px,7vw,150px)}   /* stepped, not stacked */
#hero-title .hl:nth-child(3){padding-left:clamp(0px,3vw,64px)}
/* the aperture: ink replaced by the work itself */
.hw{
  position:relative;display:inline-block;font-style:italic;
  background-image:var(--src);background-size:150% auto;background-position:20% 42%;
  -webkit-background-clip:text;background-clip:text;color:transparent;
  animation:hwDrift 26s ease-in-out infinite alternate;will-change:background-position;
}
@keyframes hwDrift{from{background-position:18% 38%}to{background-position:74% 62%}}
@supports not ((-webkit-background-clip:text) or (background-clip:text)){
  .hw{color:var(--black);background:none}
}
@media(prefers-reduced-motion:reduce){.hw{animation:none}}
#hero-sub{display:block;margin-top:clamp(24px,4vh,46px);max-width:34ch;font-size:.84rem;font-weight:300;line-height:1.85;color:var(--grey)}

/* HERO INDEX — the right half was dead space on wide screens. It now
   carries the studio's index: quiet, informative, and it balances the
   left-anchored title instead of leaving a void beside it. */
/* ══ THE DECK ══
   Four plates held as a squared-up pile, each one a paper cut: the print
   is masked to nothing and opened from the bottom edge, the way a sheet
   is drawn out of a folder. The pile deals itself while you are reading
   the title — the front plate slides off, drops to the back, the next
   steps forward — and the moment the journey starts it squares up and
   hands its top plate to the sheet. So the deck is not an ornament
   beside the headline: it is the first frame of the works sequence, and
   #plate-home is the box the plate grows out of, laid exactly over it. */
#deck{
  --deck-w:clamp(200px, min(22vw, 34svh), 320px);
  --deck-h:calc(var(--deck-w) * 1.38);
  position:relative;justify-self:end;align-self:center;
  width:var(--deck-w);pointer-events:none;
  opacity:var(--deck-o,1);will-change:opacity;
}
#deck-cards{list-style:none;position:relative;margin:0;padding:0;height:var(--deck-h)}
.dk-card{position:absolute;inset:0;transform-origin:50% 100%;will-change:transform,opacity}
/* the cut itself — the mask that opens, not the image inside it */
.dk-cut{
  display:block;position:absolute;inset:0;overflow:hidden;border-radius:3px;
  background:#efefef;
  box-shadow:0 20px 46px rgba(10,10,10,.16), 0 1px 0 rgba(10,10,10,.07);
  clip-path:inset(0 0 100% 0);will-change:clip-path;
}
.dk-card img{width:100%;height:100%;object-fit:cover;display:block}
/* No JS, no GSAP: html.hero-ready never arrives, so nothing is masked and
   the pile is the hand-made fan below — four photographs, plainly stacked. */
html:not(.hero-ready) .dk-cut{clip-path:none}
.dk-card:nth-child(1){transform:translate(0,0) rotate(0deg);z-index:4}
.dk-card:nth-child(2){transform:translate(7px,9px) rotate(1.5deg);z-index:3}
.dk-card:nth-child(3){transform:translate(14px,18px) rotate(3deg);z-index:2}
.dk-card:nth-child(4){transform:translate(21px,27px) rotate(4.5deg);z-index:1}
/* the box the sheet's plate is interpolated out of — the front card exactly */
#plate-home{position:absolute;left:0;top:0;width:100%;height:var(--deck-h);
  pointer-events:none;visibility:hidden}
#deck-count{display:flex;align-items:baseline;gap:4px;margin:14px 0 0;
  font-size:.58rem;letter-spacing:.2em;text-transform:uppercase;color:var(--grey)}
#deck-count b{font-family:var(--serif);font-weight:400;font-size:.95rem;letter-spacing:0;color:var(--black)}
#deck-count i{font-style:normal;letter-spacing:0;margin-right:.6em}

/* ── The deck is present at EVERY size; it just changes place. ──
   desktop : right field, beside the title
   tablet  : centred beneath the title
   phone   : smaller, still centred                                     */
@media(max-width:1180px){
  /* one column: title, then the pile beneath it */
  #hero{grid-template-columns:minmax(0,1fr);align-content:center;row-gap:clamp(18px,3vh,30px)}
  #deck{justify-self:center;--deck-w:clamp(180px, min(38vw, 26svh), 250px)}
  #deck-count{justify-content:center}
}
@media(max-width:768px){
  #deck{--deck-w:clamp(150px, min(46vw, 24svh), 210px)}
  #deck-count{margin-top:10px}
}
/* Scroll hint — bottom of the sheet; letters wave, a line travels down */
#scroll-hint{position:absolute;bottom:42px;left:50%;transform:translateX(-50%);display:flex;flex-direction:column;align-items:center;gap:12px;font-size:.6rem;letter-spacing:.28em;text-transform:uppercase;color:var(--black);white-space:nowrap;pointer-events:none;z-index:4}
.sh-text span{display:inline-block;will-change:transform}
.sh-line{position:relative;width:1px;height:30px;background:rgba(10,10,10,.14);overflow:hidden}
.sh-line::after{content:'';position:absolute;top:0;left:0;width:100%;height:40%;background:var(--black);animation:shTravel 1.7s ease-in-out infinite}
@keyframes shTravel{0%{transform:translateY(-110%)}60%,100%{transform:translateY(260%)}}
@media(prefers-reduced-motion:reduce){.sh-line::after{animation:none}}

/* SITE — transparent, scrolls on top of the 3D scene as it turns white */
/* The destination text lives INSIDE the pinned world (#arrival); the site
   follows right behind it with a small overlap */
/* NOTE: perspective must NOT live on #site. A perspective/transform on an
   ancestor makes it the containing block for position:fixed descendants,
   which breaks ScrollTrigger's pinning — that was the Featured Projects
   bug. Each arced section carries its own perspective in its transform
   instead, so the pinned section has no transformed ancestor. */
#site{position:relative;z-index:10;color:var(--black);background:transparent;margin-top:-8vh;padding-top:0}
/* Each section rides an arc: it arrives tilted from below, passes flat
   through the centre, and leaves tilted the opposite way — so the page
   reads as a surface curving past the viewer rather than sliding. */
.arc{transform-style:preserve-3d;will-change:transform,opacity,filter;backface-visibility:hidden}
@media(prefers-reduced-motion:reduce){.arc{transform:none!important;filter:none!important;opacity:1!important}}

/* ARRIVAL — the journey's destination, pinned inside the sticky world.
   Words condense out of 3D depth exactly as the last images release;
   driven frame-by-frame from the experience progress in animate(). */
/* The statement rests ABOVE the datum, so the line it settles onto reads
   as its rule — the same line that carried the title. */
/* Centred in the viewport — anchoring it above the middle left a dead
   white field below the statement once the plate was gone. */
#arrival{position:absolute;inset:0;z-index:3;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:0 clamp(22px,5vw,90px)}
.s-eyebrow{display:inline-block;font-size:.62rem;font-weight:500;letter-spacing:.28em;text-transform:uppercase;color:var(--grey);margin-bottom:28px;opacity:0}
/* Measure is set in em, not px/ch, so the wrap (two lines) stays identical
   at every viewport instead of drifting to three as the type scales. */
.arrival-heading{font-family:var(--serif);font-weight:400;font-size:clamp(2rem,3.8vw,3.6rem);max-width:700px;line-height:1.15;color:var(--black);perspective:1100px;margin:0 auto}
.arrival-heading .aword{display:inline-block;opacity:0;will-change:transform,opacity,filter}
#arrival .s-eyebrow{order:-1;margin-bottom:24px}
.statement-rule{width:80px;height:1px;background:rgba(0,0,0,.18);margin:36px auto 0;opacity:0;transform-origin:center}

/* SPLIT — symmetric two-column, mirrored variant */
.split{display:grid;grid-template-columns:1fr 1fr;gap:clamp(40px,6vw,96px);align-items:center}
.split-reverse .split-media{order:1}
.split-reverse .split-text{order:2}
.split-text .s-heading{margin-bottom:24px}
.split-media{position:relative;margin:0}
.split-media img{width:100%;aspect-ratio:4/5;object-fit:cover;display:block;border-radius:6px}
.split-media figcaption{margin-top:14px;font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--grey)}

/* FEATURE LIST */
.feature-list{list-style:none;margin-top:36px;border-top:1px solid rgba(0,0,0,.08)}
.feature-list li{display:flex;align-items:center;gap:16px;padding:14px 0;border-bottom:1px solid rgba(0,0,0,.08);font-size:.86rem;font-weight:300;color:var(--black);transition:padding-left .4s var(--ease-out-expo),color .3s}
.feature-list li span{font-size:.62rem;letter-spacing:.12em;color:var(--grey);min-width:20px}
.feature-list li:hover{padding-left:12px;color:#000}

/* MANIFESTO — scroll-scrubbed reading reveal */
.manifesto{padding-top:12vh;padding-bottom:12vh}
.manifesto-line{font-family:var(--serif);font-size:clamp(1.8rem,4vw,3.4rem);line-height:1.42;max-width:940px;color:var(--black)}
.m-word{display:inline-block;will-change:opacity}

/* SECTION BLOCKS — each section is one full viewport, content centred so
   nothing sits above or below the fold while it is in view */
.s-block{padding:96px 48px;min-height:100vh;min-height:100svh;display:flex;align-items:center}
.s-inner{max-width:1200px;margin:0 auto;width:100%}
/* exceptions: tall scroll-driven section + interstitial strips */
#services{min-height:0;display:block}
.stats-block{min-height:0;display:block;padding:120px 48px}
.s-label{display:inline-block;font-size:.65rem;font-weight:500;letter-spacing:.2em;text-transform:uppercase;color:var(--grey);margin-bottom:24px}
.s-heading{font-family:var(--serif);font-weight:400;font-size:clamp(1.8rem,3.5vw,3.2rem);line-height:1.2;margin-bottom:32px}
.s-body{max-width:560px;font-size:.92rem;line-height:1.9;color:var(--grey);font-weight:300}

/* TEXT SPLIT ANIMATION */
.word{display:inline-block;overflow:hidden;vertical-align:bottom;line-height:1.3}
.word-inner{display:inline-block;will-change:transform}

/* IMAGE REVEAL — clip + inner scale, fully GSAP-owned (reversible) */
.img-reveal{overflow:hidden;border-radius:4px;will-change:clip-path}
.img-reveal img{width:100%;height:100%;object-fit:cover;display:block;will-change:transform}

/* STATS */
.stats-block{border-top:1px solid rgba(0,0,0,.06);border-bottom:1px solid rgba(0,0,0,.06)}
.stats-row{display:grid;grid-template-columns:repeat(4,1fr);gap:40px;text-align:center}
.stat-num{display:block;font-family:var(--serif);font-size:clamp(3rem,5.5vw,5rem);line-height:1;font-weight:400}
.stat-lbl{display:block;font-size:.7rem;letter-spacing:.15em;text-transform:uppercase;color:var(--grey);margin-top:12px;font-weight:400}

/* MARQUEE */
.marquee-wrap{overflow:hidden;padding:48px 0}
.marquee-track{display:flex;width:max-content;will-change:transform}
.marquee-text{white-space:nowrap;font-family:var(--serif);font-size:clamp(2rem,4vw,4rem);font-weight:400;opacity:.08;padding:0 8px}

/* HORIZONTAL SCROLL PROJECTS
   Pinned full-height so the header AND the card titles both fit on screen.
   The header is left-aligned to the same 48px inset as the track — using the
   centred .s-inner max-width here made them misalign on wide screens. */
.projects-section{overflow:hidden;height:100vh;height:100svh;display:flex;flex-direction:column;justify-content:center}
.projects-header{padding:0 48px 44px;flex-shrink:0}
.s-inner.projects-header-inner{max-width:none;margin:0;display:flex;justify-content:space-between;align-items:flex-end}
.ph-text{flex:1}
.view-all{font-family:var(--sans);font-size:.85rem;text-transform:uppercase;letter-spacing:.12em;color:var(--grey);text-decoration:none;border-bottom:1px solid rgba(10,10,10,.2);padding-bottom:4px;transition:color .3s,border-color .3s;flex-shrink:0}
.view-all:hover{color:var(--black);border-color:var(--black)}
.projects-heading{margin-bottom:0}
.projects-track{display:flex;gap:32px;padding:0 48px;width:max-content;align-items:flex-start}
.project-card{width:min(40vw,560px);flex-shrink:0;text-decoration:none;color:inherit;display:block}
.project-card:nth-child(even){margin-top:48px}   /* editorial stagger */
.project-img{overflow:hidden;border-radius:6px;aspect-ratio:3/2;position:relative}
.project-img img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .8s var(--ease-out-expo)}
.project-card:hover .project-img img{transform:scale(1.06)}
.project-img::after{content:'';position:absolute;inset:0;background:linear-gradient(transparent 50%,rgba(0,0,0,.15));opacity:0;transition:opacity .4s}
.project-card:hover .project-img::after{opacity:1}
.project-meta{padding:20px 0 0}
.project-year{font-size:.65rem;letter-spacing:.15em;text-transform:uppercase;color:var(--grey);font-weight:400}
.project-meta h3{font-family:var(--serif);font-size:clamp(1.2rem,2vw,1.8rem);font-weight:400;margin:6px 0 4px}
.project-cat{font-size:.75rem;color:var(--grey);font-weight:300}

/* SERVICES — hover-image index: huge serif rows, dark sweep on hover,
   floating preview image that follows the cursor */
/* SERVICES — sticky media split: the image panel pins while services scroll
   past; each service takes focus (title inks in, image crossfades) as it
   reaches the centre of the screen. Scroll-driven, touch-friendly. */
.services-wrap{display:grid;grid-template-columns:1fr 1.15fr;gap:clamp(48px,7vw,110px);margin-top:64px;align-items:start}
.services-media{position:sticky;top:calc(50vh - min(29vw,270px))}
.sm-frame{position:relative;aspect-ratio:4/5;border-radius:14px;overflow:hidden;background:#e9e9e9}
.sm-frame img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transform:scale(1.07);transition:opacity .65s,transform 1.1s var(--ease-out-expo)}
.sm-frame img.active{opacity:1;transform:scale(1)}
.sm-count{position:absolute;bottom:16px;right:18px;color:#fff;font-size:.62rem;letter-spacing:.24em;z-index:2;text-shadow:0 1px 8px rgba(0,0,0,.45);font-variant-numeric:tabular-nums}
.service-item{min-height:46vh;min-height:46svh;display:flex;flex-direction:column;justify-content:center}
.si-num{font-size:.64rem;letter-spacing:.2em;color:var(--grey)}
.service-item h3{font-family:var(--serif);font-weight:400;font-size:clamp(2rem,3.6vw,3.4rem);line-height:1.1;margin:12px 0 16px;color:rgba(10,10,10,.22);transition:color .6s,transform .6s var(--ease-out-expo)}
.service-item.active h3{color:var(--black);transform:translateX(6px)}
.service-item p{font-size:.86rem;color:var(--grey);font-weight:300;line-height:1.8;max-width:420px}
.si-img{display:none}

/* ============================================================
   PROCESS — THE SHEET
   ------------------------------------------------------------
   A process laid out as four cards on a rule is a list with a
   timeline drawn through it: everything arrives at once and the
   only thing moving is the reader's eye. This is the opposite —
   the section pins, and the drawing on the sheet is MADE while
   you scroll, one stage accumulating over the last, the way the
   work itself accumulates. Nothing is ever taken away, because
   nothing in the real process is: the site is still under the
   building at the end.

   The whole illustration is an inline SVG of hairline paths.
   Each path is drawn by animating stroke-dashoffset from its own
   length to zero — a stroke being made, not a shape fading up.
   `vector-effect: non-scaling-stroke` keeps every line exactly
   1px at every viewport, which is what makes it read as a
   drawing rather than as artwork that got bigger.

   Everything the drawing says is also written in the title
   block, so the SVG is aria-hidden and the section is safe to
   flatten entirely under reduced motion.
   ============================================================ */

/* The scroll length the pin consumes. Set in vh here, so the
   sheet holds for four screens of scrolling and the four stages
   get one screen each; script.js reads the element, not this
   number, so the two can never disagree. */
.process { position: relative; }
.pr-scroll { position: relative; height: 400vh; }

/* What actually pins. Sized to the window rather than to its
   content so the sheet is always exactly one screen — a drawing
   you cannot see all of is not a drawing. */
.pr-sheet {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
}
.pr-shell {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  /* The nav is fixed and this sheet is the only section that sits
     under it for four screens at a stretch, so it is the only one
     that has to clear it explicitly — everything else scrolls past
     in a second or two. */
  padding: calc(var(--nav-h) + clamp(10px, 2.6svh, 30px)) 48px clamp(20px, 4svh, 44px);
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: clamp(12px, 2.4svh, 30px);
  height: 100%;
}

/* -- the head: what this is, and the note for the current stage -- */
.pr-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(20px, 4vw, 64px);
}
.pr-titles { min-width: 0; }
.pr-head .s-label { margin-bottom: 12px; }
.pr-head .s-heading { margin-bottom: 0; }

/* Four notes stacked in one box: the box is as tall as the
   tallest of them, so swapping the visible one never moves the
   drawing below. Grid rather than absolute positioning so that
   height is measured, not guessed. */
.pr-note {
  display: grid;
  flex: 0 1 clamp(220px, 26vw, 340px);
  min-width: 0;
  padding-left: clamp(14px, 2vw, 26px);
  border-left: 1px solid rgba(10, 10, 10, .14);
}
.pr-note p {
  grid-area: 1 / 1;
  margin: 0;
  font-size: .8rem;
  font-weight: 300;
  line-height: 1.7;
  color: var(--grey);
}
/* Script-driven: only the live note is shown, and it crossfades
   with the one it replaces rather than cutting. Without the script
   all four read as a plain list, which is still true and still
   legible — the failure mode is verbose, not broken. */
html.has-sheet .pr-note p {
  opacity: 0;
  transition: opacity .5s var(--ease-out-expo);
}

/* -- the board -------------------------------------------------- */
.pr-board {
  position: relative;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* The paper: a faint construction grid, fading out at the edges
   so the sheet has no hard border to fight the page's own. */
.pr-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(to right, rgba(10, 10, 10, .05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(10, 10, 10, .05) 1px, transparent 1px);
  background-size: 44px 44px;
  -webkit-mask-image: radial-gradient(ellipse 78% 74% at 50% 50%, #000 42%, transparent 100%);
          mask-image: radial-gradient(ellipse 78% 74% at 50% 50%, #000 42%, transparent 100%);
  pointer-events: none;
}

.pr-draw {
  position: relative;
  width: 100%;
  height: 100%;
  max-height: 100%;
  overflow: visible;
}
/* One stroke weight for the whole drawing, held at 1px however
   the viewBox is scaled. The three inks are the drafting
   convention: cut and built lines full strength, setting-out and
   dimension lines lighter, construction lines lighter still. */
.pr-draw path {
  fill: none;
  stroke-width: 1;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.pr-ink   { stroke: rgba(10, 10, 10, .88); }
.pr-mid   { stroke: rgba(10, 10, 10, .42); }
.pr-faint { stroke: rgba(10, 10, 10, .20); }
.pr-fine  { stroke-width: 1; }

/* -- the title block -------------------------------------------- */
.pr-block {
  position: relative;
  padding-top: clamp(12px, 1.8svh, 20px);
  border-top: 1px solid rgba(10, 10, 10, .14);
}
/* The rule across the top of the block IS the progress bar. A
   drawing's title block already carries the sheet's status; this
   one carries how much of the sheet has been drawn. */
.pr-fill {
  position: absolute;
  top: -1px;
  left: 0;
  width: 100%;
  height: 1px;
  background: var(--black);
  transform: scaleX(var(--p, 0));
  transform-origin: left;
  will-change: transform;
}
/* and the tick riding it. Positioned rather than transformed: it is
   one 1px element, and `left` in percent needs no container query
   to know what it is a percentage of. */
.pr-tick {
  position: absolute;
  top: -4px;
  left: calc(var(--p, 0) * 100%);
  width: 1px;
  height: 9px;
  background: var(--black);
}

.pr-cells {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(14px, 2.6vw, 40px);
  margin: 0;
  padding: 0;
  list-style: none;
}
.pr-cell {
  position: relative;
  min-width: 0;
  padding-left: 14px;
  /* Three states, which is one more than a list needs and exactly as
     many as a drawing has: not yet drawn, drawn, and being drawn now.
     The transition is on opacity only — nothing here moves, because
     the drawing above is the thing that moves. */
  opacity: .28;
  transition: opacity .55s var(--ease-out-expo);
}
/* the cell's own tick, on the rule above it */
.pr-cell::before {
  content: '';
  position: absolute;
  top: calc(-1 * clamp(12px, 1.8svh, 20px) - 1px);
  left: 0;
  width: 1px;
  height: 6px;
  background: rgba(10, 10, 10, .3);
  transition: height .5s var(--ease-out-expo), background .5s var(--ease-out-expo);
}
.pr-cell.is-lit { opacity: .55; }             /* drawn, and behind you */
.pr-cell.is-on  { opacity: 1; }               /* being drawn now */
.pr-cell.is-on::before { height: 10px; background: var(--black); }
.pr-cell-num {
  display: block;
  font-size: .6rem;
  letter-spacing: .2em;
  color: var(--grey);
  font-variant-numeric: tabular-nums;
}
/* The stage name rolls up out of its own box as the stage takes
   over: the one piece of type in the section that moves, and it
   moves because the sheet has advanced. */
.pr-cell-word {
  overflow: hidden;
  margin: 5px 0 0;
  font-family: var(--serif);
  font-size: clamp(1.05rem, 1.9vw, 1.6rem);
  font-weight: 400;
  line-height: 1.24;
}
.pr-cell-word > span {
  display: block;
  will-change: transform;
}
html.has-sheet .pr-cell-word > span {
  transform: translateY(110%);
  transition: transform .8s var(--ease-out-expo);
}
html.has-sheet .pr-cell.is-lit .pr-cell-word > span { transform: translateY(0); }

/* ============================================================
   PROCESS — every screen
   The sheet pins everywhere. A phone gets the same four screens
   of scroll, the same strokes made under the thumb, the same live
   note and the same rule filling under the drawing. Only the
   furniture is retuned to the width — nothing is removed, because
   the making of the drawing IS the section.
   ============================================================ */

/* Tablet: the note has nowhere to sit beside a heading this size. */
@media (max-width: 1024px) {
  .pr-shell {
    padding: calc(var(--nav-h) + clamp(8px, 2svh, 22px)) 32px clamp(18px, 3svh, 34px);
  }
  .pr-head {
    flex-direction: column;
    align-items: flex-start;
    gap: clamp(10px, 1.8svh, 18px);
  }
  .pr-note {
    flex: none;
    width: 100%;
    max-width: 60ch;
    padding-left: 14px;
  }
}

/* Portrait windows — phones and tablets alike. The drawing is
   roughly 2:1, so a full-height board on a portrait screen is a
   tall empty box with a wide drawing floating in the middle of it.
   Here the board takes the drawing's own proportion and the sheet
   becomes a compact block centred in the screen instead — the pin
   still holds a whole screen, the drawing just stops pretending to
   fill it. */
@media (max-aspect-ratio: 1 / 1) {
  .pr-shell {
    height: auto;
    max-height: 100%;
    grid-template-rows: auto auto auto;
    /* Symmetric now that the block is centred rather than stretched:
       the nav is cleared by the centring itself, and an asymmetric pad
       would only push a short block into the bottom of the screen. The
       top value still holds if the block ever grows to fill. */
    padding-bottom: calc(var(--nav-h) + clamp(10px, 2.6svh, 30px));
  }
  .pr-board { aspect-ratio: 900 / 460; height: auto; }
}

/* Phone: the same pinned sheet, at the width of a thumb. The four
   stages still divide four screens of scroll, the strokes are still
   made one at a time, and the title block still carries the rule —
   so the four cells stay in FOUR columns, because a rule filling
   left to right across two rows of two would say nothing true. What
   changes is only size: the type comes down, the gaps close, and the
   note sits under the heading rather than beside it. */
@media (max-width: 768px) {
  /* Symmetric top and bottom: the sheet is a centred block here, not a
     stretched one, so the nav is cleared by the centring and an
     asymmetric pad would only shove a short block downward. */
  .pr-shell {
    padding: calc(var(--nav-h) + clamp(8px, 1.6svh, 16px)) 20px;
    gap: clamp(10px, 1.8svh, 20px);
  }
  .pr-head .s-heading { font-size: clamp(1.6rem, 7.4vw, 2.2rem); }
  .pr-note { margin-top: 2px; }
  .pr-note p { font-size: .74rem; line-height: 1.65; }
  .pr-cells { gap: 10px; }
  .pr-cell { padding-left: 9px; }
  .pr-cell-num { font-size: .52rem; letter-spacing: .14em; }
  .pr-cell-word {
    margin-top: 3px;
    font-size: clamp(.82rem, 3.5vw, 1.15rem);
    line-height: 1.2;
  }
  /* The construction grid is drawn at 44px on a 1440 screen; at 390
     that is a coarse chequerboard behind a fine drawing. */
  .pr-grid { background-size: 30px 30px; }
}

@media (max-width: 480px) {
  .pr-shell { padding-left: 16px; padding-right: 16px; }
  .pr-note p { font-size: .7rem; }
  .pr-cells { gap: 7px; }
  .pr-cell { padding-left: 7px; }
  .pr-cell-word { font-size: clamp(.76rem, 3.6vw, 1rem); }
}

/* Short landscape windows — a laptop with a shallow window, or a phone
   turned sideways. The drawing keeps the space, the heading gives it up.
   The nav still has to be cleared. */
@media (max-height: 620px) {
  .pr-shell {
    padding-top: calc(var(--nav-h) + 6px);
    padding-bottom: 14px;
    gap: 10px;
  }
  .pr-head .s-label { margin-bottom: 6px; }
}

@media (prefers-reduced-motion: reduce) {
  /* No pin, no drawing-in: the whole sheet is simply present. */
  .pr-scroll { height: auto; }
  .pr-sheet { position: static; height: auto; display: block; padding: 76px 0; }
  .pr-shell { height: auto; display: block; }
  .pr-board { height: min(60vh, 420px); margin: 28px 0 32px; }
  .pr-draw path { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .pr-cell, .pr-cell.is-lit { opacity: 1; transition: none; }
  .pr-cell::before { transition: none; }
  .pr-fill { transform: scaleX(1); }
  .pr-tick { display: none; }
  html.has-sheet .pr-note p { opacity: 1; }
  html.has-sheet .pr-note p + p { margin-top: 7px; }
  html.has-sheet .pr-cell-word > span { transform: none; transition: none; }
}

/* THE APPROACH — contained, rounded image with a voice over it */
.parallax-section{width:min(1280px,calc(100% - 96px));margin:0 auto;height:80vh;overflow:hidden;position:relative;border-radius:18px}
.parallax-img{position:absolute;top:-20%;left:0;width:100%;height:140%;will-change:transform}
.parallax-img img{width:100%;height:100%;object-fit:cover;display:block}
.parallax-veil{position:absolute;inset:0;background:linear-gradient(rgba(0,0,0,.28),rgba(0,0,0,.44))}
.parallax-content{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;color:#fff;padding:0 24px;will-change:transform}
.p-label{font-size:.62rem;letter-spacing:.3em;text-transform:uppercase;color:rgba(255,255,255,.65);margin-bottom:26px}
.p-quote{font-family:var(--serif);font-size:clamp(1.7rem,4.4vw,3.6rem);line-height:1.3;max-width:900px}
.p-credit{font-size:.66rem;letter-spacing:.22em;text-transform:uppercase;color:rgba(255,255,255,.55);margin-top:28px}

/* CONTACT + FOOTER — see close.css. Both used to be defined here as two
   separate blocks (.contact-block then <footer>), which is why the page ended
   twice. They are one element now, footer.close, shared with the other three
   pages. .magnetic-btn is unrelated and stays. */
.magnetic-btn{display:inline-flex;align-items:center;justify-content:center;padding:18px 48px;border:1px solid var(--black);border-radius:100px;text-decoration:none;color:var(--black);font-size:.85rem;font-weight:400;letter-spacing:.08em;text-transform:uppercase;transition:background .4s,color .4s;will-change:transform;margin-bottom:80px}
.magnetic-btn:hover{background:var(--black);color:var(--white)}
.magnetic-btn span{display:inline-block;will-change:transform}

/* RESPONSIVE — tablet / iPad */
@media(max-width:1024px){
  #nav{padding:0 28px}
  .s-block{padding:110px 28px}
  .split{gap:36px}
  .projects-header{padding:0 28px 36px}
  .projects-track{padding:0 28px;gap:24px}
  .project-card{width:min(52vw,520px)}
  .services-wrap{gap:44px}
}

/* RESPONSIVE — mobile */
@media(max-width:768px){
  #nav{padding:0 20px}
  #nav-links a{display:none}
  #menu-btn{display:flex}
  #hero-row{padding:0 22px}
  #hero-left,#hero-right{font-size:clamp(2.1rem,10.5vw,3.2rem);white-space:normal;padding:0 22px}
  #hero-sub{font-size:.76rem;max-width:30ch}
  #hero-eyebrow{letter-spacing:.26em}
  #scroll-hint{bottom:30px}
  #arrival{padding:0 20px}
  .arrival-heading{font-size:clamp(2rem,9.4vw,3.2rem);max-width:11em}
  .s-block{padding:90px 20px}
  .split{grid-template-columns:1fr;gap:40px}
  .split-reverse .split-media{order:2}
  .split-reverse .split-text{order:1}
  .split-media img{aspect-ratio:3/2}
  .stats-row{grid-template-columns:repeat(2,1fr);gap:24px}
  .project-card{width:75vw}
  .project-card:nth-child(even){margin-top:24px}
  .projects-header{padding:0 20px 32px}
  .s-inner.projects-header-inner {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }
  .projects-track{padding:0 20px;gap:20px}
  .services-wrap{grid-template-columns:1fr;margin-top:36px}
  .services-media{display:none}
  .service-item{min-height:0;padding:30px 0;border-bottom:1px solid rgba(0,0,0,.08)}
  .service-item h3{color:var(--black);font-size:1.7rem;margin:8px 0 10px}
  .si-img{display:block;width:100%;aspect-ratio:3/2;object-fit:cover;border-radius:10px;margin-top:16px}
  /* .process — pinned here as everywhere; retuned to the width in the
     PROCESS block above */
  .parallax-section{width:calc(100% - 32px);height:60vh;border-radius:12px}
  .manifesto{padding-top:10vh;padding-bottom:10vh}
}

/* RESPONSIVE — small phones */
@media(max-width:480px){
  #nav-links{gap:20px}
  #nav-links a{font-size:.68rem}
  .s-block{padding:76px 16px}
  .project-card{width:84vw}
  .stats-row{gap:18px}
  .service-tag{padding-left:40px}
  .split-media figcaption{font-size:.6rem}
}
