@import url('/assets/css/cinematic-foundation.css?v=c4bfe18fa517e50f');
:root{--paper:#f7efe2;--wine:#762536;--maison-red:#842139}
*{box-sizing:border-box}
/* Snap is off by default and comes back only inside a guard. `proximity` was the
   previous setting and it never actually engaged with a wheel -- it only fires when the
   scroll already stops near a snap point -- so the scenes read as not snapping at all.
   `mandatory` is what makes a scene settle, and on its own it is safe: the F-02 landscape
   trap needed all four of `mandatory` + `scroll-snap-stop:always` + `overflow:hidden` on a
   scene + scenes forced to a fixed 680px inside a 393px viewport. Only the first is back.
   The rules that keep it safe and MUST hold:
     - `none` is the base, so anything outside the guard never snaps;
     - no `scroll-snap-stop` anywhere -- a fast flick may still cross several scenes;
     - `none` under prefers-reduced-motion;
     - scenes are `100svh` with `height:auto`, never a fixed px height, so a scene is
       never taller than the snap step by construction.
   The min-height half of the guard is the one that matters: on a short viewport -- a
   phone in landscape -- a scene is taller than the screen, and snapping there is what
   stranded the bottom of every scene. 48rem/44rem lets tablets and laptops snap and
   keeps every phone and every short viewport out. */
html{scroll-behavior:smooth;scroll-snap-type:none}
@media(min-width:48rem) and (min-height:44rem){
  html{scroll-snap-type:y mandatory}
  /* One scene per gesture. Without this, mandatory only settles once a wheel or
     trackpad gesture fully ends, so momentum can leave a scene part-shown --
     which is what "stopping with a weird amount showing" was.
     This was removed earlier because it was part of the landscape trap, but that
     needed FOUR things together: always + oversized scenes (680px in a 393px
     viewport) + overflow:hidden + snap on at that size. Scenes are now exactly
     100svh and snap is off entirely below this guard, so it is safe here. */
  .scene,.portfolio-finale{scroll-snap-stop:always}
}
@media(prefers-reduced-motion:reduce){html{scroll-snap-type:none}}
body{background:#111;color:var(--paper);font:16px/1.5 Inter,sans-serif;margin:0}
a{color:inherit}
.skip-link{align-items:center;background:var(--ink);color:var(--paper);display:inline-flex;left:10px;min-height:44px;padding:10px 14px;position:fixed;top:10px;transform:translateY(-160%);z-index:100}
.skip-link:focus{transform:none}
a:focus-visible{outline:2px solid currentColor;outline-offset:5px}
.site-header{align-items:center;color:var(--paper);display:grid;grid-template-columns:1fr auto 1fr;left:0;padding:20px var(--edge);position:fixed;right:0;text-shadow:0 1px 14px rgba(0,0,0,.7);top:0;z-index:20}
.site-header.is-over-light{color:var(--ink);text-shadow:none}
.mark,.site-header a{text-decoration:none}
.mark{align-items:center;display:inline-flex;font:700 13px Syne,sans-serif;min-height:44px}
.site-header nav{display:flex;font-size:10px;gap:28px}
.site-header nav a{align-items:center;display:flex;justify-content:center;min-height:44px;min-width:44px}
.header-contact{align-items:center;border:1px solid currentColor;border-radius:999px;display:inline-flex;font:600 10px/1 "Helvetica Neue",Arial,sans-serif;justify-content:center;justify-self:end;letter-spacing:.24em;min-height:44px;padding:0 24px;text-transform:uppercase;transition:background .2s ease,color .2s ease}
.header-contact:hover,.header-contact:focus-visible{background:var(--paper);color:var(--ink);outline:0;text-decoration:none}
.site-header.is-over-light .header-contact:hover,.site-header.is-over-light .header-contact:focus-visible{background:var(--ink);color:var(--paper)}
.counter{font:9px ui-monospace,monospace;justify-self:end;text-transform:uppercase}
.scene{height:auto;min-height:100svh;overflow:hidden;position:relative;scroll-snap-align:start}

.opening{--spot-x:50%;--spot-y:48%;--spot-radius:196px;background:#050505;color:var(--paper);display:grid;grid-template-columns:repeat(12,1fr);isolation:isolate;padding:110px var(--edge) 38px}
.opening-gallery,.opening-veil,.opening-shade{inset:0;pointer-events:none;position:absolute}.opening-gallery{background:#050505 url('/assets/hero/renaissance-arcade-v1.jpg') center/cover no-repeat;filter:saturate(.82) contrast(1.06);transform:scale(1.008);z-index:-4}.opening-veil{background:rgba(3,3,3,.58);-webkit-mask-image:radial-gradient(circle var(--spot-radius) at var(--spot-x) var(--spot-y),transparent 0 24%,rgba(0,0,0,.1) 50%,rgba(0,0,0,.48) 76%,#000 100%);mask-image:radial-gradient(circle var(--spot-radius) at var(--spot-x) var(--spot-y),transparent 0 24%,rgba(0,0,0,.1) 50%,rgba(0,0,0,.48) 76%,#000 100%);z-index:-3}.opening-shade{background:linear-gradient(180deg,rgba(3,3,3,.22),transparent 20%,transparent 74%,rgba(3,3,3,.3));z-index:-2}.opening::before{backdrop-filter:brightness(1.42) saturate(1.08);background:radial-gradient(circle,rgba(247,239,226,.065),rgba(247,239,226,.025) 42%,transparent 76%);border-radius:50%;clip-path:circle(50%);content:"";height:calc(var(--spot-radius)*2.05);left:var(--spot-x);pointer-events:none;position:absolute;top:var(--spot-y);transform:translate(-50%,-50%);width:calc(var(--spot-radius)*2.05);z-index:-1}.grain{background-image:url('/assets/grain.svg');inset:0;mix-blend-mode:soft-light;opacity:.2;pointer-events:none;position:absolute;z-index:0}
.role{font:12px/1.4 ui-monospace,monospace;grid-column:1/5;letter-spacing:.07em;text-transform:uppercase;z-index:1}
.opening h1{align-self:center;-webkit-text-stroke:.45px rgba(255,250,239,.28);font:700 clamp(74px,12vw,190px)/.7 Syne,sans-serif;grid-column:1/-1;letter-spacing:-.09em;margin:0;text-shadow:2px 3px 0 rgba(118,37,54,.58),0 14px 34px rgba(0,0,0,.62),0 2px 8px rgba(0,0,0,.4);transform:translateY(-4vh);z-index:1}
.opening h1 span{display:block}.opening h1 span:last-child{margin-left:38%}
.opening-copy{align-self:end;border-top:1px solid rgba(247,239,226,.78);display:grid;gap:30px;grid-column:7/-1;grid-template-columns:1fr auto;padding-top:15px;z-index:1}
.opening-copy p{font-size:clamp(17px,1.5vw,23px);margin:0}.opening-copy a{align-self:start;text-underline-offset:6px;white-space:nowrap}
.opening-instruction{bottom:40px;font:12px/1.4 ui-monospace,monospace;left:var(--edge);letter-spacing:.07em;margin:0;position:absolute;text-transform:uppercase;z-index:1}.opening-instruction i{background:#efb3c0;border-radius:50%;box-shadow:0 0 14px #efb3c0;display:inline-block;height:6px;margin-right:8px;width:6px}
.selected-work-intro{align-items:center;background:var(--paper);color:var(--ink);display:grid;gap:24px;grid-template-columns:auto 1fr auto;min-height:22svh;padding:clamp(46px,6vh,72px) var(--edge);scroll-snap-align:none}
.selected-work-intro>p{font:12px/1.4 ui-monospace,monospace;letter-spacing:.07em;margin:0;text-transform:uppercase}.selected-work-intro h2{font:700 clamp(42px,6.3vw,98px)/.86 Syne,sans-serif;letter-spacing:-.075em;margin:0}.selected-work-intro>a{border:1px solid rgba(23,19,16,.45);border-radius:50%;display:grid;font-size:16px;height:44px;place-items:center;text-decoration:none;width:44px}
.project{align-items:end;display:grid;grid-template-columns:repeat(12,1fr);padding:110px var(--edge) 42px}
.scene-media{height:100%;inset:0;overflow:hidden;position:absolute}
.scene-media>img,.scene-media>video{height:100%;inset:0;object-fit:cover;position:absolute;width:100%}
.scene-media iframe{background:#08090d;border:0;height:100%;inset:0;position:absolute;width:100%;z-index:1}.scene-media iframe:not([src]),.scene-media iframe[src="about:blank"]{visibility:hidden}
.shade{background:linear-gradient(90deg,rgba(4,4,4,.84),rgba(4,4,4,.3) 48%,rgba(4,4,4,.08)),linear-gradient(transparent 45%,rgba(4,4,4,.68));inset:0;pointer-events:none;position:absolute}
.project-type{align-self:start;font:9px ui-monospace,monospace;grid-column:1/6;letter-spacing:.12em;position:relative;text-transform:uppercase;z-index:6}
.project-copy{grid-column:1/8;position:relative;z-index:4}
.project-copy h2{font:700 clamp(68px,10vw,158px)/.72 Syne,sans-serif;letter-spacing:-.085em;margin:0 0 26px}
.project-copy p{font-size:clamp(17px,1.55vw,24px);max-width:42ch}
.project-copy a{display:inline-block;font-size:11px;margin-top:18px;text-underline-offset:6px}
.project-actions{align-items:center;display:flex;flex-wrap:wrap;gap:24px}
.proof{font:9px ui-monospace,monospace;grid-column:9/-1;justify-self:end;letter-spacing:.1em;position:relative;text-transform:uppercase}
.lightbridge-sequence{--lb-progress:0;min-height:100svh;overflow:visible}.lightbridge-panel{height:100svh;overflow:hidden;position:sticky;top:0}
.lightbridge-dock,.lightbridge-demos article{background:#090911;border:1px solid rgba(196,161,255,.4);box-shadow:0 26px 80px rgba(0,0,0,.58);overflow:hidden;position:absolute;z-index:3}.lightbridge-dock>span,.lightbridge-demos article>span{background:#151520;border-bottom:1px solid rgba(196,161,255,.22);display:block;font:9px ui-monospace,monospace;letter-spacing:.12em;padding:9px 11px;text-transform:uppercase}.lightbridge-dock{left:3vw;opacity:clamp(0,calc(var(--lb-progress)*5),1);top:16svh;transform:translate3d(calc((1 - var(--lb-progress))*-64px),0,0);width:min(43vw,690px)}.lightbridge-dock-screen{position:relative}.lightbridge-dock video{display:block;height:auto;position:static;width:100%}
/* The live source, sized to the CANVAS panel of the capture behind it. The capture
   (lightbridge-interface.mp4, 2800x1524) has Pulsar rendered into that panel, so the
   iframe has to cover it exactly: measured against the frame, the panel is
   x 21.4%-81.8%, y 2.9%-41.0% of .lightbridge-dock-screen, and it does not move for
   the length of the clip. Percentages, so it holds at every dock width. */
.scene-media .lightbridge-dock-source{background:#050508;border:0;height:38.1%;left:21.4%;pointer-events:none;position:absolute;top:2.9%;width:60.4%;z-index:2}
.lightbridge-demos{display:grid;gap:14px;position:absolute;right:3vw;top:11vh;width:min(35vw,520px);z-index:4}.lightbridge-demos article{height:clamp(190px,34vh,330px);opacity:clamp(0,calc((var(--lb-progress) - .24)*4.5),1);position:relative;transform:translate3d(calc((1 - var(--lb-progress))*54px),0,0)}.lightbridge-demos article:nth-child(2){opacity:clamp(0,calc((var(--lb-progress) - .42)*5),1);transform:translate3d(calc((1 - var(--lb-progress))*78px),0,0)}.scene-media .lightbridge-demos iframe{height:calc(100% - 31px);inset:31px 0 0;pointer-events:auto;width:100%}.lightbridge .project-copy{max-width:42vw}.lightbridge .project-copy h2{font-size:clamp(64px,7.1vw,112px)}.lightbridge .shade{background:linear-gradient(90deg,rgba(0,0,0,.86),rgba(0,0,0,.28) 42%,rgba(0,0,0,.08) 67%),linear-gradient(transparent 48%,rgba(0,0,0,.72))}.lightbridge-demo-note{font:9px ui-monospace,monospace;letter-spacing:.1em;margin:0;position:absolute;right:var(--edge);text-transform:uppercase;top:76px;z-index:5}.lightbridge-demo-note span{background:#c8a2ff;border-radius:50%;box-shadow:0 0 12px #c8a2ff;display:inline-block;height:6px;margin-right:7px;width:6px}
.lightbridge-dock{opacity:clamp(0,calc(var(--lb-progress)*5),calc((1 - var(--lb-progress))*3))}
.maison .shade{background:linear-gradient(90deg,rgba(74,20,34,.9),rgba(74,20,34,.2) 65%,rgba(20,5,10,.1))}
.maison .project-copy{grid-column:1/7}
.handiwork .shade{background:linear-gradient(90deg,rgba(4,5,9,.92),rgba(4,5,9,.2) 68%)}.handiwork video{filter:contrast(1.08) saturate(1.08)}
.orbricks .shade{background:linear-gradient(90deg,rgba(10,31,24,.9),rgba(10,31,24,.18) 68%)}.world-frame{opacity:0;pointer-events:none;transition:opacity .45s ease}.world-frame.is-ready{opacity:1}

.practice-reel{--reel-colour:#7156a8;background:radial-gradient(circle at 78% 14%,color-mix(in srgb,var(--reel-colour) 26%,transparent),transparent 32%),#0d1116;color:var(--paper);overflow:hidden;padding:clamp(74px,9vh,110px) 0 0;transition:background .45s ease}.reel-lead{align-items:end;display:grid;gap:30px;grid-template-columns:.5fr 1.45fr .72fr;padding:0 var(--edge)}.reel-lead>p{font:9px ui-monospace,monospace;letter-spacing:.12em;margin:0;text-transform:uppercase}.reel-lead h2{font:700 clamp(52px,7.6vw,118px)/.8 Syne,sans-serif;letter-spacing:-.075em;margin:0}.reel-lead h2 em{font:400 1em Bodoni,serif}.reel-lead>span{font-size:clamp(12px,1vw,15px);max-width:32ch;opacity:.72}.project-reel{cursor:grab;display:flex;gap:clamp(12px,1.6vw,24px);margin-top:clamp(40px,5vw,78px);overflow-x:auto;padding:0 var(--edge) 28px;scroll-snap-type:x mandatory;scrollbar-color:var(--wine) rgba(244,237,223,.1);scrollbar-width:thin}.project-reel.is-dragging{cursor:grabbing;scroll-snap-type:none}.reel-card{border:1px solid color-mix(in srgb,var(--project-colour) 74%,#fff);box-shadow:0 24px 80px color-mix(in srgb,var(--project-colour) 20%,transparent);color:#fff;flex:0 0 min(64vw,880px);height:min(55vh,570px);isolation:isolate;overflow:hidden;position:relative;scroll-snap-align:start;text-decoration:none}.reel-card::before{background:var(--project-colour);content:"";height:5px;inset:0 0 auto;position:absolute;z-index:2}.reel-card::after{background:linear-gradient(180deg,rgba(0,0,0,.02),rgba(0,0,0,.86));content:"";inset:0;position:absolute;z-index:-1}.reel-card img{height:100%;inset:0;object-fit:cover;position:absolute;transition:transform .7s cubic-bezier(.2,.75,.2,1);width:100%;z-index:-2}.reel-card header{display:flex;font:9px ui-monospace,monospace;justify-content:space-between;left:22px;letter-spacing:.08em;position:absolute;right:22px;text-transform:uppercase;top:20px}.reel-card div{align-items:end;bottom:22px;display:flex;gap:20px;justify-content:space-between;left:22px;position:absolute;right:22px}.reel-card strong{font:600 clamp(34px,5vw,78px)/.9 Syne,sans-serif;letter-spacing:-.06em}.reel-card div span{font-size:10px;letter-spacing:.08em;text-transform:uppercase}.reel-card:hover img,.reel-card:focus-visible img{transform:scale(1.035)}.reel-utility{align-items:center;border-top:1px solid rgba(244,237,223,.25);display:grid;font:9px ui-monospace,monospace;grid-template-columns:1fr auto 1fr;letter-spacing:.08em;padding:18px var(--edge) 0;text-transform:uppercase}.reel-utility>div{display:flex}.reel-utility button{background:transparent;border:1px solid rgba(244,237,223,.45);color:inherit;cursor:pointer;height:40px;width:46px}.reel-utility button+button{border-left:0}.reel-utility>a{justify-self:end}
.view-all-world{background:#080707;color:var(--paper);display:block;height:min(92svh,900px);isolation:isolate;margin-top:clamp(56px,8vw,120px);overflow:hidden;position:relative;text-decoration:none}.view-all-world__wall{display:grid;gap:4px;grid-template-columns:repeat(7,1fr);inset:-8%;position:absolute;transform:rotate(-3deg) scale(1.08);z-index:-3}.view-all-world__wall img{filter:saturate(.75);height:100%;min-height:0;object-fit:cover;width:100%}.view-all-world__wall img:nth-child(3n+2){transform:translateY(7%)}.view-all-world__wall img:nth-child(4n){transform:translateY(-6%)}.view-all-world__shade{background:linear-gradient(90deg,rgba(12,3,5,.86),rgba(68,15,30,.42),rgba(4,10,12,.78));inset:0;position:absolute;transition:opacity .45s ease;z-index:-2}.view-all-world::after{background-image:url('/assets/grain.svg');content:"";inset:0;mix-blend-mode:soft-light;opacity:.24;pointer-events:none;position:absolute}.view-all-world__meta,.view-all-world__action{font:9px ui-monospace,monospace;letter-spacing:.1em;position:absolute;text-transform:uppercase;z-index:2}.view-all-world__meta{left:var(--edge);top:clamp(28px,5vw,70px)}.view-all-world__action{bottom:clamp(28px,5vw,70px);right:var(--edge)}.view-all-world>strong{font:600 clamp(92px,19vw,300px)/.72 Syne,sans-serif;left:50%;letter-spacing:-.09em;position:absolute;top:50%;transform:translate(-50%,-50%);white-space:nowrap;z-index:2}.view-all-world:hover .view-all-world__shade,.view-all-world:focus-visible .view-all-world__shade{opacity:.65}

.portfolio-finale{align-items:center;background-color:var(--maison-red);background-image:radial-gradient(circle at 78% 20%,rgba(247,239,226,.12),transparent 30%),radial-gradient(circle at 12% 86%,rgba(39,4,13,.24),transparent 36%),linear-gradient(132deg,rgba(255,189,160,.08),transparent 45%);color:var(--paper);display:grid;grid-template-rows:minmax(0,1fr) auto;min-height:100svh;overflow:hidden;padding:clamp(92px,11vh,132px) var(--edge) 0;position:relative;scroll-snap-align:start;width:100%}.portfolio-finale::before{background-image:url('/assets/grain.svg'),repeating-radial-gradient(ellipse 78% 62% at 8% 104%,transparent 0 54px,rgba(247,239,226,.22) 55px 56px);content:"";inset:0;mix-blend-mode:soft-light;opacity:.62;pointer-events:none;position:absolute}.portfolio-finale::after{background:repeating-linear-gradient(96deg,transparent 0 8px,rgba(255,255,255,.018) 9px 10px);content:"";inset:0;mix-blend-mode:overlay;pointer-events:none}.portfolio-finale>*{position:relative;z-index:1}
.portfolio-finale__pulse{color:var(--paper);inset:0;opacity:.24;pointer-events:none;position:absolute;z-index:0}.portfolio-finale__pulse svg{height:100%;width:100%}.portfolio-finale__pulse path{animation:pulse-draw 4.8s cubic-bezier(.65,0,.35,1) infinite;stroke-dasharray:1;stroke-dashoffset:1}@keyframes pulse-draw{0%{stroke-dashoffset:1;opacity:.15}48%,72%{stroke-dashoffset:0;opacity:1}100%{stroke-dashoffset:-1;opacity:.15}}
.portfolio-finale__contact{display:grid;justify-items:center;text-align:center}.portfolio-finale__eyebrow{font:600 clamp(12px,.8vw,13px)/1.2 ui-monospace,monospace;letter-spacing:.1em;margin:0;text-transform:uppercase}.portfolio-finale__eyebrow span{background:var(--paper);border-radius:50%;display:inline-block;height:7px;margin-right:9px;width:7px}.portfolio-finale h2{font:700 clamp(52px,7.4vw,112px)/.82 Syne,sans-serif;letter-spacing:-.07em;margin:22px 0 0}.portfolio-finale h2 em{display:block;font:400 1em Bodoni,serif}.portfolio-finale__email{align-items:center;backdrop-filter:blur(10px);background:rgba(247,239,226,.08);border:1px solid rgba(247,239,226,.75);border-radius:999px;color:var(--paper);display:inline-flex;font:600 clamp(15px,1.45vw,20px)/1 Inter,sans-serif;gap:14px;justify-content:center;margin-top:34px;max-width:100%;padding:12px 12px 12px 22px;text-decoration:none;transition:background .18s ease,border-color .18s ease,color .18s ease,transform .18s ease}.portfolio-finale__email span{background:var(--paper);border-radius:50%;color:var(--maison-red);display:grid;flex:0 0 auto;height:34px;place-items:center;transition:background .18s ease,color .18s ease;width:34px}.portfolio-finale__email:hover,.portfolio-finale__email:focus-visible{background:var(--finale-gold);border-color:var(--finale-gold);color:var(--ink);transform:translateY(-2px)}
.portfolio-finale__email:focus-visible{outline:2px solid var(--paper);outline-offset:5px}
.portfolio-finale__email:hover span,.portfolio-finale__email:focus-visible span{background:var(--ink);color:var(--finale-gold)}.portfolio-finale__socials{display:flex;gap:22px;margin-top:22px}.portfolio-finale__socials a{font-size:12px;text-underline-offset:5px}
.portfolio-finale__footer{align-items:center;border-top:1px solid rgba(247,239,226,.5);display:grid;font-size:11px;gap:20px;grid-column:1/-1;grid-template-columns:1fr auto 1fr;margin-top:clamp(30px,5vh,62px);padding:22px 0 24px;width:100%}.portfolio-finale__footer nav{display:flex;gap:18px}.portfolio-finale__footer>span:last-child{text-align:right}

@media(max-width:760px){
  .site-header{color:var(--paper);grid-template-columns:1fr auto;mix-blend-mode:normal;padding-block:14px}.site-header nav{background:rgba(23,19,16,.92);bottom:calc(12px + env(safe-area-inset-bottom,0px));gap:0;justify-content:center;left:12px;padding:3px;position:fixed;right:12px}.site-header nav a{color:var(--paper);font-size:9px;justify-content:center;min-height:44px;padding:0 12px}.counter{font-size:8px}
  .opening{display:flex;flex-direction:column;padding-bottom:calc(86px + env(safe-area-inset-bottom,0px));padding-top:82px}.opening-gallery{background-position:center}.opening h1{font-size:16.5vw;margin:auto 0;transform:none;width:100%}.opening h1 span:last-child{margin-left:8%}.opening .grain{transform:none}.opening-copy{display:block;width:100%}.opening-copy p{font-size:clamp(16px,4.3vw,18px);max-width:35ch}.opening-copy a{display:block;margin-top:18px}.opening-instruction{display:none}
  .selected-work-intro{gap:12px;grid-template-columns:1fr auto;min-height:0;padding:50px 18px}.selected-work-intro>p{grid-column:1/-1}.selected-work-intro h2{font-size:13vw}
  /* P3.5 — the column flex context makes align-items horizontal; stretch keeps the copy full-bleed. */
  .project{align-items:stretch;display:flex;flex-direction:column;justify-content:flex-end;padding-bottom:calc(92px + env(safe-area-inset-bottom,0px))}.project-type{margin-bottom:auto}.project-copy h2{font-size:clamp(46px,13vw,60px)}.proof{margin-top:30px}.project-actions{gap:14px}.lightbridge .shade{background:linear-gradient(transparent 34%,rgba(4,4,8,.96) 67%)}.lightbridge-sequence{min-height:100svh}.lightbridge-dock{left:18px;top:17svh;width:calc(100vw - 36px)}.lightbridge-demos{left:18px;right:auto;top:17svh;width:calc(100vw - 36px)}.lightbridge-demos article{height:31vh}.lightbridge .project-copy{max-width:none}.lightbridge .project-copy h2{font-size:clamp(46px,13vw,60px)}.lightbridge-demo-note{display:none}
  .portfolio-finale{display:grid;min-height:100svh;padding:94px 18px 0}.portfolio-finale h2{font-size:clamp(48px,14vw,68px)}.portfolio-finale__pulse svg{height:70%;width:220%}.portfolio-finale__email{font-size:15px;padding-inline:18px 10px}.portfolio-finale__footer{grid-template-columns:1fr;margin-top:70px;padding-bottom:calc(92px + env(safe-area-inset-bottom,0px))}.portfolio-finale__footer nav{flex-wrap:wrap;order:-1}.portfolio-finale__footer>span:last-child{text-align:left}
  .practice-reel{padding-top:70px}.reel-lead{display:block;padding-inline:18px}.reel-lead h2{font-size:14vw;margin-block:18px 22px}.project-reel{margin-top:34px;padding-inline:18px}.reel-card{flex-basis:82vw;height:52vh}.reel-card div{display:block}.reel-card strong{display:block;margin-bottom:10px}.reel-utility{grid-template-columns:1fr auto;padding-inline:18px}.reel-utility>a{grid-column:1/-1;justify-self:start;margin-top:18px}.view-all-world{height:72svh}.view-all-world__wall{grid-template-columns:repeat(4,1fr)}.view-all-world__wall img:nth-child(n+9){display:none}.view-all-world>strong{font-size:24vw}.view-all-world__action{left:18px;right:auto}
  .lightbridge-dock{opacity:clamp(0,calc(var(--lb-progress)*5),calc((.48 - var(--lb-progress))*8))}.lightbridge-demos{gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))}.lightbridge-demos article{height:30vh}.lightbridge-demos article>span{font-size:7px;padding-inline:7px}
}
.contact-page .portfolio-finale{min-height:100svh}.contact-page .portfolio-finale h1{font:700 clamp(52px,7.4vw,112px)/.82 Syne,sans-serif;letter-spacing:-.07em;margin:22px 0 0}.contact-page .portfolio-finale h1 em{display:block;font:400 1em Bodoni,serif}.contact-page .site-header a[aria-current=page]{text-decoration:underline;text-underline-offset:6px}
@media(max-width:760px){.contact-page .portfolio-finale h1{font-size:clamp(48px,14vw,68px)}}
@media(max-width:420px){.site-header nav a{padding-inline:9px}.mark{font-size:11px}}
/* Short viewports: scenes grow to fit their own copy instead of being pinned to a
   fixed height taller than the screen, which made the bottom of every scene unreachable. */
@media(max-height:620px) and (orientation:landscape){
  .scene{height:auto;min-height:100svh}
  .opening{min-height:100svh}
  .project{padding-top:86px}
  .lightbridge-panel{height:auto;min-height:100svh;position:static}
}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}.opening h1{transform:none}.opening-veil{-webkit-mask-image:radial-gradient(circle 46vw at 50% 48%,transparent 0 52%,#000 100%);mask-image:radial-gradient(circle 46vw at 50% 48%,transparent 0 52%,#000 100%)}.opening::before{display:none}.reel-card img,.world-frame{transition:none}.portfolio-finale__pulse path{animation:none;stroke-dasharray:none}}

/* Interview-ready homepage refinements */
.lightbridge-dock{z-index:3}.lightbridge-demos{z-index:4}.lightbridge .shade{z-index:5}.lightbridge .project-type,.lightbridge .project-copy,.lightbridge .proof,.lightbridge-demo-note{z-index:6}

.view-all-section{background:#080707;min-height:100svh;overflow:hidden}.view-all-world{height:100svh;margin:0}.view-all-world__wall{align-content:center;display:grid;gap:clamp(7px,.8vw,14px);grid-template-columns:repeat(4,minmax(0,1fr));inset:-4vw;transform:rotate(-2deg) scale(1.04)}
.view-all-world__wall img,.view-all-world__wall img:nth-child(n){aspect-ratio:16/10;background:#161315;box-shadow:0 14px 36px rgba(0,0,0,.42);filter:saturate(.86) brightness(.78);height:auto;object-fit:contain;transform:none;width:100%}
.view-all-world__shade{background:radial-gradient(circle at 50% 50%,rgba(91,22,42,.14),rgba(5,4,5,.72) 75%),linear-gradient(90deg,rgba(4,4,5,.64),transparent 42%,rgba(4,4,5,.55))}
.view-all-world>strong{font-size:clamp(70px,13vw,220px);line-height:.82;text-align:center;white-space:normal;width:min(92vw,1500px)}

.portfolio-finale{--finale-gold:#d6b46d;background-color:#7f1f32;background-image:radial-gradient(circle at 50% 49%,rgba(224,184,101,.3),transparent 34%),radial-gradient(circle at 50% 50%,rgba(255,243,211,.08),transparent 55%),linear-gradient(135deg,rgba(39,4,13,.18),transparent 45%,rgba(255,210,149,.08));box-shadow:inset 0 2px 0 rgba(214,180,109,.72),inset 0 -2px 0 rgba(214,180,109,.72)}
.portfolio-finale::before{background-image:url('/assets/grain.svg'),repeating-radial-gradient(ellipse 66% 48% at 50% 50%,transparent 0 62px,rgba(244,214,153,.14) 63px 64px);background-position:center;opacity:.56}
.portfolio-finale__pulse{color:var(--finale-gold);opacity:.25}.portfolio-finale__pulse .pulse-base{opacity:.2}.portfolio-finale__pulse .pulse-signal{animation:pulse-flow 4.8s linear infinite;filter:drop-shadow(0 0 4px rgba(255,220,145,.34));stroke-dasharray:.16 .84;stroke-dashoffset:0}
@keyframes pulse-flow{to{stroke-dashoffset:-1}}
.portfolio-finale__eyebrow span{background:var(--finale-gold);box-shadow:0 0 6px rgba(255,216,137,.34)}.portfolio-finale__email{border-color:rgba(224,194,132,.86)}.portfolio-finale__email span{background:var(--finale-gold)}.portfolio-finale__footer{border-top:0}
.contact-page .portfolio-finale__return{left:var(--edge);margin:0;position:absolute;top:calc(72px + clamp(22px,4vw,48px));z-index:4}.contact-page .portfolio-finale__return a{color:inherit;text-decoration:none}.contact-page .portfolio-finale__return a:hover,.contact-page .portfolio-finale__return a:focus-visible{text-decoration:underline;text-underline-offset:6px}

@media(max-width:760px){
  .view-all-world__wall{gap:7px;grid-template-columns:repeat(2,minmax(0,1fr));inset:-4vh -18vw;transform:rotate(-2deg) scale(1.03)}.view-all-world__wall img:nth-child(n){display:block}.view-all-world>strong{font-size:21vw;width:92vw}.view-all-world__meta{left:18px}.view-all-world__action{bottom:28px}
  .portfolio-finale__pulse svg{height:100%;width:240%}
}
@media(prefers-reduced-motion:reduce){.portfolio-finale__pulse .pulse-signal{animation:none;stroke-dasharray:none}
  .portfolio-finale__email,.portfolio-finale__email span{transition:none}
  .portfolio-finale__email:hover,.portfolio-finale__email:focus-visible{transform:none}}

/* September launch polish */
.opening{--reveal-radius:clamp(190px,17vw,285px);--spot-radius:106px;background:#0b0a09}
.opening-gallery{filter:brightness(.7) saturate(.88) contrast(1.03);transform:none}
.opening-veil{background:rgba(3,3,3,.24);-webkit-mask-image:radial-gradient(circle var(--spot-radius) at var(--spot-x) var(--spot-y),transparent 0 34%,rgba(0,0,0,.08) 56%,rgba(0,0,0,.48) 100%);mask-image:radial-gradient(circle var(--spot-radius) at var(--spot-x) var(--spot-y),transparent 0 34%,rgba(0,0,0,.08) 56%,rgba(0,0,0,.48) 100%)}
.opening::before{backdrop-filter:none;background:url('/assets/hero/renaissance-arcade-v1.jpg') center/cover no-repeat;border-radius:0;box-shadow:none;clip-path:none;filter:brightness(1.48) saturate(1.12) contrast(1.04);height:auto;inset:0;left:0;-webkit-mask-image:radial-gradient(circle var(--reveal-radius) at var(--spot-x) var(--spot-y),#000 0 62%,rgba(0,0,0,.92) 72%,rgba(0,0,0,.3) 88%,transparent 100%);mask-image:radial-gradient(circle var(--reveal-radius) at var(--spot-x) var(--spot-y),#000 0 62%,rgba(0,0,0,.92) 72%,rgba(0,0,0,.3) 88%,transparent 100%);top:0;transform:none;width:auto}
.selected-work-intro{background:#0b0a0d;border-bottom:1px solid rgba(196,161,255,.22);border-top:1px solid rgba(247,239,226,.14);color:var(--paper);gap:18px;min-height:0;padding:24px var(--edge)}
.selected-work-intro h2{font-size:clamp(25px,2.6vw,42px);letter-spacing:-.045em}
.selected-work-intro>a{border-color:rgba(247,239,226,.35);height:44px;width:44px}
.project-copy a{font-size:clamp(18px,1.4vw,23px);font-weight:600;text-decoration-thickness:1px;text-underline-offset:9px}
.project-actions{gap:clamp(18px,2vw,34px)}
.lightbridge-dock{left:auto;opacity:1;right:3vw;top:max(94px,15svh);transform:none;width:min(48vw,760px)}
.lightbridge-dock>span{font-size:11px;padding:11px 14px}
.lightbridge .shade{background:linear-gradient(90deg,rgba(0,0,0,.88),rgba(0,0,0,.36) 43%,rgba(0,0,0,.08) 72%),linear-gradient(transparent 54%,rgba(0,0,0,.76))}
.lightbridge-demo-note{font-size:11px}
.orbricks-live{background:#06243a}.orbricks-live>img{filter:saturate(.9);object-position:center}.orbricks-live .world-frame{background:#06243a}
.view-all-world__action{align-items:center;display:flex;font-size:12px;gap:14px}
.view-all-world__action i{align-items:center;border:1px solid rgba(247,239,226,.72);border-radius:50%;display:inline-flex;font:400 18px/1 Inter,sans-serif;height:42px;justify-content:center;transition:background .2s ease,color .2s ease;width:42px}
.view-all-world:hover .view-all-world__action i,.view-all-world:focus-visible .view-all-world__action i{background:var(--paper);color:var(--ink)}
.view-all-world:hover .view-all-world__wall img,.view-all-world:focus-visible .view-all-world__wall img{filter:saturate(1) brightness(.9)}
.view-all-world__wall img{transition:filter .45s ease,transform .7s cubic-bezier(.2,.8,.2,1)}
.portfolio-finale{background-color:#47121d;background-image:radial-gradient(circle at 50% 48%,rgba(156,61,80,.255),transparent 38%),radial-gradient(circle at 50% 50%,rgba(219,178,98,.085),transparent 58%),linear-gradient(135deg,rgba(20,3,8,.6),transparent 46%,rgba(87,43,31,.153));box-shadow:inset 0 0 92px rgba(17,2,7,.5);scroll-snap-align:start}
.portfolio-finale::before{background-image:url('/assets/grain.svg'),repeating-radial-gradient(ellipse 58% 44% at 50% 50%,transparent 0 52px,rgba(244,214,153,.1) 53px 54px);background-position:center;opacity:.48}
.portfolio-finale__pulse{left:0;opacity:.18;right:0}.portfolio-finale__contact{justify-self:center;width:100%}
.portfolio-finale__email{margin-left:auto;margin-right:auto}
.portfolio-finale__linkedin{align-items:center;color:inherit;display:flex;font-size:15px;justify-content:center;margin:12px auto 0;min-height:44px;text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:6px;width:max-content}

@media(min-width:761px){
  .portfolio-finale{grid-template-rows:minmax(0,1fr) auto;height:100svh;min-height:100svh;padding:84px var(--edge) 0}
  .portfolio-finale::after{background:none;border:1px solid rgba(225,191,119,.9);bottom:78px;inset-block-start:92px;left:clamp(26px,2.6vw,50px);mix-blend-mode:normal;position:absolute;right:clamp(26px,2.6vw,50px);z-index:2}
  .portfolio-finale h2{font-size:clamp(50px,6.6vw,102px)}.portfolio-finale__email{margin-top:25px}.portfolio-finale__socials{margin-top:16px}
  .portfolio-finale__footer{margin-top:0;padding:20px 0 22px}
}

@media(max-width:760px){
  .selected-work-intro{padding:21px 18px}.selected-work-intro h2{font-size:28px}
  .project-copy a{font-size:18px}
  .lightbridge-sequence{min-height:100svh}.lightbridge-dock{left:18px;opacity:1!important;right:18px;top:17svh;transform:none;width:auto}
  .portfolio-finale__pulse svg{height:100%;width:100%}
}

/* Live Dillon's handoff: project index left, scrollable product story right. */
.view-all-section{background:radial-gradient(circle at 24% 34%,#3c1717 0,transparent 32%),linear-gradient(135deg,#090707 0,#1a0d0c 52%,#5c4729 100%);display:grid;grid-template-columns:minmax(410px,.94fr) minmax(0,1.06fr);padding:calc(72px + 3vw) var(--edge) 3vw}
.project-index-copy{align-content:center;display:grid;padding-right:clamp(22px,3vw,54px);position:relative;z-index:2}.project-index-copy>p,.project-index-copy>small{font:12px/1.5 ui-monospace,monospace;letter-spacing:.07em;text-transform:uppercase}.project-index-copy h2{font:700 clamp(78px,8.8vw,176px)/.76 Inter,sans-serif;letter-spacing:-.075em;margin:24px 0 42px}.project-index-copy a{align-items:center;border-bottom:1px solid currentColor;display:flex;font-size:clamp(18px,1.5vw,24px);justify-content:space-between;max-width:520px;min-height:44px;padding-bottom:13px;text-decoration:none}.project-index-copy small{align-self:end;margin-top:clamp(42px,8vh,100px);opacity:.65;text-transform:none}.dillons-preview{align-self:center;border:1px solid rgba(214,180,109,.72);box-shadow:0 34px 90px rgba(0,0,0,.5);height:min(76svh,760px);min-height:0;overflow:hidden;position:relative}.dillons-preview iframe{background:#28130f;border:0;height:100%;inset:0;pointer-events:none;position:absolute;width:100%}
.maison .project-copy{max-width:39vw}
/* The project-index scene on phones: copy on top, the Dillon's panel taking exactly
   what is left of the screen. It used to reserve 58svh for the panel regardless, which
   made the scene ~1.2 screens tall and pushed the panel a long way under the fixed
   bottom bar. The panel still gets a generous share -- it is the scene's only
   picture -- but the copy above it is tightened and the scene now ends 104px clear
   of the bar, the same margin every other scene keeps. */
@media(max-width:760px){.header-contact{grid-column:2;grid-row:1}.view-all-section{grid-template-columns:1fr;grid-template-rows:auto minmax(46svh,1fr);height:auto;min-height:100svh;padding:92px 18px calc(104px + env(safe-area-inset-bottom,0px))}.project-index-copy{padding:0 0 26px}.project-index-copy h2{font-size:17vw;margin:16px 0 24px}.project-index-copy small{margin-top:22px}.dillons-preview{height:auto;min-height:46svh}}
@media(max-width:760px){.maison .project-copy{max-width:none}}

/* One typographic rhythm across the five featured-project scenes. */
.project-copy h2,.lightbridge .project-copy h2,.maison .project-copy h2,.project-index-copy h2{font:700 clamp(60px,6.6vw,108px)/.76 Syne,sans-serif;letter-spacing:-.075em}
.orbricks .project-copy{max-width:44vw}.orbricks .project-copy h2 span{display:block}
.project-type,.project-index-copy>p{font:600 12px/1.45 ui-monospace,monospace;letter-spacing:.08em;text-transform:uppercase}
.project-index-copy h2{margin:24px 0 42px}

/* The scene's ground is the Fractal Glow source, full bleed -- a recording, because the
   dock below holds the page's ONE live Lightbridge document and a second iframe is the
   defect this replaced. The visual is neon line-work on true black, so dimming it does
   not grey the field: black stays black and only the rings come down, which is why the
   fractal still reads at this setting.

   Both brightness values below are MEASURED, not chosen. The method: take the
   per-pixel maximum over all 288 frames of the loop (a strict upper bound on any single
   frame, since upscaling is a convex combination), composite it under .shade, and read
   the brightest pixel behind each glyph run. .66 is the highest value at which the
   headline, the body copy and the "01 / ..." eyebrow all clear 4.5:1 against --paper at
   every viewport in the reference matrix. Raising it fails 852x393 first -- the short
   landscape layout puts the copy at the TOP of the scene, where .shade's vertical layer
   has not started yet. Re-measure before changing any of them. */
.scene-media>.lightbridge-glow{filter:brightness(.66) saturate(1.12)}
/* P1.4 — the phone .shade is a much lighter wash than the wide one (.7 -> .12 across
   the width, and nothing at all above 24%), and the eyebrow sits right in that band at
   full bleed. Phones only ever see the poster -- isLite() gates the source, so the video
   never hydrates at this width -- and even the poster leaves the eyebrow under 5:1 at the
   wide setting, so the media comes down further here. This is the P1.4 "lowered media
   brightness" surface, not a different treatment. */
@media(max-width:760px){.scene-media>.lightbridge-glow{filter:brightness(.5) saturate(1.12)}}
.lightbridge-dock video{filter:brightness(1.22) contrast(1.05) saturate(1.08)}
.lightbridge-dock-source{filter:brightness(1.26) saturate(1.16)}

/* Preserve the brighter gallery while giving the statement a stable reading field. */
.opening-copy{background:linear-gradient(90deg,rgba(5,5,6,.7),rgba(5,5,6,.4));border-top-color:rgba(247,239,226,.92);box-shadow:0 20px 44px rgba(0,0,0,.18);padding:17px 20px 16px;text-shadow:0 2px 14px rgba(0,0,0,.95)}

@media(max-width:760px){
  .project-copy h2,.lightbridge .project-copy h2,.maison .project-copy h2,.project-index-copy h2{font-size:clamp(46px,13vw,60px)}
}

/* ---------------------------------------------------------------------------
   Responsive phase 0. These sit last because several of the rules they correct
   are themselves late unqualified re-declarations; specificity is unchanged, so
   source order is what decides.
   --------------------------------------------------------------------------- */

/* P2.1 — the inline "View project ↗" keeps its type size and gains a 44px hit area. */
.project-copy a{align-items:center;display:inline-flex;min-height:44px}

/* P6.4 — the Dillon's embed is lazy like every other embed on the page, so the panel
   itself carries the resting state. It paints the demo's own ground (the gradient the
   embed stylesheet gives .m7-atmosphere), so the pre-load and no-JS states are a quiet
   dark panel that the live experience simply fills in. A product still was tried here
   and removed: it did not match the dark editorial scene behind it, so it read as a
   beige flash a few frames before being replaced. Never put an image back. */
.dillons-preview{background:radial-gradient(circle at 70% 48%,rgba(181,101,61,.36),transparent 34%),linear-gradient(110deg,#100c0b 5%,#5e2d27 54%,#4a4c25)}
.dillons-preview iframe:not([src]),.dillons-preview iframe[src="about:blank"]{visibility:hidden}

@media(max-width:760px){
  /* P1.4 — .maison/.handiwork/.orbricks each replace the whole `background`
     shorthand and so drop the base .shade's vertical layer. On mobile the copy is
     full-bleed, so it needs its own bottom scrim over the brightest frame. */
  .maison .shade{background:linear-gradient(90deg,rgba(74,20,34,.72),rgba(74,20,34,.28) 62%,rgba(20,5,10,.16)),linear-gradient(transparent 22%,rgba(22,5,11,.78) 48%,rgba(14,3,7,.96) 72%)}
  .handiwork .shade{background:linear-gradient(90deg,rgba(4,5,9,.72),rgba(4,5,9,.26) 64%),linear-gradient(transparent 22%,rgba(4,5,9,.82) 48%,rgba(3,4,7,.97) 72%)}
  .orbricks .shade{background:linear-gradient(90deg,rgba(10,31,24,.72),rgba(10,31,24,.24) 64%),linear-gradient(transparent 22%,rgba(5,20,16,.8) 48%,rgba(3,14,11,.96) 72%)}
  .lightbridge .shade{background:linear-gradient(90deg,rgba(0,0,0,.7),rgba(0,0,0,.3) 48%,rgba(0,0,0,.12) 72%),linear-gradient(transparent 24%,rgba(4,4,8,.84) 50%,rgba(2,2,5,.96) 74%)}

  /* The scene number sits above the media (z-index:6), so on Maison it landed on the
     cream carousel and half of every glyph disappeared. The carousel's own owner block
     below drops it clear of the eyebrow band; the eyebrow gets its own contrast
     wherever the media is bright. */
  .project-type{text-shadow:0 1px 12px rgba(0,0,0,.85),0 0 3px rgba(0,0,0,.6)}

  /* P3.5 / F-03 — Orbricks was the one scene whose desktop max-width was never
     reset, so the column flex context shrink-wrapped it to a 172px right-hand strip. */
  .orbricks .project-copy{max-width:none}

  /* F-19 — Work/About/Résumé already live in the fixed bottom bar; the footer
     repeats them 40px above it. One copy is enough on a phone. */
  .home-page .portfolio-finale__footer nav{display:none}
}

/* ---------------------------------------------------------------------------
   .maison-carousel — SINGLE GEOMETRY OWNER.

   This element previously carried twelve competing declarations across six media
   contexts, almost all `!important`, mixing `aspect-ratio` with fixed `height` and
   `vh` with `svh`; whichever landed last per breakpoint decided the box, so it
   reshaped on every edit and letterboxed. Every geometry property for it is now
   declared here and nowhere else in this file.

   The `!important`s existed because `.scene-media>video` (0,1,1) outranks
   `.maison-carousel` (0,1,0). That is fixed with specificity, not force: the owner
   selector is `.scene-media>.maison-carousel` (0,2,0).

   Rules for the next editor:
   - the clip is 1440x600, so the box is authored at 12/5 and the height is always
     DERIVED. Setting a height at any breakpoint is what brings the bands back;
   - `svh` only, never bare `vh`;
   - no `!important`;
   - breakpoints override individual properties below, they never re-declare the box;
   - do not add another `.maison-carousel` rule elsewhere in this file.
   --------------------------------------------------------------------------- */
.scene-media>.maison-carousel{
  aspect-ratio:12/5;
  background:#f4eddf;
  border:1px solid rgba(255,243,227,.72);
  box-shadow:0 24px 70px rgba(31,10,14,.34);
  display:block;
  height:auto;
  /* Bottom-aligned, not top-aligned: 42px is .project's own bottom padding, so the
     preview's bottom edge lands on the same baseline as the last line of the copy
     block to its left and the two read as one row instead of a card floating high
     over the scene. Verified at 1280x800, 1440x900 and 1512x982. */
  inset:auto var(--edge) 42px auto;
  object-fit:cover;
  overflow:hidden;
  position:absolute;
  top:auto;
  /* 52vw, not 55: at 1440 the 55vw box put its left edge exactly on the copy
     block's right edge, with no gutter between them. */
  width:min(52vw,880px);
  z-index:2;
}
/* Phones: a full-bleed BAND, not a card. It is anchored to the measured top of the
   copy block (--copy-h, published by cinematic-home.js) so the scene stacks
   eyebrow / media / band / copy at every height, and --band-room lets it crop
   rather than collide when a short phone cannot give it its whole derived height.
   `max-height` is not a height: the box is still derived from width x 12/5 and
   object-fit:cover means it can only ever crop, never letterbox. */
@media(max-width:760px){
  .scene-media>.maison-carousel{
    border-inline:0;
    bottom:calc(var(--pad-b) + var(--copy-h,210px) + var(--band-gap));
    inset-inline:0;
    max-height:var(--band-room);
    width:100%;
  }
}
/* Short viewports: narrower so the derived height clears the fixed header and still
   leaves the copy below it reachable. */
/* Short viewports: narrower, so the derived height still clears the fixed header
   above the bottom baseline it now shares with the copy. `top` stays `auto` — a
   `top` here would combine with the owner's `bottom` to set the height directly,
   which is exactly the letterboxing the owner block exists to prevent. */
@media(max-height:620px) and (orientation:landscape){
  .scene-media>.maison-carousel{width:min(46vw,640px)}
}

/* The dock is a photograph of a desktop application. There is no height at which
   350 CSS pixels of it is legible -- the earlier rules only argued about where to
   put something unreadable -- so on a phone it is gone and the Fractal Glow
   backdrop is the scene. See the phone composition block at the end of this file. */

/* ===========================================================================
   PHONE HOME PAGE — a composition of its own, not the desktop one shrunk.
   ===========================================================================

   The desktop scene is: full-bleed media, eyebrow top-left, copy bottom-left.
   The phone scene is the same idea stacked, and every rule below exists to make
   one of those three parts survive a 390px-wide, 844px-tall, chrome-on-both-ends
   screen. Everything here is scoped to .home-page or to a home-only class, and it
   sits at the end of the file on purpose: several of the rules it corrects are
   themselves late unqualified re-declarations, so source order is what decides.

   Fixed chrome is 72px of header at the top and a 52px pill 12px off the bottom.
   Content clears both by construction, not by a pixel or two.
   ------------------------------------------------------------------------- */

@media (max-width: 760px) {

  /* -- 1. The header gets a ground ----------------------------------------
     It is fixed and transparent over full-bleed media, so "Selected projects"
     and "View project ↗" used to scroll straight through the wordmark and the
     Contact pill. The scrim fades in once the page has moved at all: the opening
     is dark enough not to need it, and the hero reads better without it.
     chrome-universal.css is not ours to edit, so this is done from here and wins
     on specificity (.home-page .site-header) as well as on order. */
  .home-page .site-header::before {
    background: linear-gradient(180deg, rgba(7,6,9,.98) 0, rgba(7,6,9,.96) 52%, rgba(7,6,9,.62) 80%, rgba(7,6,9,0) 100%);
    content: "";
    inset: 0 0 -18px;
    opacity: 0;
    pointer-events: none;
    position: absolute;
    transition: opacity .28s ease;
    z-index: -1;
  }
  .home-page .site-header.is-scrolled::before { opacity: 1; }
  /* The is-over-light flip is gone from the JS: .selected-work-intro has been dark
     since the September pass, so it was painting near-black type on a near-black
     bar. Anything that still carries the class stays legible. */
  .home-page .site-header.is-over-light { color: var(--paper); text-shadow: 0 1px 14px rgba(0,0,0,.7); }

  /* -- 2. The bottom bar becomes an object, not a translucent smear --------
     Copy scrolls past it constantly (phones do not snap), so it has to read as a
     control floating over the page rather than as a wash the text half-shows
     through. */
  .home-page .site-header nav {
    background: rgba(10,8,12,.94);
    -webkit-backdrop-filter: blur(16px) saturate(1.25);
    backdrop-filter: blur(16px) saturate(1.25);
    border: 1px solid rgba(247,239,226,.18);
    border-radius: 999px;
    box-shadow: 0 14px 38px rgba(0,0,0,.55), 0 1px 0 rgba(247,239,226,.06) inset;
    gap: 2px;
    left: 14px;
    padding: 4px;
    right: 14px;
  }
  .home-page .site-header nav a { border-radius: 999px; letter-spacing: .1em; text-transform: uppercase; }

  /* -- 3. Phone scene composition -----------------------------------------
     --pad-b is the one number that keeps copy off the pill: 12px offset + 52px
     pill + 40px of real air. --copy-h is measured and published by
     cinematic-home.js, because the copy block is bottom-anchored and its height
     depends on width, scene and web-font arrival; the media bands below hang off
     it. --band-room is what is left for a band once the eyebrow, the copy and
     both pieces of chrome have taken their share. */
  .home-page .project {
    --band-gap: 26px;
    --pad-b: calc(104px + env(safe-area-inset-bottom, 0px));
    /* 128px is the eyebrow's own zone: 92px of scene padding, the 17px line, and
       19px of air under it. A band is allowed to crop into that room, never past it. */
    --band-room: max(72px, calc(100svh - var(--pad-b) - var(--copy-h, 210px) - var(--band-gap) - 128px));
    padding-bottom: var(--pad-b);
    padding-top: 92px;
  }
  .home-page .project-copy h2,
  .home-page .lightbridge .project-copy h2,
  .home-page .maison .project-copy h2 { font-size: clamp(44px, 12.4vw, 58px); margin: 0 0 16px; }
  .home-page .project-copy p { font-size: 17px; line-height: 1.5; margin: 0; max-width: 34ch; }
  .home-page .project-copy a { margin-top: 12px; }
  .home-page .project-type { letter-spacing: .1em; }

  /* -- 4. Scrims, re-oriented for portrait AND anchored to the copy --------
     The desktop shades are horizontal: they darken the left third, where the copy
     lives on a wide screen. On a phone the copy is full-bleed at the BOTTOM, so a
     left-to-right wash is both wrong for the composition and useless for
     legibility — it dims half the artwork and none of the text's ground.

     The stops are in pixels off the bottom edge rather than percentages, keyed to
     the same --copy-h the bands use, so the dark band is exactly as tall as the
     copy turns out to be. Percentages cannot do this: at 320x568 the copy is 36%
     of the scene and at 430x932 it is 22%, so any single set of percentage stops
     is either too weak on the small phone or eats the artwork on the large one.
     Each scene keeps its own tint; only the geometry is shared. */
  .home-page .scene .shade {
    --scrim-deep: 2,2,4;
    --scrim-body: 5,4,7;
    background:
      linear-gradient(to top,
        rgba(var(--scrim-deep),.97) 0,
        rgba(var(--scrim-deep),.95) var(--pad-b),
        rgba(var(--scrim-body),.86) calc(var(--pad-b) + var(--copy-h, 210px)),
        rgba(var(--scrim-body),.30) calc(var(--pad-b) + var(--copy-h, 210px) + 86px),
        rgba(var(--scrim-body),0)   calc(var(--pad-b) + var(--copy-h, 210px) + 152px)),
      linear-gradient(180deg,
        rgba(var(--scrim-body),.86) 0, rgba(var(--scrim-body),.80) 96px,
        rgba(var(--scrim-body),.64) 126px, rgba(var(--scrim-body),.26) 180px,
        rgba(var(--scrim-body),0) 250px);
  }
  .home-page .maison .shade   { --scrim-deep: 11,2,6;  --scrim-body: 38,9,18; }
  .home-page .handiwork .shade{ --scrim-deep: 2,2,5;   --scrim-body: 4,5,10; }
  .home-page .orbricks .shade { --scrim-deep: 2,8,7;   --scrim-body: 6,22,18; }

  /* -- 5. Lightbridge: the backdrop IS the scene --------------------------- */
  .home-page .lightbridge-dock { display: none; }
  /* Lightbridge is the one scene whose ground is already true black, so the wash
     the other three need over photography would only mute the artwork here and buy
     no contrast at all. Same copy-anchored geometry, much lighter hand. */
  .home-page .lightbridge .shade {
    background:
      linear-gradient(to top,
        rgba(1,1,3,.94) 0,
        rgba(2,2,4,.84) var(--pad-b),
        rgba(3,3,6,.68) calc(var(--pad-b) + var(--copy-h, 210px)),
        rgba(3,3,6,.24) calc(var(--pad-b) + var(--copy-h, 210px) + 46px),
        rgba(3,3,6,0)   calc(var(--pad-b) + var(--copy-h, 210px) + 92px)),
      linear-gradient(180deg, rgba(3,3,6,.80) 0, rgba(3,3,6,.72) 134px, rgba(3,3,6,.30) 178px, rgba(3,3,6,0) 236px);
  }
  /* The phone encode is the whole Fractal Glow frame, edge-feathered and composed
     into a 540x1014 portrait canvas of true black: artwork in the upper half, empty
     black where the copy goes. Nothing bright ever sits behind type here, which is
     why it can run near full brightness where the old centre-cropped 16:9 could not.

     `contain`, not `cover`, because the cut is already composed for a portrait
     screen and cropping it is pure loss — at 320x568 cover pushed the artwork up
     under the "01 / …" eyebrow. The letterbox that `contain` leaves is invisible
     twice over: the scene's ground is the same true black as the clip's (see
     .lightbridge .scene-media at the end of this file), and the artwork dissolves
     into that black well before the frame edge, so there is no seam to see even on
     the frames where the fractal expands to fill the whole frame. */
  .home-page .scene-media > .lightbridge-glow { filter: brightness(.94) saturate(1.12); object-fit: contain; }

  /* -- 6. Bands: Maison's carousel and HandiWork's demo --------------------
     Both are 16:9-ish screen recordings. A portrait cover crop keeps the middle
     24% of their width, which for HandiWork throws away both hands — the subject
     of the piece. So on a phone they play full-bleed WIDE, as a band anchored to
     the top of the copy block, over a ground that fills the rest of the scene.
     Maison's ground is the campaign still it already loads; HandiWork has no
     still of its own, so the scene enlarges and blurs its poster into one. */
  .home-page .handiwork .scene-media::before {
    animation: scene-drift 40s ease-in-out infinite alternate;
    background: url('/assets/work/video/handiwork-phone-poster.jpg') center/cover no-repeat;
    content: "";
    filter: blur(26px) saturate(.72) brightness(.54);
    inset: -70px;
    position: absolute;
  }
  .home-page .handiwork .scene-media > video {
    aspect-ratio: 780 / 422;   /* the phone encode's own frame; height is derived */
    border-block: 1px solid rgba(247,239,226,.22);
    bottom: calc(var(--pad-b) + var(--copy-h, 210px) + var(--band-gap));
    box-shadow: 0 22px 60px rgba(0,0,0,.5);
    height: auto;
    inset-inline: 0;
    max-height: var(--band-room);
    object-fit: cover;
    top: auto;
    width: 100%;
    z-index: 2;
  }

  /* -- 7. Orbricks keeps a still (three.module.js is 1.2MB before it draws a
     pixel), so the scene is given motion the cheap way instead of none at all. */
  .home-page .orbricks .scene-media > img { animation: scene-drift 34s ease-in-out infinite alternate; will-change: transform; }

  /* -- 8. The two closing scenes clear the pill by the same margin --------- */
  .home-page .view-all-section { padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }
  .home-page .portfolio-finale__footer { padding-bottom: calc(104px + env(safe-area-inset-bottom, 0px)); }
}

@keyframes scene-drift {
  from { transform: scale(1.05) translate3d(-1.4%, 1%, 0); }
  to   { transform: scale(1.13) translate3d(1.4%, -1.6%, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .home-page .orbricks .scene-media > img,
  .home-page .handiwork .scene-media::before { animation: none; transform: none; }
  .home-page .site-header::before { transition: none; }
}

/* ---------------------------------------------------------------------------
   Desktop: the two previews sit on the copy's baseline.

   Both used to open near the top of the scene (15svh / 12svh) and float there
   with the headline far below, so they read as unrelated pop-ups. Their bottom
   edge is now .project's own bottom padding — the same line the last row of the
   copy block sits on — so preview and copy read as one row. The dock's own height
   is derived from its width (min(48vw,760px) against a 2800x1524 capture), so the
   pairing holds at every desktop size: 614x334 at 1280x800, 691x376 at 1440x900,
   726x395 at 1512x982, all of them clear of the 94px header.
   --------------------------------------------------------------------------- */
@media (min-width: 761px) {
  .lightbridge-dock { bottom: 42px; top: auto; }
}

/* The dock's screen is a <canvas> that cinematic-home.js paints from the full-bleed
   backdrop's own decoded frames — see "THE TWO FRACTAL GLOWS ARE ONE" there. It was
   an iframe (a second live Lightbridge document, which drifted) and briefly a second
   <video> (which drifted less, but still by four frames). The geometry is unchanged
   from both: it covers exactly the canvas panel of the capture behind it,
   x 21.4%-81.8%, y 2.9%-41.0%, and the JS cover-fits the frame into that box. */
.scene-media canvas.lightbridge-dock-source {
  background: #050508;
  display: block;
  height: 38.1%;
  left: 21.4%;
  pointer-events: none;
  position: absolute;
  top: 2.9%;
  width: 60.4%;
  z-index: 2;
}

/* Resting grounds for the two scenes whose media is nothing but video.
   Posters here are art-directed — a phone gets a portrait cut, a desktop a wide one
   — so cinematic-home.js assigns them rather than the markup carrying one, which
   means with scripting off there is no poster and no video. These give both scenes
   the ground they are designed on, so the no-JS page is a dark scene with its copy
   on it rather than a hole. Maison and Orbricks need nothing: their <img> loads. */
.lightbridge .scene-media { background: #000; }
.lightbridge-dock-screen { background: #0b0b12; }
.handiwork .scene-media { background: #04050a; }
/* No video on this page is user-operated: they are muted, looping scenery with no
   `controls` attribute. A source-less <video> — which is every one of them before
   cinematic-home.js hydrates, and all of them for good with scripting off — still
   gets the UA's transport bar painted into it, which turns the Maison band into a
   grey play/scrub widget in the middle of the scene. There is nothing to control,
   so there is nothing to show. */
.home-page video::-webkit-media-controls,
.home-page video::-webkit-media-controls-enclosure,
.home-page video::-webkit-media-controls-panel { display: none !important; }

/* "Lightbridge" is the longest single word among the scene headlines and it sits in
   the narrowest column: the dock takes 48vw of the scene, so the copy is capped at
   42vw. Between the phone breakpoint and ~860px the shared 60px floor of
   clamp(60px,6.6vw,108px) renders the word 326px wide inside a 323px box at 768.
   Tying it to the viewport across that band lets it scale with its column and reach
   the 60px floor only once there is room for it (7vw crosses 60px at 857px). */
@media (min-width: 761px) and (max-width: 960px) {
  .lightbridge .project-copy h2 { font-size: min(60px, 7vw); }
}
