/* Expressive motion layer. Every hidden state is scoped to .fx, which JS adds only when motion is allowed. */
:root{--fx-out:cubic-bezier(.19,1,.22,1);--fx-inout:cubic-bezier(.77,0,.18,1)}

/* Hero: the photograph opens from a frame while each letter of the name rises into place. */
.hero-name h1{animation:none;overflow:hidden;padding-bottom:.02em}
.hero-char{display:inline-block;transform-origin:0 100%;animation:hero-char 1.3s var(--fx-out) backwards;animation-delay:calc(.35s + var(--i) * 48ms)}
.hero-image{animation:hero-frame 1.5s var(--fx-inout) backwards}
.hero-image img{animation:hero-zoom 2.4s var(--fx-out) backwards}
.hero-caption,.hero-scroll,.hero-name-ko{animation:hero-late .9s var(--fx-out) 1.15s backwards}
@keyframes hero-char{from{transform:translateY(112%) rotate(7deg)}}
@keyframes hero-frame{from{clip-path:inset(16% 12% 16% 12%)}to{clip-path:inset(0)}}
@keyframes hero-zoom{from{scale:1.32}}
@keyframes hero-late{from{opacity:0;translate:0 18px}}

/* Headings: words rise line by line from behind a mask. */
.fx-w{display:inline-block;vertical-align:top;overflow:hidden;padding:.03em .1em .16em;margin:-.03em -.1em -.16em}
.fx .fx-wi{display:inline-block;transform:translateY(115%) rotate(5deg);transform-origin:0 100%;transition:transform 1.15s var(--fx-out) var(--d,0ms)}
.fx .is-in>.fx-w>.fx-wi,.fx .is-in .fx-wi{transform:none}
.fx [data-reveal].fx-split{opacity:1;transform:none}
.fx .work-heading{overflow:clip}
.fx-drift .fx-w{translate:var(--drift,0px) 0;will-change:translate}

/* Pinned projects are scrubbed by scroll. JS sets per slide:
   --s  -1 (waiting below) → 0 (settled) → 1 (left above); --a is |s|
   --enter / --leave  the incoming and outgoing halves of --s
   --hold -1 → 1 while the slide is settled, for a slow continuous zoom. */
.stage-wash,.stage-numeral{position:absolute;inset:0;z-index:0;pointer-events:none}
.stage-wash{opacity:0}
.stage-numeral{display:none}
.fx .work-scroll.is-pinned{height:calc((var(--project-count,6) + .5) * 170svh)}
.fx-scrub.is-pinned .work-stage{background:var(--fx-stage-bg,var(--stage-bg));transition:none}
.fx-scrub.is-pinned .stage-wash{opacity:1;background:var(--fx-wash-bg);clip-path:circle(var(--fx-wash-r,0%) at 88% 108%)}
.fx-scrub.is-pinned .project-slide{visibility:hidden;opacity:1;transition:none}
.fx-scrub.is-pinned .project-slide.is-near{visibility:visible}
.fx-scrub.is-pinned .project-copy>*{transition:none;opacity:calc(1 - var(--ca,0) * 1.25);transform:translateY(calc(var(--c,0) * -1 * var(--lift,60px)))}
.fx-scrub.is-pinned .project-copy>:nth-child(1){--lift:40px}
.fx-scrub.is-pinned .project-copy>:nth-child(2){--lift:70px;opacity:1}
.fx-scrub.is-pinned .project-copy>:nth-child(3){--lift:95px}
.fx-scrub.is-pinned .project-copy>:nth-child(4){--lift:125px}
.fx-scrub.is-pinned .project-copy>:nth-child(5){--lift:150px}
.fx-scrub.is-pinned .project-copy h3 .fx-wi{transition:none;transform:translateY(calc(var(--c,0) * -115%)) rotate(calc(var(--c,0) * -5deg))}
.fx-scrub.is-pinned .project-visual{opacity:1;transition:none;
  transform:translate3d(calc(var(--s,0) * -3vw),calc(var(--s,0) * -34vh + var(--hold,0) * -1.6vh),0) rotate(calc(var(--s,0) * -3deg)) scale(calc(1 - var(--a,0) * .1 + var(--hold,0) * .025));
  clip-path:inset(calc(var(--leave,0) * (100% + 80px) - 40px) -40px calc(var(--enter,0) * (100% + 80px) - 40px) -40px)}
.fx .is-pinned .project-visual>:first-child{transform:perspective(1100px) rotateX(var(--tilt-x,0deg)) rotateY(var(--tilt-y,0deg))}

/* A stage-sized index in the open space behind the copy, cropped by the stage floor; the ones digit rolls with scroll. */
.fx-scrub.is-pinned .stage-numeral{display:flex;align-items:flex-end;inset:auto auto -.14em calc(var(--gutter) - .06em);font-size:min(92svh,52vw);font-weight:650;line-height:1;letter-spacing:-.085em;color:color-mix(in srgb,var(--ink) 7%,transparent);font-variant-numeric:tabular-nums;user-select:none}
.stage-numeral>span{display:block;height:1em;overflow:hidden}
.numeral-roll{display:flex;flex-direction:column;transform:translateY(calc(var(--fx-step,0) * -1em))}
.numeral-roll>span{height:1em}
.fx .project-stat strong,.fx .case-metrics strong{font-variant-numeric:tabular-nums}
@media(min-width:851px){
  .fx-scrub.is-pinned .project-slide{grid-template-columns:.74fr 1.26fr;gap:3vw}
  .fx-scrub.is-pinned .product-image.landscape img{max-height:66svh}
  .fx-scrub.is-pinned .product-image.portrait{height:66svh}
  .fx-scrub.is-pinned .studio-concept img{max-height:68svh}
}
@media(max-width:850px){.fx .work-scroll.is-pinned{height:calc((var(--project-count,6) + .5) * 150svh)}}
@media(max-width:850px){.fx-scrub.is-pinned .stage-numeral{inset:18px calc(var(--gutter) - .04em) auto auto;font-size:min(34svh,62vw)}}

/* Photographs: a vertical curtain lifts while the image settles from a closer crop. */
.fx .fx-img{overflow:clip;clip-path:inset(100% 0 0 0);transition:clip-path 1.35s var(--fx-inout) var(--d,0ms)}
.fx .fx-img img{scale:1.3;transition:scale 1.9s var(--fx-out) var(--d,0ms)}
.fx .fx-img.is-in{clip-path:inset(0)}
.fx .fx-img.is-in img{scale:1}
.fx .hack-image.is-in img{scale:1.14}
.fx .hack-image img{translate:0 var(--parallax,0px)}

/* First visit: a counted curtain lifts off the page, then the hero entrance begins. */
.preloader{display:none;position:fixed;z-index:120;inset:0;flex-direction:column;justify-content:space-between;padding:28px 3vw 0;background:var(--brand-ink);color:var(--paper);pointer-events:none}
.intro-pending .preloader,.intro-leaving .preloader{display:flex}
.intro-pending{overflow:hidden}
.intro-pending :is(.hero-char,.hero-image,.hero-image img,.hero-caption,.hero-scroll,.hero-name-ko){animation-play-state:paused}
.preloader-top,.preloader-bottom{display:flex;justify-content:space-between;align-items:flex-end;gap:24px}
.preloader-top{font-size:11px;letter-spacing:.06em;color:var(--brand-light)}
.preloader-bottom>span{font-size:clamp(15px,1.6vw,24px);letter-spacing:-.02em;padding-bottom:3.2vw;color:var(--brand-light)}
.preloader-count{font-size:clamp(120px,24vw,420px);font-weight:600;line-height:.8;letter-spacing:-.075em;font-variant-numeric:tabular-nums;padding-bottom:1.8vw}
.preloader-bar{position:absolute;left:0;right:0;bottom:0;height:6px;background:var(--brand-blue);transform:scaleX(var(--p,0));transform-origin:left}
.intro-leaving .preloader{transform:translateY(-100%);border-radius:0 0 50% 50%/0 0 14vh 14vh;transition:transform 1.05s var(--fx-inout),border-radius 1.05s var(--fx-inout)}
.intro-leaving .preloader>*{transform:translateY(-30vh);opacity:0;transition:transform 1.05s var(--fx-inout),opacity .5s ease}
@media(max-width:560px){.preloader{padding:22px var(--gutter) 0}.preloader-top{font-size:9px}.preloader-top>span:last-child{display:none}.preloader-bottom{flex-direction:column-reverse;align-items:flex-start;gap:8px}.preloader-bottom>span{padding-bottom:40px;font-size:15px}}

/* Name band: flows continuously, speeds up and reverses with the reader's scroll. */
.marquee{overflow:hidden;padding:clamp(22px,2.4vw,42px) 0 clamp(14px,1.6vw,28px);border-bottom:1px solid var(--line);background:var(--paper);position:relative}
.marquee-track{display:flex;width:max-content;white-space:nowrap;font-size:clamp(58px,10.5vw,190px);font-weight:620;line-height:1;letter-spacing:-.065em;transform:translate3d(var(--marquee-x,0px),0,0) skewX(var(--marquee-skew,0deg));will-change:transform}
.marquee-item{display:flex;align-items:center;padding-right:.35em}
.marquee-item em{font-style:normal;color:transparent;-webkit-text-stroke:1.5px var(--brand-ink)}
.marquee-item i{font-style:normal;color:var(--brand-blue);font-size:.55em;padding:0 .45em;letter-spacing:0}
@media(max-width:560px){.marquee-track{font-size:17vw}.marquee-item em{-webkit-text-stroke-width:1px}}

/* Field rail: photos sit on a shallow curve and lean with drag or scroll speed. */
.fx .fx-bend .field-photo{transform:perspective(1400px) rotateY(var(--bend,0deg)) skewX(var(--lean,0deg)) scale(var(--squash,1));transition:none;will-change:transform}

/* Smooth scrolling (Lenis) replaces the CSS smooth behavior while it is active. */
html.lenis,html.lenis body{height:auto}
html.lenis{scroll-behavior:auto!important}
.lenis.lenis-stopped{overflow:clip}
.lenis [data-lenis-prevent]{overscroll-behavior:contain}
.lenis.lenis-smooth iframe{pointer-events:none}

/* Magnetic controls follow the pointer slightly before springing back. */
.fx [data-magnet]{translate:var(--mx,0px) var(--my,0px)}

/* Header menus: a blue pill pops out under the tab, stretches into a bar and pours down into the panel while
   each label flips in letter by letter. Closing drains it back into the pill. --pill-l/--pill-w come from JS. */
.fx .work-nav summary svg{transition:transform .6s cubic-bezier(.34,1.56,.64,1)}
.fx .work-nav.is-closing summary svg{transform:none}
.fx .work-nav[open] .work-menu-panel{animation:menu-morph .78s linear backwards;transform-origin:50% 0}
.fx .work-menu-panel:before{content:'';position:absolute;z-index:2;inset:0;background:var(--brand-blue);opacity:0;pointer-events:none}
.fx .work-nav[open] .work-menu-panel:before{animation:menu-ink .78s linear backwards}
.fx .work-nav.is-closing .work-menu-panel{animation:menu-drain .34s cubic-bezier(.55,0,.75,.2) forwards}
.fx .work-nav.is-closing .work-menu-panel:before{animation:menu-ink-back .34s linear forwards}
.fx .work-nav.is-closing .work-menu-panel>*{opacity:0;transition:opacity .12s}
.fx .menu-char{display:inline-block;white-space:pre;backface-visibility:hidden}
.fx .work-nav[open]:not(.is-settled) .menu-char{animation:menu-flip .62s cubic-bezier(.2,.8,.2,1) backwards;animation-delay:calc(.3s + var(--i,0) * 45ms + var(--c,0) * 14ms)}
.fx .work-nav[open]:not(.is-settled) .work-menu-panel a>span:last-child{animation:menu-nudge .5s var(--fx-out) backwards;animation-delay:calc(.46s + var(--i,0) * 45ms)}
.fx .work-menu-panel a.is-rolling .menu-char{animation:menu-roll .62s cubic-bezier(.3,.7,.2,1) calc(var(--c,0) * 16ms)}
.fx .work-menu-panel a>span:last-child{transition:transform .45s var(--fx-out)}
@media(hover:hover){.fx .work-menu-panel a:hover>span:last-child{transform:translate(2px,-2px) rotate(45deg)}.fx .work-menu-panel .work-menu-all:hover>span:last-child{transform:translate(2px,2px)}}
/* A highlight slides between rows, and a tilted preview card rides beside the panel after the cursor. */
.fx .work-menu-panel{isolation:isolate}
.fx .menu-glide{position:absolute;z-index:-1;left:20px;right:20px;top:0;height:var(--gh,44px);translate:0 var(--gy,0px);background:#23365710;opacity:0;pointer-events:none;transition:translate .42s var(--fx-out),height .42s var(--fx-out),opacity .25s}
.fx .work-menu-panel.is-gliding .menu-glide{opacity:1}
.fx .site-header nav .work-menu-panel a:hover,.fx .site-header nav .work-menu-panel a:focus-visible{background:transparent}
@media(hover:hover) and (min-width:851px){
  .fx .menu-card{display:block;position:absolute;z-index:3;left:0;top:0;width:250px;aspect-ratio:4/3;background:var(--card-bg,#fbfaf6);box-shadow:0 26px 50px #1b284426,0 2px 6px #1b28441a;pointer-events:none;opacity:0;scale:.6;translate:var(--cx,0px) var(--cy,0px);rotate:var(--cr,0deg);transform-origin:var(--co,0%) 50%;transition:opacity .22s,scale .55s cubic-bezier(.34,1.56,.64,1),background-color .45s}
  .fx .menu-card.is-on{opacity:1;scale:1}
  .fx .menu-card img{position:absolute;inset:12px;width:calc(100% - 24px);height:calc(100% - 24px);object-fit:contain;clip-path:inset(100% 0 0 0);transition:clip-path .55s var(--fx-out)}
  .fx .menu-card img.is-shown{z-index:1;clip-path:inset(0)}
  .fx .about-nav .menu-card{width:200px;aspect-ratio:4/5}
  .fx .about-nav .menu-card img{inset:8px;width:calc(100% - 16px);height:calc(100% - 16px);object-fit:cover}
  .fx .work-nav.is-closing .menu-card{opacity:0;transition:opacity .15s}
}
@keyframes menu-morph{
  0%{clip-path:inset(0 calc(100% - var(--pill-l,10px) - var(--pill-w,70px)) calc(100% - 3px) var(--pill-l,10px) round 17px);transform:none;animation-timing-function:cubic-bezier(.3,1.6,.5,1)}
  16%{clip-path:inset(0 calc(100% - var(--pill-l,10px) - var(--pill-w,70px)) calc(100% - 34px) var(--pill-l,10px) round 17px);animation-timing-function:cubic-bezier(.6,0,.2,1)}
  40%{clip-path:inset(0 0 calc(100% - 42px) 0 round 21px);transform:scaleY(.94);animation-timing-function:cubic-bezier(.2,.75,.25,1)}
  82%{transform:scaleY(1.012)}
  100%{clip-path:inset(0 0 0 0 round 0);transform:none}
}
@keyframes menu-ink{0%,32%{opacity:1}66%,100%{opacity:0}}
@keyframes menu-drain{
  0%{clip-path:inset(0 0 0 0 round 0)}
  55%{clip-path:inset(0 0 calc(100% - 42px) 0 round 21px)}
  100%{clip-path:inset(0 calc(100% - var(--pill-l,10px) - var(--pill-w,70px)) calc(100% - 2px) var(--pill-l,10px) round 17px)}
}
@keyframes menu-ink-back{0%,30%{opacity:0}70%,100%{opacity:1}}
@keyframes menu-flip{from{opacity:0;transform:perspective(320px) rotateX(-95deg) translateY(.35em)}}
@keyframes menu-roll{40%{opacity:0;transform:translateY(-.55em)}41%{opacity:0;transform:translateY(.55em)}}
@keyframes menu-nudge{from{opacity:0;transform:translateX(-8px)}}

@media(min-width:851px){
  .fx .fx-rise{opacity:0;transform:translateY(34px);transition:opacity .8s ease var(--d,0ms),transform 1s var(--fx-out) var(--d,0ms)}
  .fx .fx-rise.is-in{opacity:1;transform:none}
  .motion-ready .skill[data-reveal]{transition-delay:var(--d,0ms)}
  .project-row{position:relative;isolation:isolate}
  .project-row:before{content:'';position:absolute;z-index:-1;inset:0 -18px;background:var(--row-bg,transparent);transform:scaleY(0);transform-origin:50% 100%;transition:transform .55s var(--fx-out)}
  .project-row:hover:before{transform:scaleY(1)}
  .project-row:hover{padding-left:28px;color:var(--ink)}
  .project-row .row-arrow{transition:transform .5s var(--fx-out)}
  .project-row:hover .row-arrow{transform:translate(4px,-4px) rotate(45deg)}
}

@media(prefers-reduced-motion:reduce){
  .hero-char,.hero-image,.hero-image img,.hero-caption,.hero-scroll,.hero-name-ko{animation:none!important}
  .fx-wi,.fx-img,.fx-img img{transform:none!important;clip-path:none!important;scale:none!important}
  .stage-wash,.preloader{display:none!important}
  .marquee-track{transform:none}
}
@media print{
  .preloader,.marquee,.stage-numeral,.stage-wash{display:none!important}
  .fx-scrub.is-pinned .project-slide{visibility:visible!important}
  .fx-scrub.is-pinned .project-copy>*{opacity:1!important;transform:none!important}
  .fx-wi,.fx-rise,.fx-img,.fx-img img,.project-visual{opacity:1!important;transform:none!important;clip-path:none!important;scale:none!important;translate:none!important}
  .stage-wash{display:none}
}
