/* ============================================================
   Marvin Fernando — site v6
   Two worlds: VIDEO (warm near-black) / STILL (warm paper).
   Display: Fraunces. Grotesque: Archivo. Accent: record-dot red.
   Engineering rule: JS animates ONLY transform + opacity on
   loop-driven elements (.card and children, #meta children,
   #progress-fill) — those elements carry `transition: none`.
   Queue depth = opaque cards + world-tone dim overlay, never
   translucent cards blending through each other.
   ============================================================ */

:root{
  --video-bg:#100f0d;
  --video-bg-soft:#171512;
  --video-ink:#f1ece1;
  --video-ink-dim:#9d968a;
  --still-bg:#edeae2;
  --still-bg-soft:#e4e0d6;
  --still-ink:#141310;
  --still-ink-dim:#7c776c;
  --red:#c8472e;

  --disp:"Fraunces", Georgia, "Times New Roman", serif;
  --grot:"Archivo", "Helvetica Neue", Arial, sans-serif;

  --bg:var(--still-bg);
  --ink:var(--still-ink);
  --ink-dim:var(--still-ink-dim);
  --dim-tone:var(--still-bg);

  --header-h:72px;
  --edge:clamp(28px,4.2vw,72px);
}

body[data-world="video"]{
  --bg:var(--video-bg);
  --ink:var(--video-ink);
  --ink-dim:var(--video-ink-dim);
  --dim-tone:var(--video-bg);
}

*{ box-sizing:border-box; margin:0; padding:0; -webkit-tap-highlight-color:transparent; }

html,body{ height:100%; }
body{
  background:var(--bg);
  color:var(--ink);
  font-family:var(--grot);
  overflow:hidden;
  overscroll-behavior:none;
  -webkit-font-smoothing:antialiased;
  transition:background-color .5s ease, color .5s ease;
}

a{ color:inherit; text-decoration:none; }
button{ color:inherit; }
:focus-visible{ outline:1px solid var(--red); outline-offset:4px; }

/* ============ world layers ============ */

#worldveil{
  position:fixed; inset:0; z-index:1;
  background:var(--video-bg);
  opacity:0; pointer-events:none;
  transition:opacity .55s ease;
}
body[data-preview="video"] #worldveil{ opacity:1; }

.prev{
  position:fixed; inset:0; z-index:2;
  opacity:0; pointer-events:none;
  transition:opacity .55s ease;
}
.prev img{
  position:absolute; top:0; height:100%; width:72%;
  object-fit:cover;
  transition:transform .8s cubic-bezier(.22,.9,.24,1);
}
/* tone the preview toward its world so the hero stays legible */
.prev::after{
  content:""; position:absolute; inset:0;
}
#prev-video img{
  left:0;
  transform:translate3d(-4%,0,0);
  -webkit-mask-image:linear-gradient(90deg,#000 42%,transparent 96%);
  mask-image:linear-gradient(90deg,#000 42%,transparent 96%);
}
#prev-video::after{
  background:linear-gradient(90deg, rgba(16,15,13,.42) 0%, rgba(16,15,13,.62) 55%, rgba(16,15,13,.2) 100%);
}
#prev-still img{
  right:0;
  transform:translate3d(4%,0,0);
  -webkit-mask-image:linear-gradient(270deg,#000 42%,transparent 96%);
  mask-image:linear-gradient(270deg,#000 42%,transparent 96%);
}
#prev-still::after{
  background:linear-gradient(270deg, rgba(237,234,226,.5) 0%, rgba(237,234,226,.62) 55%, rgba(237,234,226,.15) 100%);
}
.prev.on{ opacity:1; }
.prev.on img{ transform:translate3d(0,0,0); }
.prev.expand{ opacity:1; }
.prev.expand img{ transform:translate3d(0,0,0) scale(1.06); }
.prev.gone{ opacity:0; }

/* ============ projects backdrop (the signature blur) ============ */

#backdrop{
  position:fixed; inset:0; z-index:3;
  opacity:0; pointer-events:none;
  transition:opacity .7s ease;
}
body[data-mode="projects"] #backdrop{ opacity:1; }
.bd{
  position:absolute; inset:0;
  opacity:0;
  transition:opacity .65s ease;   /* crossfade via opacity ONLY */
}
.bd.show{ opacity:1; }
.bd img{
  position:absolute; left:-4%; top:-4%; width:108%; height:108%;
  object-fit:cover;
  /* blur is STATIC — never animated. The drift animates transform only,
     so the space feels alive while idle without repainting the blur. */
  filter:blur(26px) saturate(1.06);
  animation:bdDrift 44s ease-in-out infinite alternate;
}
@keyframes bdDrift{
  from{ transform:translate3d(-.5%,.35%,0) scale(1.02); }
  to{ transform:translate3d(.5%,-.35%,0) scale(1.06); }
}
.bd-tint{ position:absolute; inset:0; transition:background-color .55s ease; }
body[data-world="still"] .bd-tint{ background:rgba(237,234,226,.72); }
body[data-world="video"] .bd-tint{ background:rgba(16,15,13,.68); }

/* ============ header ============ */

#site-header{
  position:fixed; inset:0 0 auto 0; height:var(--header-h); z-index:30;
  display:flex; align-items:center; justify-content:space-between;
  padding:0 var(--edge);
  font-size:12px; letter-spacing:.18em;
}
#wordmark{ font-weight:700; font-size:13px; }
.wm-mf{ display:none; }
.wm-mf{
  font-family:var(--disp); font-weight:600; font-size:17px;
  letter-spacing:.04em; align-items:baseline; gap:4px;
}
.wm-mf i{
  width:5px; height:5px; border-radius:50%;
  background:var(--red); display:inline-block; margin-left:4px;
}
#site-header nav a[aria-current="true"]{ opacity:1; }
#site-header nav{ display:flex; gap:clamp(20px,2.8vw,40px); }
#site-header nav a{ opacity:.72; transition:opacity .25s ease; font-weight:500; }
#site-header nav a:hover{ opacity:1; }
#site-header nav a[aria-current="page"]{ opacity:1; }

/* ============ home ============ */

#home{
  position:fixed; inset:0; z-index:10;
  display:flex; flex-direction:column;
  align-items:center; justify-content:center;
  transition:opacity .45s ease;
}
#home.gone{ opacity:0; pointer-events:none; }

.hero{
  display:flex; align-items:center;
  gap:clamp(26px,4.2vw,64px);
}
.hero-word{
  font-family:var(--disp);
  font-weight:700;
  font-variation-settings:"opsz" 144;
  font-size:clamp(2.6rem,6.2vw,4.9rem);
  line-height:1;
  letter-spacing:.025em;
  transition:opacity .45s ease, transform .55s cubic-bezier(.22,.9,.24,1), color .5s ease;
  will-change:transform;
}
.hero-dot{
  width:clamp(8px,.9vw,12px); height:clamp(8px,.9vw,12px);
  border-radius:50%;
  background:var(--red);
  animation:rec 2.8s ease-in-out infinite;
}
@keyframes rec{ 0%,100%{opacity:1} 50%{opacity:.35} }

/* hover states (desktop): hovering VIDEO dips the whole page dark */
@media (hover:hover){
  body[data-preview="video"] #hw-video,
  body[data-preview="still"] #hw-still{ transform:scale(1.05); }
  body[data-preview="video"] #hw-still,
  body[data-preview="still"] #hw-video{ opacity:.3; transform:scale(.95); }
  body[data-preview="video"] #home,
  body[data-preview="video"] #site-header{ color:var(--video-ink); }
}

.home-line{
  position:absolute; bottom:6vh;
  font-size:10px; letter-spacing:.24em; opacity:.55;
  transition:color .5s ease;
}

/* chosen word resolves INTO the page — grows slightly and dissolves.
   No flying glyphs, nothing to mismatch. */
#home .hero-word.hero-resolve{
  transform:scale(1.16) !important;
  opacity:0 !important;
}

/* first-load intro: hero words rise once, chrome breathes in after.
   Classes are removed ~1.6s in, so hover/preview states are untouched. */
body.intro .hero-word{ opacity:0; transform:translate3d(0,26px,0); }
body.intro .hero-dot,
body.intro .home-line,
body.intro #site-header{ opacity:0; }
body.intro.intro-go .hero-word{ opacity:1; transform:none; }
body.intro.intro-go #hw-video{ transition:opacity .7s ease .1s, transform .85s cubic-bezier(.22,.9,.24,1) .1s; }
body.intro.intro-go #hw-still{ transition:opacity .7s ease .24s, transform .85s cubic-bezier(.22,.9,.24,1) .24s; }
body.intro.intro-go .hero-dot{ opacity:1; transition:opacity .5s ease .48s; }
body.intro.intro-go .home-line{ opacity:.55; transition:opacity .6s ease .72s; }
body.intro.intro-go #site-header{ opacity:1; transition:opacity .6s ease .6s; }

/* touch: two calm halves — blurred stills under radial scrims, no hover needed */
@media (hover:none){
  .prev img{ width:100%;
    -webkit-mask-image:none; mask-image:none;
    transform:scale(1.12);            /* hides the blur fringe; static */
    filter:blur(16px) saturate(1.05); /* static blur — never animated */
  }
  body[data-mode="home"] #prev-video{ opacity:1; clip-path:inset(0 0 50% 0); }
  body[data-mode="home"] #prev-still{ opacity:1; clip-path:inset(50% 0 0 0); }
  #prev-video::after{
    background:radial-gradient(120% 100% at 50% 40%, rgba(16,15,13,.55) 0%, rgba(16,15,13,.9) 100%);
  }
  #prev-still::after{
    background:radial-gradient(120% 100% at 50% 60%, rgba(237,234,226,.55) 0%, rgba(237,234,226,.92) 100%);
  }
  body[data-mode="projects"] #prev-video,
  body[data-mode="projects"] #prev-still{ opacity:0; clip-path:none; }

  #home .hero{
    position:absolute; inset:0;
    flex-direction:column; justify-content:center;
    gap:0;
  }
  /* each word IS its half — full tap target */
  .hero-word{
    position:absolute; left:0; right:0;
    display:flex; align-items:center; justify-content:center;
    height:50vh;
    font-size:clamp(1.9rem,8.4vw,2.7rem);
    letter-spacing:.05em;
  }
  .hero-word::after{
    content:"ENTER"; position:absolute;
    font-family:var(--grot); font-size:9px; letter-spacing:.34em;
    opacity:.5; margin-top:0; transform:translateY(40px);
  }
  #hw-video{ top:0; color:var(--video-ink); }
  #hw-still{ top:50vh; color:var(--still-ink); }
  .hero-dot{ position:absolute; top:50vh; left:50%;
    transform:translate(-50%,-50%); z-index:2;
    box-shadow:0 0 0 5px rgba(16,15,13,.35); }
  .home-line{ display:none; }
}

/* ============ projects ============ */

#projects{ position:fixed; inset:0; z-index:12; transition:opacity .35s ease; }
#projects[hidden]{ display:none; }
#projects.measuring{ visibility:hidden; display:block; }

#modehead{
  position:absolute; top:calc(var(--header-h) + 18px); left:0; right:0;
  z-index:6; text-align:center;
  transition:opacity .4s ease;
}
#worldtoggle{ display:inline-flex; gap:clamp(20px,2.8vw,34px); }
#worldtoggle button{
  background:none; border:0; cursor:pointer;
  font-family:var(--disp); font-weight:560;
  font-variation-settings:"opsz" 60;
  font-size:clamp(1.3rem,2.2vw,1.7rem);
  letter-spacing:.02em; line-height:1.2;
  opacity:.35;
  transition:opacity .3s ease;
}
#worldtoggle button[aria-selected="true"]{ opacity:1; }
#worldtoggle button:hover{ opacity:.8; }

#filters{
  margin-top:14px;
  display:flex; justify-content:center; align-items:center;
  gap:clamp(24px,3vw,40px);
  font-size:12px; letter-spacing:.17em;
  padding:6px 16px;
  transition:opacity .25s ease;   /* world-swap fade — JS writes container only */
}
#filters button{
  background:none; border:0; cursor:pointer;
  font:inherit; letter-spacing:inherit; text-transform:uppercase;
  opacity:.55; white-space:nowrap;
  padding:4px 2px;
  position:relative;
  transition:opacity .3s ease;
}
#filters button:hover{ opacity:.85; }
#filters button[aria-pressed="true"]{ opacity:1; font-weight:600; }
#filters button[aria-pressed="true"]::before{
  content:""; position:absolute; left:-11px; top:50%;
  width:4px; height:4px; margin-top:-2px; border-radius:50%;
  background:var(--red);
}

/* stage + cards — JS OWNS transform/opacity. No transitions here. */
#stage{
  position:absolute; inset:0; z-index:4;
  touch-action:none;
  cursor:grab;
  transition:opacity .45s ease;   /* parent fade for detail open — JS never writes this */
}
#stage.dragging{ cursor:grabbing; }

.card{
  position:absolute; left:0; top:0;
  width:min(48vw,800px);
  aspect-ratio:16/9;
  overflow:hidden;            /* clips the blur halo — no glow */
  transition:none;
  will-change:transform,opacity;
  visibility:hidden;
  user-select:none;
  -webkit-user-select:none;
}
.card img{
  width:100%; height:100%; object-fit:cover; display:block;
  pointer-events:none;
  background:var(--bg);
}
/* depth-of-field: a statically-blurred duplicate is crossfaded in by
   depth via opacity (JS-written). The blur value itself NEVER animates. */
.card-blur{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:cover;
  filter:blur(14px);
  transform:scale(1.06);
  opacity:0; pointer-events:none;
  transition:none;
}
/* depth = world-tone dim, NOT transparency. JS writes its opacity only. */
.card-dim{
  position:absolute; inset:0;
  background:var(--dim-tone);
  opacity:0; pointer-events:none;
  transition:none;
}
body[data-world="video"] .card{ box-shadow:0 26px 70px rgba(0,0,0,.5); }
body[data-world="still"] .card{ box-shadow:0 22px 60px rgba(20,19,16,.26); }

/* meta block — JS tweens transform/opacity on children. No transitions. */
/* meta is positioned by JS as a column beside the card (left/right/width
   inline, set once per layout). Text mass leans toward the card. */
#meta{
  position:absolute; z-index:5; top:50%;
  transform:translateY(-50%);
  pointer-events:none;
  transition:opacity .25s ease;   /* parent fade for detail — JS writes children only */
}
#meta > *{ transition:none; will-change:transform,opacity; }
body[data-world="video"] #meta{ text-align:left; }
body[data-world="still"] #meta{ text-align:right; }

.meta-code{
  font-size:10px; letter-spacing:.26em; opacity:.7;
  display:flex; align-items:center; gap:8px;
  margin-bottom:16px;
}
body[data-world="still"] .meta-code{ justify-content:flex-end; }
.meta-reddot{
  width:5px; height:5px; border-radius:50%; background:var(--red);
  display:inline-block; flex:none;
}
#meta h1{
  font-family:var(--disp); font-weight:500;
  font-variation-settings:"opsz" 100;
  font-size:clamp(1.9rem,3.1vw,3rem);
  line-height:1.08; letter-spacing:.002em;
  margin-bottom:16px;
}
.meta-sub{ font-size:10.5px; letter-spacing:.15em; opacity:.6; line-height:1.9; text-transform:uppercase; }

/* loop UI — JS aligns it with the title column (inline left/right) */
#loopui{
  position:absolute; bottom:7vh; z-index:5;
  display:flex; align-items:center; gap:14px;
  font-size:10px; letter-spacing:.2em; opacity:.75;
  font-variant-numeric:tabular-nums;
  transition:opacity .25s ease;
}
#progress{
  width:110px; height:1px; background:currentColor; opacity:.3;
  position:relative; display:inline-block;
}
#progress-fill{
  position:absolute; left:0; top:-0.5px; width:100%; height:2px;
  background:var(--ink);
  transform-origin:left center;
  transform:scaleX(0);
  transition:none;
}

/* projects chrome recedes while detail is open — fast, so nothing overlaps the caption */
#projects.detail-open #stage,
#projects.detail-open #meta,
#projects.detail-open #loopui,
#projects.detail-open #filters{ opacity:0; pointer-events:none; }
#projects.detail-open #modehead{ opacity:0; pointer-events:none; }
#stage{ transition-duration:.3s; }
#loopui, #modehead{ transition-duration:.25s; }

/* ============ detail view ============ */

#detail{
  position:fixed; inset:0; z-index:20;
  display:flex; align-items:center; justify-content:center;
  touch-action:pan-y;   /* keep horizontal gestures for the photo swipe */
}
#detail[hidden]{ display:none; }
#detail .dt-inner{
  position:relative;
  width:min(62vw,980px);
  opacity:0; transition:opacity .28s ease;
}
#detail.show .dt-inner{ opacity:1; transition-delay:.08s; }
/* still world: consistent square plate, photo contained inside */
#detail.square .dt-inner{ width:min(60vh,54vw,720px); }

#dt-frame{
  position:relative;
  width:100%;
  aspect-ratio:16/9;
  background:rgba(0,0,0,.2);
  box-shadow:0 30px 90px rgba(0,0,0,.4);
  overflow:hidden;
}
#dt-frame.square{
  aspect-ratio:1/1;
  background:var(--still-bg-soft);
  box-shadow:0 26px 80px rgba(20,19,16,.3);
  display:flex; align-items:center; justify-content:center;
}
body[data-world="video"] #dt-frame.square{ background:var(--video-bg-soft); box-shadow:0 30px 90px rgba(0,0,0,.4); }
#dt-frame img{
  width:100%; height:100%; object-fit:cover; display:block;
}
#dt-frame.square img{
  width:100%; height:100%;
  object-fit:contain;
}
/* gallery slides: absolutely stacked so two photos can glide past each
   other (carousel), both opaque — JS writes transform only */
.gal-img{
  position:absolute; inset:0;
  width:100%; height:100%; object-fit:contain;
  transition:none; will-change:transform;
}
#dt-frame iframe{
  position:absolute; inset:0; width:100%; height:100%; border:0;
}
/* self-hosted mp4: contain, not cover — a 9:16 file pillarboxes inside the
   16:9 plate exactly the way a YouTube embed would */
#dt-frame video{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:contain; background:#000; border:0; display:block;
}

/* YouTube facade play button — the record dot grown up */
#dt-play{
  position:absolute; left:50%; top:50%;
  width:76px; height:76px; margin:-38px 0 0 -38px;
  border-radius:50%; border:1px solid rgba(241,236,225,.85);
  background:rgba(16,15,13,.42);
  cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  transition:transform .3s ease, background-color .3s ease;
}
#dt-play::after{
  content:""; display:block;
  border-left:16px solid #f1ece1;
  border-top:10px solid transparent;
  border-bottom:10px solid transparent;
  margin-left:5px;
}
#dt-play:hover{ transform:scale(1.08); background:rgba(200,71,46,.85); }

/* gallery dots (photo position within the project) */
#dt-dots{
  position:absolute; left:0; right:0; bottom:12px;
  display:flex; justify-content:center; gap:8px;
  z-index:2;   /* above the sliding photos */
}
#dt-dots i{
  width:5px; height:5px; border-radius:50%;
  background:var(--ink); opacity:.35;
}
#dt-dots i.cur{ opacity:1; background:var(--red); }

/* caption plate — a film-credit strip under a hairline rule.
   Left: archive code + title + category. Right: spec columns. */
#dt-cap{
  position:relative;
  display:flex; justify-content:space-between; align-items:flex-start;
  gap:36px; padding-top:20px; margin-top:22px;
}
#dt-cap::before{
  content:""; position:absolute; top:0; left:0; right:0; height:1px;
  background:currentColor; opacity:.16;
}
.cap-code{
  font-size:9px; letter-spacing:.26em; opacity:.6;
  display:flex; align-items:center; gap:8px;
  margin-bottom:10px;
}
#dt-cap h2{
  font-family:var(--disp); font-weight:500;
  font-variation-settings:"opsz" 60;
  font-size:clamp(1.2rem,1.9vw,1.7rem);
  line-height:1.15; margin-bottom:6px;
}
#dt-cap .cap-l{ text-align:left; max-width:46%; flex:none; }
#dt-cap .cap-k{ font-size:9.5px; letter-spacing:.2em; opacity:.55; text-transform:uppercase; line-height:1.9; }
/* Client / Produced with / Role / Tools — one calm row of columns,
   tiny muted labels over sentence-case values (uppercase everywhere
   was the clutter) */
.cap-r{
  margin:0; padding-top:5px;
  display:flex; justify-content:flex-end;
  gap:clamp(22px,3vw,44px);
  flex-wrap:wrap;
  text-align:left;
}
.cap-r .spec dt{
  font-size:8.5px; letter-spacing:.26em; opacity:.45;
  text-transform:uppercase; margin-bottom:5px; white-space:nowrap;
}
.cap-r .spec dd{
  margin:0; font-size:12px; letter-spacing:.02em;
  font-weight:500; line-height:1.6; max-width:20ch;
}

/* JS-owned swap layer for prev/next transitions — no CSS transitions */
#dt-swap{ transition:none; will-change:transform,opacity; }

#dt-close{
  position:fixed; top:calc(var(--header-h) + 6px); right:calc(var(--edge) - 14px); z-index:22;
  width:56px; height:56px;
  background:none; border:0; cursor:pointer;
  font-family:var(--grot); font-size:20px; line-height:1;
  opacity:.8; transition:opacity .25s ease, transform .3s ease;
}
#dt-close:hover{ opacity:1; transform:rotate(90deg); }

/* edge arrows = photo carousel within the open project (hidden otherwise) */
.dt-arrow{
  position:fixed; top:50%; transform:translateY(-50%); z-index:21;
  width:56px; height:72px;
  background:none; border:0; cursor:pointer;
  font-size:20px; opacity:.4;
  transition:opacity .25s ease;
}
.dt-arrow:hover{ opacity:.95; color:var(--red); }
.dt-arrow[hidden]{ display:none; }
#dt-prev{ left:calc(var(--edge) - 14px); }
#dt-next{ right:calc(var(--edge) - 14px); }

/* ghost media for card→detail rack focus. It is the ONLY image on
   screen during the flight (the real frame is opacity-0 inline) and is
   swapped for the real frame in one instant at landing, where the
   pixels are identical — never crossfade the ghost with anything. */
.dt-ghost{
  position:fixed; left:0; top:0; z-index:21;
  transform-origin:top left;
  transition:transform .52s cubic-bezier(.3,.85,.25,1);
  will-change:transform;
  overflow:hidden;
  box-shadow:0 28px 80px rgba(0,0,0,.45);
}
.dt-ghost img{ width:100%; height:100%; object-fit:cover; display:block; }

/* ghost word for home→projects FLIP — crossfades into the real toggle
   before landing so the weight/metric mismatch never shows */
.word-ghost{
  position:fixed; z-index:45; left:0; top:0;
  font-family:var(--disp); font-weight:700; line-height:1;
  font-variation-settings:"opsz" 144;
  letter-spacing:.025em;
  transform-origin:top left;
  transition:transform .62s cubic-bezier(.3,.85,.25,1), opacity .24s ease .34s;
  pointer-events:none;
  will-change:transform;
}

/* ============ mobile menu (≤768px only) ============ */

#menu-btn{
  display:none;
  background:none; border:0; cursor:pointer;
  font:inherit; font-weight:600; letter-spacing:.18em;
  padding:8px 0 8px 12px;
  justify-self:end;
}
#mobile-menu{
  position:fixed; inset:0; z-index:60;
  background:rgba(13,12,10,.97);
  color:var(--video-ink);
  display:flex; flex-direction:column; justify-content:center;
  padding:0 9vw;
  opacity:0; pointer-events:none;
  transition:opacity .45s ease;
}
#mobile-menu.open{ opacity:1; pointer-events:auto; }
#mobile-menu nav{ display:flex; flex-direction:column; gap:3.2vh; }
#mobile-menu nav a{
  font-family:var(--disp); font-weight:600;
  font-variation-settings:"opsz" 100;
  font-size:clamp(1.6rem,7.2vw,2.1rem);
  line-height:1;
  transform:translateY(26px); opacity:0;
  transition:transform .65s cubic-bezier(.22,.9,.24,1), opacity .55s ease;
}
#mobile-menu.open nav a{ transform:none; opacity:1; }
#mobile-menu.open nav a:nth-child(1){ transition-delay:.1s; }
#mobile-menu.open nav a:nth-child(2){ transition-delay:.18s; }
#mobile-menu.open nav a:nth-child(3){ transition-delay:.26s; }
/* footer settles in last — the whole menu breathes instead of snapping */
#mobile-menu .mm-foot{
  opacity:0; transform:translateY(12px);
  transition:opacity .55s ease, transform .6s cubic-bezier(.22,.9,.24,1);
}
#mobile-menu.open .mm-foot{ opacity:.5; transform:none; transition-delay:.38s; }
#menu-close{
  position:absolute; top:10px; right:8px;
  width:52px; height:52px;
  background:none; border:0; cursor:pointer; color:inherit;
  font-size:20px;
}
.mm-foot{
  position:absolute; bottom:6vh; left:9vw; right:9vw;
  font-size:10px; letter-spacing:.16em; opacity:.5; line-height:2;
}

/* ============ page transition veil (first load only now) ============ */

#pageveil{
  position:fixed; inset:0; z-index:80;
  background:var(--bg);
  opacity:0; pointer-events:none;
  transition:opacity .3s ease;
}
#pageveil.on{ opacity:1; pointer-events:auto; }

/* ============ SPA page views (about / contact) ============ */

.page-view{
  position:fixed; inset:0; z-index:14;   /* above projects (12), below detail (20) */
  overflow-y:auto;
  -webkit-overflow-scrolling:touch;
  overscroll-behavior:contain;
  background:var(--still-bg);
  color:var(--still-ink);
}
.page-view[hidden]{ display:none; }
.page-view.view-in{ animation:viewIn .6s cubic-bezier(.22,.9,.24,1) both; }
@keyframes viewIn{ from{ opacity:0; transform:translate3d(0,22px,0); } to{ opacity:1; transform:none; } }
.page-view.view-out{ animation:viewOut .24s ease both; }
@keyframes viewOut{ to{ opacity:0; transform:translate3d(0,-12px,0); } }

/* content settles in as a stagger — one block after another */
.page-view.view-in .page > *{ animation:pageItem .55s cubic-bezier(.22,.9,.24,1) both; }
@keyframes pageItem{ from{ opacity:0; transform:translate3d(0,14px,0); } }
.page-view.view-in .page > *:nth-child(1){ animation-delay:.08s }
.page-view.view-in .page > *:nth-child(2){ animation-delay:.14s }
.page-view.view-in .page > *:nth-child(3){ animation-delay:.2s }
.page-view.view-in .page > *:nth-child(4){ animation-delay:.25s }
.page-view.view-in .page > *:nth-child(5){ animation-delay:.29s }
.page-view.view-in .page > *:nth-child(6){ animation-delay:.33s }
.page-view.view-in .page > *:nth-child(7){ animation-delay:.36s }
.page-view.view-in .page > *:nth-child(8){ animation-delay:.39s }
.page-view.view-in .page > *:nth-child(9){ animation-delay:.42s }
.page-view.view-in .page > *:nth-child(10){ animation-delay:.44s }
.page-view.view-in .page > *:nth-child(11){ animation-delay:.46s }
.page-view.view-in .page > *:nth-child(12){ animation-delay:.48s }
.page-view.view-in .page > *:nth-child(n+13){ animation-delay:.5s }

.page{ max-width:820px; margin:0 auto; padding:calc(var(--header-h) + 9vh) clamp(24px,6vw,64px) 12vh; }
/* headline scaled to CONVERSE with the text below it, not shout over it */
.page h1{ font-family:var(--disp); font-weight:480; font-variation-settings:"opsz" 100;
  font-size:clamp(2rem,4.4vw,3.3rem); line-height:1.08; margin-bottom:4vh; }
.page .lede{ font-size:16px; line-height:1.95; max-width:58ch; margin-bottom:5.5vh; }
.page .k{ font-size:10px; letter-spacing:.22em; opacity:.55; margin:4.5vh 0 1.6vh; text-transform:uppercase; }
.page .row{ display:flex; justify-content:space-between; gap:24px; padding:14px 0;
  border-top:1px solid rgba(20,19,16,.14); font-size:13.5px; }
.page .row b{ font-weight:600; } .page .row span{ opacity:.55; }
.page .tools{ font-size:13.5px; line-height:2; }
.page .big{ font-family:var(--disp); font-weight:480; font-variation-settings:"opsz" 60;
  font-size:clamp(1.15rem,2.3vw,1.55rem); }
.page .big a{ border-bottom:1px solid rgba(20,19,16,.25); }
.page .big a:hover{ border-color:var(--red); }
.page .small{ font-size:13.5px; line-height:2; }

/* client logo marquee — infinite, slow, left→right. Two identical
   groups; JS drives the track transform in MEASURED px (app.js) and
   wraps at one group-width, so the seam is invisible. Hover pauses;
   the strip is grabbable/flickable — pan-y keeps vertical page scroll. */
.logo-marquee{
  overflow:hidden;
  margin:2.2vh 0 .6vh;
  cursor:grab;
  touch-action:pan-y;
  user-select:none; -webkit-user-select:none;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 9%,#000 91%,transparent);
}
.logo-marquee.dragging{ cursor:grabbing; }
.logo-track{
  display:flex; width:max-content;
  transition:none;              /* JS owns transform — never transition it */
  will-change:transform;
}
.logo-group{
  display:flex; align-items:center; flex:none;
  gap:clamp(44px,5.5vw,76px);
  padding-right:clamp(44px,5.5vw,76px);
}
.logo-group img{
  height:24px; width:auto; flex:none;
  opacity:.68;
  pointer-events:none;          /* drags read the strip, not the images */
}

/* ============ mobile ============ */

@media (max-width:768px){
  :root{ --header-h:60px; --edge:20px; }
  /* MF· mark left, MENU right */
  #site-header{
    font-size:10px;
    display:grid; grid-template-columns:auto 1fr;
    align-items:center;
  }
  #wordmark{ grid-column:1; grid-row:1; justify-self:start; }
  .wm-mf i{ display:none; }   /* quiet mark — accent budget stays on content */
  /* MENU → two-line "stairs" glyph, right-aligned */
  #menu-btn{
    display:block; grid-column:2; grid-row:1; justify-self:end;
    position:relative; width:44px; height:44px;
    font-size:0; padding:0;
  }
  #menu-btn::before, #menu-btn::after{
    content:""; position:absolute; right:0; top:50%;
    height:1.5px; background:currentColor;
  }
  #menu-btn::before{ width:20px; transform:translateY(-4px); }
  #menu-btn::after{ width:13px; transform:translateY(3px); }
  .wm-full{ display:none; }
  .wm-mf{ display:inline-flex; }
  #site-header nav{ display:none; }
  /* narrow hover-capable windows keep the desktop home layout, where
     the one-line tagline overflows — it's decorative, so it goes.
     Real phones (hover:none) already hide it above. */
  .home-line{ display:none; }

  #modehead{ top:calc(var(--header-h) + 4.5vh); }
  #worldtoggle button{ font-size:1.45rem; }
  /* filter picker: selected chip lives in the center; neighbours recede */
  #filters{
    margin-top:14px;
    justify-content:flex-start;
    overflow-x:auto; scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
    touch-action:pan-x;
    scroll-snap-type:x mandatory;
    padding:8px calc(50vw - 44px);
    gap:26px;
    -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 12vw,#000 88vw,transparent 100%);
    mask-image:linear-gradient(90deg,transparent 0,#000 12vw,#000 88vw,transparent 100%);
  }
  #filters::-webkit-scrollbar{ display:none; }
  #filters button{
    font-size:12px;
    scroll-snap-align:center;
    opacity:1;                       /* JS drives opacity/scale by distance */
    transition:filter .3s ease;      /* tiny text, discrete state — cheap */
    will-change:transform,opacity;
  }
  #filters button.chip-dim{ filter:blur(1.3px); }

  .card{ width:90vw; }

  /* meta sits right under the card: cardBottom = 45vh + 90vw*(9/16)/2 */
  #meta, body[data-world="video"] #meta, body[data-world="still"] #meta{
    left:6vw !important; right:6vw !important; width:auto !important;
    top:calc(45vh + 25.4vw + 30px); bottom:auto;
    transform:none;
    text-align:center;
  }
  .meta-code, body[data-world="video"] .meta-code, body[data-world="still"] .meta-code{ justify-content:center; margin-bottom:10px; }
  #meta h1{ font-size:clamp(1.6rem,7.2vw,2.3rem); margin-bottom:10px; }
  .meta-sub{ font-size:10px; }

  #loopui{
    left:50% !important; right:auto !important;
    bottom:calc(5vh + env(safe-area-inset-bottom));
    transform:translateX(-50%);
  }
  #counter{ font-size:11px; }
  #progress{ width:120px; }

  /* detail on mobile */
  #detail .dt-inner{ width:92vw; }
  #detail.square .dt-inner{ width:min(88vw,58vh); }
  #dt-cap{ flex-direction:column; gap:16px; padding-top:16px; }
  #dt-cap .cap-l{ max-width:100%; }
  .cap-r{ justify-content:flex-start; text-align:left; gap:14px 24px; padding-top:0; }

  /* SPA pages on mobile */
  .page{ padding:calc(var(--header-h) + 5vh) 24px 10vh; }
  .page h1{ font-size:clamp(1.55rem,6.4vw,2rem); margin-bottom:3vh; }
  .page .lede{ font-size:14px; line-height:1.9; margin-bottom:4.5vh; }
  .page .row{ font-size:12.5px; flex-direction:column; gap:2px; padding:12px 0; }
  .page .tools{ font-size:13px; }
  .page .big{ font-size:clamp(1rem,4.2vw,1.25rem); word-break:break-word; }
  .page .small{ font-size:13px; }
  .logo-group{ gap:34px; padding-right:34px; }
  .logo-group img{ height:19px; }
  #dt-close{ top:calc(var(--header-h) - 2px); right:6px; }
  /* no edge arrows on mobile — swipe + dots carry the gallery
     (the floating mid-screen arrows read as misplaced) */
  .dt-arrow{ display:none; }
  #dt-dots{ bottom:14px; }
  #dt-dots i{ width:6px; height:6px; }
}

/* ============ reduced motion ============ */

@media (prefers-reduced-motion:reduce){
  *, *::before, *::after{
    transition-duration:.001s !important;
    animation-duration:.001s !important;
  }
  .hero-dot{ animation:none; }
  .bd img{ animation:none; }
  /* logo marquee: JS checks reduced-motion itself (no auto-drift,
     drag without momentum) — nothing to disable here */
}
