/* ============================================================
   NETWRK AG · presentation deck
   Fixed 1600x900 stage, scaled to fit any viewport.
   ============================================================ */

:root{
  --bg:#08080A;
  --ink:#F6F6F8;
  --muted:rgba(246,246,248,.60);
  --faint:rgba(246,246,248,.34);
  --hair:rgba(255,255,255,.10);
  --hair-2:rgba(255,255,255,.055);
  --glass:rgba(255,255,255,.045);
  --glass-hi:rgba(255,255,255,.075);

  --p1:#4C1D95; --p2:#7C3AED; --p3:#A855F7; --p4:#C026D3;
  --grad:linear-gradient(135deg,#4C1D95,#7C3AED,#A855F7,#C026D3);
  --grad-soft:linear-gradient(135deg,rgba(124,58,237,.9),rgba(192,38,211,.9));

  --up:#2BD47D; --down:#F2555A;

  --silver:linear-gradient(140deg,#f2f4f8 0%,#c8ccd6 26%,#8d919c 52%,#dfe2e9 74%,#a9aeb9 100%);
  --gold:linear-gradient(140deg,#fdf1c0 0%,#e6c455 24%,#b98f21 52%,#f6e08e 74%,#a97d17 100%);
  --black:linear-gradient(140deg,#26262c 0%,#111114 30%,#0a0a0c 60%,#1d1d24 100%);

  --ease:cubic-bezier(.16,1,.3,1);
  --font:'Sora','Avenir Next','Futura',system-ui,-apple-system,'Segoe UI',sans-serif;
  --font-ui:'Inter','Avenir Next',system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:'SF Mono',ui-monospace,'JetBrains Mono',Menlo,monospace;
}

*{box-sizing:border-box;margin:0;padding:0}
html,body{height:100%;overflow:hidden;background:var(--bg)}
body{
  font-family:var(--font-ui);
  color:var(--ink);
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
  cursor:default;
}
img{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
b,strong{font-weight:600}

/* ---------- ambient background ---------- */
#bg{position:fixed;inset:0;z-index:0}
#net{position:absolute;inset:0;width:100%;height:100%;opacity:.5}
.orb{position:absolute;border-radius:50%;filter:blur(110px);opacity:.42;will-change:transform}
.orb.a{width:820px;height:820px;left:-14%;top:-22%;background:radial-gradient(circle,#5b21b6,transparent 68%);animation:float1 26s ease-in-out infinite}
.orb.b{width:700px;height:700px;right:-12%;bottom:-24%;background:radial-gradient(circle,#a21caf,transparent 68%);animation:float2 32s ease-in-out infinite}
.orb.c{width:560px;height:560px;left:44%;top:36%;background:radial-gradient(circle,#7c3aed,transparent 70%);opacity:.24;animation:float3 38s ease-in-out infinite}
@keyframes float1{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(90px,60px) scale(1.12)}}
@keyframes float2{0%,100%{transform:translate(0,0) scale(1)}50%{transform:translate(-80px,-70px) scale(1.16)}}
@keyframes float3{0%,100%{transform:translate(0,0)}50%{transform:translate(-120px,40px)}}

#vignette{position:fixed;inset:0;z-index:8000;pointer-events:none;
  background:radial-gradient(120% 90% at 50% 45%,transparent 42%,rgba(0,0,0,.55) 100%)}
#grain{position:fixed;inset:-120%;z-index:8001;pointer-events:none;opacity:.045;mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='300' height='300'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='300' height='300' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grain 1.1s steps(4) infinite}
@keyframes grain{0%{transform:translate(0,0)}25%{transform:translate(-3%,2%)}50%{transform:translate(2%,-3%)}75%{transform:translate(-2%,-2%)}100%{transform:translate(3%,3%)}}

/* ---------- stage ---------- */
/* The stage is scaled with `zoom`, not `transform: scale()`.
   transform rasterises the layer once and then stretches the bitmap, so at any
   non-integer scale every glyph came out soft and pixelated. zoom changes the
   used layout size instead, so text is re-rendered at the device's real
   resolution and stays crisp. deck.js falls back to transform if zoom is
   unsupported. */
#viewport{position:fixed;inset:0;z-index:100;overflow:hidden;display:grid;place-items:center}
#stage{position:relative;width:1600px;height:900px;transform-origin:50% 50%;
  perspective:2400px;perspective-origin:50% 50%}
#stage.fallback-scale{position:absolute;left:50%;top:50%;
  transform:translate(-50%,-50%) scale(var(--s,1))}

/* ============================================================
   SLIDE TRANSITIONS
   ONE BESPOKE MOVE PER SLIDE. Every slide names its own in `data-trans`, which
   deck.js mirrors onto the stage as `data-t`. Each is built around that slide's
   own focal point, usually via transform-origin, so the motion appears to start
   from the thing the slide is about.
   NB: none of them use clip-path, deliberately. The settled state forces
   `clip-path:none`, and clip-path cannot interpolate to `none`, so it would
   snap at the halfway point instead of animating.
   Idle slides carry NO transition, so switching type repositions them
   instantly and invisibly; the animation only exists on .is-active/.is-out.
   Every type resolves to `transform:none` at rest, which is what keeps the
   type crisp once a slide has settled.
   ============================================================ */
.slide{position:absolute;inset:0;padding:78px 104px 92px;
  opacity:0;pointer-events:none;visibility:hidden;
  transform-origin:50% 46%;
  display:flex;flex-direction:column;backface-visibility:hidden}
.slide.is-active,.slide.is-out{visibility:visible}
.slide.is-active{opacity:1;transform:none;filter:none;clip-path:none;
  border-radius:0;pointer-events:auto;z-index:1}

/* curtain · the opening frame swings square on a hinge set at the network sphere on the right, so the logo lockup and headline on the left arrive last */
#stage[data-t="curtain"] .slide{opacity:1;transform:translate3d(0,0,-190px) rotateY(6deg);
  transform-origin:78% 50%}
#stage[data-t="curtain"] .slide.is-active{z-index:3;
  transition:transform 1.25s cubic-bezier(.16,1,.3,1)}
#stage[data-t="curtain"] .slide.is-out{opacity:0;transform:translate3d(0,0,90px) rotateY(-3deg);
  transform-origin:50% 50%;filter:blur(5px) brightness(.34);z-index:2;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .82s}
#stage.rev[data-t="curtain"] .slide{transform:translate3d(0,0,-190px) rotateY(-6deg);
  transform-origin:22% 50%}
#stage.rev[data-t="curtain"] .slide.is-out{transform:translate3d(0,0,90px) rotateY(3deg);
  transform-origin:50% 50%;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .82s}

/* converge · the page arrives stretched wide with both discs beyond the frame and draws them inward onto the ends of the arc, so the move is the bridge closing */
#stage[data-t="converge"] .slide{opacity:1;transform:scale(1.17,1.03);transform-origin:50% 58%}
#stage[data-t="converge"] .slide.is-active{z-index:3;
  transition:transform 1.2s cubic-bezier(.16,1,.3,1)}
#stage[data-t="converge"] .slide.is-out{opacity:0;transform:translate3d(0,0,-200px) scale(1.02);
  transform-origin:50% 50%;filter:blur(4px) brightness(.3);z-index:2;
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .7s ease,opacity .42s ease .55s}
#stage.rev[data-t="converge"] .slide{transform:scale(.88,.99)}
#stage.rev[data-t="converge"] .slide.is-out{transform:translate3d(0,0,70px) scale(1.05);
  transform-origin:50% 50%;filter:blur(4px) brightness(.55);
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .8s}

/* press · the credibility page comes in oversized and a fraction off-square, then squares up and presses flat about the register facts in the left column, like a stamp on a document */
#stage[data-t="press"] .slide{opacity:1;transform:translate3d(0,-1.6%,170px) rotate(-.8deg);
  transform-origin:26% 60%}
#stage[data-t="press"] .slide.is-active{z-index:3;
  transition:transform 1.1s cubic-bezier(.16,1,.3,1)}
#stage[data-t="press"] .slide.is-out{opacity:0;transform:translate3d(0,1%,-130px) rotate(.4deg);
  transform-origin:50% 50%;filter:blur(4px) brightness(.3);z-index:2;
  transition:transform 1.05s cubic-bezier(.3,0,.35,1),filter .65s ease,opacity .4s ease .58s}
#stage.rev[data-t="press"] .slide{transform:translate3d(0,1.2%,-140px) rotate(.6deg)}
#stage.rev[data-t="press"] .slide.is-out{transform:translate3d(0,-1.2%,150px) rotate(-.5deg);
  transform-origin:50% 50%;filter:blur(4px) brightness(.55);
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .8s}

/* board · the eight-tile grid drops in from above and flaps flat on a hinge along its top edge, the way a departure board turns over a fresh set of numbers */
#stage[data-t="board"] .slide{opacity:1;transform:translate3d(0,-100.5%,0) rotateX(5deg);
  transform-origin:50% 0}
#stage[data-t="board"] .slide.is-active{z-index:3;
  transition:transform 1.15s cubic-bezier(.16,1,.3,1)}
#stage[data-t="board"] .slide.is-out{opacity:0;transform:translate3d(0,13%,0);
  transform-origin:50% 50%;filter:brightness(.34) blur(3px);z-index:2;
  transition:transform 1.15s cubic-bezier(.55,0,.5,1),filter .85s ease,opacity .28s ease .87s}
#stage.rev[data-t="board"] .slide{transform:translate3d(0,100.5%,0) rotateX(-5deg);
  transform-origin:50% 100%}
#stage.rev[data-t="board"] .slide.is-out{transform:translate3d(0,-13%,0);transform-origin:50% 50%;
  transition:transform 1.15s cubic-bezier(.55,0,.5,1),filter .85s ease,opacity .28s ease .87s}

/* applaunch · the app chapter opens by launching the page out of the App Store icon itself, icon-sized and squircle-cornered, exactly as an app opens on iOS */
#stage[data-t="applaunch"] .slide{opacity:0;transform:scale(.38);border-radius:56px;
  transform-origin:9.5% 26%}
#stage[data-t="applaunch"] .slide.is-active{z-index:3;
  transition:opacity .28s cubic-bezier(.4,0,.2,1),
             transform 1.25s cubic-bezier(.16,1,.3,1),
             border-radius 1.05s cubic-bezier(.16,1,.3,1)}
#stage[data-t="applaunch"] .slide.is-out{opacity:0;transform:scale(1.04);border-radius:0;
  transform-origin:50% 50%;filter:brightness(.3) blur(4px);z-index:2;
  transition:transform 1.2s cubic-bezier(.3,0,.35,1),border-radius .9s ease,
             filter .85s ease,opacity .28s ease .92s}
#stage.rev[data-t="applaunch"] .slide{opacity:1;transform:scale(1.04);border-radius:0;
  transform-origin:50% 50%}
#stage.rev[data-t="applaunch"] .slide.is-out{opacity:0;transform:scale(.38);border-radius:56px;
  transform-origin:9.5% 26%;filter:brightness(.6) blur(2px);z-index:4;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),border-radius .9s ease,
             filter .8s ease,opacity .3s ease .78s}

/* donutbloom · the portfolio donut is the subject, so the page arrives oversized and skewed off its axis and unwinds square about the centre of the chart */
#stage[data-t="donutbloom"] .slide{opacity:1;transform:scale(1.2) rotate(-3deg);
  transform-origin:16.6% 42%}
#stage[data-t="donutbloom"] .slide.is-active{z-index:3;
  transition:transform 1.3s cubic-bezier(.16,1,.3,1)}
#stage[data-t="donutbloom"] .slide.is-out{opacity:0;transform:scale(.92);
  filter:brightness(.28) blur(5px);z-index:2;
  transition:transform 1.2s cubic-bezier(.3,0,.35,1),filter .85s ease,opacity .45s ease .6s}
#stage.rev[data-t="donutbloom"] .slide{transform:scale(.92)}
#stage.rev[data-t="donutbloom"] .slide.is-out{transform:scale(1.2) rotate(-3deg);
  transform-origin:16.6% 42%;filter:brightness(.55) blur(4px);
  transition:transform 1.2s cubic-bezier(.3,0,.35,1),filter .85s ease,opacity .3s ease .85s}

/* screenturn · two phone screens read left to right, so the page turns in on a vertical hinge at the shallow Y-angle the phones themselves are set at */
#stage[data-t="screenturn"] .slide{opacity:1;transform:translateX(44%) rotateY(-10deg);
  transform-origin:100% 50%}
#stage[data-t="screenturn"] .slide.is-active{z-index:3;
  transition:transform 1.1s cubic-bezier(.16,1,.3,1)}
#stage[data-t="screenturn"] .slide.is-out{opacity:0;transform:translateX(-16%);
  transform-origin:50% 50%;filter:brightness(.34) blur(3px);z-index:2;
  transition:transform 1.1s cubic-bezier(.16,1,.3,1),filter .9s ease,opacity .26s ease .84s}
#stage.rev[data-t="screenturn"] .slide{transform:translateX(-44%) rotateY(10deg);
  transform-origin:0% 50%}
#stage.rev[data-t="screenturn"] .slide.is-out{transform:translateX(16%);transform-origin:50% 50%;
  transition:transform 1.1s cubic-bezier(.16,1,.3,1),filter .9s ease,opacity .26s ease .84s}

/* carddeal · the subject is two physical cards stacked on the left, so the page is dealt onto the stack at the gold card's angle and corner radius */
#stage[data-t="carddeal"] .slide{opacity:1;transform:translate(-12%,15%) rotate(-6deg) scale(.94);
  border-radius:20px;transform-origin:27% 56%}
#stage[data-t="carddeal"] .slide.is-active{z-index:3;
  transition:transform 1.15s cubic-bezier(.16,1,.3,1),
             border-radius .95s cubic-bezier(.16,1,.3,1)}
#stage[data-t="carddeal"] .slide.is-out{opacity:0;transform:scale(1.08) rotate(.8deg);
  border-radius:0;transform-origin:50% 50%;filter:brightness(.32) blur(3px);z-index:2;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),border-radius .8s ease,
             filter .85s ease,opacity .28s ease .9s}
#stage.rev[data-t="carddeal"] .slide{transform:scale(1.08) rotate(.8deg);border-radius:0;
  transform-origin:50% 50%}
#stage.rev[data-t="carddeal"] .slide.is-out{opacity:0;
  transform:translate(-12%,15%) rotate(-6deg) scale(.94);border-radius:20px;
  transform-origin:27% 56%;filter:brightness(.6) blur(3px);z-index:4;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),border-radius .8s ease,
             filter .85s ease,opacity .32s ease .76s}

/* aiask · the AI chapter unfolds out of the phone on the left, hinged on the screen that is doing the talking */
#stage[data-t="aiask"] .slide{opacity:1;transform:rotateY(7deg) scale(1.1);
  transform-origin:18% 47%}
#stage[data-t="aiask"] .slide.is-active{z-index:3;
  transition:transform 1.25s cubic-bezier(.16,1,.3,1)}
#stage[data-t="aiask"] .slide.is-out{opacity:0;transform:scale(1.06) translateX(1.5%);
  transform-origin:50% 50%;filter:brightness(.3) blur(4px);z-index:2;
  transition:transform 1.2s cubic-bezier(.36,0,.36,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .4s ease .62s}
#stage.rev[data-t="aiask"] .slide{transform:scale(1.06) translateX(1.5%);transform-origin:50% 50%}
#stage.rev[data-t="aiask"] .slide.is-out{opacity:0;transform:rotateY(7deg) scale(1.06);
  transform-origin:18% 47%;filter:brightness(.55) blur(5px);z-index:4;
  transition:transform 1.15s cubic-bezier(.36,0,.36,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .8s cubic-bezier(.62,0,1,1) .25s}

/* aidepth · the camera descends onto the page and settles, the overview-to-depth move the slide describes */
#stage[data-t="aidepth"] .slide{opacity:1;transform:translateY(-5%) scale(1.18);
  transform-origin:50% 46%}
#stage[data-t="aidepth"] .slide.is-active{z-index:3;
  transition:transform 1.3s cubic-bezier(.16,1,.3,1)}
#stage[data-t="aidepth"] .slide.is-out{opacity:0;transform:translateY(9%) scale(1.02);
  filter:brightness(.28) blur(4px);z-index:2;
  transition:transform 1.2s cubic-bezier(.4,0,.35,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .45s ease .6s}
#stage.rev[data-t="aidepth"] .slide{transform:translateY(6%) scale(1.18)}
#stage.rev[data-t="aidepth"] .slide.is-out{transform:translateY(-9%) scale(1.02);
  transition:transform 1.2s cubic-bezier(.4,0,.35,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .45s ease .6s}

/* aicard · the page is laid down flat onto the table, hinged at the base of the membership-card phone, the way the digital card it is about would be set down */
#stage[data-t="aicard"] .slide{opacity:1;transform:translateY(1%) rotateX(6deg) scale(1.09);
  transform-origin:42% 84%}
#stage[data-t="aicard"] .slide.is-active{z-index:3;
  transition:transform 1.25s cubic-bezier(.16,1,.3,1)}
#stage[data-t="aicard"] .slide.is-out{opacity:0;transform:translateY(2%) scale(.95);
  transform-origin:50% 50%;filter:brightness(.32) blur(4px);z-index:2;
  transition:transform 1.2s cubic-bezier(.4,0,.4,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .45s ease .6s}
#stage.rev[data-t="aicard"] .slide{transform:translateY(-1%) scale(1.08);transform-origin:50% 50%}
#stage.rev[data-t="aicard"] .slide.is-out{opacity:0;
  transform:translateY(1%) rotateX(6deg) scale(1.04);transform-origin:42% 84%;
  filter:brightness(.58) blur(5px);z-index:4;
  transition:transform 1.15s cubic-bezier(.4,0,.4,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .85s cubic-bezier(.62,0,1,1) .22s}

/* aihome · the page unfolds vertically out of the wide widget panel in the lower half, the way a home-screen widget expands */
#stage[data-t="aihome"] .slide{opacity:1;transform:scaleY(.8) scaleX(1.04);
  transform-origin:50% 70%}
#stage[data-t="aihome"] .slide.is-active{z-index:3;
  transition:transform 1.2s cubic-bezier(.16,1,.3,1)}
#stage[data-t="aihome"] .slide.is-out{opacity:0;transform:scale(1.07) translateY(-1%);
  transform-origin:50% 50%;filter:brightness(.28) blur(4px);z-index:2;
  transition:transform 1.15s cubic-bezier(.4,0,.35,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .28s ease .88s}
#stage.rev[data-t="aihome"] .slide{transform:scale(1.05);transform-origin:50% 50%}
#stage.rev[data-t="aihome"] .slide.is-out{opacity:0;transform:scaleY(.82) scaleX(1.04);
  transform-origin:50% 70%;filter:brightness(.55) blur(5px);z-index:4;
  transition:transform 1.1s cubic-bezier(.4,0,.35,1),filter 1s cubic-bezier(.4,0,.6,1),
             opacity .8s cubic-bezier(.62,0,1,1) .25s}

/* dealt · three membership cards lie side by side, so the page is dealt onto the table from the lower left, pivoting on the Silver card's corner */
#stage[data-t="dealt"] .slide{opacity:1;transform:translate(-11%,14%) rotate(-2.6deg) scale(.94);
  transform-origin:14% 89%}
#stage[data-t="dealt"] .slide.is-active{z-index:3;
  transition:transform 1.15s cubic-bezier(.16,1,.3,1)}
#stage[data-t="dealt"] .slide.is-out{opacity:0;transform:translate(3%,-3%) rotate(1.2deg) scale(1.12);
  transform-origin:50% 50%;filter:brightness(.4) blur(4px);z-index:2;
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .28s ease .87s}
#stage.rev[data-t="dealt"] .slide{transform:translate(3%,-3%) rotate(1.2deg) scale(1.12);
  transform-origin:50% 50%}
#stage.rev[data-t="dealt"] .slide.is-out{opacity:0;
  transform:translate(-11%,14%) rotate(-2.6deg) scale(.94);transform-origin:14% 89%;
  filter:brightness(.62) blur(3px);z-index:4;
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .32s ease .74s}

/* unfold · the table hangs off its Silver/Gold/Black column heads, so the page hinges open downward from that header band before the rows fill in */
#stage[data-t="unfold"] .slide{opacity:1;transform:translateY(-1.5%) rotateX(-6deg) scale(1.06);
  transform-origin:69% 26%}
#stage[data-t="unfold"] .slide.is-active{z-index:3;
  transition:transform 1.2s cubic-bezier(.16,1,.3,1)}
#stage[data-t="unfold"] .slide.is-out{opacity:0;transform:translateY(7%) scale(.96);
  transform-origin:50% 50%;filter:brightness(.35) blur(3px);z-index:2;
  transition:transform 1.05s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .42s ease .58s}
#stage.rev[data-t="unfold"] .slide{transform:translateY(5%) scale(1.12);transform-origin:50% 50%}
#stage.rev[data-t="unfold"] .slide.is-out{opacity:0;
  transform:translateY(-1.5%) rotateX(-6deg) scale(1.02);transform-origin:69% 26%;
  filter:brightness(.6) blur(3px);z-index:4;
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .76s}

/* spread · two glass panels sit either side of a centre seam, so the page opens outward from that seam and the panels part into position */
#stage[data-t="spread"] .slide{opacity:1;transform:scaleX(.78) scaleY(.96);
  transform-origin:50% 59%}
#stage[data-t="spread"] .slide.is-active{z-index:3;
  transition:transform 1.15s cubic-bezier(.16,1,.3,1)}
#stage[data-t="spread"] .slide.is-out{opacity:0;transform:scaleX(1.16) scaleY(1.06);
  filter:brightness(.4) blur(4px);z-index:2;
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .28s ease .84s}
#stage.rev[data-t="spread"] .slide{transform:scaleX(1.16) scaleY(1.06)}
#stage.rev[data-t="spread"] .slide.is-out{opacity:0;transform:scaleX(.78) scaleY(.96);
  filter:brightness(.6) blur(4px);z-index:4;
  transition:transform 1.1s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .74s}

/* pullback · four partner cards in a 2x2 grid, so the camera starts hard on the Porsche card at top left and pulls back diagonally until all four are in frame */
#stage[data-t="pullback"] .slide{opacity:1;transform:translate(3.5%,4%) scale(1.18);
  transform-origin:28% 43%}
#stage[data-t="pullback"] .slide.is-active{z-index:3;
  transition:transform 1.3s cubic-bezier(.16,1,.3,1)}
#stage[data-t="pullback"] .slide.is-out{opacity:0;transform:translate(-3%,-3.5%) scale(.92);
  transform-origin:50% 50%;filter:brightness(.36) blur(5px);z-index:2;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .45s ease .55s}
#stage.rev[data-t="pullback"] .slide{transform:translate(-3%,-3.5%) scale(1.12);
  transform-origin:50% 50%}
#stage.rev[data-t="pullback"] .slide.is-out{opacity:0;transform:translate(3.5%,4%) scale(1.14);
  transform-origin:28% 43%;filter:brightness(.55) blur(5px);
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .8s}

/* track · the timeline draws left to right, so the page travels the same axis, hinged on the line's left anchor and flattening as the dates arrive */
#stage[data-t="track"] .slide{opacity:1;transform:translateX(-102%) rotateY(6deg);
  transform-origin:7% 52%}
#stage[data-t="track"] .slide.is-active{z-index:3;
  transition:transform 1.15s cubic-bezier(.16,1,.3,1)}
#stage[data-t="track"] .slide.is-out{opacity:0;transform:translateX(30%) scale(1.05);
  transform-origin:50% 50%;filter:brightness(.4) blur(3px);z-index:2;
  transition:transform 1.15s cubic-bezier(.5,0,.4,1),filter .75s ease,opacity .28s ease .87s}
#stage.rev[data-t="track"] .slide{transform:translateX(102%) rotateY(-6deg);
  transform-origin:93% 52%}
#stage.rev[data-t="track"] .slide.is-out{transform:translateX(-30%) scale(1.05);
  transform-origin:50% 50%;
  transition:transform 1.15s cubic-bezier(.5,0,.4,1),filter .75s ease,opacity .28s ease .87s}

/* rooted · the Prime Tower skyline grows out of the ground on the right, so the whole page rises and expands from the footing of that building */
#stage[data-t="rooted"] .slide{opacity:1;transform:translateY(6%) scale(.86);
  transform-origin:77% 85%}
#stage[data-t="rooted"] .slide.is-active{z-index:3;
  transition:transform 1.25s cubic-bezier(.16,1,.3,1)}
#stage[data-t="rooted"] .slide.is-out{opacity:0;transform:translateY(-6%) scale(1.14);
  transform-origin:50% 50%;filter:brightness(.36) blur(4px);z-index:2;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .28s ease .9s}
#stage.rev[data-t="rooted"] .slide{transform:translateY(-6%) scale(1.14);transform-origin:50% 50%}
#stage.rev[data-t="rooted"] .slide.is-out{opacity:0;transform:translateY(6%) scale(.86);
  transform-origin:77% 85%;filter:brightness(.6) blur(4px);z-index:4;
  transition:transform 1.15s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .34s ease .76s}

/* settle · the closing frame is centred on the logo lockup, so the deck comes to rest with a slow dissolve and the camera easing to a stop dead centre */
#stage[data-t="settle"] .slide{opacity:0;transform:scale(1.05);transform-origin:50% 50%}
#stage[data-t="settle"] .slide.is-active{z-index:3;
  transition:opacity .8s cubic-bezier(.4,0,.2,1),
             transform 1.3s cubic-bezier(.16,1,.3,1)}
#stage[data-t="settle"] .slide.is-out{opacity:0;transform:scale(1.02);
  filter:blur(5px) brightness(.45);z-index:2;
  transition:transform 1.2s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .45s ease .6s}
#stage.rev[data-t="settle"] .slide{transform:scale(.97)}
#stage.rev[data-t="settle"] .slide.is-out{transform:scale(1.05);
  transition:transform 1.2s cubic-bezier(.3,0,.35,1),filter .8s ease,opacity .45s ease .6s}

/* The settled page always wins over its type's idle rule, whatever that type
   is: square, unclipped, unfiltered and transform-free. Must stay last, and
   must out-specify `#stage[data-t="…"] .slide`. */
#stage[data-t] .slide.is-active{
  opacity:1;transform:none;filter:none;clip-path:none;border-radius:0}

/* the world moves with the camera */
#bg{transform-origin:50% 50%}
body.warp #bg{animation:warpfwd 1.25s cubic-bezier(.22,1,.28,1)}
@keyframes warpfwd{0%{transform:scale(1)}34%{transform:scale(1.06)}100%{transform:scale(1)}}
body.warp.rev #bg{animation:warpback 1.25s cubic-bezier(.22,1,.28,1)}
@keyframes warpback{0%{transform:scale(1)}34%{transform:scale(.945)}100%{transform:scale(1)}}


/* entrance animation primitives.
   NB: no `will-change` here. Promoting every animated element to its own
   composited layer made all the body text render blurry once the stage was
   scaled, and there are far too many of these elements to justify it. */
[data-anim]{opacity:0;transition:opacity .85s var(--ease),transform .95s var(--ease),filter .95s var(--ease);
  transition-delay:calc(var(--d,0) * 1ms)}
[data-anim="up"]{transform:translateY(34px)}
[data-anim="down"]{transform:translateY(-26px)}
[data-anim="left"]{transform:translateX(38px)}
[data-anim="right"]{transform:translateX(-38px)}
[data-anim="scale"]{transform:scale(.93)}
[data-anim="blur"]{filter:blur(14px);transform:translateY(20px)}
[data-anim="rise"]{transform:translateY(60px) scale(.97)}
.is-active [data-anim]{opacity:1;transform:none;filter:none}

.mask{display:block;overflow:hidden;padding-bottom:.08em;margin-bottom:-.08em}
.mask>span{display:block;transform:translateY(105%);transition:transform 1.05s var(--ease);
  transition-delay:calc(var(--d,0) * 1ms)}
.is-active .mask>span{transform:none}

/* ---------- type ---------- */
.eyebrow{display:inline-flex;align-items:center;gap:12px;font-family:var(--font-ui);
  font-size:12px;font-weight:600;letter-spacing:.22em;text-transform:uppercase;color:var(--faint)}
.eyebrow i{width:26px;height:1px;background:var(--p3);display:block;font-style:normal}
.eyebrow b{color:var(--p3);font-weight:600}

h1.display{font-family:var(--font);font-weight:200;letter-spacing:-.03em;line-height:1.02;
  font-size:86px}
h2.h-sec{font-family:var(--font);font-weight:200;letter-spacing:-.028em;line-height:1.05;font-size:60px}
h3{font-family:var(--font);font-weight:500;letter-spacing:-.01em}
.grad{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
.lede{font-size:19px;line-height:1.62;color:var(--muted);max-width:60ch;font-weight:300}
.tiny{font-size:12.5px;line-height:1.55;color:var(--faint)}
.num{font-variant-numeric:tabular-nums;font-feature-settings:"tnum"}

/* ---------- glass ---------- */
.glass{background:var(--glass);border:1px solid var(--hair);border-radius:18px;
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);position:relative;overflow:hidden}
.glass::before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:linear-gradient(150deg,rgba(255,255,255,.09),transparent 42%)}

/* ---------- chrome ---------- */
#chrome{position:fixed;inset:0;z-index:9000;pointer-events:none;font-family:var(--font-ui)}
#chrome .pin{position:absolute;pointer-events:auto}
.tl{left:34px;top:30px;display:flex;align-items:center;gap:14px}
.tl svg{width:19px;height:24px;opacity:.9}
.tl .sect{font-size:11px;letter-spacing:.2em;text-transform:uppercase;color:var(--faint);
  padding-left:14px;border-left:1px solid var(--hair)}
.tr{right:30px;top:26px;display:flex;align-items:center;gap:6px}
.cbtn{width:34px;height:34px;border-radius:10px;display:grid;place-items:center;color:var(--faint);
  border:1px solid transparent;transition:.25s}
.cbtn:hover{color:var(--ink);background:var(--glass);border-color:var(--hair)}
.cbtn.on{color:#fff;background:rgba(124,58,237,.24);border-color:rgba(168,85,247,.45)}
.cbtn svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.lang{display:flex;border:1px solid var(--hair);border-radius:10px;overflow:hidden;margin-right:6px}
.lang button{padding:7px 11px;font-size:11px;font-weight:600;letter-spacing:.1em;color:var(--faint);transition:.25s}
.lang button.on{background:var(--grad);color:#fff}

.bl{left:34px;bottom:26px;display:flex;align-items:center;gap:14px}
.br{right:34px;bottom:26px;display:flex;align-items:center;gap:16px;font-size:12px;color:var(--faint)}
.br .cur{color:var(--ink);font-weight:600}
#bar{position:fixed;left:0;bottom:0;height:2px;width:100%;z-index:9001;background:rgba(255,255,255,.06)}
#barfill{height:100%;width:0;background:var(--grad);transition:width .6s var(--ease);
  box-shadow:0 0 14px rgba(168,85,247,.65)}
#ticks{display:flex;gap:5px;align-items:center}
#ticks i{width:16px;height:2px;border-radius:2px;background:rgba(255,255,255,.16);display:block;transition:.35s;
  cursor:pointer}
#ticks i:hover{background:rgba(255,255,255,.42)}
#ticks i.on{background:var(--p3);box-shadow:0 0 10px rgba(168,85,247,.7);width:22px}
#ticks i.done{background:rgba(168,85,247,.42)}
#ticks i.chap{margin-left:15px}
#ticks i.chap::before{content:"";position:absolute;margin-left:-10px;margin-top:-3px;width:1px;height:8px;
  background:rgba(255,255,255,.16);display:block}

/* ---------- presenter notes ---------- */
/* below #chrome (9000) so the tick bar and the counter stay readable over it */
#notes{position:fixed;left:0;right:0;bottom:0;z-index:8900;padding:26px 34px 58px;
  background:linear-gradient(transparent,rgba(4,4,6,.95) 30%);
  transform:translateY(102%);transition:transform .5s var(--ease);pointer-events:none}
#notes.open{transform:none}
#notes.empty .in{display:none}
#notes .in{max-width:1180px;display:flex;gap:22px;align-items:flex-start}
#notes b{flex:none;font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--p3);padding-top:4px}
#notes p{font-size:15px;line-height:1.62;color:rgba(246,246,248,.82);font-weight:300}
#notes em{font-style:normal;color:#fff;font-weight:500}

#ring{width:28px;height:28px}
#ring circle{fill:none;stroke-width:2}
#ring .t{stroke:rgba(255,255,255,.14)}
#ring .p{stroke:var(--p3);stroke-linecap:round;transform:rotate(-90deg);transform-origin:50% 50%}

/* menu overlay */
#menu{position:fixed;inset:0;z-index:9500;background:rgba(5,5,7,.86);
  backdrop-filter:blur(22px);-webkit-backdrop-filter:blur(22px);
  opacity:0;pointer-events:none;transition:.4s var(--ease);padding:70px 90px;overflow:auto}
#menu.open{opacity:1;pointer-events:auto}
#menu h4{font-size:11px;letter-spacing:.24em;text-transform:uppercase;color:var(--faint);margin-bottom:26px}
#menuList{display:grid;grid-template-columns:repeat(3,1fr);gap:10px 26px;max-width:1180px}
#menuList button{display:flex;align-items:baseline;gap:14px;padding:11px 14px;border-radius:11px;
  text-align:left;transition:.22s;border:1px solid transparent;width:100%}
#menuList button:hover{background:var(--glass);border-color:var(--hair)}
#menuList button.on{background:rgba(124,58,237,.16);border-color:rgba(168,85,247,.4)}
#menuList em{font-style:normal;font-family:var(--mono);font-size:11px;color:var(--p3);min-width:22px}
#menuList span{font-size:14.5px;color:var(--muted)}
#menuList button.on span,#menuList button:hover span{color:var(--ink)}

/* keyboard hint */
#hint{position:fixed;left:50%;bottom:52px;transform:translateX(-50%);z-index:9002;
  display:flex;gap:18px;font-size:11.5px;color:var(--faint);letter-spacing:.04em;
  transition:opacity .6s;pointer-events:none}
#hint kbd{font-family:var(--font-ui);font-size:10.5px;border:1px solid var(--hair);border-radius:5px;
  padding:2px 6px;margin-right:6px;color:var(--muted)}
#hint.hide{opacity:0}

/* ---------- reusable bits ---------- */
.chip{display:inline-flex;align-items:center;gap:9px;padding:8px 15px;border-radius:999px;
  border:1px solid var(--hair);background:var(--glass);font-size:13px;color:var(--muted)}
.chip i{width:6px;height:6px;border-radius:50%;background:var(--p3);display:block}
.tick{width:17px;height:17px;border-radius:50%;background:var(--grad);display:grid;place-items:center;flex:none}
.tick::after{content:"";width:6px;height:3.5px;border-left:1.6px solid #fff;border-bottom:1.6px solid #fff;
  transform:rotate(-45deg) translate(.5px,-.5px)}
.dash{width:17px;height:17px;display:grid;place-items:center;flex:none}
.dash::after{content:"";width:9px;height:1px;background:rgba(255,255,255,.2)}

.rule{height:1px;background:linear-gradient(90deg,var(--hair),transparent)}

/* ---------- inline links ----------
   Every CTA in the deck is a real anchor. They all open in a new tab, so a
   click during a talk can never navigate away from the presentation, and
   deck.js's click-to-advance handler already ignores anything inside an <a>. */
.ln{color:inherit;text-decoration:none;cursor:pointer;position:relative;
  background-image:linear-gradient(var(--p3),var(--p3));
  background-size:0 1px;background-repeat:no-repeat;background-position:0 100%;
  transition:background-size .35s var(--ease),color .3s ease}
.ln:hover{color:#E9D5FF;background-size:100% 1px}
a:focus-visible,.btn:focus-visible,.cta:focus-visible,.badge:focus-visible,.wbtn:focus-visible{
  outline:2px solid var(--p3);outline-offset:4px;border-radius:6px}

.head{margin-bottom:44px}
.head .eyebrow{margin-bottom:20px}
.head .lede{margin-top:22px}

/* footnote */
.foot{position:absolute;left:104px;right:104px;bottom:40px;font-size:11.5px;color:rgba(246,246,248,.26);
  line-height:1.5;display:flex;gap:10px;align-items:flex-start}
.foot::before{content:"";width:14px;height:1px;background:rgba(255,255,255,.16);margin-top:8px;flex:none}

@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001s!important;transition-duration:.12s!important}
  #grain,.orb{animation:none!important}
}

/* ============================================================
   PRINT · Cmd+P then "Save as PDF" gives one landscape page per
   slide. Enable "Print backgrounds" in the print dialog.
   ============================================================ */
@page{size:1600px 900px;margin:0}
@media print{
  html,body{overflow:visible;height:auto;background:#08080A}
  #chrome,#hint,#bar,#menu,#notes,#grain,#vignette{display:none!important}
  #bg{position:absolute;top:0;left:0;width:1600px;height:100%}
  #net{display:none}
  /* zoom is set inline by fit(); it must be neutralised or every page prints
     at the on-screen scale instead of full size */
  #viewport{position:static;overflow:visible;display:block}
  #stage{position:static;transform:none!important;zoom:1!important;width:1600px;height:auto}
  /* transition:none matters — with a transition still declared the printed value
     can be whatever the (paused) interpolation happens to be, not the end state */
  /* every transition type has to be neutralised, not just transform */
  .slide{position:relative;inset:auto;width:1600px;height:900px;opacity:1!important;
    transform:none!important;transition:none!important;filter:none!important;
    clip-path:none!important;border-radius:0!important;visibility:visible!important;
    pointer-events:auto;page-break-after:always;break-after:page;
    background:#08080A;overflow:hidden}
  .slide:last-child{page-break-after:auto;break-after:auto}
  [data-anim]{opacity:1!important;transform:none!important;filter:none!important;transition:none!important}
  .mask>span{transform:none!important;transition:none!important}
  .val::after,.timeline .line{transform:scaleX(1)!important}
  .arcpath{stroke-dashoffset:0!important}
  .skyline .annex{height:196px!important}
  .skyline .bld{height:540px!important}
  .skyline .low{height:120px!important}
  .skyline .mast{height:48px!important}
  .matrix tbody tr{opacity:1!important;transform:none!important}
  *{-webkit-print-color-adjust:exact;print-color-adjust:exact}
}
