/* ============================================================
   Vishal K. — Portfolio
   Hero section: 1:1 reconstruction of "Hero Section.svg"
   Design canvas: 1440 × 1216. Every value below is in design px
   and is scaled fluidly by --k. Do not "round" these numbers —
   they were derived from the exported vector outlines.
   ============================================================ */

/* ---------- Fonts ---------- */
@font-face{font-family:'PP Neue Montreal';src:url('../assets/fonts/PPNeueMontreal-Book.otf') format('opentype');font-weight:350;font-style:normal;font-display:block}
@font-face{font-family:'PP Neue Montreal';src:url('../assets/fonts/PPNeueMontreal-Regular.otf') format('opentype');font-weight:400;font-style:normal;font-display:block}
@font-face{font-family:'PP Neue Montreal';src:url('../assets/fonts/PPNeueMontreal-Medium.otf') format('opentype');font-weight:500;font-style:normal;font-display:block}
@font-face{font-family:'PP Editorial New';src:url('../assets/fonts/PPEditorialNew-Regular.otf') format('opentype');font-weight:400;font-style:normal;font-display:block}
@font-face{font-family:'PP Editorial New';src:url('../assets/fonts/PPEditorialNew-Italic.otf') format('opentype');font-weight:400;font-style:italic;font-display:block}
@font-face{font-family:'PP Editorial New';src:url('../assets/fonts/PPEditorialNew-UltralightItalic.otf') format('opentype');font-weight:200;font-style:italic;font-display:block}

/* ---------- Reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html,body{margin:0;padding:0}
html{background:#000}
body{
  /* black, not white — the hero paints its own white box, so anything that
     ever shows through elsewhere should match the dark sections */
  background:#000;
  color:#fff;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
  text-rendering:geometricPrecision;
}
ul{list-style:none;margin:0;padding:0}
a{color:inherit;text-decoration:none}
img{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;padding:0}

/* ---------- Fluid design-scale ----------
   --k is the artboard→viewport scale factor. It must be a UNITLESS number
   for transform:scale(), and CSS cannot divide two lengths, so it is set
   from documentElement.clientWidth by the inline script in <head> (which
   also excludes the scrollbar, unlike 100vw). 1 is the no-JS fallback. */
:root{
  --design-w: 1440;
  --k: 1;
  --stage-h: 1216;   /* updated by JS as sections are added */
}

.stage-wrap{
  position:relative;
  width:100%;
  overflow:hidden;
  height:calc(var(--stage-h) * 1px * var(--k));
}
.stage{
  position:absolute;
  top:0; left:0;
  width:1440px;
  height:calc(var(--stage-h) * 1px);
  transform-origin:0 0;
  transform:scale(var(--k));
}

/* ============================================================
   HERO  (0 → 1216)
   ============================================================ */
.hero{
  position:absolute;
  inset:0 0 auto 0;
  height:1216px;
  background:#fff;
}

/* -- portrait: SVG rect x=290 y=0 w=1299 h=952 -- */
.hero__photo{
  position:absolute;
  left:290px; top:0;
  width:1299px; height:952px;
  overflow:hidden;
  will-change:transform;
}
.hero__photo img{
  width:1299px; height:952px;
  object-fit:fill;          /* source is 1712×1254 — identical aspect */
  will-change:transform;
}

/* -- tint band: SVG rect y=812 h=138 fill #272727 @ 10% -- */
.hero__band{
  position:absolute;
  left:0; top:812px;
  width:1440px; height:138px;
  background:rgba(39,39,39,.1);
  pointer-events:none;
}

/* -- black plate: SVG rect y=950, runs to the page bottom -- */
.hero__plate{
  position:absolute;
  left:0; top:950px;
  width:1440px; height:266px;
  background:#000;
}

/* -- veil: dims the hero as section 2 arrives (see js) -- */
.hero__veil{
  position:absolute;
  inset:0;
  background:#000;
  opacity:0;
  pointer-events:none;
  z-index:5;
  will-change:opacity;
}

/* -- headline: PP Editorial New Italic 35/45, #141313 -- */
.hero__headline{
  position:absolute;
  left:52px; top:311.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:400;
  font-size:35px;
  line-height:45px;
  color:#141313;
  white-space:nowrap;
}
/* The mask must clip vertically (that is the reveal) but never horizontally —
   italic glyphs overhang the advance width at both ends (the final "T" of
   FROM FIRST THOUGHT sticks out 4.9px). Bleed sideways via padding, pulled
   back with a matching negative margin so the text origin is unmoved. */
.hero__headline .line{
  display:block;
  overflow:hidden;
  margin-left:-24px;
  padding-left:24px;
  padding-right:32px;
}
.hero__headline .line > span{display:block;will-change:transform}

/* -- meta, right side: PP Neue Montreal Regular 15/15, #000 -- */
.hero__meta{position:absolute;left:0;top:0;width:1440px;height:1px}
.hero__meta p{
  position:absolute;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:400;
  font-size:15px;
  line-height:15px;
  color:#000;
  white-space:nowrap;
}
.hero__meta p:nth-child(1){left:1069.64px;top:446px}
.hero__meta p:nth-child(2){left:1161.35px;top:490px}

/* -- CTA: SVG rect x=52 y=567 w=187 h=54 r=11 -- */
.hero__cta{
  position:absolute;
  left:52px; top:567px;
  width:187px; height:54px;
  border-radius:11px;
  background:#000;
  display:block;
  overflow:hidden;
  will-change:transform;
}
.hero__cta .label{
  position:absolute;
  left:18px;              /* 70 − 52 */
  top:19px;               /* 586 − 567 */
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:400;
  font-size:15px;
  line-height:15px;
  color:#fff;
  white-space:nowrap;
}
.hero__cta .arrow{
  position:absolute;
  left:153px;             /* 205 − 52 */
  top:22px;               /* 589 − 567 */
  width:10px; height:10px;
  overflow:visible;
}

/* -- categories: PP Editorial New Italic 15/15 -- */
.hero__cats{position:absolute;left:0;top:0;width:1440px;height:1px}
.hero__cats li{
  position:absolute;
  top:873.5px;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:400;
  font-size:15px;
  line-height:15px;
  white-space:nowrap;
}
.hero__cats li:nth-child(1){left:130.02px;color:#000}
.hero__cats li:nth-child(2){left:503.51px;color:#fff}
.hero__cats li:nth-child(3){left:850.04px;color:#fff}
.hero__cats li:nth-child(4){left:1196.30px;color:#fff}

/* -- wordmark: PP Editorial New Italic 62/62, #fff -- */
.hero__wordmark{
  position:absolute;
  left:45px; top:1047px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:400;
  font-size:62px;
  line-height:62px;
  color:#fff;
  white-space:nowrap;
  overflow:hidden;
  margin-left:-24px;
  padding-left:24px;
  padding-right:32px;
  margin-top:-14px;       /* italic caps rise above the 62px line box */
  padding-top:14px;
}
.hero__wordmark > span{display:block;will-change:transform}

/* -- wordmark tagline: PP Neue Montreal Regular 11/11, ls 1.7244 -- */
.hero__tagline{
  position:absolute;
  left:53px; top:1113.5px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:400;
  font-size:11px;
  line-height:11px;
  letter-spacing:1.7244px;
  color:#fff;
  white-space:nowrap;
}

/* -- body copy: PP Neue Montreal Regular 18/29, #fff -- */
.hero__body{
  position:absolute;
  top:1056.5px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:400;
  font-size:18px;
  line-height:29px;
  color:#fff;
  white-space:nowrap;
}
.hero__body--a{left:448px}
.hero__body--b{left:960px}
.hero__body .line{
  display:block;
  overflow:hidden;
  margin-left:-16px;
  padding-left:16px;
  padding-right:24px;
}
.hero__body .line > span{display:block;will-change:transform}

/* ============================================================
   NAV  — lives in its own fixed, equally-scaled layer so it can
   stick without being affected by the stage transform.
   ============================================================ */
.navlayer{
  position:fixed;
  left:0; top:0;
  width:100vw; height:0;
  z-index:60;
  pointer-events:none;
}
.navlayer__scale{
  position:relative;
  width:1440px; height:0;
  transform-origin:0 0;
  transform:scale(var(--k));
}

/* pill: SVG rect x=425.5 y=39.5 w=589 h=38 r=19, 1px stroke #EBEBEB */
.nav{
  position:absolute;
  left:425px; top:39px;
  width:590px; height:39px;
  border:1px solid #EBEBEB;
  border-radius:19.5px;
  background:rgba(0,0,0,.01);
  pointer-events:auto;
  will-change:transform;
}
.nav a{
  position:absolute;
  top:13px;                 /* 53 − 39 − 1(border) */
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:12px;
  line-height:12px;
  color:#000;
  white-space:nowrap;
  transition:color .4s cubic-bezier(.4,0,.2,1);
}
/* set per-item by the backdrop sampler when the nav is over dark pixels */
.nav a.is-on-dark{color:#fff}
.nav.is-on-dark{border-color:rgba(255,255,255,.22)}
.nav{transition:border-color .4s cubic-bezier(.4,0,.2,1)}
.nav a:nth-of-type(1){left:61px}    /* 487 − 426 */
.nav a:nth-of-type(2){left:193px}   /* 619 − 426 */
.nav a:nth-of-type(3){left:329px}   /* 755 − 426 */
.nav a:nth-of-type(4){left:492px}   /* 918 − 426 */

/* hover: roll. 15px tall so descenders ("Playground") clear the mask;
   the second copy is offset by that same 15px and animated in px. */
.nav a .roll{
  position:relative;display:block;overflow:hidden;
  height:15px;padding-right:8px;
}
.nav a .roll i{display:block;font-style:normal;will-change:transform}
.nav a .roll i:last-child{position:absolute;left:0;top:15px}


/* ============================================================
   Load curtain
   ============================================================ */
.curtain{
  position:fixed; inset:0;
  background:#000;
  z-index:150;
  pointer-events:none;
  transform-origin:50% 100%;
}
.js-ready .curtain{pointer-events:none}

/* ============================================================
   Motion opt-outs
   ============================================================ */
html[data-static="1"] .curtain{display:none}

@media (prefers-reduced-motion:reduce){
  .curtain{display:none}
  *{animation-duration:.001ms !important;transition-duration:.001ms !important}
}

/* ============================================================
   SECTION 2 — "Brand Identities"  (artboard 1440 × 993)

   This one is PINNED, so it is scaled to *fit* the viewport
   (contain) rather than to width like the hero. A 1440×993
   artboard is proportionally taller than any 16:9 screen, so
   width-scaling would crop the card on a 1080p display. The
   section and the page are both pure black, so the letterbox
   is invisible. --k2 is set by JS alongside --k.
   ============================================================ */
:root{ --k2: 1; }

.s2{
  position:relative;
  height:360vh;              /* 100vh visible + 260vh of pinned scroll */
  background:#000;
}
.s2__sticky{
  position:sticky;
  top:0;
  height:100vh;
  overflow:hidden;
  background:#000;
}
.s2__art{
  position:absolute;
  left:50%; top:50%;
  width:1440px; height:900px;
  margin:-450px 0 0 -720px;     /* centre the artboard */
  transform:scale(var(--k2));
  transform-origin:50% 50%;
  /* The artboard is the frame: slides travel beyond its edges during a
     transition and must vanish there. Without this they would keep drifting
     across the black letterbox margin on screens where --k2 is height-bound. */
  overflow:hidden;
}
/* separate layer so GSAP can animate the entry without clobbering --k2 */
.s2__inner{
  position:absolute;
  inset:0;
  will-change:transform;
}

/* -- shared heading -- */
.s2__heading{
  position:absolute;
  left:468px; top:76.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;              /* Ultralight Italic */
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}

/* -- slides stack -- */
.s2__slide{
  position:absolute;
  inset:0;
  will-change:opacity;      /* own compositor layer → opacity costs nothing */
}
/* no-JS / pre-JS fallback — GSAP overrides the container with inline
   opacity:1 and animates the two column groups instead */
.s2__slide[aria-hidden="true"]{opacity:0;pointer-events:none}

/* the two transform groups: text enters from the left, card from the right.
   One transform per column rather than one per element.
   Sized to the column's actual content, NOT inset:0 — origin stays at 0,0 so
   the children's coordinates are untouched, but the area the compositor has
   to blur and composite drops from 1440×993 to 560×820. */
.s2__text{
  position:absolute;
  left:0; top:0;
  width:560px; height:820px;
  will-change:transform,opacity,filter;
}

/* -- card -- */
/* The card group now spans the whole artboard: each image carries its own
   .s2__frame with artboard coordinates and its own clipping, so this element
   is only the transform/opacity group the transition animates. Giving it the
   old 557,279 803x586 box offset every frame inside it by that amount and
   clipped the overflow. */
.s2__card{
  position:absolute;
  left:0; top:0;
  width:1440px; height:900px;
  will-change:transform,opacity,filter;
}
.s2__card img{
  position:absolute;
  max-width:none;
  will-change:transform;
}

/* -- left column -- */
.s2__title{
  position:absolute;               /* left/top inline per slide */
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:500;              /* Medium */
  font-size:50px;
  line-height:50px;
  color:#fff;
  white-space:nowrap;
}
.s2__tagline{
  position:absolute;               /* left/top inline per slide */
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:18px;
  line-height:18px;
  color:#fff;
  white-space:nowrap;
}
.s2__body{
  position:absolute;               /* left/top inline per slide */
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;              /* Book */
  font-size:18px;
  line-height:29px;
  color:#fff;
  white-space:nowrap;
}
.s2__credits{
  position:absolute;               /* left/top inline per slide */
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:12px;
  line-height:18px;
  color:#fff;
  opacity:.5;                      /* slides 2-3: white @ 50% */
  white-space:nowrap;
}
/* slide 1 uses a flat grey fill instead — #727272 at full opacity */
.s2__slide--1 .s2__credits{ color:#727272; opacity:1 }

/* per-slide overrides taken from the artboards */
.s2__slide--1 .s2__body{top:456.5px}          /* 4 lines, not 5 */
.s2__slide--3 .s2__tagline{left:423px;top:346px}
.s2__slide--3 .s2__cta{top:653px}

/* -- CTA -- */
/* Shared by sections 2 and 3 — the artboards use an identical pill, only the
   position differs. The SVG rect is 164.5×50.5 with a 0.5 stroke, and SVG
   strokes straddle the path, so the outer box is 165×51 and the radius grows
   by half the stroke (4.75 → 5). CSS borders sit inside the box. */
.cta{
  position:absolute;
  width:165px; height:51px;
  border:.5px solid #fff;
  border-radius:5px;
  background:#000;
  display:block;
  overflow:hidden;
  isolation:isolate;               /* keep the sweep from painting over neighbours */
}
/* Light travelling along the button border.
   Uses box-shadow with blur for smooth glow effect that follows the outline. */
.cta::before{
  content:'';
  position:absolute;
  inset:-2px;
  border-radius:7px;
  background:conic-gradient(from 0deg,
      rgba(255,255,255,0) 0deg 240deg,
      rgba(255,255,255,.3) 280deg,
      #fff 300deg,
      rgba(255,255,255,.3) 320deg,
      rgba(255,255,255,0) 360deg);
  animation:cta-sweep 4s linear infinite;
  z-index:0;
  pointer-events:none;
  -webkit-mask:radial-gradient(circle at center, transparent 0%, transparent calc(100% - 2px), black calc(100% - 1px));
  mask:radial-gradient(circle at center, transparent 0%, transparent calc(100% - 2px), black calc(100% - 1px));
}
/* covers the middle, leaving only the border visible */
.cta::after{
  content:'';
  position:absolute;
  inset:2px;
  border-radius:5px;
  background:#000;
  z-index:1;
  pointer-events:none;
}
.cta .label,.cta .arrow{ z-index:2 }

@keyframes cta-sweep{ to{ transform:translate(-50%,-50%) rotate(360deg) } }

/* only run while the button is on screen — initCtaGlow adds the class */
.cta:not(.is-live)::before{ animation-play-state:paused }

@media (prefers-reduced-motion:reduce){
  .cta::before{ animation:none; opacity:0 }
}

/* Page transition fade-in */
body { opacity: 0; animation: page-fade-in 0.8s ease-out 0.2s forwards; }
@keyframes page-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.cta .label{
  position:absolute;
  left:20.5px; top:18px;        /* label ink sits +21.12,+20.275 from the CTA
                                   border-box in every artboard; 17.5 put it
                                   half a pixel high in all nine buttons */
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:400;
  font-size:15px;
  line-height:15px;
  color:#fff;
  white-space:nowrap;
}
.cta .arrow{
  position:absolute;
  left:133.5px; top:21.5px;
  width:10px; height:10px;
  overflow:visible;
}
/* .s2__cta position is inline per slide */

/* -- reveal masks (vertical clip only, per the hero's rules) -- */
.s2 .line{display:block;overflow:hidden;margin-left:-16px;padding-left:16px;padding-right:26px}
.s2 .line > span{display:block;will-change:transform}

/* ============================================================
   SECTION 3 — "Campaigns"  (artboard 1440 x 834, REDESIGN)

   Rebuilt from ~/Downloads/campaign.svg. Not pinned: at 834 tall
   the artboard is proportionally shorter than section 2's, so it
   scales to WIDTH like the hero and simply scrolls past.

   The old layout (257x457 reel, column 2 = column 1 + 681) is GONE.
   The two columns are no longer a uniform offset of each other:
   the TEXT columns sit on a 738px pitch (426 -> 1164) but the media
   frames do NOT (46 -> 777, a 731 pitch), so every child carries an
   absolute artboard coordinate.

   Pendulo (LEFT, --1) runs 4-line body blocks and its title and
   subtitle sit exactly 21px HIGHER than Raffeta's (RIGHT, --2),
   which runs 3 lines. The columns were swapped at the user's
   request, so each project kept its own vertical rhythm and only
   the x coordinates changed. Both CTAs share y=664.

   No credits line in this export - the 13 paths are heading + 6 per
   column (title, subtitle, 2 body blocks, CTA label, arrow).
   ============================================================ */
.s3{
  position:relative;
  width:100%;
  height:calc(834px * var(--k));
  overflow:hidden;
  background:#000;
}
.s3__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:834px;
  transform-origin:0 0;
  transform:scale(var(--k));
}

/* -- heading: PP Editorial New Ultralight Italic 82/82.
      Same left as the previous export; the redesign lifts it 46px. -- */
.s3__heading{
  position:absolute;
  left:542px; top:50.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}

/* -- columns are full-artboard groups; children are absolute.

      Both columns are inset:0 and FULLY OVERLAP (each computes to
      0,0,1440,834), so column 2 sits on top of column 1 and swallows
      every click aimed at column 1's "View case study" button — the
      same trap section 6's two blocks have. Neither column needs to be
      hit-testable itself; only its button does. -- */
.s3__col{position:absolute;inset:0;pointer-events:none}
.s3__col .cta{pointer-events:auto}

/* -- media: 352x627 r10. The pattern matrix puts the image at
      -0.34375,0 at 352.686x627 inside a 352x627 frame, which is
      exactly what object-fit:cover computes for a 0.5625 source
      in a 0.5614 box. Both videos are 9:16, so nothing is cropped
      horizontally beyond that 0.34px. -- */
.s3__media{
  position:absolute;
  top:170px;
  width:352px; height:627px;
  border-radius:10px;
  overflow:hidden;
  background:#D9D9D9;
}
.s3__col--1 .s3__media{left:46px}
.s3__col--2 .s3__media{left:777px}
.s3__media video{
  width:100%; height:100%;
  object-fit:cover;
  object-position:center;
  display:block;
}

/* -- title: PP Neue Montreal Medium 40/40 -- */
.s3__title{
  position:absolute;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:500;
  font-size:40px;
  line-height:40px;
  color:#fff;
  white-space:nowrap;
}
.s3__col--1 .s3__title{left:426px;  top:256px}
.s3__col--2 .s3__title{left:1164px; top:277px}

/* -- subtitle: PP Editorial New Ultralight Italic 18/18 -- */
.s3__subtitle{
  position:absolute;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:18px;
  line-height:18px;
  color:#fff;
  white-space:nowrap;
}
.s3__col--1 .s3__subtitle{left:426px;  top:311.5px}
.s3__col--2 .s3__subtitle{left:1164px; top:332.5px}

/* -- body: PP Neue Montreal Book 15/21.
      15px is confirmed by the ink HEIGHT landing on 0.000 for all
      four blocks; weight 400 runs 2-4px wide, so this is Book. -- */
.s3__body{
  position:absolute;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:15px;
  line-height:21px;
  color:#fff;
  white-space:nowrap;
}
.s3__col--1 .s3__body--a{left:426px;  top:417.5px}
.s3__col--1 .s3__body--b{left:426px;  top:518.5px}
.s3__col--2 .s3__body--a{left:1164px; top:433.5px}
.s3__col--2 .s3__body--b{left:1164px; top:511.5px}

/* -- CTA: the shared .cta at its full 165x51 box.
      SVG rect 426.25,664.25 164.5x50.5 + 0.5 stroke from the
      centre = a 165x51 border-box at 426,664. -- */
.s3__col--1 .s3__cta{left:426px;  top:664px}
.s3__col--2 .s3__cta{left:1164px; top:664px}

/* -- reveal masks (vertical clip only) -- */
.s3 .line{display:block;overflow:hidden;margin-left:-14px;padding-left:14px;padding-right:24px}
.s3 .line > span{display:block;will-change:transform}


/* ============================================================
   SECTION 4 — "Social Media"  (artboard 1440 × 900, 4 slides)

   Pinned scroll-driven carousel, same converge/expand blurred
   cross-fade as section 2.

   The frosted panels are baked Figma exports, not backdrop-filter
   (see .s4__panel below). The panel is still a SIBLING of
   .s4__copy rather than a child — the cross-fade animates the
   copy's opacity and the panel is tweened alongside it.
   ============================================================ */
.s4{
  position:relative;
  height:400vh;              /* 100vh visible + 300vh of pinned scroll */
  background:#000;
}
.s4__sticky{
  position:sticky;
  top:0;
  height:100vh;
  overflow:hidden;
  background:#000;
}
.s4__art{
  position:absolute;
  left:50%; top:50%;
  width:1440px; height:900px;
  margin:-450px 0 0 -720px;
  transform:scale(var(--k4));
  transform-origin:50% 50%;
  overflow:hidden;
}
.s4__inner{position:absolute;inset:0}

/* -- shared heading + intro -- */
.s4__heading{
  position:absolute;
  left:507px; top:53.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}
/* centred on the artboard centre (720.04 measured) */
.s4__intro{
  position:absolute;
  left:0; top:141px;
  width:1440px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:18px;
  line-height:25px;
  color:#fff;
  text-align:center;
  white-space:nowrap;
}

/* -- slides -- */
/* plain wrappers — the cube is gone; no perspective or preserve-3d here,
   both of which would force the blurred/faded groups onto a 3D compositing
   path they do not need. */
.s4__deck,.s4__stage{position:absolute;inset:0}
.s4__slide{
  position:absolute;
  inset:0;
  will-change:transform;     /* NOT opacity — see the note above */
}
/* no-JS / pre-JS fallback — GSAP overrides with inline opacity */
.s4__slide[aria-hidden="true"]{opacity:0;pointer-events:none}
.s4__media,.s4__copy{position:absolute;inset:0}

/* every image sits in a clipping frame, positioned in artboard px */
.s4__frame{position:absolute;overflow:hidden}
/* artboard paints the brand logo AFTER the panel — keep it on top */
.s4__logo{z-index:2}
.s4__frame img{position:absolute;max-width:none;display:block}

/* will-change only while something is actually moving — see initSlides4.
   (No backdrop-filter left to drop: the panels are baked images now.) */
.s4.is-moving .s4__media,
.s4.is-moving .s4__copy,
.s4.is-moving .s4__panel{ will-change:transform,opacity,filter; }
.s4:not(.is-moving) .s4__slide,
.s4:not(.is-moving) .s4__media,
.s4:not(.is-moving) .s4__copy{ will-change:auto; }
/* Frosted panels — the real Figma render, exported per slide.

   Figma's Glass material cannot be expressed in CSS, and backdrop-filter was
   only ever an approximation of it. Each panel sits over a FIXED backdrop
   (its own slide), so a baked export is not a compromise — it is exact, and it
   deletes the single most expensive thing on this section: a live
   backdrop-filter re-sampling a large region every scrubbed frame.

   It also retires the backdrop-root fragility entirely — no ancestor's opacity,
   filter or will-change can silently switch this off any more.

   The exports carry blur + tint only: scanning inward from every edge the
   luminance is flat, so there is no specular rim, and the rounded corners are
   baked into the alpha. The approximated 1px rim and inset "light from −45°"
   shadows that used to live here have been removed to match. */
.s4__panel{
  position:absolute;
  pointer-events:none;
  border-radius:inherit;
  backdrop-filter:blur(26px);
  -webkit-backdrop-filter:blur(26px);
}

/* -- body copy: PP Neue Montreal Regular 18/27 -- */
.s4__body{
  position:absolute;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:15px;
  line-height:23px;
  color:#fff;
  white-space:nowrap;
}

/* -- slide 4's wordmark: PP Editorial New Italic 20 -- */
.s4__mark{
  position:absolute;
  margin:0;                        /* left/top set inline per slide */
  font-family:'PP Editorial New',Georgia,serif;
  font-style:normal;               /* upright on the new artboard, not italic */
  font-weight:400;
  font-size:15px;
  line-height:15px;
  color:#fff;
  white-space:nowrap;
}

/* ============================================================
   SECTION 5 — "Visual Exploration"  (artboard 1440 × 900)

   Not pinned. Like section 3 it scales to WIDTH and simply
   scrolls past, so there is no letterbox.
   Solved against the outlines, all on round values:
     heading  Editorial New Ultralight Italic 82/82  @ 422, 76.5
     intro    Neue Montreal Book 16/22              @ 259.31, 747.5
     button   the shared .cta, 134 wide instead of 165
   ============================================================ */
.s5{
  position:relative;
  width:100%;
  height:calc(900px * var(--k));
  overflow:hidden;
  background:#000;
}
.s5__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:900px;
  transform-origin:0 0;
  transform:scale(var(--k));
}
.s5__heading{
  position:absolute;
  left:422px; top:76.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}
/* the artboard's translucent slab behind the three posters */
.s5__card{
  position:absolute;
  left:164px; top:189px;
  width:1112px; height:637px;
  border-radius:10px;
  background:rgba(73,65,65,.2);   /* #494141 @ 20% */
}
.s5__frame{position:absolute;overflow:hidden}
.s5__frame img{position:absolute;max-width:none;display:block}
.s5__intro{
  position:absolute;
  left:259.31px; top:747.5px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:16px;
  line-height:22px;
  color:#fff;
  white-space:nowrap;
}
/* same component as sections 2/3, narrower box */
.s5__cta{ left:1062px; top:745px; width:134px }
.s5__cta .label{ left:19.5px; top:17.99px }
.s5__cta .arrow{ left:102.5px; top:21.5px }

/* reveal mask — vertical clip only. "Exploration" is italic and its final
   'n' overhangs the advance width, so bleed right or it gets sliced. */
.s5 .line{display:block;overflow:hidden;margin-left:-14px;padding-left:14px;padding-right:22px}
.s5 .line > span{display:block;will-change:transform}

/* ============================================================
   SECTION 6 — "Visual Exploration", continued  (artboard 1440 × 1800)

   Two stacked blocks on one artboard: a fanned deck of five 16:9
   frames, then four 9:16 reel thumbnails. Each block has its own
   copy line and "View more" button.

   Not pinned — scales to WIDTH like sections 3 and 5 and scrolls.
   Type is identical to section 5 (same chapter), and both buttons
   are the shared .cta at 134 wide.
   ============================================================ */
.s6{
  position:relative;
  width:100%;
  height:calc(1700px * var(--k));
  overflow:hidden;
  background:#000;
}
.s6__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:1700px;
  transform-origin:0 0;
  transform:scale(var(--k));
}
.s6__block{position:absolute;inset:0}
/* The section-6 heading was removed — it repeated section 5's "Visual
   Exploration" verbatim. Rule kept, unused, in case it comes back. */
.s6__heading{
  position:absolute;
  left:422px; top:76.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}
/* the drop shadows are inline per frame — Figma's feGaussianBlur
   stdDeviation is HALF the CSS blur radius, hence 4.4 → 8.8px.
   They sit on pure black, so they read as almost nothing; kept for
   fidelity rather than effect. */
.s6__frame{position:absolute;overflow:hidden}
.s6__frame img{position:absolute;max-width:none;display:block}
/* ---- reels row: right-to-left auto marquee ------------------------
   Replaces the fanned four-thumbnail arrangement with one continuous
   strip of uniform 9:16 tiles, per the user's new design.

   Seamlessness is geometry, not trickery: the track holds THREE copies
   of the 15-tile set and travels exactly ONE set width (15 x 319 =
   4785), so the frame at the end of the loop is identical to the frame
   at the start. Same recipe as the logofolio rows.

   The wrapper clips to the artboard so the strip bleeds off both edges
   instead of widening the page. */
.s6__reels{
  position:absolute;
  left:0; top:882px;
  width:1440px; height:514px;
  overflow:hidden;
}
.s6__track{
  position:absolute;
  left:0; top:0;
  height:514px;
  display:flex;
  will-change:transform;
}
.s6__set{ display:flex; flex:0 0 auto }
.s6__set > .s6__tile{ margin-right:30px }      /* GAP - part of the 319 pitch */
.s6__tile{
  flex:0 0 auto;
  width:289px; height:514px;
  border-radius:10px;
  overflow:hidden;
  background:#111;
}
.s6__tile img{
  width:100%; height:100%;
  object-fit:cover;
  display:block;
}

.s6__intro{
  position:absolute;
  left:251.31px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:16px;
  line-height:22px;
  color:#fff;
  white-space:nowrap;
}
.s6__intro--a{ top:606.5px }
.s6__intro--b{ top:1501.5px }
.s6__cta{ left:1054px; width:134px }
.s6__cta--a{ top:604px }
.s6__cta--b{ top:1499px }
.s6__cta .label{ left:19.5px; top:17.99px }
.s6__cta .arrow{ left:102.5px; top:21.5px }

/* vertical clip only — the heading is italic and overhangs its advance */
.s6 .line{display:block;overflow:hidden;margin-left:-14px;padding-left:14px;padding-right:22px}
.s6 .line > span{display:block;will-change:transform}

/* The two section-6 blocks are both inset:0 and FULLY OVERLAP, so the reels
   block sits on top of the deck and swallows pointer events aimed at it —
   including clicks on the deck's own "View more" button. Neither block needs to
   be hit-testable itself; only its button does. */
.s6__block{position:absolute;inset:0;pointer-events:none}
.s6__cta{pointer-events:auto}

/* The artboard's own drop shadows, moved out of inline style earlier.
   Keyed to the SLOT, not the card: a promoted card takes over the slot's
   shadow rather than carrying its own across. data-slot is authored in the
   markup, so the resting state is correct with no JS. */
.s6__frame[data-slot="r1"]  { box-shadow:0 0 8.8px rgba(0,0,0,.25) }
.s6__frame[data-slot="l1"]  { box-shadow:0 0 6.2px rgba(0,0,0,.48) }
.s6__frame[data-slot="hero"]{ box-shadow:0 0 10px  rgba(0,0,0,.53) }

/* ---- hover-to-promote, deck block only -----------------------------
   The resting state is the untouched artboard: no transform, no blur,
   nothing moves until the cursor reaches a card. Hovering a card swaps
   it with whatever holds the hero slot; leaving the deck resets it.
   Click and keyboard still work, for touch and for focus navigation.
   The block itself stays pointer-events:none (it overlaps the reels
   block); only the frames opt back in. */
.s6__block--deck .s6__frame{ pointer-events:auto; cursor:pointer }
.s6__block--deck .s6__frame:focus-visible{
  outline:2px solid #fff; outline-offset:3px;
}
/* only ever applied while a card is promoted */
.s6__frame--dim{ filter:blur(4px) }
.s6__block--deck .s6__frame{ transition:filter .6s cubic-bezier(.4,0,.2,1) }

@media (prefers-reduced-motion:reduce){
  .s6__block--deck .s6__frame{ transition:none }
}


/* section 2 card frames — one clipping box per layered image */
.s2__frame{position:absolute;overflow:hidden}
.s2__frame img,.s2__frame video{position:absolute;max-width:none;display:block}
/* The media box the user set in Figma: 995x645, centred on the 904x584 card
   ((904-995)/2 = -45.5, (584-645)/2 = -30.5) and clipped by the frame.
   These clips are 9:16, so covering a 1.54:1 box draws them 995x1768.89 and
   shows the middle 36% of the frame height. Chosen over `contain` (which fit
   the whole frame into a 328.5x584 strip) so the card reads full-bleed. */
.s2__frame video.s2__fill{
  position:absolute;
  left:-45.5px; top:-30.5px;
  width:995px; height:645px;
  object-fit:cover;
  object-position:center;
}

/* 5% film grain — Bloom & Body and Fire Island cards only */
.s2__frame--grain::after{
  content:'';
  position:absolute;
  inset:0;
  z-index:3;
  pointer-events:none;
  opacity:.05;
  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='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:200px 200px;
  animation:s2-grain .6s steps(1) infinite;
}
@keyframes s2-grain{
  0%   { background-position:   0px   0px }
  12.5%{ background-position: -37px  22px }
  25%  { background-position:  61px -18px }
  37.5%{ background-position: -84px -49px }
  50%  { background-position:  29px  73px }
  62.5%{ background-position: -55px  41px }
  75%  { background-position:  92px -66px }
  87.5%{ background-position: -13px -91px }
}
@media (prefers-reduced-motion:reduce){
  .s2__frame--grain::after{ animation:none }
}



/* ============================================================
   SECTION 7 — "The Logofolio"  (artboard 1440 × 900)

   Two rows of 222×222 tiles at a 272px pitch, drifting in
   opposite directions. Not pinned — scales to WIDTH and scrolls.

   Each tile is a flattened render of the Figma tile: the artboard
   builds them from a base rect, a masked photo, an inner-shadow
   filter and a logo overlay, all at per-tile opacities. Rebuilding
   that stack in CSS would be guesswork; baking it is exact.
   ============================================================ */
.s7{
  position:relative;
  width:100%;
  height:calc(900px * var(--k));
  overflow:hidden;
  background:#000;
}
.s7__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:900px;
  transform-origin:0 0;
  transform:scale(var(--k));
}
.s7__heading{
  position:absolute;
  left:513px; top:76.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}
.s7__intro{
  position:absolute;
  left:0; top:182px;
  width:1440px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:18px;
  line-height:25px;
  color:#fff;
  text-align:center;
  white-space:nowrap;
}

/* -- the two marquee rows -- */
.s7__row{
  position:absolute;
  left:0; width:1440px; height:222px;
  overflow:hidden;                 /* the artboard is the window */
}
.s7__row--1{ top:287px }
.s7__row--2{ top:565px }
/* The track is wider than the row and holds three copies of the set, so a
   shift of exactly one set width lands on an identical frame — that is what
   makes the loop seamless rather than snapping. */
.s7__track{
  position:absolute;
  top:0;
  display:flex;
  gap:50px;                        /* 272 pitch − 222 tile */
  will-change:transform;
}
.s7__tile{
  flex:0 0 auto;
  width:222px; height:222px;
  border-radius:10px;
  overflow:hidden;
}
.s7__tile img{
  width:100%; height:100%;
  object-fit:cover;
  display:block;
}
@media (prefers-reduced-motion:reduce){
  .s7__track{ will-change:auto }
}

/* reveal mask — vertical clip only; the heading is italic and overhangs */
.s7 .line{display:block;overflow:hidden;margin-left:-14px;padding-left:14px;padding-right:22px}
.s7 .line > span{display:block;will-change:transform}

/* ============================================================
   SECTION 8 — "Image compositing"  (artboard 1440 × 900)

   Two before/after cards with a draggable divider. Not pinned —
   scales to WIDTH and scrolls.

   The 'before' layer keeps the artboard's own placement, stretch
   included: the raw photo is landscape and the card is portrait,
   and Figma scaled it non-uniformly to fit. Reproduced verbatim at
   the user's instruction ("just do it like i did"). One consequence
   worth knowing: that placement only spans 275 of the card's 456px,
   so the divider's travel is clamped in JS to where the image
   actually reaches — otherwise dragging further would expose bare
   card.
   ============================================================ */
.s8{
  position:relative;
  width:100%;
  height:calc(900px * var(--k));
  overflow:hidden;
  background:#000;
}
.s8__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:900px;
  transform-origin:0 0;
  transform:scale(var(--k));
}
.s8__heading{
  position:absolute;
  left:432px; top:76.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}
.s8__intro{
  position:absolute;
  left:0; top:182px;
  width:1440px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:18px;
  line-height:25px;
  color:#fff;
  text-align:center;
  white-space:nowrap;
}

/* -- the comparison cards -- */
.s8__card{
  position:absolute;
  overflow:hidden;
  cursor:ew-resize;
  touch-action:pan-y;              /* let the page still scroll vertically */
  user-select:none;
}
.s8__card img{position:absolute;max-width:none;display:block;pointer-events:none}
/* the 'before' half: only its WIDTH changes, so the image inside never moves */
.s8__before{
  position:absolute;
  left:0; top:0; bottom:0;
  overflow:hidden;
}
.s8__divider{
  position:absolute;
  top:0; bottom:0;
  width:2px;
  margin-left:-1px;                /* the artboard's line is centred on the split */
  background:#fff;
  pointer-events:none;             /* the whole card is the drag target */
}
/* keyboard users still get a target, but nothing is drawn until it is focused */
.s8__divider:focus-visible{
  outline:2px solid #fff;
  outline-offset:4px;
}

/* reveal mask — vertical clip only; the heading is italic and overhangs */
.s8 .line{display:block;overflow:hidden;margin-left:-14px;padding-left:14px;padding-right:22px}
.s8 .line > span{display:block;will-change:transform}

/* ============================================================
   SECTION 9 — "Print & Collateral"  (artboard 1440 × 900)
   Not pinned — scales to WIDTH and scrolls.
   ============================================================ */
.s9{
  position:relative;
  width:100%;
  height:calc(900px * var(--k));
  overflow:hidden;
  background:#000;
}
.s9__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:900px;
  transform-origin:0 0;
  transform:scale(var(--k));
}
.s9__heading{
  position:absolute;
  left:454px; top:58.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:82px;
  line-height:82px;
  color:#fff;
  white-space:nowrap;
}
/* the artboard sets the ampersand smaller than the caps — solved at 50.5px,
   which lands the ink width on 540.64 exactly */
.s9__heading .amp{ font-size:50.5px }

.s9__intro{
  position:absolute;
  left:452.44px; top:152px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:18px;
  line-height:25px;
  color:#fff;
  white-space:nowrap;
}
.s9__frame{position:absolute;overflow:hidden}
.s9__frame img{position:absolute;max-width:none;display:block}

/* translucent slab over the card, left side */
.s9__panel{
  position:absolute;
  left:154px; top:339px;
  width:334px; height:429px;
  border-radius:10px;
  background:rgba(24,24,24,.15);   /* #181818 @ 15% */
  pointer-events:none;
}
.s9__logo{ z-index:2 }
.s9__body{
  position:absolute;
  left:193px; top:520px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:15px;
  line-height:26px;
  color:#fff;
  white-space:nowrap;
  z-index:2;
}
/* the shared .cta, at this section's smaller box */
.s9__cta{ left:257px; top:668px; width:129px; height:54px; border-radius:11px; z-index:2 }
.s9__cta .label{ left:17.5px; top:18.99px }
.s9__cta .arrow{ left:95.5px; top:21.5px }

/* reveal mask — vertical clip only; the heading is italic and overhangs */
.s9 .line{display:block;overflow:hidden;margin-left:-14px;padding-left:14px;padding-right:22px}
.s9 .line > span{display:block;will-change:transform}

/* ============================================================
   SECTION 10 — "About"  (artboard 1440 × 1450)
   The closing section: bio, experience, expertise, contact links.
   All type, no imagery. Not pinned — scales to WIDTH.
   ============================================================ */
.s10{
  position:relative;
  width:100%;
  height:calc(1450px * var(--k));
  overflow:hidden;
  background:#000;
}
.s10__art{
  position:absolute;
  left:0; top:0;
  width:1440px; height:1450px;
  transform-origin:0 0;
  transform:scale(var(--k));
}
/* the artboard lifts the whole panel slightly off black */
.s10__wash{
  position:absolute; inset:0;
  background:#1A1A1A;
  opacity:.6;
}
/* left column labels — Editorial New Ultralight Italic 30 */
.s10__label{
  position:absolute;
  left:74px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:30px;
  line-height:30px;
  color:#fff;
  white-space:nowrap;
}
/* right column — Neue Montreal Book 18 throughout */
.s10__bio,.s10__job,.s10__list{
  position:absolute;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:18px;
  color:#fff;
  white-space:nowrap;
}
.s10__bio{ left:678.86px; top:89.5px; line-height:32px }
.s10__job{ left:680px; line-height:18px }         /* top set inline per role */
.s10__list{ line-height:42px }
.s10__list--1{ left:678.79px; top:1033.5px }
.s10__list--2{ left:1065px;   top:1033.5px }

/* contact links — the label is Editorial italic 15, the arrow points up-right */
/* role dates and the closing colophon — both carried by opacity in the
   artboard, not a different fill colour */
.s10__date{
  position:absolute;
  left:680px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:350;
  font-size:15px;
  line-height:15px;
  color:#fff;
  opacity:.65;
  white-space:nowrap;
}
.s10__colophon{
  position:absolute;
  left:707px; top:1383.49px;
  margin:0;
  font-family:'PP Neue Montreal',Helvetica,Arial,sans-serif;
  font-weight:400;
  font-size:15px;
  line-height:15px;
  color:#fff;
  opacity:.4;
  white-space:nowrap;
}
.s10__link{
  position:absolute;
  top:1384.5px;
  margin:0;
  font-family:'PP Editorial New',Georgia,serif;
  font-style:italic;
  font-weight:200;
  font-size:15px;
  line-height:15px;
  color:#fff;
  white-space:nowrap;
  text-decoration:none;
}
.s10__link:hover{ text-decoration:underline; text-underline-offset:3px }
.s10__link:focus-visible{ outline:2px solid #fff; outline-offset:4px }
.s10__arrow{
  position:absolute;
  top:2.33px;
  overflow:visible;
}
