/* ══════════════════════════════════════════════════════════════
   MARTIAN — Independent Digital Design Studio
   Section 1 only. Hand-written CSS, motion by GSAP.

   Reference values measured from Aries home-1 rendered locally:
     hero heading  158.4px at 1440 wide (= 11vw), letter-spacing -11.04px
     hero image    360×450 at rest → 100vw/100vh on load
     palette       #121212 · #FBFBFB · #FF7E5D · #ED5145
   ══════════════════════════════════════════════════════════════ */

:root{
  --ink:    #121212;
  --ink-2:  #1A1A1A;
  --pearl:  #FBFBFB;
  --dim:    #8B8781;
  --oxide:  #C1440E;
  --flare:  #FF7E5D;
  --line:   rgba(251,251,251,.13);
  --line-2: rgba(251,251,251,.07);

  --sans: 'Satoshi', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --disp: 'General Sans', 'Satoshi', ui-sans-serif, system-ui, sans-serif;
  /* Micro-labels — descriptor, marquees, section numbers, categories.
     Was a system monospace stack: too thin, too small, and it made the
     descriptor read as the same object as the tickers. Now Satoshi at 600,
     larger, with the tracking pulled back from .28em to .14em. */
  --mic: 'Satoshi', ui-sans-serif, system-ui, -apple-system, sans-serif;

  /* Aries runs 11vw on a 15-character headline. MARTIAN is 7 characters, so
     the same vw would look half the size. Solved as a line through two
     measured points instead, holding the same share of the container at 320
     and at 1440 — a single vw term can only satisfy one end. */
  --t-hero: clamp(2.85rem, calc(18.4vw - 12px), 16rem);
  --t-mic:  clamp(.78rem, .92vw, .92rem);

  /* One shadow recipe for any white type sitting on the photograph. The
     backdrop under the hero runs L=0.00 to L=0.91 — no flat colour survives
     that, so white carries its own dark ground: a tight 1px core to hold the
     letterforms against blown highlights, then two soft halos to seat it. */
  --lift: 0 1px 2px rgba(0,0,0,.85),
          0 2px 10px rgba(0,0,0,.62),
          0 6px 34px rgba(0,0,0,.48);

  --gut: clamp(20px, 5vw, 72px);
  --ease: cubic-bezier(.22,.61,.36,1);
}

*,*::before,*::after{ box-sizing:border-box; }
/* NO scroll-behavior:smooth. Lenis runs its own scroll animation, and the
   two fight for the same frame — anchor jumps come out jittery because
   both are animating scrollTop at once. Anchors are routed through
   lenis.scrollTo() instead, which also carries the header offset that
   scroll-padding-top used to provide. */
html{ -webkit-text-size-adjust:100%; }
body{
  margin:0; background:var(--ink); color:var(--pearl);
  font-family:var(--sans); font-size:clamp(.95rem,1.05vw,1.08rem); line-height:1.62;
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
}
h1{ margin:0; font-family:var(--disp); font-weight:700; letter-spacing:-.035em; line-height:1.03; }
p{ margin:0; }
a{ color:inherit; text-decoration:none; }
img{ display:block; max-width:100%; }
::selection{ background:var(--oxide); color:#fff; }

/* The single gutter system. Every content section sits in one of these.
   One source of truth for horizontal rhythm — never a second padded
   element nested inside, which is how gutters silently get applied twice
   and cost 60–70px of reading width on a phone. */
.wrap{ max-width:1440px; width:100%; margin-inline:auto; padding-inline:var(--gut); }

/* ═══ BUTTON — mask wipes up from the bottom ═══ */
.btn{
  position:relative; display:inline-flex; align-items:center; justify-content:center;
  border:1px solid var(--line); border-radius:100px; overflow:hidden;
  padding:14px 26px; min-height:46px; font-size:.92rem; white-space:nowrap;
  transition:border-color .4s var(--ease);
}
.btn__mask{ position:absolute; inset:auto 0 0 0; height:100%; background:var(--pearl);
  transform:translateY(101%); transition:transform .5s var(--ease); }
.btn__t{ position:relative; z-index:1; transition:color .35s var(--ease); }
.btn:hover{ border-color:var(--pearl); }
.btn:hover .btn__mask{ transform:translateY(0); }
.btn:hover .btn__t{ color:var(--ink); }

/* ═══ NAV ═══ */
.nav{
  position:fixed; top:0; left:0; right:0; z-index:70;
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  padding:16px var(--gut);
  transition:transform .5s var(--ease);
}
.nav.is-up{ transform:translateY(-115%); }
.nav__mark{ display:flex; align-items:center; gap:10px; min-height:44px;
  font-family:var(--disp); font-weight:700; font-size:1.02rem; letter-spacing:.01em;
  text-shadow:0 2px 10px rgba(0,0,0,.5); }

/* The hero is now a PALE photograph, so white nav text disappears against it.
   JS adds .is-onLight while the hero is in view and removes it after. */
.nav.is-onLight .nav__mark,
.nav.is-onLight .nav__link{ color:var(--ink); text-shadow:0 1px 8px rgba(255,255,255,.55); }
.nav.is-onLight .nav__link{ color:rgba(18,18,18,.68); }
.nav.is-onLight .nav__link:hover{ color:var(--ink); }
.nav.is-onLight .btn{ border-color:rgba(18,18,18,.28); color:var(--ink); }
.nav.is-onLight .btn__mask{ background:var(--ink); }
.nav.is-onLight .btn:hover{ border-color:var(--ink); }
.nav.is-onLight .btn:hover .btn__t{ color:var(--pearl); }
.nav.is-onLight{ background:linear-gradient(to bottom, rgba(217,217,215,.9), rgba(217,217,215,0)); }
/* The ™ must live INSIDE .nav__word, not as a direct child of .nav__mark —
   .nav__mark is a flex row with gap:10px, so a bare <sup> becomes a flex
   item and inherits that 10px as a visible space before the symbol. */
.nav__word{ display:inline-block; white-space:nowrap; }
.nav__word sup{ font-size:.5em; top:-.62em; opacity:.6; margin-left:.02em; letter-spacing:0; }
.nav__dot{ width:7px; height:7px; border-radius:50%; background:var(--flare); animation:ping 3.4s infinite; }
/* 2-keyframe outward ping — reads as a signal, not as breathing */
@keyframes ping{ 0%{ box-shadow:0 0 0 0 rgba(255,126,93,.5);} 100%{ box-shadow:0 0 0 9px rgba(255,126,93,0);} }
.nav__right{ display:flex; align-items:center; gap:6px; }
.nav__link{ display:none; align-items:center; min-height:44px; padding:0 15px;
  color:rgba(251,251,251,.72); font-size:.9rem; transition:color .3s var(--ease);
  text-shadow:0 2px 10px rgba(0,0,0,.5); }
.nav__link:hover{ color:var(--pearl); }
@media (min-width:820px){ .nav__link{ display:flex; } }

/* ═══ 1 · HERO ═══════════════════════════════════════════════
   The stage RESTS at its finished size. JS shrinks it to the opening
   4:5 shape only once GSAP has confirmed it loaded, then plays it open.
   A blocked script therefore leaves a correct full-bleed hero rather
   than a small rectangle stranded mid-animation. */
.hero{ position:relative; height:100svh; overflow:hidden; display:grid; place-items:center; }
.hero__stage{
  position:absolute; top:50%; left:50%; transform:translate(-50%,-50%);
  width:100vw; height:100svh; border-radius:0;
  overflow:hidden; will-change:width,height;
}
.hero__stage img{ width:100%; height:100%; object-fit:cover; object-position:center 20%; }

/* No scrim on the light hero. The previous photograph measured L = 0.024 —
   near-black — which is why it needed 62%. This one is pale, and a scrim
   here would grey out the face and defeat the point of the portrait. */
.hero--light{ background:#D9D9D7; }

/* THE WORDMARK INVERTS THE PHOTOGRAPH.
   Measured across the band the headline occupies, the image runs from
   L = 0.001 (visor) to L = 0.811 (background). Against that range:
       plain white text  worst case 1.18:1   fails
       plain dark text   worst case 1.10:1   fails
   No single colour survives. mix-blend-mode:exclusion with white gives
   result = 1 − backdrop, a per-pixel inversion, so contrast becomes
   |1 − 2L| and adapts to whatever is underneath: near-black over the pale
   ground, near-white across the visor, cyan across the orange suit.

   Its one blind spot is L ≈ 0.5, where the inversion matches the backdrop.
   That is 3.3% of pixels in this band — isolated patches, not a region.

   TWO THINGS MUST BE TRUE or this silently renders as flat white:
     1. NO isolation:isolate here — that isolates the element FROM its
        backdrop, which is the exact opposite of what blending needs.
     2. No ancestor between this and the photograph may create a stacking
        context. .hero__over previously carried z-index:2, which did, so
        the blend had only transparency to work against. It is z-index:auto
        now and still paints above the image, because both sit in the same
        stacking context and it comes later in the DOM. */
.hero__blend{ mix-blend-mode:exclusion; }

.hero__over{ position:relative; text-align:center; padding-inline:var(--gut); width:100%; }
.hero__h1{
  font-size:var(--t-hero); line-height:.9; letter-spacing:-.055em; color:var(--pearl);
  white-space:nowrap;          /* characters are individually wrapped for the reveal */
  /* Pure white and NO shadow. Under exclusion a shadow would be inverted too
     and would smear a halo around every letter. The blend is the contrast. */
  color:#fff; text-shadow:none;
}
.hero__h1 .ch{ display:inline-block; }
/* ™ is simply the 8th character of the wordmark, so it splits and rises with
   the rest — one tween, no separate treatment. Styled as a superscript here
   rather than with a <sup>. */
.hero__h1 .ch:last-child{
  font-size:.2em; vertical-align:super; opacity:.72;
  margin-left:-.03em; letter-spacing:0;
}
/* Identity descriptor — sits directly under the wordmark, small and quiet.
   It says who we are. The line beneath it says what the client gets. */
.hero__desc{
  margin-top:clamp(10px,1.8vh,20px);
  font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.14em; text-transform:uppercase;
  color:rgba(251,251,251,.94); text-shadow:var(--lift);
}
/* The promise. Larger than the descriptor because this is the line that
   has to do the selling. */
.hero__tag{
  margin-top:clamp(18px,3vh,34px);
  font-family:var(--disp); font-weight:500;
  font-size:clamp(1.02rem,1.75vw,1.6rem); letter-spacing:-.018em; line-height:1.3;
  color:var(--pearl); max-width:22ch; margin-inline:auto;
  text-shadow:var(--lift);
}
.hero__foot{ position:absolute; inset:auto 0 clamp(86px,11vh,124px) 0; z-index:2; display:grid; place-items:center; }

/* ═══ MARQUEE — fixed window, nowrap track, seamless -50% loop ═══ */
.marquee{
  width:min(23rem,80vw); overflow:hidden;
  mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 14%,#000 86%,transparent);
}
.marquee__track{
  display:flex; align-items:center; gap:1rem; white-space:nowrap; width:max-content;
  animation:slide 15s linear infinite;
  font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.16em; text-transform:uppercase;
  color:rgba(251,251,251,.7); text-shadow:0 2px 8px rgba(0,0,0,.6);
}
/* the hero marquee sits on the photograph, so it takes the same white-on-lift
   treatment as the descriptor and tagline rather than dark ink */
.hero .marquee__track{ color:rgba(251,251,251,.92); text-shadow:var(--lift); }
.marquee__track i{ width:5px; height:5px; border-radius:50%; background:var(--flare); flex:0 0 5px; }
@keyframes slide{ to{ transform:translateX(-50%); } }

/* ═══ 2 · STATEMENT ═══════════════════════════════════════════
   Type measured off the reference: 3.05vw / line-height 1.22 /
   tracking -0.58px at 1440 (= -0.0132em) / Satoshi 400.
   Floored and capped so it stays readable below 900 and does not run
   away on ultrawide — the reference has no cap and gets very large. */
.say{ padding-block:clamp(96px,16vh,220px) clamp(96px,14vh,190px); }
.marquee--say{ margin:0 auto clamp(40px,7vh,90px); }
.say__big{
  margin:0; font-family:var(--sans); font-weight:400;
  font-size:clamp(1.6rem, 3.05vw, 3.4rem);
  line-height:1.22; letter-spacing:-.0132em;
  color:var(--pearl);
  /* ~42 characters per line, measured off the reference (its first line
     "We blend creativity with purpose, creating" is 42). At 24ch the
     highlighted phrase wrapped at every width, which it must not do on
     desktop. */
  max-width:26ch;
  text-wrap:balance;
}
.say__big .w{ display:inline-block; }

/* Supporting line — deliberately smaller so the statement above carries the
   weight and this reads as continuation rather than a second headline. */
.say__sub{
  margin-top:clamp(22px,3.2vh,40px);
  font-size:clamp(1.02rem,1.45vw,1.3rem); line-height:1.55;
  color:rgba(251,251,251,.66); max-width:46ch;
}

/* Sweeps LEFT TO RIGHT, like a marker drawn across the words — not
   downward. background-size grows 0% → 100% from the left edge, and the
   text travels grey → near-black as the coral passes under it.
   box-decoration-break:clone gives one box per line when it wraps, which
   is what happens on a phone. */
.hl{
  font-style:normal;
  background-image:linear-gradient(var(--flare),var(--flare));
  background-repeat:no-repeat;
  background-position:0 50%;
  background-size:0% 100%;
  box-decoration-break:clone; -webkit-box-decoration-break:clone;
  padding:.02em .11em; margin:0 -.05em;
}

/* ═══ 3 · WHAT YOU GET ════════════════════════════════════════
   Reference at 1440: 528px columns, 112px column-gap, 128px row-gap,
   every second item pushed down 192px. At 411: one column, 48px gap,
   stagger removed. Expressed fluidly here so it holds between those
   two measured points instead of snapping at a breakpoint. */
.cards{ padding-bottom:clamp(96px,16vh,220px); }
/* Two staggered columns, capped at the reference's own measure —
   528 + 112 + 528 = 1168. Left to fill the 1296px wrap the columns reach
   592px, which at a 5:7 aspect makes each card 812px tall and pushes its
   heading off a 900px screen. */
.cards__grid{ display:grid; grid-template-columns:1fr; gap:clamp(48px,7vw,128px);
              max-width:1168px; margin-inline:auto; }
@media (min-width:900px){
  .cards__grid{
    grid-template-columns:1fr 1fr;
    column-gap:clamp(56px,7.8vw,112px);
    row-gap:clamp(64px,8.9vw,128px);
  }
  /* the measured 12rem offset, dropped in a single column where it would
     only add dead space */
  .cards__grid .card:nth-child(2n){ margin-top:clamp(96px,13.3vw,192px); }
}
/* In one column a card would stretch the full gutter width — at 768 that
   makes a 691×948 image, taller than the screen. */
@media (max-width:899px){ .card{ max-width:520px; } }

.card__media{
  position:relative; overflow:hidden; border-radius:.4rem;
  aspect-ratio:504/691;                 /* 5:7, measured */
  background:var(--ink-2);
  margin-bottom:clamp(20px,2.6vw,34px);
}
.card__media img{ width:100%; height:100%; object-fit:cover; object-position:top center; }
/* Bottom-anchored, resting RETRACTED so a blocked script leaves the images
   visible rather than buried under solid coral. JS re-covers it once GSAP
   is confirmed loaded, then collapses it downward. */
.card__mask{ position:absolute; inset:auto 0 0 0; height:0; background:var(--flare); z-index:2; }

.card__n{
  display:block; font-family:var(--mic); font-weight:600; font-size:var(--t-mic);
  letter-spacing:.2em; color:var(--flare); margin-bottom:clamp(10px,1.2vw,16px);
}
.card__h{
  font-family:var(--disp); font-weight:600; letter-spacing:-.028em; line-height:1.12;
  font-size:clamp(1.35rem,2.1vw,1.95rem); color:var(--pearl);
  margin-bottom:clamp(10px,1.2vw,16px); max-width:20ch;
}
.card__p{
  font-size:clamp(.98rem,1.53vw,1.375rem);   /* 22px at 1440, measured */
  line-height:1.5; color:rgba(251,251,251,.66); max-width:34ch;
}
/* The one place the technical approach is stated. Once, quietly, as a
   supporting detail — never as the product. */
.card__note{
  margin-top:clamp(10px,1.1vw,14px);
  font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.14em;
  text-transform:uppercase; color:rgba(251,251,251,.42);
}

/* ═══ 4 · APPROACH ════════════════════════════════════════════
   The reference uses a fixed 250rem (4000px) track at both breakpoints.
   Matched, but floored against viewport height so a very tall screen
   doesn't end up with less scroll than the animation needs. */
.apr{ position:relative; height:max(250rem, 420svh); }
.apr__stage{
  position:sticky; top:0; height:100svh; overflow:hidden;
  display:flex; flex-direction:column; justify-content:center;
  gap:clamp(24px,5vh,56px);
}

.apr__field{ position:absolute; inset:0; }
.apr__ph{
  position:absolute; object-fit:cover; border-radius:.35rem;
  filter:blur(6px) saturate(.55); opacity:.5;
  will-change:transform;
}
/* corner positions, each bleeding off its edge — measured from the reference */
.apr__ph.is-1{ width:259px; height:259px; left:-29px;  top:5%;   }
.apr__ph.is-2{ width:259px; height:259px; left:-86px;  bottom:8%; }
.apr__ph.is-3{ width:288px; height:259px; right:-58px; top:-8%;  }
.apr__ph.is-4{ width:288px; height:259px; right:-25px; bottom:12%; }
/* the reference drops half the field below 900 */
@media (max-width:899px){
  .apr__ph{ width:200px !important; height:180px !important; }
  .apr__ph.is-1, .apr__ph.is-4{ display:none; }
  .apr__ph.is-2{ left:-56px; bottom:6%; }
  .apr__ph.is-3{ right:-40px; top:-4%; }
}

/* exactly the reference's vignette */
.apr__veil{
  position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(var(--ink), rgba(18,18,18,0) 50%, var(--ink));
}

.apr__rail{ position:relative; z-index:2; }
.apr__line{
  margin:0; font-family:var(--sans); font-weight:700;
  font-size:clamp(3.2rem, 14.1vw, 13rem);   /* 203.04px @1440, measured */
  line-height:1; letter-spacing:-.02em; text-transform:uppercase;
  color:var(--pearl); white-space:nowrap; width:max-content;
  padding-inline:8vw; will-change:transform;
}
.apr__note{
  position:relative; z-index:2; padding-inline:var(--gut);
  max-width:44ch; font-size:clamp(.95rem,1.11vw,1rem);   /* 16px @1440 */
  line-height:1.6; color:rgba(251,251,251,.62);
}

/* ═══ 5 · LIGHT INVERSION ═════════════════════════════════════
   Measured: #FBFBFB ground, #1A1A1A text. The whole page flips. */
.light{ background:var(--pearl); color:var(--ink-2); padding-block:clamp(90px,14vh,180px) clamp(70px,11vh,140px); }
.marquee--dark{ margin:0 auto clamp(34px,5vh,64px); }
.marquee--dark .marquee__track{ color:rgba(18,18,18,.5); text-shadow:none; }
.light__big{
  margin:0; font-family:var(--disp); font-weight:600;
  font-size:clamp(2rem,5.2vw,4.4rem); line-height:1.06; letter-spacing:-.04em;
  color:var(--ink-2); max-width:20ch;
}
.light__big .w{ display:inline-block; }
.light__sub{
  margin-top:clamp(20px,3vh,36px); max-width:52ch;
  font-size:clamp(1rem,1.4vw,1.25rem); line-height:1.55; color:rgba(18,18,18,.62);
}

/* ═══ 6–8 · PROJECTS ══════════════════════════════════════════
   Sticky stack: each item pins at top:0 and the next scrolls over it.
   Measured — this is CSS alone, the reference animates nothing here. */
.works{ background:var(--pearl); padding-top:clamp(64px,9vh,128px); }
.work{ position:sticky; top:0; height:100svh; overflow:hidden; }
.work__link{ position:relative; display:block; height:100%; }
.work__link img{ width:100%; height:100%; object-fit:cover; object-position:top center;
  transition:transform 1.2s var(--ease); }
/* These are landscape screenshots of real sites, and every one of them puts
   its logo, headline and copy on the LEFT. Cropping to centre on a narrow
   portrait viewport throws exactly that away and leaves a middle strip of
   background. Anchor to the left edge instead, so what survives the crop is
   the part that identifies the site. */
@media (max-width:899px){
  .work__link img{ object-position:top left;
    /* The reveal scales this image 1.16 -> 1 (app.js). With the default
       50% 50% origin it grows in every direction, so at the moment the wipe
       opens the leftmost ~8% is pushed outside the box — which is exactly
       the strip the line above just anchored. Grow away from the anchored
       corner instead, so the left edge never moves. */
    transform-origin:top left; }
}
.work__link:hover img{ transform:scale(1.035); }
/* Veil strength is per-project, because the three screenshots differ by an
   order of magnitude in the band where the text sits. Measured luminance
   there: Otto De Fiore 0.997 (a near-white page), Black Sovereign 0.318,
   Besuperhuman 0.283.

   At a uniform 0.5 alpha, white type reads 4.76:1 and 5.19:1 on the two
   dark ones and 1.83:1 on Otto — invisible. A single veil heavy enough for
   Otto would crush the other two, so each carries its own. */
/* Coral wipe over each project — the same mechanic as the service cards and
   as the reference's .mask-frame. Bottom-anchored, resting RETRACTED at
   height 0 so a blocked script leaves the photograph visible rather than
   buried under solid colour. JS re-covers it once GSAP is confirmed loaded,
   then collapses it downward.

   z-index 4 puts it ABOVE the veil, the meta text and the number. Below the
   veil the dark gradient paints over it and the coral reads as a grey wash. */
.work__wipe{
  position:absolute; inset:auto 0 0 0; height:0;
  background:var(--flare); z-index:4;
}

.work__veil{
  position:absolute; inset:0; z-index:1;
  --v-top:.45; --v-mid:.06; --v-low:.62; --v-end:.86;
  background:linear-gradient(180deg,
    rgba(18,18,18,var(--v-top)) 0%,
    rgba(18,18,18,var(--v-mid)) 30%,
    rgba(18,18,18,var(--v-low)) 62%,
    rgba(18,18,18,var(--v-end)) 100%);
}
/* a light-ground project — takes white type from 1.83:1 to ~4.3:1 */
.work--light .work__veil{ --v-top:.55; --v-mid:.30; --v-low:.80; --v-end:.95; }

.work__meta{ position:absolute; left:var(--gut); right:var(--gut); bottom:clamp(84px,12vh,128px); z-index:2; max-width:44ch; }
.work__cat{ display:block; font-family:var(--mic); font-weight:600; font-size:var(--t-mic);
  letter-spacing:.19em; text-transform:uppercase; color:rgba(251,251,251,.72);
  margin-bottom:clamp(10px,1.4vh,18px); text-shadow:0 2px 10px rgba(0,0,0,.6); }
.work__name{ font-family:var(--disp); font-weight:600; letter-spacing:-.035em; line-height:1.04;
  font-size:clamp(1.8rem,4.2vw,3.6rem); color:var(--pearl);
  margin-bottom:clamp(10px,1.5vh,18px); text-shadow:0 2px 14px rgba(0,0,0,.55); }
.work__desc{ font-size:clamp(.95rem,1.3vw,1.15rem); line-height:1.55;
  color:rgba(251,251,251,.8); text-shadow:0 2px 10px rgba(0,0,0,.6); }
.work__no{ position:absolute; right:var(--gut); top:clamp(84px,11vh,116px); z-index:2;
  font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.2em;
  color:rgba(251,251,251,.75); text-shadow:0 2px 10px rgba(0,0,0,.6); }

/* Dark pill, white text, 8px radius, 8px/12px padding — measured, not the
   white pill I built before. Desktop pointers only. */
.follow{ position:absolute; inset:0; z-index:3; pointer-events:none; display:none; place-items:center; }
@media (hover:hover) and (pointer:fine){ .follow{ display:grid; } }
.follow__pill{
  background:var(--ink); color:var(--pearl);
  border-radius:8px; padding:8px 12px; font-weight:500; font-size:.92rem; white-space:nowrap;
  opacity:0; transition:opacity .3s var(--ease); will-change:transform;
}
.work__link:hover .follow__pill{ opacity:1; }

/* ═══ 9 · THE APPROACH ════════════════════════════════════════ */
.apch{ padding-block:clamp(90px,15vh,200px); }
.apch__h{ margin:0 0 clamp(26px,4vh,44px); font-family:var(--disp); font-weight:600;
  font-size:clamp(2rem,5.2vw,4.4rem); line-height:1.06; letter-spacing:-.04em; max-width:20ch; }
.apch__p{ max-width:56ch; font-size:clamp(1rem,1.42vw,1.28rem); line-height:1.6;
  color:rgba(251,251,251,.66); }
.apch__p--em{ margin-top:clamp(14px,2vh,22px); color:var(--pearl); }

.prin{ margin-top:clamp(56px,9vh,110px); display:grid; grid-template-columns:1fr; gap:0;
       list-style:none; padding:0; }
.prin__i{ padding-block:clamp(28px,4vh,44px); border-top:1px solid var(--line-2); }
.prin__i:last-child{ border-bottom:1px solid var(--line-2); }
@media (min-width:860px){
  .prin{ grid-template-columns:repeat(3,1fr); column-gap:clamp(32px,4.4vw,64px); }
  .prin__i{ border-bottom:1px solid var(--line-2); }
}
.prin__n{ display:block; font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.2em;
  color:var(--flare); margin-bottom:clamp(10px,1.2vw,16px); }
.prin__h{ font-family:var(--disp); font-weight:600; letter-spacing:-.028em;
  font-size:clamp(1.3rem,2vw,1.8rem); margin-bottom:clamp(8px,1vw,14px); }
.prin__p{ font-size:clamp(.95rem,1.3vw,1.1rem); line-height:1.55; color:rgba(251,251,251,.6); max-width:34ch; }

/* ═══ 10 · METHOD ═════════════════════════════════════════════ */
.mth{ padding-bottom:clamp(90px,15vh,200px); }
.mth__list{ display:grid; grid-template-columns:1fr; list-style:none; padding:0; margin:0; }
@media (min-width:760px){ .mth__list{ grid-template-columns:repeat(2,1fr); column-gap:clamp(40px,6vw,96px); } }
@media (min-width:1180px){ .mth__list{ grid-template-columns:repeat(4,1fr); column-gap:clamp(28px,3.4vw,56px); } }
.mth__i{ padding-block:clamp(26px,3.6vh,40px); border-top:1px solid var(--line); }
/* Each stage carries an image with the same coral wipe as everywhere else,
   so the section reads as finished rather than as a bare list. */
.mth__media{
  position:relative; overflow:hidden; border-radius:.35rem; aspect-ratio:4/3;
  background:var(--ink-2); margin-bottom:clamp(16px,2vw,24px);
}
.mth__media img{ width:100%; height:100%; object-fit:cover; }
.mth__mask{ position:absolute; inset:auto 0 0 0; height:0; background:var(--flare); z-index:2; }
.mth__n{ display:block; font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.2em;
  color:rgba(251,251,251,.4); margin-bottom:clamp(10px,1.2vw,16px); }
.mth__h{ font-family:var(--disp); font-weight:600; letter-spacing:-.028em;
  font-size:clamp(1.2rem,1.85vw,1.6rem); margin-bottom:clamp(8px,1vw,13px); }
.mth__p{ font-size:clamp(.92rem,1.2vw,1.02rem); line-height:1.55; color:rgba(251,251,251,.58); max-width:30ch; }

/* ═══ 11 · FINAL CTA ══════════════════════════════════════════
   Measured: the reference pins this at 100vh with overflow hidden and
   caps the inner block at 720px, resting at opacity 0. */
.last{ position:relative; height:100svh; overflow:hidden; display:grid; place-items:center; }
.last__bg{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; object-position:center 22%; }
.last__scrim{ position:absolute; inset:0;
  background:linear-gradient(180deg, rgba(18,18,18,.86), rgba(18,18,18,.72) 45%, rgba(18,18,18,.94)); }
.last__in{ position:relative; z-index:2; text-align:center; max-width:720px;
  padding-inline:var(--gut); }
.last__h{ margin:0 0 clamp(18px,2.6vh,30px); font-family:var(--disp); font-weight:600;
  font-size:clamp(2rem,5.6vw,4.6rem); line-height:1.04; letter-spacing:-.042em;
  text-shadow:0 2px 6px rgba(0,0,0,.5), 0 14px 44px rgba(0,0,0,.5); }
.last__p{ margin:0 auto clamp(28px,4vh,44px); max-width:44ch;
  font-size:clamp(1rem,1.4vw,1.22rem); line-height:1.55; color:rgba(251,251,251,.78);
  text-shadow:0 2px 10px rgba(0,0,0,.6); }

/* contact rows */
.det{ padding-block:clamp(56px,8vh,110px); }
.det__row{ display:flex; flex-wrap:wrap; gap:6px 28px; align-items:baseline;
  padding:clamp(16px,2.2vh,22px) 0; border-bottom:1px solid var(--line);
  transition:padding-left .4s var(--ease); }
.det__row:first-child{ border-top:1px solid var(--line); }
a.det__row:hover{ padding-left:14px; }
.det__row span:first-child{ font-family:var(--mic); font-weight:600; font-size:var(--t-mic); letter-spacing:.16em;
  text-transform:uppercase; color:var(--dim); min-width:92px; }
.det__row span:last-child{ font-family:var(--disp); font-size:clamp(1.02rem,2.2vw,1.55rem); letter-spacing:-.02em; }
a.det__row:hover span:last-child{ color:var(--flare); }

/* ═══ FOOTER ══════════════════════════════════════════════════ */
.foot{ padding-block:clamp(30px,4vh,44px) calc(clamp(30px,4vh,44px) + 96px); border-top:1px solid var(--line-2); }
.foot__in{ display:flex; flex-wrap:wrap; gap:18px 32px; justify-content:space-between; align-items:flex-end; }
.foot__mark{ display:block; font-family:var(--disp); font-weight:700; font-size:1.02rem; letter-spacing:.01em; }
.foot__mark sup{ font-size:.5em; top:-.62em; opacity:.6; margin-left:-.06em; letter-spacing:0; }
.foot__desc{ display:block; margin-top:4px; font-family:var(--mic); font-weight:600; font-size:var(--t-mic);
  letter-spacing:.2em; text-transform:uppercase; color:var(--dim); }
.foot__line{ font-size:clamp(.9rem,1.2vw,1.02rem); color:rgba(251,251,251,.52); max-width:40ch; }

/* ═══ BOTTOM DOCK ═══ */
.dock{
  position:fixed; z-index:80; left:50%; bottom:clamp(14px,2.4vh,26px); transform:translateX(-50%);
  display:flex; align-items:center; gap:4px; padding:6px; border-radius:100px;
  border:1px solid var(--line); background:rgba(26,26,26,.84); backdrop-filter:blur(14px);
  max-width:calc(100vw - 26px);
  transition:transform .55s var(--ease), opacity .45s var(--ease);
}
.dock.is-down{ transform:translate(-50%,190%); opacity:0; }
.dock__btn{
  display:inline-flex; align-items:center; gap:9px; min-height:44px; padding:0 16px;
  border:0; border-radius:100px; cursor:pointer; background:transparent; color:var(--pearl);
  font:inherit; font-size:.86rem; white-space:nowrap; transition:background .3s var(--ease);
}
.dock__btn:hover,.dock__btn[aria-expanded="true"]{ background:rgba(251,251,251,.09); }
.dock__btn--cta{ background:var(--pearl); color:var(--ink); font-weight:500; }
.dock__btn--cta:hover{ background:var(--flare); }
.dock__ico{ width:13px; height:13px; border-radius:3px; border:1.5px solid currentColor; opacity:.7; flex:0 0 13px; }
.dock__ico--r{ border-radius:50%; }
@media (max-width:430px){ .dock__btn{ padding:0 12px; font-size:.8rem; } }

/* Visibility gated with opacity + pointer-events, never display — display
   cannot be transitioned, so a panel toggled that way opens smoothly and
   then vanishes instantly on close. */
.dock__panel{
  position:absolute; bottom:calc(100% + 10px); left:50%; width:min(360px, calc(100vw - 26px));
  transform:translate(-50%,10px); opacity:0; visibility:hidden; pointer-events:none;
  display:grid; gap:2px; padding:8px; border-radius:18px;
  border:1px solid var(--line); background:rgba(26,26,26,.96); backdrop-filter:blur(14px);
  transition:opacity .38s var(--ease), transform .38s var(--ease), visibility .38s;
}
.dock__panel.is-open{ opacity:1; visibility:visible; pointer-events:auto; transform:translate(-50%,0); }
.dock__panel a{ display:grid; gap:2px; padding:13px 15px; border-radius:12px; transition:background .28s var(--ease); }
.dock__panel a:hover{ background:rgba(251,251,251,.07); }
.dock__panel b{ font-weight:500; font-size:.92rem; }
.dock__panel i{ font-style:normal; font-size:.8rem; color:var(--dim); }

/* ═══ REDUCED MOTION ═══
   Every animated element gets an explicit resting state so nothing is left
   frozen mid-animation when motion is switched off. */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  /* Lenis is not initialised at all under reduced motion — see app.js —
     so nothing here needs to undo it. */
  *,*::before,*::after{ animation-duration:.001ms !important; animation-iteration-count:1 !important;
                        transition-duration:.001ms !important; }
  .hero__stage{ width:100vw !important; height:100svh !important; border-radius:0 !important; }
}
