
/* ============================================================
   MY10PRODUCTIONS — V4
   The mark is a rounded square. So everything is a tile,
   and the tiles have depth.
   ============================================================ */
:root{
  --black:#000;
  --panel:#08080A;
  --white:#F5F5F7;
  --grey:#86868B;
  --grey2:#8E8E93;
  --hair:rgba(245,245,247,.10);
  --red:#DE1B24;
  --red-hi:#FF3A32;
  --red-ink:#FF4238;   /* red for TEXT — the brand red fails contrast at body size */
  --gold:#C8A24A;      /* accent only: awards, marks of quality */
  --gold-ink:#E3C377;  /* gold for TEXT, contrast-safe on black */
  --lightbg:#F5F5F7;
  --lightink:#1D1D1F;
  --lightgrey:#6E6E73;
  --e:cubic-bezier(.16,1,.3,1);
  --gut:3.281rem;
  /* fluid, so a 4K display gets a full-width layout instead of a
     1240px column marooned in the middle */
  --maxw:min(90vw, 116rem);
  --navh:4.05rem;
  --brand-r:1.896rem;      /* the mark's radius */
  --tile-r:1.094rem;       /* small tiles */
  /* the glass recipe, defined once */
  --glass:linear-gradient(150deg,rgba(255,255,255,.11),rgba(255,255,255,.025) 46%,rgba(255,255,255,.06));
  --glass-edge:inset 0 1px 0 rgba(255,255,255,.20), inset 0 -1px 0 rgba(255,255,255,.05);
  --lift:0 30px 70px rgba(0,0,0,.55), 0 8px 20px rgba(0,0,0,.4);
}
*,*::before,*::after{box-sizing:border-box}
/* scroll-behavior is deliberately NOT smooth here — the virtual scroller
   below owns easing, and the two fight each other if both are on */
html{-webkit-text-size-adjust:100%;
  /* THE GLOBAL SCALE. Every length in this sheet is rem, so this one line
     sizes the entire site. 15.5px up to ~1210w, then rising to 23.8px at
     ~3160w, where it holds. The slope is 85% of what it was — the whole UI
     was reading oversized on a laptop — while the floor stays near 16px so
     phones don't drop below a comfortable reading size.
     To nudge the whole site: scale the vw and px terms together, not the
     floor on its own, or big displays stop scaling with the window.
     NOTE: must be px/vw — a rem value here resolves against the browser's
     initial 16px, not against itself, which silently shrinks the whole page. */
  font-size:clamp(15.5px, 0.427vw + 10.32px, 23.8px)}
body{
  margin:0;background:var(--black);color:var(--white);
  overflow-anchor:none;
  font-family:"Inter",-apple-system,BlinkMacSystemFont,"SF Pro Display","Segoe UI",sans-serif;
  font-size:1rem;line-height:1.52;letter-spacing:-.011em;
  overflow-x:hidden;-webkit-font-smoothing:antialiased;
  /* Inter v4 carries an optical-size axis — let the browser use it, so
     display sizes get tighter apertures and text sizes stay open */
  font-optical-sizing:auto;
  font-synthesis-weight:none;
}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
:focus-visible{outline:2px solid var(--red);outline-offset:4px;border-radius:3px}

h1,h2,h3{margin:0;font-weight:600;text-wrap:balance}
/* Optical tracking: Inter needs progressively tighter spacing as it gets
   larger, and progressively looser leading as it gets smaller. One value
   for all three was wrong at both ends. */
.h-xl{font-size:min(5.7rem,12.5vw);line-height:.9;letter-spacing:-.05em}
.h-lg{font-size:min(4.8rem,10.5vw);line-height:.95;letter-spacing:-.045em}
.h-md{font-size:min(2.395rem,7.6vw);line-height:1.09;letter-spacing:-.03em}
/* every small-caps label shares one set of values */
.eyebrow,.chapter,.crd dt,.pre-cap,.navmid,.bignav .mi,.card .num,.mock .row span{
  font-weight:500;letter-spacing:.15em;line-height:1.3}
.eyebrow{color:var(--red-ink);font-size:.8125rem;text-transform:uppercase;margin:0 0 .75rem}
.body{color:var(--grey);font-size:1.0625rem;line-height:1.52;letter-spacing:-.011em;
  text-wrap:pretty}
.small{font-size:.8125rem;color:var(--grey2);letter-spacing:0}

.lnk{color:var(--red-ink);font-size:1.0625rem;display:inline-flex;align-items:center;gap:.28em;
  transition:opacity .3s var(--e)}
.lnk:hover{opacity:.72}
.lnk i{font-style:normal;transition:transform .35s var(--e)}
.lnk:hover i{transform:translateX(3px)}
.links{display:flex;flex-wrap:wrap;gap:1.75rem;margin-top:2rem}

.btn{display:inline-flex;align-items:center;justify-content:center;
  background:var(--red);color:#fff;font-size:1rem;font-weight:500;letter-spacing:-.011em;
  padding:.8rem 1.5rem;border-radius:980px;border:0;cursor:pointer;
  transition:background .3s var(--e),transform .3s var(--e),box-shadow .3s var(--e)}
.btn:hover{background:var(--red-hi);box-shadow:0 10px 30px rgba(222,27,36,.35)}
.btn:active{transform:scale(.985)}
/* --red is a surface colour; as text on black it measures 4.12:1, under
   the 4.5 minimum. --red-ink is the same hue tuned for text (6.09:1). */
.btn.ghost{background:transparent;color:var(--red-ink);
  box-shadow:inset 0 0 0 1px currentColor}
.btn.ghost:hover{background:rgba(222,27,36,.10);box-shadow:inset 0 0 0 1px currentColor}
.btn.glass{background:var(--glass);color:var(--white);
  box-shadow:var(--glass-edge),0 8px 24px rgba(0,0,0,.4);
  border:1px solid rgba(255,255,255,.14);backdrop-filter:blur(16px) saturate(150%)}
.btn.glass:hover{background:linear-gradient(150deg,rgba(255,255,255,.18),rgba(255,255,255,.06))}

.skip{position:fixed;top:.75rem;left:.75rem;z-index:400;
  padding:.7rem 1.1rem;border-radius:999px;background:var(--red);color:#fff;
  font-size:.875rem;font-weight:500;transform:translateY(-160%);
  transition:transform .3s var(--e)}
.skip:focus{transform:none}

/* ============================================================
   Cursor — a lerped ring that swells and names what it's over.
   Fine pointers only; touch keeps its own behaviour entirely.
   ============================================================ */
.cur{position:fixed;top:0;left:0;z-index:300;pointer-events:none;
  width:.86rem;height:.86rem;border-radius:50%;background:var(--white);
  mix-blend-mode:difference;display:grid;place-items:center;
  transform:translate3d(-50%,-50%,0);opacity:0;
  transition:width .45s var(--e),height .45s var(--e),background .45s var(--e),
             opacity .3s var(--e),mix-blend-mode 0s}
.cur.on{opacity:1}
.cur .lab{font-size:.6875rem;letter-spacing:.15em;text-transform:uppercase;
  color:#fff;opacity:0;transition:opacity .3s var(--e);white-space:nowrap}
.cur.hot{width:2.4rem;height:2.4rem;background:var(--red);mix-blend-mode:normal}
.cur.lab-on{width:5.6rem;height:5.6rem;background:var(--red);mix-blend-mode:normal}
.cur.lab-on .lab{opacity:1}
@media(hover:hover) and (pointer:fine){
  html.cursor-on,html.cursor-on *{cursor:none !important}
}
/* JS already gates this on pointer type; this is the belt to that braces,
   so a touch device can never paint a stray ring */
@media(hover:none),(pointer:coarse){ .cur{display:none} }

/* ============================================================
   Opening titles — doubles as cover while fonts and the hero
   film load, so the first frame is never half-built.
   ============================================================ */
.pre{position:fixed;inset:0;z-index:200;background:#000;display:grid;place-items:center;
  transition:transform 1.15s var(--e),opacity .6s var(--e)}
.pre.done{transform:translateY(-101%);pointer-events:none}
.pre-in{display:flex;flex-direction:column;align-items:center;gap:2rem;width:min(560px,80vw)}
.pre-in img{height:4.1rem;width:auto;opacity:.95}
.pre-num{font-size:min(5.225rem,10vw);font-weight:600;letter-spacing:-.05em;line-height:1;
  font-variant-numeric:tabular-nums;color:var(--white)}
.pre-num s{text-decoration:none;color:var(--red)}
.pre-bar{width:100%;height:1px;background:rgba(245,245,247,.14);overflow:hidden}
.pre-bar b{display:block;height:100%;width:100%;transform:scaleX(0);transform-origin:0 50%;
  background:var(--red)}
.pre-cap{font-size:.6875rem;letter-spacing:.15em;text-transform:uppercase;color:var(--grey2)}
/* nothing in the hero plays until the titles clear */
body.booting{overflow:hidden}
body.booting .tile .face,
body.booting .filmbed,
body.booting .filmbed .sheen,
body.booting .copy h1 .l > span,
body.booting .copy .body,
body.booting .copy .links{animation-play-state:paused}

/* ============================================================
   Chapter markers — the page is a reel, so each act is numbered
   ============================================================ */
.chapter{display:flex;align-items:center;gap:1rem;margin:0 0 1.5rem;
  font-size:.6875rem;letter-spacing:.15em;text-transform:uppercase;color:var(--grey2)}
.chapter b{color:var(--red-ink);font-weight:600;letter-spacing:.15em}
.chapter i{flex:1;height:1px;background:var(--hair);font-style:normal;max-width:8rem}

/* mask-slide link hover */
.ml{position:relative;display:inline-block;overflow:hidden;vertical-align:bottom}
.ml span{display:block;transition:transform .48s var(--e)}
.ml span+span{position:absolute;left:0;top:100%;color:var(--red-ink)}
.ml:hover span{transform:translateY(-100%)}

/* ============================================================
   Backdrop — slow drifting light, grain in front of it.
   Sits behind every dark section, which is why they're transparent.
   ============================================================ */
.bg{position:fixed;inset:0;z-index:0;pointer-events:none;overflow:hidden;background:#000}
.bg b{position:absolute;display:block;border-radius:50%;filter:blur(90px);
  mix-blend-mode:screen;will-change:transform}
.bg .b1{width:62vw;height:62vw;left:-14vw;top:-18vw;
  background:radial-gradient(closest-side,rgba(222,27,36,.42),transparent);
  animation:float1 34s ease-in-out infinite}
.bg .b2{width:54vw;height:54vw;right:-12vw;top:6vh;
  background:radial-gradient(closest-side,rgba(150,16,24,.40),transparent);
  animation:float2 44s ease-in-out infinite}
.bg .b3{width:70vw;height:70vw;left:18vw;bottom:-26vw;
  background:radial-gradient(closest-side,rgba(90,12,20,.44),transparent);
  animation:float3 52s ease-in-out infinite}
.bg .b4{width:36vw;height:36vw;left:42vw;top:34vh;
  background:radial-gradient(closest-side,rgba(200,162,74,.16),transparent);
  animation:float4 38s ease-in-out infinite}
@keyframes float1{0%,100%{transform:translate3d(0,0,0) scale(1)}
  50%{transform:translate3d(12vw,10vh,0) scale(1.18)}}
@keyframes float2{0%,100%{transform:translate3d(0,0,0) scale(1.1)}
  50%{transform:translate3d(-14vw,16vh,0) scale(.9)}}
@keyframes float3{0%,100%{transform:translate3d(0,0,0) scale(1)}
  50%{transform:translate3d(-10vw,-12vh,0) scale(1.22)}}
@keyframes float4{0%,100%{transform:translate3d(0,0,0) scale(.9);opacity:.7}
  50%{transform:translate3d(16vw,-14vh,0) scale(1.3);opacity:1}}
/* keeps the gradients from banding, and gives the whole thing a film grain */
.noise{position:fixed;inset:0;z-index:1;pointer-events:none;opacity:.055;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='4' stitchTiles='stitch'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>")}
/* scroll progress */
.prog{position:fixed;top:0;left:0;right:0;height:2px;z-index:90;pointer-events:none}
.prog b{display:block;height:100%;width:100%;transform:scaleX(0);transform-origin:0 50%;
  background:linear-gradient(90deg,rgba(222,27,36,.35),var(--red),var(--red-hi))}

/* ============================================================
   Nav
   ============================================================ */
.nav{position:fixed;top:0;left:0;right:0;z-index:90;height:var(--navh);
  display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:1.5rem;
  padding:0 var(--gut);
  transition:background .5s var(--e),backdrop-filter .5s var(--e),transform .55s var(--e)}
.nav.solid{background:rgba(0,0,0,.55);backdrop-filter:saturate(180%) blur(22px)}
.nav.hide{transform:translateY(-104%)}
.nav .mark{justify-self:start;display:flex;align-items:center;min-width:0}
/* the wordmark carries the brand in the bar — it was reading as a caption
   at 1.385rem. Sized in rem so it rides the global scale. */
.nav .mark img{height:2.42rem;width:auto}
.navmid{justify-self:center;display:flex;align-items:center;gap:.7rem;
  font-size:0.5987rem;letter-spacing:.15em;
  text-transform:uppercase;color:var(--grey2)}
.navmid i{width:8px;height:8px;border-radius:50%;background:var(--red);
  box-shadow:0 0 10px var(--red)}
.menubtn{justify-self:end;display:flex;align-items:center;gap:0.7291rem;
  background:none;border:0;color:var(--white);cursor:pointer;padding:.4rem 0;
  font-size:0.8165rem;font-weight:500;letter-spacing:-.011em;
  font-family:inherit}
.menubtn .bars{display:grid;gap:0.3281rem;width:1.75rem}
.menubtn .bars i{display:block;height:2px;background:var(--white);border-radius:2px;
  transition:transform .5s var(--e),opacity .4s var(--e)}
body.menu-open .menubtn .bars i:first-child{transform:translateY(0.2333rem) rotate(45deg)}
body.menu-open .menubtn .bars i:last-child{transform:translateY(-0.2333rem) rotate(-45deg)}

/* ============================================================
   FULLSCREEN MENU — the whole navigation is one typographic screen,
   with the reel playing alongside it as artwork.

   Sizing note: the item size is capped against svh as well as rem and
   vw. Sized on font alone, seven items plus the footer overflowed any
   window under ~760px tall — a 1280x720 laptop scrolled.

   Animation note: both ends of the reveal are expressed in the same unit.
   Going from inset(0 0 100% 0) to inset(0 0 0 0) mixes % and px, which
   leans on calc() interpolation for no reason.
   ============================================================ */
.mobmenu{position:fixed;inset:0;z-index:85;background:rgba(6,4,5,.92);
  backdrop-filter:blur(26px) saturate(160%);
  display:flex;flex-direction:column;justify-content:center;
  padding:calc(var(--navh) + 2.2vh) var(--gut) 3vh;
  padding:calc(var(--navh) + 2.2svh) var(--gut) 3svh;
  clip-path:inset(0% 0% 100% 0%);pointer-events:none;
  visibility:hidden;
  transition:clip-path .8s var(--e),visibility 0s .8s}
.mobmenu.open{clip-path:inset(0% 0% 0% 0%);pointer-events:auto;
  visibility:visible;transition:clip-path .8s var(--e),visibility 0s}

.menuwrap{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.62fr);
  align-items:center;gap:clamp(2rem,5vw,5.5rem);
  max-width:var(--maxw);margin:0 auto;width:100%}

.bignav{--mi:min(4.35rem,8.4vw,6.4vh);--mi:min(4.35rem,8.4vw,6.4svh);
  display:flex;flex-direction:column;min-width:0}
.bignav a{display:grid;grid-template-columns:clamp(1.9rem,2.8vw,2.7rem) minmax(0,1fr);
  align-items:start;column-gap:clamp(.75rem,1.3vw,1.35rem);
  padding:clamp(.18rem,.85vh,.72rem) 0;
  padding:clamp(.18rem,.85svh,.72rem) 0;position:relative;font-size:var(--mi);
  opacity:0;transform:translateY(40px);
  transition:opacity .7s var(--e),transform .7s var(--e),color .4s var(--e)}
.mobmenu.open .bignav a{opacity:1;transform:none}
.mobmenu.open .bignav a:nth-child(1){transition-delay:.14s}
.mobmenu.open .bignav a:nth-child(2){transition-delay:.20s}
.mobmenu.open .bignav a:nth-child(3){transition-delay:.26s}
.mobmenu.open .bignav a:nth-child(4){transition-delay:.32s}
.mobmenu.open .bignav a:nth-child(5){transition-delay:.38s}
.mobmenu.open .bignav a:nth-child(6){transition-delay:.44s}
.mobmenu.open .bignav a:nth-child(7){transition-delay:.50s}
/* the index rides the cap height of the word, not its baseline — on a
   70px word a baseline-aligned 11px number reads as floating loose */
.bignav .mi{font-size:.66rem;letter-spacing:.15em;color:var(--grey2);
  line-height:1;margin-top:calc(var(--mi) * .255);
  transition:color .4s var(--e),transform .5s var(--e)}
.bignav .mt{font-size:1em;font-weight:600;letter-spacing:-.045em;
  line-height:.98;display:block;
  transition:transform .5s var(--e)}
.bignav a:hover .mt,.bignav a:focus-visible .mt{transform:translateX(.85rem)}
.bignav a:hover .mi,.bignav a:focus-visible .mi{transform:translateX(.3rem)}
.bignav a:hover,.bignav a:focus-visible{color:var(--red-ink)}
.bignav a:hover .mi,.bignav a:focus-visible .mi{color:var(--red-ink)}
/* a hairline that draws itself under the item being pointed at */
.bignav a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;
  background:linear-gradient(90deg,var(--red),rgba(222,27,36,0));
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform .55s var(--e)}
.bignav a:hover::after,.bignav a:focus-visible::after{transform:scaleX(1)}

/* the reel, playing beside the list */
.menuprev{min-width:0;opacity:0;transform:translateY(24px);
  transition:opacity .9s .42s var(--e),transform .9s .42s var(--e)}
.mobmenu.open .menuprev{opacity:1;transform:none}
.mp-media{position:relative;width:100%;aspect-ratio:4/3;
  border-radius:var(--brand-r);box-shadow:var(--lift);
  /* clipped, so the turning marks are cropped by the panel rather than
     wandering out over the menu behind it */
  overflow:hidden;isolation:isolate;
  background:radial-gradient(120% 90% at 50% 45%,rgba(222,27,36,.22),transparent 64%),
             linear-gradient(160deg,#120c0d,#060505)}
.mp-frame{position:absolute;inset:.55rem;border-radius:calc(var(--brand-r) * .82);
  border:1px solid rgba(222,27,36,.55);pointer-events:none}

/* a faint crosshair behind the scenes, so the panel has an anchor */
.ma-rule{position:absolute;background:rgba(255,255,255,.09);pointer-events:none}
.ma-rule.v{left:50%;top:10%;bottom:10%;width:1px}
.ma-rule.h{top:50%;left:10%;right:10%;height:1px}
/* a beam that crosses the panel, like a projector sweep */
.ma-beam{position:absolute;top:-10%;bottom:-10%;width:34%;left:-40%;
  pointer-events:none;transform:skewX(-12deg);z-index:1;
  background:linear-gradient(90deg,transparent,rgba(222,27,36,.16) 45%,
             rgba(255,255,255,.05) 55%,transparent);
  animation:maSweep 8s var(--e) infinite}

/* ONE SCENE PER MENU ITEM
   A numeral alone said nothing about where a link goes. Each item now has a
   drawn scene that animates on its own; pointing at the item brings its
   scene forward. Stacked in the same grid cell and crossfaded. */
.sc{position:absolute;inset:8%;z-index:2;width:84%;height:84%;
  fill:none;stroke:rgba(245,245,247,.82);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;
  opacity:0;transform:scale(.96);pointer-events:none;
  transition:opacity .5s var(--e),transform .6s var(--e)}
.sc.on{opacity:1;transform:none}

/* 01 services — four disciplines, lighting in turn */
.s-quad rect{stroke:rgba(245,245,247,.55)}
.s-dot circle{stroke:none;fill:var(--red);animation:scFlash 3.2s ease-in-out infinite}
.s-dot circle:nth-child(2){animation-delay:.4s}
.s-dot circle:nth-child(3){animation-delay:1.2s}
.s-dot circle:nth-child(4){animation-delay:.8s}

/* 02 showreel — the ring fills as it plays */
.sc[data-sc="02"] .s-track{stroke:rgba(245,245,247,.22)}
.s-prog{stroke:var(--red);stroke-dasharray:176;stroke-dashoffset:176;
  transform:rotate(-90deg);transform-origin:60px 45px;
  animation:scProg 4.5s linear infinite}
.s-play{fill:rgba(245,245,247,.92);stroke:none}
.s-bars rect{fill:var(--gold);stroke:none;transform-origin:center;
  animation:scBars 1.1s ease-in-out infinite}
.s-bars rect:nth-child(2){animation-delay:.16s}
.s-bars rect:nth-child(3){animation-delay:.32s}
.s-bars rect:nth-child(4){animation-delay:.48s}

/* 03 how we work — a dot walking the four stages */
.sc[data-sc="03"] .s-track{stroke:rgba(245,245,247,.22)}
.s-nodes circle{fill:#0b0708;stroke:rgba(245,245,247,.5)}
.s-run{fill:var(--red);stroke:none;animation:scRun 5.2s var(--e) infinite}
.s-ticks line{stroke:rgba(245,245,247,.28);stroke-width:1.5}

/* 04 work — frames filling in */
.s-grid rect{stroke:rgba(245,245,247,.42);fill:rgba(222,27,36,0);
  animation:scFill 5.4s ease-in-out infinite}
.s-grid rect:nth-child(2){animation-delay:.3s}
.s-grid rect:nth-child(3){animation-delay:.6s}
.s-grid rect:nth-child(4){animation-delay:.9s}
.s-grid rect:nth-child(5){animation-delay:1.2s}
.s-grid rect:nth-child(6){animation-delay:1.5s}

/* 05 studio — the camera on sticks */
.s-body{fill:rgba(245,245,247,.06)}
.s-lens{fill:rgba(222,27,36,.20)}
.s-rec{fill:var(--red);stroke:none;animation:scFlash 1.8s ease-in-out infinite}
.s-legs line{stroke:rgba(245,245,247,.5)}

/* 06 details — the spec writing itself, then signed off */
.s-page{fill:rgba(245,245,247,.04);stroke:rgba(245,245,247,.42)}
.s-lines line{stroke:rgba(245,245,247,.5);stroke-dasharray:60;
  stroke-dashoffset:60;animation:scDraw 5s ease-in-out infinite}
.s-lines line:nth-child(2){animation-delay:.25s}
.s-lines line:nth-child(3){animation-delay:.5s}
.s-lines line:nth-child(4){animation-delay:.75s}
.s-tick{stroke:var(--gold);stroke-width:3;stroke-dasharray:44;
  stroke-dashoffset:44;animation:scDraw 5s ease-in-out 1.3s infinite}

/* 07 portal — the dashboard coming up */
.s-win{fill:rgba(245,245,247,.04);stroke:rgba(245,245,247,.45)}
.s-bar{stroke:rgba(245,245,247,.30)}
.s-pips circle{fill:rgba(245,245,247,.35);stroke:none}
.s-pips circle:first-child{fill:var(--red)}
.s-blocks rect{stroke:none;fill:rgba(245,245,247,.16);
  animation:scBlock 4.4s ease-in-out infinite}
.s-blocks rect:nth-child(2){animation-delay:.3s}
.s-blocks rect:nth-child(3){animation-delay:.6s}

@keyframes maSweep{0%{left:-40%}55%,100%{left:104%}}
@keyframes scFlash{0%,100%{opacity:.25}50%{opacity:1}}
@keyframes scProg{to{stroke-dashoffset:0}}
@keyframes scBars{0%,100%{transform:scaleY(.5)}50%{transform:scaleY(1)}}
@keyframes scRun{0%{transform:translateX(0)}
  20%,28%{transform:translateX(28px)}
  48%,56%{transform:translateX(56px)}
  76%,100%{transform:translateX(84px)}}
@keyframes scFill{0%,100%{fill:rgba(222,27,36,0)}45%{fill:rgba(222,27,36,.55)}}
@keyframes scDraw{0%{stroke-dashoffset:60}30%,100%{stroke-dashoffset:0}}
@keyframes scBlock{0%,100%{fill:rgba(245,245,247,.10)}
  50%{fill:rgba(222,27,36,.45)}}
.mp-note{margin:1.05rem 0 0;font-size:.8165rem;color:var(--grey);
  letter-spacing:-.005em;transition:opacity .3s var(--e)}
.mp-note.swap{opacity:0}

.menufoot{display:flex;flex-wrap:wrap;align-items:center;gap:1.2rem 2.5rem;
  max-width:var(--maxw);margin:clamp(1.4rem,3.4vh,3.4rem) auto 0;width:100%;
  margin:clamp(1.4rem,3.4svh,3.4rem) auto 0;
  padding-top:clamp(1rem,2.2vh,2rem);padding-top:clamp(1rem,2.2svh,2rem);border-top:1px solid var(--hair);
  font-size:0.8165rem;color:var(--grey);
  opacity:0;transform:translateY(18px);
  transition:opacity .8s .56s var(--e),transform .8s .56s var(--e)}
.mobmenu.open .menufoot{opacity:1;transform:none}
.menusoc{display:flex;gap:1.5rem;margin-right:auto}

/* under 1024 the preview is dropped and the list gets the full width */
@media (max-width:1023px){
  .menuwrap{grid-template-columns:1fr}
  .menuprev{display:none}
  .bignav{--mi:min(4.6rem,11vw,7.4vh);--mi:min(4.6rem,11vw,7.4svh)}
}

/* ============================================================
   HERO — the 3D tile scene
   ============================================================ */
.hero{position:relative;z-index:10;min-height:100vh;min-height:100svh;display:grid;place-items:center;
  padding:calc(var(--navh) + 2rem) var(--gut) 4rem;overflow:hidden;isolation:isolate}
/* ambient red light behind everything */
.hero::before{content:"";position:absolute;left:50%;top:50%;width:min(80rem,150%);height:min(60rem,120%);
  transform:translate(-50%,-50%);pointer-events:none;z-index:0;
  background:radial-gradient(closest-side,rgba(222,27,36,.20),rgba(222,27,36,.05) 55%,transparent)}

.scene{position:relative;z-index:5;width:100%;max-width:min(92vw,100rem);
  display:grid;place-items:center;
  perspective:1700px;perspective-origin:50% 46%}

/* the depth layer — everything in here shares one 3D space */
.stack3d{position:absolute;inset:-8% -2%;transform-style:preserve-3d;pointer-events:none;
  will-change:transform}

.tile{position:absolute;left:calc(50% + var(--x));top:calc(50% + var(--y));
  width:var(--s);aspect-ratio:1;border-radius:var(--tile-r);
  transform:translate3d(-50%,-50%,var(--z));transform-style:preserve-3d;
  pointer-events:auto;cursor:pointer;text-decoration:none}
/* .face owns the animation (transform), .inner owns the look and the hover
   lift — one element can't do both without them overwriting each other */
.tile .face{position:absolute;inset:0;border-radius:inherit;opacity:0;
  animation:tileIn 1.25s var(--d,0s) var(--e) both,
            drift var(--dur,11s) calc(var(--d,0s) + 1.3s) ease-in-out infinite}
.tile .inner{position:absolute;inset:0;border-radius:inherit;overflow:hidden;
  background:var(--glass);border:1px solid rgba(255,255,255,.13);
  box-shadow:var(--glass-edge),var(--lift);
  transition:transform .55s var(--e),border-color .45s var(--e),box-shadow .55s var(--e)}
.tile .inner::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(135deg,rgba(255,255,255,.22),transparent 42%)}
.tile:not(.deco):hover .inner,.tile:not(.deco):focus-visible .inner{transform:translateY(-9px) scale(1.05);
  border-color:rgba(222,27,36,.85);
  box-shadow:var(--glass-edge),0 40px 90px rgba(222,27,36,.30),0 14px 30px rgba(0,0,0,.55)}
.tile.red .inner{border-color:rgba(222,27,36,.55);
  background:linear-gradient(150deg,rgba(222,27,36,.24),rgba(222,27,36,.05) 55%,rgba(255,255,255,.05))}
.tile.blur .inner{backdrop-filter:blur(20px) saturate(150%)}
.tile img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:brightness(.62) saturate(.85);transition:filter .55s var(--e)}
.tile:not(.deco):hover img{filter:brightness(.9) saturate(1)}
/* the label is the point — it says what the tile is for */
.tile .lab{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:.55rem .6rem;font-size:.6875rem;font-weight:500;line-height:1.3;
  letter-spacing:-.011em;color:rgba(245,245,247,.92);
  background:linear-gradient(transparent,rgba(0,0,0,.8))}
/* decoration only — no label, no link, and never in the way of a real tile */
.tile.deco{pointer-events:none;cursor:default}
.tile.solid .inner{border-color:rgba(255,96,88,.55);
  background:linear-gradient(150deg,rgba(222,27,36,.92),rgba(150,12,20,.55) 60%,rgba(222,27,36,.35));
  box-shadow:var(--glass-edge),0 30px 70px rgba(222,27,36,.35)}
.tile.goldtile .inner{border-color:rgba(200,162,74,.6);
  background:linear-gradient(150deg,rgba(200,162,74,.26),rgba(140,110,40,.06) 55%,rgba(255,255,255,.05));
  box-shadow:var(--glass-edge),0 30px 70px rgba(200,162,74,.24)}
.tile.outline .inner{background:rgba(255,255,255,.015);border-color:rgba(245,245,247,.24);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.14)}
.tile.outline.red .inner{border-color:rgba(222,27,36,.7);
  box-shadow:inset 0 1px 0 rgba(255,120,110,.18),0 20px 50px rgba(222,27,36,.14)}
.tile.wide{aspect-ratio:16/10}
.tile.tall{aspect-ratio:3/4}

@keyframes tileIn{
  0%{opacity:0;transform:translateY(46px) scale(.86)}
  100%{opacity:1;transform:none}}
@keyframes drift{
  0%,100%{transform:none}
  50%{transform:translateY(-14px)}}

/* the screen — the mark, with the film inside it */
/* width is also capped by viewport HEIGHT: at 16/10 a width of 104svh is
   65svh tall, so the hero fills a tall window instead of floating in it */
/* THE FILM IS THE PAGE.
   It fills the viewport edge to edge instead of sitting in a box, and the
   brand's rounded square becomes the frame around the whole screen rather
   than a small rectangle in the middle of it. */
.filmbed{position:absolute;inset:0;z-index:1;overflow:hidden;
  clip-path:inset(0 round 0);
  animation:bedIn 2.1s .05s var(--e) both;will-change:clip-path}
@keyframes bedIn{
  0%  {clip-path:inset(33% 37% round 4rem);opacity:0}
  14% {opacity:1}
  100%{clip-path:inset(0 round 0);opacity:1}}
/* the mark, holding the entire viewport */
.markframe{position:absolute;inset:1.1rem;z-index:4;pointer-events:none;
  border:1px solid rgba(222,27,36,.72);border-radius:var(--brand-r);
  box-shadow:0 0 60px rgba(222,27,36,.22),inset 0 0 90px rgba(222,27,36,.10);
  opacity:0;animation:frameUp 1.1s 1.5s var(--e) forwards}
@keyframes frameUp{to{opacity:1}}
@keyframes screenIn{
  0%{opacity:0;clip-path:inset(40% 44% round 80px);transform:scale(.97)}
  60%{opacity:1}
  100%{opacity:1;clip-path:inset(0% 0% round var(--brand-r));transform:none}}
.filmbed video,.filmbed .alt{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.filmbed .alt{opacity:0;transform:scale(1.05);z-index:1;
  transition:opacity .7s var(--e),transform 1.4s var(--e)}
.filmbed .alt.on{opacity:1;transform:scale(1)}
.now{position:absolute;left:0;bottom:0;z-index:4;display:flex;align-items:center;gap:.5rem;
  margin:1.393rem;padding:.5rem .85rem;border-radius:999px;
  background:rgba(0,0,0,.42);border:1px solid rgba(255,255,255,.14);
  backdrop-filter:blur(14px) saturate(150%);
  font-size:.75rem;color:rgba(245,245,247,.92);white-space:nowrap;
  opacity:0;transform:translateY(8px);transition:opacity .45s var(--e),transform .45s var(--e)}
.now.on{opacity:1;transform:none}
.now u{width:6px;height:6px;border-radius:50%;background:var(--red);text-decoration:none;
  box-shadow:0 0 10px var(--red)}
.filmbed .grade{position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(0,0,0,.42),rgba(0,0,0,.30) 40%,rgba(0,0,0,.72)),
             radial-gradient(60% 55% at 50% 50%,rgba(0,0,0,.55),transparent 75%)}
.filmbed .tint{position:absolute;inset:0;mix-blend-mode:screen;
  background:radial-gradient(60% 60% at 50% 55%,rgba(222,27,36,.16),transparent 70%)}
/* glass sheen that sweeps once the screen has opened */
.filmbed .sheen{position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(115deg,transparent 30%,rgba(255,255,255,.16) 46%,transparent 62%);
  transform:translateX(-120%);animation:sweep 1.5s 1.5s var(--e) both}
@keyframes sweep{to{transform:translateX(120%)}}

/* copy sits outside the 3D layer so the type stays perfectly sharp */
.copy{position:relative;z-index:6;grid-area:1/1;text-align:center;
  padding:2.613rem;max-width:min(64rem,78vw);
  transform-style:preserve-3d;will-change:transform}
.copy h1{margin-bottom:1.25rem;transform-style:preserve-3d}
/* .l holds the depth (static), the inner span holds the entrance animation —
   one element can't own both without the animation eating the translateZ */
.copy h1 .l{display:block;transform:translateZ(var(--lz,0));transform-style:preserve-3d;
  backface-visibility:hidden}
.copy h1 .l.red{color:var(--red)}
.copy h1 .l > span{display:inline-block;opacity:0;transform:translateY(26px);
  animation:rise 1.3s var(--e) forwards;
  text-shadow:0 6px 44px rgba(0,0,0,.85),0 2px 12px rgba(0,0,0,.6)}
.copy h1 .l:nth-child(1) > span{animation-delay:.55s}
.copy h1 .l:nth-child(2) > span{animation-delay:.66s}
.copy h1 .l:nth-child(3) > span{animation-delay:.77s}
.copy .body{max-width:33rem;margin:0 auto;color:#C6C9CE;transform:translateZ(20px);
  text-shadow:0 2px 20px rgba(0,0,0,.85);opacity:0;animation:rise 1.3s .92s var(--e) forwards}
.copy .links{justify-content:center;transform:translateZ(20px);
  opacity:0;animation:rise 1.3s 1.04s var(--e) forwards}
@keyframes rise{to{opacity:1;transform:translateY(0)}}
.hint{position:absolute;left:50%;bottom:1.75rem;transform:translateX(-50%);z-index:10;
  font-size:.75rem;color:var(--grey2);transition:opacity .6s var(--e)}

/* ============================================================
   Sections
   ============================================================ */
.sec{position:relative;z-index:10;padding:5.742rem var(--gut)}
.wrap{max-width:var(--maxw);margin:0 auto}
.narrow{max-width:min(60rem,80vw);margin:0 auto}

.statement{position:relative;z-index:10;height:180vh}
.statement .pin{position:sticky;top:0;height:100vh;height:100svh;display:flex;align-items:center;
  justify-content:center;padding:0 var(--gut);text-align:center}
.statement h2{max-width:20ch;font-size:min(5.4rem,11vw);letter-spacing:-.05em;line-height:.98}
.statement h2 w{display:inline-block;opacity:.12;filter:blur(3px);
  transform:perspective(800px) translateZ(-30px);
  transition:opacity .6s var(--e),filter .6s var(--e),transform .6s var(--e)}
.statement h2 w.on{opacity:1;filter:blur(0);transform:perspective(800px) translateZ(0)}
.statement h2 w.red.on{color:var(--red)}

/* services — the sticky tile */
.svc{position:relative;z-index:10}
.svc .grid{position:relative}
.svc .grid{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);gap:5rem;
  max-width:var(--maxw);margin:0 auto;padding:0 var(--gut);align-items:stretch}
.svc .media{position:relative}
.svc .mediainner{position:sticky;top:0;height:100vh;height:100svh;display:flex;align-items:center;
  perspective:1400px}
.svc .mediawrap{position:relative;width:100%}
/* the act number sits behind the image as an outline — scale without weight */
.svc .ghost{position:absolute;right:-.75rem;top:-3.8rem;z-index:2;pointer-events:none;
  font-size:11rem;font-weight:700;line-height:1;letter-spacing:-.06em;
  color:transparent;-webkit-text-stroke:1px rgba(255,255,255,.13);
  font-variant-numeric:tabular-nums}
/* caption under the frame, so the column reads as a plate not a floating box */
.svc .cap{position:relative;z-index:2;display:flex;align-items:center;gap:.85rem;
  margin:1.35rem 0 0;font-size:.8125rem;font-weight:500;letter-spacing:.15em;
  text-transform:uppercase;color:var(--grey2)}
.svc .cap i{display:block;width:2.25rem;height:1px;background:var(--red);flex:0 0 auto}
/* which of the four you're on */
.svcrail{position:absolute;right:1.25rem;top:50%;transform:translateY(-50%);z-index:12;
  display:flex;flex-direction:column;gap:.75rem;margin:0;padding:0;list-style:none}
.svcrail li{display:block;width:2px;height:2.25rem;border-radius:2px;
  background:rgba(245,245,247,.16);
  transition:background .6s var(--e),height .6s var(--e),box-shadow .6s var(--e)}
.svcrail li.on{background:var(--red);height:4rem;box-shadow:0 0 16px rgba(222,27,36,.7)}
/* capability chips */
.chips{display:flex;flex-wrap:wrap;gap:.5rem;margin:1.6rem 0 0;padding:0;list-style:none}
.chips li{font-size:.8125rem;letter-spacing:-.005em;color:var(--grey);
  padding:.45rem .85rem;border-radius:999px;
  border:1px solid rgba(255,255,255,.13);background:rgba(255,255,255,.045)}
/* 4:5, so a width of 52svh stands 65svh tall — the frame grows with the
   window's height as well as its width, and never overflows a short one */
.svc .stack{position:relative;z-index:1;width:min(100%,36rem,52vh);width:min(100%,36rem,52svh);margin-inline:auto;
  aspect-ratio:4/5;border-radius:var(--brand-r);
  overflow:hidden;background:var(--panel);
  border:1px solid rgba(222,27,36,.55);
  box-shadow:0 0 0 1px rgba(222,27,36,.14),
             0 0 34px rgba(222,27,36,.30),
             0 0 90px rgba(222,27,36,.16),
             0 30px 70px rgba(0,0,0,.6),
             var(--glass-edge);
  animation:frameglow 6.5s ease-in-out infinite;
  /* --ry is driven by scroll: +ve on the first panel, -ve on the last,
     so the panel turns through the section like a slow reveal */
  transform:perspective(1500px) rotateY(var(--ry,14deg)) rotateX(var(--rx,2deg))
            translateZ(var(--rz,0px));
  transform-style:preserve-3d}
/* if a source blocks hotlinking, alt text otherwise sprawls across the frame */
.svc .stack img,.tile img,.card img,.studio img{color:transparent;font-size:0}
/* a blocked or missing source leaves a considered surface, not a broken icon */
img.failed{opacity:0}
.imgfail{position:relative}
.imgfail::after{content:"";position:absolute;inset:0;border-radius:inherit;
  background:linear-gradient(140deg,rgba(222,27,36,.16),rgba(255,255,255,.05) 55%,rgba(0,0,0,.4));
  pointer-events:none}
.svc .stack img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transform:scale(1.07);
  transition:opacity 1s var(--e),transform 1.8s var(--e);filter:brightness(.84) saturate(.9)}
.svc .stack img.on{opacity:1;transform:scale(1)}
/* video sits over the still; the still stays as the poster underneath */
.svid{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:2;
  opacity:0;transition:opacity .8s var(--e)}
.svid.on{opacity:1}
.svc .stack::after{content:"";position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  background:linear-gradient(135deg,rgba(255,255,255,.14),transparent 38%)}
.svc .panel{min-height:100vh;min-height:100svh;display:flex;flex-direction:column;justify-content:center;padding:6rem 0}
/* copy sits on its own translucent card so it can never crowd the image */
.svc .pcard{position:relative;max-width:min(100%,40rem);
  padding:3rem 2.8rem;
  border-radius:var(--brand-r);
  border:1px solid rgba(255,255,255,.09);
  background:linear-gradient(155deg,rgba(255,255,255,.062),rgba(255,255,255,.014) 55%,rgba(222,27,36,.05));
  box-shadow:var(--glass-edge),0 40px 100px rgba(0,0,0,.45),0 0 90px rgba(222,27,36,.07);
  backdrop-filter:blur(16px) saturate(140%)}
.svc .pcard::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(140deg,rgba(255,255,255,.11),transparent 40%)}
.svc .pcard > *{position:relative;z-index:1}
.svc .panel h3{margin-bottom:1.25rem}
.svc .panel .body{margin:0 0 1rem;max-width:46ch}

/* running band — outlined type, so it adds movement without adding weight */
.band{position:relative;z-index:10;overflow:hidden;padding:2.6rem 0;
  border-top:1px solid var(--hair);border-bottom:1px solid var(--hair);
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent)}
.bandtrack{display:flex;align-items:center;gap:3rem;width:max-content;
  animation:bandroll 46s linear infinite;will-change:transform}
.band:hover .bandtrack{animation-play-state:paused}
@keyframes bandroll{to{transform:translateX(-50%)}}
/* the frame breathes rather than sitting flat */
@keyframes frameglow{
  0%,100%{box-shadow:0 0 0 1px rgba(222,27,36,.14),0 0 34px rgba(222,27,36,.30),
          0 0 90px rgba(222,27,36,.16),0 30px 70px rgba(0,0,0,.6),var(--glass-edge)}
  50%{box-shadow:0 0 0 1px rgba(222,27,36,.22),0 0 52px rgba(222,27,36,.44),
      0 0 130px rgba(222,27,36,.24),0 30px 70px rgba(0,0,0,.6),var(--glass-edge)}}
.bandtrack span{font-size:3.4rem;font-weight:700;letter-spacing:-.045em;line-height:1;
  white-space:nowrap;color:transparent;-webkit-text-stroke:1px rgba(245,245,247,.30);
  transition:color .5s var(--e),-webkit-text-stroke-color .5s var(--e)}
.bandtrack span:nth-child(4n+2){-webkit-text-stroke-color:rgba(222,27,36,.75)}
.bandtrack span:nth-child(8n+6){-webkit-text-stroke-color:rgba(200,162,74,.8)}
.bandtrack i{width:.55rem;height:.55rem;border-radius:50%;background:var(--red);
  flex:0 0 auto;opacity:.8}
.band:hover .bandtrack span{color:rgba(245,245,247,.06)}

/* showreel tile, with a reflection under it */
/* the showreel is the single most important thing a production company owns —
   it gets the whole screen and its own scroll beat, not a box in a column */
.reel{position:relative;z-index:10;height:190vh}
.reelpin{position:sticky;top:0;height:100vh;height:100svh;overflow:hidden;background:#000}

.reelbox{position:absolute;inset:0;overflow:hidden;background:#000;
  transform:scale(var(--tscale,1));transform-origin:50% 50%}
.reelbox video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
/* The background loop fills the screen. It is a separate encode, already
   cropped to the reel's 2.39:1 picture, so `cover` here trims nothing that
   was not black bar — the frame is not being recomposed to fit. */
.reelbg{transition:opacity .6s var(--e)}
/* The reel itself is shown whole. `contain` inside a black pin means the
   letterboxing the reel was finished with is the only letterboxing there
   is — the site adds none of its own and crops none of it away. */
.reelfull{opacity:0;pointer-events:none;object-fit:contain!important;
  transition:opacity .6s var(--e)}
.reelbox .vp{position:absolute;inset:0;z-index:3;opacity:0;pointer-events:none;
  transition:opacity .6s var(--e)}
.reelbox .vp video{object-fit:contain}
.reelbox.playing .reelbg{opacity:0}
.reelbox.playing .reelfull,.reelbox.playing .vp{opacity:1;pointer-events:auto}
/* The frame mark sits above the background but below the player's bar, so
   it never swallows a click meant for the scrubber. */
.reelbox.playing .markframe{opacity:.35}
.plab{font-size:min(2.1rem,6vw);font-weight:600;letter-spacing:-.03em}
.psub{font-size:.9375rem;color:var(--grey);letter-spacing:.02em}
.reelbox .play{position:absolute;inset:0;width:100%;border:0;cursor:pointer;color:var(--white);
  background:linear-gradient(rgba(0,0,0,.12),rgba(0,0,0,.5));
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1rem;
  transition:opacity .6s var(--e)}
.reelbox .play .disc{width:82px;height:82px;border-radius:50%;
  background:var(--glass);border:1px solid rgba(255,255,255,.2);
  box-shadow:var(--glass-edge),0 12px 40px rgba(0,0,0,.5);
  backdrop-filter:blur(16px) saturate(160%);display:grid;place-items:center;
  transition:transform .5s var(--e),background .5s var(--e)}
.reelbox .play:hover .disc{transform:scale(1.08);background:var(--red);border-color:var(--red)}
.reelbox .play .disc::after{content:"";margin-left:5px;
  border-left:17px solid #fff;border-top:11px solid transparent;border-bottom:11px solid transparent}
.reelbox.playing .play{opacity:0;pointer-events:none}


.studio{display:grid;grid-template-columns:minmax(0,.62fr) minmax(0,1.38fr);
  gap:3.646rem;align-items:center}
.studio figure{margin:0;border-radius:var(--brand-r);overflow:hidden;background:var(--panel);
  border:1px solid rgba(255,255,255,.10);box-shadow:var(--glass-edge),0 40px 90px rgba(0,0,0,.6);
  position:relative}
.studio figure::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(135deg,rgba(255,255,255,.13),transparent 40%)}
.studio figure{perspective:1200px;aspect-ratio:5/7;overflow:hidden;
  width:min(100%,23rem);margin-inline:auto}
.studio img{width:100%;height:100%;object-fit:cover;object-position:50% 18%;
  filter:none;transform:scale(1.03) translateY(var(--py,0px));will-change:transform}
.studio p{margin:0 0 1.25rem}

.specs{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:2.613rem;border-top:1px solid var(--hair);padding-top:2.5rem;margin-top:3.5rem}
.specs b.odo,.odo{display:inline-flex;line-height:1;height:1em;
  overflow:hidden;vertical-align:bottom}
.odo .dg,.odo .dgi,.odo .dgi > span{color:inherit;font-size:inherit;margin:0;max-width:none}
.dg{display:block;height:1em;overflow:hidden}
.dgi{display:block;transform:translateY(0);
  transition:transform 1.9s cubic-bezier(.16,1,.3,1)}
.dgi > span{display:block;height:1em;line-height:1;text-align:center}
.specs b,.step .sn,.pre-num,.card .num,.bignav .mi,.chapter b{
  font-variant-numeric:tabular-nums;font-feature-settings:"tnum" 1}
.specs b{display:block;font-size:min(2.83rem,8.4vw);font-weight:600;letter-spacing:-.045em;
  line-height:1;color:var(--red-ink)}
.specs > div{padding-left:1.25rem;border-left:1px solid var(--hair)}
.specs > div.gold b{color:var(--gold-ink)}
.specs > div.gold{border-left-color:rgba(200,162,74,.4)}
.specs > div:first-child{padding-left:0;border-left:0}
.specs > div > span{display:block;margin-top:.6rem;color:var(--grey);font-size:.9375rem;
  text-wrap:balance;max-width:14ch}

.quotesec{padding-top:clamp(3rem,10vh,9rem);padding-bottom:clamp(3rem,10vh,9rem)}
.quote{position:relative;overflow:hidden;text-align:left;margin:0 auto;
  max-width:min(62rem,90vw);
  padding:3.4rem 3.2rem 3rem;
  border-radius:var(--brand-r);
  border:1px solid rgba(255,255,255,.09);
  background:linear-gradient(150deg,rgba(222,27,36,.30),rgba(150,18,26,.20) 45%,rgba(60,10,14,.28));
  box-shadow:var(--glass-edge),0 40px 110px rgba(0,0,0,.5),0 0 130px rgba(200,162,74,.10)}
/* warm light pooling in from the lower left, as in the reference */
.quote::before{content:"";position:absolute;left:-8%;bottom:-42%;width:70%;height:90%;
  pointer-events:none;border-radius:50%;filter:blur(60px);
  background:radial-gradient(closest-side,rgba(200,162,74,.55),rgba(200,162,74,.12) 60%,transparent)}
.quote::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(140deg,rgba(255,255,255,.10),transparent 38%)}
.quote blockquote{position:relative;z-index:1;margin:0;text-wrap:pretty;
  font-size:min(2.1rem,5.6vw);font-weight:500;letter-spacing:-.022em;line-height:1.28;
  color:#E7E4E2}
/* the mark sits under the words, not over them */
.qmark{position:relative;z-index:1;display:block;margin:1.6rem 0 0;
  font-size:min(4.4rem,12vw);line-height:.55;color:var(--gold);opacity:.95;
  font-weight:700;pointer-events:none}
.quote figcaption{position:relative;z-index:1;margin-top:2.6rem;
  display:flex;flex-direction:column;gap:.25rem}
.quote figcaption b{font-size:1.35rem;font-weight:600;letter-spacing:-.025em;color:var(--white)}
.quote figcaption em{font-style:normal;font-size:1rem;color:var(--grey)}

/* work — a pinned horizontal sequence, driven by vertical scroll */
.hwork{position:relative;z-index:10}
.hpin{position:sticky;top:0;height:100vh;height:100svh;display:flex;flex-direction:column;
  justify-content:center;overflow:hidden;gap:clamp(1.25rem,3vh,2.5rem)}
.hhead{padding:0 var(--gut);max-width:var(--maxw);margin:0 auto;width:100%}
.htrack{display:flex;gap:1.742rem;padding:0 var(--gut);
  width:max-content;will-change:transform}
.work{display:contents}
.card{position:relative;border-radius:var(--brand-r);overflow:hidden;
  height:min(62vh,34rem);height:min(62svh,34rem);width:auto;aspect-ratio:4/3;flex:0 0 auto;
  background:var(--panel);display:block;
  border:1px solid rgba(255,255,255,.10);
  box-shadow:var(--glass-edge),0 30px 70px rgba(0,0,0,.55);
  transition:box-shadow .6s var(--e)}
.card .num{position:absolute;left:0;top:0;z-index:3;padding:1rem 1.25rem;
  font-size:.75rem;letter-spacing:.15em;color:rgba(245,245,247,.75)}
.card:hover{box-shadow:var(--glass-edge),0 44px 100px rgba(222,27,36,.20),0 30px 70px rgba(0,0,0,.6)}
.card img{width:100%;height:100%;object-fit:cover;filter:brightness(.68);
  transform:scale(1.08);transition:filter 1.2s var(--e);will-change:transform}
.card:hover img{filter:brightness(.9)}
.card .gloss{position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  background:linear-gradient(135deg,rgba(255,255,255,.16),transparent 40%)}
.card .meta{position:absolute;left:0;right:0;bottom:0;padding:1.5rem;
  background:linear-gradient(transparent,rgba(0,0,0,.85))}
.card .meta{padding:2.4rem 2rem 2rem}
.card .meta b{display:block;font-size:1.6rem;font-weight:600;letter-spacing:-.03em;margin:.35rem 0 .15rem}
.card .meta .mtop{display:block;font-size:.75rem;font-weight:500;letter-spacing:.15em;
  text-transform:uppercase;color:var(--red-ink)}
.card .meta .mcl{display:block;font-size:.9375rem;color:var(--grey)}
.card .meta .mnote{display:block;font-size:.9375rem;color:var(--grey);margin-top:.6rem;
  max-width:38ch;text-wrap:pretty;
  max-height:0;opacity:0;overflow:hidden;
  transition:max-height .7s var(--e),opacity .5s var(--e),margin .7s var(--e)}
.card:hover .mnote{max-height:7rem;opacity:1}
.card .meta .mgo{display:inline-flex;align-items:center;gap:.4rem;margin-top:.9rem;
  font-size:.875rem;color:var(--red-ink);opacity:0;transform:translateY(6px);
  transition:opacity .5s var(--e),transform .5s var(--e)}
.card:hover .mgo{opacity:1;transform:none}
.card .meta .mgo i{font-style:normal}

/* how we work */
.howgrid{display:grid;grid-template-columns:.85fr 1.15fr;gap:4.375rem;align-items:start}
.howhead{position:sticky;top:calc(var(--navh) + 2rem)}
.steps{list-style:none;margin:0;padding:0;counter-reset:s}
.step{display:grid;grid-template-columns:auto 1fr;gap:2.177rem;
  padding:2.395rem 0;border-top:1px solid var(--hair);align-items:start}
.step:last-child{border-bottom:1px solid var(--hair)}
.step .sn{font-size:min(2.395rem,7.6vw);font-weight:600;letter-spacing:-.04em;
  line-height:1;color:var(--red);opacity:.9;font-variant-numeric:tabular-nums}
.step h3{font-size:1.524rem;letter-spacing:-.03em;margin-bottom:.6rem}
.step .body{text-wrap:pretty;font-size:1.0625rem;max-width:46ch;margin:0}

/* the details */
.dl{margin:0}
.dl > div{display:grid;grid-template-columns:.6fr 1.4fr;gap:2.613rem;
  padding:1.6rem 0;border-top:1px solid var(--hair)}
.dl > div:last-child{border-bottom:1px solid var(--hair)}
.dl dt{font-size:1.0625rem;font-weight:600;letter-spacing:-.02em;margin:0}
.dl dd{margin:0;text-wrap:pretty;color:var(--grey);font-size:1.0625rem;max-width:56ch}

/* portal — light */
.light{background:var(--lightbg);color:var(--lightink);position:relative;z-index:10;
  padding:5.742rem var(--gut)}
.light .body{color:var(--lightgrey)}
.light .pgrid{display:grid;grid-template-columns:1fr 1fr;gap:4.375rem;
  align-items:center;max-width:var(--maxw);margin:0 auto;perspective:1200px}
.light ul{list-style:none;margin:2rem 0 2.5rem;padding:0;display:grid;gap:.9rem}
.light li{display:flex;gap:.85rem;align-items:baseline;color:var(--lightgrey);font-size:1.0625rem}
.light li::before{content:"";flex:0 0 auto;width:5px;height:5px;border-radius:50%;background:var(--red)}
.mock{background:#fff;border-radius:24px;padding:1.75rem;
  box-shadow:0 40px 100px rgba(0,0,0,.13),0 2px 8px rgba(0,0,0,.05);
  transform:rotateY(-6deg) rotateX(2deg);transition:transform 1.2s var(--e)}
.light .pgrid:hover .mock{transform:rotateY(-2deg) rotateX(1deg)}
.mock .top{display:flex;justify-content:space-between;align-items:center;gap:1rem;
  padding-bottom:1.1rem;border-bottom:1px solid rgba(0,0,0,.08);font-size:.8125rem;color:var(--lightgrey)}
.mock .top b{color:var(--lightink);font-weight:600}
.mock .row{display:flex;justify-content:space-between;align-items:center;gap:1rem;
  padding:.95rem 0;border-bottom:1px solid rgba(0,0,0,.06);font-size:.9375rem}
.mock .row:last-of-type{border-bottom:0}
.mock .row b{font-weight:500}
.mock .row span{font-size:.75rem;color:var(--lightgrey)}
.mock .row.live span{color:var(--red);font-weight:500}
.mock .bar{height:4px;border-radius:99px;background:rgba(0,0,0,.08);margin-top:1.25rem;overflow:hidden}
.mock .bar b{display:block;height:100%;width:0;background:var(--red);border-radius:99px;
  transition:width 1.8s var(--e)}
.mock.in .bar b{width:62%}

.cta{text-align:center;position:relative;z-index:10;
  padding:7.656rem var(--gut);overflow:hidden}
.cta::before{content:"";position:absolute;left:50%;top:50%;width:min(60rem,140%);height:34rem;
  transform:translate(-50%,-50%);pointer-events:none;
  background:radial-gradient(closest-side,rgba(222,27,36,.18),transparent)}
/* 16ch forced three lines with a stranded short word in the middle
   ("Ready to make / something / worth watching?") and text-wrap:balance
   could not improve on it — the words are too long to re-break. 22ch
   gives two lines with a deliberate long-over-short rag. Below about
   1000px the container caps the width and it wraps naturally again. */
.cta h2{position:relative;max-width:22ch;margin:0 auto 2.5rem}
.cta .links{justify-content:center;position:relative}

/* oversized close — the wordmark runs edge to edge and is clipped by it */
.bigtype{position:relative;z-index:10;overflow:hidden;padding:0;
  display:flex;justify-content:center;line-height:.78;user-select:none}
.bigtype span{display:block;white-space:nowrap;font-weight:700;
  /* pure vw: the string is fixed-length, so this is the only way it reliably
     runs past both edges at every width instead of centring with gaps */
  font-size:13vw;letter-spacing:-.06em;
  background:linear-gradient(180deg,rgba(245,245,247,.30),rgba(245,245,247,.02) 72%,transparent);
  -webkit-background-clip:text;background-clip:text;color:transparent;
  transform:translateY(16%)}

/* contact block */
.credits{max-width:min(64rem,86vw);margin:0 auto 4.354rem;text-align:center}
.bigmail{display:block;margin:1.5rem 0 3.484rem;
  font-size:min(3.701rem,9.5vw);font-weight:600;letter-spacing:-.045em;
  line-height:.97;color:var(--white);transition:color .4s var(--e)}
.bigmail:hover{color:var(--red-ink)}
.crd{margin:0;display:grid;gap:1.5rem}
.crd > div{display:grid;gap:.35rem}
.crd dt{font-size:.6875rem;letter-spacing:.15em;text-transform:uppercase;color:var(--grey2)}
.crd dd{margin:0;font-size:1.167rem;font-weight:500;letter-spacing:-.02em;
  color:var(--white)}
footer{position:relative;z-index:10;border-top:1px solid var(--hair);
  padding:3rem var(--gut) 3.5rem;color:var(--grey2)}
.fwrap{max-width:var(--maxw);margin:0 auto;display:flex;flex-wrap:wrap;gap:1.5rem 2rem;
  justify-content:space-between;align-items:center;font-size:.8125rem}
.fwrap img{height:3.05rem;width:auto;opacity:.9}
.fwrap nav{display:flex;flex-wrap:wrap;gap:1.5rem}
.fwrap nav a{font-size:0.762rem}
.fwrap a{transition:color .3s var(--e)}
.fwrap a:hover{color:var(--white)}
.fnote{max-width:var(--maxw);margin:2rem auto 0;padding-top:1.5rem;border-top:1px solid var(--hair)}

.rv{opacity:0;transform:perspective(1000px) translateY(34px) rotateX(7deg);
  transform-origin:50% 100%;
  transition:opacity 1.2s var(--e),transform 1.2s var(--e)}
.rv.in{opacity:1;transform:perspective(1000px) translateY(0) rotateX(0deg)}
.rv.d1{transition-delay:.10s}.rv.d2{transition-delay:.20s}.rv.d3{transition-delay:.30s}
/* the mock is both a reveal AND permanently angled — it needs a higher
   specificity rule or .rv.in{rotateX(0)} flattens it on arrival */
.mock.rv{transform:perspective(1200px) translateY(34px) rotateX(7deg)}
.mock.rv.in{transform:perspective(1200px) rotateY(-6deg) rotateX(2deg)}
.light .pgrid:hover .mock.rv.in{transform:perspective(1200px) rotateY(-2deg) rotateX(1deg)}

/* ============================================================
   Responsive
   ============================================================ */
@media(max-width:900px){
  :root{--gut:1.15rem}
  .nav{grid-template-columns:1fr auto}
  .navmid{display:none}
  /* 78vw minus 2.6rem of padding left ~220px of text column, which broke
     "On screens." across two lines */
  .copy{max-width:100%;padding:1.5rem 1rem}
  .markframe{inset:.6rem;border-radius:calc(var(--brand-r) * .7)}
  .copy h1{font-size:min(3.4rem,11.5vw)}
  .copy .body{font-size:1rem}
  /* Floating tiles are unusable on a phone, but they carry real links now,
     so they become a tappable grid under the film instead of vanishing. */
  .scene{grid-template-rows:auto auto}
  .copy{grid-area:1/1}
  /* .scene uses place-items:center, so this grid item does not stretch and
     the auto-width tiles collapsed to nothing — take the full row width */
  .stack3d{grid-area:2/1;position:relative;inset:auto;margin-top:1.25rem;
    width:100%;justify-self:stretch;
    display:grid;grid-template-columns:repeat(2,1fr);gap:.6rem;
    transform:none !important;opacity:1 !important;perspective:none}
  .tile{position:relative;left:auto;top:auto;width:auto;transform:none;aspect-ratio:1}
  .tile.deco{display:none}
  .tile.wide,.tile.tall{aspect-ratio:1}
  .tile .face{animation:tileIn .9s var(--d,0s) var(--e) both}
  .tile .lab{font-size:.6875rem;padding:.5rem .55rem}
  .copy h1 .l{transform:none}
  .copy .body,.copy .links{transform:none}
  .svc .grid{grid-template-columns:1fr;gap:0}
  .svc .media{position:sticky;top:var(--navh);z-index:5;margin-left:0;background:var(--black);padding:.75rem 0}
  .svc .mediainner{position:static;height:auto;perspective:none}
  .svc .stack{aspect-ratio:4/3;transform:none;width:100%;max-width:none;
    border-radius:var(--brand-r);animation:none}
  .svc .ghost,.svcrail{display:none}
  .svc .cap{font-size:.6875rem;margin:1rem 0 0}
  .chips li{font-size:.75rem;padding:.35rem .7rem}
  .studio figure{width:100%;max-width:22rem}
  .svc .panel{min-height:auto;padding:2.25rem 0}
  .svc .pcard{padding:1.75rem 1.5rem;max-width:none;
    box-shadow:var(--glass-edge),0 20px 50px rgba(0,0,0,.4)}
  .svc .panels{padding-bottom:3rem}
  .studio{grid-template-columns:1fr;gap:2.5rem}
  .bigmail{font-size:min(5.225rem,6.8vw)}
  .quote{padding:2.1rem 1.6rem 2rem}
  .quote blockquote{font-size:min(1.5rem,6.4vw)}
  .howgrid{grid-template-columns:1fr;gap:2.5rem}
  .howhead{position:static}
  .dl > div{grid-template-columns:1fr;gap:.5rem}
  /* pinned horizontal scroll is miserable on touch — swipe natively instead */
  .hwork{height:auto !important}
  .hpin{position:static;height:auto;overflow:visible}
  .htrack{overflow-x:auto;width:auto;transform:none !important;
    scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;
    padding-bottom:1rem;gap:.75rem}
  .card{scroll-snap-align:center;width:82vw}
  .light .pgrid{grid-template-columns:1fr;gap:3rem}
  .mock{transform:none}
  .statement{height:150vh}
}
/* 1600px+ : real desktops and 4K panels */
@media(min-width:1600px){
  .studio{gap:2.916rem;
    grid-template-columns:minmax(0,.6fr) minmax(0,1.4fr)}
  .dl > div{grid-template-columns:.42fr 1.58fr}
  .howgrid{grid-template-columns:.7fr 1.3fr}
  .step .body{max-width:60ch}
  .studio p,.svc .panel .body{max-width:66ch}
  .specs{grid-template-columns:repeat(3,1fr);max-width:none}
}

@media(prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important}
  .rv{opacity:1;transform:none}
  .h-md.rv > .ln{transform:none}
  .bg b{animation:none}
  .statement h2 w{filter:none;transform:none}
  .tile .face{opacity:1;animation:none}
  .filmbed{clip-path:none;opacity:1;animation:none}
  .markframe{opacity:1;animation:none}
  .filmbed .sheen{display:none}
  .copy h1 .l > span,.copy .body,.copy .links{opacity:1;transform:none}
  .statement h2 w{opacity:1}
}

/* ============================================================
   INNER PAGES
   ============================================================ */
.phero{position:relative;z-index:10;padding:calc(var(--navh) + 5rem) var(--gut) 3rem}
.phero .wrap{max-width:var(--maxw);margin:0 auto}
.phero h1{font-size:min(4.521rem,12.5vw);line-height:.93;letter-spacing:-.045em;
  font-weight:600;margin:0 0 1.25rem}
.phero .body{max-width:48ch}
.phero .acts{display:flex;flex-wrap:wrap;gap:1.75rem;margin-top:2.25rem}

.filters{display:flex;flex-wrap:wrap;gap:.6rem;margin:2.5rem 0 0;padding:0;list-style:none}
.filters button{font-family:inherit;font-size:.9375rem;font-weight:500;cursor:pointer;
  padding:.6rem 1.1rem;border-radius:999px;color:var(--grey);
  border:1px solid rgba(255,255,255,.13);background:rgba(255,255,255,.035);
  transition:color .35s var(--e),border-color .35s var(--e),background .35s var(--e)}
.filters button:hover{color:var(--white);border-color:rgba(255,255,255,.3)}
.filters button[aria-pressed="true"]{color:#fff;background:var(--red);border-color:transparent}
.filters .count{color:var(--grey2);font-size:.8125rem;letter-spacing:.15em;
  text-transform:uppercase;align-self:center;margin-left:.5rem}

.workwall{position:relative;z-index:10;max-width:var(--maxw);margin:0 auto;
  padding:2.5rem var(--gut) clamp(4rem,8vh,8rem);
  display:grid;grid-template-columns:repeat(12,1fr);gap:1.5rem}
.pitem{grid-column:span 4;position:relative;border-radius:var(--brand-r);overflow:hidden;
  background:var(--panel);aspect-ratio:4/3;display:block;cursor:pointer;
  border:1px solid rgba(255,255,255,.10);
  box-shadow:var(--glass-edge),0 30px 70px rgba(0,0,0,.5);
  transition:box-shadow .6s var(--e),transform .6s var(--e)}
/* A featured item takes a full-width band of its own. It used to span 8 of 12
   columns and keep a 4:3 shape, which left its 4-column row-mate standing in a
   300px hole — the spans come from Notion data, so no pairing can be relied on.
   Owning the whole row means the layout cannot mismatch whatever order arrives. */
.pitem.wide{grid-column:1/-1;aspect-ratio:21/9}
.pitem.tall{grid-column:span 4;aspect-ratio:4/3}
/* A row of standard cells is three wide, so a tail of one or two would leave
   the rest of its row standing open. Two of the covers are still hosted
   remotely and a card whose image never loads removes itself, so the count can
   drop at render time — the tail stretches to fill whatever row it lands in. */
.pitem.fill-1{grid-column:1/-1;aspect-ratio:21/9}
.pitem.fill-2{grid-column:span 6;aspect-ratio:16/9}
.pitem:hover{box-shadow:var(--glass-edge),0 44px 100px rgba(222,27,36,.22),0 30px 70px rgba(0,0,0,.55)}
.pitem img{width:100%;height:100%;object-fit:cover;filter:brightness(.66);
  transform:scale(1.05);transition:transform 1.2s var(--e),filter 1.2s var(--e)}
.pitem:hover img{transform:scale(1);filter:brightness(.88)}
.pitem .gloss{position:absolute;inset:0;pointer-events:none;border-radius:inherit;
  background:linear-gradient(140deg,rgba(255,255,255,.13),transparent 40%)}
/* The caption plate. A single top-to-bottom gradient looks right until the
   covers change: it only reaches full strength at the very bottom, so the
   discipline label — the topmost line — sits on almost clear glass, and the
   red label ink needs a genuinely dark backing to stay readable at 12px.
   Percentage stops cannot fix that either, because the box grows whenever a
   title wraps to two lines and every stop slides with it.
   So: a fixed 2.4rem fade at the top, then a constant plate behind the text,
   whatever the height. Measured at 4.9:1 or better against pure white. */
.pitem .pm{position:absolute;left:0;right:0;bottom:0;padding:2.4rem 1.6rem 1.5rem;
  background:
    linear-gradient(rgba(0,0,0,0),rgba(0,0,0,.88)) 0 0/100% 2.4rem no-repeat,
    linear-gradient(rgba(0,0,0,.88),rgba(0,0,0,.88)) 0 2.4rem/100% calc(100% - 2.4rem) no-repeat}
.pitem .pm .lab{display:block;font-size:.75rem;font-weight:500;letter-spacing:.15em;
  text-transform:uppercase;color:var(--red-ink)}
.pitem.award .pm .lab{color:var(--gold-ink)}
.pitem .pm b{display:block;font-size:1.5rem;font-weight:600;letter-spacing:-.03em;margin:.3rem 0 .1rem}
.pitem .pm em{font-style:normal;display:block;font-size:.9375rem;color:var(--grey)}
.pitem .play{position:absolute;top:1.1rem;right:1.1rem;width:2.6rem;height:2.6rem;
  border-radius:50%;display:grid;place-items:center;
  background:rgba(8,8,10,.55);border:1px solid rgba(255,255,255,.2);backdrop-filter:blur(12px)}
.pitem .play::after{content:"";margin-left:3px;
  border-left:.65rem solid #fff;border-top:.42rem solid transparent;border-bottom:.42rem solid transparent}
.pempty{grid-column:1/-1;padding:4rem 0;text-align:center;color:var(--grey)}

.pview{position:fixed;inset:0;z-index:120;background:rgba(4,3,4,.9);
  backdrop-filter:blur(24px) saturate(150%);display:flex;align-items:center;justify-content:center;
  padding:var(--gut);opacity:0;visibility:hidden;
  transition:opacity .5s var(--e),visibility 0s .5s}
.pview.open{opacity:1;visibility:visible;transition:opacity .5s var(--e),visibility 0s}
.pbox{position:relative;width:min(76rem,100%);max-height:88vh;overflow-y:auto;
  border-radius:var(--brand-r);border:1px solid rgba(255,255,255,.1);background:var(--panel);
  box-shadow:0 60px 160px rgba(0,0,0,.7),var(--glass-edge);
  transform:translateY(24px) scale(.985);transition:transform .6s var(--e)}
.pview.open .pbox{transform:none}
/* The viewer shows the film as it was cut. `aspect-ratio` here is only the
   shape of the box BEFORE the file reports its own; once the metadata
   arrives the box is reshaped to match, so nothing is letterboxed either.
   `contain` is the guarantee underneath that: whatever the box ends up
   being, the picture is fitted into it whole.

   This was `cover` on a fixed 16/9 box, which quietly cropped anything not
   shot at 16:9 — Coming Home is finished at 2.4:1, and the viewer was
   slicing the sides off the frame. A viewer that recomposes someone's shot
   is worse than no viewer. */
.pmedia{position:relative;aspect-ratio:16/9;background:#000;overflow:hidden;
  max-height:78vh}
.pmedia img,.pmedia video{width:100%;height:100%;object-fit:contain;display:block}
.pbody{padding:2.4rem 2.4rem 2.8rem}
.pbody .lab{font-size:.75rem;font-weight:500;letter-spacing:.15em;text-transform:uppercase;color:var(--red-ink)}
.pbody h2{font-size:min(2.83rem,8vw);letter-spacing:-.035em;line-height:1.05;margin:.5rem 0 .35rem}
.pbody .cl{color:var(--grey);font-size:1.0625rem;margin:0 0 1.5rem}
.pbody .sum{color:var(--grey);font-size:1.0625rem;line-height:1.55;max-width:62ch;text-wrap:pretty}
.pmeta{display:flex;flex-wrap:wrap;gap:.5rem;margin:1.75rem 0 0;padding:0;list-style:none}
.pmeta li{font-size:.8125rem;color:var(--grey);padding:.45rem .85rem;border-radius:999px;
  border:1px solid rgba(255,255,255,.13);background:rgba(255,255,255,.045)}
.pclose{position:absolute;top:1rem;right:1rem;z-index:3;width:2.8rem;height:2.8rem;
  border-radius:50%;cursor:pointer;color:var(--white);font-size:1.1rem;font-family:inherit;
  background:rgba(8,8,10,.6);border:1px solid rgba(255,255,255,.2);backdrop-filter:blur(12px)}
.pclose:hover{background:var(--red);border-color:transparent}

/* service pages */
.shero{display:grid;grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr);
  gap:4rem;align-items:center;max-width:var(--maxw);margin:0 auto}
.sfig{position:relative;border-radius:var(--brand-r);overflow:hidden;aspect-ratio:4/3;
  border:1px solid rgba(222,27,36,.45);
  box-shadow:0 0 34px rgba(222,27,36,.24),0 30px 70px rgba(0,0,0,.6),var(--glass-edge)}
.sfig img,.sfig video{width:100%;height:100%;object-fit:cover;filter:brightness(.85);display:block}
.incl{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut);
  display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1.25rem}
.incl div{padding:1.6rem 1.4rem;border-radius:var(--brand-r);
  border:1px solid rgba(255,255,255,.09);
  background:linear-gradient(155deg,rgba(255,255,255,.055),rgba(255,255,255,.012) 55%,rgba(222,27,36,.045));
  box-shadow:var(--glass-edge)}
.incl b{display:block;font-size:1.0625rem;font-weight:600;letter-spacing:-.02em;margin-bottom:.4rem}
.incl span{color:var(--grey);font-size:.9375rem;text-wrap:pretty}
.srel{max-width:var(--maxw);margin:0 auto;padding:0 var(--gut)}

/* albums */
.alb{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(22rem,100%),1fr));gap:1.5rem}
.albcard{position:relative;border-radius:var(--brand-r);overflow:hidden;aspect-ratio:4/3;
  display:block;cursor:pointer;background:var(--panel);
  border:1px solid rgba(255,255,255,.1);box-shadow:var(--glass-edge),0 30px 70px rgba(0,0,0,.5);
  transition:box-shadow .6s var(--e)}
.albcard:hover{box-shadow:var(--glass-edge),0 44px 100px rgba(200,162,74,.2),0 30px 70px rgba(0,0,0,.55)}
.albcard img{width:100%;height:100%;object-fit:cover;filter:brightness(.68);
  transform:scale(1.05);transition:transform 1.2s var(--e),filter 1.2s var(--e)}
.albcard:hover img{transform:scale(1);filter:brightness(.9)}
.albcard .pm{position:absolute;left:0;right:0;bottom:0;padding:1.8rem 1.5rem 1.4rem;
  background:linear-gradient(transparent,rgba(0,0,0,.86))}
.albcard .pm b{display:block;font-size:1.35rem;font-weight:600;letter-spacing:-.03em}
.albcard .pm em{font-style:normal;color:var(--grey);font-size:.9375rem}
.lightgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(18rem,100%),1fr));
  gap:.75rem;padding:1.5rem}
.lightgrid img{width:100%;aspect-ratio:3/2;object-fit:cover;border-radius:10px;
  border:1px solid var(--hair)}

/* 404 */
.nf{min-height:100vh;min-height:100svh;display:grid;place-items:center;text-align:center;
  padding:calc(var(--navh) + 4rem) var(--gut) 4rem;position:relative;z-index:10}
.nf .code{font-size:min(9rem,26vw);font-weight:700;letter-spacing:-.05em;line-height:1;
  color:transparent;-webkit-text-stroke:1px rgba(222,27,36,.7)}

@media(max-width:1024px){
  .pitem,.pitem.wide,.pitem.tall{grid-column:span 6}
  .shero{grid-template-columns:1fr;gap:2.5rem}
}
@media(max-width:700px){
  /* Every card is full width on a phone — including the fill-1 / fill-2
     classes the grid adds to close up a short last row. Those were not in
     this list, so the two cards that happened to land in a stranded row
     stayed at span 6: 146px wide and 82px tall on an iPhone, with
     "Creating Tomorrow College Hero Video" wrapping to five lines inside
     them. On one column there is no short row to close, so the whole idea
     is moot here anyway. */
  .pitem,.pitem.wide,.pitem.tall,
  .pitem.fill-1,.pitem.fill-2{grid-column:span 12;aspect-ratio:4/3}
  .pbody{padding:1.6rem 1.4rem 2rem}
}

/* ============================================================
   MOTION LAYER
   Everything here is transition-based and keyed off .rv.in, the
   class the reveal observer already sets, so it costs no extra
   JS and inherits the existing reduced-motion handling (the
   media query below forces transition-duration to ~0 globally).
   Anything that starts hidden is also reset at the bottom, so a
   visitor who asks for reduced motion still sees every element.
   ============================================================ */

/* reveals arrive out of focus as well as from below — reads like a
   rack focus rather than a slide */
.rv{filter:blur(5px)}
.rv.in{filter:blur(0)}

/* the hairline in a section marker draws itself out */
.chapter i{transform:scaleX(0);transform-origin:0 50%;
  transition:transform .9s .1s var(--e)}
.chapter:not(.rv) i,.chapter.rv.in i{transform:scaleX(1)}

/* links: the fade is replaced by an underline that sweeps in from the
   left and out to the right, so the direction reads as forward motion */
.lnk{position:relative}
.lnk::after{content:"";position:absolute;left:0;right:0;bottom:-.16em;height:1px;
  background:currentColor;transform:scaleX(0);transform-origin:100% 50%;
  transition:transform .45s var(--e)}
.lnk:hover,.lnk:focus-visible{opacity:1}
.lnk:hover::after,.lnk:focus-visible::after{transform:scaleX(1);transform-origin:0 50%}
.lnk:hover i,.lnk:focus-visible i{transform:translateX(5px)}

/* a light passes across a button on hover */
.btn{position:relative;overflow:hidden;isolation:isolate}
.btn::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(115deg,transparent 32%,rgba(255,255,255,.30) 50%,transparent 68%);
  transform:translateX(-130%);transition:transform .85s var(--e)}
.btn:hover::after,.btn:focus-visible::after{transform:translateX(130%)}

/* "what's included" cards lift and pick up a red edge */
.incl div{transition:transform .5s var(--e),border-color .5s var(--e),
  box-shadow .5s var(--e),background .5s var(--e)}
.incl div:hover{transform:translateY(-.4rem);
  border-color:rgba(222,27,36,.42);
  box-shadow:0 1.4rem 3.4rem rgba(0,0,0,.5),0 0 0 1px rgba(222,27,36,.22)}

/* each step rules itself off as it arrives */
.step{border-top-color:transparent;position:relative}
.step:last-child{border-bottom-color:transparent}
.step::before,.step:last-child::after{content:"";position:absolute;left:0;right:0;
  height:1px;background:var(--hair);transform:scaleX(0);transform-origin:0 50%;
  transition:transform .95s var(--e)}
.step::before{top:-1px}
.step:last-child::after{bottom:-1px;transition-delay:.12s}
.step.rv.in::before,.step.rv.in:last-child::after,
.step:not(.rv)::before,.step:not(.rv):last-child::after{transform:scaleX(1)}
.step .sn{transition:transform .5s var(--e),color .5s var(--e)}
.step:hover .sn{transform:translateX(.25rem);color:var(--red-hi)}

/* portfolio and album cards: the caption settles as the image opens up */
.pitem .pm,.albcard .pm{transform:translateY(.5rem);
  transition:transform .55s var(--e)}
.pitem:hover .pm,.pitem:focus-visible .pm,
.albcard:hover .pm,.albcard:focus-visible .pm{transform:none}
.pitem:hover,.pitem:focus-visible,
.albcard:hover,.albcard:focus-visible{transform:translateY(-.35rem)}
/* a corner tick that draws in, so the card reads as selectable */
.pitem::after,.albcard::after{content:"";position:absolute;top:.9rem;left:.9rem;
  width:1.15rem;height:1.15rem;pointer-events:none;z-index:3;
  border-top:1px solid var(--red);border-left:1px solid var(--red);
  opacity:0;transform:translate(.4rem,.4rem);
  transition:opacity .45s var(--e),transform .45s var(--e)}
.pitem:hover::after,.pitem:focus-visible::after,
.albcard:hover::after,.albcard:focus-visible::after{opacity:1;transform:none}

/* the footer address gets the same underline treatment, at scale */
.bigmail{position:relative;display:inline-block;
  transition:color .45s var(--e),letter-spacing .6s var(--e)}
.bigmail::after{content:"";position:absolute;left:0;right:0;bottom:.06em;height:2px;
  background:var(--red);transform:scaleX(0);transform-origin:100% 50%;
  transition:transform .6s var(--e)}
.bigmail:hover::after,.bigmail:focus-visible::after{transform:scaleX(1);transform-origin:0 50%}

/* media drifts against the scroll — set from JS, composed here so the
   hover scale on a card and the drift never overwrite each other */
.sfig img,.sfig video{transform:translate3d(0,var(--py,0px),0) scale(1.06);
  transition:filter 1s var(--e)}
.sfig{position:relative}
.sfig::after{content:"";position:absolute;inset:0;pointer-events:none;
  border-radius:inherit;box-shadow:inset 0 0 0 1px rgba(255,255,255,.07)}

/* leaving the page: a short fade so navigation feels continuous */
body{transition:opacity .26s linear}
body.leaving{opacity:0}

@media(prefers-reduced-motion:reduce){
  .rv{filter:none}
  .chapter i{transform:scaleX(1)}
  .step::before,.step:last-child::after{transform:scaleX(1)}
  .pitem .pm,.albcard .pm{transform:none}
  .sfig img,.sfig video{transform:scale(1.06)}
  .btn::after{display:none}
  body.leaving{opacity:1}
}

/* ============================================================
   DISCIPLINE GLYPHS
   The four navigation tiles carry drawn, animated marks instead of
   photographs. The photograph still exists — it is what fills the
   film bed on hover — so the tile says what the discipline IS and
   the hero shows what it LOOKS like.
   Everything is inline SVG on a 64x64 grid, stroked in currentColor,
   so it stays crisp at any tile size and costs no requests.
   ============================================================ */
.tile .gl{position:absolute;left:50%;top:44%;transform:translate(-50%,-50%);
  width:64%;height:64%;overflow:visible;
  fill:none;stroke:rgba(245,245,247,.85);stroke-width:2.4;
  stroke-linecap:round;stroke-linejoin:round;
  transition:stroke .5s var(--e),transform .6s var(--e)}
.tile:hover .gl,.tile:focus-visible .gl{stroke:#fff;
  transform:translate(-50%,-50%) scale(1.06)}
/* a soft pool of light behind the mark so it does not float on glass */
.tile:not(.deco) .inner::before{content:"";position:absolute;left:50%;top:46%;
  width:88%;height:88%;transform:translate(-50%,-50%);border-radius:50%;
  background:radial-gradient(closest-side,rgba(222,27,36,.20),transparent 72%);
  opacity:.55;transition:opacity .55s var(--e);pointer-events:none}
.tile:not(.deco):hover .inner::before{opacity:1}

/* videography — the spools turn, the record light breathes, the eye blinks */
.gl-video .reels{transform-origin:31px 13px;animation:glSpin 8s linear infinite}
.gl-video .rec{stroke:none;animation:glPulse 1.8s ease-in-out infinite}
.gl-video .body{fill:rgba(245,245,247,.05)}
.gl-video .eye{stroke-width:2.6;animation:glEye 4.4s ease-in-out infinite}

/* photography — the iris opens and closes, the flash blinks on the beat */
.gl-photo .body{fill:rgba(245,245,247,.05)}
.gl-photo .iris-ring{stroke-width:2.6}
.gl-photo .iris{fill:rgba(245,245,247,.14);stroke-width:2;
  transform-origin:32px 35px;transform-box:fill-box;
  animation:glIris 4.2s ease-in-out infinite}
.gl-photo .flash{stroke:none;animation:glBlink 4.2s ease-in-out infinite}

/* projection mapping — the beam holds and the facade lights pane by pane */
.gl-map .proj{fill:rgba(245,245,247,.10)}
.gl-map .facade{fill:rgba(0,0,0,.42)}
.gl-map .beam{stroke-width:1.6;animation:glBeam 3.6s ease-in-out infinite}
.gl-map .door{stroke-width:2}
.gl-map .panes rect{stroke:none;animation:glPane 3.6s ease-in-out infinite}
.gl-map .panes rect:nth-child(2){animation-delay:.22s}
.gl-map .panes rect:nth-child(3){animation-delay:.44s}
.gl-map .panes rect:nth-child(4){animation-delay:.66s}

@keyframes glEye{0%,88%,100%{transform:scale(1)}94%{transform:scale(.82)}}
@keyframes glSpin{to{transform:rotate(360deg)}}
@keyframes glPulse{0%,100%{opacity:1}50%{opacity:.25}}
@keyframes glBlink{0%,86%,100%{opacity:.25}90%{opacity:1}}
@keyframes glIris{0%,100%{transform:scale(1)}50%{transform:scale(.42)}}
@keyframes glBeam{0%,100%{opacity:.55}50%{opacity:1}}
@keyframes glPane{0%,100%{fill:rgba(245,245,247,.14)}
  50%{fill:rgba(222,27,36,.85)}}

/* An interaction marker, not a label. Four red "HOVER" badges shouted over
   the tiles and duplicated the hint line below the hero; a pulsing dot says
   the same thing quietly. The word itself is kept for screen readers. */
.tile .hovertag{position:absolute;top:.5rem;right:.5rem;z-index:3;
  width:.46rem;height:.46rem;border-radius:50%;overflow:hidden;
  text-indent:-999em;background:var(--red);
  box-shadow:0 0 0 0 rgba(222,27,36,.55);
  animation:tagPing 2.4s ease-out infinite;
  transition:opacity .45s var(--e)}
.tile:hover .hovertag,.tile:focus-visible .hovertag{opacity:0}
body.tiles-used .tile .hovertag{opacity:0;animation:none}
@keyframes tagPing{0%{box-shadow:0 0 0 0 rgba(222,27,36,.55)}
  70%{box-shadow:0 0 0 .5rem rgba(222,27,36,0)}
  100%{box-shadow:0 0 0 0 rgba(222,27,36,0)}}

/* and one line of plain instruction under the hero links, which
   retires itself the moment a tile has actually been hovered */
.usehint{display:flex;align-items:center;gap:.5rem;margin:1.25rem 0 0;
  font-size:.7rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--grey2);transition:opacity .6s var(--e),transform .6s var(--e)}
.usehint .uh-dot{width:.42rem;height:.42rem;border-radius:50%;
  background:var(--red);box-shadow:0 0 0 0 rgba(222,27,36,.55);
  animation:uhPing 2.2s ease-out infinite}
@keyframes uhPing{0%{box-shadow:0 0 0 0 rgba(222,27,36,.5)}
  70%{box-shadow:0 0 0 .55rem rgba(222,27,36,0)}
  100%{box-shadow:0 0 0 0 rgba(222,27,36,0)}}
body.tiles-used .usehint{opacity:0;transform:translateY(-.3rem);pointer-events:none}
/* touch has no hover, so say the true thing there instead */
@media(hover:none),(pointer:coarse){
  .tile .hovertag{display:none}
  .usehint{display:none}
}

@media(prefers-reduced-motion:reduce){
  .ma-ring,.ma-beam{animation:none}
  .ma-beam{display:none}
  .tile .gl *{animation:none !important}
  .gl-photo .iris{transform:scale(.7)}
  .tile .hovertag{animation:none;opacity:1}
  .usehint .uh-dot{animation:none}
}

/* ============================================================
   MENU FOCUS — the global focus ring drew a red box the full width
   of a menu item, which read as a selection box rather than a focus
   state. The item already answers with colour, a shift and a rule
   that draws under it, so the box is dropped and those are made
   unmistakable instead. Keyboard users keep a clear indicator.
   ============================================================ */
.bignav a:focus-visible{outline:none}
.bignav a:focus-visible .mt{transform:translateX(.85rem)}
.bignav a::before{content:"";position:absolute;left:-.85rem;top:22%;bottom:22%;
  width:2px;border-radius:2px;background:var(--red);
  transform:scaleY(0);transform-origin:50% 50%;
  transition:transform .4s var(--e)}
.bignav a:focus-visible::before,.bignav a:hover::before{transform:scaleY(1)}

/* ============================================================
   COLOUR ON THE SQUARES
   Every tile was glass over whatever the film happened to be doing
   behind it, so they read as grey and lifeless. Each now carries a
   brand accent — red and gold alternating across the four
   disciplines, and the decoration picking up the same two.
   ============================================================ */
/* A dark base sits under the accent, otherwise the film behind the glass
   tints it — red over stage lighting came out magenta, gold came out olive.
   With the base, the accent reads the same whatever is playing. */
.tile:not(.deco) .inner{
  border-color:color-mix(in srgb,var(--acc,var(--red)) 45%,rgba(255,255,255,.14));
  background:
    linear-gradient(152deg,
      color-mix(in srgb,var(--acc,var(--red)) 34%,transparent),
      color-mix(in srgb,var(--acc,var(--red)) 8%,transparent) 54%,
      rgba(255,255,255,.05)),
    linear-gradient(0deg,rgba(9,6,7,.70),rgba(9,6,7,.70))}
.tile:not(.deco):hover .inner,.tile:not(.deco):focus-visible .inner{
  border-color:color-mix(in srgb,var(--acc,var(--red)) 85%,white);
  box-shadow:var(--glass-edge),
    0 2.2rem 5rem color-mix(in srgb,var(--acc,var(--red)) 34%,transparent),
    0 .8rem 1.7rem rgba(0,0,0,.55)}
/* the pool of light behind the glyph takes the accent too */
.tile:not(.deco) .inner::before{
  background:radial-gradient(closest-side,
    color-mix(in srgb,var(--acc,var(--red)) 38%,transparent),transparent 72%)}
.tile .gl{stroke:#fff}
/* the accent does the colouring inside each glyph */
.gl-video .rec,.gl-photo .flash{fill:var(--acc,var(--red))}
.gl-video .lensbox{fill:color-mix(in srgb,var(--acc,var(--red)) 22%,transparent)}
.gl-map .beam{fill:color-mix(in srgb,var(--acc,var(--red)) 24%,transparent);
  stroke:color-mix(in srgb,var(--acc,var(--red)) 70%,transparent)}
.tile .hovertag{background:var(--acc,var(--red))}
.tile .lab{background:linear-gradient(transparent,rgba(0,0,0,.86))}

/* decoration: the same two accents, never neutral */
.tile.deco.solid .inner{
  background:linear-gradient(150deg,
    color-mix(in srgb,var(--acc,var(--red)) 88%,transparent),
    color-mix(in srgb,var(--acc,var(--red)) 42%,transparent)),
    linear-gradient(0deg,rgba(9,6,7,.55),rgba(9,6,7,.55));
  border-color:color-mix(in srgb,var(--acc,var(--red)) 60%,transparent)}
.tile.deco.outline .inner{background:none;
  border-color:color-mix(in srgb,var(--acc,var(--red)) 62%,transparent);
  box-shadow:inset 0 0 2.2rem color-mix(in srgb,var(--acc,var(--red)) 16%,transparent)}
.tile.deco.blur .inner{
  background:linear-gradient(150deg,
    color-mix(in srgb,var(--acc,var(--red)) 22%,rgba(255,255,255,.10)),
    color-mix(in srgb,var(--acc,var(--red)) 5%,rgba(255,255,255,.03)))}

/* Safari below 16.2 has no color-mix; these keep the tiles on-brand there
   rather than falling back to the browser's initial (transparent) value. */
@supports not (color: color-mix(in srgb, red 50%, blue)){
  .tile:not(.deco) .inner{border-color:rgba(222,27,36,.45);
    background:linear-gradient(152deg,rgba(222,27,36,.30),rgba(222,27,36,.06) 54%,rgba(255,255,255,.05)),
               linear-gradient(0deg,rgba(9,6,7,.70),rgba(9,6,7,.70))}
  .tile:not(.deco):hover .inner,.tile:not(.deco):focus-visible .inner{
    border-color:rgba(255,90,84,.9);
    box-shadow:var(--glass-edge),0 2.2rem 5rem rgba(222,27,36,.34),0 .8rem 1.7rem rgba(0,0,0,.55)}
  .tile:not(.deco) .inner::before{
    background:radial-gradient(closest-side,rgba(222,27,36,.38),transparent 72%)}
  .tile.deco.solid .inner{background:linear-gradient(150deg,rgba(222,27,36,.88),rgba(222,27,36,.42)),
    linear-gradient(0deg,rgba(9,6,7,.55),rgba(9,6,7,.55))}
  .tile.deco.outline .inner{border-color:rgba(222,27,36,.62);
    box-shadow:inset 0 0 2.2rem rgba(222,27,36,.16)}
  .tile.deco.blur .inner{background:linear-gradient(150deg,rgba(222,27,36,.22),rgba(255,255,255,.04))}
  .gl-video .rec,.gl-photo .flash{fill:var(--red)}
  .gl-video .lensbox{fill:rgba(222,27,36,.22)}
  .gl-map .beam{fill:rgba(222,27,36,.24);stroke:rgba(222,27,36,.70)}
  .tile .hovertag{background:var(--red)}
}

/* Three places set color:transparent and rely on -webkit-text-stroke to
   draw the letterforms. Any engine without the property would render them
   invisible rather than unstyled, so give the text back a colour there. */
@supports not (-webkit-text-stroke: 1px red){
  .bandtrack span,.nf .code,.svc .ghost{color:rgba(245,245,247,.28)}
}

/* ── Drawn wordmark ──────────────────────────────────────────────────────
   Stands in for the hosted logo if that request fails (see site.js). Sized
   off the same scale as everything else, so it drops into the nav, the
   loading panel and the footer at each one's own size without extra rules. */
.wordmark{display:inline-flex;align-items:center;gap:.5em;font-size:inherit;
  line-height:1;white-space:nowrap}
.wordmark b{display:inline-flex;align-items:center;justify-content:center;
  width:1.55em;height:1.55em;border-radius:.34em;background:var(--red);
  color:#fff;font-size:.62em;font-weight:700;letter-spacing:-.04em}
.wordmark i{font-style:normal;font-weight:600;font-size:.58em;
  letter-spacing:.02em;color:#fff}
.nav .mark .wordmark{font-size:2.42rem}
.pre-in .wordmark{font-size:4.1rem}
.fwrap .wordmark{font-size:3.05rem}

/* ── Photography gallery ─────────────────────────────────────────────────
   Photographs are static, so the presentation carries the interest: rows
   justified to each photo's own ratio, so nothing is cropped and no two rows
   repeat. Row widths are computed in JS and written as inline px, because
   only the script knows the ratios; everything else lives here. */
.gallery-sec{position:relative;z-index:10}
.gwall{position:relative;z-index:10;max-width:var(--maxw);margin:0 auto;
  padding:0 var(--gut) clamp(2rem,5vh,4rem);
  /* The row builder reads this, so it has to be a resolved px length, not a
     rem the script would have to convert. */
  --ggap:14px}
.grow{display:flex;gap:var(--ggap);margin-bottom:var(--ggap);flex-wrap:nowrap}
.grow[data-last]{justify-content:flex-start}
.gcell{position:relative;flex:0 0 auto;padding:0;border:0;cursor:pointer;
  border-radius:var(--brand-r);overflow:hidden;background:var(--panel);
  border:1px solid rgba(255,255,255,.10);
  box-shadow:var(--glass-edge),0 18px 44px rgba(0,0,0,.45);
  transition:box-shadow .55s var(--e),transform .55s var(--e)}
.gcell img{width:100%;height:100%;object-fit:cover;display:block;
  filter:brightness(.78) saturate(.95);transform:scale(1.035);
  transition:transform .8s var(--e),filter .55s var(--e)}
.gcell:hover img,.gcell:focus-visible img{transform:scale(1);filter:brightness(1) saturate(1)}
.gcell:hover,.gcell:focus-visible{transform:translateY(-3px);
  box-shadow:var(--glass-edge),0 30px 70px rgba(222,27,36,.18),0 20px 50px rgba(0,0,0,.55)}
.gcell .gser{position:absolute;left:.7rem;bottom:.65rem;font-size:.6875rem;
  font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:#fff;
  opacity:0;transform:translateY(.4rem);pointer-events:none;
  text-shadow:0 1px 10px rgba(0,0,0,.9);
  transition:opacity .45s var(--e),transform .45s var(--e)}
.gcell:hover .gser,.gcell:focus-visible .gser{opacity:1;transform:none}
.gfilters{margin-top:1.4rem}

/* Lightbox. Its own element rather than the projects viewer, because this one
   steps through a series and that one opens a single project. */
.lbox{position:fixed;inset:0;z-index:300;display:none;place-items:center;
  background:rgba(6,4,5,.94);backdrop-filter:blur(14px);padding:clamp(1rem,4vw,3rem)}
.lbox.on{display:grid;animation:lbIn .38s var(--e) both}
@keyframes lbIn{from{opacity:0}to{opacity:1}}
.lfig{margin:0;max-width:100%;max-height:100%;display:flex;flex-direction:column;
  align-items:center;gap:.9rem}
.lfig img{max-width:100%;max-height:78vh;max-height:78svh;object-fit:contain;
  border-radius:var(--brand-r);box-shadow:0 40px 110px rgba(0,0,0,.7);
  animation:lbPop .5s var(--e) both}
@keyframes lbPop{from{opacity:0;transform:scale(.975)}to{opacity:1;transform:none}}
.lfig figcaption{font-size:.75rem;font-weight:500;letter-spacing:.15em;
  text-transform:uppercase;color:var(--grey)}
.lclose,.lnav{position:absolute;border:1px solid rgba(255,255,255,.16);
  background:rgba(255,255,255,.06);color:#fff;cursor:pointer;border-radius:999px;
  display:grid;place-items:center;transition:background .3s var(--e),transform .3s var(--e)}
.lclose:hover,.lnav:hover{background:rgba(255,255,255,.14)}
.lclose{top:1.1rem;right:1.1rem;width:2.7rem;height:2.7rem;font-size:1.5rem;line-height:1}
.lnav{top:50%;margin-top:-1.55rem;width:3.1rem;height:3.1rem}
.lprev{left:1.1rem}
.lnext{right:1.1rem}
.lnav::after{content:"";width:.7rem;height:.7rem;border-top:2px solid #fff;
  border-right:2px solid #fff}
.lprev::after{transform:rotate(-135deg);margin-left:.22rem}
.lnext::after{transform:rotate(45deg);margin-right:.22rem}
@media (max-width:640px){
  .lnav{width:2.6rem;height:2.6rem;margin-top:-1.3rem}
  .lprev{left:.5rem} .lnext{right:.5rem}
}
@media (prefers-reduced-motion:reduce){
  .gcell,.gcell img,.gcell .gser{transition:none}
  .gcell img{transform:none}
  .lbox.on,.lfig img{animation:none}
}

/* The lightbox photograph fades in once it has decoded, so stepping through a
   series never shows the previous frame under the new caption. */
.lfig img{opacity:0;transition:opacity .28s var(--e)}
.lfig img.ready{opacity:1}
@media (prefers-reduced-motion:reduce){
  .lfig img{transition:none;opacity:1}
  .gcell{transition-delay:0s !important}
}

/* Each body of work gets its own heading and its own wall, so the range is
   visible without the visitor having to click a filter to discover it. */
.gset{margin-bottom:clamp(2.2rem,4vh,3.4rem)}
.gsh{display:flex;align-items:baseline;gap:.85rem;margin:0 0 1rem;
  font-size:1.05rem;font-weight:600;letter-spacing:-.01em;color:#fff}
.gsh::after{content:"";flex:1;height:1px;margin-left:.35rem;
  background:linear-gradient(90deg,rgba(255,255,255,.22),transparent)}
.gsh span{order:3;flex:0 0 auto;font-size:.6875rem;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;color:var(--grey)}

/* ── The live hero collage ───────────────────────────────────────────────
   Only the photography page uses this; every other surface plays the
   recorded reel. Rows are moved with translate3d from a rAF loop, so each
   row is a composited layer the browser slides rather than a layout it
   redoes sixty times a second. */
.hcol{display:block;cursor:grab;touch-action:pan-y;background:var(--panel);
  --hgap:12px}
.hcol.dragging{cursor:grabbing}
.hcol-rows{position:absolute;inset:0;display:flex;flex-direction:column;
  justify-content:center;gap:var(--hgap);padding:var(--hgap) 0}
.hcol-row{display:flex;gap:var(--hgap);flex:1 1 0;min-height:0;width:max-content;
  will-change:transform}
.hcol-t{flex:0 0 auto;height:100%;width:auto;padding:0;border:0;background:none;
  border-radius:calc(var(--brand-r) * .5);overflow:hidden;cursor:inherit;
  position:relative;
  transition:transform .45s var(--e),filter .45s var(--e)}
.hcol-t img{display:block;height:100%;width:100%;object-fit:cover;
  filter:brightness(.72) saturate(.95);
  transition:filter .45s var(--e);pointer-events:none}
.hcol-t:hover,.hcol-t:focus-visible{transform:translateY(-4px) scale(1.03);z-index:2}
.hcol-t:hover img,.hcol-t:focus-visible img{filter:brightness(1.04) saturate(1.05)}
/* The frame's own edges, so a bright photograph does not butt straight onto
   the page behind it. */
.hcol::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:3;
  border-radius:inherit;
  background:linear-gradient(90deg,rgba(9,6,7,.92),transparent 16%,transparent 84%,rgba(9,6,7,.92)),
             radial-gradient(120% 90% at 50% 50%,transparent 45%,rgba(9,6,7,.55))}
.hcol-hint{position:absolute;left:50%;bottom:.85rem;transform:translateX(-50%);
  z-index:4;font-size:.625rem;font-weight:500;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.72);pointer-events:none;
  padding:.3rem .7rem;border-radius:999px;background:rgba(9,6,7,.55);
  border:1px solid rgba(255,255,255,.14);backdrop-filter:blur(6px);
  transition:opacity .5s var(--e)}
.hcol.used .hcol-hint{opacity:0}
@media (hover:none){ .hcol-hint::after{content:""} }
@media (prefers-reduced-motion:reduce){
  .hcol-row{will-change:auto}
  .hcol-t{transition:none}
  .hcol-t:hover,.hcol-t:focus-visible{transform:none}
}

/* ==========================================================
   ALBUM VIEWER (assets/album.js)
   Full-screen, dark, and built around the photograph: the chrome
   sits on top of the image only where it has to, and gets out of
   the way while you are dragging.
   ========================================================== */
.alv{position:fixed;inset:0;z-index:120;display:none;
  grid-template-rows:auto 1fr auto;
  background:rgba(6,6,8,.97);backdrop-filter:blur(26px) saturate(140%)}
.alv.on{display:grid;animation:alvIn .32s var(--e) both}
@keyframes alvIn{from{opacity:0}to{opacity:1}}

.alv-bar{display:flex;align-items:center;gap:1.25rem;
  padding:1.1rem clamp(1rem,3vw,2.25rem)}
.alv-ttl{flex:1;min-width:0}
.alv-ttl b{display:block;font-size:1.0625rem;font-weight:600;letter-spacing:-.02em;
  color:var(--white);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.alv-ttl em{font-style:normal;display:block;font-size:.8125rem;color:var(--grey);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.alv-cnt{font-size:.8125rem;color:var(--grey);font-variant-numeric:tabular-nums;
  letter-spacing:.06em;flex-shrink:0}
.alv-x{width:2.4rem;height:2.4rem;flex-shrink:0;border-radius:50%;cursor:pointer;
  border:1px solid rgba(255,255,255,.16);background:rgba(255,255,255,.05);
  position:relative;transition:background .3s var(--e),border-color .3s var(--e)}
.alv-x:hover{background:rgba(222,27,36,.85);border-color:transparent}
.alv-x::before,.alv-x::after{content:"";position:absolute;left:50%;top:50%;
  width:.85rem;height:1.5px;background:var(--white);border-radius:2px}
.alv-x::before{transform:translate(-50%,-50%) rotate(45deg)}
.alv-x::after{transform:translate(-50%,-50%) rotate(-45deg)}

/* The bottom padding is the hint's room. Without it the image fills the
   stage and the hint prints straight over the bottom of the photograph. */
.alv-stage{position:relative;display:flex;align-items:center;justify-content:center;
  min-height:0;padding:0 clamp(.5rem,4vw,4.5rem) 1.75rem}
.alv-shot{position:relative;width:100%;height:100%;display:flex;
  align-items:center;justify-content:center;overflow:hidden;cursor:zoom-in}
.alv.zoomed .alv-shot{cursor:grab}
.alv-shot.dragging{cursor:grabbing}
/* Never drawn larger than the file itself — these are 1024px exports. */
.alv-shot img{position:absolute;max-width:min(100%,1024px);max-height:100%;
  width:auto;height:auto;object-fit:contain;border-radius:var(--brand-r);
  opacity:0;transition:opacity .34s var(--e),transform .34s var(--e);
  box-shadow:0 40px 90px rgba(0,0,0,.55);user-select:none;-webkit-user-drag:none}
.alv-shot img.on{opacity:1}
.alv-shot.dragging img{transition:none}

.alv-nav{width:3rem;height:3rem;flex-shrink:0;border-radius:50%;cursor:pointer;z-index:2;
  border:1px solid rgba(255,255,255,.16);background:rgba(10,10,12,.55);
  backdrop-filter:blur(10px);position:relative;
  transition:background .3s var(--e),border-color .3s var(--e),opacity .3s var(--e)}
.alv-nav:hover{background:rgba(222,27,36,.85);border-color:transparent}
.alv-nav::after{content:"";position:absolute;left:50%;top:50%;width:.6rem;height:.6rem;
  border-right:1.5px solid var(--white);border-bottom:1.5px solid var(--white)}
.alv-nav.prev::after{transform:translate(-35%,-50%) rotate(135deg)}
.alv-nav.next::after{transform:translate(-65%,-50%) rotate(-45deg)}
.alv.zoomed .alv-nav{opacity:.25}

.alv-hint{position:absolute;left:50%;bottom:.15rem;transform:translateX(-50%);
  display:flex;gap:1.25rem;margin:0;font-size:.6875rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--tx3,#555);pointer-events:none;
  transition:opacity .3s var(--e)}
.alv-shot.dragging ~ .alv-hint,.alv.zoomed .alv-hint{opacity:0}

.alv-strip{display:flex;gap:.5rem;overflow-x:auto;overflow-y:hidden;
  padding:1rem clamp(1rem,3vw,2.25rem) 1.35rem;scrollbar-width:thin;
  scrollbar-color:rgba(255,255,255,.18) transparent}
.alv-strip::-webkit-scrollbar{height:6px}
.alv-strip::-webkit-scrollbar-thumb{background:rgba(255,255,255,.18);border-radius:99px}
.alv-strip button{flex:0 0 auto;height:4.25rem;width:calc(4.25rem * var(--ar,1.5));
  padding:0;border:0;border-radius:calc(var(--brand-r) * .5);overflow:hidden;cursor:pointer;
  background:none;opacity:.45;position:relative;
  transition:opacity .28s var(--e),transform .28s var(--e)}
.alv-strip button:hover{opacity:.85;transform:translateY(-2px)}
.alv-strip button.on{opacity:1;transform:translateY(-3px)}
.alv-strip button.on::after{content:"";position:absolute;inset:0;border-radius:inherit;
  border:2px solid var(--red)}
.alv-strip img{width:100%;height:100%;object-fit:cover;display:block}

@media (max-width:760px){
  .alv-nav{display:none}
  .alv-strip button{height:3.25rem}
  .alv-hint span:last-child{display:none}
}
@media (prefers-reduced-motion:reduce){
  .alv.on{animation:none}
  .alv-shot img,.alv-strip button{transition:opacity .2s linear}
}

/* Album cards: three thumbnails fanned so the card reads as a stack of
   photographs rather than one picture with a number beside it. */
.albcard{display:block;width:100%;text-align:left;font-family:inherit;padding:0;border:0}
.albstack{position:absolute;inset:0;display:block}
.albstack img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  border-radius:inherit;filter:brightness(.68);
  transform:rotate(calc((var(--z) - 1) * 2.4deg)) scale(calc(1 - var(--z) * .05))
            translateY(calc(var(--z) * .5rem));
  transform-origin:50% 100%;
  transition:transform .75s var(--e),filter .75s var(--e);
  z-index:calc(3 - var(--z));opacity:calc(1 - var(--z) * .22)}
.albcard:hover .albstack img,.albcard:focus-visible .albstack img{
  transform:rotate(calc((var(--z) - 1) * 5deg)) scale(calc(1 - var(--z) * .03))
            translateY(calc(var(--z) * -.35rem));
  filter:brightness(.9)}

/* A clip cut to fit the host's file ceiling says so, rather than letting a
   visitor assume a 75-second cut is the finished film. */
.pexc{margin:.75rem 0 0;font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;
  color:var(--grey)}

/* ==========================================================
   PORTFOLIO HOVER PREVIEW
   The film plays in the card itself, with a band that slides
   across to say what a click does.
   ========================================================== */
/* The video covers the whole card, so it can simply fade in ON TOP of the
   still and the still never has to move. Fading one out while the other
   faded in put a dip of bare card between them — a visible flash of black
   on every hover, and a permanently black card whenever the film was slow.
   Nothing is hidden underneath; there is nothing to gain by clearing it. */
.pitem video.prev{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  z-index:1;opacity:0;transition:opacity .5s var(--e);pointer-events:none;
  filter:brightness(.72)}
/* `playing`, not `previewing`: the fade waits for a decoded frame. */
.pitem.playing video.prev{opacity:1}
/* The still lifts a shade as the film arrives, so the handover reads as one
   movement rather than a swap. */
.pitem img{transition:opacity .5s var(--e),transform .5s var(--e),filter .5s var(--e)}
.pitem.playing img{filter:brightness(.92)}
.pitem.previewing .play{opacity:0;transform:scale(.8)}
.pitem .play{transition:opacity .35s var(--e),transform .35s var(--e)}

/* The band is glass, not paint: it takes its colour from the footage
   moving underneath rather than covering it. A heavy blur plus saturation
   is what reads as "frosted" instead of "grey"; the hairline top and
   bottom edges are the lit rim that sells it as a physical pane; and the
   sheen is a single specular pass that crosses once as the band arrives.
   The whole thing sits over video, so every layer stays translucent —
   nothing here is allowed to become an opaque bar. */
.prevtag{position:absolute;left:0;right:0;top:50%;z-index:3;
  transform:translateY(-50%);pointer-events:none;overflow:hidden;
  display:flex;align-items:center;justify-content:center;
  height:3.1rem;
  background:linear-gradient(180deg,
    rgba(255,255,255,.22),
    rgba(255,255,255,.10) 42%,
    rgba(255,255,255,.14));
  backdrop-filter:blur(22px) saturate(190%) brightness(1.06);
  -webkit-backdrop-filter:blur(22px) saturate(190%) brightness(1.06);
  border-top:1px solid rgba(255,255,255,.42);
  border-bottom:1px solid rgba(255,255,255,.16);
  box-shadow:0 10px 30px rgba(0,0,0,.28),
             inset 0 1px 0 rgba(255,255,255,.30),
             inset 0 -1px 0 rgba(255,255,255,.10);
  clip-path:inset(0 100% 0 0);
  transition:clip-path .62s cubic-bezier(.22,.61,.36,1)}
.pitem.previewing .prevtag{clip-path:inset(0 0 0 0)}

/* the specular pass */
.prevtag::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(105deg,transparent 30%,
    rgba(255,255,255,.55) 48%,rgba(255,255,255,.14) 56%,transparent 70%);
  transform:translateX(-130%)}
.pitem.previewing .prevtag::after{
  animation:prevSheen 1.5s cubic-bezier(.22,.61,.36,1) .28s both}
@keyframes prevSheen{to{transform:translateX(130%)}}

.prevtag i{position:relative;z-index:1;
  font-style:normal;font-size:.78rem;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:#fff;white-space:nowrap;
  text-shadow:0 1px 10px rgba(0,0,0,.55),0 0 1px rgba(0,0,0,.6);
  transform:translateX(-1.5rem);opacity:0;
  transition:transform .5s cubic-bezier(.22,.61,.36,1) .14s,opacity .4s var(--e) .14s}
.pitem.previewing .prevtag i{transform:none;opacity:1}

/* Safari on older macOS has no backdrop-filter here; without a floor the
   band would be nearly invisible white-on-bright-footage. */
@supports not ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .prevtag{background:rgba(18,18,20,.62)}
}

@media (hover:none),(prefers-reduced-motion:reduce){
  .pitem video.prev,.prevtag{display:none}
}

/* ==========================================================
   The film player.

   One bar, the site's own, instead of whatever grey capsule the browser
   happens to draw. Built from the same glass as the hover band so the two
   read as one piece of design: a blurred plate that takes its colour from
   the film behind it, with the brand red only on the parts that respond.
   ========================================================== */
.vp{position:relative;width:100%;height:100%;background:#000}
/* contain, never cover — the player frames the film, it does not recrop it */
.vp video{display:block;width:100%;height:100%;object-fit:contain;cursor:pointer}

.vp-bar{position:absolute;left:0;right:0;bottom:0;z-index:4;
  display:flex;align-items:center;gap:.85rem;
  padding:.7rem .95rem calc(.7rem + env(safe-area-inset-bottom,0px));
  background:linear-gradient(to top,rgba(8,8,10,.82),rgba(8,8,10,.46) 62%,transparent);
  backdrop-filter:blur(18px) saturate(170%);
  -webkit-backdrop-filter:blur(18px) saturate(170%);
  border-top:1px solid rgba(245,245,247,.13);
  opacity:1;transform:translateY(0);
  transition:opacity .35s var(--e),transform .35s var(--e)}
/* Out of the way once a film is running and the pointer has settled. */
.vp.idle .vp-bar{opacity:0;transform:translateY(115%);pointer-events:none}
.vp.idle video{cursor:none}

.vp-b{flex:0 0 auto;display:grid;place-items:center;
  width:2.3rem;height:2.3rem;padding:0;border:0;border-radius:50%;
  background:rgba(245,245,247,.08);color:var(--white);cursor:pointer;
  transition:background .2s var(--e),transform .2s var(--e)}
.vp-b:hover{background:rgba(245,245,247,.17);transform:scale(1.06)}
.vp-b:active{transform:scale(.94)}
.vp-b:focus-visible{outline:2px solid var(--red-hi);outline-offset:2px}
.vp-b svg{width:1.15rem;height:1.15rem;fill:currentColor;
  stroke:currentColor;stroke-width:1.6;stroke-linecap:round;fill-rule:evenodd}
/* The speaker and frame marks are drawn as strokes, not filled shapes. */
.vp-mute svg,.vp-full svg{fill:none}
.vp-mute svg path:first-child{fill:currentColor}

.vp-scrub{position:relative;flex:1 1 auto;height:1.05rem;cursor:pointer;
  display:flex;align-items:center;touch-action:none}
.vp-scrub::before{content:"";position:absolute;left:0;right:0;height:.22rem;
  border-radius:99px;background:rgba(245,245,247,.2)}
.vp-scrub i{position:absolute;left:0;height:.22rem;border-radius:99px;pointer-events:none}
.vp-buf{background:rgba(245,245,247,.3);width:0}
.vp-done{background:linear-gradient(90deg,var(--red),var(--red-hi));width:0}
.vp-knob{position:absolute;top:50%;left:0;width:.72rem;height:.72rem;border-radius:50%;
  background:var(--white);box-shadow:0 1px 6px rgba(0,0,0,.6);pointer-events:none;
  transform:translate(-50%,-50%) scale(.7);opacity:.9;
  transition:transform .2s var(--e)}
.vp-scrub:hover .vp-knob,.vp-scrub:focus-visible .vp-knob{transform:translate(-50%,-50%) scale(1.15)}
.vp-scrub:focus-visible{outline:2px solid var(--red-hi);outline-offset:3px;border-radius:99px}

.vp-time{flex:0 0 auto;font-size:.76rem;letter-spacing:.04em;
  color:var(--grey2);font-variant-numeric:tabular-nums;white-space:nowrap}
.vp-time em{font-style:normal;color:var(--white)}

/* The volume slider is always there. It began as a track that slid open on
   hover, which looked tidier and was worse: a control that does not exist
   until the pointer is already on it cannot be aimed at, and it sat at zero
   width often enough in testing to be a real miss, not a flaky one. It
   still widens a little under the pointer. */
.vp-vol{flex:0 0 auto;display:flex;align-items:center;gap:.45rem}
.vp-vtrack{position:relative;width:3.4rem;height:1rem;display:flex;align-items:center;
  cursor:pointer;touch-action:none;transition:width .28s var(--e)}
.vp-vol:hover .vp-vtrack,.vp-vtrack:focus-visible{width:4.6rem}
.vp-vtrack::before{content:"";position:absolute;left:0;right:0;height:.2rem;
  border-radius:99px;background:rgba(245,245,247,.2)}
.vp-vfill{position:absolute;left:0;height:.2rem;border-radius:99px;
  background:var(--white);width:100%}

@media (max-width:640px){
  /* Volume is the system's job on a phone, and the bar needs the room. */
  .vp-vol{display:none}
  .vp-bar{gap:.6rem;padding:.55rem .7rem calc(.55rem + env(safe-area-inset-bottom,0px))}
}
@media (prefers-reduced-motion:reduce){
  .vp-bar{transition:none}
  .vp.idle .vp-bar{opacity:1;transform:none;pointer-events:auto}
}

/* ==========================================================
   Getting out of the showreel.

   The section is pinned for 190vh, which is the right scroll beat for the
   most important thing the company owns and the wrong amount of scrolling
   to be stuck in with no exit. Neither of these is discovered — the next-up
   cue sits there the whole time, and the close button appears the moment
   the reel takes the screen.
   ========================================================== */
.reelclose{position:absolute;top:1.6rem;right:1.6rem;z-index:6;
  display:flex;align-items:center;gap:.5rem;
  padding:.62rem 1.05rem;border-radius:99px;cursor:pointer;
  font-size:.8rem;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  color:var(--white);background:rgba(10,10,12,.5);
  border:1px solid rgba(245,245,247,.18);
  backdrop-filter:blur(18px) saturate(170%);
  -webkit-backdrop-filter:blur(18px) saturate(170%);
  opacity:0;pointer-events:none;transform:translateY(-6px);
  transition:opacity .4s var(--e),transform .4s var(--e),background .25s var(--e)}
.reelbox.playing .reelclose{opacity:1;pointer-events:auto;transform:none}
.reelclose:hover{background:var(--red);border-color:var(--red)}
.reelclose:focus-visible{outline:2px solid var(--red-hi);outline-offset:3px}
.reelclose::after{content:"";width:.62rem;height:.62rem;
  background:linear-gradient(currentColor,currentColor) 50%/100% 1.4px no-repeat,
             linear-gradient(currentColor,currentColor) 50%/1.4px 100% no-repeat;
  transform:rotate(45deg)}

/* The way on. Always visible, labelled with where it goes rather than a
   bare chevron, and a real link so it works before any script runs. */
.reelnext{position:absolute;left:50%;bottom:1.9rem;z-index:6;
  transform:translateX(-50%);
  display:flex;flex-direction:column;align-items:center;gap:.5rem;
  padding:.7rem 1.2rem .55rem;border-radius:1.1rem;
  text-decoration:none;color:var(--white);
  background:rgba(10,10,12,.42);border:1px solid rgba(245,245,247,.14);
  backdrop-filter:blur(16px) saturate(160%);
  -webkit-backdrop-filter:blur(16px) saturate(160%);
  transition:background .3s var(--e),transform .3s var(--e),border-color .3s var(--e)}
.reelnext:hover{background:rgba(10,10,12,.66);border-color:rgba(245,245,247,.3);
  transform:translateX(-50%) translateY(-3px)}
.reelnext:focus-visible{outline:2px solid var(--red-hi);outline-offset:3px}
.rnlab{font-size:.78rem;font-weight:600;letter-spacing:.16em;text-transform:uppercase;
  color:var(--white);opacity:.92}
.rnarrow{width:1px;height:1.5rem;background:linear-gradient(var(--white),transparent);
  position:relative;animation:rnDrift 1.9s var(--e) infinite}
.rnarrow::after{content:"";position:absolute;left:50%;bottom:0;
  width:.42rem;height:.42rem;margin-left:-.21rem;
  border-right:1.4px solid var(--white);border-bottom:1.4px solid var(--white);
  transform:rotate(45deg);opacity:.9}
@keyframes rnDrift{0%,100%{transform:translateY(0);opacity:.95}
  50%{transform:translateY(5px);opacity:.55}}

@media (max-width:640px){
  .reelclose{top:1rem;right:1rem;padding:.5rem .8rem;font-size:.72rem}
  .reelnext{bottom:1.1rem;padding:.55rem 1rem .45rem}
  .rnarrow{height:1.1rem}
}
@media (prefers-reduced-motion:reduce){ .rnarrow{animation:none} }

/* While the reel runs, the next-up cue would sit on top of the scrubber.
   The close button is the exit then, so the cue steps aside and comes back
   the moment the reel stops. */
.reelbox.playing .reelnext{opacity:0;pointer-events:none;
  transform:translateX(-50%) translateY(10px)}
.reelnext{opacity:1}

/* ==========================================================
   Phones.

   Measured on an iPhone viewport with touch emulation, because that is what
   makes (hover:none) match — a narrow window with a mouse reports a site no
   phone will ever see.
   ========================================================== */
@media (max-width:760px){

  /* ---- the showreel background ----
     The loop is a 2.39:1 cut. Poured into a portrait phone with `cover` it
     was being blown up about five times and cropped to a thin horizontal
     sliver — the screenshot looked like a pixelated still of something
     else entirely. `contain` shows the cut as it was graded, in a band
     across the middle of a black screen, which is how a reel is supposed
     to look anyway. */
  .reelbg{object-fit:contain!important}
  /* With the film no longer filling the screen, the title needs its own
     space rather than sitting on top of the picture. */
  /* The band sits a little above centre so the title and the play disc get
     the lower third to themselves, and the padding clears the next-section
     cue at the very bottom — at 4.6rem "Play with sound" was landing right
     on top of it. */
  .reelbg{object-position:50% 38%}
  .reelbox .play{justify-content:flex-end;padding-bottom:7.4rem;gap:.8rem;
    background:linear-gradient(transparent 38%,rgba(0,0,0,.78))}
  .reelbox .play .disc{width:66px;height:66px}
  /* A shorter pin. 190vh of held screen is a long time on a thumb. */
  .reel{height:150vh}
  /* Clear of the home indicator. */
  .reelnext{bottom:calc(1.1rem + env(safe-area-inset-bottom,0px))}
  .reelclose{top:calc(1rem + env(safe-area-inset-top,0px))}

  /* ---- tap targets ----
     Apple's floor is 44x44pt and almost every control here was under it:
     the menu button was 70x26. Padding does the work rather than font size,
     so nothing is redrawn — the targets just stop being slivers. */
  .menubtn{min-height:44px;padding:.55rem .2rem .55rem .7rem}
  .nav .mark{min-height:44px;display:inline-flex;align-items:center}
  .lnk{display:inline-flex;align-items:center;min-height:44px}
  .bigmail{display:inline-flex;align-items:center;min-height:44px}
  .filters button{min-height:44px;padding-inline:1.05rem}
  .mobmenu a,.mobmenu .ml{min-height:44px;display:flex;align-items:center}
  .vp-b{width:44px;height:44px}
  .vp-bar{gap:.5rem}
  /* The scrubber is the one control people miss on a phone: give it a
     taller invisible grab area without making the line itself thicker. */
  .vp-scrub{height:2.2rem}
  .alv-strip button{min-height:44px}

  /* ---- text that was too small to read ----
     Several tracked labels sat at 9.7–11.8px. At arm's length on a phone
     that is a smudge, and uppercase tracking makes it worse, so the floor
     here is 12px with the tracking eased off slightly to keep the words
     from running together at the smaller size. */
  .lab,.chapter span,.mtop,.psub,.hcol-hint,.filters .count,
  .specs > div > span,.steps .step p,.card em,.pitem em{
    font-size:max(12px,.78rem);letter-spacing:.1em}
  .hcol-hint{font-size:12px}
  dt{font-size:max(12px,.8rem)}

  /* ---- the three service tiles ----
     Two-up left the third stranded in a half-width box of its own. One
     column reads as a deliberate list instead of a broken grid. */
  /* ---- the three service tiles ----
     Two columns left the third stranded in a half-width box with empty
     space beside it. Three across fixed the orphan but squeezed the labels
     — "Projection mapping" does not fit in a third of a phone. So: two on
     top, the third spanning the full width underneath. No orphan, and
     every label gets room to sit on one line. */
  .stack3d{grid-template-columns:repeat(2,1fr);gap:.55rem}
  .stack3d a.tile:nth-of-type(3){grid-column:1/-1;aspect-ratio:16/9}
  .tile .lab{font-size:12px;padding:.5rem .6rem;letter-spacing:.06em}

  /* ---- text that was below the readable floor ----
     These are the exact selectors the audit found, rather than the bare
     class names I reached for first — the originals are more specific and
     simply won. Nothing is restyled, only floored at 12px, with the
     uppercase tracking eased so the words do not run together. */
  .cap span,
  .pcard .chips li,
  .card .meta .mtop,
  .crd dt,
  .nav a.ml span,
  .mobmenu a.ml span,
  .pitem .pm .lab{font-size:max(12px,.76rem);letter-spacing:.09em}
  /* The skip link is keyboard-only, but there is no reason for it to be
     the one control under the floor. */
  .skip{min-height:44px;display:inline-flex;align-items:center}
  /* The menu panel's own links. They sit in a bare <nav>, not under the
     class I first reached for, which is why the earlier rule missed them —
     41x18 is not a tap target on a phone. */
  a.ml{min-height:44px;display:flex;align-items:center}
  /* Full-width rows in the menu panel: the link was only as wide as its
     own word, so "Projects" was a 43px target in the middle of an empty
     row. The whole row should take the tap. */
  #mobmenu a.ml{width:100%}
  a.ml span{font-size:max(12px,.8rem)}
  /* A hair over the floor, so a sub-pixel line-height cannot round under it. */
  .lnk,.bigmail{min-height:46px}
}

/* Landscape on a phone: the pinned reel has almost no height to work with,
   so the pin is dropped entirely rather than squeezing the controls. */
@media (max-width:900px) and (orientation:landscape) and (max-height:500px){
  .reel{height:auto}
  .reelpin{position:relative;height:auto;aspect-ratio:21/9}
}
