/* ===========================================================
   Physicl - shared foundation
   Tokens lifted verbatim from the live physicl.ai stylesheet.
   =========================================================== */

@font-face{font-family:Aspekta;src:url("https://cdn.prod.website-files.com/6abe2f7f24d2b0156b3974c2/6abe4bc3166a2e9d0d37a896_font-aspekta-450.woff2") format("woff2");font-weight:400;font-display:swap}
@font-face{font-family:Aspekta;src:url("https://cdn.prod.website-files.com/6abe2f7f24d2b0156b3974c2/6abe4bc3e21a54a5bea6f8da_font-aspekta-500.woff2") format("woff2");font-weight:500;font-display:swap}
@font-face{font-family:Geistmono;src:url("https://cdn.prod.website-files.com/6abe2f7f24d2b0156b3974c2/6abe4bc439df96a09beb07ed_font-geistmono-500.woff2") format("woff2");font-weight:500;font-display:swap}

:root{
  --n25:#fdfdfc; --n50:#fafaf9; --n100:#f5f5f4; --n200:#e7e5e4; --n300:#d6d3d1;
  --n400:#a8a29e; --n500:#78716c; --n600:#57534e; --n700:#44403c; --n800:#292524;
  --n900:#1c1917; --n950:#171412;
  --ok:#41cc50;
  --pad:2.5rem;
  --r:12px; --rl:16px; --rxl:24px;
  --maxw:1240px;
  --shadow-card:0 0 0 1px rgba(0,0,0,.05), 0 8px 20px 0 rgba(23,20,18,.04), 0 24px 64px 0 rgba(23,20,18,.06);
  --shadow-lift:0 0 0 1px rgba(0,0,0,.06), 0 18px 40px 0 rgba(23,20,18,.08), 0 48px 100px 0 rgba(23,20,18,.10);
  /* v83. One ladder for type and rules on dark, five rungs. Before this there were
     forty-nine distinct alphas of the same cream across the stylesheets, which is what
     a design system looks like when it is not one. Values under .10 are left alone:
     those are shadows and gradient stops, where the exact number is load bearing. */
  --od-1:rgba(250,250,249,.95);   /* primary on dark   */
  --od-2:rgba(250,250,249,.72);   /* secondary         */
  --od-3:rgba(250,250,249,.50);   /* tertiary, mono    */
  --od-4:rgba(250,250,249,.30);   /* faint             */
  --od-5:rgba(250,250,249,.14);   /* hairlines, fills  */
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
}

*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
body{
  margin:0;background:var(--n50);color:var(--n800);
  font-family:Aspekta,-apple-system,BlinkMacSystemFont,"Segoe UI",Arial,sans-serif;
  font-weight:400;font-size:16px;line-height:1.45;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  font-feature-settings:"ss01","cv01";
}
img,video,svg{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
::selection{background:var(--n800);color:var(--n50)}

/* ---------- layout ---------- */
.wrap{width:100%;max-width:var(--maxw);margin:0 auto;padding-inline:var(--pad)}
.wrap-wide{width:100%;max-width:1460px;margin:0 auto;padding-inline:var(--pad)}
section{position:relative}
.sec{padding-block:clamp(60px,7.2vw,116px)}
.rule{height:1px;background:var(--n200);border:0;margin:0}

/* ---------- type ---------- */
h1,h2,h3,h4{font-weight:500;margin:0;color:var(--n800);text-wrap:balance}
h1{font-size:clamp(38px,5.2vw,68px);line-height:1.04;letter-spacing:-.035em}
h2{font-size:clamp(30px,3.5vw,46px);line-height:1.08;letter-spacing:-.028em}
h3{font-size:clamp(20px,1.6vw,27px);line-height:1.18;letter-spacing:-.02em}
p{margin:0}
.lede{font-size:clamp(17px,1.35vw,21px);line-height:1.5;color:var(--n600);letter-spacing:-.011em;text-wrap:pretty}
.body{font-size:16.5px;line-height:1.6;color:var(--n600);text-wrap:pretty}
.small{font-size:14px;line-height:1.55;color:var(--n500)}
.mono{font-family:Geistmono,ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:500;
  font-size:11.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--n400)}
.mono-lg{font-family:Geistmono,ui-monospace,monospace;font-weight:500;letter-spacing:.02em}
.eyebrow{display:flex;align-items:center;gap:10px;margin-bottom:22px}
.eyebrow::after{content:"";flex:1;height:1px;background:var(--n200)}
.eyebrow.center{justify-content:center}
.eyebrow.center::after{display:none}
.stack>*+*{margin-top:var(--gap,18px)}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;gap:8px;padding:12.8px 18px;border-radius:var(--r);
  font-size:16px;font-weight:500;letter-spacing:-.01em;border:1.5px solid transparent;
  transition:transform .18s var(--ease),background .18s var(--ease),border-color .18s var(--ease),color .18s var(--ease)}
.btn:active{transform:translateY(1px)}
.btn-primary{background:var(--n800);color:var(--n50);border-color:var(--n800)}
.btn-primary:hover{background:var(--n950);border-color:var(--n950)}
.btn-secondary{background:var(--n200);color:var(--n800);border-color:var(--n200)}
.btn-secondary:hover{background:var(--n300);border-color:var(--n300)}
.btn-ghost{background:transparent;color:var(--n800);border-color:var(--n300)}
.btn-ghost:hover{border-color:var(--n800)}
.btn-sm{padding:9px 14px;font-size:14.5px}
.btn .arw{transition:transform .22s var(--ease)}
.btn:hover .arw{transform:translateX(3px)}
.on-dark .btn-primary{background:var(--n50);color:var(--n950);border-color:var(--n50)}
.on-dark .btn-primary:hover{background:#fff;border-color:#fff}
.on-dark .btn-ghost{color:var(--n50);border-color:var(--od-4)}
.on-dark .btn-ghost:hover{border-color:var(--od-2)}

.txtlink{display:inline-flex;align-items:center;gap:7px;font-size:15.5px;color:var(--n800);
  padding-bottom:2px;border-bottom:1px solid var(--n300);transition:border-color .2s,gap .2s}
.txtlink:hover{border-color:var(--n800);gap:11px}

/* ---------- nav ---------- */
.nav{position:fixed;inset:0 0 auto;z-index:100;transition:background .3s var(--ease),border-color .3s,backdrop-filter .3s;
  border-bottom:1px solid transparent}
/* v95. Measured against the live physicl.ai nav, which computes to
   rgba(255,255,255,.1) + blur(6px). Ours was rgba(250,250,249,.5) plus
   saturate(170%): five times the opacity, and the saturate pushed it whiter
   again, so the bar read as a white band instead of glass. Alpha down to .14,
   saturate gone, blur up to 16px to keep the links legible over a busy frame
   now that the tint is doing almost nothing. */
.nav.stuck{background:rgba(250,250,249,.14);backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);border-bottom-color:transparent}
.nav-in{display:flex;align-items:center;gap:30px;height:66px}
.brand{display:flex;align-items:center;gap:9px;margin-right:6px}
.brand svg,.brand img{height:19px;width:auto}
.brand .tag{font-family:Geistmono,monospace;font-size:10.5px;font-weight:500;letter-spacing:.06em;
  color:var(--n600);border:1px solid var(--n300);border-radius:999px;padding:3px 8px 2px}
.nav-links{display:flex;align-items:center;gap:26px;font-size:15px;color:var(--n700)}
.nav-links a{position:relative;padding-block:6px;transition:color .18s}
.nav-links a:hover{color:var(--n950)}
.nav-links a::after{content:"";position:absolute;left:0;right:100%;bottom:0;height:1px;background:var(--n800);
  transition:right .28s var(--ease-out)}
.nav-links a:hover::after{right:0}
.nav-cta{margin-left:auto;display:flex;align-items:center;gap:10px}
/* v108. Careers made six items, and between 940 and about 1060 the row and the
   two buttons no longer fit on one line: four of them wrapped. The menu takes
   over earlier rather than the bar being cramped. */
@media(max-width:1060px){.nav-links{display:none}}

/* ---------- footer ---------- */
.foot{background:var(--n950);color:var(--n300);padding-block:74px 34px}
.foot h3,.foot h4{color:var(--n50);font-size:13px;letter-spacing:.06em;text-transform:uppercase;
  font-family:Geistmono,monospace;font-weight:500;margin-bottom:16px}
.foot a{color:var(--n400);font-size:15px;line-height:2;transition:color .18s}
.foot a:hover{color:var(--n50)}
.foot-grid{display:grid;grid-template-columns:1.6fr repeat(4,1fr);gap:40px}
.foot-bot{margin-top:56px;padding-top:24px;border-top:1px solid var(--od-5);
  display:flex;justify-content:space-between;gap:20px;flex-wrap:wrap;font-size:13.5px;color:var(--n500)}
@media(max-width:860px){.foot-grid{grid-template-columns:1fr 1fr;gap:32px}}

/* ---------- reveal ---------- */
.rv{opacity:0;transform:translateY(18px);transition:opacity .85s var(--ease-out),transform .85s var(--ease-out)}
.rv.in{opacity:1;transform:none}
.rv-d1{transition-delay:.07s}.rv-d2{transition-delay:.14s}.rv-d3{transition-delay:.21s}
.rv-d4{transition-delay:.28s}.rv-d5{transition-delay:.35s}.rv-d6{transition-delay:.42s}
.clip{display:block;overflow:hidden}
/* manual line breaks must not wrap inside their mask */
h1 .clip,h2 .clip{white-space:nowrap}
@media(max-width:820px){h1 .clip,h2 .clip{white-space:normal;overflow:visible}}
.clip>span{display:block;transform:translateY(102%);transition:transform 1.05s var(--ease-out)}
.rv.in .clip>span,.clip.in>span{transform:none}
@media(prefers-reduced-motion:reduce){
  .rv,.clip>span{opacity:1!important;transform:none!important;transition:none!important}
  html{scroll-behavior:auto}
}

/* ---------- media ---------- */
.frame{position:relative;overflow:hidden;border-radius:var(--rl);background:var(--n100);
  box-shadow:var(--shadow-card)}
.frame video,.frame img{width:100%;height:100%;object-fit:cover}
.frame-flat{box-shadow:0 0 0 1px var(--n200)}
.cap{display:flex;justify-content:space-between;gap:12px;margin-top:11px}

/* label chip sitting on media */
.chip{position:absolute;z-index:2;font-family:Geistmono,monospace;font-size:10.5px;font-weight:500;
  letter-spacing:.09em;text-transform:uppercase;padding:5px 9px;border-radius:7px;
  background:rgba(23,20,18,.76);color:var(--n50);backdrop-filter:blur(8px)}
.chip.tl{top:12px;left:12px}.chip.tr{top:12px;right:12px}.chip.bl{bottom:12px;left:12px}

/* ---------- logo strip ---------- */
/* v96. Sized on measured wordmark cap height, not on box height. Every one of
   these viewBoxes is already tight, so a common CSS height does NOT make them
   look equal: what the eye compares is the height of the lettering, and at a
   common box that ranges from 97% (Meta, whose wordmark fills the box) down to
   48% (World Labs, a large mark beside small text). Rendering each at 4x and
   measuring the ink band of the wordmark alone gives the ratios below, which
   put every wordmark at the same ~13px cap. v91 got this backwards and made
   Meta larger, which is why it read as the biggest thing in the row. */
.logos{display:flex;align-items:center;
  gap:clamp(20px,3.4vw,46px) clamp(26px,3.6vw,52px);flex-wrap:wrap}
/* v108. The row held three different kinds of asset and treated them alike, so
   two of them came out wrong. Spaitial ships a light on dark wordmark, whose
   white letters disappeared on this background and left only the cyan mark
   behind. Epic's logo is a filled badge with the type knocked out of it, which
   read as a black brick beside eight grey wordmarks. Everything except Epic is
   now flattened to one grey, whatever it started as, so the row is genuinely
   one weight. Epic keeps its real badge and is toned with opacity instead,
   because flattening it fills the type in. */
.logos img{width:auto;opacity:1;filter:grayscale(1) brightness(0) invert(62%);
  transition:filter .3s,opacity .3s}
.logos img:hover{filter:grayscale(1) brightness(0) invert(48%)}
.logos .lg-epic{filter:grayscale(1);opacity:.34}
.logos .lg-epic:hover{filter:grayscale(1);opacity:.5}
.logos .lg-meta{height:14px}
.logos .lg-amazon{height:21px}
.logos .lg-deepmind{height:15px}
.logos .lg-spaitial{height:21px}
.logos .lg-nvidia{height:19px}
.logos .lg-microsoft{height:20px}
.logos .lg-adobe{height:21px}
.logos .lg-epic{height:23px}
.logos .lg-worldlabs{height:26px}



/* ---------- misc ---------- */
.dot{width:6px;height:6px;border-radius:50%;background:var(--ok);display:inline-block;
  box-shadow:0 0 0 3px rgba(65,204,80,.16)}
.pulse{animation:pulse 2.4s ease-in-out infinite}
@keyframes pulse{0%,100%{box-shadow:0 0 0 3px rgba(65,204,80,.16)}50%{box-shadow:0 0 0 6px rgba(65,204,80,.05)}}
.grid-2{display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,3.2vw,56px)}
.grid-3{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,2.4vw,34px)}
.grid-4{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(14px,1.6vw,22px)}
@media(max-width:900px){.grid-2,.grid-3,.grid-4{grid-template-columns:1fr}}
@media(max-width:900px){:root{--pad:1.25rem}}

/* article cards (SEO block - keep the 6 links) */
.arts{display:grid;grid-template-columns:repeat(3,1fr);gap:24px}
.art{display:flex;flex-direction:column;gap:13px;padding-bottom:20px;border-bottom:1px solid var(--n200);
  transition:border-color .25s}
.art:hover{border-color:var(--n800)}
.art .t{font-size:17px;line-height:1.28;letter-spacing:-.017em;color:var(--n800);font-weight:500}
.art:hover .t{text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:1px}
@media(max-width:900px){.arts{grid-template-columns:1fr}}

/* ===========================================================
   Studio card - a live, designed product surface.
   Not a screenshot: real DOM, animated, brand-grade.
   =========================================================== */
.plate{position:relative;border-radius:var(--rxl);overflow:hidden;background:var(--n100)}
.plate>.bg{position:absolute;inset:-6%;width:112%;height:112%;object-fit:cover;
  filter:blur(30px) saturate(1.18) brightness(1.02) contrast(1.05);transform:scale(1.1)}
.plate>.veil{position:absolute;inset:0;
  background:linear-gradient(155deg,var(--od-3),rgba(245,245,244,.40) 42%,rgba(214,211,209,.52))}
.plate>.grain{position:absolute;inset:0;opacity:.5;pointer-events:none;
  background-image:radial-gradient(rgba(23,20,18,.045) 1px,transparent 1px);background-size:3px 3px}
.plate>.inner{position:relative;padding:clamp(22px,3.4vw,58px);display:flex;justify-content:center}

.sc{width:100%;max-width:620px;background:rgba(253,253,252,.94);border-radius:18px;
  box-shadow:0 0 0 1px rgba(23,20,18,.07),0 2px 4px rgba(23,20,18,.03),
             0 18px 40px rgba(23,20,18,.09),0 54px 100px rgba(23,20,18,.11);
  backdrop-filter:blur(20px);overflow:hidden;display:flex;flex-direction:column}
.sc-top{display:flex;align-items:center;gap:9px;padding:13px 16px;border-bottom:1px solid var(--n200);
  background:var(--od-2)}
.sc-top img{height:14px;width:auto;opacity:.9}
.sc-pill{font-family:Geistmono,monospace;font-size:9.5px;font-weight:500;letter-spacing:.09em;
  text-transform:uppercase;border:1px solid var(--n300);border-radius:999px;padding:3px 8px 2px;color:var(--n600)}
.sc-top .spacer{flex:1}
.sc-body{padding:20px 18px 12px;display:flex;flex-direction:column;justify-content:flex-end;
  min-height:318px;gap:0;overflow:hidden}
.sc-body::before{content:"";flex:1}
.m{opacity:0;transform:translateY(14px);filter:blur(5px);transition:opacity .5s var(--ease-out),
  transform .6s var(--ease-out),filter .5s var(--ease-out);margin-top:12px}
.m.in{opacity:1;transform:none;filter:none}
.m.hid{display:none}
.m-u{align-self:flex-end;max-width:84%;background:var(--n900);color:var(--n50);border-radius:14px 14px 4px 14px;
  padding:11px 14px;font-size:14.5px;line-height:1.42;margin-left:auto}
.m-a{font-size:14.5px;line-height:1.52;color:var(--n700);max-width:95%}
.m-a b{color:var(--n900);font-weight:500}
.chips{display:flex;gap:7px;flex-wrap:wrap}
.chip-o{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--n300);border-radius:9px;
  padding:8px 11px;font-size:13.5px;color:var(--n600);background:var(--n25);
  transition:border-color .25s,color .25s,background .25s}
.chip-o .bx{width:13px;height:13px;border-radius:3.5px;border:1.5px solid var(--n300);
  display:inline-block;position:relative;transition:background .25s,border-color .25s}
.chip-o.sel{border-color:var(--n900);color:var(--n900);background:#fff}
.chip-o.sel .bx{background:var(--n900);border-color:var(--n900)}
.chip-o.sel .bx::after{content:"";position:absolute;left:3.5px;top:1px;width:3px;height:6.5px;
  border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(43deg)}
.chip-o .dim{color:var(--n400);font-size:12px}
.tool{display:inline-flex;align-items:center;gap:9px;font-family:Geistmono,monospace;font-size:11px;
  letter-spacing:.04em;color:var(--n500);border:1px solid var(--n200);border-radius:8px;padding:7px 11px;
  background:var(--n25)}
.tool .sp{width:11px;height:11px;border-radius:50%;border:1.6px solid var(--n300);border-top-color:var(--n700);
  animation:spin .75s linear infinite}
.tool.done .sp{border:none;background:var(--ok);position:relative;animation:none}
.tool.done .sp::after{content:"";position:absolute;left:3.5px;top:1px;width:3px;height:6px;
  border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(43deg)}
@keyframes spin{to{transform:rotate(360deg)}}
.sc-out{border:1px solid var(--n200);border-radius:12px;overflow:hidden;background:#fff}
.sc-out-h{display:flex;gap:8px;align-items:center;padding:8px 11px;border-bottom:1px solid var(--n200)}
.sc-grid{display:grid;grid-template-columns:1.62fr 1fr;gap:4px;padding:4px;background:var(--n100)}
.sc-grid .big{grid-row:span 3;border-radius:7px;overflow:hidden;background:var(--n200);aspect-ratio:4/3}
.sc-grid .sm{border-radius:6px;overflow:hidden;background:var(--n200);position:relative;aspect-ratio:16/9}
.sc-grid img,.sc-grid video{width:100%;height:100%;object-fit:cover}
.sc-grid .sm span{position:absolute;left:4px;bottom:3px;font-family:Geistmono,monospace;font-size:8px;
  letter-spacing:.08em;text-transform:uppercase;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.65)}
.sc-stats{display:flex;gap:22px;padding:10px 12px;border-top:1px solid var(--n200)}
.sc-stats div{display:flex;flex-direction:column;gap:2px}
.sc-stats .k{font-family:Geistmono,monospace;font-size:9px;letter-spacing:.1em;text-transform:uppercase;color:var(--n400)}
.sc-stats .v{font-size:14px;font-weight:500;color:var(--n900);letter-spacing:-.01em}
.sc-in{display:flex;align-items:center;gap:10px;margin:8px 14px 14px;padding:10px 12px;
  border:1px solid var(--n200);border-radius:12px;background:#fff}
.sc-in .ph{flex:1;font-size:14px;color:var(--n400)}
.sc-in .ph i{display:inline-block;width:1.5px;height:15px;background:var(--n800);vertical-align:-3px;
  margin-left:1px;animation:car 1.05s step-end infinite}
@keyframes car{0%,49%{opacity:1}50%,100%{opacity:0}}
.sc-in .go{width:27px;height:27px;border-radius:50%;background:var(--n900);color:#fff;display:grid;
  place-items:center;font-size:13px;flex-shrink:0}

/* exploded pass layers */
.stack{position:relative;perspective:1700px;display:grid;place-items:center;overflow:hidden;
  padding:clamp(40px,6vw,86px) clamp(30px,5vw,70px);min-height:clamp(330px,40vw,540px)}
.stack-in{position:relative;width:min(100%,330px);aspect-ratio:3/4;transform-style:preserve-3d;
  transform:rotateX(9deg) rotateY(-19deg) rotateZ(4deg)}
.pl{position:absolute;inset:0;border-radius:11px;overflow:hidden;
  box-shadow:0 0 0 1px rgba(23,20,18,.09),0 26px 60px rgba(23,20,18,.17);
  transform:translateZ(0) translateX(0) translateY(0);opacity:0;
  transition:transform 1.25s var(--ease-out),opacity .8s var(--ease-out)}
.pl img{width:100%;height:100%;object-fit:cover}
.pl .lb{position:absolute;left:9px;top:9px;font-family:Geistmono,monospace;font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:#fff;background:rgba(23,20,18,.68);
  padding:4px 7px;border-radius:5px;backdrop-filter:blur(6px)}
.stack.go .pl{opacity:1}
@media(prefers-reduced-motion:reduce){.pl{transition:none}}

/* ===== showcase: full-width media panel with the product card floating over it ===== */
.showcase{position:relative;border-radius:var(--rxl);overflow:visible;
  margin-top:clamp(56px,6.2vw,96px)}
.showcase .media{position:relative;border-radius:var(--rxl);overflow:hidden;
  aspect-ratio:2.3/1;min-height:clamp(300px,36vw,560px);
  box-shadow:0 0 0 1px rgba(23,20,18,.07),0 30px 70px rgba(23,20,18,.13),0 80px 140px rgba(23,20,18,.10)}
.showcase .media img{width:100%;height:100%;object-fit:cover;transform:scale(1.02)}
.showcase .media::after{content:"";position:absolute;inset:0;
  background:linear-gradient(105deg,rgba(23,20,18,.42),rgba(23,20,18,.05) 46%,rgba(23,20,18,.30))}
.showcase .tagline{position:absolute;left:clamp(22px,3vw,44px);top:clamp(22px,3vw,40px);z-index:3;
  max-width:24ch;color:var(--n50)}
.showcase .tagline .k{font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--od-2)}
.showcase .tagline .v{font-size:clamp(17px,1.5vw,22px);line-height:1.3;letter-spacing:-.018em;margin-top:10px}
.showcase .floater{position:absolute;right:clamp(16px,2.6vw,44px);bottom:clamp(-52px,-3.4vw,-32px);
  z-index:4;width:min(94%,430px)}
.showcase .floater .sc{box-shadow:0 0 0 1px rgba(23,20,18,.08),0 4px 8px rgba(23,20,18,.04),
  0 26px 54px rgba(23,20,18,.15),0 70px 120px rgba(23,20,18,.18)}
.showcase-pad{padding-bottom:clamp(26px,3vw,46px)}
@media(max-width:900px){
  .showcase .media{aspect-ratio:4/3;min-height:0}
  .showcase .floater{position:static;width:100%;margin-top:18px}
  .showcase-pad{padding-bottom:0}
}

/* full-bleed dark band */
.band-dark{position:relative;overflow:hidden;background:var(--n950);color:var(--n50);
  padding-block:clamp(70px,8vw,128px)}
.band-dark .bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.34}
.band-dark::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to right,rgba(23,20,18,.94),rgba(23,20,18,.62) 55%,rgba(23,20,18,.88))}
.band-dark .c{position:relative;z-index:2}
.band-dark h2{color:var(--n50)}
.band-dark .lede{color:var(--od-2)}

/* stack tuned for 16:9 passes */
.stack-in.wide{width:min(100%,540px);aspect-ratio:16/10}
@media(max-width:760px){.stack-in.wide{width:min(100%,330px)}}

/* the floating card is smaller: shorter body so it never reads as empty */
.showcase .floater .sc-body{min-height:236px;padding:16px 15px 10px}
.showcase .floater .sc-in{margin:6px 12px 12px;padding:9px 11px}
.showcase .floater .m{margin-top:10px}
.showcase .tagline .v{max-width:340px}

/* v95. Nav sitting over a dark section, scrolled or not. The :not(.stuck)
   guard was right while the stuck bar was nearly opaque white; with a 14%
   glass bar it left dark text on dark content. site.js now sets over-dark
   from what is actually under the bar, so these apply in both states, and a
   stuck glass bar over a dark section tints dark instead of light. */
.nav.over-dark.stuck{background:rgba(23,20,18,.30);
  backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}
.nav.over-dark .brand img{filter:invert(1) brightness(1.6)}
.nav.over-dark .nav-links a{color:var(--od-2)}
.nav.over-dark .nav-links a:hover{color:#fff}
.nav.over-dark .nav-links a::after{background:#fff}
.nav.over-dark .btn-secondary{background:var(--od-5);color:var(--n50);border-color:transparent}
.nav.over-dark .btn-secondary:hover{background:var(--od-4)}
.nav.over-dark .btn-primary{background:var(--n50);color:var(--n950);border-color:var(--n50)}

/* USP strip: the three reasons, right under the hero */
.usps{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--n200);
  border-top:1px solid var(--n200);border-bottom:1px solid var(--n200)}
.usps>div{background:var(--n50);padding:clamp(22px,2.4vw,32px) clamp(20px,2vw,28px)}
.usps .k{font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.11em;text-transform:uppercase;color:var(--n400)}
.usps .t{font-size:clamp(17px,1.35vw,20px);font-weight:500;letter-spacing:-.018em;color:var(--n900);margin-top:12px}
.usps .d{font-size:15px;line-height:1.55;color:var(--n500);margin-top:9px;max-width:38ch}
@media(max-width:900px){.usps{grid-template-columns:1fr}}
.usps.on-dark-strip{background:var(--od-5);border-color:var(--od-5)}
.usps.on-dark-strip>div{background:var(--n950)}
.usps.on-dark-strip .t{color:var(--n50)}
.usps.on-dark-strip .d{color:var(--od-3)}
.usps.on-dark-strip .k{color:var(--od-3)}


/* ===========================================================
   Exploded pass stack - scroll-driven, pointer-tilted,
   and linked to the layer list beside it.
   =========================================================== */
.stack{position:relative;perspective:1700px;display:grid;place-items:center;overflow:hidden;
  padding:clamp(86px,9.5vw,150px) clamp(40px,6vw,96px);min-height:clamp(400px,48vw,660px)}
.stack-in{position:relative;width:min(100%,330px);aspect-ratio:3/4;transform-style:preserve-3d;
  --sep:0;--px:0deg;--py:0deg;
  transform:rotateX(calc(9deg + var(--py))) rotateY(calc(-19deg + var(--px))) rotateZ(4deg);
  transition:transform .5s var(--ease-out)}
.stack-in.wide{width:min(100%,540px);aspect-ratio:16/10;
  transform:rotateX(calc(11deg + var(--py))) rotateY(calc(-21deg + var(--px))) rotateZ(3deg)}
@media(max-width:760px){.stack-in.wide,.stack-in{width:min(100%,300px)}}

.pl{position:absolute;inset:0;border-radius:11px;overflow:hidden;
  box-shadow:0 0 0 1px rgba(23,20,18,.09),0 26px 60px rgba(23,20,18,.17);
  opacity:0;
  transform:translate3d(calc(var(--dx) * var(--sep)),calc(var(--dy) * var(--sep)),calc(var(--dz) * var(--sep)));
  transition:opacity .7s var(--ease-out),filter .45s var(--ease),box-shadow .45s var(--ease)}
.pl img{width:100%;height:100%;object-fit:cover}
.pl .lb{position:absolute;left:9px;top:9px;font-family:Geistmono,monospace;font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:#fff;background:rgba(23,20,18,.68);
  padding:4px 7px;border-radius:5px;backdrop-filter:blur(6px);
  transition:background .35s var(--ease),transform .35s var(--ease)}
.stack.go .pl{opacity:1}
.stack.go .pl:nth-child(1){transition-delay:.04s}
.stack.go .pl:nth-child(2){transition-delay:.12s}
.stack.go .pl:nth-child(3){transition-delay:.2s}
.stack.go .pl:nth-child(4){transition-delay:.28s}

.pl:nth-child(1){--dx:-40px;--dy:-62px;--dz:150px}
.pl:nth-child(2){--dx:-14px;--dy:-21px;--dz:75px}
.pl:nth-child(3){--dx:13px;--dy:19px;--dz:0px}
.pl:nth-child(4){--dx:39px;--dy:59px;--dz:-75px}
@media(max-width:760px){
  .pl:nth-child(1){--dx:-22px;--dy:-34px;--dz:92px}
  .pl:nth-child(2){--dx:-8px;--dy:-12px;--dz:46px}
  .pl:nth-child(3){--dx:7px;--dy:11px;--dz:0px}
  .pl:nth-child(4){--dx:21px;--dy:33px;--dz:-46px}
}

/* isolate: the hovered layer comes forward, the rest recede and dim */
.stack[data-iso] .pl{filter:saturate(.35) brightness(1.06);opacity:.42;
  box-shadow:0 0 0 1px rgba(23,20,18,.06),0 10px 24px rgba(23,20,18,.08)}
.stack[data-iso] .pl .lb{background:rgba(23,20,18,.3)}
.stack[data-iso="1"] .pl:nth-child(1),
.stack[data-iso="2"] .pl:nth-child(2),
.stack[data-iso="3"] .pl:nth-child(3),
.stack[data-iso="4"] .pl:nth-child(4){filter:none;opacity:1;
  box-shadow:0 0 0 1px rgba(23,20,18,.12),0 34px 74px rgba(23,20,18,.28);z-index:5}
.stack[data-iso="1"] .pl:nth-child(1) .lb,
.stack[data-iso="2"] .pl:nth-child(2) .lb,
.stack[data-iso="3"] .pl:nth-child(3) .lb,
.stack[data-iso="4"] .pl:nth-child(4) .lb{background:rgba(23,20,18,.86);transform:translateY(-1px)}

/* the layer rows drive it, so they read as controls */
/* only rows that drive a layer stack are interactive; a plain list does not move */
.lrow.is-live{cursor:pointer;transition:padding-left .3s var(--ease),border-color .3s}
.lrow.is-live:hover{padding-left:8px}
.lrow.act .n{color:var(--n950)}

@media(prefers-reduced-motion:reduce){
  .stack-in{--sep:1!important;transition:none}
  .pl{transition:none}
}

/* ===========================================================
   Pass wipe - a full-bleed frame that reveals itself as
   synthetic, one ground-truth layer at a time, on scroll.
   =========================================================== */
.wipe{position:absolute;inset:0;--e1:1;--e2:1;--e3:1}
.wipe img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.wipe .l2{clip-path:polygon(calc(var(--e1) * 118% + 6%) 0%, 124% 0%, 124% 100%, calc(var(--e1) * 118% - 12%) 100%)}
.wipe .l3{clip-path:polygon(calc(var(--e2) * 118% + 6%) 0%, 124% 0%, 124% 100%, calc(var(--e2) * 118% - 12%) 100%)}
.wipe .l4{clip-path:polygon(calc(var(--e3) * 118% + 6%) 0%, 124% 0%, 124% 100%, calc(var(--e3) * 118% - 12%) 100%)}
.wipe-key{position:absolute;left:0;right:0;bottom:clamp(18px,3vw,34px);z-index:6;pointer-events:none}
.wipe-key .in{display:flex;gap:clamp(12px,2vw,26px);flex-wrap:wrap;align-items:center}
.wipe-key b{font-family:Geistmono,monospace;font-weight:500;font-size:10.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--od-4);display:inline-flex;align-items:center;gap:7px;
  transition:color .4s var(--ease)}
.wipe-key b::before{content:"";width:5px;height:5px;border-radius:50%;background:var(--od-4);
  transition:background .4s var(--ease),box-shadow .4s var(--ease)}
.wipe-key b.on{color:var(--n50)}
.wipe-key b.on::before{background:var(--n50);box-shadow:0 0 0 3px var(--od-5)}
.wipe-hint{font-family:Geistmono,monospace;font-size:10px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--od-4);margin-left:auto;transition:opacity .4s}
@media(prefers-reduced-motion:reduce){.wipe .l2,.wipe .l3,.wipe .l4{clip-path:none;opacity:0}}

/* ===========================================================
   Condition map - the space of scenes, and the cells where a
   model actually fails. C's signature visual.
   =========================================================== */
.cmap{border:1px solid var(--n200);border-radius:var(--rxl);background:var(--n25);overflow:hidden}
.cmap-h{display:flex;justify-content:space-between;gap:18px;align-items:flex-start;flex-wrap:wrap;
  padding:22px clamp(20px,2.4vw,32px);border-bottom:1px solid var(--n200)}
.cmap-h .t{font-size:clamp(17px,1.4vw,20px);font-weight:500;letter-spacing:-.018em;color:var(--n900);margin-top:8px}
.cmap-b{padding:clamp(22px,2.6vw,34px);display:grid;grid-template-columns:auto 1fr;gap:14px}
.cmap-yl{display:flex;flex-direction:column;justify-content:space-between;padding:2px 0;
  font-family:Geistmono,monospace;font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--n400);
  text-align:right;gap:6px}
.cmap-grid{display:grid;grid-template-columns:repeat(14,1fr);gap:4px}
.cell{aspect-ratio:1;border-radius:3px;background:var(--n200);position:relative;
  transform:scale(.4);opacity:0;
  transition:transform .55s var(--ease-out),opacity .45s var(--ease-out),background .3s,box-shadow .3s}
.cmap.go .cell{transform:none;opacity:1}
.cell[data-hot]{cursor:crosshair}
.cell:hover{box-shadow:0 0 0 2px var(--n900);z-index:3}
.cmap-x{grid-column:2;display:flex;justify-content:space-between;
  font-family:Geistmono,monospace;font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--n400);margin-top:4px}
.cmap-f{display:flex;gap:14px;align-items:flex-start;padding:18px clamp(20px,2.4vw,32px);
  border-top:1px solid var(--n200);background:var(--n100);flex-wrap:wrap}
.cmap-read{font-family:Geistmono,monospace;font-size:11.5px;letter-spacing:.04em;color:var(--n600);
  min-width:250px;padding:7px 11px;border:1px solid var(--n200);border-radius:8px;background:var(--n25)}
.cmap-read b{color:var(--n950);font-weight:500}
.cmap-leg{display:flex;align-items:center;gap:9px;margin-left:auto;
  font-family:Geistmono,monospace;font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--n400)}
.cmap-leg i{display:block;width:74px;height:7px;border-radius:4px;
  background:linear-gradient(to right,#e7e5e4,#78716c,#1c1917)}
@media(max-width:720px){.cmap-grid{grid-template-columns:repeat(10,1fr)}.cmap-b{grid-template-columns:1fr}
  .cmap-yl{flex-direction:row;justify-content:space-between;text-align:left}}
@media(prefers-reduced-motion:reduce){.cell{transform:none;opacity:1;transition:none}}

/* app rows: status is visible at rest, not only on hover */
.seq-row[data-state="soon"]{opacity:.62}
.seq-row[data-state="next"]{opacity:.82}
.seq-row[data-state="soon"]:hover,.seq-row[data-state="next"]:hover,
.seq-row[data-state="soon"].on,.seq-row[data-state="next"].on{opacity:1}
.seq-row .out{display:block;margin-top:9px;font-family:Geistmono,monospace;font-size:11px;
  letter-spacing:.04em;color:var(--n400)}
.seq-row[data-state="live"] .status.live{box-shadow:0 0 0 3px rgba(65,204,80,.1)}

/* ===========================================================
   Floating conversation. No card: the messages sit on the scene,
   tilted slightly off the picture plane, and scrolling pulls the
   thread upward while the older ones soften and dissolve.
   =========================================================== */
/* deliberately taller than the video: the thread lives in front of the panel,
   rising past its top edge and entering from below its bottom edge */
.convo{position:absolute;left:0;right:0;top:-72px;bottom:-66px;z-index:4;
  overflow:clip;overflow-clip-margin:0;pointer-events:none;
  perspective:1200px;perspective-origin:74% 48%;
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 30px,#000 calc(100% - 26px),transparent 100%);
          mask-image:linear-gradient(to bottom,transparent 0,#000 30px,#000 calc(100% - 26px),transparent 100%)}
.convo-track{position:absolute;right:clamp(18px,2.4vw,40px);bottom:clamp(10px,1.4vw,22px);
  width:min(100% - clamp(32px,4vw,64px),560px);
  transform-style:preserve-3d;
  display:flex;flex-direction:column;align-items:stretch;gap:clamp(9px,.9vw,13px);
  transform:translate3d(var(--mx,0px),var(--y,0px),0);
  will-change:transform}
.msg{max-width:min(88%,420px);padding:12px 16px;border-radius:17px;
  font-size:clamp(13.5px,1.02vw,15px);line-height:1.46;letter-spacing:-.008em;
  backdrop-filter:blur(18px) saturate(1.4);-webkit-backdrop-filter:blur(18px) saturate(1.4);
  box-shadow:0 1px 2px rgba(23,20,18,.07),0 14px 38px rgba(23,20,18,.18);
  transform:translate3d(var(--dx,0px),0,var(--dz,0px))
            rotateY(var(--rx,-9deg)) rotateX(var(--ry,2.5deg)) scale(var(--s,1));
  transform-origin:var(--org,50%) 50%;
  transition:box-shadow .35s var(--ease)}
.msg.u{align-self:flex-end;--org:100%;background:rgba(23,20,18,.86);color:var(--n50);
  border-radius:17px 17px 5px 17px}
.msg.a{align-self:flex-start;--org:0%;background:rgba(253,253,252,.9);color:var(--n800);
  border-radius:17px 17px 17px 5px}
.msg.a b{color:var(--n950);font-weight:500}
.msg.pick{align-self:flex-end;--org:100%;background:rgba(253,253,252,.94);color:var(--n900);
  font-family:Geistmono,monospace;font-size:11.5px;letter-spacing:.04em;line-height:1;
  padding:11px 15px 11px 13px;border-radius:999px;max-width:none;width:auto;
  display:inline-flex;align-items:center;gap:9px}
.msg.pick+.msg.pick{margin-top:calc(-1 * clamp(10px,1vw,15px) + 6px)}
.msg.pick span.bx{width:14px;height:14px;border-radius:5px;background:var(--n900);
  flex:0 0 auto;position:relative}
.msg.pick span.bx::after{content:"";position:absolute;left:4.6px;top:3px;width:3px;height:6.5px;
  border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(43deg)}
.msg.pick em{font-style:normal;color:var(--n500)}
.msg.tool{align-self:flex-start;--org:0%;background:rgba(23,20,18,.76);color:var(--od-1);
  font-family:Geistmono,monospace;font-size:11px;letter-spacing:.05em;line-height:1;
  padding:11px 14px;border-radius:10px;max-width:none;width:auto;
  display:inline-flex;align-items:center;gap:9px}
.msg.out{align-self:flex-start;--org:0%;width:100%;max-width:none;padding:12px 12px 11px;
  background:rgba(253,253,252,.93);color:var(--n800);border-radius:15px;
  display:flex;flex-direction:column;gap:10px}
.msg.out .oh{display:flex;align-items:center;gap:8px;font-family:Geistmono,monospace;
  font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--n500)}
.msg.out .oh .sp{flex:1}
.msg.out .og{display:grid;grid-template-columns:repeat(5,1fr);gap:6px}
.msg.out .og figure{margin:0;border-radius:8px;overflow:hidden;background:var(--n200);position:relative;
  aspect-ratio:16/10}
.msg.out .og img{width:100%;height:100%;object-fit:cover;display:block}
.msg.out .og figcaption{position:absolute;left:0;right:0;bottom:0;padding:9px 6px 4px;
  font-family:Geistmono,monospace;font-size:8.5px;letter-spacing:.07em;text-transform:uppercase;
  color:#fff;background:linear-gradient(to top,rgba(23,20,18,.72),transparent)}
.msg.out .of{font-size:12.5px;line-height:1.4;color:var(--n600);letter-spacing:-.004em}
.msg.tool i{width:5px;height:5px;border-radius:50%;background:var(--ok);flex:0 0 auto;
  box-shadow:0 0 0 3px rgba(65,204,80,.2)}
/* pointer isolate, the same move as the pass stack */
.convo-track:hover .msg{opacity:calc(var(--o,1) * .45)}
.convo-track .msg:hover{opacity:var(--o,1)!important;
  box-shadow:0 1px 2px rgba(23,20,18,.07),0 22px 54px rgba(23,20,18,.26)}
.msg{pointer-events:auto}
/* the scene, running slowly behind the thread */
.showcase .media.with-convo{aspect-ratio:2/1}
.showcase .media.with-convo video,
.showcase .media.with-convo img{width:100%;height:100%;object-fit:cover;
  position:absolute;inset:0;transform:scale(1.02)}
.showcase .media.with-convo::after{
  background:linear-gradient(196deg,rgba(23,20,18,.38),rgba(23,20,18,.10) 40%,rgba(23,20,18,.42))}
@media(max-width:900px){
  .showcase .media.with-convo{aspect-ratio:4/5;min-height:0}
  .convo{perspective:800px;top:-40px;bottom:-36px}
  .convo-track{width:calc(100% - 28px);gap:9px}
  .msg{max-width:86%;font-size:13px;padding:10px 13px;line-height:1.42}
  .msg.pick,.msg.tool{font-size:10px;padding:9px 12px}
  .msg.pick{padding-left:10px;gap:7px}
  .msg.pick span.bx{width:12px;height:12px;border-radius:4px}
  .msg.pick span.bx::after{left:4px;top:2.5px;height:5.5px}
  .msg.out .og figcaption{font-size:7px;padding:7px 4px 3px}
  .msg.out .of{font-size:11.5px}
}
@media(prefers-reduced-motion:reduce){
  .convo-track{transform:translate3d(-50%,0,0)}
  .msg{opacity:1!important;filter:none!important}
}

/* ===========================================================
   Hero stack. One clean rectangle while the hero is being read.
   Later in the scroll the passes swing out from their own hinges,
   each showing a tapering wedge of its own edge, the way a stack
   of paper sits when someone has knocked it askew.
   =========================================================== */
.hstack{position:relative;margin-top:clamp(18px,2vw,30px);
  padding:clamp(58px,6.2vw,90px) clamp(36px,4vw,64px);
  overflow:clip;overflow-clip-margin:160px;
  perspective:1700px;perspective-origin:54% 44%}
.hstack-in{position:relative;width:100%;aspect-ratio:2/1;
  min-height:clamp(300px,34vw,560px);transform-style:preserve-3d;
  --sep:0;--px:0deg;--py:0deg;
  transform:rotateX(var(--py)) rotateY(var(--px));
  transition:transform .55s var(--ease-out)}
.hpl{position:absolute;inset:0;border-radius:var(--rxl);overflow:hidden;background:var(--n200);
  transform-origin:var(--ox,50%) var(--oy,50%);
  transform:translate3d(calc(var(--tx,0px) * var(--sep) * var(--k,1)),
                        calc(var(--ty,0px) * var(--sep) * var(--k,1)),
                        calc(var(--tz,0px) * var(--sep) * var(--k,1)))
            rotate(calc(var(--rot,0deg) * var(--sep) * var(--k,1)));
  transition:transform .45s var(--ease-out)}
.hpl>img,.hpl>video{width:100%;height:100%;object-fit:cover;display:block}
.hpl>video{opacity:0;transition:opacity .4s var(--ease)}
.hpl:nth-child(4)>video{opacity:1}
/* The sheets behind are flat. A 15px slice of a segmentation map is
   coloured noise, a flat sheet is a sheet. The pass itself only
   appears when you isolate that layer. No shadows back here either,
   they read as lines against the front panel. */
.hpl>img{opacity:0;transition:opacity .4s var(--ease)}
.hpl:nth-child(4)>video,.hpl:nth-child(4)>img{opacity:1}
/* one deck, fanned. Same hinge at the centre, same rotational direction,
   each sheet further round than the one in front, so every sheet shows at
   the top right and the bottom left. */
.hpl:nth-child(1){--ox:50%;--oy:50%;--rot:-5.1deg;--tx:20px;--ty:-9px;--tz:-104px;background:#b07ab0}
.hpl:nth-child(2){--ox:50%;--oy:50%;--rot:-3.25deg;--tx:13px;--ty:-6px;--tz:-66px;background:#9a97c4}
.hpl:nth-child(3){--ox:50%;--oy:50%;--rot:-1.55deg;--tx:6px;--ty:-3px;--tz:-32px;background:#b9b4ad}
.hpl:nth-child(4){--rot:0deg;--tx:0px;--ty:0px;
  box-shadow:0 0 0 1px rgba(23,20,18,.06),0 20px 50px rgba(23,20,18,.14),0 64px 120px rgba(23,20,18,.10)}
.hstack[data-iso="4"] .hpl:nth-child(1)>video,
.hstack[data-iso="3"] .hpl:nth-child(2)>video,
.hstack[data-iso="2"] .hpl:nth-child(3)>video{opacity:1}
.hpl .lb{display:none}
/* hovering a layer name swings that sheet a little further out */
.hstack[data-iso="4"] .hpl:nth-child(1),
.hstack[data-iso="3"] .hpl:nth-child(2),
.hstack[data-iso="2"] .hpl:nth-child(3){--k:1.3}
@media(max-width:900px){
  .hstack{padding:26px 14px 18px;perspective:900px}
  .hstack-in{aspect-ratio:4/3;min-height:0}
  .hpl:nth-child(1){--rot:-4deg;--tx:11px;--ty:-5px;--tz:-56px}
  .hpl:nth-child(2){--rot:-2.55deg;--tx:7px;--ty:-4px;--tz:-36px}
  .hpl:nth-child(3){--rot:-1.2deg;--tx:3px;--ty:-2px;--tz:-17px}
}
@media(prefers-reduced-motion:reduce){.hstack-in{--sep:1!important;transition:none}}

/* Studio panel inside the suite section */
.spanel{margin-top:clamp(40px,5vw,72px);border:1px solid var(--n200);border-radius:var(--rxl);
  background:var(--n25);padding:clamp(14px,1.6vw,22px);overflow:clip;overflow-clip-margin:90px}
.spanel-hd{display:flex;align-items:center;gap:10px;padding:0 4px 13px}
.spanel-hd .sp{flex:1}

/* ===========================================================
   Sections built for the Studio-led page
   =========================================================== */

/* 03 the problem: filmed against built, the right column fills in */
.cmp{display:grid;grid-template-columns:1fr 1fr;gap:clamp(14px,1.8vw,28px);
  margin-top:clamp(34px,4vw,58px);align-items:start}
@media(max-width:820px){.cmp{grid-template-columns:1fr}}
.cmp-col{border-radius:var(--rxl);padding:clamp(18px,2vw,28px);border:1px solid var(--n200);background:var(--n25)}
.cmp-col.built{border-color:var(--n900);border-width:1.5px;background:#fff;
  box-shadow:0 18px 44px rgba(23,20,18,.07)}
.cmp-col .hd{display:flex;align-items:center;gap:9px;font-family:Geistmono,monospace;font-size:10px;
  letter-spacing:.11em;text-transform:uppercase;color:var(--n500);margin-bottom:14px}
.cmp-col.built .hd{color:var(--n900)}
.cmp-shot{border-radius:var(--r);overflow:hidden;aspect-ratio:16/10;background:var(--n200);margin-bottom:16px}
.cmp-shot img,.cmp-shot video{width:100%;height:100%;object-fit:cover;display:block}
.cmp-row{display:flex;align-items:baseline;gap:12px;padding:9px 0;border-top:1px solid var(--n200);
  font-size:14.5px;opacity:0;transform:translateY(6px);
  transition:opacity .5s var(--ease-out),transform .5s var(--ease-out)}
.cmp-row.in{opacity:1;transform:none}
.cmp-col:not(.built) .cmp-row{opacity:1;transform:none}
.cmp-row .n{flex:1;color:var(--n600)}
.cmp-row .v{font-family:Geistmono,monospace;font-size:11.5px;letter-spacing:.03em;text-align:right}
.cmp-col:not(.built) .cmp-row .v{color:#b45309}
.cmp-col.built .cmp-row .v{color:var(--n950)}
.cmp-note{margin-top:clamp(22px,2.6vw,34px);font-size:15.5px;color:var(--n500);max-width:60ch}

/* 05 studio: the scene with the thread over it */
.studio-stage{position:relative;border-radius:var(--rxl);overflow:hidden;
  aspect-ratio:2/1;min-height:clamp(320px,36vw,600px);
  box-shadow:0 0 0 1px rgba(23,20,18,.07),0 30px 70px rgba(23,20,18,.13)}
.studio-stage>video,.studio-stage>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.studio-stage::after{content:"";position:absolute;inset:0;z-index:2;
  background:linear-gradient(196deg,rgba(23,20,18,.40),rgba(23,20,18,.10) 40%,rgba(23,20,18,.44))}
.stage-cap{position:absolute;left:clamp(20px,2.6vw,42px);top:clamp(18px,2.2vw,34px);z-index:5;color:var(--n50);
  max-width:30ch}
.stage-cap{max-width:none;padding:12px 15px;border-radius:10px;
  background:rgba(23,20,18,.44);backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px)}
.stage-cap>*{font-family:Geistmono,monospace;white-space:nowrap}
.stage-cap .k{font-size:10px;letter-spacing:.13em;text-transform:uppercase;color:var(--od-2)}
.stage-cap .v{font-size:12px;letter-spacing:.02em;color:var(--n50);margin-top:7px}
.stage-cap .w{font-size:9.5px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--od-2);margin-top:6px}
@media(max-width:620px){.stage-cap>*{white-space:normal}}

/* 06 what you can vary */
.vary{display:grid;grid-template-columns:84px 1fr;gap:clamp(12px,1.4vw,20px);align-items:center;
  margin-top:clamp(9px,1vw,14px)}
@media(max-width:820px){.vary{grid-template-columns:1fr;gap:8px}}
.vary .axis{font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--n400)}
.vary .cells{display:grid;grid-template-columns:repeat(6,1fr);gap:clamp(5px,.6vw,9px)}
.vcell{position:relative;border-radius:8px;overflow:hidden;aspect-ratio:16/10;background:var(--n200);
  transition:transform .4s var(--ease-out),box-shadow .4s var(--ease);
  opacity:0;transform:translateY(10px) scale(.97)}
.vcell.in{opacity:1;transform:none}
.vcell img,.vcell video{width:100%;height:100%;object-fit:cover;display:block}
.vcell:hover{transform:scale(1.07);z-index:4;box-shadow:0 12px 30px rgba(23,20,18,.22)}
.vcell .cl{position:absolute;left:0;right:0;bottom:0;padding:14px 6px 4px;opacity:0;
  font-family:Geistmono,monospace;font-size:8.5px;letter-spacing:.03em;text-transform:uppercase;color:#fff;
  background:linear-gradient(to top,rgba(23,20,18,.8),transparent);transition:opacity .3s}
.vcell:hover .cl{opacity:1}
.vcell .pl{position:absolute;right:6px;top:6px;width:5px;height:5px;border-radius:50%;background:var(--ok);
  box-shadow:0 0 0 3px rgba(65,204,80,.25)}
@media(max-width:620px){.vary .cells{grid-template-columns:repeat(3,1fr)}}
@media(max-width:900px){
  .studio-stage{aspect-ratio:4/5;min-height:0}
  .stage-cap{max-width:24ch}
}

/* ===========================================================
   Section intro: heading left, lede right, on one baseline.
   Stops every section from being a half-empty row.
   =========================================================== */
.intro{display:grid;grid-template-columns:minmax(0,1.04fr) minmax(0,.86fr);
  gap:clamp(24px,4.4vw,92px);align-items:start}
@media(max-width:940px){.intro{grid-template-columns:1fr;gap:18px}}
.intro h2{margin:0}
.intro .lede{margin:0;padding-top:.5em;max-width:46ch}
.band-dark .intro .lede{color:var(--od-2)}

/* a pair of sections that belong together share one gap instead of two */
.sec.pair{padding-top:clamp(30px,3.4vw,54px)}

/* dark band without the background wash: cleaner, and the stack reads */
.band-dark.plain{background:var(--n950)}
.band-dark.plain::after{display:none}

/* the pass stack sits centred in its half rather than crowding the edge */
.layers-wrap{grid-template-columns:.92fr 1fr;align-items:center}
.stack{padding:clamp(22px,2.4vw,40px) clamp(20px,2.6vw,46px)}
.stack-in.wide{width:min(100%,600px)}
/* the hero caption sits on the panel, inside the fan's padding */
.hero-cap{position:absolute;z-index:6;
  left:calc(clamp(36px,4vw,64px) + 16px);top:calc(clamp(58px,6.2vw,90px) + 16px)}
@media(max-width:900px){.hero-cap{left:28px;top:34px}}

/* ===========================================================
   v3 - hero gutter alignment, Studio as a two column demo,
   a thread that types itself in, and the pass stack uncropped.
   =========================================================== */

/* 1. the hero text sits on the same left and right edge as the video panel */
:root{--hp:clamp(36px,4vw,64px)}
.hstack{padding-inline:var(--hp)}
.hero>.wrap-wide>.rv:first-child,
.hero .hero-row{padding-inline:var(--hp)}
.hero-cap{left:calc(var(--hp) + 16px)}
@media(max-width:900px){
  :root{--hp:14px}
  .hero>.wrap-wide>.rv:first-child,.hero .hero-row{padding-inline:0}
  .hero-cap{left:28px;top:34px}
}

/* 2. Studio: explainer and call to action on the left, the scene on the right */
.studio-grid{display:grid;grid-template-columns:minmax(0,.82fr) minmax(0,1fr);
  gap:clamp(26px,4.2vw,78px);align-items:center;margin-top:clamp(22px,2.6vw,38px)}
.studio-say h2{margin:0}
.studio-say .lede{margin-top:clamp(15px,1.6vw,22px);max-width:44ch}
.slist{margin-top:clamp(22px,2.6vw,34px)}
.srow{display:flex;gap:14px;padding:13px 0;border-top:1px solid var(--n200)}
.srow .k{font-family:Geistmono,monospace;font-size:11px;color:var(--n400);min-width:24px;padding-top:3px}
.srow b{display:block;font-size:16px;font-weight:500;color:var(--n900);letter-spacing:-.015em}
.srow i{display:block;font-style:normal;font-size:14px;color:var(--n500);margin-top:3px;line-height:1.5}

.studio-demo{position:relative;padding-top:var(--tpad,150px)}
.sstage{position:relative;border-radius:var(--rxl);overflow:hidden;aspect-ratio:4/3;
  background:var(--n200);
  box-shadow:0 0 0 1px rgba(23,20,18,.07),0 30px 70px rgba(23,20,18,.13)}
.sstage>video,.sstage>img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.sstage::after{content:"";position:absolute;inset:0;z-index:2;
  background:linear-gradient(196deg,rgba(23,20,18,.42),rgba(23,20,18,.12) 42%,rgba(23,20,18,.40))}

/* the thread is a sibling of the panel, not a child of it, so nothing clips it */
.thread{position:absolute;z-index:6;left:clamp(-108px,-5.4vw,-30px);right:clamp(12px,1.6vw,26px);
  bottom:clamp(12px,1.5vw,24px);display:flex;flex-direction:column;align-items:stretch;
  gap:clamp(8px,.85vw,12px);pointer-events:none;
  perspective:1250px;perspective-origin:78% 50%;
  transform:translate3d(var(--tx,0px),var(--ty,0px),0);
  transition:transform .66s var(--ease-out);will-change:transform}
.thread .msg{opacity:0;pointer-events:auto;
  transform:translate3d(0,16px,var(--dz,0px)) rotateY(-9deg) rotateX(2deg) scale(.962);
  transition:opacity .46s var(--ease-out),transform .6s var(--ease-out)}
.thread .msg.on{opacity:1;
  transform:translate3d(0,0,var(--dz,0px)) rotateY(-9deg) rotateX(2deg) scale(1)}

/* the four ground truth choices are pills that tick themselves one by one */
.msg.picks{align-self:flex-end;--org:100%;background:none;box-shadow:none;padding:0;
  backdrop-filter:none;-webkit-backdrop-filter:none;max-width:none;width:auto;
  display:flex;flex-wrap:wrap;gap:7px;justify-content:flex-end}
.thread .msg.picks{opacity:1;transform:none;transition:none}
.pk{display:inline-flex;align-items:center;gap:8px;background:rgba(253,253,252,.94);color:var(--n900);
  font-family:Geistmono,monospace;font-size:11px;letter-spacing:.04em;line-height:1;
  padding:10px 14px 10px 12px;border-radius:999px;
  box-shadow:0 1px 2px rgba(23,20,18,.07),0 10px 26px rgba(23,20,18,.16);
  backdrop-filter:blur(18px) saturate(1.4);-webkit-backdrop-filter:blur(18px) saturate(1.4);
  opacity:0;transform:translateY(9px) scale(.94);
  transition:opacity .32s var(--ease-out),transform .42s var(--ease-out)}
.msg.picks.on .pk{opacity:1;transform:none}
.msg.picks.on .pk:nth-child(1){transition-delay:.03s}
.msg.picks.on .pk:nth-child(2){transition-delay:.15s}
.msg.picks.on .pk:nth-child(3){transition-delay:.27s}
.msg.picks.on .pk:nth-child(4){transition-delay:.39s}
.pk .bx{width:14px;height:14px;border-radius:5px;background:var(--n900);flex:0 0 auto;position:relative}
.pk .bx::after{content:"";position:absolute;left:4.6px;top:3px;width:3px;height:6.5px;
  border:solid #fff;border-width:0 1.5px 1.5px 0;transform:rotate(43deg)}
.pk em{font-style:normal;color:var(--n500)}
.thread .msg.out{max-width:none;width:100%}
.thread .msg.out .og figure{aspect-ratio:16/11}

@media(max-width:1000px){
  .studio-grid{grid-template-columns:1fr;gap:clamp(30px,5vw,54px)}
  .studio-demo{padding-top:var(--tpad,120px)}
  .thread{left:clamp(-26px,-2vw,-10px);right:10px}
}
@media(max-width:640px){
  .sstage{aspect-ratio:1/1}
  .thread{left:0;right:0;gap:8px}
  .thread .msg{font-size:13px;padding:10px 13px;line-height:1.42}
  .pk{font-size:10px;padding:9px 12px 9px 10px}
  .thread .msg,.thread .msg.on{transform:translate3d(0,var(--sy,0px),0) scale(var(--ss,1))}
  .thread .msg{--sy:12px;--ss:.97}
  .thread .msg.on{--sy:0px;--ss:1}
}

/* 3. the exploded pass stack gets the room it needs, and stops at the band */
.layers-wrap{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}
.stack{padding:clamp(30px,3.4vw,58px) clamp(28px,3.4vw,58px);
  min-height:clamp(320px,34vw,500px);
  overflow:clip;overflow-clip-margin:70px}
.layers-wrap{margin-top:clamp(28px,3.2vw,48px)!important}
.stack-in.wide{width:min(100%,470px)}
@media(max-width:1000px){.stack-in.wide{width:min(100%,400px)}}
@media(max-width:760px){.stack-in.wide{width:min(100%,300px)}}

/* the hero caption belongs to the deck: it sits in the same 3D space as the
   sheets, a little in front of the front panel, so it turns and parallaxes
   with them instead of floating over the whole thing on its own plane */
.hero-cap{position:absolute;left:clamp(14px,1.5vw,22px);top:clamp(14px,1.5vw,22px);z-index:6;
  background:linear-gradient(135deg,rgba(23,20,18,.66),rgba(23,20,18,.52));
  transform-style:preserve-3d;transform:translate3d(0,0,38px);
  transition:transform .32s var(--ease-out)}
@media(max-width:900px){.hero-cap{left:12px;top:12px}}

/* ===========================================================
   v5 - the caption as a scrim on the edge of the panel, and
   the problem section rebuilt as a reel that resolves on one line.
   =========================================================== */

/* the technical caption: a soft gradient off the panel edge, no box */
.cap-scrim{position:absolute;inset:auto 0 0 0;z-index:5;
  padding:44px clamp(18px,2vw,30px) clamp(13px,1.4vw,19px);
  background:linear-gradient(to top,rgba(23,20,18,.6),rgba(23,20,18,.22) 52%,rgba(23,20,18,0));
  font-family:Geistmono,monospace;font-size:clamp(9.5px,.78vw,11px);letter-spacing:.07em;
  text-transform:uppercase;color:var(--od-1);pointer-events:none}
.cap-scrim.top{inset:0 0 auto 0;
  padding:clamp(13px,1.4vw,19px) clamp(18px,2vw,30px) 44px;
  background:linear-gradient(to bottom,rgba(23,20,18,.6),rgba(23,20,18,.22) 52%,rgba(23,20,18,0))}
@media(max-width:820px){.cap-scrim{font-size:9px;letter-spacing:.05em;line-height:1.5}}

/* the reel: real footage running past, and the count that goes with it */
.reelwrap{position:relative;margin-top:clamp(30px,3.6vw,54px);border-radius:var(--rxl);
  overflow:clip;background:var(--n200);height:clamp(92px,9.4vw,142px);
  -webkit-mask-image:linear-gradient(to right,transparent 0,#000 56px,#000 calc(100% - 56px),transparent 100%);
          mask-image:linear-gradient(to right,transparent 0,#000 56px,#000 calc(100% - 56px),transparent 100%)}
.reel{position:absolute;inset:0;display:flex;gap:5px;width:max-content;
  transform:translate3d(var(--tx,0px),0,0)}
.reel img{height:100%;width:auto;flex:0 0 auto;display:block;object-fit:cover;
  filter:saturate(.92) contrast(1.02)}
.reeltag{display:inline-flex;align-items:center;gap:8px;margin-bottom:11px;
  font-family:Geistmono,monospace;font-size:10px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--n400)}
.reeltag .rec{width:6px;height:6px;border-radius:50%;background:#e5484d;
  box-shadow:0 0 0 3px rgba(229,72,77,.16)}

.land{margin-top:clamp(28px,3.2vw,46px);font-size:clamp(28px,3.7vw,54px);line-height:1.08;
  letter-spacing:-.032em;color:var(--n400);max-width:30ch;text-wrap:balance}
.land .n{color:var(--n950);font-variant-numeric:tabular-nums lining-nums;
  font-feature-settings:"tnum" 1}
.land b{font-weight:500;color:var(--n950);opacity:0;
  transition:opacity .6s var(--ease-out)}
.land.landed b{opacity:1}
.landsub{margin-top:clamp(14px,1.6vw,22px);font-size:clamp(16px,1.3vw,19px);line-height:1.5;
  color:var(--n500);max-width:56ch}

/* ===========================================================
   v6 - the hero deck becomes F plus G, hinged at its bottom
   left corner with every sheet lifting as well, at the settings
   chosen in the lab: half at 1.32, unevenness 36, tilt 2.0.
   =========================================================== */
.hstack{padding:var(--head,150px) var(--hp) clamp(20px,2.4vw,36px);
  overflow:clip;overflow-clip-margin:0;perspective-origin:54% 46%}
.hstack-in{--a:.66;--u:.36;--hx:0px;--hy:0px;
  --ru:-3.1deg;--xu:5px;--yu:-16px;--zu:-50px;
  transform:translateY(calc(var(--head,150px) * (var(--sep) - 1) * .74))
            rotateX(var(--py)) rotateY(var(--px));
  transition:transform .34s var(--ease-out)}
.hpl{--k:calc(var(--i,0) * var(--a));
  --mr:calc(1 + (var(--jr,1) - 1) * var(--u));
  --my:calc(1 + (var(--jy,1) - 1) * var(--u));
  --mz:calc(1 + (var(--jz,1) - 1) * var(--u));
  --mx:calc(1 + (var(--jx,1) - 1) * var(--u));
  transform-origin:calc(6% + var(--jo,0px)) 94%;
  transform:translate3d(calc(var(--xu) * var(--k) * var(--mx) * var(--sep) + var(--hx) * var(--i,0)),
                        calc(var(--yu) * var(--k) * var(--my) * var(--sep) + var(--hy) * var(--i,0)),
                        calc(var(--zu) * var(--k) * var(--mz) * var(--sep)))
            rotate(calc(var(--ru) * var(--k) * var(--mr) * var(--sep)));
  transition:transform .32s var(--ease-out)}
/* the steps are uneven on purpose: same direction every time, only the size
   of each one varies, and each hinge is shifted a few pixels */
.hpl:nth-child(1){--i:3;--jr:.9;--jy:1.1;--jz:.95;--jx:1.18;--jo:7px}
.hpl:nth-child(2){--i:2;--jr:1.2;--jy:.84;--jz:1.14;--jx:.68;--jo:-9px}
.hpl:nth-child(3){--i:1;--jr:.78;--jy:1.24;--jz:.9;--jx:1.3;--jo:0px}
.hpl:nth-child(4){--i:0}
@media(max-width:900px){
  .hstack{padding:var(--head,90px) 14px 18px;perspective:900px}
  .hstack-in{--a:.5}
}

/* ===========================================================
   v7 - the problem is one dark block. Headline, the footage and
   the line that lands, nothing else, so there is one thing to
   look at at a time.
   =========================================================== */
.problem-band{background:var(--n950);color:var(--n50);
  padding-block:clamp(56px,6.6vw,104px);overflow:clip}
.problem-band h2{color:var(--n50);max-width:18ch}
.problem-band .reelwrap{margin-top:clamp(40px,4.8vw,76px);border-radius:12px;background:#241f1c;
  height:clamp(74px,7.2vw,110px)}
.reelfoot{display:flex;justify-content:space-between;align-items:baseline;gap:20px;margin-top:15px;
  font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;
  color:var(--od-3)}
.reelfoot .c{color:var(--n50);font-size:13px;letter-spacing:.02em}
.problem-band .land{margin-top:clamp(44px,5.2vw,82px);color:var(--od-3);max-width:30ch}
.problem-band .land .n,.problem-band .land b{color:var(--n50)}
/* the display face has proportional figures, a 1 is 13px narrower than a 0 at this
   size, so each digit is boxed by hand and the words after it stop moving */
.land .n i{font-style:normal;display:inline-block;width:.62em;text-align:center}
.land .n i.sep{width:.26em}
.problem-band .landsub{margin-top:clamp(16px,1.8vw,24px);color:var(--od-3);max-width:48ch}
@media(max-width:700px){.problem-band h2{max-width:none}}

/* ===========================================================
   v8 - the nav answers the background, the closing line waits
   its turn, and Studio loses the step list it was narrating.
   =========================================================== */

/* over a dark section the bar keeps exactly the same glass, it just
   inverts: the tint goes dark and the type and logo go white */
.nav.on-dark{background:rgba(23,20,18,.42);
  backdrop-filter:saturate(170%) blur(11px);-webkit-backdrop-filter:saturate(170%) blur(11px);
  border-bottom-color:transparent}
.nav.on-dark .brand img{filter:invert(1) brightness(1.7)}
.nav.on-dark .nav-links{color:var(--od-2)}
.nav.on-dark .nav-links a{color:var(--od-2)}
.nav.on-dark .nav-links a:hover{color:#fff}
.nav.on-dark .nav-links a::after{background:#fff}
.nav.on-dark .btn-secondary{background:var(--od-5);color:var(--n50);
  border-color:var(--od-5)}
.nav.on-dark .btn-secondary:hover{background:var(--od-4);border-color:var(--od-4)}
.nav.on-dark .btn-primary{background:var(--n50);color:var(--n950);border-color:var(--n50)}
.nav.on-dark .btn-primary:hover{background:#fff;border-color:#fff}

/* the closing line arrives with the landing, not before it */
.problem-band .landsub{opacity:0;transform:translateY(8px);
  transition:opacity .6s var(--ease-out) .18s,transform .6s var(--ease-out) .18s}
.problem-band .land.landed ~ .landsub{opacity:1;transform:none}

/* Studio: title, one paragraph, the buttons. The thread on the right already
   shows describe, vary and export, so the numbered list was narrating it twice */
.studio-say .lede{margin-top:clamp(18px,1.9vw,26px);max-width:46ch}
.studio-say .hero-cta{margin-top:clamp(30px,3.4vw,48px)}
.studio-grid{align-items:center;gap:clamp(30px,5vw,96px)}

/* ===========================================================
   v9 - Studio is pinned: the page holds until the renders are out,
   the thread takes its depth from z rather than from rotation, and
   three planes move at three speeds under the pointer.
   =========================================================== */
#studio{padding-block:0}
#studio>.wrap-wide>.rv:first-child{padding-top:0}
.pin-wrap{position:relative;height:340vh}
.pin-stick{position:sticky;top:0;height:100vh;display:flex;align-items:center}
.pin-stick .studio-grid{width:100%;margin-top:0}
@media(max-width:1000px){
  .pin-wrap{height:auto}
  .pin-stick{position:static;height:auto;display:block}
}

/* the scene is the back plane: it slides against the pointer */
.sstage{aspect-ratio:16/10}
.sstage>video{transform:scale(1.06) translate3d(var(--bx,0px),var(--by,0px),0);
  transition:transform .5s var(--ease-out)}

/* Depth language. Planes rotate because they are photographs. Cards carrying
   type stay square to the reader and take their depth from z alone: scale,
   shadow, and a little softness as they fall behind. One perspective, 1700px. */
.thread{perspective:1700px;perspective-origin:74% 50%;
  transform:translate3d(var(--tx,0px),calc(var(--ty,0px) + var(--ythread,0px)),0)
            rotateY(var(--ry,0deg)) rotateX(var(--rx,0deg))}
.thread .msg{transform:translate3d(0,15px,0) scale(.955);
  transition:opacity .42s var(--ease-out),transform .52s var(--ease-out),
             filter .42s var(--ease),box-shadow .42s var(--ease)}
.thread .msg.on{transform:translate3d(calc(var(--mx,0px) * var(--near,1)),
                                      calc(var(--my,0px) * var(--near,1)),0) scale(var(--s,1))}
.thread .msg.on:not(.picks){box-shadow:0 1px 2px rgba(23,20,18,.06),
  0 calc(6px + 16px * var(--near,1)) calc(16px + 34px * var(--near,1)) rgba(23,20,18,.2)}
.thread .msg.picks{box-shadow:none;background:none;
  backdrop-filter:none;-webkit-backdrop-filter:none}

/* the loader: one small circle, and only while the assistant is writing */
.typing{align-self:flex-start;display:none;padding:6px 4px;pointer-events:none}
.typing.on{display:block}
.typing i{display:block;width:11px;height:11px;border-radius:50%;background:#fff;
  box-shadow:0 1px 2px rgba(23,20,18,.28),0 6px 18px rgba(23,20,18,.28);
  animation:tp 1.45s var(--ease) infinite}
@keyframes tp{0%,100%{opacity:.4;transform:scale(.72)}48%{opacity:1;transform:scale(1)}}

/* ===========================================================
   v10 - the variation matrix moves to the right of its own
   heading and gets smaller, so it reads as evidence beside the
   claim rather than as a wall of pictures.
   =========================================================== */
.vary-grid{display:grid;grid-template-columns:minmax(0,.72fr) minmax(0,1fr);
  gap:clamp(26px,4.2vw,80px);align-items:center;margin-top:clamp(10px,1.2vw,18px)}
.vary-say h2{margin:0;max-width:15ch}
.vary-say .lede{margin-top:clamp(15px,1.6vw,22px);max-width:38ch}
.vary-cells .vary{grid-template-columns:54px minmax(0,1fr);gap:12px;
  margin-top:clamp(5px,.55vw,8px)}
.vary-cells .vary:first-child{margin-top:0}
.vary-cells .vary .axis{font-size:9.5px;letter-spacing:.11em}
.vary-cells .cells{gap:clamp(3px,.36vw,5px)}
.vary-cells .vcell{border-radius:5px}
.vary-cells .vcell .cl{font-size:7.5px;padding:10px 4px 3px;letter-spacing:.04em}
.vary-cells .vcell:hover{transform:scale(1.14);z-index:6}
.vary-cells .vcell .pl{width:4px;height:4px;right:4px;top:4px}
@media(max-width:1000px){
  .vary-grid{grid-template-columns:1fr;gap:clamp(26px,4vw,44px)}
  .vary-say h2,.vary-say .lede{max-width:none}
}
@media(max-width:620px){.vary-cells .vary{grid-template-columns:1fr;gap:6px}}

/* ===========================================================
   v11 - one spacing scale, one two column shape, one thing
   moving per section. The page had eight different section
   paddings and four different column splits; it has one of each
   now, so every joint between two sections is the same size.
   =========================================================== */
:root{
  --sec-pad:clamp(58px,6.4vw,100px);   /* half a joint: two sections give one gap */
  --gap-part:clamp(34px,4vw,64px);     /* heading to the thing it introduces */
  --gap-col:clamp(32px,4.4vw,80px);    /* the one column gap */
}

/* every section pays the same, so every joint is 2 x --sec-pad */
.sec,.sec.pair,.problem-band,.band-dark,body>section{padding-block:var(--sec-pad)}
.hero{padding-top:clamp(70px,6.4vw,94px);padding-bottom:var(--sec-pad)}
.hero.showcase-pad{padding-bottom:var(--sec-pad)}
#studio{padding-block:var(--sec-pad)}
#studio>.wrap-wide>.rv:first-child{padding-top:0}
.pin-wrap{height:320vh}
.logos-sec{padding-block:var(--sec-pad)}

/* the one two column shape: words left, the thing they describe right */
.two{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1fr);
  gap:var(--gap-col);align-items:center}
@media(max-width:1000px){.two{grid-template-columns:1fr;gap:var(--gap-part)}}
.two>div>h2{margin:0}
.two .lede{margin-top:clamp(15px,1.6vw,22px);max-width:42ch}
.studio-grid,.vary-grid{margin-top:var(--gap-part)}
.vary-say h2{max-width:15ch}

/* the ground truth band, now in the same shape */
:is(#ground,#layers) .lrows{margin-top:var(--gap-part)}
:is(#ground,#layers) .lrow{border-color:var(--od-5)}
:is(#ground,#layers) .lrow .n{color:var(--n50)}
:is(#ground,#layers) .lrow .d{color:var(--od-3)}
:is(#ground,#layers) .stack{padding:0;min-height:0}
:is(#ground,#layers) .stack-in.wide{width:min(100%,460px)}

/* one thing moves per section. Sections with a scroll driven animation no
   longer also fade their text in, which was a second motion competing with
   the first every time you crossed a section boundary. */
.hero .rv,.problem-band .rv,#studio .rv{transition-duration:.01s}
.close-sec{padding-block:var(--sec-pad)}

/* ===========================================================
   v13 - the three sheets behind carry their pass. The flat
   colours were there from when the exposed wedge was 15px wide;
   the fan is far wider now, so each sheet shows its own pass.
   =========================================================== */
.hpl>video{opacity:1}
.hpl:nth-child(1),.hpl:nth-child(2),.hpl:nth-child(3){background:var(--n900)}


/* ===========================================================
   v14 - the hero deck opens sideways instead of upward, so each
   pass shows a real slice of picture rather than a coloured
   edge. Lab variant A, centred and folded shut at rest.
   =========================================================== */
.hstack-in{--ru:-1.4deg;--xu:124px;--yu:0px;--zu:-42px;--cx:-118px;
  width:min(100%,clamp(860px,73vw,1240px));margin-inline:auto;
  transform:translateY(calc(var(--head,150px) * (var(--sep) - 1) * .74))
            translateX(calc(var(--cx) * var(--sep)))
            rotateX(var(--py)) rotateY(var(--px))}
/* the sideways steps stay even, so the bands read as one set off the same
   shot, but the angle and the height of each sheet vary a few percent, which
   is what stops the fan looking machined */
.hpl:nth-child(1){--i:3;--jr:1.08;--jy:.9;--jz:1;--jx:1;--jo:5px}
.hpl:nth-child(2){--i:2;--jr:.88;--jy:1.2;--jz:1;--jx:1;--jo:-6px}
.hpl:nth-child(3){--i:1;--jr:1.16;--jy:.86;--jz:1;--jx:1;--jo:2px}
/* segmentation is the loudest thing on the page at full chroma */
.hpl:nth-child(1)>video{filter:saturate(.62)}
.pass-tag{position:absolute;right:12px;bottom:16px;z-index:4;writing-mode:vertical-rl;
  font-family:Geistmono,monospace;font-size:9.5px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--od-1);text-shadow:0 1px 2px rgba(0,0,0,.6);
  opacity:var(--sep,0);transition:opacity .4s var(--ease)}
.hpl:nth-child(4) .pass-tag{display:none}
@media(max-width:1200px){.hstack-in{--xu:92px;--cx:-88px}}
@media(max-width:900px){.hstack-in{--xu:26px;--cx:-20px;width:100%}}
/* the title and the CTA line up with the panel edges, which now sit inside
   the hero rather than at the full width of the wrap */
.hero .hero-row{width:min(100%,clamp(860px,73vw,1240px));margin-inline:auto;padding-inline:0}
.hero .wrap-wide>.rv:first-child{padding-inline:0}
.hero:not(.sub-hero) .wrap-wide>.rv:first-child{width:min(100%,clamp(860px,73vw,1240px));margin-inline:auto}
@media(max-width:900px){
  .hero .hero-row,.hero:not(.sub-hero) .wrap-wide>.rv:first-child{width:100%;padding-inline:14px}
}

/* ===========================================================
   v17 - the page answers rather than lists, the Studio demo
   renders in front of you, and the lower page earns its screens.
   =========================================================== */

/* --- hero: the headline sits on the call to action, and the
       reveal mask no longer eats the descenders --- */
.hero .hero-row{align-items:end}
.hero .hero-row>.h1box{margin-bottom:clamp(26px,2.8vw,42px)}
h1 .clip,h2 .clip{padding-bottom:.16em;margin-bottom:-.16em}
@media(max-width:1000px){
  .hero .hero-row{align-items:start}
  .hero .hero-row>.h1box{margin-bottom:0}
}

/* --- Studio: the four passes arrive the way a render arrives --- */
.og figure{position:relative}
.og .ov{overflow:hidden}
.og .ov .ovp,.og .ov video{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block;border-radius:inherit}
.og .ov video{opacity:0;transition:opacity .5s var(--ease)}
.og .ov.running video{opacity:1}
.og .pb{position:absolute;left:50%;top:50%;width:26px;height:26px;margin:-13px 0 0 -13px;
  border:0;border-radius:50%;padding:0;cursor:pointer;z-index:3;
  background:rgba(23,20,18,.55);backdrop-filter:blur(6px);
  transition:opacity .34s var(--ease),transform .34s var(--ease)}
.og .pb::before{content:"";position:absolute;left:10px;top:8px;
  border-left:8px solid #fff;border-top:5px solid transparent;border-bottom:5px solid transparent}
.og .ov.running .pb{opacity:0;transform:scale(.7);pointer-events:none}
/* still rendering: out of focus behind a spinner, no control offered yet */
.og .ov .ovp{transition:filter 1.1s var(--ease-out),transform 1.1s var(--ease-out)}
.og .ov.loading .ovp{filter:blur(9px) saturate(.5);transform:scale(1.04)}
.og .ov.loading .pb{opacity:0;transform:scale(.7);pointer-events:none}
.og .rxl{position:absolute;left:50%;top:50%;width:17px;height:17px;margin:-8.5px 0 0 -8.5px;z-index:3;
  border-radius:50%;border:1.6px solid var(--od-4);border-top-color:#fff;
  opacity:0;animation:rxspin .8s linear infinite;transition:opacity .4s var(--ease)}
.og .ov.loading .rxl{opacity:1}
@keyframes rxspin{to{transform:rotate(360deg)}}

/* the run footer reports what is rendering, with the numbers from the thread */
.of{display:flex;align-items:center;gap:9px}
.of .spin{flex:none;width:12px;height:12px;border-radius:50%;
  border:1.5px solid rgba(23,20,18,.18);border-top-color:var(--n800);
  animation:rxspin .75s linear infinite}
.of .ofc{margin-left:auto;font-family:Geistmono,monospace;font-size:10.5px;
  letter-spacing:.04em;color:var(--n500)}
.of .ofc b{color:var(--n800);font-weight:500}

/* --- how it works: five steps, left to right, opened from the button --- */
.chev{display:inline-block;width:7px;height:7px;margin-left:7px;vertical-align:1px;
  border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .34s var(--ease)}
#howBtn[aria-expanded="true"] .chev{transform:rotate(-135deg) translate(-2px,-2px)}
.howrow{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows .55s var(--ease-out),opacity .4s var(--ease)}
.howrow>.howtrack{overflow:hidden;min-height:0;opacity:0;
  transition:opacity .4s var(--ease)}
.howrow.open{grid-template-rows:1fr}
.howrow.open>.howtrack{opacity:1}
.howtrack{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));
  gap:clamp(14px,1.8vw,30px)}
.hstep{margin-top:var(--gap-part);padding-top:15px;border-top:1px solid var(--n200);
  opacity:0;transform:translateY(12px);
  transition:opacity .5s var(--ease-out),transform .5s var(--ease-out)}
.howrow.open .hstep{opacity:1;transform:none}
.howrow.open .hstep:nth-child(2){transition-delay:.06s}
.howrow.open .hstep:nth-child(3){transition-delay:.12s}
.howrow.open .hstep:nth-child(4){transition-delay:.18s}
.howrow.open .hstep:nth-child(5){transition-delay:.24s}
.hstep .hn{font-family:Geistmono,monospace;font-size:10px;letter-spacing:.1em;color:var(--n400)}
.hstep h3,.hstep h4{margin:9px 0 6px;font-size:15px;font-weight:500;letter-spacing:-.012em;color:var(--n900)}
.hstep p{margin:0;font-size:13.5px;line-height:1.5;color:var(--n500)}
@media(max-width:900px){.howtrack{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.howtrack{grid-template-columns:1fr}}

/* --- the variation grid runs past the edge, and the rows do not
       line up, so the set reads as a window onto a longer one --- */
#vary{overflow:clip}
.vary-cells{margin-right:calc((100vw - 100%) / -2 - 0px)}
.vary-cells .vary{--sh:0px;transform:translateX(var(--sh))}
.vary-cells .vary:nth-child(1){--sh:-22px}
.vary-cells .vary:nth-child(2){--sh:14px}
.vary-cells .vary:nth-child(3){--sh:-34px}
.vary-cells .vary:nth-child(4){--sh:6px}
.vary-cells .cells{grid-template-columns:repeat(8,minmax(0,1fr))}
@media(max-width:1000px){
  .vary-cells{margin-right:0}
  .vary-cells .vary{transform:none}
  .vary-cells .cells{grid-template-columns:repeat(8,minmax(0,1fr))}
}
/* v112 phones: eight frames per axis as two full rows of four, never six and a stray two */
@media(max-width:620px){.vary-cells .cells{grid-template-columns:repeat(4,minmax(0,1fr))}}

/* --- insights: a square frame beside every title --- */
.art .th{display:block;width:100%;aspect-ratio:1/1;border-radius:6px;overflow:hidden;
  background:var(--n200);margin-bottom:2px}
.art .th img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .6s var(--ease-out)}
.art:hover .th img{transform:scale(1.045)}
.arts{grid-template-columns:repeat(6,1fr);gap:clamp(14px,1.6vw,22px)}
.art{gap:11px}
.art .t{font-size:14.5px;line-height:1.3}
@media(max-width:1100px){.arts{grid-template-columns:repeat(3,1fr)}}
@media(max-width:640px){.arts{grid-template-columns:repeat(2,1fr)}}

/* --- the closing screen --- */
.close{position:relative;overflow:hidden}
.cstrip{position:absolute;inset:auto 0 0 0;height:74px;display:flex;gap:6px;
  padding:0 6px 6px;opacity:.5;
  -webkit-mask-image:linear-gradient(to top,#000,transparent);
  mask-image:linear-gradient(to top,#000,transparent)}
.cstrip i{flex:1;border-radius:5px;background-size:cover;background-position:center;
  filter:grayscale(.3)}
.close h2{margin:0}
.close .lede{margin:clamp(15px,1.7vw,24px) auto 0;max-width:46ch}
.cbtns{display:flex;gap:11px;justify-content:center;margin-top:clamp(26px,3vw,38px);flex-wrap:wrap}
.cmeta{margin:clamp(22px,2.4vw,32px) auto 0;max-width:52ch;
  font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.06em;
  text-transform:uppercase;line-height:1.7;color:var(--od-3)}
/* v23 the strip that needed this room is gone, so the panel sits on its own text */
.close-sec .close{padding-block:clamp(72px,7.5vw,116px)}

/* v24/v44 the closing panel is the one still surface on the page, so it gets a
   slow depth drift rather than a gradient. v44 rebuilt it: the v24 version used
   linear gradients, whose isolines are straight and whose ends terminated inside
   the panel, so the light read as a grey shape with a visible edge. These are
   large radial domes instead. Their zero rim sits well outside the panel at every
   point of the travel, so nothing with an edge ever crosses the frame, and the
   peak is roughly a third of what it was. The noise layer on top dithers the
   ramp, which is what kills the contour lines on a near-black field. */
.close{isolation:isolate}
/* v68 every child of the panel except the effect layer sits above it. The old
   list named three classes, so a panel built with an unclassed div lost its
   buttons behind the portal video the moment that video got a z-index. */
.close>*:not(.cfx):not(.cstrip){position:relative;z-index:3}
.cfx{position:absolute;inset:0;z-index:0;pointer-events:none;
  border-radius:inherit;overflow:hidden;background:var(--n950)}
.cfx::before,.cfx::after{content:"";position:absolute;inset:0;
  background-repeat:no-repeat}
/* Two rules keep this from reading as a grey shape with an edge.
   1. The ellipse exactly fills its own background box, so it is already at zero
      alpha where that box ends. Nothing is ever cut mid ramp, which is what the
      v24 linear version did and what the eye was catching.
   2. Each light is centred above or below the panel, so its contours cross the
      frame as arcs and never close into a ring. A ring is what the eye reads as
      an object with an edge. They travel sideways, which is the movement.
   The layers move by background-position rather than by transform, so no box
   edge can ever travel into view. */
.cfx::before{
  background-image:radial-gradient(ellipse 50% 50% at 50% 50%,
    rgba(250,250,249,.078) 0%,rgba(250,250,249,.069) 24%,rgba(250,250,249,.049) 46%,
    rgba(250,250,249,.027) 66%,rgba(250,250,249,.010) 84%,rgba(250,250,249,0) 100%);
  background-size:200% 320%;
  animation:cdrift 34s ease-in-out infinite alternate}
.cfx::after{
  background-image:radial-gradient(ellipse 50% 50% at 50% 50%,
    rgba(250,250,249,.050) 0%,rgba(250,250,249,.041) 28%,rgba(250,250,249,.025) 52%,
    rgba(250,250,249,.009) 74%,rgba(250,250,249,0) 100%);
  background-size:230% 300%;
  animation:cdrift2 53s ease-in-out infinite alternate;animation-delay:-21s}
.cfx>i{position:absolute;inset:-2%;z-index:2;pointer-events:none;opacity:.5;
  mix-blend-mode:overlay;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n' color-interpolation-filters='sRGB'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='.33 .33 .33 0 0 .33 .33 .33 0 0 .33 .33 .33 0 0 0 0 0 0 1'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>")}
@keyframes cdrift{from{background-position:85% 91%}to{background-position:15% 91%}}
@keyframes cdrift2{from{background-position:27% 5%}to{background-position:69% 5%}}
@media(prefers-reduced-motion:reduce){.cfx::before,.cfx::after{animation:none}}
@media(max-width:700px){.cstrip{height:52px}.cstrip i:nth-child(n+5){display:none}}

/* the ground truth stack was being clipped by its own box: the sheets step
   out by 40 across, 62 down and 150 forward, and the box had no room for it */
:is(#ground,#layers) .stack{padding:clamp(54px,5.4vw,96px) clamp(46px,4.8vw,86px);min-height:0;overflow:visible}
:is(#ground,#layers) .stack-in.wide{width:min(100%,440px)}
@media(max-width:1000px){#ground .stack-in.wide{width:min(100%,380px)}}
@media(max-width:760px){#ground .stack{padding:clamp(34px,7vw,56px) clamp(28px,6vw,46px)}}

/* the headline is set from the column it lives in, not from the viewport.
   The two had drifted apart, so the second line was being cut at every width
   between 1100 and 1440. 11.4cqw keeps the longest line inside the column. */
.h1box{container-type:inline-size;min-width:0}
.hero h1{font-size:min(68px,11.4cqw);margin:0}
@media(max-width:820px){.hero h1{font-size:clamp(31px,8.4vw,46px)}}

/* insights: a small square beside the title, three across, not six big cards */
.arts{grid-template-columns:repeat(3,1fr);gap:clamp(18px,2vw,30px) clamp(22px,2.6vw,44px)}
.art{flex-direction:row;align-items:flex-start;gap:14px;padding-bottom:18px}
.art .th{flex:none;width:54px;height:54px;aspect-ratio:auto;margin-bottom:0;border-radius:5px}
.art .atx{display:flex;flex-direction:column;gap:7px;min-width:0}
.art .t{font-size:15px;line-height:1.32}
@media(max-width:900px){.arts{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.arts{grid-template-columns:1fr}}
.cmeta{max-width:60ch}

/* the instance boxes sit between the depth sheet and the segmentation sheet,
   on the same parallax as the rest of the deck. They are the part of the
   claim that is hard to show any other way: the scene knows what each thing
   is and how far away it is, on every frame, without anyone labelling it. */
.boxes{position:absolute;inset:0;z-index:3;pointer-events:none;
  --dx:-40px;--dy:-62px;--dz:150px;
  transform:translate3d(calc(var(--dx) * var(--sep)),calc(var(--dy) * var(--sep)),calc(var(--dz) * var(--sep)))}
@media(max-width:760px){.boxes{--dx:-22px;--dy:-34px;--dz:92px}}
.boxes b{position:absolute;left:var(--bx);top:var(--by);width:var(--bw);height:var(--bh);
  border:1.5px solid rgb(var(--bc,120 240 190) / .95);border-radius:3px;
  box-shadow:0 0 0 1px rgba(23,20,18,.35),0 0 18px rgb(var(--bc,120 240 190) / .22);
  opacity:0;transform:scale(.94);
  transition:opacity .5s var(--ease-out),transform .5s var(--ease-out)}
.stack.go .boxes b{opacity:calc(var(--sep) * 1);transform:none}
.stack.go .boxes b:nth-child(2){transition-delay:.12s}
.stack.go .boxes b:nth-child(3){transition-delay:.24s}
.boxes b i,.boxes b u{position:absolute;font-style:normal;text-decoration:none;
  font-family:Geistmono,monospace;font-size:8px;letter-spacing:.06em;
  white-space:nowrap;padding:2.5px 4px;border-radius:2.5px;line-height:1}
/* the name is a label and shouts, the distance is a unit and must not:
   an uppercase M is mega, and this is metres */
.boxes b i{text-transform:uppercase}
.boxes b u{text-transform:none}
/* the name sits on the box the way a detector draws it, the distance inside it,
   so two labels never fight for the same few pixels */
.boxes b i{left:-1.5px;bottom:100%;margin-bottom:2.5px;
  background:rgb(var(--bc,120 240 190) / .96);color:#09120e}
.boxes b u{right:2px;bottom:2px;background:rgba(9,18,14,.82);color:rgb(var(--bc,120 240 190) / .98)}
@media(max-width:760px){.boxes b u{display:none}.boxes b i{font-size:7.5px}}
/* a narrow box cannot carry both labels on one line, so the distance drops under it */
.boxes b.lo u{top:100%;bottom:auto;left:-1.5px;right:auto;margin-top:2.5px}
/* the sheets take the aspect of the frame they carry, so a box drawn at a
   measured percentage of the mask lands on the object it was measured from */
:is(#ground,#layers) .stack-in.wide{aspect-ratio:16/9;width:min(100%,470px)}
@media(max-width:1000px){#ground .stack-in.wide{width:min(100%,400px)}}
@media(max-width:760px){#ground .stack-in.wide{width:min(100%,320px)}}
/* the two nav actions were wrapping to two lines each on a phone */
@media(max-width:560px){
  .nav-cta .btn-sm{padding:8px 11px;font-size:12.5px;white-space:nowrap}
  .nav .brand img{height:17px}
  .cap-scrim{font-size:8.5px;letter-spacing:.03em;padding:34px 12px 10px}
}

/* ===========================================================
   v18 - the phone pass. Nothing overflowed, but the metadata
   labels were down at 7.5px and half the tap targets were under
   25px, which is fine for a mouse and not for a thumb.
   =========================================================== */
@media(max-width:900px){
  /* a label that cannot be read is worse than no label: the grid cells and the
     hero bands are a few dozen pixels wide on a phone, so theirs come off */
  .vcell .cl{display:none}
  .pass-tag{display:none}

  /* everything else that stays gets back up to a readable size */
  .vary-cells .vary .axis,.vary .axis{font-size:11px;letter-spacing:.09em}
  .pl .lb,.stack .lb{font-size:11px;padding:5px 8px}
  .cap-scrim{font-size:10px;letter-spacing:.045em;line-height:1.5;padding:30px 14px 12px}
  .msg,.msg.tool,.of{font-size:13px}
  .msg .pk{font-size:11.5px}
  .mono{font-size:11px}
  .cmeta{font-size:11px;line-height:1.75}
  .of .ofc{font-size:11px}
  .og figcaption{font-size:10px}
  .hstep .hn,.tile .tn,.tile .tmeta{font-size:11px}
  .art .mono{font-size:10.5px}

  /* a thumb needs about 44px, so the tap area grows while the mark does not */
  .nav .brand{display:flex;align-items:center;min-height:44px}
  .btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .nav-cta .btn-sm{min-height:40px}
  .txtlink{display:inline-flex;align-items:center;min-height:44px}
  .foot-grid a{display:block;padding-block:9px;min-height:40px}
  .nav-links a{display:inline-flex;align-items:center;min-height:44px}
  .subnav a{display:inline-flex;align-items:center;min-height:44px}
  .og .pb{width:40px;height:40px;margin:-20px 0 0 -20px}
  .og .pb::before{left:16px;top:13px;border-left-width:11px;
    border-top-width:7px;border-bottom-width:7px}
}
@media(max-width:560px){
  /* the closing strip is decoration, and on a narrow screen it is just noise */
  .cstrip{height:44px;opacity:.36}
  .facts{gap:18px 14px}
}

/* a tablet in landscape is 1024 wide and still a thumb, so touch sizing keys
   off the pointer rather than the width */
@media(hover:none){
  .nav .brand{display:flex;align-items:center;min-height:44px}
  .btn{min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  .nav-cta .btn-sm{min-height:40px}
  .txtlink{display:inline-flex;align-items:center;min-height:44px}
  .foot-grid a,.subnav a,.nav-links a{display:inline-flex;align-items:center;min-height:44px}
  .og .pb{width:40px;height:40px;margin:-20px 0 0 -20px}
  .og .pb::before{left:16px;top:13px;border-left-width:11px;
    border-top-width:7px;border-bottom-width:7px}
  /* a cell label only appears on hover, so on a touch screen it never appears */
  .vcell .cl{display:none}
  .pass-tag{display:none}
  .pl .lb,.stack .lb{font-size:11px;padding:5px 8px}
  .vary .axis,.vary-cells .vary .axis{font-size:11px}
}
@media(max-width:1024px){
  .cap-scrim{font-size:10.5px}
  .msg.out .oh span{font-size:10.5px}
}

/* ===========================================================
   v21 - the run manifest, in the page's own language. It is the
   one still surface on a page full of motion, which is the point:
   after four sections of things moving, a plain listing of what
   arrives reads as the page finally showing its working.
   =========================================================== */
#run .two{align-items:center}
.manifest{background:var(--n950);color:var(--n50);
  border-radius:var(--rxl);padding:clamp(24px,2.6vw,38px) clamp(22px,2.4vw,34px);
  box-shadow:0 0 0 1px rgba(23,20,18,.08),0 24px 60px rgba(23,20,18,.16);
  font-family:Geistmono,monospace;font-size:12.5px;line-height:1.75}
/* the header uses the same mono metadata treatment as every other label */
.manifest .mh{display:flex;justify-content:space-between;gap:16px;align-items:baseline;
  padding-bottom:15px;margin-bottom:15px;border-bottom:1px solid var(--od-5);
  font-size:10px;letter-spacing:.11em;text-transform:uppercase;color:var(--od-3)}
.manifest .mrow{display:flex;gap:12px;align-items:baseline;padding:3px 0}
.manifest .ind{padding-left:1.6em}
.manifest b{font-weight:400;color:var(--n50);flex:none;min-width:11.5em}
.manifest i{font-style:normal;color:var(--od-3);min-width:0}
/* the same green that labels an instance box in the section above */
.manifest em{font-style:normal;color:rgba(120,240,190,.92)}
@media(max-width:1000px){.manifest b{min-width:0}}
@media(max-width:620px){
  .manifest{font-size:11.5px;padding:20px 17px}
  .manifest .mrow{flex-direction:column;gap:1px;padding:5px 0}
  .manifest .ind{padding-left:1.1em}
  .manifest .mh{font-size:10.5px;flex-direction:column;gap:3px}
}

/* the header actions are redundant while the hero is still offering them,
   so they wait until the hero call to action has scrolled away */
.nav-cta{opacity:0;transform:translateY(-6px);pointer-events:none;
  transition:opacity .42s var(--ease-out),transform .42s var(--ease-out)}
.nav-cta.in{opacity:1;transform:none;pointer-events:auto}
@media(prefers-reduced-motion:reduce){.nav-cta{transition:none}}

/* v30 the right column is one frame of the footage, scrubbing as you scroll,
   with the things that should be attached to it hanging underneath, unknown.
   Same four names as the ground truth stack later, so the page answers itself. */
.landrow{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.92fr);
  gap:clamp(30px,5vw,80px);align-items:end}
.problem-band .landrow .land{margin-top:clamp(44px,5.2vw,82px)}

.framecard{width:100%;max-width:410px;justify-self:end;opacity:0;transform:translateY(10px);
  transition:opacity .7s var(--ease-out) .18s,transform .7s var(--ease-out) .18s}
.framecard.in{opacity:1;transform:none}

.fstrip{position:relative;aspect-ratio:16/10;border-radius:12px;overflow:hidden;
  background:#1d1a18;box-shadow:0 0 0 1px rgba(250,250,249,.08)}
.fstrip img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;filter:saturate(.76) brightness(.94)}
.fstrip img.on{opacity:1}
.fscan{position:absolute;inset:0;pointer-events:none;
  background:repeating-linear-gradient(to bottom,rgba(250,250,249,.035) 0 1px,transparent 1px 3px)}
.fmeta{position:absolute;left:10px;right:10px;bottom:9px;display:flex;
  justify-content:space-between;align-items:baseline;gap:10px;
  font-family:Geistmono,ui-monospace,monospace;font-size:9.5px;letter-spacing:.07em;
  text-transform:uppercase;text-shadow:0 1px 8px rgba(23,20,18,.75)}
.fmeta b{font-weight:500;color:var(--od-1)}
.fmeta i{font-style:normal;color:var(--od-3);font-variant-numeric:tabular-nums}

.fslots{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:10px}
.fs{display:block;text-align:center}
.fs u{display:flex;align-items:center;justify-content:center;aspect-ratio:16/10;
  border:1px dashed var(--od-4);border-radius:7px;text-decoration:none;
  background:rgba(250,250,249,.022);
  font-family:Geistmono,ui-monospace,monospace;font-size:12.5px;
  color:var(--od-4)}
.fs b{display:block;margin-top:6px;font-weight:400;
  font-family:Geistmono,ui-monospace,monospace;font-size:8.5px;letter-spacing:.03em;
  text-transform:uppercase;color:var(--od-4);line-height:1.3}

@media(max-width:1000px){
  .landrow{grid-template-columns:1fr;gap:clamp(30px,5vw,44px);align-items:start}
  .framecard{max-width:440px;margin-left:0}
}
@media(max-width:560px){
  .fslots{gap:6px}
  .fs b{font-size:9px;letter-spacing:.04em}
}

/* v33 six consecutive frames of a pan is a quarter of a second, so the strip was
   quietly contradicting the number under it. The clock says what it really is:
   one hour, sampled, with a playhead that follows the reader down the section. */
.tline{position:relative;margin-top:11px;padding-top:11px;display:flex;
  justify-content:space-between;
  font-family:Geistmono,ui-monospace,monospace;font-size:9.5px;letter-spacing:.09em;
  color:var(--od-4)}
.tline::before{content:"";position:absolute;left:0;right:0;top:0;height:1px;
  background:var(--od-5)}
.tline i{font-style:normal;position:relative}
.tline i::before{content:"";position:absolute;left:50%;top:-11px;width:1px;height:5px;
  background:var(--od-5)}
.tline i:first-child::before{left:0}
.tline i:last-child::before{left:auto;right:0}
.tph{position:absolute;top:-3px;left:calc(var(--p,0) * 100%);width:7px;height:7px;
  margin-left:-3.5px;border-radius:50%;background:var(--n50);
  box-shadow:0 0 0 3px rgba(23,20,18,.9),0 0 12px var(--od-3)}
@media(max-width:700px){
  .tline{font-size:9px;letter-spacing:.04em}
  .tline i:nth-child(3),.tline i:nth-child(5){display:none}
}

/* v37 the stack leads with the frame and the data recedes behind it. The boxes
   belong on the image, which is where a detector would draw them, and the sheet
   with the most to get wrong is now the furthest away and the faintest. */
:is(#ground,#layers) .stack.go .pl:nth-child(2){opacity:.86}
:is(#ground,#layers) .stack.go .pl:nth-child(3){opacity:.66}
:is(#ground,#layers) .stack.go .pl:nth-child(4){opacity:.46}
:is(#ground,#layers) .pl:nth-child(3) img{filter:saturate(.88)}
:is(#ground,#layers) .pl:nth-child(4) img{filter:saturate(.8) blur(.4px)}
/* isolating a sheet still brings it fully forward */
:is(#ground,#layers) .stack[data-iso="2"] .pl:nth-child(2),
:is(#ground,#layers) .stack[data-iso="3"] .pl:nth-child(3),
:is(#ground,#layers) .stack[data-iso="4"] .pl:nth-child(4){opacity:1}
:is(#ground,#layers) .stack[data-iso="3"] .pl:nth-child(3) img,
:is(#ground,#layers) .stack[data-iso="4"] .pl:nth-child(4) img{filter:none}

/* v39 the eyebrow was outside the pinned block, so it sat at the top of the
   section while the block centred its content a third of a screen lower. It
   travels with the thing it labels now, and the pinned panel no longer needs
   a whole viewport to hold what is in it. */
.pin-in{width:100%}
.pin-in .eyebrow{margin-bottom:clamp(18px,2vw,26px)}
#studio .pin-stick{height:auto;min-height:100vh;padding-block:clamp(56px,6vw,96px)}
#studio .pin-in .studio-grid{margin-top:clamp(20px,2.4vw,34px)}
@media(max-width:1000px){
  #studio .pin-stick{min-height:0;padding-block:0}
  #studio .pin-in .studio-grid{margin-top:var(--gap-part)}
}

/* v39 the distance in a box is unexplained otherwise, and it is the whole point:
   a detector gives you a rectangle, this gives you the rectangle and how far
   away the thing is, because the depth pass is in the same frame. */
.stackwrap{display:flex;flex-direction:column}
.stackcap{margin-top:clamp(14px,1.6vw,22px);text-align:center;
  font-family:Geistmono,ui-monospace,monospace;font-size:10px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--od-3);line-height:1.6;
  max-width:46ch;margin-inline:auto}
@media(max-width:760px){.stackcap{font-size:9px;letter-spacing:.03em}}

/* v47 the problem section's number has two beats. While you scrub it counts the
   clip you are actually watching, 48 frames of two seconds. When the strip lands
   it multiplies to the hour and the sentence closes on what Studio answers. The
   tail swaps rather than being rewritten, so neither state is ever half built. */



/* v51 keyboard users should not have to tab the whole nav on every page */
.skip{position:absolute;left:-9999px;top:0;z-index:999;
  background:var(--n950);color:var(--n50);padding:12px 18px;border-radius:0 0 10px 0;
  font-size:14.5px;letter-spacing:-.01em}
.skip:focus{left:0}

/* v51 the reduced-motion audit found five loops still running: the status dot,
   the render spinners, the loading spinner and the typing caret. None of them
   carry information a still frame cannot, so they stop. */
@media(prefers-reduced-motion:reduce){
  .pulse,.rxl,.spin,.typing i,.ph i,.car,.cur{animation:none!important}
  .ph i{opacity:1}
  .dot.pulse{opacity:1}
}

/* v51 target size. The play buttons were 26px and the smallest rendered at 17px,
   under the 24px minimum. The visible disc is unchanged; the hit area is grown
   underneath it, which is the fix that does not cost the design anything. */
.og .pb{min-width:26px;min-height:26px}
.og .pb::after{content:"";position:absolute;left:50%;top:50%;
  width:44px;height:44px;transform:translate(-50%,-50%)}
.brand{padding-block:11px;margin-block:-11px}
.foot a{display:inline-block;padding-block:3px}
/* v87. The rule above is a tap target, but it also turned the footer column
   links inline-block at every width, so on desktop they ran together with no
   break: "InsightsGlossaryCompany". The columns are one link per line. */
.foot-grid a{display:block}
.nav-links a{padding-block:8px;margin-block:-8px}


/* v53 the pinned Studio block. The grid was centring a short text column against
   a tall demo column, which opened a gap under the eyebrow and pushed the demo
   below the fold. Both columns start at the top instead, and the block sits
   higher in the viewport so the animation is fully visible when the scroll locks. */
#studio .pin-stick{align-items:flex-start;padding-block:clamp(40px,4.4vw,68px)}
#studio .studio-grid{align-items:center}
#studio .pin-in .studio-grid{margin-top:clamp(14px,1.6vw,22px)}
@media(max-width:900px){
  #studio .pin-stick{align-items:stretch;padding-block:0}
  #studio .studio-grid{align-items:start}
}

/* v54 the problem band holds still while the strip scrubs, so the footage has
   room to run instead of finishing as the section clears the top. */
.prob-pin{height:250vh}
.problem-band .pin-stick{align-items:center}
@media(max-width:900px){
  .prob-pin{height:auto}
  .problem-band .pin-stick{position:static;height:auto;min-height:0;display:block;padding-block:0}
}

/* v55 two alignment corrections in the pinned sections.

   The problem band centred its content in the full viewport, so on a shorter
   window the heading slid up behind the fixed nav. The block now centres inside
   the space below the nav instead, which keeps the clearance constant whatever
   the window height, and the reel sits a little closer to the heading to buy
   that room back. */
.problem-band .pin-stick{padding-top:clamp(92px,11vh,132px);padding-bottom:clamp(20px,3vh,44px)}
.problem-band .reelwrap{margin-top:clamp(30px,3.4vw,46px)}

/* The Studio demo column reserves room above the video for the message stack to
   rise into, and the grid was centring that padded box, which left the video
   itself sitting below the middle of the text beside it. Cancelling the reserved
   space out of the layout height centres the video rather than the box. The
   reserved room is still there; it just no longer counts twice. */
#studio .studio-demo{transform:translateY(calc(var(--tpad,150px) / -2))}
@media(max-width:900px){
  .problem-band .pin-stick{padding-top:0;padding-bottom:0}
  #studio .studio-demo{transform:none}
}

/* v56 the Studio pin gets more scroll to spend, so the sequence keeps its pace
   and still leaves a tail where the finished render sits on screen. */
#studio .pin-wrap{height:380vh}
@media(max-width:900px){#studio .pin-wrap{height:auto}}

/* v57 the gap above the variation section was three spacings stacking: the pin
   wrapper's own trailing room, the Studio section's bottom padding on top of it,
   then the variation section's top padding and a grid margin meant for a heading
   this section does not have. 425 pixels above against 92 below. The pin already
   carries the separation, so the section padding under it goes, and the grid
   margin goes with it. */
#vary .vary-grid{margin-top:0}

/* v57 the pinned Studio block sat hard against the top of its sticky frame, which
   left a viewport's worth of leftover room underneath it and pushed the heading
   up under the nav. Centring it splits that room evenly, so the block clears the
   nav and the section below it starts on time. */
#studio .pin-stick{align-items:center}
@media(max-width:900px){#studio .pin-stick{align-items:flex-start}}

/* v58 pinned sections stop reserving a viewport they do not fill.
   The sticky box was 100vh with the content centred inside it, so every pinned
   section handed the page roughly a hundred pixels of empty room at the top and
   the same at the bottom, on top of its section padding. Measured across the
   homepage that made the light run between blocks 74, 187, 205, 76, 149, 218 and
   302 pixels where it should be one number.
   The sticky box is now the content itself and the centring moves to its top
   offset, floored so the block never rides up under the nav on a short window.
   A pinned section now takes exactly the height of what it shows, and the space
   around it is --sec-pad like every other section. */
@media(min-width:901px){
  .pin-stick{
    height:auto;min-height:0;padding-block:0;
    top:max(var(--pin-clear,clamp(88px,10vh,124px)),calc((100vh - var(--pin-h,100vh)) / 2))}
  .problem-band .pin-stick,#studio .pin-stick{
    height:auto;min-height:0;padding-block:0;align-items:stretch}
  #studio{padding-bottom:var(--sec-pad)}
}

/* v58 the light run at a colour change.
   Between two light sections the eye reads both paddings as one continuous run,
   about 200 pixels. Where a light section meets the dark band only its own padding
   is light, because the band's padding is inside the band, so the same nominal
   92 reads as 75. That is why the space under the variation grid looked half the
   space above it: 202 above, 75 below, from identical padding values.
   The light side of a colour change therefore carries the run on its own and gets
   both paddings' worth. #run is left alone: its eyebrow column already sits 149
   below the section edge, which is the run the rest of the page is reading. */
.logos-sec{padding-bottom:calc(var(--sec-pad) * 2)}
.problem-band + .sec,.problem-band + #studio{padding-top:calc(var(--sec-pad) * 2)}
#vary{padding-bottom:calc(var(--sec-pad) * 2)}
@media(max-width:900px){
  .logos-sec{padding-bottom:calc(var(--sec-pad) * 1.5)}
  .problem-band + .sec,.problem-band + #studio{padding-top:calc(var(--sec-pad) * 1.5)}
  #vary{padding-bottom:calc(var(--sec-pad) * 1.5)}
}

/* v60 label rows on a dark band.
   .lrow .n is --n900, which on the --n950 band is invisible: the names read at
   roughly 1:1 contrast against their own background, so only the descriptions
   showed. The homepage carried a fix for this scoped to #ground and it was never
   generalised, so every sub-page using .band-dark shipped the rows with their
   titles blanked out. */
.band-dark .lrow{border-color:var(--od-5)}
.band-dark .lrow .n{color:var(--n50)}
.band-dark .lrow .d{color:var(--od-3)}
.band-dark .lrow .k{color:var(--od-4)}
.band-dark .lrow.act .n{color:var(--n50)}

/* v67 the closing panel is a wall with a room behind it.
   The drifting domes above stay put: they are the fallback for no JS, for touch,
   and for reduced motion. site.js only adds .on when it has decided this device
   should get the portal, and only then do the domes step aside. */
/* v107.5. Masking the video to the pointer meant the panel showed a bright blob
   in one corner and nothing anywhere else, which reads as a broken background
   rather than a portal. The scene now fills the panel, at a brightness low
   enough to stay a wall, and the pointer brightens what is under it instead of
   being the only thing that reveals it. */
.cfx .pv{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  z-index:1;opacity:0;transition:opacity 1.1s var(--ease);
  filter:blur(4px) brightness(.13) saturate(.4)}
.cfx.on .pv{opacity:1}
/* the light that follows the pointer, and wanders on its own when nothing is on it */
/* v108. At 30 percent the room was legible across the whole panel even with
   nothing on it, which made the panel a photograph rather than a wall. The
   scene now sits at 13, where it reads as texture, and the light the pointer
   carries is what brings any of it up. */
.cfx .pl{position:absolute;inset:0;z-index:2;pointer-events:none;
  opacity:0;transition:opacity 1.1s var(--ease);mix-blend-mode:plus-lighter;
  background:radial-gradient(circle var(--pr,285px) at var(--px,50%) var(--py,50%),
    rgba(250,250,249,.20) 0%,rgba(250,250,249,.135) 30%,rgba(250,250,249,.055) 60%,
    rgba(250,250,249,0) 100%)}
.cfx.on .pl{opacity:1}
.cfx.on::before,.cfx.on::after{opacity:0;transition:opacity .9s var(--ease)}

/* ---------------------------------------------------------------
   v76 phone floor. Measured at 390px on every page: nothing rendered
   sits under 10px any more, and every control that is not an inline
   link inside a sentence clears 40px of height. The visible design is
   unchanged above 620px. Inline links in running text are left alone:
   padding them out breaks the line, and WCAG 2.5.8 exempts them.
   --------------------------------------------------------------- */
@media(max-width:620px){
  /* labels inside the product mock-ups. 7px is not a size anyone reads */
  .msg.out .og figcaption{font-size:10px;padding:10px 6px 4px;letter-spacing:.05em}
  .tline i,.fslots .fs b,.stackcap,.fstrip .fmeta b,.fstrip .fmeta i{font-size:10.5px}
  .boxes b i{font-size:10px}
  /* controls that were shorter than a fingertip */
  .job h3 a{display:inline-block;padding-block:8px}
  .crumb a,.entity dd a{display:inline-flex;align-items:center;min-height:40px;margin-block:-9px}
  /* footer links spanned only their own word, so the column is the target */
  .foot-grid a{display:block}
}

/* ---------------------------------------------------------------
   v84 motion. Measured against the reference set: Linear 641
   animated nodes, Scale 719, Anthropic 453, Cohere 416, ours 41 to
   206. Ours was concentrated in three showpieces and absent from
   everything else. This gives every list, grid and control the
   motion the showpieces already had.

   Three parts: children of a revealed block arrive in sequence
   rather than together; every interactive element has a state to
   move to; and text links draw their own underline.
   All of it collapses under prefers-reduced-motion.
   --------------------------------------------------------------- */

/* 1. staggered arrival. --d is written per child by site.js */
.rv [data-st]{opacity:0;transform:translateY(14px);
  transition:opacity .62s var(--ease-out),transform .62s var(--ease-out);
  transition-delay:var(--d,0ms)}
.rv.in [data-st]{opacity:1;transform:none}

/* 2. a state to move to, on everything that responds to a pointer */
.job,.qa summary,.lrow,.term,.tile,.env,.pw-key,.artgrid .art,.adv,.run,
.glos-nav a,.foot a,.foot-grid a,.subnav a,.cats li,.art,.use,.hstep,.fstep{
  transition:color .22s var(--ease),background-color .22s var(--ease),
             border-color .22s var(--ease),transform .28s var(--ease-out),
             box-shadow .28s var(--ease),opacity .22s var(--ease)}
.lrow{border-radius:8px;padding-inline:10px;margin-inline:-10px}
.lrow.is-live:hover{background:var(--n100)}
.band-dark .lrow.is-live:hover,.on-dark .lrow.is-live:hover{background:var(--od-5)}
.term{border-radius:10px;padding-inline:12px;margin-inline:-12px}
.term:hover{background:var(--n100)}
.foot a:hover,.foot-grid a:hover{transform:translateX(3px)}
.qa summary:hover{padding-left:6px}
.glos-nav a:hover{padding-left:5px}

/* 3. text links draw their underline instead of just having one */
.qa .a a,.passfoot a,.lede a,.term p a,p a:not(.btn){
  background-image:linear-gradient(currentColor,currentColor);
  background-size:0% 1px;background-position:0 100%;background-repeat:no-repeat;
  border-bottom:1px solid var(--n300);
  transition:background-size .34s var(--ease-out),border-color .2s var(--ease)}
.qa .a a:hover,.passfoot a:hover,.lede a:hover,.term p a:hover,p a:not(.btn):hover{
  background-size:100% 1px;border-color:transparent}

@media(prefers-reduced-motion:reduce){
  .rv [data-st]{opacity:1;transform:none;transition:none;transition-delay:0ms!important}
  .job,.qa summary,.lrow,.term,.tile,.env,.pw-key,.artgrid .art,.adv,.run,
  .glos-nav a,.foot a,.foot-grid a,.subnav a,.cats li,.art,.use,.hstep,.fstep{transition:none}
  .foot a:hover,.foot-grid a:hover{transform:none}
  .qa summary:hover,.glos-nav a:hover{padding-left:0}
  .qa .a a,.passfoot a,.lede a,.term p a,p a:not(.btn){transition:none}
}

/* v84. Scroll-linked drift. --dy is written by site.js from the element's
   position in the viewport; the CSS owns how it is applied. Transform only,
   so it never triggers layout. */
[data-drift]{transform:translate3d(0,var(--dy,0px),0);will-change:transform}
[data-drift-in]{transform:translate3d(0,var(--dy,0px),0) scale(var(--ds,1));
  will-change:transform}
@media(prefers-reduced-motion:reduce){
  [data-drift],[data-drift-in]{transform:none!important;will-change:auto}
}


/* ---------------------------------------------------------------
   v90. Mobile menu. Under 940px the nav links were set to display:none
   with nothing in their place, so Studio, Robot policies, World models,
   Company and Insights were unreachable on a phone: the only things in
   the bar were the two CTAs. The panel is built at runtime from the
   links already in the nav, so it cannot drift out of sync with them.
   --------------------------------------------------------------- */
.navtog{display:none;position:relative;width:44px;height:44px;margin-right:-10px;
  border:0;background:none;padding:0;cursor:pointer;flex:none;z-index:2}
.navtog span,.navtog span::before,.navtog span::after{position:absolute;left:12px;
  width:20px;height:1.5px;background:var(--n900);border-radius:2px;
  transition:transform .3s var(--ease-out),opacity .2s var(--ease)}
.navtog span{top:21px}
.navtog span::before{content:"";top:-6px;left:0}
.navtog span::after{content:"";top:6px;left:0}
.nav.over-dark:not(.stuck) .navtog span,
.nav.over-dark:not(.stuck) .navtog span::before,
.nav.over-dark:not(.stuck) .navtog span::after{background:#fff}
.navtog[aria-expanded="true"] span{background:transparent}
.navtog[aria-expanded="true"] span::before{transform:translateY(6px) rotate(45deg);background:var(--n900)}
.navtog[aria-expanded="true"] span::after{transform:translateY(-6px) rotate(-45deg);background:var(--n900)}

.navmenu{position:fixed;inset:0;z-index:60;background:var(--n25);
  padding:calc(var(--navh,64px) + 18px) 22px 30px;
  display:flex;flex-direction:column;gap:2px;overflow-y:auto;overscroll-behavior:contain;
  opacity:0;visibility:hidden;transform:translateY(-8px);
  transition:opacity .26s var(--ease),transform .26s var(--ease-out),visibility .26s}
.navmenu.open{opacity:1;visibility:visible;transform:none}
.navmenu a{display:flex;align-items:center;min-height:52px;font-size:22px;
  letter-spacing:-.02em;color:var(--n800);border-bottom:1px solid var(--n200)}
.navmenu a:last-of-type{border-bottom:0}
.navmenu .mcta{margin-top:24px;display:flex;flex-direction:column;gap:10px}
.navmenu .mcta a{justify-content:center;min-height:48px;font-size:16px;border-bottom:0;
  border-radius:var(--r);text-align:center}
.navmenu .mcta a:first-child{background:var(--n100);color:var(--n900)}
.navmenu .mcta a:last-child{background:var(--n950);color:var(--n25)}
body.navopen{overflow:hidden}
@media(max-width:1060px){.navtog{display:block}}
@media(min-width:941px){.navmenu{display:none}}
@media(prefers-reduced-motion:reduce){
  .navmenu{transition:opacity .01s}
  .navtog span,.navtog span::before,.navtog span::after{transition:none}
}

/* v90. Menu open state. The nav sits above the panel so the close control
   stays reachable, which means the bar itself has to switch to the panel's
   surface: on a dark hero the logo and burger are white and were invisible
   against the cream, and the nav CTAs doubled the ones in the panel. */
body.navopen .nav{background:var(--n25);border-bottom-color:transparent;backdrop-filter:none}
body.navopen .nav .nav-cta{display:none}
body.navopen .nav .brand img{filter:none}
body.navopen .nav.over-dark .brand img{filter:invert(1) brightness(.12)}
body.navopen .navtog span::before,
body.navopen .navtog span::after,
body.navopen .nav.over-dark:not(.stuck) .navtog span::before,
body.navopen .nav.over-dark:not(.stuck) .navtog span::after{background:var(--n900)}
body.navopen .navtog span,
body.navopen .nav.over-dark:not(.stuck) .navtog span{background:transparent}

body.navopen .navtog{margin-left:auto}

/* v91. On a phone the row was 21px logos at a 30px gap, which wrapped two
   per line and read as oversized. 16px holds three per line on a 390px
   screen and drops the row to two clean lines. */
@media(max-width:620px){
  .logos{gap:16px 22px}
  .logos .lg-meta{height:11px}
  .logos .lg-amazon{height:16px}
  .logos .lg-deepmind{height:12px}
  .logos .lg-spaitial{height:16px}
  .logos .lg-nvidia{height:15px}
  .logos .lg-microsoft{height:15px}
  .logos .lg-adobe{height:16px}
  .logos .lg-epic{height:18px}
  .logos .lg-worldlabs{height:20px}
}

/* ---------------------------------------------------------------
   v107 the render panel on a phone. Five passes across a 390px
   screen gave each tile 57px, which is narrower than its own caption:
   "SEGMENTATION" was clipped to "SEGMENTAT" on both pages, and the
   pictures were too small to read anyway. Below 620px the passes run
   three across and wrap, so every tile is wide enough for its label
   and large enough to show what the pass is.
   --------------------------------------------------------------- */
@media(max-width:620px){
  .msg.out .og{grid-template-columns:repeat(3,1fr)}
  .msg.out .og figcaption{font-size:9px;letter-spacing:.02em;padding:9px 5px 4px}
}

/* ---------------------------------------------------------------
   v108 nav: a New marker on Studio, and Careers waiting for a link.
   The pill is an index on the word rather than a badge beside it, so
   the nav keeps its rhythm. Careers is deliberately not a link yet:
   it is a span, so it cannot be tabbed to or clicked, and it reads
   one step back from the items that go somewhere.
   --------------------------------------------------------------- */
/* v108.1 outlined, anchored to the right edge of the word, label centred by flex */
.nav-links .npill{position:absolute;top:5px;left:100%;margin-left:5px;
  display:inline-flex;align-items:center;justify-content:center;
  height:14px;padding:0 4.5px;box-sizing:border-box;
  font-family:Geistmono,monospace;font-style:normal;font-size:8px;line-height:1;
  letter-spacing:.07em;text-indent:.07em;text-transform:uppercase;
  border:1px solid var(--n300);border-radius:4px;background:transparent;
  color:var(--n600);white-space:nowrap;
  pointer-events:none;transition:border-color .18s,color .18s}
.nav-links a:hover .npill{border-color:var(--n500);color:var(--n900)}
.nav.over-dark .nav-links .npill,.nav.on-dark .nav-links .npill{
  border-color:var(--od-4);color:var(--od-2)}
.nav.over-dark .nav-links a:hover .npill,.nav.on-dark .nav-links a:hover .npill{
  border-color:var(--od-2);color:#fff}
.nav-links .soon{color:var(--n400);cursor:default;padding-block:6px}
.nav.over-dark .nav-links .soon,.nav.on-dark .nav-links .soon{color:var(--od-3)}
/* the Studio item carries a pill in its top right corner, so the gap after it
   is widened to keep the row evenly spaced */
.nav-links a:has(.npill){margin-right:30px}

/* ---------------------------------------------------------------
   v108. Reveal transforms and the fanning pass stack momentarily
   reach a few pixels past the right edge while they are in flight,
   which on a tablet flashes a horizontal scrollbar. overflow-x:clip
   rather than hidden, because clip does not make the body a scroll
   container and so leaves position:sticky working, which the FAQ
   heading and the pinned Studio section both rely on.
   --------------------------------------------------------------- */
html,body{overflow-x:clip}

/* v108 the menu carries the same two markers the desktop nav has: the New pill
   on Studio, set inline at this size rather than parked in a corner, and
   Careers as inert text until it has somewhere to go. */
.navmenu .soon{display:flex;align-items:center;min-height:52px;font-size:22px;
  letter-spacing:-.025em;color:var(--n400);border-bottom:1px solid var(--n200);cursor:default}
.navmenu a .npill{position:static;margin-left:11px;
  display:inline-flex;align-items:center;justify-content:center;
  height:18px;padding:0 6px;box-sizing:border-box;
  font-family:Geistmono,monospace;font-style:normal;font-size:9.5px;line-height:1;
  letter-spacing:.07em;text-indent:.07em;text-transform:uppercase;
  border:1px solid var(--n300);border-radius:5px;background:transparent;color:var(--n500)}

/* v112 phones and tablets: the Studio conversation plays inside its panel, never above it.
   No reserve above the stage, the thread fills the panel from the bottom and the oldest
   bubbles fade out under the top edge. The panel is taller so four bubbles fit. */
@media(max-width:900px){
  .studio-demo,#studio .studio-demo{padding-top:0!important;transform:none!important}
  .sstage,.studio-solo .sstage{aspect-ratio:4/5}
  .thread,.studio-solo .thread{top:12px;bottom:12px;left:12px;right:12px;
    justify-content:flex-end;overflow:hidden;transform:none!important;
    -webkit-mask-image:linear-gradient(to bottom,transparent 0,#000 16%);
    mask-image:linear-gradient(to bottom,transparent 0,#000 16%)}
  .thread .msg.out .og{grid-template-columns:repeat(3,1fr)}
}

/* v112 the burger stays white over any dark section, stuck or not */
.nav.over-dark .navtog span,.nav.over-dark .navtog span::before,.nav.over-dark .navtog span::after{background:#fff}
body.navopen .nav.over-dark .navtog span::before,body.navopen .nav.over-dark .navtog span::after{background:var(--n900)}
body.navopen .nav.over-dark .navtog span{background:transparent}

/* ---------------------------------------------------------------
   v118 THE nav colour rule. One source for every state, last in the file
   so nothing above can override it. Two themes only:
   light (default)  : links grey, hover and current page near black
   dark (.over-dark / .on-dark, set by site.js from what is under the bar):
                      links light grey, hover and current page white
   The NEW pill never has its own colour: its text and outline follow the
   link it sits on, so it always matches in every state.
   --------------------------------------------------------------- */
html .nav .nav-links{color:var(--n700)}
html .nav .nav-links a{color:var(--n700)}
html .nav .nav-links a:hover,
html .nav .nav-links a[aria-current="page"]{color:var(--n950)}
html .nav .nav-links a::after{background:currentColor}
html .nav .nav-links .soon{color:var(--n400)}
html .nav.over-dark .nav-links,html .nav.on-dark .nav-links,
html .nav.over-dark .nav-links a,html .nav.on-dark .nav-links a{color:var(--od-2)}
html .nav.over-dark .nav-links a:hover,html .nav.on-dark .nav-links a:hover,
html .nav.over-dark .nav-links a[aria-current="page"],html .nav.on-dark .nav-links a[aria-current="page"]{color:#fff}
html .nav.over-dark .nav-links .soon,html .nav.on-dark .nav-links .soon{color:var(--od-3)}
html .nav .nav-links .npill,html .nav .nav-links a:hover .npill,
html .nav.over-dark .nav-links .npill,html .nav.on-dark .nav-links .npill,
html .nav.over-dark .nav-links a:hover .npill,html .nav.on-dark .nav-links a:hover .npill{
  color:inherit;background:transparent;
  border-color:color-mix(in srgb,currentColor 45%,transparent)}

@media (max-width:480px){.nav .nav-in{gap:12px}.nav .nav-cta .btn-secondary{display:none}.nav .brand,.nav .brand img{flex:none}.nav .brand img{max-width:none}}
@media (max-width:900px){.hstack{overflow:visible}.hero{overflow-x:clip}.thread .msg,.thread .typing{--mx:0px!important;--my:0px!important}.nav.stuck{background:rgba(250,250,249,.88)}.nav.over-dark.stuck,.nav.on-dark{background:rgba(23,20,18,.86)}}
@media (max-width:620px){.logos-sec .small,.cf-logos .small{text-align:center}.logos{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:28px 12px;justify-items:center;align-items:center}.logos .lg-epic{height:24px}}
@media (max-width:900px){html,body,#studio{overflow-x:visible}.pcl-site>main>section:not(#studio),.pcl-site>main>header,.pcl-site>footer{overflow-x:clip}}
@media (max-width:900px){.pin-unit{background:var(--n50)}.pin-unit .rprog{margin:0 0 14px}.pin-unit .rsteps{margin-bottom:14px}.pin-unit .rstep p{display:none}}
