html,body{margin:0;background:#f5f5f5}
a{color:#0a0a0a}a:hover{color:#363636}
*{box-sizing:border-box}
.d{font-family:'GT Walsheim','DM Sans',system-ui,sans-serif;font-weight:500;letter-spacing:-0.04em;line-height:1;margin:0}
.it{font-family:'Instrument Serif',serif;font-style:italic;font-weight:400;letter-spacing:-0.01em}
.fr .it{font-family:'Fraunces',serif;font-variation-settings:'opsz' 144;letter-spacing:-0.02em}
.wrap{width:100%;padding-left:32px;padding-right:32px}
.beat{position:relative;min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:clip;perspective:1000px}
.center{position:relative;z-index:1;display:flex;flex-direction:column;align-items:center;gap:28px;text-align:center;max-width:1180px}
/* Phones: the carousel's side cards peek in at the edges, so the hero text keeps clear of them. */
@media (max-width:767px){.hs-hero .center{padding-inline:24px}}
.tile{position:absolute;border-radius:8px;overflow:hidden;display:flex;align-items:center;justify-content:center;text-align:center;padding:12px;font-size:12px;color:#6b6b6b;z-index:0}
.t1{aspect-ratio:3 / 2;width:22%;top:9%;left:7%;background:rgba(255,255,255,0.65)}
.t2{aspect-ratio:16 / 9;width:24%;top:6%;right:8%;background:rgba(0,0,0,0.06)}
.t3{aspect-ratio:4 / 5;width:15%;bottom:11%;right:5%;background:rgba(255,255,255,0.65)}
.t4{aspect-ratio:3 / 2;width:23%;bottom:4%;left:38%;background:rgba(0,0,0,0.06)}
.t5{aspect-ratio:1 / 1;width:15%;bottom:12%;left:5%;background:rgba(255,255,255,0.65)}
/* Each word glows in through a filter, and mobile Safari clips a filtered element to its own box:
   descenders (p, g, y) and the italic's overhang sit outside it at this tight line height. Padding
   gives the glyphs room (the negative margin keeps the layout), and the glow ends with no filter. */
.gw{display:inline-block;padding:0 .12em .22em;margin:0 -.12em -.22em}
@keyframes glowIn{0%{opacity:0;color:transparent;text-shadow:0 0 5px #4CC7F0;filter:hue-rotate(0deg)}27%{opacity:1;color:transparent;text-shadow:0 0 5px #4CC7F0;filter:hue-rotate(45deg)}60%{color:rgba(10,10,10,0.55);text-shadow:0 0 6px rgba(76,199,240,0.35);filter:hue-rotate(100deg)}100%{opacity:1;color:#0a0a0a;text-shadow:none;filter:none}}
@media (prefers-reduced-motion: no-preference){
.gw{animation:glowIn 1.1s linear backwards;animation-delay:calc(0.25s + var(--i) * 0.05s)} /* backwards: once done, the word drops the animation (and its filter) for its own style */
}
.w{display:inline-block;white-space:nowrap;padding-right:0.08em}
.btn{display:inline-flex;align-items:center;gap:10px;min-height:44px;padding:0 18px;border-radius:999px;font-family:'Geist',sans-serif;font-size:14px;font-weight:500;line-height:1;text-decoration:none;letter-spacing:0}
.nav a.d{display:inline-flex;align-items:center}
.nav a{font-size:14px;text-decoration:none;color:#5a5a5a;padding:8px 12px;border-radius:999px;min-height:36px;display:inline-flex;align-items:center}
.nav a:hover,.nav a[aria-current]{color:#0a0a0a}
.row{display:grid;grid-template-columns:minmax(0,1fr) 280px 120px;gap:24px;align-items:end;padding:26px 0;border-bottom:1px solid #0000001a;text-decoration:none;color:#0a0a0a}
.row:hover .d{opacity:0.65}
a:focus-visible{outline:2px solid #0a0a0a;outline-offset:3px}
/* Scroll-driven motion: finished state is the default, motion layers on top where supported */
@supports (animation-timeline: view()) {
@media (prefers-reduced-motion: no-preference) {
.flip{animation:flip linear both;animation-timeline:view();animation-range:entry 0% exit 100%;transform-origin:50% 50%}
@keyframes flip{0%{transform:rotateX(35deg);opacity:0}35%,65%{transform:rotateX(0deg);opacity:1}100%{transform:rotateX(-35deg);opacity:0}}
.spread .w{animation:spread linear both,glowIn linear both;animation-timeline:view(),view();animation-range:entry 10% cover 45%,entry 15% cover 50%}
@keyframes spread{0%{translate:var(--dx) 0;opacity:0.2}100%{translate:0 0;opacity:1}}
.tile{animation:tileIn linear both;animation-timeline:view();animation-range:entry 0% cover 40%}
@keyframes tileIn{0%{opacity:0;transform:translateY(90px) rotateX(28deg) scale(0.94)}100%{opacity:1;transform:none}}
.par{animation:par linear both;animation-timeline:view();animation-range:cover 0% cover 100%}
@keyframes par{0%{translate:0 60px}100%{translate:0 -60px}}
.row{animation:rowIn linear both;animation-timeline:view();animation-range:entry 0% entry 100%}
@keyframes rowIn{0%{opacity:0;translate:0 40px}100%{opacity:1;translate:0 0}}
.logo-in{animation:logoIn linear both;animation-timeline:view();animation-range:exit 0% exit 60%}
@keyframes logoIn{0%{opacity:1;scale:1}100%{opacity:0;scale:0.85}}
}
}
@media (max-width:991px){
.t2,.t4{display:none}
.t1{width:34%;top:4%;left:4%}
.t3,.t5{width:26%}
.row{grid-template-columns:minmax(0,1fr);gap:8px}
.navlinks{display:none !important}
}
@media (max-width:600px){
.wrap{padding-left:16px;padding-right:16px}
}
/* Page-enter curtain (mirrors PageTransition.astro): the mark assembles, fades, the curtain slides up.
   Pure CSS from mount, so it can never get stuck covering the page. */
.pt{position:fixed;inset:0;z-index:9999;pointer-events:none;animation:ptGone 0s linear 2.15s forwards}
@keyframes ptGone{to{visibility:hidden}}
.pt-bg{position:absolute;inset:0;background:#f5f5f5;animation:ptUp 1s cubic-bezier(.4,0,.2,1) 1.1s forwards}
@keyframes ptUp{to{opacity:0}}
.pt-mark{position:absolute;inset:0;display:grid;place-items:center;color:#0a0a0a;animation:ptFade .6s ease .9s forwards}
@keyframes ptFade{to{opacity:0}}
.pt-mark svg{width:3.83rem;height:auto;overflow:visible}
.pt-piece{opacity:0;animation:ptJoin .7s cubic-bezier(.33,1,.68,1) forwards}
.pt-top{--from:translateY(-8px)}
.pt-left{--from:translate(-6px, 6px);animation-delay:.12s}
.pt-right{--from:translate(6px, 6px);animation-delay:.24s}
@keyframes ptJoin{from{opacity:0;transform:var(--from)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion: reduce){.pt{display:none}}
/* Hero stage: the carousel pins behind the headline. The headline scrolls away, the stage
   darkens to black and the carousel becomes section 2. Clicking a card jumps to that view. */
.hs{position:relative;height:200svh;--hs-p:0}
/* The stage reaches the bottom of the screen when the phone browser bar hides (no light strip under
   it); the carousel itself keeps the small-screen height, so its layout does not jump. */
.hs-stick{position:sticky;top:0;height:100svh;height:100lvh;overflow:hidden}
.hs-stick > [data-cylindrical-carousel]{height:100svh;background:none}
/* The stage darkens as you scroll: an opacity change on its own layer, so the browser never repaints
   the full screen behind the 3D canvas (that repaint made the fade stutter on phones). */
.hs-stick::before{content:"";position:absolute;inset:0;z-index:0;background:#000;opacity:var(--hs-p);will-change:opacity;pointer-events:none}
.hs [data-cylindrical-carousel] .controls{opacity:var(--hs-p);transition:opacity .2s}
.hs:not([data-revealed]) [data-cylindrical-carousel] .controls{pointer-events:none}
.hs:not([data-revealed]) [data-cylindrical-carousel] .gesture{cursor:pointer}
.hs-hero{position:absolute;inset:0 0 auto;height:100svh;z-index:2;display:grid;place-items:center;pointer-events:none;padding:0 32px}
.hs-hero .center{position:relative;pointer-events:none}
.hs-hero .center p{text-wrap:balance}
.hs-hero a,.hs-hero button{pointer-events:auto}
.hs-veil{position:absolute;left:50%;top:50%;width:min(1100px, 92vw);height:min(720px, 86svh);transform:translate(-50%,-50%);border-radius:50%;opacity:calc(1 - var(--hs-p) * 1.6);will-change:opacity}
.hs-veil::before{content:"";position:absolute;inset:0;border-radius:inherit;background:radial-gradient(closest-side, rgba(245,245,245,1) 0%, rgba(245,245,245,.98) 22%, rgba(245,245,245,.93) 38%, rgba(245,245,245,.83) 52%, rgba(245,245,245,.66) 64%, rgba(245,245,245,.45) 75%, rgba(245,245,245,.25) 85%, rgba(245,245,245,.1) 93%, rgba(245,245,245,0) 100%)}
/* Intro, one logo: the hero mark assembles in the screen centre over the curtain, glows,
   then glides into its exact place above the headline. The headline's glow follows. */
.pt{z-index:3}
.hs-hero{z-index:4}
.hs-logo{position:relative;transform-origin:50% 50%;overflow:visible}
@media (prefers-reduced-motion: no-preference){
.hs-logo{animation:logoSettle 1.3s cubic-bezier(.65,0,.35,1) 1.05s both,logoGlow 1.7s linear .8s both}
@keyframes logoSettle{from{transform:translate(var(--fx, 0px), var(--fy, 0px)) scale(var(--fs, 1))}to{transform:none}}
@keyframes logoGlow{0%{color:#0a0a0a;filter:drop-shadow(0 0 0 rgba(76,199,240,0))}30%{color:rgba(76,199,240,0.35);filter:drop-shadow(0 0 5px #4CC7F0) hue-rotate(45deg)}65%{color:rgba(10,10,10,0.6);filter:drop-shadow(0 0 6px rgba(76,199,240,0.35)) hue-rotate(100deg)}100%{color:#0a0a0a;filter:drop-shadow(0 0 0 rgba(76,199,240,0))}}
.hs-hero .gw{animation-duration:1.4s;animation-delay:calc(2.35s + var(--i) * 0.09s)}
.hs-in{animation:hsIn 1s cubic-bezier(.22,.61,.36,1) 2.9s both}
.hs-stick [data-cylindrical-carousel]{animation:hsAppear 1.6s cubic-bezier(.22,.61,.36,1) 1.1s both}
@keyframes hsAppear{from{transform:scale(1.04)}to{transform:none}}
.hs-veil::before{animation:veilIn 1.6s cubic-bezier(.22,.61,.36,1) 2.2s both}
@keyframes veilIn{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}
@keyframes hsIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
}
/* Scroll: the hero text fades and lifts away while the stage darkens. */
.hs-hero .center{opacity:calc(1 - var(--hs-p) * 1.6);transform:translateY(calc(var(--hs-p) * -80px));will-change:opacity,transform}
/* Phones and tablets: the same fade, timed instead of following the finger (data-dim, set once
   the page leaves the top). Timed opacity runs on the compositor, so it stays smooth mid-scroll. */
@media (hover: none), (max-width: 1024px){
.hs-stick::before{opacity:0;transition:opacity .8s cubic-bezier(.65,0,.35,1)}
.hs-veil{opacity:1;transition:opacity .6s ease}
.hs-hero .center{opacity:1;transform:none;transition:opacity .5s ease,transform .8s cubic-bezier(.65,0,.35,1)}
.hs [data-cylindrical-carousel] .controls{opacity:0;transition:opacity .5s ease .3s}
.hs[data-dim] .hs-stick::before{opacity:1}
.hs[data-dim] .hs-veil{opacity:0}
.hs[data-dim] .hs-hero .center{opacity:0;transform:translateY(-80px)}
.hs[data-dim] [data-cylindrical-carousel] .controls{opacity:1}
}
/* Phones, first screen: the cards and the headline sit centred in the space below the menu bar
   (half its 76px lower), then glide back to the carousel's own centre as the stage darkens. */
@media (max-width: 699px){
.hs-stick [data-cylindrical-carousel] .scene{translate:0 38px;transition:opacity 300ms ease,translate .8s cubic-bezier(.65,0,.35,1)}
.hs[data-dim] .hs-stick [data-cylindrical-carousel] .scene{translate:none}
.hs-hero{padding-top:76px}
}
/* The menu stays hidden while the loader plays and fades in once the page is revealed. */
@media (prefers-reduced-motion: no-preference){
.mn-header{animation:navIn .7s cubic-bezier(.22,.61,.36,1) 3.1s both}
@keyframes navIn{from{opacity:0;visibility:hidden}to{opacity:1;visibility:visible}}
}
/* Top morphing navigation (same timings as the site build: panel ease .75,0,.25,1). */
.mnav{--ez:cubic-bezier(.75,0,.25,1);--rev:cubic-bezier(.165,.84,.44,1);--t1:#f5f5f4;--t2:#a6a09b;--s3:#2e2b29;color:var(--t1)}
.mn-backdrop{position:fixed;inset:0;z-index:40;background:rgba(0,0,0,0.12);opacity:0;visibility:hidden;transition:opacity 310ms,visibility 310ms}
.mnav[data-open=true] .mn-backdrop{opacity:1;visibility:visible}
.mn-header{position:fixed;inset:0 0 auto;z-index:50;padding:24px;pointer-events:none;display:flex;justify-content:center;transition:transform .73s var(--ez) .21s}
.mn-panel{position:relative;width:330px;height:60px;flex-shrink:0;pointer-events:auto;overflow:hidden;border-radius:12px;corner-shape:superellipse(1.5);background:rgba(0,0,0,0.7);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);transition:width .73s var(--ez) .21s,height .49s var(--ez) 0s,border-radius .73s var(--ez) .21s,background-color .49s var(--ez) .1s}
.mnav[data-open=true] .mn-panel{background-color:rgba(10,10,10,0.92);width:min(750px, calc(100vw - 48px));height:364px;transition:width .73s var(--ez) 0s,height .73s var(--ez) .23s,border-radius .73s var(--ez) 0s,background-color .49s var(--ez) 0s}
.mn-bar{position:absolute;inset:0 0 auto;height:60px;z-index:2}
.mn-home{position:absolute;top:0;left:8px;width:60px;height:60px;display:grid;place-items:center;color:var(--t1);transition:scale .3s}
.mn-home:hover{scale:.91}
.mn-toggle{position:absolute;right:4px;top:0;width:60px;height:60px;border:0;background:none;color:var(--t1);cursor:pointer;padding:0}
.mn-toggle::before{content:"";position:absolute;inset:10px;border-radius:8px;transition:background 200ms}
.mn-toggle:hover::before{background:rgba(46,43,41,0.3)}
.mn-toggle span{position:absolute;left:50%;width:20px;height:2px;translate:-50% -50%;border-radius:2px;background:currentColor;transition:top .49s var(--ez),rotate .49s var(--ez)}
.mn-t{top:42%}.mn-b{top:58%}
.mnav[data-open=true] .mn-t{top:50%;rotate:45deg}
.mnav[data-open=true] .mn-b{top:50%;rotate:-45deg}
.mn-home:focus-visible,.mn-toggle:focus-visible{outline:none}
.mn-home:focus-visible::after,.mn-toggle:focus-visible::after{content:"";position:absolute;inset:10px;border-radius:8px;outline:1.5px solid rgba(245,245,244,0.6);outline-offset:2px}
.mn-content{position:absolute;top:60px;left:50%;width:min(750px, calc(100vw - 48px));padding:20px 24px 24px;transform:translateX(-50%);max-height:calc(100dvh - 108px);overflow-y:auto;scrollbar-width:none}
.mn-spread{display:grid;grid-template-columns:1fr 398px;grid-template-areas:"links media" "footer footer";align-items:start;gap:24px 32px}
.mn-enter{opacity:0;transform:translateY(20px);filter:blur(4px);transition:opacity .3s ease-in,transform .3s ease-in,filter .3s ease-in;transition-delay:calc(var(--ri) * .03s)}
.mnav[data-open=true] .mn-enter{opacity:1;transform:none;filter:blur(0);transition:opacity .73s var(--rev),transform .73s var(--rev),filter .73s var(--rev);transition-delay:calc(.5s + var(--i) * .065s)}
.mn-media{grid-area:media;position:relative;width:100%;aspect-ratio:398/212;overflow:hidden;border-radius:8px;corner-shape:superellipse(1.5);background:var(--s3);opacity:0;transition:opacity .3s ease-in .03s}
.mnav[data-open=true] .mn-media{opacity:1;transition:opacity .73s var(--ez) .5s}
.pv{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:12px;color:rgba(255,255,255,0.6);opacity:0;z-index:0;transition:opacity 0s linear .2s}
.pv.on{opacity:1;z-index:2;transition:opacity .2s cubic-bezier(.25,.46,.45,.94)}
.pv img{display:block;width:100%;height:100%;object-fit:cover}
.pv.on img{animation:pvZoom .6s cubic-bezier(.215,.61,.355,1)}
@keyframes pvZoom{from{scale:1.1}to{scale:1}}
.mn-links{grid-area:links;display:block}
.mn-links a{position:relative;display:flex;align-items:center;min-height:40px;padding-right:.75em;color:var(--t1);font-size:28px;line-height:1.2;border-radius:8px;text-decoration:none;letter-spacing:-0.01em}
.mn-links a::before{content:"";position:absolute;top:50%;left:0;width:.45em;height:2px;background:currentColor;transform:translateY(-50%) scaleX(0);transform-origin:left center;transition:transform 500ms cubic-bezier(.19,1,.22,1)}
.mn-links a .word{display:block;transition:transform 500ms cubic-bezier(.19,1,.22,1),opacity 240ms ease}
.mn-links a:hover::before,.mn-links a:focus-visible::before{transform:translateY(-50%) scaleX(1)}
.mn-links a:hover .word,.mn-links a:focus-visible .word{transform:translateX(.7em)}
.mn-links:has(a:hover) a:not(:hover) .word,.mn-links:has(a:focus-visible) a:not(:focus-visible) .word{opacity:.35}
.mn-links a:focus-visible{outline:1.5px solid rgba(245,245,244,0.6);outline-offset:2px}
/* Work opens the case-study list in place of the main links; Back returns. */
.mn-work{grid-area:links;display:none}
.mnav[data-view=work] .mn-links{display:none}
.mnav[data-view=work] .mn-work{display:block;animation:mnView .6s var(--rev) both}
.mn-links{animation:mnView .6s var(--rev) both}
@keyframes mnView{from{opacity:0;transform:translateY(12px);filter:blur(4px)}to{opacity:1;transform:none;filter:none}}
.mn-back{display:inline-flex;align-items:center;margin:0 0 10px;padding:4px 0;border:0;background:none;color:var(--t2);font:inherit;font-size:15px;cursor:pointer;transition:color 180ms}
.mn-back:hover{color:var(--t1)}
.mn-back:focus-visible{outline:1.5px solid rgba(245,245,244,0.6);outline-offset:2px;border-radius:4px}
.mn-work ul{list-style:none;margin:0;padding:0}
.mn-work a{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:6px 0;border-bottom:1px solid rgba(245,245,244,0.08);color:var(--t1);font-size:17px;line-height:1.4;text-decoration:none;transition:opacity 240ms ease}
.mn-wd{font-size:13px;color:var(--t2);white-space:nowrap}
.mn-work:has(a:hover) a:not(:hover),.mn-work:has(a:focus-visible) a:not(:focus-visible){opacity:.35}
.mn-work a[aria-current] .mn-wn::after{content:"";display:inline-block;width:5px;height:5px;margin-left:8px;border-radius:50%;background:currentColor;vertical-align:middle}
.mn-work a:focus-visible{outline:1.5px solid rgba(245,245,244,0.6);outline-offset:2px}
.mn-mail{color:var(--t1);font-size:15px;text-decoration:none;transition:opacity 180ms}
.mn-mail:hover{opacity:.7}
.mn-meta{margin-right:auto;color:var(--t2);font-size:15px}
@media (min-width:768px){
.mnav[data-open=true][data-view=work] .mn-panel{height:min(576px, calc(100dvh - 48px))}
.mnav[data-view=work] .mn-spread{grid-template-columns:1fr 300px}
.mnav[data-view=work] .mn-media{aspect-ratio:1 / 1}
}
.mn-foot{grid-area:footer;display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:16px}
.mn-socials{display:flex;align-items:flex-end;gap:10px}
.mn-socials a{display:grid;place-items:center;width:24px;height:24px;border-radius:6px;color:var(--t2);transition:color 180ms}
.mn-x svg{transform:translateY(1px)}
.mn-socials a:hover,.mn-utility a:hover{color:var(--t1)}
.mn-utility{display:flex;align-items:center;gap:24px;margin-left:auto;font-size:15px;line-height:1.4}
.mn-utility a[aria-current]{color:var(--t1)}
.mn-utility a{color:var(--t2);text-decoration:none;min-height:24px;display:inline-flex;align-items:center;transition:color 180ms}
@media (max-width:767px){
.mn-header{padding:16px}
.mn-panel{width:calc(100vw - 32px)}
.mnav[data-open=true] .mn-header{transform:translateY(-16px);transition:transform .73s var(--ez) 0s}
.mnav[data-open=true] .mn-panel{width:100vw;height:100dvh;border-radius:0}
.mn-content{width:100vw;height:calc(100dvh - 60px);max-height:calc(100dvh - 60px)}
.mn-spread{grid-template-columns:1fr;grid-template-areas:"links" "media" "footer";gap:20px}
.mn-links a{font-size:30px;min-height:48px}
.mn-media{height:160px;aspect-ratio:auto}
.mnav[data-view=work] .mn-media{display:none}
}
@media (prefers-reduced-motion:reduce){
.mnav *{transition-duration:0s !important;transition-delay:0s !important;animation:none !important}
}
/* Section transitions (data-st-01): sibling blocks stack at z-index 1 so reveal works. */
.st-flow > section:not(#s-top),.st-flow > footer{position:relative;z-index:1}
.st-flow > section:not(#s-top):not([data-cylindrical-carousel]),.st-flow > footer{background:#f5f5f5}
.st-flow > section[data-st-01]{min-height:100vh}
/* Last section, "Launching something?": a globe of mark tiles on a canvas behind the text (proto.js,
   brief()). It fills the screen, starts dark and turns light as the big mark lands on the globe. */
.st-flow > section#s-brief{min-height:100svh;background:#f5f5f5;color:#0a0a0a}
.br-globe{position:absolute;inset:0;width:100%;height:100%;pointer-events:none}
.br-line{margin:0;font-size:var(--t-lead);color:#363636}
.br-main{background:#0a0a0a;color:#ffffff}
.br-soft{background:#0000000f;color:#0a0a0a}
#s-brief,#s-brief .br-line{transition:background-color 1.5s cubic-bezier(.37,0,.63,1),color 1.5s cubic-bezier(.37,0,.63,1)}
#s-brief .btn{transition:background-color 1.5s cubic-bezier(.37,0,.63,1),color 1.5s cubic-bezier(.37,0,.63,1),transform .3s cubic-bezier(.2,.8,.2,1)}
.st-flow > section#s-brief[data-dark]{background:#0a0a0a;color:#f5f5f5}
#s-brief[data-dark] .br-line{color:#a8a8a8}
#s-brief[data-dark] .br-main{background:#f5f5f5;color:#0a0a0a}
#s-brief[data-dark] .br-soft{background:#ffffff1a;color:#f5f5f5}
.st-flow > section[data-st-01]:not([data-st-01="pin"]){will-change:transform}
/* Cylindrical carousel, on black inside the parallax section. */
[data-cylindrical-carousel]{--carousel-background:#000000;--carousel-color:#f5f5f5;--carousel-control:rgb(38,38,38);--carousel-control-hover:rgb(58,58,58);--carousel-focus:#4CC7F0;position:relative;width:100%;height:100svh;min-height:420px;overflow:hidden;background:var(--carousel-background);color:var(--carousel-color);font-family:'GT Walsheim','DM Sans',system-ui,sans-serif;font-weight:500}
[data-cylindrical-carousel],[data-cylindrical-carousel] *,[data-cylindrical-carousel] *::before,[data-cylindrical-carousel] *::after{box-sizing:border-box}
[data-cylindrical-carousel]:focus,[data-cylindrical-carousel]:focus-visible{outline:none}
[data-cylindrical-carousel] .scene{position:absolute;inset:0;z-index:1;display:block;width:100%;height:100%;opacity:0;transition:opacity 300ms ease}
[data-cylindrical-carousel][data-ready] .scene{opacity:1}
[data-cylindrical-carousel] .gesture{position:absolute;inset:8% 0;z-index:2;cursor:grab;touch-action:pan-y}
:root{--t-hero:clamp(48px, 6.6vw, 104px);--t-project:clamp(44px, 6vw, 96px);--t-h2:clamp(32px, 3.4vw, 48px);--t-lede:clamp(20px, 2vw, 28px);--t-accent:20px;--t-lead:18px;--t-body:15px;--t-ui:14px;--t-small:13px;--t-caption:12px;--sec:clamp(96px, 10vw, 140px);--sec-s:clamp(56px, 6vw, 80px)}
/* Section 3, what we do: services are added one by one as you scroll. The current one opens its
   description and a soft pass of the logo gradient runs through its name, settling back to
   white; earlier ones close and dim.
   A single blended glow sits behind the current service. */
@property --g{syntax:'<number>';inherits:false;initial-value:0}
.st-flow > section#s-what.sv{position:relative;background:#000;color:#f5f5f5;overflow-x:clip}
.sv-intro,.sv-stick{max-width:1440px;margin-left:auto;margin-right:auto;box-sizing:border-box}
.sv-intro{padding-top:var(--sec);padding-bottom:var(--sec-s)}
.sv-statement{font-size:var(--t-h2);letter-spacing:-0.035em;line-height:1.1;max-width:19em}
.sv-statement .it{color:rgba(245,245,245,0.55);white-space:nowrap} /* "In one look." stays on one line */
.sv-track{position:relative;height:calc(100svh + var(--n) * 70svh)}
.sv-stick{position:sticky;top:0;height:100svh;display:grid;grid-template-columns:minmax(0, 1.15fr) minmax(0, 1fr);gap:clamp(32px, 5vw, 96px);align-items:center}
.sv-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:clamp(4px, 0.8vw, 12px);position:relative;z-index:1}
.sv-item{opacity:0;transform:translateY(32px);transition:opacity .6s cubic-bezier(.22,.61,.36,1),transform .8s cubic-bezier(.22,.61,.36,1)}
.sv-item[data-s="on"]{opacity:1;transform:none}
.sv-item[data-s="past"]{opacity:.22;transform:none}
/* The name is painted through the gradient; --g mixes it from white (0) to full colour (1). */
.sv-name{font-size:var(--t-project);padding-bottom:.14em;margin-bottom:-.14em;color:transparent;-webkit-text-fill-color:transparent;-webkit-background-clip:text;background-clip:text;background-size:150% 100%;background-image:linear-gradient(100deg, color-mix(in oklab, #4CC7F0 calc(var(--g) * 100%), #f5f5f5) 0%, color-mix(in oklab, #8F75F5 calc(var(--g) * 100%), #f5f5f5) 35%, color-mix(in oklab, #ED85DB calc(var(--g) * 100%), #f5f5f5) 65%, color-mix(in oklab, #4CC7F0 calc(var(--g) * 100%), #f5f5f5) 100%)}
.sv-more{display:grid;grid-template-rows:0fr;transition:grid-template-rows .65s cubic-bezier(.65,0,.35,1)}
.sv-more > div{overflow:hidden;min-height:0;opacity:0;filter:blur(8px);transition:opacity .4s ease,filter .4s ease}
.sv-item[data-s="on"] .sv-more{grid-template-rows:1fr}
.sv-item[data-s="on"] .sv-more > div{opacity:1;filter:none;transition-delay:.18s}
.sv-line{font-family:'Geist',system-ui,sans-serif;font-size:var(--t-lead);line-height:1.5;color:rgba(245,245,245,0.8);max-width:28em;margin:14px 0 6px}
.sv-get{font-family:'Geist',system-ui,sans-serif;font-size:var(--t-small);line-height:1.4;color:rgba(245,245,245,0.5);margin:0 0 8px}
/* One blended cloud: the three logo colours overlap heavily so they read as a single light. */
.sv-glow{position:absolute;left:-14%;top:0;width:46%;height:68%;translate:0 calc(var(--gy, 50svh) - 50%);pointer-events:none;z-index:0;opacity:0;filter:hue-rotate(calc(var(--sv-i, 0) * 22deg));transition:opacity 1.2s ease,filter 1.8s ease}
#s-what[data-live] .sv-glow{opacity:.4}
#s-what[data-live][data-bloom] .sv-glow{opacity:.55}
.sv-glow span{position:absolute;inset:0;background:radial-gradient(closest-side at 42% 46%, rgba(76,199,240,0.55), rgba(76,199,240,0.3) 40%, rgba(76,199,240,0) 100%),radial-gradient(closest-side at 56% 52%, rgba(143,117,245,0.55), rgba(143,117,245,0.3) 40%, rgba(143,117,245,0) 100%),radial-gradient(closest-side at 48% 60%, rgba(237,133,219,0.42), rgba(237,133,219,0.22) 40%, rgba(237,133,219,0) 100%);-webkit-mask-image:radial-gradient(closest-side, #000 30%, transparent 100%);mask-image:radial-gradient(closest-side, #000 30%, transparent 100%)}
@media (prefers-reduced-motion: no-preference){
.sv-item[data-s="on"] .sv-name{animation:svPass 2.2s cubic-bezier(.22,.61,.36,1) .15s both}
@keyframes svPass{0%{--g:0;background-position:0% 50%}30%{--g:.55}100%{--g:0;background-position:100% 50%}}
/* No rotation: the cloud only stretches and leans a little, like light shifting. */
.sv-glow span{animation:svMorph 22s cubic-bezier(.37,0,.63,1) infinite alternate}
@keyframes svMorph{from{transform:scale(1.012, .988) translate(-.3%, .2%)}to{transform:scale(.99, 1.01) translate(.3%, -.2%) skewX(-.5deg)}}
}
.sv-media{position:relative;justify-self:end;width:100%;max-width:600px;--box-h:min(70svh, 640px);height:var(--box-h);z-index:1}
.sv-fig{position:absolute;left:50%;top:50%;translate:-50% -50%;margin:0;width:min(100%, calc((var(--box-h) - 64px) * var(--ar)));opacity:0;transition:opacity .7s ease}
.sv-fig[data-on]{opacity:1}
.sv-fig video{display:block;width:100%;height:auto;aspect-ratio:var(--ar);border-radius:20px;object-fit:cover;background:#111}
/* Who the film is for: brand name, then the services on that project. */
.sv-fig figcaption{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px;margin-top:14px}
.sv-cap-name{font-family:'GT Walsheim','DM Sans',system-ui,sans-serif;font-weight:500;font-size:var(--t-accent);letter-spacing:-0.01em;color:#f5f5f5}
.sv-cap-services{font-family:'Geist',system-ui,sans-serif;font-size:var(--t-small);color:rgba(245,245,245,0.55)}
/* Each film opens its project; a quiet pill names the action on hover. */
.sv-fig{pointer-events:none}
.sv-fig[data-on]{pointer-events:auto}
.sv-link{position:relative;display:block;color:inherit;text-decoration:none;border-radius:20px}
.sv-view{position:absolute;left:50%;top:50%;translate:-50% calc(-50% + 6px);padding:10px 18px;border-radius:999px;background:rgba(255,255,255,0.14);-webkit-backdrop-filter:blur(14px) saturate(1.4);backdrop-filter:blur(14px) saturate(1.4);border:1px solid rgba(255,255,255,0.22);font-family:'Geist',system-ui,sans-serif;font-size:var(--t-ui);color:#fff;white-space:nowrap;opacity:0;transition:opacity .35s ease,translate .45s cubic-bezier(.22,.61,.36,1);pointer-events:none}
.sv-link:hover .sv-view,.sv-link:focus-visible .sv-view{opacity:1;translate:-50% -50%}
.sv-link:focus-visible{outline:2px solid #fff;outline-offset:4px}
@media (hover:none){.sv-view{display:none}}
/* Large screens: type stays on its tokens; only the layout and the films get the extra room. */
@media (min-width:1800px){
.sv-intro,.sv-stick{max-width:1600px}
.sv-media{max-width:800px;--box-h:min(74svh, 820px)}
.sv-fig video,.sv-link{border-radius:24px}
}
@media (max-width:899px){
.sv-glow{left:-25%;width:150%;height:62%}
.sv-stick{grid-template-columns:1fr;grid-template-rows:auto 1fr;align-content:center;gap:24px;padding-top:88px;padding-bottom:32px}
.sv-media{order:-1;justify-self:stretch;max-width:none;--box-h:32svh}
}
/* Phones: lighter rendering in the pinned panel. Mobile Safari flickers and stutters while scrolling
   when gradient-clipped text animates (the names' colour sweep) and blurred layers change inside a
   sticky panel, so here the names are plain white, the glow holds still and descriptions only fade. */
@media (max-width:899px){
.sv-name,.sv-item[data-s="on"] .sv-name{animation:none;color:#f5f5f5;-webkit-text-fill-color:#f5f5f5;background:none}
.sv-glow{filter:none;transition:opacity 1.2s ease}
.sv-glow span{animation:none}
.sv-more > div{filter:none}
}
/* Phones: one service at a time. A thin five-part bar at the top fills with scroll (--f, set per
   segment by mountServices); the current service's name and line slide in from below while the
   previous slides out above; its film sits underneath in its own shape with the project under it.
   The text area has a fixed height so the film never jumps. */
.sv-bar{display:none}
@media (max-width:899px){
.sv-stick{display:flex;flex-direction:column;justify-content:flex-start;align-items:stretch;gap:0;padding-top:84px;padding-bottom:24px}
.sv-bar{display:flex;gap:5px;margin-bottom:22px;position:relative;z-index:1}
.sv-bar span{flex:1;height:2px;border-radius:2px;background:rgba(245,245,245,0.16);overflow:hidden}
.sv-bar i{display:block;height:100%;background:#f5f5f5;transform-origin:0 50%;transform:scaleX(var(--f, 0))}
.sv-list{position:relative;height:178px;gap:0}
.sv-item,.sv-item[data-s]{position:absolute;left:0;right:0;top:0;transition:opacity .45s ease,transform .6s cubic-bezier(.22,1,.36,1)}
.sv-item{opacity:0;transform:translateX(40px)}
.sv-item[data-s="on"]{opacity:1;transform:none}
.sv-item[data-s="past"]{opacity:0;transform:translateX(-40px)}
.sv-more,.sv-item[data-s] .sv-more{grid-template-rows:1fr;transition:none}
.sv-more > div,.sv-item[data-s="on"] .sv-more > div{opacity:1;transition:none}
.sv-line{font-size:var(--t-body);margin:10px 0 4px}
.sv-media{order:0;flex:none;margin-top:8px;--box-h:calc(100svh - 84px - 24px - 178px - 32px)}
/* Smooth scrolling on phones: no blurred glow behind the panel, and what moves gets its own layer. */
.sv-glow{display:none}
.sv-item,.sv-fig{will-change:opacity,transform}
.sv-bar i{will-change:transform}
/* Not pinned on phones: one screen in the normal flow, the services cycle by themselves. */
.sv-track{height:auto}
.sv-stick{position:relative;top:auto;height:auto;padding-top:96px;padding-bottom:var(--sec-s);touch-action:pan-y}
.sv-media{--box-h:min(58svh, 540px)}
.sv-fig{top:0;translate:-50% 0}
.sv-bar{z-index:3}
.sv-item:not([data-s="on"]){pointer-events:none}
.sv-bar span{position:relative;cursor:pointer}
.sv-bar span::before{content:"";position:absolute;inset:-12px 0}
}
@media (prefers-reduced-motion: reduce){
.sv-track{height:auto}
.sv-stick{position:static;height:auto;padding-top:24px;padding-bottom:96px}
.sv-item,.sv-item[data-s]{opacity:1;transform:none}
.sv-more,.sv-item[data-s] .sv-more{grid-template-rows:1fr}
.sv-more > div{opacity:1;filter:none}
}
/* Brands we've worked with: a slow logo strip at the top of section 3, white marks on black,
   fading out at both edges. It never pauses on hover. */
.sv-logos{padding-top:var(--sec-s);overflow:hidden;-webkit-mask-image:linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);mask-image:linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent)}
.sv-logo-track{list-style:none;margin:0;padding:0;display:flex;width:max-content}
.sv-logo-track li{flex:none;height:96px;padding:0 clamp(28px, 3.4vw, 56px);display:grid;place-items:center;opacity:.62}
.sv-logo-mono{filter:brightness(0) invert(1)}
.sv-logo-gray{filter:grayscale(1) brightness(1.3)}
.sv-logo-name{font-size:var(--t-accent);letter-spacing:-0.01em;color:#f5f5f5}
@media (prefers-reduced-motion: no-preference){
.sv-logo-track{animation:svLogos 48s linear infinite}
@keyframes svLogos{to{transform:translateX(-50%)}}
}
@media (prefers-reduced-motion: reduce){
.sv-logos{-webkit-mask-image:none;mask-image:none}
.sv-logo-track{width:auto;flex-wrap:wrap;justify-content:center}
.sv-logo-track li[aria-hidden]{display:none}
}
@media (max-width:767px){.sv-logo-track li{height:80px;padding:0 22px}}
/* Hover captions on the revealed carousel: project name, then services, in a small glass tag. */
.cc-caption{position:absolute;left:0;top:0;z-index:3;display:flex;flex-direction:column;gap:3px;padding:10px 14px 11px;border-radius:12px;background:rgba(10,10,10,0.55);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border:1px solid rgba(255,255,255,0.08);pointer-events:none;opacity:0;transition:opacity .25s ease;max-width:300px;will-change:transform}
.cc-caption[data-show]{opacity:1}
.cc-title{font-family:'GT Walsheim','DM Sans',system-ui,sans-serif;font-weight:500;font-size:var(--t-accent);line-height:1.15;letter-spacing:-0.01em;color:#f5f5f5}
.cc-services{font-family:'Geist',system-ui,sans-serif;font-weight:400;font-size:var(--t-small);line-height:1.35;color:rgba(245,245,245,0.62)}
.cc-caption[data-placeholder] .cc-services{color:#1a1a1a;background:#ffd84d;padding:0 4px;border-radius:3px;align-self:flex-start}
.hs:not([data-revealed]) .cc-caption{display:none}
@media (hover: none){.cc-caption{display:none}}
/* Pinned captions (data-hover-captions="card"): title above the hovered card, services below. */
.cc-pin{position:absolute;left:0;top:0;z-index:3;pointer-events:none;width:0;height:0}
.cc-pin > span{position:absolute;left:0;top:0;width:max-content;max-width:min(420px, 80vw);text-align:center;opacity:0;transition:opacity .3s ease,translate .45s cubic-bezier(.22,.61,.36,1)}
.cc-pin-top > span{transform:translate(-50%, calc(-100% - 18px));translate:0 8px}
.cc-pin-bottom > span{transform:translate(-50%, 18px);translate:0 -8px}
.cc-pin[data-show] > span{opacity:1;translate:0 0}
.cc-pin-top .cc-title{font-size:var(--t-accent)}
.cc-pin-bottom[data-placeholder] .cc-services{color:#1a1a1a;background:#ffd84d;padding:0 4px;border-radius:3px}
.hs:not([data-revealed]) .cc-pin{display:none}

[data-cylindrical-carousel][data-dragging] .gesture{cursor:grabbing}
[data-cylindrical-carousel] .controls{position:absolute;top:var(--controls-top, 86%);left:50%;z-index:3;display:flex;align-items:center;gap:16px;transform:translateX(-50%)}
[data-cylindrical-carousel] .controls button{display:grid;place-items:center;width:48px;height:48px;margin:0;padding:0;border:0;border-radius:50%;background:var(--carousel-control);color:inherit;font:inherit;cursor:pointer;transition:background 150ms,transform 150ms}
[data-cylindrical-carousel] .controls button:hover{background:var(--carousel-control-hover)}
[data-cylindrical-carousel] .controls button:active{transform:scale(.97)}
[data-cylindrical-carousel] .controls button:focus-visible{outline:2px solid var(--carousel-focus);outline-offset:4px}
[data-cylindrical-carousel] .controls svg{display:block;width:9px;height:15px;transform:translateX(1px)}
/* "View all" between the arrows: a pill in the same style and height as the buttons. */
[data-cylindrical-carousel] .controls .cc-all{display:inline-flex;align-items:center;height:48px;padding:0 22px;border-radius:999px;background:var(--carousel-control);color:inherit;font-size:var(--t-ui);font-weight:500;text-decoration:none;white-space:nowrap;transition:background 150ms,transform 150ms}
[data-cylindrical-carousel] .controls .cc-all:hover{background:var(--carousel-control-hover)}
[data-cylindrical-carousel] .controls .cc-all:active{transform:scale(.97)}
[data-cylindrical-carousel] .controls .cc-all:focus-visible{outline:2px solid var(--carousel-focus);outline-offset:4px}
[data-cylindrical-carousel] .controls .previous{transform:translateX(-1px) rotate(180deg)}
[data-cylindrical-carousel] .accessible{position:absolute;width:1px;height:1px;margin:0;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;pointer-events:none}
[data-cylindrical-carousel] .error{position:absolute;inset:45% 24px auto;margin:0;text-align:center;font-size:16px}
/* Image loading: a faint light runs across the empty frame, then the image fades in. Images
   already in the cache show at once. */
.lz::before{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;background:linear-gradient(100deg, transparent 30%, rgba(255,255,255,0.32) 50%, transparent 70%);background-size:220% 100%;animation:lzShine 1.5s linear infinite}
@keyframes lzShine{from{background-position:120% 0}to{background-position:-120% 0}}
img[data-fade]{opacity:0;transition:opacity .7s cubic-bezier(.22,.61,.36,1)}
img[data-fade][data-in]{opacity:1}
@media (prefers-reduced-motion:reduce){.lz::before{animation:none}img[data-fade]{transition:none}}
