/* ═══════════════════════════════════════════════════════════════
   steady sun v2 · warm, food forward. See BRIEF.md
   ═══════════════════════════════════════════════════════════════ */
:root{
  --bone:#FAF6EF; --bone-2:#F1E9DC; --bone-3:#E4D8C5;
  --ink:#221B14; --ink-2:#4E4034; --ink-3:#716252;
  --char:#1A1410; --char-2:#241C16;
  --gold:#B4802C; --gold-2:#E0A94F;
  --rule:rgba(34,27,20,.14);
  /* 1560 capped content at 13.9% inset on a 1920 screen, which read as a
     margin rather than a layout. 1920 keeps the gutter proportion the same
     (4.5%) from 1440 up to 1920, and still caps genuinely huge displays. */
  --maxw:1920px;
  --gut:clamp(1.15rem,4.5vw,5.5rem);
  --e-out:cubic-bezier(.23,1,.32,1);
  --e-io:cubic-bezier(.77,0,.175,1);
  --serif:"Fraunces",Georgia,serif;
  --sans:"Montserrat",ui-sans-serif,system-ui,sans-serif;
}
*,*::before,*::after{box-sizing:border-box}
html{
  -webkit-text-size-adjust:100%; color-scheme:light;
  scroll-padding-top:clamp(4.5rem,9vh,6.5rem);
}
@media (prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}
body{
  margin:0; background:var(--bone); color:var(--ink);
  font-family:var(--sans); font-size:clamp(.975rem,.93rem + .18vw,1.0625rem);
  line-height:1.6; overflow-x:hidden;
  touch-action:manipulation; -webkit-tap-highlight-color:rgba(180,128,44,.18);
  -webkit-font-smoothing:antialiased;
}
body.locked{overflow:hidden}
img{display:block;max-width:100%;height:auto}
a{color:inherit}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px}

h1,h2,h3{font-family:var(--serif);font-weight:400;font-optical-sizing:auto;
  letter-spacing:-.026em;line-height:1;margin:0;text-wrap:balance}
p{margin:0 0 1.1em;max-width:62ch;text-wrap:pretty}
p:last-child{margin-bottom:0}

.wrap{width:100%;max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gut)}
.eyebrow{font-size:.6875rem;letter-spacing:.2em;text-transform:uppercase;
  font-weight:500;color:var(--ink-3);font-variant-numeric:tabular-nums}
.lede{font-size:clamp(1.05rem,.98rem + .45vw,1.35rem);line-height:1.5;color:var(--ink-2)}
.dark{--bone:var(--char);--bone-2:var(--char-2);--ink:#F6EFE3;--ink-2:#D3C5B1;
  --ink-3:#9C8A75;--rule:rgba(246,239,227,.16);--gold:#E0A94F;
  background:var(--bone);color:var(--ink)}

/* grain, fixed and inert */
.grain{position:fixed;inset:-50%;z-index:60;pointer-events:none;opacity:.045;
  mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}

.skip{position:fixed;top:.6rem;left:.6rem;z-index:120;background:var(--ink);
  color:var(--bone);padding:.7rem 1.1rem;font-size:.8125rem;text-decoration:none;
  transform:translateY(-160%);transition:transform 160ms var(--e-out)}
.skip:focus-visible{transform:translateY(0)}

/* ══ NAV ══ */
.nav{position:fixed;inset:0 0 auto 0;z-index:50;display:flex;align-items:center;
  gap:1.5rem;color:#F6EFE3;
  padding:clamp(.9rem,1.9vw,1.3rem) var(--gut);
  /* The bar stays full-bleed so its stuck background spans the screen, but its
     CONTENTS have to line up with the capped containers below it (.wrap,
     .hero-in, .band-in). Without this the wordmark hugs the gutter while the
     headline is centred inside --maxw, and they drift apart above 1560px:
     60px at 1680, 180px at 1920, 500px at 2560. Padding does what a
     max-width would, without shrinking the background. */
  --nav-inset:max(var(--gut),calc((100% - var(--maxw)) / 2 + var(--gut)));
  padding-left:max(var(--nav-inset),env(safe-area-inset-left));
  padding-right:max(var(--nav-inset),env(safe-area-inset-right));
  transition:background-color 280ms ease,color 280ms ease}
.nav::after{content:"";position:absolute;inset:auto 0 0 0;height:1px;
  background:var(--rule);opacity:0;transition:opacity 280ms ease}
.nav.stuck{background:var(--bone);color:var(--ink)}
.nav.stuck::after{opacity:1}
.brand{font-family:var(--serif);font-size:1.0625rem;text-decoration:none;
  margin-right:auto;display:inline-flex;align-items:baseline;gap:.42rem;white-space:nowrap}
.brand i{width:.44rem;height:.44rem;border-radius:50%;background:var(--gold-2);
  flex:none;transform:translateY(-.06rem)}
.nav.stuck .brand i{background:var(--gold)}
.nav-links{display:flex;align-items:center;gap:clamp(1.1rem,2vw,2rem)}
.nav-links a{text-decoration:none;font-size:.8125rem;letter-spacing:.08em;
  text-transform:uppercase;font-weight:500;position:relative;padding-block:.3rem}
.nav-links a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:left;
  transition:transform 220ms var(--e-out)}
@media (hover:hover) and (pointer:fine){.nav-links a:hover::after{transform:scaleX(1)}}
.book{border:1px solid currentColor;padding:.52rem 1.05rem;font-size:.75rem;
  letter-spacing:.1em;text-transform:uppercase;font-weight:500;text-decoration:none;
  white-space:nowrap;transition:transform 160ms var(--e-out)}
.book:active{transform:scale(.97)}
.burger{display:none;width:2.75rem;height:2.75rem;margin-right:-.6rem;position:relative}
.burger span{position:absolute;left:.55rem;right:.55rem;height:1.5px;background:currentColor;
  transition:transform 240ms var(--e-out)}
.burger span:nth-child(1){top:1.02rem}
.burger span:nth-child(2){top:1.44rem}
.nav.open .burger span:nth-child(1){transform:translateY(.21rem) rotate(45deg)}
.nav.open .burger span:nth-child(2){transform:translateY(-.21rem) rotate(-45deg)}
@media (max-width:900px){
  .burger{display:block}
  /* The open menu owns the whole screen. The old panel only wrapped the
     links, so the page showed through underneath and the book button fell
     back into the header row beside the wordmark. */
  .nav-links{position:fixed;inset:0;background:var(--bone);color:var(--ink);
    flex-direction:column;align-items:flex-start;justify-content:center;gap:0;
    padding:5.2rem var(--gut) 8rem;display:none}
  .nav.open{background:var(--bone);color:var(--ink)}
  .nav.open .nav-links{display:flex}
  .nav.open .brand,.nav.open .burger{position:relative;z-index:2}
  .nav.open .book{display:block;position:fixed;z-index:2;
    left:var(--gut);right:var(--gut);
    bottom:max(1.8rem,env(safe-area-inset-bottom));
    text-align:center;padding-block:1rem}
  .nav:not(.open) .book{display:none}
  .nav-links a{font-family:var(--serif);font-size:2rem;text-transform:none;
    letter-spacing:-.015em;padding-block:1.05rem;width:100%;
    border-bottom:1px solid var(--rule)}
  .nav-links a:last-child{border-bottom:none}
  .nav-links a::after{display:none}
  /* the page behind the panel must not scroll while the menu is up */
  body.locked{overflow:hidden}
}

/* ══ HERO · food first ══ */
.hero{position:relative;min-height:100svh;display:flex;align-items:flex-end;isolation:isolate}
.hero-img{position:absolute;inset:0;z-index:-2;overflow:hidden}
.hero-img img{width:100%;height:100%;object-fit:cover;object-position:50% 46%;
  transform:scale(1.06);transform-origin:52% 46%}
@media (prefers-reduced-motion:no-preference){
  .hero-img img{animation:drift 22s var(--e-io) infinite alternate}
}
@keyframes drift{to{transform:scale(1.16) translate3d(-1.2%,-1%,0)}}
/* bottom for the headline, top so the nav reads, left so the eyebrows and
   body copy survive the bright pastry underneath them */
.hero::before{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(to top,rgba(26,20,16,.86) 0%,rgba(26,20,16,.63) 32%,rgba(26,20,16,.34) 58%,rgba(26,20,16,0) 82%),
  linear-gradient(to bottom,rgba(26,20,16,.5) 0%,rgba(26,20,16,.13) 9%,rgba(26,20,16,0) 20%),
  linear-gradient(to right,rgba(26,20,16,.72) 0%,rgba(26,20,16,.46) 28%,rgba(26,20,16,.14) 48%,rgba(26,20,16,0) 68%)}
.hero-in{width:100%;max-width:var(--maxw);margin-inline:auto;color:#FBF6EC;
  padding:0 var(--gut) calc(clamp(2.2rem,6vh,4rem) + env(safe-area-inset-bottom));
  padding-left:max(var(--gut),env(safe-area-inset-left))}
.hero h1{font-size:clamp(3.2rem,1.4rem + 8.4vw,9.5rem);font-weight:300;
  letter-spacing:-.045em;line-height:.86;margin-bottom:.18em}
.hero-line{font-family:var(--serif);font-weight:300;line-height:1.16;
  font-size:clamp(1.3rem,1rem + 1.5vw,2.6rem);letter-spacing:-.018em;
  max-width:17ch;margin:0 0 1.2rem}
.hero-sub{max-width:44ch;color:rgba(251,246,236,.82);font-size:.9375rem;line-height:1.65;margin:0}
.hero-cta{display:flex;flex-wrap:wrap;gap:.7rem;margin-top:clamp(1.5rem,3vw,2.2rem)}
/* Lives in the footer band, not above the wordmark. High-key food photography
   cannot hold 11px light type at 4.5:1 anywhere in the upper frame, and the
   scrim needed to force it there turned the photograph to mud. */
.hero-meta{display:flex;flex-wrap:wrap;gap:.5rem 1rem;align-items:center;
  color:rgba(251,246,236,.9)}
/* .eyebrow sets --ink-3 on itself, which measures 3.41:1 against the hero
   scrim. On a photograph the eyebrows inherit the light colour instead. */
.hero-meta .eyebrow,.pj-hero-foot .eyebrow{color:inherit}
.hero-meta .tick{width:1.9rem;height:1px;background:currentColor;opacity:.5}
.hero-foot{display:flex;justify-content:space-between;align-items:flex-end;gap:2rem;
  margin-top:clamp(1.8rem,5vh,3rem);border-top:1px solid rgba(251,246,236,.22);padding-top:1rem}
.hero-cred{font-size:.75rem;letter-spacing:.05em;color:rgba(251,246,236,.78);margin:0}
@media (max-width:560px){.hero-foot{flex-direction:column;align-items:flex-start;gap:.8rem}}
.cue{display:inline-flex;align-items:center;gap:.6rem;text-decoration:none;
  color:rgba(251,246,236,.85);font-size:.6875rem;letter-spacing:.19em;
  text-transform:uppercase;font-weight:500;white-space:nowrap}
.cue b{display:block;width:2.6rem;height:1px;background:currentColor;position:relative;overflow:hidden}
.cue b::after{content:"";position:absolute;inset:0;background:var(--gold-2);transform:translateX(-100%)}
@media (prefers-reduced-motion:no-preference){.cue b::after{animation:sweep 2.6s var(--e-io) 3}}
@keyframes sweep{0%{transform:translateX(-100%)}55%,100%{transform:translateX(100%)}}

/* ══ SECTIONS ══ */
.sect{padding-block:clamp(4.5rem,10vw,9.5rem)}
.head{display:grid;gap:1.5rem;padding-top:1.3rem;border-top:1px solid var(--rule);
  margin-bottom:clamp(2.4rem,5vw,4.5rem)}
@media (min-width:940px){
  .head{grid-template-columns:minmax(0,8rem) minmax(0,1fr) minmax(0,30rem);gap:2.5rem;align-items:start}
}
.head h1,.head h2{font-size:clamp(2.1rem,1.3rem + 3.2vw,4.6rem);font-weight:300;letter-spacing:-.032em}

/* ══ THE REEL · a continuous drift, both breakpoints ══
   Kevin asked for autoscroll everywhere, so the reel borrows the client
   marquee's loop: two identical runs, the track slides half its width.
   Spacing is baked into the runs, not the track, so the wrap seam is the
   same width as every other gap. */
.reel-sect{position:relative;background:var(--char);color:#F6EFE3;overflow:hidden}
.reel-head{padding:clamp(3.5rem,8vw,7rem) var(--gut) clamp(1.5rem,3vw,2.5rem);
  max-width:var(--maxw);margin-inline:auto}
.reel-head h2{font-size:clamp(2rem,1.2rem + 3.2vw,4.4rem);font-weight:300;
  letter-spacing:-.032em;color:#F6EFE3;margin-bottom:.5rem}
.reel-head .eyebrow{color:#9C8A75}
.reel-head p{color:#D3C5B1;max-width:46ch;margin-top:.9rem}
.reel-pin{padding-bottom:clamp(3.5rem,8vw,7rem)}
.reel-track{display:flex;width:max-content}
.reel-run{display:flex;align-items:flex-start;
  gap:clamp(1rem,2.2vw,2.2rem);padding-left:clamp(1rem,2.2vw,2.2rem)}
.frame{flex:0 0 auto;position:relative}
/* one height for every frame, widths following the photograph: a filmstrip */
/* .plate-btn img sets width:100% for the plate grids and sits later in the
   file; the reel needs the opposite axis fixed, so these are scoped one
   level deeper to outrank it. */
.frame .plate-btn{width:auto;background:none}
.frame .plate-btn img{height:min(46svh,26rem);width:auto;max-width:none;
  background:#2A211A;display:block}
@media (min-width:901px){.frame .plate-btn img{height:min(56svh,31rem)}}
.frame figcaption{display:flex;justify-content:space-between;gap:1rem;align-items:baseline;
  margin-top:.7rem;padding-top:.5rem;border-top:1px solid rgba(246,239,227,.18)}
.frame .no{font-variant-numeric:tabular-nums;letter-spacing:.14em;font-size:.6875rem;
  color:#9C8A75;font-weight:500}
.frame .ttl{font-family:var(--serif);font-size:.9375rem;color:#D3C5B1}
.frame .pl{font-size:.6875rem;letter-spacing:.13em;text-transform:uppercase;
  color:#9C8A75;white-space:nowrap}
@keyframes reelDrift{to{transform:translate3d(-50%,0,0)}}
@media (prefers-reduced-motion:no-preference){
  /* linear on purpose: any easing makes the wrap audible as a stutter */
  .reel-track{animation:reelDrift 75s linear infinite;will-change:transform}
}
/* motion off: one run, swiped by hand */
@media (prefers-reduced-motion:reduce){
  .reel-run[aria-hidden]{display:none}
  .reel-track{width:auto}
  .reel-pin{overflow-x:auto;scroll-snap-type:x proximity;-webkit-overflow-scrolling:touch;
    scrollbar-width:none}
  .reel-pin::-webkit-scrollbar{display:none}
  .frame{scroll-snap-align:center}
}

/* ══ CLIENT LIST ══ */
.clients{display:flex;flex-wrap:wrap;gap:.5rem .5rem;margin-top:2rem}
.clients span{border:1px solid var(--rule);padding:.45rem 1rem;font-size:.8125rem;
  letter-spacing:.02em;color:var(--ink-2)}

/* ══ SELECTED CLIENTS ═══════════════════════════════════════════
   Kevin asked for a client carousel like the one on vlslg.com. He has
   the names but not the logo files, so this runs as type. That suits the
   monograph better anyway: a line of names set in Fraunces reads like a
   title page, where a row of mismatched logos reads like a trust badge
   bolted onto the front.

   The band is masked at both edges rather than hard-clipped, so names
   arrive and leave instead of popping in at a cut line. */
.marq-sect{padding:clamp(3.4rem,6.5vw,6rem) 0;border-top:1px solid var(--rule)}
.marq-head{display:flex;flex-direction:column;gap:.85rem;
  margin-bottom:clamp(1.9rem,3.8vw,3rem)}
.marq-line{font-family:var(--serif);font-weight:300;
  font-size:clamp(1.45rem,1.05rem + 1.8vw,2.8rem);line-height:1.22;
  letter-spacing:-.026em;color:var(--ink);max-width:21ch;margin:0;
  text-wrap:balance}

.marq{position:relative;overflow:hidden;
  border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);
  padding:clamp(1.1rem,2.2vw,1.75rem) 0;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.marq-track{display:flex;width:max-content}
.marq-run{display:flex;align-items:center;flex:0 0 auto}
.marq-i{display:flex;align-items:center;white-space:nowrap;
  font-family:var(--serif);font-weight:300;letter-spacing:-.015em;
  font-size:clamp(1.1rem,.92rem + .85vw,1.75rem);color:var(--ink-2);
  padding-right:clamp(1.3rem,2.8vw,2.6rem)}
/* a lozenge between names, the way a printed colophon separates entries */
.marq-i::after{content:"";width:5px;height:5px;background:var(--gold);
  transform:rotate(45deg);margin-left:clamp(1.3rem,2.8vw,2.6rem);opacity:.8}

@keyframes marq{to{transform:translate3d(-50%,0,0)}}
@media (prefers-reduced-motion:no-preference){
  /* linear on purpose. Any easing makes the seam audible as a stutter at
     the wrap, because the speed at the end of a cycle no longer matches
     the speed at the start of the next one. */
  /* Runs through hover on purpose. A band that stops under the cursor reads
     as broken rather than considerate, and there is nothing focusable inside
     it to pause for either. */
  .marq-track{animation:marq 46s linear infinite;will-change:transform}
}
/* Motion off: the duplicate run has nothing left to do, and the single
   run wraps onto as many lines as it needs instead of running off the
   edge into the overflow. */
@media (prefers-reduced-motion:reduce){
  .marq{-webkit-mask-image:none;mask-image:none}
  .marq-track{width:auto}
  .marq-run{flex-wrap:wrap;justify-content:center;row-gap:.55rem}
  .marq-run+.marq-run{display:none}
  .marq-run .marq-i:last-child{padding-right:0}
  .marq-run .marq-i:last-child::after{display:none}
}

/* ══ PLATE GRID ══ */
.plates{display:grid;grid-template-columns:1fr;gap:clamp(2.4rem,5vw,4rem)}
@media (min-width:820px){
  .plates{grid-template-columns:repeat(12,1fr);
    gap:clamp(2.6rem,4.2vw,5rem) clamp(1rem,2.2vw,2rem);align-items:start}
  .plate{grid-column:var(--col) / span var(--span);margin-top:var(--drop,0)}
}
.plate{margin:0;position:relative}
.plate-btn{display:block;width:100%;padding:0;text-align:left;position:relative;background:var(--bone-2)}
.plate-frame{overflow:hidden;position:relative;display:block}
.plate-btn img{width:100%;height:auto;transition:transform 800ms var(--e-out)}
@media (hover:hover) and (pointer:fine){.plate-btn:hover img{transform:scale(1.02)}}
.plate-btn::after{content:"";position:absolute;inset:0;pointer-events:none;
  box-shadow:inset 0 0 0 1px rgba(34,27,20,.07)}
.plate-meta{display:flex;justify-content:space-between;gap:1rem;align-items:baseline;
  margin-top:.7rem;padding-top:.5rem;border-top:1px solid var(--rule)}
.plate-no{font-variant-numeric:tabular-nums;letter-spacing:.14em;font-size:.6875rem;
  color:var(--ink-3);font-weight:500}
.plate-name{font-family:var(--serif);font-size:.9375rem;color:var(--ink-2)}
.plate-place{font-size:.6875rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--ink-3);white-space:nowrap}
@media (prefers-reduced-motion:no-preference){
  .plates.reveal .plate{opacity:0;transform:translateY(20px);
    transition:opacity 640ms var(--e-out),transform 760ms var(--e-out)}
  .plates.reveal .plate .plate-frame{clip-path:inset(0 0 100% 0);
    transition:clip-path 900ms var(--e-io)}
  .plates.reveal .plate.in{opacity:1;transform:none}
  .plates.reveal .plate.in .plate-frame{clip-path:inset(0 0 0 0)}
}

/* ══ SERVICES / PROCESS ══ */
.svc{list-style:none;margin:2.2rem 0 0;padding:0;border-top:1px solid var(--rule)}
.svc li{padding:1.15rem 0;border-bottom:1px solid var(--rule);display:grid;gap:.3rem}
@media (min-width:640px){.svc li{grid-template-columns:minmax(0,16rem) minmax(0,1fr);gap:1.5rem;align-items:baseline}}
.svc h3{font-size:1.24rem;font-weight:400}
.svc p{font-size:.9063rem;color:var(--ink-2);margin:0}
.steps{list-style:none;margin:0;padding:0;counter-reset:s;border-top:1px solid var(--rule)}
.steps li{counter-increment:s;border-bottom:1px solid var(--rule);
  padding:clamp(1.2rem,2.4vw,1.8rem) 0;display:grid;gap:.4rem}
@media (min-width:760px){.steps li{grid-template-columns:4.5rem minmax(0,14rem) minmax(0,1fr);gap:2rem;align-items:baseline}}
.steps li::before{content:counter(s,decimal-leading-zero);font-variant-numeric:tabular-nums;
  font-size:.75rem;letter-spacing:.16em;color:var(--gold);font-weight:500}
.steps h3{font-size:clamp(1.25rem,1.1rem + .7vw,1.65rem);font-weight:400}
.steps p{color:var(--ink-2);font-size:.9375rem;margin:0}

/* ══ ABOUT / CONTACT ══ */
.two{display:grid;gap:clamp(2.2rem,5vw,4.5rem)}
@media (min-width:980px){.two{grid-template-columns:minmax(0,.9fr) minmax(0,1fr);gap:clamp(3rem,6vw,6rem)}}
.about-body p:first-of-type{font-family:var(--serif);
  font-size:clamp(1.35rem,1.05rem + 1.3vw,2.1rem);line-height:1.3;
  letter-spacing:-.02em;color:var(--ink);max-width:23ch}
.about-body p{color:var(--ink-2)}
.sign{margin-top:1.8rem;font-family:var(--serif);font-size:1.15rem;color:var(--ink-3)}
.contact-h{font-size:clamp(2rem,1.2rem + 3.6vw,4.6rem);font-weight:300;
  letter-spacing:-.034em;max-width:16ch}
.cta{display:flex;flex-wrap:wrap;gap:.75rem;margin-top:1.9rem}
.btn{display:inline-flex;align-items:center;gap:.65rem;text-decoration:none;
  padding:.92rem 1.6rem;font-size:.8125rem;letter-spacing:.1em;text-transform:uppercase;
  font-weight:500;border:1px solid currentColor;
  transition:transform 160ms var(--e-out),background-color 160ms ease,color 160ms ease}
.btn-solid{background:var(--gold);border-color:var(--gold);color:#1A1410}
@media (hover:hover) and (pointer:fine){
  .btn-solid:hover{background:var(--gold-2);border-color:var(--gold-2)}
  .btn-ghost:hover{background:var(--ink);color:var(--bone)}
}
.btn:active{transform:scale(.97)}
.clist{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule);
  max-width:34rem;margin-left:auto;width:100%}
.clist li{padding:.85rem 0;border-bottom:1px solid var(--rule);display:flex;
  justify-content:space-between;gap:1rem;align-items:baseline}
.clist a{text-decoration:none;border-bottom:1px solid var(--rule)}
.foot{padding:clamp(2.4rem,5vw,3.6rem) 0 clamp(1.8rem,4vw,2.6rem);border-top:1px solid var(--rule)}
.foot-row{display:flex;flex-wrap:wrap;gap:1rem 2rem;justify-content:space-between;align-items:center}
.foot-note{margin-top:1.6rem;padding-top:1.1rem;border-top:1px solid var(--rule);
  font-size:.75rem;color:var(--ink-3);line-height:1.6}
/* Copyright left, studio credit right, one hairline between them and the
   row above. On a phone the two spans wrap into stacked left lines. */
.foot-note{display:flex;flex-wrap:wrap;gap:.3rem 2rem;justify-content:space-between}

/* ══ LOUPE ══ */
.loupe{position:fixed;top:0;left:0;z-index:55;pointer-events:none;
  width:13rem;height:13rem;margin:-6.5rem 0 0 -6.5rem;border-radius:50%;
  background-repeat:no-repeat;box-shadow:0 18px 50px -12px rgba(26,20,16,.55),
  inset 0 0 0 1px rgba(251,246,236,.5);opacity:0;transform:scale(.7);
  transition:opacity 200ms ease,transform 320ms var(--e-out)}
.loupe.on{opacity:1;transform:scale(1)}
body.loupe-live .plate-btn,body.loupe-live .frame img,body.loupe-live .pl-btn{cursor:none}

/* ══ LIGHTBOX ══ */
.lb{border:0;padding:0;margin:0;width:100%;max-width:100%;height:100%;max-height:100%;
  background:var(--bone);color:var(--ink);overflow:hidden;overscroll-behavior:contain;
  padding-bottom:env(safe-area-inset-bottom)}
.lb::backdrop{background:rgba(20,15,11,.94)}
.lb[open]{display:flex;flex-direction:column}
@media (prefers-reduced-motion:no-preference){
  .lb[open]{animation:lbIn 300ms var(--e-out)}
  .lb.closing{animation:lbOut 190ms ease forwards}
}
@keyframes lbIn{from{opacity:0;transform:scale(.975)}to{opacity:1;transform:none}}
@keyframes lbOut{to{opacity:0;transform:scale(.985)}}
.lb-bar,.lb-foot{display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding:clamp(.85rem,2vw,1.3rem) clamp(1rem,3vw,2.2rem);flex:none}
.lb-bar{border-bottom:1px solid var(--rule)}
.lb-foot{border-top:1px solid var(--rule);align-items:flex-end}
.lb-count{font-variant-numeric:tabular-nums;letter-spacing:.16em;font-size:.75rem;
  color:var(--ink-3);font-weight:500}
.lb-stage{flex:1;min-height:0;display:flex;align-items:center;justify-content:center;
  padding:clamp(1rem,2.5vw,2rem) clamp(1rem,3vw,2.5rem)}
.lb-stage img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  transition:opacity 150ms ease}
.lb-stage img.swap{opacity:0}
.lb-cap h3{font-size:clamp(1.05rem,.95rem + .5vw,1.5rem);font-weight:400;margin-bottom:.2rem}
.lb-nav{display:flex;gap:.5rem;flex:none}
.lb-btn{width:2.9rem;height:2.9rem;border:1px solid var(--rule);display:grid;place-items:center;
  transition:background-color 160ms ease,color 160ms ease,transform 160ms var(--e-out)}
@media (hover:hover) and (pointer:fine){.lb-btn:hover{background:var(--ink);color:var(--bone);border-color:var(--ink)}}
.lb-btn:active{transform:scale(.94)}
.lb-btn svg{width:1.05rem;height:1.05rem;fill:none;stroke:currentColor;stroke-width:1.4}
@media (max-width:640px){.lb-foot{flex-direction:column;align-items:stretch;gap:.9rem}
  .lb-nav{justify-content:space-between}.lb-btn{flex:1}}

/* ══ LOADER ═════════════════════════════════════════════════════
   Hidden by default and only revealed once an inline script in <head>
   has added .preload to <html>. So if JavaScript never runs there is no
   overlay at all, rather than an opaque panel covering the whole site
   forever. Same contract as every other hidden state here.

   It shows once per session, so clicking through to Work or a project
   does not sit you through it again. */
.load{display:none}
html.preload .load{position:fixed;inset:0;z-index:100;background:var(--bone);
  display:grid;place-items:center;
  clip-path:inset(0 0 0 0);
  transition:clip-path 640ms var(--e-io);
  /* failsafe: if the finish handler never runs, the panel still leaves.
     Nothing on this site is allowed to strand. */
  animation:loadBail 1ms linear 6s forwards}
@keyframes loadBail{to{opacity:0;visibility:hidden;pointer-events:none}}
/* Two stages, and they must not overlap. .done completes the bar while the
   panel is still up; .out clears it afterwards. Running both at once was the
   bug: the fill was still in flight when the panel started leaving, so the bar
   appeared to stall around 80% and then the site just appeared.

   The exit is six slats lifting in sequence rather than one flat wipe. The
   ground travels with them, so the panel's own background is dropped the
   instant .out lands and the slats become the only thing covering the page.
   The stagger is small on purpose: 40ms across six is a lean, not a wave, so
   it still reads as one gesture. */
.load.out{background:transparent}

.load-slats{position:absolute;inset:0;display:flex;z-index:0}
.load-slats i{flex:1 0 auto;background:var(--bone);
  /* a hair of overlap, or sub-pixel rounding shows the page through the seams */
  margin-right:-1px;
  transform:translateY(0);
  transition:transform 780ms cubic-bezier(.72,0,.16,1)}
.load-slats i:last-child{margin-right:0}
.load.out .load-slats i{transform:translateY(-101%)}
.load.out .load-slats i:nth-child(1){transition-delay:0ms}
.load.out .load-slats i:nth-child(2){transition-delay:38ms}
.load.out .load-slats i:nth-child(3){transition-delay:76ms}
.load.out .load-slats i:nth-child(4){transition-delay:114ms}
.load.out .load-slats i:nth-child(5){transition-delay:152ms}
.load.out .load-slats i:nth-child(6){transition-delay:190ms}

.load-in{display:grid;justify-items:center;gap:1.15rem;position:relative;z-index:1;
  transition:opacity 240ms ease,transform 420ms var(--e-out)}
/* the mark clears out just ahead of the slats, so it is never sliced by them */
.load.out .load-in{opacity:0;transform:translateY(-10px)}

/* reduced motion gets the same exit without the travel: a straight fade */
@media (prefers-reduced-motion:reduce){
  .load-slats i{transition:opacity 200ms linear!important;transform:none!important}
  .load.out .load-slats i{opacity:0}
}
.load-mark{font-family:var(--serif);font-size:1.4rem;letter-spacing:-.01em;
  display:inline-flex;align-items:baseline;gap:.42rem;
  opacity:0;transform:translateY(7px);
  transition:opacity 760ms var(--e-out),transform 760ms var(--e-out)}
.load-mark i{width:.44rem;height:.44rem;border-radius:50%;background:var(--gold);
  flex:none;transform:translateY(-.06rem)}
.load.go .load-mark{opacity:1;transform:none}

.load-bar{width:9.5rem;height:1px;background:var(--rule);overflow:hidden}
/* moves off fast then creeps, the way a real progress bar behaves, rather
   than easing symmetrically into a stall */
.load-bar i{display:block;height:100%;background:var(--gold);transform:scaleX(0);
  transform-origin:left;transition:transform 1600ms cubic-bezier(.11,.79,.26,1)}
.load.go .load-bar i{transform:scaleX(.84)}
/* and then it actually finishes, visibly, before anything else moves */
.load.done .load-bar i{transform:scaleX(1);
  transition:transform 300ms cubic-bezier(.23,1,.32,1)}


@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
}

/* ══ FILTER ROW (work page) ══ */
.filters{display:flex;flex-wrap:wrap;gap:.5rem .55rem;align-items:center;
  margin-bottom:clamp(2rem,4vw,3rem);
  position:sticky;top:var(--nav-h,0px);z-index:40;
  padding:.85rem 0;margin-inline:calc(var(--gut) * -1);padding-inline:var(--gut);
  background:color-mix(in srgb,var(--bone) 92%,transparent);
  backdrop-filter:saturate(120%) blur(6px);
  border-bottom:1px solid transparent;transition:border-color 200ms ease}
.filters.stuck{border-bottom-color:var(--rule)}
@supports not (backdrop-filter:blur(1px)){.filters{background:var(--bone)}}
.filters button{border:1px solid var(--rule);padding:.72rem 1.05rem;border-radius:999px;
  font-size:.75rem;letter-spacing:.09em;text-transform:uppercase;font-weight:500;
  color:var(--ink-3);white-space:nowrap;
  transition:color 160ms ease,border-color 160ms ease,background-color 160ms ease,
             transform 160ms var(--e-out)}
@media (hover:hover) and (pointer:fine){.filters button:hover{color:var(--ink);border-color:var(--ink-3)}}
.filters button:active{transform:scale(.97)}
.filters button[aria-pressed="true"]{background:var(--ink);border-color:var(--ink);color:var(--bone)}
.filters .count{font-variant-numeric:tabular-nums;opacity:.6;margin-left:.35rem}
.page-head{padding-top:clamp(7rem,14vh,10rem)}

/* ═══════════════════════════════════════════════════════════════
   PROJECT PAGE · "the plate section of a monograph, set vertically"

   Print conventions doing real work: numbered plates, a colophon,
   a running head. The sequence is deliberately UNEQUAL · full bleed,
   then inset, then a small plate adrift in negative space · because a
   monograph varies plate scale and a gallery does not. Nothing here
   is a card and nothing here is a uniform grid.

   The only numbers on this page are plate numbers. Section eyebrows
   are deliberately absent: numbering everything turns a real sequence
   into wallpaper.
   ═══════════════════════════════════════════════════════════════ */

/* ── project hero ─────────────────────────────────────────────── */
.pj-hero{position:relative;min-height:clamp(30rem,82svh,52rem);
  display:flex;align-items:flex-end;isolation:isolate;overflow:hidden}
.pj-hero-img{position:absolute;inset:0;z-index:-2}
.pj-hero-img img{width:100%;height:100%;object-fit:cover;object-position:50% 50%}
@media (prefers-reduced-motion:no-preference){
  .pj-hero-img img{transform:scale(1.04);animation:pjDrift 26s var(--e-io) infinite alternate}
}
@keyframes pjDrift{to{transform:scale(1.11) translate3d(-.9%,-.8%,0)}}
/* the scrim is a band, not a wash. High-key food cannot hold light
   type anywhere in the upper frame · v1 proved that four times. */
.pj-hero::before{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(to top,rgba(26,20,16,.88) 0%,rgba(26,20,16,.62) 26%,rgba(26,20,16,.2) 52%,rgba(26,20,16,0) 74%),
  linear-gradient(to bottom,rgba(26,20,16,.46) 0%,rgba(26,20,16,.1) 11%,rgba(26,20,16,0) 22%),
  linear-gradient(to right,rgba(26,20,16,.74) 0%,rgba(26,20,16,.46) 26%,rgba(26,20,16,.14) 47%,rgba(26,20,16,0) 66%)}
.pj-hero-in{width:100%;max-width:var(--maxw);margin-inline:auto;color:#FBF6EC;
  padding:0 var(--gut) clamp(2.2rem,6vh,4.2rem);
  padding-left:max(var(--gut),env(safe-area-inset-left))}
.pj-back{display:inline-flex;align-items:center;gap:.6rem;text-decoration:none;
  font-size:.6875rem;letter-spacing:.19em;text-transform:uppercase;font-weight:500;
  color:rgba(251,246,236,.82);margin-bottom:clamp(1.4rem,4vh,2.4rem)}
.pj-back span{display:block;width:1.7rem;height:1px;background:currentColor;
  transition:transform 260ms var(--e-out);transform-origin:right}
@media (hover:hover) and (pointer:fine){.pj-back:hover span{transform:scaleX(1.5)}}
/* capped well below the wordmark's 9.5rem: project names run long
   ("The Decadence Project") and a 9rem clamp overflows on tablet */
.pj-hero h1{font-size:clamp(2.5rem,1.5rem + 4.4vw,6rem);font-weight:300;
  letter-spacing:-.038em;line-height:.94;margin:0;max-width:15ch}
.pj-tagline{font-family:var(--serif);font-weight:300;
  font-size:clamp(1.1rem,.95rem + .9vw,1.75rem);line-height:1.24;
  letter-spacing:-.016em;color:rgba(251,246,236,.88);max-width:30ch;margin:.85rem 0 0}
.pj-hero-foot{display:flex;flex-wrap:wrap;gap:.5rem 1.1rem;align-items:center;
  margin-top:clamp(1.6rem,4.5vh,2.6rem);padding-top:1rem;
  border-top:1px solid rgba(251,246,236,.24);color:rgba(251,246,236,.9)}
.pj-hero-foot .tick{width:1.9rem;height:1px;background:currentColor;opacity:.5}

/* ── colophon: the data block that makes it read as catalogued ──
   An editorial split. The brief takes the right column at reading
   width; the left stays largely empty on purpose. Confidence is the
   cheapest expensive thing on a page. */
.pj-brief{padding-block:clamp(3.6rem,9vw,8rem) clamp(2.6rem,6vw,5rem)}
.pj-split{display:grid;gap:clamp(2.4rem,5vw,3.5rem)}
@media (min-width:1000px){
  .pj-split{grid-template-columns:minmax(0,20rem) minmax(0,1fr);
    gap:clamp(3rem,7vw,7rem);align-items:start}
}
.colophon{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.colophon div{display:flex;justify-content:space-between;gap:1.2rem;align-items:baseline;
  padding:.72rem 0;border-bottom:1px solid var(--rule)}
.colophon dt{font-size:.6875rem;letter-spacing:.19em;text-transform:uppercase;
  font-weight:500;color:var(--ink-3);flex:none}
.colophon dd{margin:0;font-size:.875rem;color:var(--ink-2);text-align:right;
  font-variant-numeric:tabular-nums}
/* the client's own site and instagram are real links, so they have to look
   like ones: the same underline the studio credit uses in the footer.
   inline-block because a standalone link has to clear the 24px target. */
.colo-link{display:inline-block;padding-block:.1rem;color:var(--ink-2);
  text-decoration:none;border-bottom:1px solid var(--rule);
  transition:color 200ms ease,border-color 200ms ease}
@media (hover:hover) and (pointer:fine){
  .colo-link:hover{color:var(--gold);border-bottom-color:var(--gold)}
}
/* the opening line carries the weight, the rest recedes · same move as
   the about column, so the two pages feel written by one hand */
.pj-body p:first-of-type{font-family:var(--serif);
  font-size:clamp(1.35rem,1.05rem + 1.35vw,2.2rem);line-height:1.28;
  letter-spacing:-.021em;color:var(--ink);max-width:24ch}
.pj-body p{color:var(--ink-2);max-width:60ch}
.pj-body p + p{margin-top:1.05em}
.pj-deliver{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:clamp(1.8rem,4vw,2.6rem);
  padding-top:1.3rem;border-top:1px solid var(--rule)}
.pj-deliver span{border:1px solid var(--rule);padding:.42rem .95rem;
  font-size:.75rem;letter-spacing:.04em;color:var(--ink-2)}

/* ── THE PLATE SEQUENCE ────────────────────────────────────────
   Five plate scales, cycled so a new project is composed by default
   and Chan never has to art-direct one by hand:

     full    edge to edge, caption inset underneath
     wide    inset to the measure, caption hanging right
     tall    ~46% width pushed right, caption adrift in the left void
     pair    a diptych at 57/43, never 50/50 · equal halves read as a grid
     detail  small and centred in a charcoal field, so a macro reads precious

   Spacing between plates is intentionally larger than the home grid.
   A monograph gives a plate room; a contact sheet does not. */
/* the plates own their own spacing, so the run does not stack two
   sets of padding at every seam */
.seq{padding-block:0}
.pl{margin:0 auto;padding-block:clamp(1.6rem,4vw,3.4rem)}
/* the edge-to-edge scales earn a little more air than the inset ones */
.pl-full,.pl-detail{padding-block:clamp(2rem,5vw,4.4rem)}
.pl-frame{overflow:hidden;position:relative;display:block;background:var(--bone-2)}
.pl-btn{display:block;width:100%;padding:0;text-align:left;position:relative}
.pl-btn img,.pl-frame video{width:100%;height:auto;display:block;
  transition:transform 900ms var(--e-out)}
@media (hover:hover) and (pointer:fine){.pl-btn:hover img{transform:scale(1.022)}}
.pl-frame::after{content:"";position:absolute;inset:0;pointer-events:none;
  box-shadow:inset 0 0 0 1px rgba(34,27,20,.08)}

/* caption furniture · the plate number lives in the margin, never on
   the photograph, exactly as it would be set in print */
.pl-cap{display:flex;gap:1.1rem;align-items:baseline;margin-top:.85rem;
  padding-top:.55rem;border-top:1px solid var(--rule)}
.pl-no{font-variant-numeric:tabular-nums;letter-spacing:.15em;font-size:.6875rem;
  font-weight:500;color:var(--gold);flex:none}
.pl-ttl{font-family:var(--serif);font-size:1rem;color:var(--ink-2);margin-right:auto}
.pl-note{font-size:.6875rem;letter-spacing:.13em;text-transform:uppercase;
  color:var(--ink-3);text-align:right}

/* full · the only plates that touch both edges */
.pl-full{width:100%;padding-inline:0}
.pl-full .pl-cap{max-width:var(--maxw);margin-inline:auto;padding-inline:var(--gut)}

/* wide, tall, pair, detail all sit inside the measure */
.pl-wide,.pl-tall,.pl-pair,.pl-detail{
  width:100%;max-width:var(--maxw);padding-inline:var(--gut)}

.pl-tall .pl-inner{margin-left:auto;width:100%}
@media (min-width:900px){
  .pl-tall .pl-inner{width:46%}
  /* the caption sits in the empty half, aligned to the plate's baseline,
     which is what the negative space is actually for */
  .pl-tall{display:grid;grid-template-columns:1fr 46%;
    gap:clamp(1.5rem,4vw,3.5rem);align-items:end}
  .pl-tall .pl-inner{width:100%;grid-column:2}
  .pl-tall .pl-cap{grid-column:1;grid-row:1;align-self:end;margin-top:0;
    border-top:0;padding-top:0;flex-direction:column;gap:.3rem;align-items:flex-start;
    text-align:left;padding-bottom:.3rem}
  .pl-tall .pl-note{text-align:left}
  .pl-tall .pl-ttl{font-size:clamp(1.15rem,1rem + .7vw,1.7rem);color:var(--ink);margin-right:0}
}

.pl-pair .pl-inner{display:grid;gap:clamp(1rem,2.4vw,2rem)}
@media (min-width:760px){
  /* 57/43, never half and half. Equal columns are a card grid wearing a hat */
  .pl-pair .pl-inner{grid-template-columns:1.33fr 1fr;align-items:end}
}
.pl-pair figure{margin:0;display:flex;flex-direction:column}
.pl-pair .pl-cap{margin-top:.7rem}

/* detail · small, centred, on charcoal. The band makes the field, the
   restraint makes the value. */
.pl-detail{background:none;padding-inline:0}
.pl-detail .pl-band{background:var(--char);
  padding-block:clamp(3.5rem,10vw,9rem);padding-inline:var(--gut)}
.pl-detail .pl-inner{max-width:min(30rem,64vw);margin-inline:auto}
.pl-detail .pl-cap{max-width:min(30rem,64vw);margin-inline:auto;
  border-top-color:rgba(246,239,227,.2)}
.pl-detail .pl-ttl{color:#D3C5B1}
.pl-detail .pl-note{color:#9C8A75}
.pl-detail .pl-no{color:var(--gold-2)}
.pl-detail .pl-frame{background:var(--char-2)}
.pl-detail .pl-frame::after{box-shadow:inset 0 0 0 1px rgba(246,239,227,.1)}

/* video sits in the sequence beside the photographs, as asked.
   All three films are vertical, so the plate is capped off the viewport
   height rather than the column width: a 9:16 frame at 46% of a wide
   column runs past the fold, and a film you cannot see the whole of while
   it plays is not a plate. --vw and --vh come from the encode. */
.pl-video .pl-inner{max-width:calc(82svh * var(--vw) / var(--vh))}
.pl-video .pl-frame{background:var(--char)}
.pl-video video{cursor:pointer}
.pl-play{position:absolute;inset:0;display:grid;place-items:center;
  background:rgba(26,20,16,.24);border:0;width:100%;
  transition:opacity 260ms var(--e-out),background-color 260ms ease}
.pl-play b{display:grid;place-items:center;width:clamp(3.4rem,7vw,5rem);
  aspect-ratio:1;border:1px solid rgba(251,246,236,.7);border-radius:50%;
  color:#FBF6EC;transition:transform 260ms var(--e-out),background-color 260ms ease}
.pl-play b::after{content:"";width:0;height:0;margin-left:.22em;
  border:.5rem solid transparent;border-left-color:currentColor;border-right:0}
@media (hover:hover) and (pointer:fine){
  .pl-play:hover b{transform:scale(1.07);background:rgba(251,246,236,.14)}
}
.pl-play:active b{transform:scale(.96)}
.pl-video.playing .pl-play{opacity:0;pointer-events:none}

/* reveal · clip wipe, same language as the home grid.
   Added by JS only after it has proven it can take it off again. */
@media (prefers-reduced-motion:no-preference){
  .seq.reveal .pl .pl-frame{clip-path:inset(0 0 100% 0);
    transition:clip-path 1000ms var(--e-io)}
  .seq.reveal .pl .pl-cap{opacity:0;transform:translateY(10px);
    transition:opacity 620ms var(--e-out) 160ms,transform 700ms var(--e-out) 160ms}
  .seq.reveal .pl.in .pl-frame{clip-path:inset(0 0 0 0)}
  .seq.reveal .pl.in .pl-cap{opacity:1;transform:none}
}

/* ── running head + live plate counter ─────────────────────────
   A monograph sets the body of work in the top margin of every page.
   This is that, made live: the project name standing in the gutter and
   the plate number ticking over as each plate crosses the centre line.

   Only appears where the gutter is genuinely wide enough to hold it, so
   it never crowds the measure. The digits do NOT animate · a number
   that transitions every time you scroll past a plate is a nuisance,
   and this one changes constantly. Only the progress hairline moves. */
.rail{position:fixed;left:0;top:50%;transform:translateY(-50%);z-index:30;
  width:var(--gut);display:none;pointer-events:none;
  flex-direction:column;align-items:center;gap:1.1rem;
  opacity:0;transition:opacity 500ms var(--e-out)}
.rail.on{opacity:1}
@media (min-width:1280px) and (min-height:600px){.rail{display:flex}}
.rail-name{writing-mode:vertical-rl;transform:rotate(180deg);
  font-size:.6875rem;letter-spacing:.24em;text-transform:uppercase;font-weight:500;
  color:var(--ink-3);white-space:nowrap;max-height:34vh;overflow:hidden}
.rail-bar{width:1px;height:clamp(4rem,11vh,7rem);background:var(--rule);
  position:relative;overflow:hidden;flex:none}
.rail-bar i{position:absolute;inset:0 0 auto 0;height:100%;background:var(--gold);
  transform:scaleY(0);transform-origin:top;
  transition:transform 420ms var(--e-out)}
.rail-no{font-variant-numeric:tabular-nums;font-size:.75rem;letter-spacing:.13em;
  font-weight:500;color:var(--ink)}
.rail-no s{text-decoration:none;color:var(--ink-3)}
/* The rail sits over charcoal bands as often as bone, so it re-tints. Each
   part carries its own tint rather than the rail carrying one for all three:
   the rail is taller than the band edge is thick, so it regularly straddles
   the boundary, and a single class would leave whichever part is on the far
   side unreadable. */
.rail-name.on-dark{color:#9C8A75}
.rail-no.on-dark{color:#F6EFE3}
.rail-no.on-dark s{color:#9C8A75}
.rail-bar.on-dark{background:rgba(246,239,227,.2)}
.rail-bar.on-dark i{background:var(--gold-2)}

/* ── next project · the page turn ──────────────────────────────
   Full bleed, deliberately underexposed, and it comes up to meet you
   on hover. Seen once per visit, so it can afford to be generous. */
.turn{position:relative;display:block;overflow:hidden;text-decoration:none;
  min-height:clamp(22rem,62svh,38rem);display:flex;align-items:flex-end;
  isolation:isolate;background:var(--char)}
.turn img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  z-index:-2;filter:brightness(.52) saturate(.86);
  transform:scale(1.04);
  transition:transform 1100ms var(--e-out),filter 700ms ease}
.turn::before{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(to top,rgba(26,20,16,.72) 0%,rgba(26,20,16,.3) 45%,rgba(26,20,16,.1) 100%)}
@media (hover:hover) and (pointer:fine){
  .turn:hover img{transform:scale(1.09);filter:brightness(.66) saturate(.98)}
  .turn:hover .turn-go span{transform:scaleX(1.6)}
}
.turn-in{width:100%;max-width:var(--maxw);margin-inline:auto;color:#FBF6EC;
  padding:clamp(3rem,9vw,7rem) var(--gut) clamp(2.4rem,6vw,4rem);
  padding-left:max(var(--gut),env(safe-area-inset-left));
  padding-right:max(var(--gut),env(safe-area-inset-right))}
.turn-lbl{font-size:.6875rem;letter-spacing:.22em;text-transform:uppercase;
  font-weight:500;color:rgba(251,246,236,.72);margin:0 0 .9rem}
.turn h2{font-size:clamp(2.1rem,1.4rem + 3.4vw,5rem);font-weight:300;
  letter-spacing:-.036em;line-height:.96;max-width:14ch;color:#FBF6EC}
.turn-go{display:inline-flex;align-items:center;gap:.7rem;margin-top:1.6rem;
  font-size:.6875rem;letter-spacing:.19em;text-transform:uppercase;font-weight:500;
  color:rgba(251,246,236,.9)}
.turn-go span{display:block;width:2.6rem;height:1px;background:currentColor;
  /* origin right: transforms do not reflow, so a left origin grew the line
     straight through the label on hover. Growing away from the text. */
  transform-origin:right;transition:transform 380ms var(--e-out)}

/* ── footer, tightened ─────────────────────────────────────────
   Was 191px of box around 65px of content, with the parent section
   stacking another 142px of padding underneath it. */
.foot{margin-top:clamp(3rem,6vw,5rem);
  padding:clamp(1.6rem,3vw,2.3rem) 0 clamp(1.1rem,2.2vw,1.6rem);
  border-top:1px solid var(--rule)}
.foot-note{margin-top:.9rem;padding-top:.75rem;border-top:1px solid var(--rule);
  font-size:.75rem;color:var(--ink-3);line-height:1.5;max-width:none}
/* The page ends ON the footer. .foot carries its own bottom padding, so any
   section padding under it is just dead space below the last line. */
.sect:has(> .wrap > .foot){padding-bottom:0}

/* ── project index on the work page ────────────────────────────
   A contents page, not a card grid. Hairline rules, a thumbnail small
   enough to be a reference rather than a hero, and the plate count
   sitting hard right in tabular figures. The row lifts and the title
   slides on hover; the thumbnail is the only thing that scales. */
.pjx-list{list-style:none;margin:0 0 clamp(3rem,7vw,5.5rem);padding:0;
  border-top:1px solid var(--rule)}
.pjx a{display:grid;grid-template-columns:auto 1fr auto;
  gap:.15rem clamp(1rem,3vw,2.2rem);align-items:center;
  padding:clamp(.9rem,2vw,1.35rem) 0;border-bottom:1px solid var(--rule);
  text-decoration:none;position:relative;
  transition:padding-left 420ms var(--e-out)}
.pjx-img{grid-row:1 / span 2;width:clamp(3.4rem,8vw,5.4rem);aspect-ratio:1;
  overflow:hidden;background:var(--bone-2);display:block}
.pjx-img img{width:100%;height:100%;object-fit:cover;
  transition:transform 900ms var(--e-out)}
.pjx-ttl{font-family:var(--serif);font-weight:400;
  font-size:clamp(1.25rem,1.05rem + 1.1vw,2.15rem);letter-spacing:-.024em;
  line-height:1.08;color:var(--ink);
  transition:color 260ms ease}
.pjx-meta{grid-column:2;font-size:.75rem;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3);margin-top:.3rem}
.pjx-n{grid-row:1 / span 2;grid-column:3;font-variant-numeric:tabular-nums;
  font-size:.75rem;letter-spacing:.15em;font-weight:500;color:var(--ink-3);
  transition:color 260ms ease}
@media (hover:hover) and (pointer:fine){
  .pjx a:hover{padding-left:clamp(.6rem,1.6vw,1.4rem)}
  .pjx a:hover .pjx-img img{transform:scale(1.09)}
  .pjx a:hover .pjx-ttl{color:var(--gold)}
  .pjx a:hover .pjx-n{color:var(--ink-2)}
}
.pjx a:focus-visible{outline-offset:-2px}

/* The inquiry block does not want the full 1920 container. The form caps at
   34rem for usability, so a stretched column opened a 238px hole beside it;
   widening the other column instead just pushed its two blocks out of
   alignment with each other. Capping the block at its 1440 width is what
   actually reads right · left-aligned under the headline, with the extra
   width left as margin rather than spent on a form nobody wants that wide. */
/* Both rows of the inquiry section, not just the form block. Capping only the
   .two left the headline row running to the full container while the block
   under it stopped 360px short · one ragged right edge instead of none. */
.two:has(.form),
.head:has(+ .two .form){max-width:82rem;margin-inline:auto}

/* ── inquiry form ──────────────────────────────────────────────
   Same vocabulary as everything else: hairline rules, square corners,
   the field sunk very slightly into the page rather than floating on it.
   Netlify collects it, so there is no backend and nothing to maintain. */
.form{margin-top:.4rem;max-width:34rem}
.f-row{display:grid;gap:.4rem;margin-bottom:1.05rem}
.f-row label{font-size:.6875rem;letter-spacing:.19em;text-transform:uppercase;
  font-weight:500;color:var(--ink-3)}
.form input,.form select,.form textarea{
  font:inherit;font-size:1rem;color:var(--ink);background:var(--bone-2);
  border:1px solid rgba(34,27,20,.26);border-radius:0;padding:.78rem .9rem;width:100%;
  transition:border-color 200ms ease,background-color 200ms ease}
.form textarea{resize:vertical;min-height:6.5rem;line-height:1.55}
.form select{appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,var(--ink-3) 50%),
    linear-gradient(135deg,var(--ink-3) 50%,transparent 50%);
  background-position:calc(100% - 1.15rem) 1.32rem,calc(100% - .8rem) 1.32rem;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:2.6rem}
.form input::placeholder,.form textarea::placeholder{color:var(--ink-3);opacity:1}
.form input:hover,.form select:hover,.form textarea:hover{border-color:rgba(34,27,20,.45)}
.form input:focus,.form select:focus,.form textarea:focus{
  outline:2px solid var(--gold);outline-offset:1px;border-color:transparent;
  background:var(--bone)}
.form .btn{margin-top:.5rem;cursor:pointer}
.f-note{margin-top:1.1rem;font-size:.8125rem;color:var(--ink-3);max-width:38ch}
/* honeypot: present for a bot, gone for a person and for a screen reader */
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.dark .form input,.dark .form select,.dark .form textarea{background:var(--bone-2)}

/* Target size. These are standalone links, not links inside a sentence, so the
   inline exemption does not cover them and 18px fails the 24px minimum.
   Padding grows the hit area; baseline alignment keeps the text put. */
a.eyebrow,.clist a{display:inline-block;padding-block:.28rem}

/* the studio credit is a real link, so it has to look like one */
.foot-note .credit{color:var(--ink-2);text-decoration:none;
  border-bottom:1px solid var(--rule);
  transition:color 200ms ease,border-color 200ms ease}
@media (hover:hover) and (pointer:fine){
  .foot-note .credit:hover{color:var(--gold);border-bottom-color:var(--gold)}
}

/* ══ SERVICE SPREADS ════════════════════════════════════════════
   A photographer arguing for photography with a bulleted list is a
   photographer losing the argument. Each service is a spread: the
   photograph that proves it, and the copy beside it. Sides alternate
   and the column split flips with them, so six entries read as a
   sequence rather than six of the same card. */
.spread{display:grid;gap:clamp(1.6rem,4vw,3.2rem);
  padding-block:clamp(2.4rem,6vw,5rem);
  border-top:1px solid var(--rule)}
.spread:first-of-type{border-top:0;padding-top:clamp(1rem,2vw,2rem)}
@media (min-width:900px){
  .spread{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
    gap:clamp(2.5rem,6vw,6rem);align-items:center}
  /* flip both the order and the emphasis, so the rhythm is not a metronome */
  .spread:nth-of-type(even) .spread-fig{order:2}
  .spread:nth-of-type(even){grid-template-columns:minmax(0,.95fr) minmax(0,1.05fr)}
}
.spread-fig{margin:0}
.spread-fig .pl-frame{display:block;overflow:hidden;position:relative;
  background:var(--bone-2)}
.spread-fig img{width:100%;height:auto;display:block;
  transition:transform 900ms var(--e-out)}
.spread-fig .pl-frame::after{content:"";position:absolute;inset:0;
  pointer-events:none;box-shadow:inset 0 0 0 1px rgba(34,27,20,.08)}
@media (hover:hover) and (pointer:fine){
  .spread:hover .spread-fig img{transform:scale(1.025)}
}
.spread-n{font-variant-numeric:tabular-nums;letter-spacing:.16em;
  font-size:.6875rem;font-weight:500;color:var(--gold);display:block;
  margin-bottom:.9rem}
.spread-body h3{font-size:clamp(1.6rem,1.2rem + 1.7vw,2.7rem);font-weight:400;
  letter-spacing:-.028em;line-height:1.02;margin-bottom:.7rem}
.spread-body p{color:var(--ink-2);max-width:44ch;margin-bottom:1.3rem}
.spread-inc{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
  gap:.4rem}
.spread-inc li{border:1px solid var(--rule);padding:.34rem .8rem;
  font-size:.75rem;letter-spacing:.03em;color:var(--ink-3)}
.dark .spread{border-top-color:var(--rule)}

/* The band is already a full-stop; 144px of section padding under it read as
   a hole between the headline and the form. ~28px tighter at desktop. */
.band + .sect{padding-top:clamp(3.4rem,8vw,7.6rem)}

/* ══ CONTACT · a compact page head over a photograph ════════════ */
.band{position:relative;isolation:isolate;overflow:hidden;
  min-height:clamp(17rem,42svh,26rem);display:flex;align-items:flex-end;
  background:var(--char)}
.band img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  z-index:-2}
.band::before{content:"";position:absolute;inset:0;z-index:-1;background:
  linear-gradient(to top,rgba(26,20,16,.9) 0%,rgba(26,20,16,.6) 34%,rgba(26,20,16,.2) 66%,rgba(26,20,16,.05) 100%),
  linear-gradient(to right,rgba(26,20,16,.72) 0%,rgba(26,20,16,.3) 40%,rgba(26,20,16,0) 70%)}
.band-in{width:100%;max-width:var(--maxw);margin-inline:auto;color:#FBF6EC;
  padding:0 var(--gut) clamp(1.8rem,4vw,3rem);
  padding-left:max(var(--gut),env(safe-area-inset-left))}
.band-in .eyebrow{color:rgba(251,246,236,.78)}
.band-in h1{font-size:clamp(2rem,1.3rem + 3.2vw,4.2rem);font-weight:300;
  letter-spacing:-.034em;line-height:1;max-width:17ch;margin:.7rem 0 0;
  color:#FBF6EC}

/* the right column was three orphans stacked. One ruled block instead. */
.aside-block{border-top:1px solid var(--rule);margin-top:clamp(2rem,4vw,3rem);
  padding-top:1.2rem}
.aside-block h3{font-size:1.05rem;font-weight:500;font-family:var(--sans);
  letter-spacing:.01em;margin-bottom:.9rem}
.hints{list-style:none;margin:0;padding:0}
.hints li{padding:.72rem 0;border-bottom:1px solid var(--rule);
  display:grid;gap:.15rem}
.hints li:last-child{border-bottom:0;padding-bottom:0}
.hints b{font-family:var(--serif);font-weight:400;font-size:1.02rem;color:var(--ink)}
.hints span{font-size:.875rem;color:var(--ink-3);line-height:1.5}

/* ══ PAGE TRANSITIONS ═══════════════════════════════════════════════
   Cross document view transitions: every navigation crossfades, and the
   project you click morphs its index thumbnail into the page hero, because
   both carry the same view-transition-name. Browsers without support fall
   back to an ordinary jump, and reduced motion never opts in at all. */
@media (prefers-reduced-motion:no-preference){
  @view-transition{navigation:auto}
  ::view-transition-old(root),
  ::view-transition-new(root){animation-duration:360ms;
    animation-timing-function:cubic-bezier(.4,0,.2,1)}
}

/* ══ ENTRANCE ═══════════════════════════════════════════════════════
   The site arrives as the slats lift, rather than sitting finished behind
   them waiting to be uncovered. Type rises and resolves; nothing scales,
   because the hero photograph is already drifting and two transforms on
   the same area fight each other.

   Gated on html.preload:not(.entered), which means the offset state only
   ever exists once the inline head script has run · so with JavaScript off
   there is no loader AND no hidden hero, just the page. Same contract as
   every other hidden state here. .entered lands with .out, so the entrance
   overlaps the exit instead of queueing behind it. */
.hero-line,.hero-sub,.hero-cta,.hero-foot,
.pj-back,.pj-tagline,.pj-hero-foot,
.band-in .eyebrow,.band-in h1,
.nav .brand,.nav-links,.nav .book{
  transition:opacity 820ms var(--e-out),transform 940ms var(--e-out)}

/* ── the two moments you actually notice ──────────────────────────
   The photograph pulls into focus, like a lens finding it, and the
   wordmark wipes up out of nothing. blur() is used rather than scale
   because the hero image is already drifting on its own transform and
   two transforms on one element fight. */
.hero-img img,.pj-hero-img img,.band img{
  transition:filter 1500ms cubic-bezier(.2,.7,.2,1)}
html.preload:not(.entered) .hero-img img,
html.preload:not(.entered) .pj-hero-img img,
html.preload:not(.entered) .band img{filter:blur(18px) saturate(.72)}

.hero h1,.pj-hero h1{
  clip-path:inset(-30% -10% -30% -2%);
  transition:clip-path 1250ms var(--e-io),transform 1250ms var(--e-out)}
html.preload:not(.entered) .hero h1,
html.preload:not(.entered) .pj-hero h1{
  clip-path:inset(-30% -10% 112% -2%);transform:translateY(46px)}

html.preload:not(.entered) .hero-line,
html.preload:not(.entered) .hero-sub,
html.preload:not(.entered) .hero-cta,
html.preload:not(.entered) .hero-foot,
html.preload:not(.entered) .pj-back,
html.preload:not(.entered) .pj-hero h1,
html.preload:not(.entered) .pj-tagline,
html.preload:not(.entered) .pj-hero-foot,
html.preload:not(.entered) .band-in .eyebrow,
html.preload:not(.entered) .band-in h1,
html.preload:not(.entered) .nav .brand,
html.preload:not(.entered) .nav-links,
html.preload:not(.entered) .nav .book{
  opacity:0;transform:translateY(34px)}

/* the wordmark leads, everything else follows it up in order */
.nav .brand      {transition-delay:120ms}
.nav-links       {transition-delay:180ms}
.nav .book       {transition-delay:230ms}
.pj-back,.band-in .eyebrow               {transition-delay:260ms}
.hero h1,.pj-hero h1                     {transition-delay:240ms}
.hero-line,.band-in h1                   {transition-delay:560ms}
.hero-sub,.pj-tagline                    {transition-delay:720ms}
.hero-cta                                {transition-delay:790ms}
.hero-foot,.pj-hero-foot                 {transition-delay:860ms}

/* the underline sweep under "The reel" should not start until it is on screen */
html.preload:not(.entered) .cue b::after{animation-play-state:paused}

@media (prefers-reduced-motion:reduce){
  html.preload:not(.entered) .hero-img img,
  html.preload:not(.entered) .pj-hero-img img,
  html.preload:not(.entered) .band img{filter:none}
  html.preload:not(.entered) .hero h1,
  html.preload:not(.entered) .pj-hero h1{clip-path:none;transform:none}
  html.preload:not(.entered) .hero h1,
  html.preload:not(.entered) .hero-line,
  html.preload:not(.entered) .hero-sub,
  html.preload:not(.entered) .hero-cta,
  html.preload:not(.entered) .hero-foot,
  html.preload:not(.entered) .pj-back,
  html.preload:not(.entered) .pj-hero h1,
  html.preload:not(.entered) .pj-tagline,
  html.preload:not(.entered) .pj-hero-foot,
  html.preload:not(.entered) .band-in .eyebrow,
  html.preload:not(.entered) .band-in h1,
  html.preload:not(.entered) .nav .brand,
  html.preload:not(.entered) .nav-links,
  html.preload:not(.entered) .nav .book{transform:none}
}

/* ══ PER-PAGE ENTRANCES ═════════════════════════════════════════════
   Each section arrives with a gesture drawn from what it contains, so the
   site does not feel like one template with the pictures swapped.

   These are CSS animations with `both`, deliberately, not class-toggled
   transitions: an animation self-completes and ends on the visible state,
   so a JavaScript failure cannot strand content half-revealed. Without
   html.pg nothing is hidden at all, so no script means no animation and a
   perfectly readable page.

   html.pg is set immediately on a return visit, and only AFTER the loading
   screen has gone on a first visit · playing these underneath the loader
   is how the hero entrance ended up invisible. */
@keyframes pgRise  {from{opacity:0;transform:translateY(30px)} to{opacity:1;transform:none}}
@keyframes pgLeft  {from{opacity:0;transform:translateX(-46px)}to{opacity:1;transform:none}}
@keyframes pgRight {from{opacity:0;transform:translateX(46px)} to{opacity:1;transform:none}}
@keyframes pgWipe  {from{clip-path:inset(0 0 108% 0)} to{clip-path:inset(0 0 -8% 0)}}
@keyframes pgFocus {from{filter:blur(16px) saturate(.75);opacity:.4} to{filter:none;opacity:1}}
@keyframes pgRule  {from{transform:scaleX(0)} to{transform:scaleX(1)}}

/* every page: the heading wipes up, the standfirst follows */
html.pg .page-head .head h1,.head h2,html.pg .pj-brief .head h1,.head h2{
  animation:pgWipe 900ms var(--e-io) both}
html.pg .page-head .head .eyebrow{animation:pgRise 620ms var(--e-out) both}
html.pg .page-head .head .lede{animation:pgRise 760ms var(--e-out) 160ms both}

/* ── WORK · a contents page, so the rows deal themselves in ───────── */
html.pg .pjx{animation:pgLeft 620ms var(--e-out) both}
html.pg .pjx:nth-child(1){animation-delay:240ms}
html.pg .pjx:nth-child(2){animation-delay:315ms}
html.pg .pjx:nth-child(3){animation-delay:390ms}
html.pg .pjx:nth-child(4){animation-delay:465ms}
html.pg .pjx:nth-child(5){animation-delay:540ms}
html.pg .pjx:nth-child(n+6){animation-delay:615ms}
html.pg .filters{animation:pgRise 700ms var(--e-out) 300ms both}

/* ── SERVICES · spreads alternate, so the photographs do too ──────── */
html.pg .spread:nth-of-type(odd)  .spread-fig{animation:pgLeft  820ms var(--e-out) both}
html.pg .spread:nth-of-type(even) .spread-fig{animation:pgRight 820ms var(--e-out) both}
html.pg .spread .spread-body{animation:pgRise 760ms var(--e-out) 140ms both}
html.pg .spread:nth-of-type(1) .spread-fig,
html.pg .spread:nth-of-type(1) .spread-body{animation-delay:260ms}

/* ── ABOUT · the portrait finds focus, the writing rises ──────────── */
html.pg #aboutFig{animation:pgFocus 1300ms cubic-bezier(.2,.7,.2,1) 200ms both}
html.pg .about-body p{animation:pgRise 720ms var(--e-out) both}
html.pg .about-body p:nth-of-type(1){animation-delay:340ms}
html.pg .about-body p:nth-of-type(2){animation-delay:430ms}
html.pg .about-body p:nth-of-type(3){animation-delay:520ms}
html.pg .about-body p:nth-of-type(n+4){animation-delay:610ms}

/* ── CONTACT · the band settles, then the fields in filling order ── */
html.pg .band img{animation:pgFocus 1400ms cubic-bezier(.2,.7,.2,1) both}
html.pg .band-in .eyebrow{animation:pgRise 600ms var(--e-out) 260ms both}
html.pg .band-in h1{animation:pgWipe 1000ms var(--e-io) 340ms both}
html.pg .form .f-row{animation:pgRise 560ms var(--e-out) both}
html.pg .form .f-row:nth-of-type(1){animation-delay:420ms}
html.pg .form .f-row:nth-of-type(2){animation-delay:490ms}
html.pg .form .f-row:nth-of-type(3){animation-delay:560ms}
html.pg .form .f-row:nth-of-type(4){animation-delay:630ms}
html.pg .form .f-row:nth-of-type(5){animation-delay:700ms}
html.pg .form .f-row:nth-of-type(6){animation-delay:770ms}
html.pg .form .btn{animation:pgRise 560ms var(--e-out) 840ms both}
html.pg .clist li{animation:pgRise 540ms var(--e-out) both}
html.pg .clist li:nth-child(1){animation-delay:400ms}
html.pg .clist li:nth-child(2){animation-delay:460ms}
html.pg .clist li:nth-child(3){animation-delay:520ms}
html.pg .clist li:nth-child(4){animation-delay:580ms}
html.pg .clist li:nth-child(5){animation-delay:640ms}
html.pg .clist li:nth-child(6){animation-delay:700ms}

/* ── PROJECT PAGE · the colophon ticks in like a readout ──────────── */
html.pg .colophon div{animation:pgRise 500ms var(--e-out) both}
html.pg .colophon div:nth-child(1){animation-delay:300ms}
html.pg .colophon div:nth-child(2){animation-delay:365ms}
html.pg .colophon div:nth-child(3){animation-delay:430ms}
html.pg .colophon div:nth-child(4){animation-delay:495ms}
html.pg .colophon div:nth-child(5){animation-delay:560ms}
html.pg .colophon div:nth-child(6){animation-delay:625ms}
html.pg .colophon div:nth-child(7){animation-delay:690ms}
html.pg .pj-body p{animation:pgRise 760ms var(--e-out) 420ms both}
html.pg .pj-deliver{animation:pgRise 700ms var(--e-out) 620ms both}
/* the rule under the running head draws itself */
html.pg .rail-bar{transform-origin:top;animation:pgRule 900ms var(--e-io) 700ms both}

@media (prefers-reduced-motion:reduce){
  html.pg *{animation:none!important}
}
