/* ============================================================
   BAMBI SHEPHERD — bambilicious.com
   Shared design system: tokens, chrome, nav, overlays, footer.
   Page-specific blocks live at the bottom, clearly sectioned.
   ============================================================ */

/* ---------- tokens ---------- */
:root {
  --void:  #050506;
  --ink:   #0b0c0e;
  --coal:  #131417;
  --smoke: #26282d;
  --ash:   #7f7d78;
  --bone:  #efece7;
  --frost: #b9cbd6;

  --serif: "Bodoni Moda", "Didot", "Bodoni MT", Georgia, serif;
  --sans:  "Inter", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;

  --ease:  cubic-bezier(0.22, 1, 0.36, 1);
  --slow:  cubic-bezier(0.16, 1, 0.3, 1);

  --gut:   clamp(20px, 5vw, 68px);   /* page gutter */
  --navh:  clamp(64px, 9vh, 88px);

  --z-grain: 6;
  --z-ash:   5;
  --z-menu:  50;
  /* above the menu: .nav is a stacking context, so the burger inside it
     cannot rise over the overlay on its own — the whole bar has to */
  --z-nav:   60;
  --z-veil:  90;
}

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

html {
  background: var(--void);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--void);
  color: var(--bone);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

::selection { background: var(--frost); color: var(--void); }

/* utility ------------------------------------------------- */
.eyebrow {
  font-size: 11px;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0;
}
.rule {
  height: 1px;
  background: linear-gradient(90deg, rgba(239,236,231,.24), rgba(239,236,231,0));
  border: 0;
  margin: 0;
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: var(--gut); top: 10px; z-index: 100;
  transform: translateY(-200%);
  background: var(--bone); color: var(--void);
  padding: 10px 18px; font-size: 12px; letter-spacing: .18em; text-transform: uppercase;
}
.skip-link:focus { transform: translateY(0); }

:focus-visible {
  outline: 1px solid var(--frost);
  outline-offset: 4px;
}

/* ============================================================
   ATMOSPHERE — grain, vignette, ash canvas, page veil
   ============================================================ */
.grain,
.vignette {
  position: fixed;
  inset: -50%;
  pointer-events: none;
  z-index: var(--z-grain);
}
.grain {
  inset: -100%;
  width: 300%; height: 300%;
  opacity: .045;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/></filter><rect width='140' height='140' filter='url(%23n)'/></svg>");
  animation: grainshift 850ms steps(1) infinite;
}
@keyframes grainshift {
  0%   { transform: translate3d(0,0,0); }
  20%  { transform: translate3d(-6%,3%,0); }
  40%  { transform: translate3d(4%,-5%,0); }
  60%  { transform: translate3d(-3%,-2%,0); }
  80%  { transform: translate3d(5%,4%,0); }
  100% { transform: translate3d(0,0,0); }
}
.vignette {
  inset: 0;
  background:
    radial-gradient(120% 85% at 50% 42%, transparent 38%, rgba(0,0,0,.55) 100%),
    linear-gradient(180deg, rgba(0,0,0,.45) 0%, transparent 22%, transparent 74%, rgba(0,0,0,.6) 100%);
}

#ash-canvas {
  position: fixed;
  inset: 0;
  width: 100%; height: 100%;
  pointer-events: none;
  z-index: var(--z-ash);
}

/* page-transition veil */
.veil {
  position: fixed;
  inset: 0;
  z-index: var(--z-veil);
  background: var(--void);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity .5s var(--ease), visibility 0s linear .5s;
}
.veil.is-out {                  /* covering the screen */
  opacity: 1;
  visibility: visible;
  pointer-events: all;
  transition: opacity .42s var(--ease), visibility 0s;
}

/* first-load intro */
.loader {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  place-items: center;
  background: var(--void);
  transition: opacity .8s var(--ease), visibility 0s linear .8s;
}
.loader.is-done { opacity: 0; visibility: hidden; pointer-events: none; }
.loader__mark {
  font-family: var(--serif);
  font-size: clamp(20px, 4vw, 34px);
  letter-spacing: .5em;
  text-indent: .5em;
  color: var(--bone);
  opacity: .9;
}
.loader__bar {
  position: absolute;
  left: 50%; bottom: 26%;
  transform: translateX(-50%);
  width: min(200px, 42vw);
  height: 1px;
  background: rgba(239,236,231,.16);
  overflow: hidden;
}
.loader__bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--frost);
  transform-origin: left;
  transform: scaleX(0);
  animation: load 1.1s var(--ease) forwards;
}
@keyframes load { to { transform: scaleX(1); } }

/* ============================================================
   CURSOR AMBIENCE (pointer-fine only)
   A soft pool of light trailing the pointer — no ring, no dot. The
   native cursor is left visible, so this is purely atmosphere.
   `screen` lifts whatever it passes over instead of veiling it, which is
   what makes it read as light rather than a grey disc.
   ============================================================ */
.cursor-glow {
  position: fixed;
  top: 0; left: 0;
  width: 44vmax; height: 44vmax;
  margin: -22vmax 0 0 -22vmax;
  border-radius: 50%;
  pointer-events: none;
  /* over the page content (z 10) but under the nav (z 60) */
  z-index: 30;
  mix-blend-mode: screen;
  background: radial-gradient(closest-side,
              rgba(196, 214, 226, .13),
              rgba(185, 203, 214, .058) 38%,
              rgba(185, 203, 214, 0) 72%);
  opacity: 0;
  transition: opacity .9s var(--ease);
  will-change: transform;
}
body.cursor-ready .cursor-glow { opacity: .85; }
.cursor-glow.is-hover { opacity: 1; }

@media (hover: none), (pointer: coarse) {
  .cursor-glow { display: none; }
}

/* ============================================================
   NAV
   ============================================================ */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: var(--navh);
  z-index: var(--z-nav);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--gut);
  transition: transform .45s var(--ease);
}
.nav.is-hidden { transform: translateY(-100%); }

/* Frosted glass bar (vassqo.com's treatment), but held back until you
   scroll. At the top of the home page the panel's blur and darkening land
   squarely on Bambi's face, so up there the nav is type only — nothing
   sits over the photo but the words themselves. */
.nav::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom, rgba(5, 5, 6, 0.72), rgba(5, 5, 6, 0.26));
  border-bottom: 1px solid rgba(239, 236, 231, 0.08);
  opacity: 0;
  transition: opacity .45s var(--ease);
  pointer-events: none;
}
.nav.is-solid::before {
  opacity: 1;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
/* keep the bar legible while it is bare type over a photograph */
.nav__mark,
.nav__links,
.burger { position: relative; z-index: 1; }
.nav__mark,
.nav__link { text-shadow: 0 1px 16px rgba(0, 0, 0, .55); }
.nav.is-solid .nav__mark,
.nav.is-solid .nav__link { text-shadow: none; }

.nav__mark {
  font-family: var(--serif);
  font-size: 15px;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--bone);
  white-space: nowrap;
}
.nav__links {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 46px);
  list-style: none;
  margin: 0; padding: 0;
}
.nav__link {
  position: relative;
  font-size: 11px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--bone);
  padding: 6px 0;
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .45s var(--ease);
}
.nav__link:hover::after,
.nav__link[aria-current="page"]::after { transform: scaleX(1); transform-origin: left; }
.nav__link--ig span { display: inline-block; transition: transform .4s var(--ease); }
.nav__link--ig:hover span { transform: translate(3px, -3px); }

/* burger */
.burger {
  display: none;
  width: 40px; height: 40px;
  margin-right: -8px;
  position: relative;
  z-index: calc(var(--z-menu) + 1);
}
.burger i {
  position: absolute;
  left: 8px;
  width: 24px; height: 1px;
  background: var(--bone);
  transition: transform .45s var(--ease), opacity .25s;
}
.burger i:nth-child(1) { top: 16px; }
.burger i:nth-child(2) { top: 23px; }
.burger.is-open i:nth-child(1) { transform: translateY(3.5px) rotate(45deg); }
.burger.is-open i:nth-child(2) { transform: translateY(-3.5px) rotate(-45deg); }

/* mobile menu */
.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-menu);
  background: rgba(5,5,6,.96);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 var(--gut);
  opacity: 0;
  visibility: hidden;
  transition: opacity .5s var(--ease), visibility 0s linear .5s;
}
.menu.is-open { opacity: 1; visibility: visible; transition: opacity .5s var(--ease), visibility 0s; }
.menu ol { list-style: none; margin: 0; padding: 0; }
.menu li { overflow: hidden; }
.menu a {
  display: block;
  font-family: var(--serif);
  font-size: clamp(38px, 12vw, 72px);
  line-height: 1.14;
  letter-spacing: .01em;
  padding: 4px 0;
  transform: translateY(110%);
  transition: transform .7s var(--ease);
}
.menu.is-open a { transform: translateY(0); }
.menu.is-open li:nth-child(1) a { transition-delay: .06s; }
.menu.is-open li:nth-child(2) a { transition-delay: .12s; }
.menu.is-open li:nth-child(3) a { transition-delay: .18s; }
.menu.is-open li:nth-child(4) a { transition-delay: .24s; }
.menu__foot {
  margin-top: clamp(36px, 7vh, 64px);
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ash);
}

@media (max-width: 820px) {
  .nav__links { display: none; }
  .burger { display: block; }
}

/* ============================================================
   SCROLL-REVEAL primitive
   ============================================================ */
.reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 1s var(--ease), transform 1s var(--ease);
}
.reveal.is-in { opacity: 1; transform: none; }
.reveal[data-d="1"] { transition-delay: .1s; }
.reveal[data-d="2"] { transition-delay: .2s; }
.reveal[data-d="3"] { transition-delay: .3s; }
.reveal[data-d="4"] { transition-delay: .4s; }

/* ============================================================
   FOOTER
   ============================================================ */
.foot {
  position: relative;
  z-index: 10;
  padding: clamp(56px, 10vh, 96px) var(--gut) clamp(28px, 5vh, 42px);
  border-top: 1px solid rgba(239,236,231,.09);
}
.foot__top {
  display: flex;
  flex-wrap: wrap;
  gap: 28px 48px;
  justify-content: space-between;
  align-items: flex-end;
}
.foot__name {
  font-family: var(--serif);
  font-size: clamp(34px, 8vw, 78px);
  line-height: .95;
  margin: 0;
  letter-spacing: .01em;
}
.foot__links {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
}
.foot__links a { color: var(--ash); transition: color .3s; }
.foot__links a:hover { color: var(--bone); }
.foot__bar {
  margin-top: clamp(36px, 7vh, 60px);
  padding-top: 20px;
  border-top: 1px solid rgba(239,236,231,.08);
  display: flex;
  flex-wrap: wrap;
  gap: 10px 24px;
  justify-content: space-between;
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--smoke);
}
.foot__bar span { color: var(--ash); }

/* ============================================================
   HOME — hero with split name
   ============================================================ */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-items: center;
  overflow: hidden;
}
.hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}
.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* framed so her head clears the nav row rather than sitting under it */
  object-position: 50% 21%;
  /* Soft enough to sit back behind the type, sharp enough to still read as
     her. The scale(1.08) below doubles as bleed — blur() fades an element's
     own edges over ~3× the radius, and the overhang is well past that, so
     there's no halo at the frame edges. */
  /* Only a light desaturation: the cold teal is the whole character of this
     frame, and the .5 that suited the previous site's warm studio shot
     flattened it to grey. Raise it back toward .5 for a colder, greyer read. */
  filter: grayscale(.15) contrast(1.06) brightness(.96) blur(5px);
  transform: scale(1.08);
  will-change: transform;
}
/* Falling snow — two depth layers straddling the type, clipped to the
   hero by its own overflow:hidden. Nothing here escapes the first screen. */
.hero__snow {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
.hero__snow--back  { z-index: 1; }   /* behind the name */
.hero__snow--front { z-index: 3; }   /* drifting over it */

/* the near layer sits off the focal plane — a touch of blur sells the
   depth. Skipped on touch devices, where it is not worth the fill rate. */
@media (hover: hover) and (pointer: fine) {
  .hero__snow--front { filter: blur(1px); }
}

.hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70% 60% at 50% 45%, transparent 30%, rgba(5,5,6,.5) 100%),
    linear-gradient(180deg, rgba(5,5,6,.55) 0%, transparent 30%, rgba(5,5,6,.85) 100%);
}

/* The middle column is the empty lane over her figure; the 1fr columns
   must fit "CAITLYN" — the longer word — so the type size is tuned to
   (100vw − gutters − lane) / 2 ÷ ~4.8em of Bodoni caps. */
.hero__name {
  position: relative;
  z-index: 2;
  display: grid;
  /* minmax(0,…), not a bare 1fr: a bare fr floors at min-content, so the
     longer word (SHEPHERD) would widen its own column and shove the whole
     composition off-centre rather than being sized to fit it. */
  grid-template-columns: minmax(0, 1fr) minmax(140px, 20vw) minmax(0, 1fr);
  align-items: center;
  width: 100%;
  padding: 0 clamp(14px, 3vw, 40px);
  pointer-events: none;
}
/* A soft dark bloom behind each word so the white Bodoni holds up over the
   pale part of the backdrop. `--scrim` (0–1) is driven from the scroll loop
   so the bloom leaves with the letters instead of lingering; it lives in the
   colour alphas rather than on `opacity`, which the intro fade already owns. */
.hero__word::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 132%;
  height: 300%;
  transform: translate(-50%, -50%);
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.1s var(--ease) .3s;
  background: radial-gradient(closest-side,
              rgba(5,5,6,.66), rgba(5,5,6,.34) 55%, rgba(5,5,6,0) 100%);
  background: radial-gradient(closest-side,
              rgb(5 5 6 / calc(.66 * var(--scrim, 1))),
              rgb(5 5 6 / calc(.34 * var(--scrim, 1))) 55%,
              rgb(5 5 6 / 0) 100%);
}
.is-lit .hero__word::before { opacity: 1; }

.hero__word {
  position: relative;
  isolation: isolate;         /* pins the bloom behind this word's letters */
  font-family: var(--serif);
  font-weight: 400;
  /* sized to the longer word: SHEPHERD is 8 characters, where the previous
     tuning only had to fit 7 */
  font-size: clamp(38px, 6.7vw, 150px);
  line-height: .84;
  margin: 0;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  white-space: nowrap;
  text-shadow: 0 8px 60px rgba(0,0,0,.6);
}
.hero__word--l { grid-column: 1; justify-self: end;   text-align: right; }
.hero__word--r { grid-column: 3; justify-self: start; text-align: left;  }

/* Per-letter intro. The outer .ch runs the entrance (CSS transition); the
   inner <i> is left free for the scroll exit, which JS writes inline with
   no transition so it tracks the wheel exactly. */
.hero__word .ch {
  display: inline-block;
  opacity: 0;
  transform: translateY(.42em) rotate(6deg);
  filter: blur(9px);
  transition: opacity .95s var(--slow), transform 1.15s var(--slow), filter .95s var(--slow);
}
.hero__word .ch > i {
  display: inline-block;
  font-style: normal;
  will-change: transform, opacity;
}
.hero__word--l .ch { transform: translate(-.3em, .3em) rotate(-5deg); }
.hero__word--r .ch { transform: translate(.3em, .3em) rotate(5deg); }
.is-lit .hero__word .ch { opacity: 1; transform: none; filter: blur(0); }

.hero__sub {
  position: absolute;
  left: 50%;
  bottom: clamp(96px, 16vh, 150px);
  transform: translateX(-50%);
  z-index: 2;
  text-align: center;
  font-size: 10px;
  letter-spacing: .42em;
  text-transform: uppercase;
  color: var(--frost);
  opacity: 0;
  transition: opacity 1s var(--ease) .9s;
  white-space: nowrap;
}
.is-lit .hero__sub { opacity: .85; }

.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: clamp(26px, 5vh, 46px);
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  font-size: 9px;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--ash);
  opacity: 0;
  transition: opacity 1s var(--ease) 1.2s;
}
.is-lit .hero__scroll { opacity: 1; }

/* both cues retire as soon as you engage the scroll */
.is-lit.hero-scrolled .hero__sub {
  opacity: 0;
  transition: opacity .45s var(--ease);
}
.is-lit.hero-scrolled .hero__scroll {
  opacity: 0;
  transform: translate(-50%, 14px);
  transition: opacity .4s var(--ease), transform .5s var(--ease);
}

.hero__scroll i {
  display: block;
  width: 1px; height: 44px;
  background: linear-gradient(180deg, rgba(239,236,231,.7), transparent);
  animation: drip 2.4s var(--ease) infinite;
  transform-origin: top;
}
@keyframes drip {
  0%   { transform: scaleY(0); opacity: 0; }
  35%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(44px); opacity: 0; }
}

/* mobile: stack the name above/below the figure */
@media (max-width: 780px) {
  .hero__name {
    grid-template-columns: 1fr;
    /* the middle row is the empty lane her face sits in — it needs a real
       height, an `auto` row collapses and the two words meet */
    grid-template-rows: 1fr minmax(30svh, 36svh) 1fr;
    justify-items: center;
    min-height: 100svh;
    padding-top: var(--navh);
    padding-bottom: 20svh;
  }
  .hero__word { font-size: clamp(40px, 15vw, 84px); }
  .hero__word--l { grid-column: 1; grid-row: 1; justify-self: center; align-self: end; text-align: center; }
  .hero__word--r { grid-column: 1; grid-row: 3; justify-self: center; align-self: start; text-align: center; }
  .hero__media img { object-position: 50% 26%; }
  .hero__sub { bottom: clamp(78px, 13vh, 110px); font-size: 9px; letter-spacing: .3em; }
}

/* --- home: portrait gallery ---
   Four frames on a brick stagger. The offsets are static; the drift that
   separates the columns as you pass is a transform written from js/home.js. */
.gallery {
  position: relative;
  z-index: 10;
  padding: clamp(70px, 13vh, 150px) var(--gut);
  max-width: 1500px;
  margin: 0 auto;
}
.gallery > .eyebrow { margin-bottom: clamp(26px, 5vh, 52px); }

.gallery__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 1.6vw, 26px);
  align-items: start;
}
.gallery__item {
  position: relative;
  margin: 0;
  will-change: transform;
}
/* every second frame rides lower, so the row never reads as a filmstrip */
.gallery__item:nth-child(2n) { margin-top: clamp(26px, 6vw, 88px); }

.gallery__frame {
  position: relative;
  overflow: hidden;
  background: var(--coal);
  aspect-ratio: 3 / 4;
}
.gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* the source files are already monochrome — this is exposure, not desaturation */
  filter: contrast(1.06) brightness(.9);
  transform: scale(1.03);
  transition: transform 1.2s var(--ease), filter .7s var(--ease);
}
.gallery__item:hover img {
  transform: scale(1.09);
  filter: contrast(1.04) brightness(1);
}
.gallery__item::after {
  content: attr(data-n);
  position: absolute;
  left: 0;
  top: calc(100% + 12px);
  font-size: 10px;
  letter-spacing: .26em;
  color: var(--ash);
  transition: color .5s var(--ease);
}
.gallery__item:hover::after { color: var(--bone); }

@media (max-width: 860px) {
  .gallery__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(8px, 2.4vw, 18px) clamp(8px, 2.4vw, 18px);
    row-gap: clamp(30px, 7vw, 48px);
  }
  .gallery__item:nth-child(2n) { margin-top: clamp(22px, 8vw, 54px); }
}

/* --- home: measurements ---
   A comp-card spec line, not a table: no rules, no cells, no container.
   The figures carry it, held apart by whitespace alone. */
.specs {
  position: relative;
  z-index: 10;
  padding: clamp(54px, 11vh, 118px) var(--gut) 0;
  max-width: 1500px;
  margin: 0 auto;
}
.specs__list {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(30px, 6vw, 104px);
  margin: 0;
  padding: 0;
}
.specs__list > div { min-width: 0; }
.specs dt {
  font-size: 10px;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--ash);
  margin: 0 0 clamp(8px, 1.4vh, 14px);
  white-space: nowrap;
}
.specs dd {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(24px, 3vw, 42px);
  line-height: 1;
  letter-spacing: -0.005em;
  white-space: nowrap;
}
/* the spec line and the frames below it read as one block, so pull them together */
.specs + .gallery { padding-top: clamp(46px, 9vh, 104px); }

@media (max-width: 720px) {
  .specs__list { gap: clamp(24px, 7vw, 40px) clamp(30px, 9vw, 56px); }
  .specs dd { font-size: clamp(22px, 6.4vw, 30px); }
}

/* --- home: featured strip --- */
.featured {
  position: relative;
  z-index: 10;
  padding: clamp(70px, 14vh, 150px) 0 clamp(60px, 12vh, 130px);
}
.featured__head {
  display: flex;
  flex-wrap: wrap;
  gap: 16px 32px;
  align-items: baseline;
  justify-content: space-between;
  padding: 0 var(--gut) clamp(28px, 5vh, 48px);
}
.featured__title {
  font-family: var(--serif);
  font-size: clamp(30px, 5.6vw, 74px);
  line-height: 1;
  margin: 0;
}
.featured__track {
  display: flex;
  gap: clamp(12px, 2vw, 26px);
  padding: 0 var(--gut);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* without this, mandatory snapping eats the left gutter on load */
  scroll-padding-inline: var(--gut);
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.featured__track::-webkit-scrollbar { display: none; }
.featured__track a {
  position: relative;
  flex: 0 0 auto;
  /* double the previous clamp(190px, 24vw, 330px) — capped by viewport
     height so a whole frame still fits on screen on short laptops */
  width: clamp(300px, 48vw, 620px);
  aspect-ratio: 3 / 4;
  max-height: 82svh;
  overflow: hidden;
  scroll-snap-align: start;
  background: var(--coal);
}
.featured__track img {
  width: 100%; height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05);
  transform: scale(1.02);
  transition: transform 1.1s var(--ease), filter .6s var(--ease);
}
.featured__track a:hover img { transform: scale(1.09); filter: grayscale(.15) contrast(1.05); }
.featured__track a::after {
  content: attr(data-n);
  position: absolute;
  left: 14px; bottom: 12px;
  font-size: 10px;
  letter-spacing: .24em;
  color: var(--bone);
  mix-blend-mode: difference;
}

/* the big link-out */
.bigcta {
  position: relative;
  z-index: 10;
  display: block;
  padding: clamp(60px, 12vh, 130px) var(--gut);
  border-top: 1px solid rgba(239,236,231,.09);
  text-align: center;
}
.bigcta__word {
  font-family: var(--serif);
  font-size: clamp(42px, 12vw, 168px);
  line-height: .92;
  margin: 0;
  text-transform: uppercase;
  transition: letter-spacing .8s var(--ease), color .5s;
  display: block;
}
.bigcta:hover .bigcta__word { letter-spacing: .05em; color: var(--frost); }
.bigcta .eyebrow { margin-bottom: 18px; }

/* ============================================================
   PORTFOLIO — continuous scroll, frames arriving from depth
   ============================================================ */
.pf {
  position: relative;
  z-index: 10;
}
.pf__intro {
  min-height: 62svh;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: calc(var(--navh) + 8vh) var(--gut) clamp(40px, 8vh, 80px);
}
.pf__title {
  font-family: var(--serif);
  font-size: clamp(48px, 15vw, 210px);
  line-height: .86;
  margin: 14px 0 0;
  text-transform: uppercase;
}
.pf__hint {
  margin-top: clamp(24px, 5vh, 46px);
  font-size: 11px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ash);
}

/* A masonry wall, positioned from js. Not a grid: frames pack into whichever
   column is shortest, some run double-width, each carries a small fixed jog
   and a degree or two of tilt. The result is irregular but still tight —
   which a row-based grid cannot be, because its rows are only as short as
   their tallest frame.

   Everything below is read by js/portfolio.js at layout time, so the
   proportions stay tunable from here. */
.pf__flow {
  position: relative;
  padding: 0 var(--gut) clamp(70px, 14vh, 160px);
  max-width: 1700px;
  margin: 0 auto;

  --colw: clamp(230px, 26vw, 420px);   /* target column width — also sets the column count */
  --gx:   clamp(18px, 2.6vw, 52px);    /* between columns */
  --gy:   clamp(40px, 8vh, 110px);     /* between stacked frames */
  --jog:  170px;                       /* max extra drop, varies per frame */
  --tilt: 2.6;                         /* max rotation in degrees, unitless */
}

/* Metrics probe — how js gets at the four lengths above.
   Custom properties are substitution-only: getComputedStyle hands back the
   literal `clamp(230px, 26vw, 420px)` string, never a resolved pixel value,
   so reading them directly gives NaN. Applying them to real length
   properties on a hidden element forces the browser to resolve them, and js
   measures this instead. (`--tilt` is an angle with nothing to measure it
   against, so it stays a plain unitless number.) */
.pf__metrics {
  position: absolute;
  top: 0; left: 0;
  visibility: hidden;
  pointer-events: none;
  width: var(--colw);
  height: var(--gy);
  margin-left: var(--gx);
  margin-top: var(--jog);
}
.pf__fig {
  position: absolute;
  top: 0;
  left: 0;
  margin: 0;
  cursor: pointer;
}

@media (max-width: 820px) {
  .pf__flow {
    --colw: clamp(140px, 42vw, 220px);
    --gx:  clamp(10px, 3vw, 22px);
    --gy:  clamp(28px, 7vw, 60px);
    --jog: 70px;
    --tilt: 1.8deg;
  }
  .pf__frame { box-shadow: 0 16px 44px rgba(0, 0, 0, .5); }
}

.pf__lift {
  transform-origin: 50% 55%;
  will-change: transform, opacity;
  backface-visibility: hidden;
}

.pf__frame {
  position: relative;
  overflow: hidden;
  background: var(--coal);
  /* Backstop so a whole frame always fits on screen — a portrait photo at
     full column width can otherwise stand taller than the viewport and
     never be seen entire. Only bites on the tallest sources. */
  max-height: 86svh;
  box-shadow: 0 30px 90px rgba(0, 0, 0, .6);
}
.pf__fig img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 86svh;
  object-fit: cover;
  /* `--col` (0–1) is written from the scroll pass — 1 when the frame sits in
     the middle of the screen. Colour returns as a photo reaches the centre
     and drains again as it leaves; hover takes it the rest of the way. The
     transition is short on purpose: this tracks the wheel, so anything
     slower reads as lag rather than easing. */
  filter: grayscale(calc(.92 - .77 * var(--col, 0)))
          contrast(1.06)
          brightness(calc(.84 + .16 * var(--col, 0)));
  transition: filter .3s var(--ease);
}
.pf__fig:hover img { filter: grayscale(0) contrast(1.04) brightness(1); }

.pf__fig figcaption {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  margin-top: 14px;
  font-size: 10px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ash);
  opacity: 0;
  will-change: opacity;
}
.pf__fig figcaption b { font-weight: 400; color: var(--bone); }
.pf__fig figcaption span { color: var(--frost); }
.pf__fig figcaption em {
  font-style: normal;
  color: var(--smoke);
  margin-right: 12px;
}

/* no-JS / reduced motion: everything is simply already there */
.pf--flat .pf__lift { transform: none !important; opacity: 1 !important; }
.pf--flat .pf__fig img { --col: .6; }   /* nothing is driving it, so pick a middle grade */
.pf--flat .pf__fig figcaption { opacity: 1 !important; }
.pf--flat .pf__hud { display: none; }

/* progress + counter rail */
.pf__hud {
  position: fixed;
  right: var(--gut);
  top: 50%;
  transform: translateY(-50%);
  z-index: 20;
  display: flex;
  align-items: center;
  gap: 14px;
  mix-blend-mode: difference;
  opacity: 0;
  transition: opacity .5s var(--ease);
  pointer-events: none;
}
.pf__hud.is-on { opacity: 1; }
.pf__count {
  font-family: var(--serif);
  font-size: 13px;
  letter-spacing: .16em;
  writing-mode: vertical-rl;
}
.pf__count em { font-style: normal; color: var(--bone); }
.pf__count i { font-style: normal; color: var(--ash); }
.pf__prog {
  width: 1px;
  height: min(230px, 30vh);
  background: rgba(239,236,231,.2);
  position: relative;
}
.pf__prog i {
  position: absolute;
  inset: 0 auto 0 0;
  width: 1px;
  background: var(--bone);
  transform-origin: top;
  transform: scaleY(0);
}
@media (max-width: 780px) { .pf__hud { display: none; } }

/* lightbox */
.lb {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  /* explicit minmax(0,1fr) track — an auto row would grow to the image's
     intrinsic height and make its own max-height:100% meaningless */
  grid-template: minmax(0, 1fr) / minmax(0, 1fr);
  place-items: center;
  padding: clamp(20px, 5vh, 56px) var(--gut) clamp(54px, 9vh, 92px);
  background: rgba(5,5,6,.93);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  visibility: hidden;
  transition: opacity .45s var(--ease), visibility 0s linear .45s;
}
.lb.is-open { opacity: 1; visibility: visible; transition: opacity .45s var(--ease), visibility 0s; }
.lb img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
  transform: scale(.96);
  transition: transform .6s var(--ease);
  box-shadow: 0 40px 140px rgba(0,0,0,.8);
}
.lb.is-open img { transform: scale(1); }
.lb__close,
.lb__nav {
  position: absolute;
  z-index: 2;
  font-size: 11px;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--bone);
  padding: 12px 16px;
  transition: color .3s;
}
.lb__close { top: 14px; right: 12px; }
.lb__nav { top: 50%; transform: translateY(-50%); font-size: 22px; letter-spacing: 0; }
.lb__nav--p { left: 4px; }
.lb__nav--n { right: 4px; }
.lb__close:hover, .lb__nav:hover { color: var(--frost); }
.lb__cap {
  position: absolute;
  left: 0; right: 0; bottom: 16px;
  text-align: center;
  font-size: 10px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ash);
}

/* ============================================================
   CONTACT
   ============================================================ */
.ct {
  position: relative;
  z-index: 10;
  padding: calc(var(--navh) + 10vh) var(--gut) clamp(60px, 12vh, 120px);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: clamp(40px, 7vw, 110px);
  align-items: start;
  max-width: 1500px;
  margin: 0 auto;
}
.ct__title {
  font-family: var(--serif);
  font-size: clamp(44px, 8vw, 118px);
  line-height: .9;
  margin: 14px 0 clamp(28px, 5vh, 46px);
  text-transform: uppercase;
}
.ct__blurb { color: var(--ash); max-width: 42ch; margin: 0 0 clamp(32px, 6vh, 56px); }
.ct__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 22px; }
.ct__list dt,
.ct__list .k {
  font-size: 10px;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ash);
  margin-bottom: 6px;
}
.ct__list dd { margin: 0; }         /* kill the UA indent */
.ct__list .v {
  font-family: var(--serif);
  font-size: clamp(17px, 2vw, 24px);
}
.ct__list a { position: relative; }
.ct__list a::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform .5s var(--ease);
}
.ct__list a:hover::after { transform: scaleX(1); transform-origin: left; }

/* form */
.form { display: grid; gap: clamp(20px, 3.4vh, 34px); }
.field { position: relative; }
.field input,
.field textarea {
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid rgba(239,236,231,.22);
  color: var(--bone);
  font-family: var(--sans);
  font-size: 15px;
  padding: 26px 0 12px;
  border-radius: 0;
  transition: border-color .4s var(--ease);
}
.field textarea { resize: vertical; min-height: 120px; line-height: 1.6; }
.field input:focus,
.field textarea:focus { outline: none; border-bottom-color: var(--frost); }
.field label {
  position: absolute;
  left: 0; top: 26px;
  font-size: 14px;
  letter-spacing: .06em;
  color: var(--ash);
  pointer-events: none;
  transform-origin: left top;
  transition: transform .4s var(--ease), color .4s var(--ease);
}
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-24px) scale(.74);
  color: var(--frost);
  letter-spacing: .22em;
  text-transform: uppercase;
}
.field__err {
  display: block;
  min-height: 15px;
  margin-top: 6px;
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: #d98a8a;
  opacity: 0;
  transition: opacity .3s;
}
.field.is-bad input,
.field.is-bad textarea { border-bottom-color: #d98a8a; }
.field.is-bad .field__err { opacity: 1; }

/* honeypot */
.hp { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden; }

.btn {
  position: relative;
  justify-self: start;
  overflow: hidden;
  border: 1px solid rgba(239,236,231,.3);
  padding: 17px 40px;
  font-size: 11px;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--bone);
  transition: color .45s var(--ease), border-color .45s var(--ease);
}
.btn span { position: relative; z-index: 1; }
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--bone);
  transform: translateY(101%);
  transition: transform .5s var(--ease);
}
.btn:hover { color: var(--void); border-color: var(--bone); }
.btn:hover::before { transform: translateY(0); }
.btn[disabled] { opacity: .45; pointer-events: none; }

.form__note {
  font-size: 11px;
  letter-spacing: .1em;
  min-height: 20px;
  color: var(--frost);
}
.form__note.is-bad { color: #d98a8a; }

@media (max-width: 900px) {
  .ct { grid-template-columns: 1fr; }
}

/* ============================================================
   reduced motion
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .grain { animation: none; }
  .hero__scroll i { animation: none; }
  .hero__media img { transform: none; }
  .hero__word .ch,
  .hero__word .ch > i,
  .reveal,
  .menu a {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition-duration: .01ms !important;
  }
  .loader__bar i { animation-duration: .01ms; }
}
