/* ==========================================================================
   Milo Nielsen — Portfolio  ·  editorial / boutique motion-studio system
   Restrained type · monospace micro-labels · asymmetric grid · quiet accent
   Palette: cream #F4F3EF · cream-2 #EDEBE4 · ink #161513 · accent #FF4D00
   ========================================================================== */

:root {
  --cream: #f4f3ef;
  --cream-2: #edebe4;
  --ink: #161513;
  --accent: #ff4d00;
  --line: rgba(22, 21, 19, 0.14);
  --line-2: rgba(22, 21, 19, 0.08);
  --muted: #8a877f;
  --muted-2: #adaaa1;
  --maxw: 1760px;
  --pad: clamp(1.25rem, 4vw, 6rem);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --sans: 'Outfit', system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'SFMono-Regular', monospace;
}

* { box-sizing: border-box; }

/* hidden must always win, even over rules like .modal{display:flex} */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 300;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  font-feature-settings: 'ss01' 1, 'cv01' 1;
}

::selection { background: var(--accent); color: #fff; }

img, video { display: block; max-width: 100%; }
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; padding: 0; }
a { color: inherit; text-decoration: none; }
ul { margin: 0; padding: 0; list-style: none; }

.accent { color: var(--accent); }
.muted { color: var(--muted); }

/* shared micro-label (monospace kicker) */
.kicker {
  display: inline-block;
  font-family: var(--mono);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: lowercase;
  color: var(--muted);
}

/* ---------- reveal animation ---------- */
@keyframes appleReveal {
  0% { opacity: 0; transform: translateY(18px); filter: blur(6px); }
  100% { opacity: 1; transform: translateY(0); filter: blur(0); }
}
@keyframes navReveal {
  0% { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: translateY(0); }
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }

.reveal-up { opacity: 0; animation: appleReveal 1.1s var(--ease) forwards; }
.delay-100 { animation-delay: 0.12s; }
.delay-200 { animation-delay: 0.22s; }
.delay-300 { animation-delay: 0.34s; }

.reveal {
  opacity: 0;
  transform: translateY(34px);
  filter: blur(6px);
  transition: opacity 1s var(--ease), transform 1s var(--ease), filter 1s var(--ease);
  will-change: opacity, transform;
}
.reveal.in { opacity: 1; transform: none; filter: none; }

/* ---------- scroll progress ---------- */
.progress {
  position: fixed; top: 0; left: 0;
  height: 2px; width: 100%;
  background: var(--accent);
  transform: scaleX(0); transform-origin: 0 50%;
  z-index: 60; transition: transform 0.1s linear;
}

/* ==========================================================================
   NAV
   ========================================================================== */
.nav {
  position: fixed; top: 0; left: 0; width: 100%;
  z-index: 40; padding: 1.6rem 0; color: var(--cream);
  transition: padding 0.4s var(--ease), background 0.4s ease, color 0.4s ease, border-color 0.4s ease;
  border-bottom: 1px solid transparent;
}
.nav[data-solid='true'] {
  padding: 1rem 0;
  background: rgba(244, 243, 239, 0.86);
  backdrop-filter: blur(14px) saturate(1.2);
  border-bottom: 1px solid var(--line-2);
  color: var(--ink);
}
.nav__inner {
  max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad);
  display: flex; align-items: center; justify-content: space-between;
}
.nav__brand {
  font-family: var(--mono);
  font-size: 0.82rem; font-weight: 500; letter-spacing: 0.02em;
  text-transform: lowercase; height: 1.4rem; overflow: hidden;
  display: flex; align-items: center;
}
.nav__brand span:first-child { animation: navReveal 0.6s var(--ease) forwards; }
.nav__links { display: flex; gap: 2.4rem; }
.nav__link {
  font-family: var(--mono); font-size: 0.78rem; font-weight: 400;
  letter-spacing: 0.02em; text-transform: lowercase; color: inherit;
  transition: color 0.25s ease; position: relative;
}
.nav__idx { color: var(--accent); opacity: 0.85; margin-right: 0.15em; font-size: 0.72em; }
.nav__link:hover { color: var(--accent); }
.nav__link.is-active { color: var(--accent); }
.nav__link.is-active .nav__idx { opacity: 1; }

.nav__toggle { display: none; align-items: center; gap: 0.5rem; font-family: var(--mono); font-size: 0.78rem; text-transform: lowercase; color: inherit; }
.nav__toggle .icon-close { display: none; }
.nav[data-menu='true'] .nav__toggle .icon-menu { display: none; }
.nav[data-menu='true'] .nav__toggle .icon-close { display: block; }
.nav[data-menu='true'] .nav__toggle-label { display: none; }

.nav__mobile {
  display: none; flex-direction: column; gap: 1.1rem;
  padding: 1.5rem var(--pad) 2rem; margin-top: 1rem;
  background: rgba(244, 243, 239, 0.97); backdrop-filter: blur(14px);
  border-top: 1px solid var(--line-2); color: var(--ink);
  animation: fadeIn 0.3s ease forwards;
}
.nav__mobile .nav__link { font-size: 1.4rem; text-align: left; }

/* ==========================================================================
   VIEWS / SHARED
   ========================================================================== */
.view { animation: fadeIn 0.6s ease forwards; }
main.view { flex: 1 0 auto; }

.section-head, .page-head, .about, .work__grid {
  max-width: var(--maxw); margin: 0 auto; width: 100%;
}

.page-head { padding: clamp(8rem, 16vh, 12rem) var(--pad) 0; }
.page-head .kicker { margin-bottom: 1.4rem; }
.page-title {
  font-size: clamp(2.75rem, 7vw, 5.5rem);
  font-weight: 200; letter-spacing: -0.035em; line-height: 0.98;
  text-transform: lowercase; margin: 0 0 1.5rem;
}
.page-sub {
  color: var(--muted); font-size: clamp(1rem, 1.6vw, 1.2rem);
  font-weight: 300; max-width: 38rem; margin: 0; line-height: 1.55;
}

/* ==========================================================================
   HERO
   ========================================================================== */
.hero {
  position: relative; height: 100svh; min-height: 600px; width: 100%;
  display: flex; align-items: center; overflow: hidden; background: var(--ink);
}
.hero__bg { position: absolute; inset: 0; z-index: 0; }
/* the reel sits BEHIND the gradient, dimmed + softly blurred + scaled so it
   reads as a moving backdrop set back in space rather than a foreground video */
.hero__video {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0.28;
  /* black & white, pushed back in space (dim + soft blur + slight scale) */
  filter: grayscale(1) blur(2.4px) brightness(0.72) contrast(1.1);
  transform: scale(1.18);
  animation: heroDrift 36s ease-in-out infinite alternate;
}
@keyframes heroDrift {
  from { transform: scale(1.18) translate3d(0, 0, 0); }
  to { transform: scale(1.26) translate3d(-1.4%, -2.2%, 0); }
}
/* edge vignette to deepen the sense of depth */
.hero::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  box-shadow: inset 0 0 200px 50px rgba(11, 10, 9, 0.65);
}
.hero__overlay {
  position: absolute; inset: 0;
  background:
    /* soft vignette for hero-text legibility */
    radial-gradient(120% 90% at 20% 10%, rgba(22,21,19,0.22), transparent 60%),
    /* darkening at the top that fully clears by mid-frame so the video shows */
    linear-gradient(to bottom, rgba(22,21,19,0.5) 0%, rgba(22,21,19,0.28) 38%, rgba(22,21,19,0) 66%),
    /* long, eased wash to cream at the bottom — no hard seam */
    linear-gradient(to bottom,
      rgba(244,243,239,0) 46%,
      rgba(244,243,239,0.12) 66%,
      rgba(244,243,239,0.4) 80%,
      rgba(244,243,239,0.72) 90%,
      var(--cream) 100%);
}
/* slow sweeping sheen drifting across the hero gradient (desaturated, warm-neutral) */
.hero__overlay::after {
  content: ''; position: absolute; inset: -14%; pointer-events: none;
  /* a soft cluster of light — beams sit close together and are blurred so they
     read as one diffuse, natural light rather than a scanner streak. it breathes
     gently and follows the cursor (parallax) instead of sliding across */
  background:
    linear-gradient(101deg, transparent 45.5%, rgba(255, 252, 247, 0.21) 49.5%, transparent 53.5%),
    linear-gradient(101deg, transparent 47.5%, rgba(255, 252, 247, 0.15) 51%, transparent 54.5%),
    linear-gradient(101deg, transparent 43.5%, rgba(255, 252, 247, 0.12) 47.5%, transparent 51.5%);
  background-size: 200% 200%, 200% 200%, 200% 200%;
  background-repeat: no-repeat;
  /* positions wander via JS (wide, non-repeating drift) */
  background-position:
    var(--p1x, 50%) var(--p1y, 45%),
    var(--p2x, 53%) var(--p2y, 50%),
    var(--p3x, 47%) var(--p3y, 40%);
  filter: blur(9px);
  transform: translate(var(--bx, 0px), var(--by, 0px));
  mix-blend-mode: screen;
}
/* subtle film grain for a crafted, tactile feel */
.hero__grain {
  position: absolute; inset: -40%; pointer-events: none; opacity: 0.62;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size: 200px 200px;
  animation: grainShift 0.7s steps(4) infinite;
}
@keyframes grainShift {
  0% { transform: translate(0, 0); }
  25% { transform: translate(-6%, 4%); }
  50% { transform: translate(4%, -5%); }
  75% { transform: translate(-3%, 6%); }
  100% { transform: translate(0, 0); }
}
.hero__content {
  position: relative; z-index: 10; width: 100%;
  max-width: var(--maxw); margin: 0 auto; padding: 0 var(--pad);
}
.hero__kicker {
  font-family: var(--mono); font-size: 0.8rem; font-weight: 400;
  letter-spacing: 0.06em; text-transform: lowercase;
  color: rgba(244, 243, 239, 0.7); margin: 0 0 1.6rem;
}
.hero__title {
  font-size: clamp(2.6rem, 9vw, 8.5rem);
  letter-spacing: -0.025em; line-height: 0.92;
  text-transform: lowercase; color: var(--cream); margin: 0;
}
/* both lines: same weight, solid fill */
.hero__line {
  display: block;
  font-weight: 500;
  color: var(--cream);
}
/* Last name is indented to stagger under the first; it inherits the title's
   -0.025em, which lands it at the same measure as "milo" so the two lines stack
   flush. It used to carry -0.17em to claw back width the per-letter text-indent
   was adding (see .hero__char) — with that fixed, this tracking is correct and
   the split/unsplit renderings are identical. */
.hero__line:last-child { text-indent: clamp(0.25rem, 1.5vw, 1.5rem); }
.hero__title .accent { color: var(--accent); }
/* per-character pieces for the dither micro-interaction.
   text-indent MUST be reset here: it inherits, and an inline-block is a block
   container, so each letter would indent its own single line by the parent's full
   indent — adding that gap between every character instead of once before the line.
   Harmless-looking on desktop (small indent), but the mobile indent is ~4rem, which
   spreads the last name across the viewport and pushes its final letters off-screen. */
/* will-change is applied by JS only while the dither is running (see setCharLayers) */
.hero__char { display: inline-block; text-indent: 0; pointer-events: none; }
.hero__tagline {
  max-width: 26rem; margin: 2.4rem 0 0;
  color: rgba(244, 243, 239, 0.78);
  font-size: clamp(1rem, 1.5vw, 1.2rem); font-weight: 300; line-height: 1.5;
}
.btn-reel {
  display: inline-flex; align-items: center; gap: 0.7rem; margin-top: 2.6rem;
  font-family: var(--mono); font-size: 0.92rem; font-weight: 500;
  letter-spacing: 0.03em; text-transform: lowercase; color: var(--cream);
  padding: 0.7rem 0; border-bottom: 1.5px solid var(--cream);
  transition: color 0.3s ease, border-color 0.3s ease, gap 0.3s var(--ease);
}
.btn-reel__dot {
  width: 10px; height: 10px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 0 rgba(255, 77, 0, 0.5);
  animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.8); } }
.btn-reel:hover { color: #fff; border-color: #fff; gap: 1rem; }
.btn-reel svg { color: var(--cream); transition: transform 0.3s var(--ease); }
.btn-reel:hover svg { transform: translate(2px, -2px); }

/* the name is the reel trigger — this is just a quiet hint beneath it */
.hero__title[role='button'] { cursor: pointer; width: max-content; }
.hero__reelhint {
  display: inline-flex; align-items: center; gap: 0.5rem; margin-top: 2.2rem;
  font-family: var(--mono); font-size: 0.74rem; letter-spacing: 0.06em; text-transform: lowercase;
  color: rgba(244, 243, 239, 0.6); transition: color 0.3s ease;
}
.hero__reelhint::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  animation: pulse 2.4s ease-in-out infinite;
}
.hero__reelhint::after { content: '↗'; font-size: 0.9em; }
#heroName:hover ~ .hero__reelhint { color: var(--cream); }

.hero__scroll {
  position: absolute; bottom: 1.8rem; left: 50%; transform: translateX(-50%);
  z-index: 10; font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.18em;
  text-transform: uppercase; color: rgba(244, 243, 239, 0.55);
}
.hero__scroll span { position: relative; padding-bottom: 2.2rem; }
.hero__scroll span::after {
  content: ''; position: absolute; bottom: 0; left: 50%; width: 1px; height: 1.6rem;
  background: rgba(244, 243, 239, 0.5); transform-origin: top; animation: scrollLine 2.2s var(--ease) infinite;
}
@keyframes scrollLine { 0% { transform: scaleY(0); } 40% { transform: scaleY(1); } 100% { transform: scaleY(0); transform-origin: bottom; } }

/* ==========================================================================
   MARQUEE  (quiet, micro)
   ========================================================================== */
.marquee {
  position: relative; z-index: 20; overflow: hidden;
  background: var(--cream); color: var(--ink);
  padding: 1rem 0; border-top: 1px solid var(--line-2); border-bottom: 1px solid var(--line-2);
}
.marquee__track { display: flex; width: max-content; animation: marquee 40s linear infinite; }
.marquee__track span {
  white-space: nowrap; font-family: var(--mono); font-size: 0.82rem; font-weight: 400;
  letter-spacing: 0.04em; text-transform: lowercase; color: var(--muted); padding-right: 0.5rem;
}
.marquee__track i { color: var(--accent); font-style: normal; margin: 0 0.7rem; }
.marquee:hover .marquee__track { animation-play-state: paused; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* ==========================================================================
   WORK — asymmetric editorial grid
   ========================================================================== */
.work { padding: clamp(5rem, 12vh, 9rem) 0; }
.section-head {
  padding: 0 var(--pad); margin-bottom: clamp(3rem, 7vw, 5.5rem);
  display: grid; grid-template-columns: 1fr; gap: 1.2rem; align-items: start;
}
.section-head .kicker { grid-column: 1; }
.section-title {
  grid-column: 1; margin: 0; max-width: 30ch;
  font-size: clamp(1.17rem, 2.34vw, 1.87rem); font-weight: 300;
  letter-spacing: -0.02em; line-height: 1.18;
}
.section-count { font-family: var(--mono); font-size: 0.72rem; color: var(--muted); letter-spacing: 0.06em; }

/* solid, uniform grid — 1 col on phones, 2 on laptop, 3 on wide screens */
.work__grid {
  padding: 0 var(--pad);
  display: grid; grid-template-columns: 1fr;
  column-gap: clamp(1rem, 2vw, 2rem); row-gap: clamp(2.5rem, 5vw, 4rem);
}

.work-item { display: block; text-align: left; }
/* uniform 16:9 tile, thin grey border, NO base shadow. media is contained
   (letterboxed on a dark tile) so source content is never cropped. */
.work-item__media {
  position: relative; overflow: hidden; background: var(--ink);
  aspect-ratio: 16 / 9;
  transition: transform 0.4s var(--ease), box-shadow 0.4s var(--ease);
}
/* on hover the tile comes forward in z and gains a soft shadow */
.work-item:hover .work-item__media {
  transform: translateY(-8px);
  box-shadow: 0 26px 50px -22px rgba(11, 10, 9, 0.5);
  border-color: var(--line-2);
}
.work-item__img {
  width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(100%) contrast(1.02);
  transition: filter 0.7s var(--ease);
}
.work-item:hover .work-item__img { filter: grayscale(0%); }
.work-item__view {
  position: absolute; left: 1rem; bottom: 1rem; z-index: 2;
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.05em; text-transform: lowercase;
  color: var(--cream); background: rgba(22, 21, 19, 0.55); backdrop-filter: blur(6px);
  padding: 0.4rem 0.7rem; display: inline-flex; align-items: center; gap: 0.4rem;
  opacity: 0; transform: translateY(8px); transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
}
.work-item:hover .work-item__view { opacity: 1; transform: translateY(0); }

/* click feedback on any cover */
.work-item:active .work-item__media { transform: translateY(-4px) scale(0.995); }

/* hover-preview video that fades in over the cover (contained, no crop) */
.work-item__preview {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  z-index: 1; opacity: 0;
  transition: opacity 0.5s var(--ease); pointer-events: none;
}
.work-item.has-preview:hover .work-item__preview { opacity: 1; }
/* small label so people know the cover is hoverable */
.work-item__badge {
  position: absolute; top: 0.85rem; right: 0.85rem; z-index: 2;
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.06em; text-transform: lowercase;
  color: var(--ink); background: rgba(244, 243, 239, 0.9); backdrop-filter: blur(6px);
  padding: 0.32rem 0.55rem; transition: opacity 0.4s ease;
}
.work-item__badge svg { color: var(--accent); }
.work-item.has-preview:hover .work-item__badge { opacity: 0; }

.work-item__cap {
  display: grid; grid-template-columns: auto 1fr auto; align-items: baseline; gap: 1rem;
  margin-top: 1.1rem; padding-top: 0.9rem; border-top: 1px solid var(--line);
}
.work-item__idx { font-family: var(--mono); font-size: 0.72rem; color: var(--accent); }
.work-item__title {
  font-size: clamp(1.05rem, 1.7vw, 1.5rem); font-weight: 400; letter-spacing: -0.01em;
  transition: color 0.3s ease;
  /* long titles shrink to fit one line (via JS) instead of wrapping and
     bumping the row height / breaking the grid */
  white-space: nowrap; overflow: hidden; min-width: 0;
}
.work-item:hover .work-item__title { color: var(--accent); }
.work-item__meta {
  font-family: var(--mono); font-size: 0.7rem; color: var(--muted);
  letter-spacing: 0.03em; text-transform: lowercase; text-align: right; white-space: nowrap;
}

/* placeholder shown when an image file isn't present yet */
.ph {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%; background: var(--cream-2); color: var(--muted-2);
  font-family: var(--mono); font-size: 0.62rem; text-transform: lowercase;
  letter-spacing: 0.06em; text-align: center; padding: 1rem;
}

/* ==========================================================================
   PROJECT DETAIL
   ========================================================================== */
.project { max-width: var(--maxw); margin: 0 auto; width: 100%; padding: clamp(7rem, 14vh, 10rem) var(--pad) 6rem; }
.back-link {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.76rem; text-transform: lowercase; letter-spacing: 0.03em;
  color: var(--muted); margin-bottom: clamp(2.5rem, 6vw, 4.5rem); transition: gap 0.3s var(--ease), color 0.3s ease;
}
.back-link:hover { color: var(--accent); gap: 0.8rem; }
.project__head {
  display: grid; grid-template-columns: 1fr; gap: 2.5rem;
  margin-bottom: clamp(2.5rem, 6vw, 4.5rem); align-items: end;
}
.project__title {
  font-size: clamp(2.3rem, 6.5vw, 5.2rem); font-weight: 200; letter-spacing: -0.035em;
  line-height: 0.95; text-transform: lowercase; margin: 0;
}
.project__meta { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.3rem 1.6rem; }
.project__meta dt {
  font-family: var(--mono); font-size: 0.68rem; text-transform: lowercase; letter-spacing: 0.05em;
  color: var(--muted); margin-bottom: 0.4rem;
}
.project__meta dd { margin: 0; font-size: 0.95rem; font-weight: 400; }
.project__hero {
  position: relative; aspect-ratio: 16 / 9; width: 100%;
  background: var(--ink); margin-bottom: clamp(2.8rem, 5.5vw, 4.4rem); overflow: hidden;
}
.project__hero img, .project__hero video { width: 100%; height: 100%; object-fit: contain; }
/* preloaded video sits invisibly behind the poster until play is pressed */
.project__prewarm { position: absolute; inset: 0; opacity: 0; pointer-events: none; z-index: 0; }
/* hero that autoplays + loops (no poster/play button) */
.project__loop { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; z-index: 1; }
.project__hero.is-playing .project__prewarm { opacity: 1; pointer-events: auto; z-index: 1; }
.project__iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.project__hero.is-playing { background: #000; }
.project__play { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(22,21,19,0.18); opacity: 0; transition: opacity 0.3s ease; }
.project__hero:hover .project__play { opacity: 1; }
.project__play button {
  width: 76px; height: 76px; border-radius: 50%; background: rgba(244,243,239,0.92); color: var(--ink);
  display: flex; align-items: center; justify-content: center; transition: transform 0.3s var(--ease);
}
.project__play button:hover { transform: scale(1.08); }
/* editorial content sections: mono kicker (left) + measured body (right) */
.project__section {
  display: grid; grid-template-columns: 1fr; gap: clamp(0.55rem, 2vw, 0.85rem);
  margin-top: 0; padding-top: 0;
  /* first section (overview) sits right under the video — no divider line */
}
/* only put a break + divider between consecutive content sections */
.project__section + .project__section {
  margin-top: clamp(3.6rem, 7vw, 6rem); padding-top: clamp(2.4rem, 4.5vw, 3.2rem);
  border-top: 1px solid var(--line);
}
/* label + rule live together in a row; the rule flexes so the body copy always
   starts at the same x no matter how long the label is (long label -> short dash) */
.project__head-row { display: flex; align-items: baseline; gap: 0.6rem; }
.project__kick { align-self: baseline; white-space: nowrap; }
.project__rule { flex: 0 0 2.75rem; width: 2.75rem; height: 1px; background: var(--line); align-self: center; }
.project__body { max-width: 72ch; }
.project__p { font-size: clamp(1rem, 1.3vw, 1.14rem); font-weight: 300; line-height: 1.6; color: var(--ink); margin: 0 0 1rem; }
.project__p:last-child { margin: 0; }
/* filmstrip of the kinetic-type clips — sits below the (label) ——— note copy */
.project__clips {
  grid-column: 1 / -1; margin: clamp(2rem, 3.5vw, 2.8rem) 0 0;
  display: grid; grid-template-columns: 1fr; gap: clamp(0.7rem, 1.6vw, 1.1rem);
}
.project__clip {
  width: 100%; aspect-ratio: 5 / 2; object-fit: cover; display: block;
  background: #000;
}
/* spans the full row — a closing wide reference sheet under a multi-up row */
.project__clip--full { grid-column: 1 / -1; }
/* a tidy uniform row of mixed-format prints/merch — cropped square instead of contain */
.project__clip--square { aspect-ratio: 1; }
/* phone-shaped UI mockups: some animation frames are smaller than the canvas
   (scale-in/out), so drop the clip box entirely — no background, no border —
   and let the mockup sit smaller and centered directly on the page */
.project__clip--phone {
  background: transparent; border: none;
  max-width: 58%; margin: 0 auto;
}
/* style frames read as finished art — fill the tile edge-to-edge with no border
   or letterbox background so nothing frames them */
.project__clip--seamless { border: none; background: transparent; object-fit: cover !important; }
/* a portrait / social-cut reel featured on its own — capped width, centered,
   so a tall aspect ratio doesn't blow out to full-bleed */
.project__clip--narrow { max-width: 52%; margin: 0 auto; }
/* a shelf of finished print pieces (poster, sticker sheet, the poster hung for
   real). Mixed portrait/landscape formats sit at ONE shared height, so the row
   lands on a solid baseline without cropping anything to get there — each piece
   just takes the width its own aspect ratio asks for. */
.project__clips--shelf {
  display: flex; flex-wrap: wrap;
  align-items: flex-end; justify-content: center;
  gap: clamp(0.8rem, 1.8vw, 1.5rem);
}
.project__clips--shelf .project__clip {
  width: auto; max-width: 100%;
  height: clamp(190px, 26vw, 400px);
  object-fit: contain; background: transparent;
}
/* At desktop the shelf becomes a JUSTIFIED row: each piece grows in proportion to
   its own aspect ratio (--ar, set per image in app.js), so every item still shares
   one height but the row spans the full content width edge to edge. */
@media (min-width: 880px) {
  .project__clips--shelf { flex-wrap: nowrap; justify-content: space-between; }
  .project__clips--shelf .project__clip {
    height: auto; min-width: 0;
    flex: var(--ar, 1) 1 0;
  }
}
.project__gallery { display: grid; grid-template-columns: 1fr; gap: clamp(1rem, 2.5vw, 2rem); }
.project__gallery img, .project__gallery .ph { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; background: var(--cream-2); }
.project__foot {
  margin-top: clamp(4rem, 9vw, 7rem); padding-top: 2rem; border-top: 1px solid var(--line);
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
}
.project__foot .end { font-family: var(--mono); font-size: 0.72rem; text-transform: lowercase; letter-spacing: 0.05em; color: var(--muted); margin: 0; }
.project__next {
  font-size: clamp(1.1rem, 2vw, 1.6rem); font-weight: 300; letter-spacing: -0.02em;
  text-transform: lowercase; transition: color 0.3s ease; text-align: right;
}
.project__next:hover { color: var(--accent); }

/* ==========================================================================
   GALLERY — rotating sphere, with a static grid view toggle
   ========================================================================== */
.view--misc { position: relative; }
.misc__head {
  position: absolute; top: clamp(6rem, 12vh, 8rem); left: var(--pad); right: var(--pad); z-index: 5;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.7rem 1rem;
}
/* Sits in the flow under the lede rather than absolutely positioned. It used to be
   pinned with a hand-tuned top offset, which meant every copy change re-broke the
   spacing; in flow it just stacks and stays balanced. */
.sphere__hint {
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.06em; text-transform: lowercase;
  color: var(--muted-2); display: inline-flex; align-items: center; gap: 0.45rem;
  margin-top: 0.35rem;
}
.sphere__hint::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); }

/* kicker, a proper lede, then the interaction hint — stacked at the left of the head */
.misc__lead { display: flex; flex-direction: column; align-items: flex-start; gap: 0.7rem; }
/* Reads as page copy, not UI microcopy: near body size, ink for the opening line with
   the detail muted after it, mirroring the section headline on the work page. */
.misc__note {
  margin: 0; max-width: 40ch;
  font-size: clamp(1.02rem, 1.35vw, 1.24rem);
  font-weight: 300; line-height: 1.45; letter-spacing: -0.01em; color: var(--ink);
}
/* sphere / grid toggle — small segmented control matching the mono kicker language */
.misc__toggle { display: inline-flex; border: 1px solid var(--line); }
.misc__toggle-btn {
  font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.05em; text-transform: lowercase;
  color: var(--muted); padding: 0.4rem 0.85rem; transition: color 0.3s ease, background 0.3s ease;
}
.misc__toggle-btn + .misc__toggle-btn { border-left: 1px solid var(--line); }
.misc__toggle-btn:hover { color: var(--ink); }
.misc__toggle-btn.is-active { color: var(--cream); background: var(--ink); }

.sphere {
  position: relative; width: 100%; height: 100svh; min-height: 560px;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; touch-action: none;
}
.sphere__rotor { position: relative; width: 0; height: 0; }
/* No 1px border here on purpose: the tile is rescaled continuously, so a hairline gets
   re-rasterized at a slightly different width every frame and crawls. The media inside
   is photographic and resamples invisibly — the frame edge was the part showing it. */
.sphere__tile {
  position: absolute; top: 0; left: 0;
  background: var(--ink); overflow: hidden; padding: 0;
  /* will-change is applied by JS only while the sphere is on screen (see
     setSphereLayers) — as a static rule it pinned 22 GPU layers for the whole
     session, including on routes that never show the sphere */
  cursor: pointer;
}
/* Depth darkening rides THIS element's opacity (set per frame in app.js) against the
   tile's --ink background — no overlay element, no custom property, no extra layer. */
.sphere__media { width: 100%; height: 100%; object-fit: cover; display: block; }
.sphere__cap {
  position: absolute; left: 0.4rem; bottom: 0.4rem; z-index: 2;
  font-family: var(--mono); font-size: 0.56rem; letter-spacing: 0.04em; text-transform: lowercase;
  color: var(--cream); background: rgba(22, 21, 19, 0.55); padding: 0.2rem 0.42rem;
  opacity: 0; transition: opacity 0.3s ease;
}
.sphere__tile:hover .sphere__cap { opacity: 1; }

/* static grid view — plain, evenly-lit alternative to the sphere */
.gallery-grid {
  display: none; grid-template-columns: repeat(3, 1fr); gap: clamp(0.4rem, 1vw, 0.65rem);
  max-width: var(--maxw); margin: 0 auto; width: 100%;
  padding: clamp(10rem, 18vh, 13rem) var(--pad) clamp(4rem, 8vw, 6rem);
}
.gallery-grid__tile {
  position: relative; aspect-ratio: 1; overflow: hidden; padding: 0; cursor: pointer;
  background: var(--ink);
}
.gallery-grid__media, .gallery-grid__tile .ph {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(1); transition: filter 0.35s ease;
}
/* tiles are grayscale until they're the one playing (sequential) or hovered */
.gallery-grid__tile:hover .gallery-grid__media,
.gallery-grid__tile:focus-visible .gallery-grid__media,
.gallery-grid__tile.is-active .gallery-grid__media { filter: grayscale(0); }
.gallery-grid__tile.is-active { outline: 1px solid var(--accent); outline-offset: -1px; }
.gallery-grid__cap {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.03em; text-transform: lowercase;
  color: var(--cream); background: linear-gradient(to top, rgba(22,21,19,0.75), transparent);
  padding: 1.6rem 0.6rem 0.5rem; opacity: 0; transition: opacity 0.3s ease;
}
.gallery-grid__tile:hover .gallery-grid__cap,
.gallery-grid__tile:focus-visible .gallery-grid__cap,
.gallery-grid__tile.is-active .gallery-grid__cap { opacity: 1; }

/* toggle gates which view is visible — sphere is the default. The hint stays in both
   views now; app.js just swaps its wording to match how you drive each one. */
.view--misc[data-gallery-view='grid'] .sphere { display: none; }
/* In grid view the head joins the flow instead of floating over a full-viewport
   sphere, so the grid sits below it automatically. It used to be absolute in both
   views with the grid clearing it via a hand-tuned padding — which broke the moment
   this copy got taller. Now the clearance can't drift out of sync with the content. */
.view--misc[data-gallery-view='grid'] .misc__head {
  position: static; max-width: var(--maxw); margin: 0 auto;
  padding: clamp(7rem, 14vh, 9.5rem) var(--pad) 0;
}
.view--misc[data-gallery-view='grid'] .gallery-grid {
  padding-top: clamp(1.6rem, 3vw, 2.6rem);
}
.view--misc[data-gallery-view='sphere'] .gallery-grid { display: none; }
.view--misc[data-gallery-view='grid'] .gallery-grid { display: grid; }

/* ---------- clients marquee (bottom of home) ---------- */
.marquee--clients .marquee__track span { display: inline-flex; align-items: center; }
.marquee--clients .marquee__lead {
  font-family: var(--mono); font-size: 0.72rem; text-transform: lowercase;
  letter-spacing: 0.06em; color: var(--muted); padding-right: 0.2rem;
}
.marquee--clients .client {
  font-family: var(--sans); font-weight: 500; font-size: 0.92rem; letter-spacing: 0.03em;
  text-transform: uppercase; color: var(--ink);
}
/* user-supplied client logos, rendered solid black */
.marquee--clients .client-logo {
  height: 26px; width: auto; display: block;
  filter: brightness(0); opacity: 0.82;
}
.marquee--clients .client-logo--sm { height: 20px; }   /* nike, nvidia — a touch smaller */
.marquee--clients .client-logo--big { height: 46px; }  /* WWU wordmark reads small — size up */
/* logos that are white-on-black (e.g. LMNT): blend so the black stays black
   and the white knocks out to the cream strip instead of blacking out */
.marquee--clients .client-logo--knockout {
  filter: none; opacity: 1; mix-blend-mode: multiply; height: 32px;
}
/* Microsoft is four colored squares — grayscale keeps them readable (not one black block) */
.marquee--clients .client-logo--gray { filter: grayscale(1) contrast(0.95); opacity: 0.9; }
.marquee--clients i { color: var(--accent); font-style: normal; margin: 0 1.7rem; font-size: 1rem; line-height: 1; }

/* ---------- misc lightbox ---------- */
.mlb {
  position: fixed; inset: 0; z-index: 80; display: flex; align-items: center; justify-content: center;
  padding: var(--pad); background: rgba(15, 14, 13, 0.9); backdrop-filter: blur(9px);
  animation: fadeIn 0.3s ease forwards;
}
.mlb__close {
  position: absolute; top: 1.4rem; right: var(--pad); z-index: 2; display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.76rem; text-transform: lowercase; color: var(--cream); transition: color 0.3s ease;
}
.mlb__close:hover { color: var(--accent); }
.mlb__frame { display: flex; align-items: center; justify-content: center; max-width: min(92vw, 1400px); max-height: 86vh; }
.mlb__frame video, .mlb__frame img {
  max-width: 100%; max-height: 86vh; width: auto; height: auto; object-fit: contain;
  background: #000; border: 1px solid rgba(255, 255, 255, 0.08);
}

/* ==========================================================================
   ABOUT — editorial
   ========================================================================== */
.about { max-width: var(--maxw); margin: 0 auto; width: 100%; padding: clamp(7rem, 14vh, 10rem) var(--pad) clamp(4rem, 9vw, 7rem); }
.about__grid { display: grid; grid-template-columns: 1fr; gap: clamp(2.5rem, 6vw, 5rem); align-items: start; }
.about__left { display: flex; flex-direction: column; gap: 1.1rem; }
.about__photo { aspect-ratio: 4 / 5; width: 100%; max-width: 312px; overflow: hidden; background: var(--ink); }
.about__photo img, .about__photo .ph { width: 100%; height: 100%; object-fit: cover; filter: none; transition: filter 0.7s ease; }
.about__photo:hover img { filter: grayscale(1); }
.has-cursor .about__photo { cursor: none; }
.about__photo-cap { font-family: var(--mono); font-size: 0.68rem; letter-spacing: 0.03em; text-transform: lowercase; color: var(--muted-2); margin: -0.4rem 0 0; }
.about__resume {
  display: inline-flex; align-items: center; justify-content: space-between; gap: 0.6rem;
  font-family: var(--mono); font-size: 0.78rem; text-transform: lowercase; letter-spacing: 0.03em;
  color: var(--ink); border: 1px solid var(--line); padding: 0.72rem 0.9rem;
  transition: color 0.3s ease, border-color 0.3s ease, background 0.3s ease;
}
.about__resume:hover { color: var(--cream); background: var(--ink); border-color: var(--ink); }
.about__body { display: flex; flex-direction: column; }
/* head row echoes the project sections — (label) ————, a mono kicker with a
   hairline lead-in — so about reads as part of the same system, not its own page */
.about__head-row { display: flex; align-items: center; gap: 0.8rem; margin-bottom: clamp(1.5rem, 3.4vw, 2.3rem); }
.about__kicker { display: inline-block; margin-bottom: 0; flex: 0 0 auto; }
/* runs to the full measure rather than stopping at a 2.75rem stub — a section
   rule under the label, the way a magazine opener sets off its standfirst */
.about__rule { flex: 1 1 auto; min-width: 1rem; height: 1px; background: var(--line); }

/* the headline opens the body copy as a lede, set in the same voice as the
   section titles on work + gallery rather than its own lowercase, ultralight cut */
.about__lede {
  font-size: clamp(1.17rem, 2.34vw, 1.87rem); font-weight: 300; letter-spacing: -0.02em;
  line-height: 1.18; color: var(--ink);
  max-width: 26ch; margin: 0 0 clamp(1.8rem, 4vw, 2.6rem);
}
.about__p { font-size: clamp(0.98rem, 1.4vw, 1.18rem); font-weight: 300; line-height: 1.6; max-width: 59ch; color: var(--ink); margin: 0 0 1.4rem; }
.about__p--muted { color: var(--muted); font-size: clamp(0.9rem, 1.2vw, 1.02rem); }
/* editorial marginalia rule flags the lead paragraph, echoing the accent
   marks used for indices elsewhere on the site */
.about__lede + .about__p { position: relative; padding-left: 1.15rem; }
.about__lede + .about__p::before {
  content: ''; position: absolute; left: 0; top: 0.2em; bottom: 0.2em; width: 2px; background: var(--accent);
}
.about__meta {
  margin-top: clamp(2.6rem, 6vw, 4.5rem); display: grid; grid-template-columns: 1fr 1fr; gap: 2rem 2.5rem;
  border-top: 1px solid var(--line); padding-top: clamp(2.2rem, 4vw, 3rem);
}
.about__label { font-family: var(--mono); font-size: 0.68rem; text-transform: lowercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 400; margin: 0 0 1rem; }
.about__label--gap { margin-top: 1.8rem; }
.about__caps { display: flex; flex-direction: column; gap: 0.6rem; }
.about__caps li { display: flex; align-items: baseline; gap: 0.7rem; font-size: 1rem; font-weight: 400; }
.about__capidx { font-family: var(--mono); font-size: 0.68rem; color: var(--accent); }
.about__email { display: inline-block; font-size: 1rem; font-weight: 400; margin-bottom: 1rem; border-bottom: 1px solid var(--line); padding-bottom: 0.15rem; transition: color 0.3s ease, border-color 0.3s ease; }
.about__email:hover { color: var(--accent); border-color: var(--accent); }
.about__loc { font-family: var(--mono); font-size: 0.8rem; color: var(--ink); margin: 0; }
.about__socials { display: flex; flex-direction: column; gap: 0.55rem; margin-top: 0.5rem; }
.about__socials a { display: inline-flex; align-items: center; gap: 0.5rem; font-family: var(--mono); font-size: 0.74rem; text-transform: lowercase; color: var(--muted); transition: color 0.3s ease, gap 0.3s var(--ease); }
.about__socials a:hover { color: var(--accent); gap: 0.75rem; }
.about__socials svg { width: 15px; height: 15px; }

/* ==========================================================================
   FOOTER
   ========================================================================== */
/* compact, seamless footer — same cream as the page, just a hairline above it */
.footer {
  flex-shrink: 0; background: var(--cream); border-top: 1px solid var(--line);
  padding: clamp(2rem, 4vw, 3rem) var(--pad) 1.4rem; margin-top: auto;
}
.footer__inner {
  max-width: var(--maxw); margin: 0 auto;
  display: flex; flex-wrap: wrap; gap: 1rem 2.5rem; align-items: center; justify-content: space-between;
}
.footer__lead { display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.8rem 1.3rem; }
.footer__email {
  font-family: var(--mono); font-size: clamp(0.82rem, 1.3vw, 1rem); font-weight: 400; letter-spacing: 0.02em;
  color: var(--accent); border-bottom: 1px solid var(--accent); padding-bottom: 0.15rem;
  transition: color 0.3s ease, border-color 0.3s ease, letter-spacing 0.3s var(--ease);
}
.footer__email:hover { color: var(--ink); border-color: var(--ink); letter-spacing: 0.06em; }
.footer__avail { font-family: var(--mono); font-size: 0.72rem; color: var(--muted); text-transform: lowercase; letter-spacing: 0.04em; }
.footer__socials { display: flex; flex-direction: row; gap: 1.4rem; }
.footer__socials a {
  display: inline-flex; align-items: center; gap: 0.45rem; font-family: var(--mono);
  font-size: 0.74rem; text-transform: lowercase; letter-spacing: 0.03em; color: var(--muted);
  transition: color 0.3s ease, gap 0.3s var(--ease);
}
.footer__socials a:hover { color: var(--accent); gap: 0.7rem; }
.footer__socials svg { width: 15px; height: 15px; }
.footer__bottom {
  max-width: var(--maxw); margin: 1.4rem auto 0; padding-top: 1.1rem; border-top: 1px solid var(--line-2);
  display: flex; flex-direction: row; gap: 0.6rem 1.5rem; flex-wrap: wrap; justify-content: space-between; align-items: center;
  font-family: var(--mono); font-size: 0.68rem; color: var(--muted-2); letter-spacing: 0.04em; text-transform: lowercase;
}
/* brand wordmark inside the marquee */
.marquee__track b { color: var(--ink); font-weight: 500; }

/* ==========================================================================
   REEL MODAL
   ========================================================================== */
.modal {
  position: fixed; inset: 0; z-index: 50; display: flex; align-items: center; justify-content: center;
  background: rgba(15, 14, 13, 0.96); backdrop-filter: blur(10px); padding: var(--pad);
  animation: fadeIn 0.3s ease forwards;
}
.modal__close {
  position: absolute; top: 1.4rem; right: var(--pad); z-index: 50; display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.76rem; text-transform: lowercase; color: var(--cream); transition: color 0.3s ease;
}
.modal__close:hover { color: var(--accent); }
.modal__frame { position: relative; width: 100%; max-width: 78rem; aspect-ratio: 16 / 9; background: #000; overflow: hidden; border: 1px solid rgba(255,255,255,0.08); }
.modal__frame video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; }

/* ---------- document viewer (résumé) ----------
   Same overlay language as the reel, but a portrait page instead of a 16:9 video,
   so the frame is driven by available height and the bar sits above it. */
/* The whole page has to be visible at once, so the frame is page-shaped (US Letter
   portrait) and its width is derived from the height left over after the bar. That
   makes the frame height exactly (100vh - reserved), so it can never overflow, and
   the bar shares the same width so the two stay aligned. */
.modal--doc {
  --doc-ratio: 612 / 792;
  --doc-w: min(100% - 2 * var(--pad), (100vh - 7rem) * 0.7727);
  flex-direction: column; align-items: center; justify-content: flex-start; gap: 0.9rem; padding-top: 1.1rem;
}
.modal__bar {
  width: var(--doc-w); display: flex; align-items: center; justify-content: space-between; gap: 1rem;
}
.modal__dl {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-family: var(--mono); font-size: 0.76rem; text-transform: lowercase; color: var(--cream);
  border-bottom: 1px solid rgba(255,255,255,0.22); padding-bottom: 0.15rem; transition: color 0.3s ease, border-color 0.3s ease;
}
.modal__dl:hover { color: var(--accent); border-color: var(--accent); }
/* the close button is in the bar here, not pinned to the viewport corner */
.modal__close--inbar { position: static; top: auto; right: auto; }
.modal__doc {
  position: relative; width: var(--doc-w); aspect-ratio: var(--doc-ratio); flex: 0 0 auto;
  background: #fff; overflow: hidden; border: 1px solid rgba(255,255,255,0.08);
}
.modal__doc iframe, .modal__doc embed { display: block; width: 100%; height: 100%; border: 0; }

body.no-scroll { overflow: hidden; }

/* ==========================================================================
   CUSTOM CURSOR — orange circle that morphs to a "watch reel" pill over the hero
   (only on devices with a real pointer; touch keeps the native behaviour)
   ========================================================================== */
.has-cursor, .has-cursor * { cursor: none !important; }
.cursor {
  position: fixed; top: 0; left: 0; z-index: 90;
  width: 18px; height: 18px; border-radius: 50%;
  background: var(--accent); color: #fff;
  display: flex; align-items: center; justify-content: center;
  pointer-events: none; opacity: 0; overflow: hidden;
  transition: width 0.35s var(--ease), height 0.35s var(--ease),
    border-radius 0.35s var(--ease), opacity 0.3s ease;
  will-change: transform;
}
.cursor.is-visible { opacity: 1; }
.cursor.is-hover { width: 30px; height: 30px; }
.cursor.is-reel {
  width: 132px; height: 46px; border-radius: 999px;
  box-shadow: 0 10px 30px -8px rgba(255, 77, 0, 0.5);
}
.cursor__label {
  font-family: var(--mono); font-size: 0.7rem; letter-spacing: 0.06em; text-transform: lowercase;
  color: #fff; white-space: nowrap; opacity: 0; transform: scale(0.8);
  transition: opacity 0.25s ease 0.05s, transform 0.3s var(--ease) 0.05s;
}
.cursor.is-reel .cursor__label { opacity: 1; transform: scale(1); }
/* the hero advertises itself as clickable-to-watch */
.has-cursor .hero { cursor: none; }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */
@media (min-width: 640px) {
  .footer__bottom { flex-direction: row; justify-content: space-between; align-items: center; }
  .gallery-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 880px) {
  .work__grid { grid-template-columns: repeat(2, 1fr); }
  .section-head { grid-template-columns: 1fr auto; }
  .section-head .kicker { grid-column: 1; }
  .section-title { grid-column: 1; }
  .section-count { grid-column: 2; grid-row: 1 / span 2; align-self: end; }
  .about__grid { grid-template-columns: auto 1fr; gap: clamp(3rem, 6vw, 6rem); }
  .about__left { position: sticky; top: 6rem; width: 312px; }
  .about__body { margin-left: clamp(2rem, 12vw, 12.7rem); } /* copy block nudged right, pulled 1/3 back toward the photo */
  .project__head { grid-template-columns: 1.4fr 1fr; }
  /* fixed-width label column so body copy aligns across every section, then body */
  .project__section {
    grid-template-columns: 11rem minmax(0, 1fr);
    gap: clamp(2rem, 4vw, 3rem) clamp(1.6rem, 3vw, 3rem);
    align-items: start;
  }
  .project__head-row { margin-top: 0.28rem; } /* nudge label to sit by the body's first line */
  .project__rule { flex: 1 1 auto; width: auto; min-width: 0.9rem; } /* rule flexes; long label -> short dash */
  .project__clips { margin-top: 0; } /* row-gap handles the space from the copy above */
  .project__clips { grid-template-columns: repeat(var(--section-cols, 2), 1fr); }
  .project__clips--single { grid-template-columns: 1fr; } /* one wide reference sheet — no second column */
  .project__clips--center { align-items: center; } /* vertically center mismatched-height items (phone mockups) */

  /* stacked-media section: media stacked large on the LEFT, description on the right.
     DOM order stays text-then-media so narrow screens still read label → copy → clips;
     the columns are assigned explicitly here to flip them at desktop only.
     The copy STICKS to the top of its column instead of centring against the whole
     stack — centring left a screen-tall hole above the label and floated the note
     away from the clips it describes. Sticky keeps the copy beside every prompt as
     they scroll past, so the run of graphics holds attention start to finish. */
  .project__section--stack { grid-template-columns: minmax(0, 1.26fr) minmax(0, 0.74fr); align-items: start; }
  .project__section--stack .project__split-text {
    grid-column: 2; grid-row: 1;
    /* Pin the block to the RIGHT of its column (justify-self) so its right edge stays
       flush with the page content edge — level with the divider rules and the nav —
       and let max-width set how far the left edge sits in from there. Tightening the
       measure this way narrows the box without ever unsticking that right edge. */
    justify-self: end;
    max-width: 46ch;
    position: sticky; top: clamp(5.5rem, 12vh, 8rem);
  }
  /* the label sits tight against the copy here because this column is narrow —
     give the body its own breathing room under the (label) ———— rule */
  .project__section--stack .project__split-text .project__body { margin-top: 0.85rem; }
  /* Cap the head-row at the same 11rem the label column uses everywhere else, so the
     rule flexes to the identical length as every other section instead of stretching
     the full width of this (much wider) column. Long label still shortens its dash. */
  .project__section--stack .project__head-row { max-width: 11rem; }
  .project__section--stack .project__clips {
    grid-column: 1; grid-row: 1; grid-template-columns: 1fr; margin: 0;
    gap: clamp(0.9rem, 2vw, 1.5rem);
  }

  .project__gallery { grid-template-columns: repeat(2, 1fr); }
  .gallery-grid { grid-template-columns: repeat(6, 1fr); }
}
/* keep the work grid a steady 2 wide (2 × 3); just roomier type on big screens */
@media (min-width: 1500px) {
  .section-title { max-width: 42ch; }
}
@media (max-width: 767px) {
  .nav__links { display: none; }
  .nav__toggle { display: inline-flex; }
  .nav[data-menu='true'] .nav__mobile { display: flex; }
  .hero__line:last-child { text-indent: clamp(1.5rem, 12vw, 4rem); }
}

/* ---------- reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important; scroll-behavior: auto !important;
  }
  .reveal-up { opacity: 1; }
  .reveal { opacity: 1; transform: none; filter: none; }
  .marquee__track { animation: none; }
  .hero__scroll span::after { animation: none; }
  .btn-reel__dot { animation: none; }
  .hero__overlay::after { animation: none; }
  .hero__video { animation: none; transform: scale(1.18); }
  .hero__grain { animation: none; }
}
