/* shared page components: hero shape, layer rows, gallery, closing card.
   Lifted out of the homepage so robotics and foundation models sit on the
   same system rather than a copy of it. */
.hero{padding-top:clamp(74px,6.6vw,98px)}
.hero h1{max-width:none}
.hero .lede{max-width:50ch;margin-top:26px}
.hero-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,420px);
  gap:clamp(24px,4vw,88px);align-items:start}
@media(max-width:940px){.hero-row{grid-template-columns:1fr}}
.hero-row>div{padding-top:10px}
.hero .lede{max-width:none;margin-top:0}
.hero-cta{display:flex;gap:11px;flex-wrap:wrap;align-items:center}
.hero-meta{display:flex;gap:9px;align-items:center;margin-top:16px}

.layers-wrap{display:grid;grid-template-columns:.8fr 1fr;gap:clamp(28px,4.5vw,76px);align-items:center}
@media(max-width:1000px){.layers-wrap{grid-template-columns:1fr}}
.lrow{display:flex;gap:14px;padding:16px 0;border-bottom:1px solid var(--n200)}
.lrow .k{font-family:Geistmono,monospace;font-size:11px;color:var(--n400);min-width:26px;padding-top:4px}
.lrow .n{display:block;font-size:17px;font-weight:500;color:var(--n900);letter-spacing:-.015em}
.lrow .d{display:block;font-size:14.5px;color:var(--n500);margin-top:4px;line-height:1.5}

.gal{display:grid;grid-template-columns:1.4fr 1fr 1fr;gap:12px}
.gal .f{position:relative;border-radius:var(--rl);overflow:hidden;box-shadow:0 0 0 1px rgba(23,20,18,.06);aspect-ratio:4/3}
.gal .f:first-child{aspect-ratio:auto}
.gal .f img{width:100%;height:100%;object-fit:cover}
@media(max-width:900px){.gal{grid-template-columns:1fr 1fr}.gal .f:first-child{grid-column:1/-1;aspect-ratio:16/10}}

.close{background:var(--n950);color:var(--n50);border-radius:var(--rxl);padding:clamp(48px,6vw,92px) clamp(28px,4vw,72px);text-align:center}
.close h2{color:var(--n50);max-width:17ch;margin-inline:auto}
.close .lede{color:var(--n400);max-width:52ch;margin:22px auto 0}

/* ---- subpage system: the vertical pages run on the homepage rhythm ---- */
.sub-hero{padding-top:clamp(88px,8vw,124px);padding-bottom:var(--sec-pad)}
.sub-hero .wrap-wide{display:grid;gap:clamp(30px,3.6vw,56px)}
.sub-hero h1{max-width:17ch;font-size:min(62px,7.2vw)}
.sub-hero .lede{max-width:54ch}
.sub-hero .hero-cta{margin-top:clamp(24px,2.8vw,36px)}
.sub-shot{position:relative;border-radius:var(--rxl);overflow:hidden;
  aspect-ratio:21/9;background:var(--n200);
  box-shadow:0 0 0 1px rgba(23,20,18,.06),0 24px 60px rgba(23,20,18,.12)}
.sub-shot video,.sub-shot img{width:100%;height:100%;object-fit:cover;display:block}
@media(max-width:760px){.sub-shot{aspect-ratio:4/3}}

.facts{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(16px,2vw,32px);
  margin-top:var(--gap-part)}
.fact{border-top:1px solid var(--n200);padding-top:15px}
.fact .fv{font-size:clamp(26px,2.6vw,36px);letter-spacing:-.028em;color:var(--n900);line-height:1}
.fact .fk{display:block;margin-top:9px;font-size:13.5px;line-height:1.45;color:var(--n500)}
@media(max-width:760px){.facts{grid-template-columns:repeat(2,1fr)}}

.tiles{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.6vw,22px);
  margin-top:var(--gap-part)}
.tile{border:1px solid var(--n200);border-radius:var(--rl);padding:clamp(18px,2vw,26px);
  background:var(--n50);transition:border-color .3s var(--ease),transform .4s var(--ease-out)}
.tile:hover{border-color:var(--n400);transform:translateY(-2px)}
.tile .tn{font-family:Geistmono,monospace;font-size:10px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--n400)}
.tile h3{margin:11px 0 8px;font-size:17px;font-weight:500;letter-spacing:-.016em;color:var(--n900)}
.tile p{margin:0;font-size:14px;line-height:1.55;color:var(--n500)}
.tile .tmeta{display:block;margin-top:13px;font-family:Geistmono,monospace;font-size:10.5px;
  letter-spacing:.05em;color:var(--n400)}
@media(max-width:900px){.tiles{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.tiles{grid-template-columns:1fr}}

.engines{display:flex;flex-wrap:wrap;gap:9px;margin-top:var(--gap-part)}
.engines span{font-family:Geistmono,monospace;font-size:11.5px;letter-spacing:.05em;
  border:1px solid var(--n200);border-radius:999px;padding:8px 15px;color:var(--n600)}
.band-dark .engines span{border-color:var(--od-5);color:var(--od-2)}

.subnav{display:flex;gap:18px;flex-wrap:wrap;margin-top:var(--gap-part);
  font-size:14px}
.subnav a{color:var(--n600);border-bottom:1px solid var(--n200);padding-bottom:2px}
.subnav a:hover{color:var(--n900);border-color:var(--n900)}

/* phone sizing for the subpage components. This file loads after base.css, so
   the overrides have to live here or the desktop sizes win. */
@media(max-width:900px),(hover:none){
  .tile .tn,.tile .tmeta{font-size:11px}
  .fact .fk{font-size:14px}
  .engines span{font-size:12px;padding:9px 15px}
  .subnav a{display:inline-flex;align-items:center;min-height:44px}
}
@media(max-width:760px){
  .sub-hero h1{font-size:clamp(31px,8.4vw,44px)}
  .facts{grid-template-columns:1fr 1fr;gap:16px}
  .tiles{gap:12px}
}

/* v1 sub-page as a child of Studio: a breadcrumb instead of an eyebrow, so the
   page reads as one use case of the product rather than a product of its own. */
.crumb{display:flex;align-items:center;gap:9px;margin-bottom:clamp(16px,1.8vw,24px);
  font-family:Geistmono,monospace;font-size:11px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--n400)}
.crumb a{color:var(--n500);text-decoration:none;border-bottom:1px solid var(--n300);
  padding-bottom:1px;transition:color .2s var(--ease),border-color .2s var(--ease)}
.crumb a:hover{color:var(--n900);border-color:var(--n900)}
.crumb span[aria-hidden]{color:var(--n300)}
/* footer group captions are navigation labels, not document headings: as H3 they
   broke the heading outline on every page of the site */
.fcap{font-size:13px;font-weight:500;letter-spacing:-.01em;color:var(--n50);
  margin:0 0 14px}

/* v1 sub-hero lede spacing. Line 11 zeroes the hero lede's top margin for the
   homepage layout and the sub-hero rule never restored it, so on every sub-page
   the lede sat hard against the h1 while /company picked up 24px from elsewhere.
   One value for all of them. */
.sub-hero .lede{margin-top:clamp(20px,2.2vw,28px)}

/* ---- v3 sub-page demonstrations ------------------------------------------
   The sub-pages described the product where the homepage shows it. These two
   blocks do the showing: the same scene with one axis moved, and the four
   passes of one second played together. ------------------------------------ */
.axisrow{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(12px,1.5vw,22px);
  margin-top:var(--gap-part)}
@media(max-width:820px){.axisrow{grid-template-columns:1fr}}
.axis-card{margin:0}
.axis-vid{position:relative;border-radius:var(--rl);overflow:hidden;aspect-ratio:4/3;
  background:var(--n200);box-shadow:0 0 0 1px rgba(23,20,18,.06),0 10px 30px rgba(23,20,18,.08)}
.axis-vid video{width:100%;height:100%;object-fit:cover;display:block}
.axis-card figcaption{display:flex;align-items:baseline;gap:9px;margin-top:12px;flex-wrap:wrap}
.axis-card .ax{font-size:15px;font-weight:500;letter-spacing:-.015em;color:var(--n900)}
.axis-card .axd{font-family:Geistmono,monospace;font-size:11.5px;letter-spacing:.02em;color:var(--n500)}

.passgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.2vw,16px);
  margin-top:var(--gap-part)}
@media(max-width:940px){.passgrid{grid-template-columns:repeat(2,1fr)}}
.pass{margin:0;position:relative;border-radius:var(--rl);overflow:hidden;aspect-ratio:1;
  background:#0f0d0c;box-shadow:0 0 0 1px rgba(250,250,249,.08)}
.pass video{width:100%;height:100%;object-fit:cover;display:block}
.pass figcaption{position:absolute;left:0;right:0;bottom:0;padding:26px 14px 12px;
  display:flex;align-items:baseline;justify-content:space-between;gap:8px;
  background:linear-gradient(to top,rgba(10,9,8,.82),rgba(10,9,8,0))}
.pass figcaption b{font-size:13.5px;font-weight:500;letter-spacing:-.01em;color:var(--n50)}
.pass figcaption i{font-family:Geistmono,monospace;font-style:normal;font-size:10.5px;
  letter-spacing:.06em;color:var(--od-3)}
.passfoot{margin-top:22px;font-size:14px;color:var(--od-3);max-width:60ch}

/* v3 the pass wipe. Four renders of one frame, stacked and revealed by a wipe
   as the section scrolls. Stacking rather than tiling is the point: the passes
   are registered to the same pixels, and a wipe is the only presentation that
   shows it. */
.passwipe{margin-top:var(--gap-part)}
.pw-stage{position:relative;border-radius:var(--rl);overflow:hidden;aspect-ratio:16/9;
  background:#0f0d0c;box-shadow:0 0 0 1px rgba(250,250,249,.09)}
.pw-stage .pw-layer{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.pw-stage .pw-layer[data-i="0"]{clip-path:none}
.pw-edge{position:absolute;top:0;bottom:0;width:1px;background:var(--od-3);
  left:0;opacity:0;transition:opacity .3s var(--ease);pointer-events:none}
.passwipe.live .pw-edge{opacity:1}
.pw-keys{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;margin-top:14px;
  background:var(--od-5);border:1px solid var(--od-5);
  border-radius:10px;overflow:hidden}
@media(max-width:700px){.pw-keys{grid-template-columns:repeat(2,1fr)}}
.pw-key{background:#171412;padding:13px 15px 15px;display:flex;flex-direction:column;gap:3px;
  transition:background .35s var(--ease)}
.pw-key b{font-size:13.5px;font-weight:500;letter-spacing:-.01em;color:var(--od-4);
  transition:color .35s var(--ease)}
.pw-key i{font-family:Geistmono,monospace;font-style:normal;font-size:10.5px;letter-spacing:.06em;
  color:var(--od-4);transition:color .35s var(--ease)}
.pw-key.on{background:#221E1B}
.pw-key.on b{color:var(--n50)}
.pw-key.on i{color:var(--od-3)}
@media(prefers-reduced-motion:reduce){
  .pw-stage .pw-layer{clip-path:none!important;position:relative;inset:auto}
  .pw-stage{aspect-ratio:auto;display:grid;grid-template-columns:repeat(2,1fr);gap:8px;background:none;box-shadow:none}
  .pw-edge{display:none}
  .pw-key{background:#221E1B}
  .pw-key b{color:var(--n50)} .pw-key i{color:var(--od-3)}
}

/* v4 the pass wipe also carries video layers, for the scenes whose four passes
   were rendered as clips rather than stills. */
.pw-stage video.pw-layer{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}

/* v4 environment row. Different building types at the same render quality, which
   is the only honest way to show range: same engine, different scene. */
.envrow{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.2vw,18px);
  margin-top:var(--gap-part)}
@media(max-width:940px){.envrow{grid-template-columns:repeat(2,1fr)}}
@media(max-width:520px){.envrow{grid-template-columns:1fr}}
.env{margin:0}
.env img{width:100%;aspect-ratio:16/10;object-fit:cover;display:block;border-radius:var(--rl);
  background:var(--n200);box-shadow:0 0 0 1px rgba(23,20,18,.06),0 10px 26px rgba(23,20,18,.07)}
.env figcaption{margin-top:11px}
.env figcaption b{display:block;font-size:14.5px;font-weight:500;letter-spacing:-.015em;color:var(--n900)}
.env figcaption i{display:block;font-family:Geistmono,monospace;font-style:normal;font-size:10.5px;
  letter-spacing:.05em;color:var(--n500);margin-top:3px}

/* v5 company page: the entity block and the disambiguation note.
   The note is written to be quoted verbatim by an AI answer, so it is set as a
   pull quote rather than body copy: something a machine can lift cleanly and a
   reader stops on. */
.disamb{border-left:2px solid var(--n900);padding:6px 0 6px 22px;margin:0;max-width:60ch}
.disamb p{font-size:clamp(17px,1.7vw,21px);line-height:1.5;letter-spacing:-.015em;color:var(--n700)}
.disamb b{color:var(--n950);font-weight:500}

/* v90. Removed a dead .advrow block. No page used it, but its .adv rule was
   unscoped and leaked padding onto the live advisor cards. */
.entity{margin:var(--gap-part) 0 0;display:grid;gap:0;max-width:820px}
.entity>div{display:grid;grid-template-columns:minmax(140px,210px) 1fr;gap:20px;
  padding:15px 0;border-bottom:1px solid var(--n200)}
@media(max-width:620px){.entity>div{grid-template-columns:1fr;gap:4px}}
.entity>div:last-child{border-bottom:0}
.entity dt{font-family:Geistmono,monospace;font-size:11px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--n500);padding-top:3px}
.entity dd{margin:0;font-size:15.5px;color:var(--n800);line-height:1.55}
.entity dd a{color:var(--n900);text-decoration:none;border-bottom:1px solid var(--n300)}
.entity dd a:hover{border-color:var(--n900)}

/* v5 the category list. The four renders were reading as the whole catalogue;
   they are examples. The list is what Studio will build to order, and it leads. */
.cats{list-style:none;margin:var(--gap-part) 0 0;padding:0;
  display:grid;grid-template-columns:repeat(3,1fr);gap:1px;
  background:var(--n200);border:1px solid var(--n200);border-radius:var(--rl);overflow:hidden}
@media(max-width:860px){.cats{grid-template-columns:repeat(2,1fr)}}
@media(max-width:480px){.cats{grid-template-columns:1fr}}
.cats li{background:var(--n50);padding:15px 20px;font-size:15px;color:var(--n800);
  letter-spacing:-.01em;transition:background .2s var(--ease),color .2s var(--ease)}
.cats li:hover{background:#fff;color:var(--n950)}
.catfoot{margin-top:clamp(30px,3.4vw,46px);font-family:Geistmono,monospace;font-size:11px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--n400)}

/* v6 the Studio session, given the page to itself.
   On the homepage this sits in one half of a two-column row. Here it is the
   section, so the heading goes above it and the scene runs near full measure. */
@media(min-width:901px){
  #studio .pin-wrap{height:460vh}   /* eleven beats now, not seven */
  .studio-solo{max-width:1120px;margin-inline:auto}
  .solo-say{margin-bottom:clamp(26px,3vw,44px);max-width:56ch}
  .solo-say h2{font-size:clamp(28px,3.4vw,44px);line-height:1.08;letter-spacing:-.03em}
  .studio-solo .studio-demo{padding-top:var(--tpad,120px)}
  .studio-solo .sstage{aspect-ratio:16/9}
  .studio-solo .thread{left:clamp(-140px,-7vw,-60px);right:clamp(16px,2vw,34px)}
}
@media(max-width:900px){
  #studio .pin-wrap{height:auto}
  #studio .pin-stick{position:static;height:auto;min-height:0;display:block;padding-block:0}
  .studio-solo .sstage{aspect-ratio:4/5}
}

/* v6 short windows. The session is tall: stage plus thread plus the render panel.
   On a laptop around 800px the panel ran past the fold during the hold, which is
   the one moment it has to be fully visible. A shallower stage pulls the whole
   column up without touching the thread. */
@media(min-width:901px) and (max-height:900px){
  .studio-solo{max-width:1020px}
  .studio-solo .sstage{aspect-ratio:21/9}
  .solo-say{margin-bottom:clamp(18px,2vw,28px)}
  .solo-say h2{font-size:clamp(26px,2.8vw,36px)}
}

/* ---- v68 Studio landing: match the homepage rhythm ---- */
/* The two pages were inverted: home inset its hero and ran sections flush,
   this page did the opposite. Home is the reference. */
@media(min-width:901px){
  /* One left edge for the whole page. The homepage insets its hero because that hero
     is two columns inside a narrowed box; these pages are a single column, so copying
     the inset only put the hero on a different edge from every section under it. */
  /* Narrower than the container: full width made the stage read as a banner rather
     than a panel. It stays pinned to the page's left edge rather than centring, so
     capping the width does not put it back on a different edge from everything else. */
  /* two columns now, so the block uses the full container again: capping it left a
     dead band down the right of the section. The stage is the right column, which is
     what keeps the animation from reading as a banner. */
  .studio-solo{max-width:none;margin-inline:0}
  /* the negative left below was sized against the old 1020px cap, which left slack
     either side. At full width it walks the thread off the page, so it comes back
     inside the panel. */
  .studio-solo .thread{left:clamp(18px,2.4vw,46px);right:clamp(18px,2.4vw,46px)}
  /* No mask here. Masking the thread put it on a different raster path and every
     bubble came out soft. Instead the heading sits on the page colour above the
     thread's own layer, so a thread that grows tall slides behind it and is never
     cut or faded. Deterministic, where reserving a measured gap was not: the
     output card grows after its media loads and the reserve was always a guess. */
  .studio-solo .solo-say{position:relative;z-index:8;background:var(--n50);
    margin-bottom:0;padding-bottom:clamp(26px,3vw,44px)}
}
@media(min-width:901px) and (max-height:900px){.studio-solo{max-width:none}}

}

/* v68 the session runs a scene on video, so the pass figures take one too */
.msg.out .og figure video{display:block;width:100%;height:100%;object-fit:cover}


/* ---- v71 the scene arrives through a blur ----
   The room is not resolved when the conversation starts: a frosted field drifts
   over it while the person is still describing what they need, and it clears as
   the order is placed, so the render lands on a scene you can finally see.
   --veil runs 1 to 0 off the same scroll progress that walks the messages. */
.sstage .sveil{position:absolute;inset:0;z-index:1;pointer-events:none;
  opacity:var(--veil,1);
  backdrop-filter:blur(calc(var(--veil,1) * 26px)) saturate(calc(1 + var(--veil,1) * .25));
  -webkit-backdrop-filter:blur(calc(var(--veil,1) * 26px)) saturate(calc(1 + var(--veil,1) * .25));
  transition:opacity .5s linear}
/* two slow domes that drift and swell, so the blur reads as moving rather than flat */
.sstage .sveil::before,.sstage .sveil::after{content:"";position:absolute;inset:-25%;
  background-repeat:no-repeat;will-change:transform}
.sstage .sveil::before{
  background-image:radial-gradient(ellipse 46% 52% at 50% 50%,
    var(--od-3) 0%,var(--od-4) 45%,rgba(250,250,249,0) 78%);
  background-size:150% 170%;animation:sveilA 19s ease-in-out infinite alternate}
.sstage .sveil::after{
  background-image:radial-gradient(ellipse 52% 44% at 50% 50%,
    rgba(23,20,18,.30) 0%,rgba(23,20,18,.13) 48%,rgba(23,20,18,0) 80%);
  background-size:170% 150%;animation:sveilB 27s ease-in-out infinite alternate;
  animation-delay:-9s}
@keyframes sveilA{
  0%{background-position:12% 30%;transform:scale(1)}
  100%{background-position:82% 66%;transform:scale(1.18)}}
@keyframes sveilB{
  0%{background-position:78% 72%;transform:scale(1.12)}
  100%{background-position:22% 26%;transform:scale(1)}}
@media(prefers-reduced-motion:reduce){
  .sstage .sveil::before,.sstage .sveil::after{animation:none}
  .sstage .sveil{backdrop-filter:none;-webkit-backdrop-filter:none;opacity:0}}


/* ---- v74 one section: the step reel on the left, the run on the right ----
   The steps used to be a separate wall below the session, which said the same
   thing twice. They are now the caption track for the animation: the left column
   advances a step at a time, like a story, and the right column plays the part of
   the run that step is describing. One scroll drives both. */
@media(min-width:901px){
  .runreel{display:grid;grid-template-columns:minmax(0,.72fr) minmax(0,1.28fr);
    gap:clamp(30px,4vw,68px);align-items:center}
  .rl-say{align-self:center}
}
.rl-say h2{margin:0}
/* the segmented bar, read as progress through the five */
.rprog{display:flex;gap:6px;margin:clamp(22px,2.6vw,34px) 0 clamp(20px,2.4vw,30px);
  max-width:320px}
.rprog i{flex:1;height:3px;border-radius:2px;background:var(--n200);position:relative;overflow:hidden}
.rprog i::after{content:"";position:absolute;inset:0;background:var(--n900);
  transform:scaleX(0);transform-origin:left;transition:transform .5s var(--ease-out)}
.rprog i.done::after{transform:scaleX(1)}
/* every step occupies the same cell, so the column never jumps as they change */
.rsteps{display:grid}
.rstep{grid-area:1/1;opacity:0;transform:translateY(10px);pointer-events:none;
  transition:opacity .42s var(--ease-out),transform .52s var(--ease-out)}
.rstep.on{opacity:1;transform:none;pointer-events:auto}
.rstep .k{font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.1em;color:var(--n400)}
.rstep h3{margin:9px 0 10px;font-size:clamp(20px,1.9vw,26px);font-weight:500;
  letter-spacing:-.022em;color:var(--n900)}
.rstep p{margin:0;font-size:15px;line-height:1.6;color:var(--n500);max-width:42ch}
@media(max-width:900px){
  .rl-say{margin-bottom:clamp(22px,4vw,34px)}
  .rprog{max-width:none}
}

/* v74 the oldest messages leave through the top of the run panel.
   Clipping happens on the demo, never on the thread itself: masking the thread
   (which carries 3D transforms) is what smeared every bubble in v68. */
@media(min-width:901px){
  .runreel .studio-demo{clip-path:inset(0 -24% -10% -24%)}
  .runreel .studio-demo::before{content:"";position:absolute;left:-24%;right:-24%;top:0;
    height:clamp(56px,7vh,96px);z-index:7;pointer-events:none;
    background:linear-gradient(to bottom,var(--n50) 12%,rgba(250,250,249,0))}
}

/* v75. The top fade on the pinned demo bleeds 24% past its own box so the messages
   leave through a soft edge. That bleed was also 160px of horizontal page scroll at
   1440. Clip the section on x only: overflow:clip is not a scroll container, so the
   sticky pin inside is unaffected. */
#studio{overflow-x:clip}

/* ---------------------------------------------------------------
   v76. The jobs grid, promoted out of studio.html so robotics and
   world models use the same component. Six or five hairline cards,
   each naming the task and the layers it consumes. No decoration:
   the photo cards it replaced showed rooms, not the product.
   The mono label sizes step up below 620px, where 10px is not a
   size anyone reads on a phone.
   --------------------------------------------------------------- */
.jobs{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--n200);
  border:1px solid var(--n200);border-radius:var(--rl);overflow:hidden}
@media(max-width:900px){.jobs{grid-template-columns:repeat(2,1fr)}}
@media(max-width:620px){.jobs{grid-template-columns:1fr}}
.job{background:var(--n25);padding:clamp(20px,2vw,26px);display:flex;flex-direction:column;
  transition:background .2s var(--ease)}
.job:hover{background:#fff}
.job .k{font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--n400)}
.job h3{font-size:19px;margin-top:11px;letter-spacing:-.02em}
.job h3 a{color:inherit;text-decoration:none;border-bottom:1px solid var(--n300);
  transition:border-color .2s var(--ease)}
.job h3 a:hover{border-color:var(--n950)}
.job p{font-size:14.5px;line-height:1.6;color:var(--n500);margin-top:10px}
.job .ly{display:block;margin-top:auto;padding-top:20px;
  font-family:Geistmono,monospace;font-size:10px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--n400)}
@media(max-width:620px){
  .job .k{font-size:12px}
  .job .ly{font-size:11.5px;letter-spacing:.07em}
  .job h3{font-size:20px}
  .job p{font-size:15.5px}
}

/* ---------------------------------------------------------------
   v78. The FAQ, borrowed in structure from the technical landing
   pages we use as reference. Built on <details> so it needs no JS,
   works with a keyboard, and is readable with styles off. Google
   reads the open and closed states the same way.
   --------------------------------------------------------------- */
.faq{border-top:1px solid var(--n200);margin-top:clamp(28px,3.4vw,48px)}
.qa{border-bottom:1px solid var(--n200)}
.qa summary{list-style:none;cursor:pointer;display:flex;align-items:flex-start;gap:16px;
  padding:clamp(18px,2vw,24px) 0;font-size:clamp(16px,1.4vw,18.5px);color:var(--n900);
  letter-spacing:-.015em;line-height:1.4;transition:color .18s var(--ease)}
.qa summary::-webkit-details-marker{display:none}
.qa summary:hover{color:var(--n950)}
.qa summary::after{content:"";flex:none;width:11px;height:11px;margin-left:auto;margin-top:6px;
  border-right:1.5px solid var(--n400);border-bottom:1.5px solid var(--n400);
  transform:rotate(45deg) translate(-2px,-2px);transition:transform .22s var(--ease)}
.qa[open] summary::after{transform:rotate(-135deg) translate(-3px,-3px)}
.qa .a{padding:0 0 clamp(20px,2.2vw,26px);max-width:68ch}
.qa .a p{font-size:15.5px;line-height:1.65;color:var(--n500);margin:0}
.qa .a p+p{margin-top:12px}
.qa .a a{color:var(--n800);border-bottom:1px solid var(--n300)}
.qa .a a:hover{border-color:var(--n950)}
@media(max-width:620px){
  .qa summary{font-size:17px;gap:12px}
  .qa .a p{font-size:16px}
}
@media(prefers-reduced-motion:reduce){.qa summary,.qa summary::after{transition:none}}

/* ---------------------------------------------------------------
   v101. The environment catalogue as a queue of scenes. The stage and
   dense grid before this ran three interaction models at once and you
   could not steer any of them. One deck, two arrows, and the card on
   top turns by itself. Separation and tilt are the same numbers as the
   ground truth stack on the homepage, so the two read as one system.
   --------------------------------------------------------------- */
.envq-two{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1fr);
  gap:0 var(--gap-col);align-items:center;
  grid-template-areas:"txt deck" "nav deck"}
.envq-txt{grid-area:txt;align-self:end}
.envq-txt .lede{margin-top:clamp(15px,1.6vw,22px);max-width:42ch}
.envq-ctrl{grid-area:nav;align-self:start}
.envq-stage{grid-area:deck}
.envq-stage{position:relative;perspective:1700px;
  min-height:clamp(280px,30vw,390px);display:grid;place-items:center}
.envq-deck{position:relative;width:min(80%,460px);aspect-ratio:3/2;
  transform-style:preserve-3d;--sep:1;--px:0deg;--py:0deg;
  transform:translate3d(-12%,9%,0) rotateX(calc(9deg + var(--py)))
    rotateY(calc(-19deg + var(--px))) rotateZ(2deg);
  transition:transform .5s var(--ease-out);cursor:pointer}
.envq-deck:focus-visible{outline:2px solid var(--n900);outline-offset:16px;border-radius:4px}
.envq-card{position:absolute;inset:0;border-radius:12px;overflow:hidden;background:var(--n200);
  --dx:0px;--dy:0px;--dz:0px;
  transform:translate3d(calc(var(--dx) * var(--sep)),calc(var(--dy) * var(--sep)),
    calc(var(--dz) * var(--sep)));
  transition:transform .56s var(--ease-out),box-shadow .56s var(--ease),opacity .56s var(--ease);
  backface-visibility:hidden;contain:paint}
.envq-card.mv{will-change:transform,opacity}
.envq-card img,.envq-card video{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block}
/* the video gets its own layer, otherwise every decoded frame repaints the
   rounded clip and the shadow of a card sitting inside a 3D transform */
.envq-card video{opacity:0;transform:translateZ(0);backface-visibility:hidden;
  transition:opacity .55s var(--ease)}
.envq-card.on video{opacity:1}
.envq-pills{position:absolute;left:11px;top:11px;z-index:3;display:flex;gap:5px;
  opacity:0;transition:opacity .5s var(--ease)}
.envq-card.top .envq-pills{opacity:1}
.envq-pills span{font-family:Geistmono,monospace;font-size:9px;letter-spacing:.09em;
  text-transform:uppercase;color:#fff;background:rgba(11,10,9,.72);padding:4px 8px;
  border-radius:5px;white-space:nowrap}
.envq-pills .nm{letter-spacing:.06em}
.envq-pills .tp{color:rgba(255,255,255,.66)}

.envq-nav{display:flex;align-items:center;gap:9px;margin-top:clamp(24px,2.6vw,34px)}
.envq-nav button{width:40px;height:40px;border-radius:50%;border:1px solid var(--n300);
  background:#fff;cursor:pointer;display:grid;place-items:center;color:var(--n700);
  transition:border-color .22s var(--ease),color .22s var(--ease),
    transform .22s var(--ease-out),box-shadow .22s var(--ease)}
.envq-nav button:hover{border-color:var(--n900);color:var(--n950);transform:translateY(-1px);
  box-shadow:0 6px 16px rgba(23,20,18,.10)}
.envq-nav button:focus-visible{outline:2px solid var(--n900);outline-offset:2px}
.envq-nav svg{width:15px;height:15px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.envq-nav .ct{font-family:Geistmono,monospace;font-size:11px;letter-spacing:.1em;
  color:var(--n400);margin-left:8px;font-variant-numeric:tabular-nums}
.envq-dots{display:flex;gap:4px;margin-top:18px;flex-wrap:wrap;max-width:280px}
.envq-dots i{width:5px;height:5px;border-radius:50%;background:var(--n300);display:block;
  transition:background .3s var(--ease),transform .3s var(--ease-out)}
.envq-dots i.on{background:var(--n950);transform:scale(1.5)}

.envq-foot{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;
  margin-top:clamp(28px,3.2vw,44px);padding-top:clamp(16px,1.8vw,22px);
  border-top:1px solid var(--n200);
  font-family:Geistmono,monospace;font-size:11px;letter-spacing:.06em;color:var(--n500)}
.envq-foot b{color:var(--n900);font-weight:400}
.envq-foot a{color:var(--n900);border-bottom:1px solid var(--n300)}
.envq-foot a:hover{border-color:var(--n900)}

@media(max-width:1000px){
  .envq-two{grid-template-columns:1fr;gap:0;
    grid-template-areas:"txt" "deck" "nav"}
  .envq-txt,.envq-ctrl{align-self:auto}
  .envq-nav{margin-top:clamp(18px,2.4vw,26px)}
  .envq-stage{min-height:0;padding:46px 0 6px}
  .envq-deck{width:min(72%,420px)}
  .envq-nav{margin-top:22px}
}
@media(max-width:620px){.envq-deck{width:min(66%,420px)}}
@media(max-width:520px){
  .envq-foot{gap:8px 14px;font-size:10px}
  .envq-foot span:last-child{margin-left:0!important}
}
@media(prefers-reduced-motion:reduce){
  .envq-card video{display:none}
  .envq-card,.envq-deck{transition:none}
}
}

/* ---------------------------------------------------------------
   v81. The pass wipe was running full container width. The source
   clips are 960x480, so at 1440 the browser was inventing half the
   pixels it drew and the segmentation pass, which is flat colour
   with hard edges, showed every one of them. Capped at the native
   width and set on a dark panel so the constraint reads as a frame
   rather than as a shrunken element.
   --------------------------------------------------------------- */
.passwipe{background:var(--n950);border-radius:var(--rxl);
  padding:clamp(18px,2.2vw,30px) clamp(18px,2.2vw,30px) clamp(16px,2vw,26px)}
.pw-hold{max-width:960px;margin-inline:auto}
.pw-stage{box-shadow:0 0 0 1px var(--od-5),0 24px 60px rgba(0,0,0,.45)}
.passfoot{max-width:960px;margin-inline:auto}
@media(min-width:981px){ .passwipe{padding-inline:clamp(26px,3vw,48px)} }

/* ---------------------------------------------------------------
   v81. Company. The page had no photograph on it at all, while a
   picture of the whole team was sitting on the live site. It is now
   the band the page turns on, with the two numbers we can stand
   behind laid over it. The legal entity table is gone: it duplicated
   the imprint page, which is where a reader expects it.
   --------------------------------------------------------------- */
.band-team{position:relative;border-radius:var(--rxl);overflow:hidden;background:var(--n950)}
.band-team img{width:100%;display:block;aspect-ratio:21/9;object-fit:cover;
  transform:scale(1.02);transition:transform 1.4s var(--ease-out)}
.band-team:hover img{transform:scale(1.045)}
.band-team::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(11,10,9,.94) 0%,rgba(11,10,9,.78) 14%,rgba(11,10,9,.30) 40%,rgba(11,10,9,.04) 70%)}
.band-meta{position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:clamp(20px,2.6vw,40px);display:flex;align-items:flex-end;gap:clamp(20px,4vw,64px);
  flex-wrap:wrap;color:var(--n50)}
.band-meta .cap{font-family:Geistmono,monospace;font-size:11px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--od-2);max-width:34ch;line-height:1.75;
  text-shadow:0 1px 10px rgba(0,0,0,.7)}
.band-nums{display:flex;gap:clamp(24px,4vw,64px);margin-left:auto}
.band-nums div{min-width:0}
.band-nums .v{display:block;font-size:clamp(28px,3.4vw,46px);line-height:1;letter-spacing:-.035em;
  color:#fff;font-weight:500}
.band-nums .k{display:block;margin-top:8px;font-family:Geistmono,monospace;font-size:10.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--od-3)}
/* v93. On a phone the overlay sat straight across the faces: the scrim keeps
   the caption legible but it is covering the thing the photograph is for.
   Below 700px the meta drops out of the image and into its own dark strip
   under it, the gradient goes with it, and the crop opens to 3:2 so fewer
   people are cut off at the edges. */
@media(max-width:700px){
  .band-team img{aspect-ratio:3/2}
  .band-team::after{display:none}
  .band-meta{position:static;flex-direction:column;align-items:flex-start;gap:18px;
    background:var(--n950);padding:22px 20px 24px}
  .band-meta .cap{max-width:none;text-shadow:none}
  .band-nums{margin-left:0;gap:28px}
}

/* v96. Advisors. Three cards at a third of the width each made three people
   look like the whole company; the list is also going to grow. Four across,
   portrait crop rather than square, and the type stepped down with it.

   The white hairline on hover was the card's own background showing between
   its 1px border and the image: a translated, rounded, overflow-hidden box
   leaves a subpixel gap on that edge in Chrome. The border is now an inset
   shadow, which paints inside the clip and cannot separate from it.

   Each card carries the mark of the company the person is known for. */
.advs{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(12px,1.4vw,20px)}
@media(max-width:1000px){.advs{grid-template-columns:repeat(3,1fr)}}
@media(max-width:720px){.advs{grid-template-columns:repeat(2,1fr)}}
/* v112 two portraits per row on phones: one per row made each face a full screen */
.adv{border:0;box-shadow:inset 0 0 0 1px var(--n200);border-radius:var(--rl);
  overflow:hidden;background:var(--n25);backface-visibility:hidden}
.adv:hover{box-shadow:inset 0 0 0 1px var(--n200),var(--shadow-card);transform:translateY(-2px)}
.adv .ph{display:block;line-height:0}
.adv img{width:100%;aspect-ratio:4/5;object-fit:cover;display:block;
  filter:grayscale(1);transition:filter .45s var(--ease)}
.adv:hover img{filter:grayscale(0)}
.adv .tx{padding:13px 14px 15px}
.adv .nm{display:block;font-size:14.5px;font-weight:500;letter-spacing:-.015em;color:var(--n950)}
.adv .rl{display:flex;align-items:center;gap:6px;margin-top:6px;
  font-family:Geistmono,monospace;font-size:9.5px;letter-spacing:.07em;
  text-transform:uppercase;color:var(--n400);line-height:1.45}
.adv .rl .cm{width:12px;height:12px;aspect-ratio:1;flex:none;object-fit:contain;
  filter:grayscale(1) brightness(.55);opacity:.8;transition:none}
.adv:hover .rl .cm{filter:grayscale(1) brightness(.55)}
@media(prefers-reduced-motion:reduce){
  .band-team img,.adv img,.adv{transition:none}
  .band-team:hover img{transform:scale(1.02)}
}

/* ---------------------------------------------------------------
   v81. One scene, run again. Five runs of the same bedroom with one
   axis moved each time, as an accordion: the active panel takes the
   room and the rest compress to a spine carrying their axis label.
   Hovering expands. It is the product promise as an interaction
   rather than as a sentence.
   --------------------------------------------------------------- */
/* v111.5 no tray: each panel is its own rounded image with a gap of page colour between them */
.runs{display:flex;gap:8px;height:clamp(340px,42vw,470px)}
.run{position:relative;flex:1 1 0;min-width:0;border:0;padding:0;cursor:pointer;background:#0b0a09;
  border-radius:6px;overflow:hidden;
  transition:flex-grow .55s var(--ease-out)}
.run.on{flex-grow:4.2}
.run img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  filter:grayscale(.7) brightness(.52);transition:filter .5s var(--ease)}
.run.on img{filter:none}
.run::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(11,10,9,.9) 0%,rgba(11,10,9,.25) 42%,transparent 66%)}
.run .lb{position:absolute;left:0;right:0;bottom:0;z-index:2;padding:16px 16px 15px;text-align:left}
.run .ax{display:block;font-family:Geistmono,monospace;font-size:10px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--od-3);white-space:nowrap}
.run .vl{display:block;margin-top:5px;font-size:15px;letter-spacing:-.015em;color:#fff;
  white-space:nowrap;opacity:.72;transition:opacity .4s var(--ease)}
.run.on .vl{opacity:1;font-size:clamp(16px,1.5vw,20px)}
.run .no{position:absolute;top:14px;left:16px;z-index:2;font-family:Geistmono,monospace;
  font-size:10px;letter-spacing:.11em;color:var(--od-3)}
.run:focus-visible{outline:2px solid #fff;outline-offset:-2px}
@media(max-width:820px){
  .runs{flex-direction:column;height:auto}
  .run{flex:none;height:88px;transition:height .5s var(--ease-out)}
  .run.on{height:clamp(240px,58vw,330px)}
  .run .vl,.run.on .vl{white-space:normal}
}
@media(prefers-reduced-motion:reduce){
  .run,.run img,.run .vl{transition:none}
  .runs{flex-wrap:wrap;height:auto}
  .run{flex:1 1 30%;height:200px}
  .run img{filter:none}
}

/* a collapsed panel is too narrow for its value, and a clipped half-word
   reads as a bug. Collapsed shows the axis only; the value arrives with the room. */
.run .vl{opacity:0;transform:translateY(6px);
  transition:opacity .38s var(--ease),transform .38s var(--ease),font-size .38s var(--ease)}
.run.on .vl{opacity:1;transform:none}
.run .ax{transition:color .3s var(--ease)}
.run.on .ax{color:var(--od-2)}
.run:not(.on) .lb{padding-bottom:18px}
@media(max-width:820px){ .run .vl{opacity:1;transform:none} }
@media(prefers-reduced-motion:reduce){ .run .vl{opacity:1;transform:none} }
@media(max-width:820px){ .run .no{top:auto;bottom:16px;left:auto;right:16px} }
/* the phone floor applies to the new components too */
@media(max-width:620px){
  .run .ax,.run .no{font-size:11.5px}
  .envq-foot{font-size:10.5px}
  .glos-nav .gn,.glos-nav .gc,.glos-nav .gt,.glos-nav .gtot,.gh .gn{font-size:11.5px}
  .artgrid .art .d{font-size:11.5px}
  .band-meta .cap,.band-nums .k{font-size:11.5px}
}

/* ---------------------------------------------------------------
   v82. The cinematic sub-page hero. Measured against the reference
   sites: theirs open full bleed with motion and the headline over
   the image; ours opened with a headline and then a still in a box
   underneath. Same video, given the whole viewport and the type on
   top of it.
   --------------------------------------------------------------- */
.chero{position:relative;min-height:clamp(560px,78vh,820px);display:flex;align-items:flex-end;
  background:#0b0a09;overflow:hidden;isolation:isolate}
.chero-bg{position:absolute;inset:0;z-index:0}
.chero-bg video,.chero-bg img{width:100%;height:100%;object-fit:cover;display:block;
  transform:scale(1.03)}
.chero-bg::after{content:"";position:absolute;inset:0;
  background:linear-gradient(to top,rgba(11,10,9,.93) 0%,rgba(11,10,9,.74) 26%,
    rgba(11,10,9,.34) 58%,rgba(11,10,9,.46) 100%)}
/* bright footage needs a floor under the gradient or white type sits on white ceiling */
.chero-bg::before{content:"";position:absolute;inset:0;z-index:1;background:rgba(11,10,9,.30)}
.chero-bg::after{z-index:2}
.chero .wrap-wide{position:relative;z-index:2;width:100%;
  padding-top:clamp(120px,16vh,180px);padding-bottom:clamp(40px,5vh,72px)}
.chero .crumb{margin-bottom:clamp(18px,2vw,26px)}
.chero .crumb a,.chero .crumb span{color:var(--od-2)}
.chero .crumb a{border-bottom-color:var(--od-4)}
.chero .crumb a:hover{color:#fff;border-bottom-color:#fff}
.chero h1{color:#fff;max-width:17ch}
.chero .lede{color:var(--od-2);max-width:56ch;margin-top:clamp(18px,2vw,26px)}
.chero .lede a{color:#fff;border-bottom:1px solid var(--od-3)}
.chero .lede a:hover{border-color:#fff}
.chero .hero-cta{margin-top:clamp(26px,3vw,38px);display:flex;gap:11px;flex-wrap:wrap}
.chero .btn-ghost{color:#fff;border-color:var(--od-4);background:transparent}
.chero .btn-ghost:hover{border-color:#fff;background:rgba(250,250,249,.07)}
.chero-mark{position:absolute;right:clamp(18px,3vw,44px);bottom:clamp(18px,2.4vw,32px);z-index:2;
  font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.11em;text-transform:uppercase;
  color:var(--od-3);text-align:right;line-height:1.9}
@media(max-width:760px){
  .chero{min-height:auto}
  .chero .wrap-wide{padding-top:clamp(108px,20vh,150px);padding-bottom:36px}
  .chero-mark{display:none}
}
@media(prefers-reduced-motion:reduce){.chero-bg video{display:none}}

/* five cards in a three-column grid leaves a visible hole in the sixth slot.
   Six columns, each card spanning two, and the last row's two cards spanning
   three, so five items fill the block with no gap. */
@media(min-width:901px){
  .jobs:has(> .job:nth-child(5):last-child){grid-template-columns:repeat(6,1fr)}
  .jobs:has(> .job:nth-child(5):last-child) > .job{grid-column:span 2}
  .jobs:has(> .job:nth-child(5):last-child) > .job:nth-child(4){grid-column:span 3}
  .jobs:has(> .job:nth-child(5):last-child) > .job:nth-child(5){grid-column:span 3}
}


/* v85. The pass caption had three inline glossary links inside one sentence,
   which read as a link farm under the showpiece. One quiet link after the
   sentence keeps the internal link without breaking the caption. */
.passlink{display:inline-block;margin-left:14px;color:var(--od-2);
  border-bottom:1px solid var(--od-5);padding-bottom:1px}
.passlink:hover{color:var(--od-1);border-color:var(--od-3)}
@media(max-width:620px){.passlink{display:inline-flex;align-items:center;min-height:40px;margin-left:0;margin-top:4px}}

/* v85. The page's statement, carried by the heading of the dark pass section
   rather than by a section of its own. One step above the 46px h2 and still
   under the 68px hero, so it ranks without competing. The second clause drops
   to the faint rung, which is what gives the line its shape. */
.stmt-h2{font-size:clamp(32px,4.2vw,58px);line-height:1.04;letter-spacing:-.032em;max-width:20ch}
.stmt-h2 .dim{color:var(--od-4)}

/* ---------------------------------------------------------------
   v86. Frame stack. The job and format cards were text only, so a grid
   of them read as a wall of paragraphs. Three real render thumbnails
   per card, the environments or passes that card is actually about.
   At rest they sit as a stack; on hover they spread into an even row,
   which says what a run produces rather than decorating the card.
   Real imagery, no icons.
   --------------------------------------------------------------- */
.stk{position:relative;display:block;width:100%;max-width:252px;height:56px;
  margin-bottom:18px;flex:none}
.stk img{position:absolute;top:0;left:0;width:84px;height:56px;object-fit:cover;
  border-radius:6px;border:1.5px solid #fff;background:var(--n100);
  box-shadow:0 1px 4px rgba(28,25,23,.15);
  transition:transform .42s var(--ease-out),box-shadow .3s var(--ease)}
.stk img:nth-child(1){transform:translateX(0) rotate(-3deg);z-index:1}
.stk img:nth-child(2){transform:translateX(15px) rotate(.5deg);z-index:2}
.stk img:nth-child(3){transform:translateX(30px) rotate(3.5deg);z-index:3}
.job:hover .stk img,.tile:hover .stk img{box-shadow:0 2px 8px rgba(28,25,23,.17)}
.job:hover .stk img:nth-child(1),.tile:hover .stk img:nth-child(1){transform:translateX(0) rotate(0)}
.job:hover .stk img:nth-child(2),.tile:hover .stk img:nth-child(2){transform:translateX(88px) rotate(0)}
.job:hover .stk img:nth-child(3),.tile:hover .stk img:nth-child(3){transform:translateX(176px) rotate(0)}
@media(max-width:820px){
  .stk{max-width:200px;height:46px}
  .stk img{width:68px;height:46px}
  .stk img:nth-child(2){transform:translateX(12px) rotate(.5deg)}
  .stk img:nth-child(3){transform:translateX(24px) rotate(3.5deg)}
  .job:hover .stk img:nth-child(2),.tile:hover .stk img:nth-child(2){transform:translateX(66px) rotate(0)}
  .job:hover .stk img:nth-child(3),.tile:hover .stk img:nth-child(3){transform:translateX(132px) rotate(0)}
}
@media(prefers-reduced-motion:reduce){
  .stk img{transition:none}
  .job:hover .stk img:nth-child(1),.tile:hover .stk img:nth-child(1){transform:translateX(0) rotate(-3deg)}
  .job:hover .stk img:nth-child(2),.tile:hover .stk img:nth-child(2){transform:translateX(15px) rotate(.5deg)}
  .job:hover .stk img:nth-child(3),.tile:hover .stk img:nth-child(3){transform:translateX(30px) rotate(3.5deg)}
}

/* ---------------------------------------------------------------
   v88. Pass grid. Replaces the four stacked videos that cycled one
   pass at a time: they showed a black box until the video loaded,
   took eight seconds to show all four, and weighed 2.4MB. These are
   the real frames from the Studio demo, all four visible at once,
   which is the whole point of the section.
   --------------------------------------------------------------- */
.pgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(8px,1vw,14px);
  margin-top:clamp(26px,3.4vw,46px)}
.pgrid .pf{margin:0;position:relative}
.pgrid img{width:100%;aspect-ratio:16/9;object-fit:cover;display:block;
  border-radius:var(--r);background:var(--n900)}
.pgrid figcaption{display:flex;flex-direction:column;gap:2px;margin-top:10px}
.pgrid figcaption b{font-family:Geistmono,monospace;font-size:10.5px;font-weight:500;
  letter-spacing:.11em;text-transform:uppercase;color:var(--od-2)}
.pgrid figcaption i{font-family:Geistmono,monospace;font-size:10px;font-style:normal;
  letter-spacing:.04em;color:var(--od-4)}
@media(max-width:820px){.pgrid{grid-template-columns:1fr 1fr}}

/* v89. Contact pages. They had four invented sections each: a fictional
   call agenda, a queue policy, a "what actually happens" ladder and a
   closing panel, none of it anything we actually commit to. A contact
   page is a title, a form and a short note on what you get. */
.uspline{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(20px,2.6vw,44px);
  margin-top:clamp(18px,2vw,26px)}
.uspline .k{font-family:Geistmono,monospace;font-size:10.5px;font-weight:500;
  letter-spacing:.11em;text-transform:uppercase;color:var(--n400);display:block}
.uspline p{font-size:15px;line-height:1.55;color:var(--n600);margin-top:9px;max-width:34ch}
@media(max-width:760px){.uspline{grid-template-columns:1fr;gap:22px}}

/* ---------------------------------------------------------------
   v90. Viewpoint row. Three real frames from the Studio demo, each a
   different robot's own camera on the same kitchen. Robot policies
   only: world models gets the authored-camera row instead, because a
   prediction model consumes a trajectory, not an embodiment.
   --------------------------------------------------------------- */
.vprow{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(10px,1.4vw,20px);
  margin-top:clamp(28px,3.4vw,46px)}
/* v95. These frames carry a HUD burned into the render, and every element of
   it sits flush to the edge: the CAPTURED strip, the speed and heading
   readout, the trajectory minimap, and the object labels at left and right.
   A border-radius on the image itself therefore clipped the corners off real
   content, which read as the overlay falling out of the frame. The image now
   sits inside a dark bezel that owns the radius, so nothing is cut and the
   edge-to-edge HUD reads as a viewport rather than a mistake. */
.vprow figure{margin:0}
.vprow .fr{display:block;background:var(--n950);border-radius:var(--r);
  padding:5px;overflow:hidden}
.vprow img{width:100%;aspect-ratio:2/1;object-fit:cover;display:block;
  border-radius:calc(var(--r) - 5px);background:var(--n100)}
.vprow figcaption{margin-top:12px}
.vprow .k{display:block;font-size:17px;letter-spacing:-.017em;color:var(--n900);font-weight:500}
.vprow .d{display:block;font-family:Geistmono,monospace;font-size:10.5px;letter-spacing:.09em;
  text-transform:uppercase;color:var(--n400);margin-top:6px}
@media(max-width:820px){
  .vprow{grid-template-columns:1fr;gap:22px}
}
/* 16/9 here cropped ~10% off each side, which is exactly where the HUD
   readouts live. The source is 1.978:1, so 2/1 loses nothing. */
.vprow.four{grid-template-columns:repeat(4,1fr)}
@media(max-width:900px){.vprow.four{grid-template-columns:1fr 1fr}}
/* four stacked cards ran 1.9 screen-heights on a phone; two columns holds it to one */
@media(max-width:560px){.vprow.four{gap:12px}.vprow.four figcaption{margin-top:9px}
  .vprow.four .k{font-size:15px}}

/* ---------------------------------------------------------------
   v105. The variant strip. The four passes show one run. The thread
   promises 480 of them, so the strip shows the queue filling in: the
   current run outlined, the ones still to come dimmed, and the axis
   being varied named beside the counter.
   --------------------------------------------------------------- */
.msg.out .svar{display:grid;grid-template-columns:repeat(6,minmax(0,clamp(58px,7.2vw,94px)));
  gap:5px;margin-top:10px;padding-top:10px;border-top:1px solid var(--n200);justify-content:start}
.msg.out .svar i{position:relative;display:block;border-radius:6px;overflow:hidden;
  aspect-ratio:16/9;background:var(--n200);
  box-shadow:inset 0 0 0 1px rgba(23,20,18,.10);
  opacity:.34;filter:grayscale(.55);
  transition:opacity .45s var(--ease),filter .45s var(--ease),box-shadow .3s var(--ease)}
.msg.out .svar i img{width:100%;height:100%;object-fit:cover;display:block}
.msg.out .svar i.done{opacity:.8;filter:none}
.msg.out .svar i.on{opacity:1;filter:none;box-shadow:inset 0 0 0 2px var(--n950)}
.msg.out .of .ax{margin-left:auto;font-family:Geistmono,monospace;font-size:10.5px;
  letter-spacing:.08em;color:var(--n500);white-space:nowrap}
@media(max-width:620px){
  .msg.out .svar{grid-template-columns:repeat(6,minmax(0,1fr));gap:4px}
  .msg.out .of .ax{display:none}
}
@media(prefers-reduced-motion:reduce){.msg.out .svar i{transition:none}}

/* v108 Careers on the company page. One heading, one factual line and a control
   that is deliberately inert until there is an ATS behind it. It is a span, not
   a link or a button, so nothing about it invites a click it cannot answer. */
.careers{display:grid;gap:clamp(20px,2.6vw,38px);align-items:end}
.careers h2{margin:0}
.careers .lede{margin:clamp(14px,1.6vw,20px) 0 0;max-width:52ch}
.careers .is-soon{cursor:default;color:var(--n500);border-color:var(--n200);
  background:transparent;pointer-events:none}
@media(min-width:901px){
  .careers{grid-template-columns:minmax(0,1fr) auto}
  .careers-act{padding-bottom:4px}
}

/* v108 the article cards leave the site. They point at physicl.ai, which still
   runs the old header, so the jump was reading as a bug. They now open in a new
   tab and the arrow points out rather than right, which is the one convention
   everybody already knows. When this site replaces the live one the links become
   internal and this marker comes off. */
.art .go-out{transform:none}
.art:hover .go-out{transform:translate(2px,-2px)}


/* ---------------------------------------------------------------
   v108 the Q and A, denser and moved to the end of the page.
   Three questions filling a whole screen was not a Q and A, it was a
   gap with text in it. The heading now sits in its own column and the
   questions run beside it in two columns on a wide screen, so eight
   of them take the room three used to. Below 900 it falls back to one
   column, in the order it reads.
   --------------------------------------------------------------- */
@media(min-width:901px){
  .faq-two{display:grid;grid-template-columns:minmax(0,.46fr) minmax(0,1fr);
    gap:0 var(--gap-col);align-items:start}
  .faq-two .faq-say{position:sticky;top:clamp(96px,11vh,132px)}
  /* two fixed stacks: opening a question only pushes the ones under it, never moves it across */
  .faq-cols{display:grid;grid-template-columns:1fr 1fr;column-gap:clamp(26px,3vw,46px);align-items:start}
  .faq{margin-top:0}
}
.faq-say h2{margin:0}
.faq-say .lede{margin-top:clamp(12px,1.4vw,18px);max-width:34ch}
@media(max-width:900px){
  .faq-say{max-width:660px}
  .faq{margin-top:clamp(24px,3vw,38px)}
}
/* the closing panel is the last thing with a background, so the Q and A that
   follows it sits on the page itself and needs its own breathing room */
.faq-sec{padding-block:clamp(56px,6.4vw,96px) clamp(64px,7vw,110px)}

/* v108 the camera row plays rather than describes. It used to be four stills of
   four camera rigs we cannot show, which is the weakest thing a section about
   movement can be. It is four stretches of one real run now, so the claim and
   the picture are the same thing. Same bezel as the still version. */
.vprow video{width:100%;aspect-ratio:2/1;object-fit:cover;display:block;
  border-radius:calc(var(--r) - 5px);background:var(--n100);
  transform:translateZ(0)}
.camrow .fr{contain:paint}

/* v108 the pass stack on World models needs the same room the homepage gives it:
   the sheets step out by 40 across, 62 down and 150 forward, and a box with no
   padding clips them. */
#layers .stack{padding:clamp(54px,5.4vw,96px) clamp(46px,4.8vw,86px);min-height:0;overflow:visible}
#layers .stack-in.wide{width:min(100%,440px)}

/* v108 a collapsed run column is about 130px between the tablet breakpoint and
   a laptop, and any value longer than a word ran past it. The active card has
   the room for the full label; the collapsed ones cut cleanly instead. */
.run .vl{overflow:hidden;text-overflow:ellipsis}
.run.on .vl{overflow:visible;text-overflow:clip}

/* v108 the one link in the catalogue footer strip was 15px tall on a phone,
   under the 40px floor the rest of the site keeps. */
@media(max-width:620px){
  .envq-foot a{display:inline-flex;align-items:center;min-height:40px;margin-block:-10px}
}

.qa summary:focus:not(:focus-visible){outline:none}

/* v110.1 The two camera rows, set like every other section: the heading block on top, then one
   frame across two thirds of the page with its list beside it, the list exactly as tall as the
   frame so both edges line up. World models plays the four stretches of the gym run in order
   and the rule above each chapter fills as it plays. On Robot policies the list is a height
   scale: humanoid at the top, floor robot at the bottom, the marker travelling between them.
   The robot frames carry a HUD to the very edge, so both frames share one small 6px corner. */
.cam-wrap,.eye-wrap{display:grid;grid-template-columns:minmax(0,2fr) minmax(0,1fr);
  gap:clamp(22px,3vw,48px);align-items:stretch;margin-top:clamp(30px,3.6vw,48px)}
.cam-stage,.eye-stage{position:relative;overflow:hidden;background:var(--n100);aspect-ratio:2/1;width:100%}
.cam-stage,.eye-stage{border-radius:6px}
.cam-stage::after,.eye-stage::after{content:"";position:absolute;inset:0;border-radius:inherit;
  box-shadow:inset 0 0 0 1px rgba(20,18,16,.08);pointer-events:none;z-index:2}
.cam-stage video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .6s var(--ease)}
.cam-stage video.on{opacity:1}
.cam-tag{position:absolute;left:14px;bottom:13px;z-index:3;color:rgba(255,255,255,.88);
  font-family:Geistmono,monospace;font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  background:rgba(12,11,10,.45);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  border-radius:6px;padding:6px 9px 5px}
.cam-ch,.eye-opt{appearance:none;border:0;background:none;padding:0;margin:0;text-align:left;cursor:pointer;font:inherit;color:inherit}
.cam-line{display:flex;flex-direction:column}
.cam-ch{flex:1 1 0;display:flex;flex-direction:column}
.cam-ch .bar{display:block;height:1px;background:var(--n200);overflow:hidden}
.cam-ch .bar i{display:block;height:100%;width:100%;transform:scaleX(0);transform-origin:0 50%;background:var(--n900)}
.cam-ch .row{display:flex;gap:14px;padding-top:14px}
.cam-ch .nb,.eye-opt .nb{font-family:Geistmono,monospace;font-size:11px;color:var(--n400);min-width:22px;padding-top:4px}
.cam-ch .k,.eye-opt .k{display:block;font-size:17px;font-weight:500;letter-spacing:-.015em;color:var(--n400);transition:color .3s}
.cam-ch .d,.eye-opt .d{display:block;margin-top:4px;font-family:Geistmono,monospace;font-size:10px;
  letter-spacing:.09em;text-transform:uppercase;color:var(--n400)}
.cam-ch.on .k,.cam-ch:hover .k,.eye-opt.on .k,.eye-opt:hover .k{color:var(--n900)}
.eye-rail{position:relative;display:flex;flex-direction:column;justify-content:space-between;padding:2px 0 2px 26px}
.eye-rail::before{content:"";position:absolute;left:5px;top:8px;bottom:8px;width:1px;background:var(--n200)}
.eye-rail .dot{position:absolute;left:0;top:6px;width:11px;height:11px;border-radius:50%;background:var(--n900);
  box-shadow:0 0 0 4px var(--n25);transition:top .9s var(--ease-out)}
.eye-stage img,.eye-stage video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;
  transform:translateY(3%) scale(1.03);transition:opacity .8s var(--ease),transform 1.2s var(--ease-out)}
.eye-stage img.on,.eye-stage video.on{opacity:1;transform:none}
.eye-stage img.up,.eye-stage video.up{transform:translateY(-3%) scale(1.03)}
@media(max-width:900px){
  .cam-wrap,.eye-wrap{grid-template-columns:1fr}
  .cam-line{display:grid;grid-template-columns:1fr 1fr;column-gap:18px;row-gap:14px}
  .cam-ch .row{padding-top:11px}
  .cam-ch .k,.eye-opt .k{font-size:15px}
  .eye-rail{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;padding:0}
  .eye-rail .eye-opt[data-i="0"]{order:1}.eye-rail .eye-opt[data-i="1"]{order:2}.eye-rail .eye-opt[data-i="2"]{order:3}
  .eye-rail::before,.eye-rail .dot{display:none}
}
@media(prefers-reduced-motion:reduce){.cam-stage video,.eye-stage img,.eye-rail .dot{transition:none}.eye-stage img{transform:none}}

/* v113 phones and tablets: the Studio block is pinned like on desktop and the scroll
   drives the conversation. The height of the pinned range and the sticky offset are
   set by site.js from the block's own height. Messages slide up the way they do on
   desktop: they stay in the flow and move together by the height of what is to come. */
@media(max-width:900px){
  #studio .pin-wrap{height:var(--pin-wrap-h,auto)}
  #studio .pin-stick{position:sticky;top:var(--pin-top,0px);height:auto;min-height:0;display:block;padding-block:0}
  .thread .msg,.thread .typing{translate:0 var(--ythread,0px);
    transition:opacity .42s var(--ease-out),transform .52s var(--ease-out),translate .6s var(--ease-out),
               filter .42s var(--ease),box-shadow .42s var(--ease)}
  .thread .msg.picks{transition:translate .6s var(--ease-out)}
}
@media(min-width:601px) and (max-width:900px){
  .sstage,.studio-solo .sstage{aspect-ratio:4/3}
}

/* v114 a pick left unticked: the axis exists but is held still for this order */
.pk.off{color:var(--n500)}
.pk.off .bx{background:none;box-shadow:inset 0 0 0 1.5px var(--n300)}
.pk.off .bx::after{display:none}

/* v118 Robot policies: the statement block is light and the spaces block is dark,
   so the page alternates dark hero, light, dark, light. */
.stmt-light .stmt-h2 .dim{color:var(--n400)}
.stmt-light .pgrid img{background:var(--n200)}
.stmt-light .pgrid figcaption b{color:var(--n800)}
.stmt-light .pgrid figcaption i{color:var(--n500)}
.envs-dark .eyebrow .mono{color:var(--od-3)}
.envs-dark .eyebrow::after{background:var(--od-5)}
.envs-dark .envq-nav button{border-color:var(--od-5);color:var(--od-2);background:transparent}
.envs-dark .envq-nav button:hover{border-color:#fff;color:#fff}
.envs-dark .envq-nav button:focus-visible{outline-color:#fff}
.envs-dark .envq-deck:focus-visible{outline-color:#fff}
.envs-dark .envq-dots i{background:var(--od-5)}
.envs-dark .envq-dots i.on{background:#fff}
.envs-dark .envq-card{box-shadow:0 24px 60px rgba(0,0,0,.45)}

/* v120 dark camera block (World models) and dark jobs blocks (both use-case pages),
   so every page alternates dark and light; the World models layer block goes light */
.cam-dark .eyebrow .mono,.jobs-dark .eyebrow .mono{color:var(--od-3)}
.cam-dark .eyebrow::after,.jobs-dark .eyebrow::after{background:var(--od-5)}
.cam-dark .cam-stage{background:var(--n900)}
.cam-dark .cam-stage::after{box-shadow:inset 0 0 0 1px rgba(255,255,255,.06)}
.cam-dark .cam-ch .bar{background:var(--od-5)}
.cam-dark .cam-ch .bar i{background:#fff}
.cam-dark .cam-ch .nb,.cam-dark .cam-ch .k,.cam-dark .cam-ch .d{color:var(--od-4)}
.cam-dark .cam-ch.on .k,.cam-dark .cam-ch:hover .k{color:#fff}
.cam-dark .cam-ch.on .d,.cam-dark .cam-ch.on .nb{color:var(--od-3)}
.jobs-dark .lede a{color:var(--n50);border-bottom:1px solid var(--od-4)}
.jobs-dark .jobs{background:var(--od-5);border-color:var(--od-5)}
.jobs-dark .job{background:var(--n950)}
.jobs-dark .job:hover{background:#221f1c}
.jobs-dark .job h3{color:var(--n50)}
.jobs-dark .job h3 a{border-color:var(--od-4)}
.jobs-dark .job h3 a:hover{border-color:#fff}
.jobs-dark .job p{color:var(--od-3)}
.jobs-dark .job .k,.jobs-dark .job .ly{color:var(--od-4)}

/* the World models layer list now sits on light: undo the #layers dark colours */
.stmt-light#layers .lrow{border-color:var(--n200)}
.stmt-light#layers .lrow .n{color:var(--n900)}
.stmt-light#layers .lrow .d{color:var(--n500)}
.stmt-light#layers .lrow .k{color:var(--n400)}

/* v122 contact pages (Private Beta, Talk to sales): the three facts sit under the
   headline so the left column is not empty; the form carries the live HubSpot fields,
   short ones in pairs; no mono header and no status dot on the card. */
.cpage .cfacts{margin-top:clamp(30px,3.4vw,46px);max-width:46ch;border-top:1px solid var(--n200)}
.cpage .frow{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.cpage .frow .fld{margin-top:18px}
.cpage .fcard>.fld{margin-top:18px}
.cpage .fcard>.frow:first-child .fld,.cpage .fcard>.fld:first-child{margin-top:0}
.cpage .fld label i{font-style:normal;color:var(--n400)}
.cpage .fld input,.cpage .fld textarea{background:#fff}
.cpage .ferr{margin:14px 0 0;font-size:13.5px;color:#a8321f}
.cpage .fcard .fine a{text-decoration:underline;text-underline-offset:2px}
.cpage .pcl-thanks h2{font-size:clamp(22px,2vw,26px);letter-spacing:-.02em;margin:0}
.cpage .pcl-thanks p{margin:10px 0 0;color:var(--n500);font-size:15px}
@media(max-width:520px){.cpage .frow{grid-template-columns:1fr;gap:0}.cpage .fcard>.frow:first-child .fld+.fld{margin-top:18px}}

/* v123 contact pages, second pass: form on the left without a card, a dark proof panel on
   the right with real Studio passes, the three facts and the logo strip (Scale-style layout,
   our own material). */
.cpage2 .cgrid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.92fr);gap:clamp(36px,5vw,84px);align-items:start}
@media(max-width:1000px){.cpage2 .cgrid{grid-template-columns:1fr}}
.cpage2 h1{font-size:clamp(38px,4.6vw,60px);letter-spacing:-.03em;line-height:1.04;margin:0;max-width:14ch}
.cpage2 .lede{max-width:44ch;margin-top:20px}
.cpage2 .cform{margin-top:clamp(28px,3vw,40px);max-width:620px}
.cpage2 .cform>.frow:first-child .fld,.cpage2 .cform>.fld:first-child{margin-top:0}
.cpage2 .cform>.fld{margin-top:18px}
.cpage2 .cform .btn{margin-top:24px}
.cpage2 .cform .fine{font-size:13px;color:var(--n500);margin-top:14px}
.cpage2 .cform .fine a{text-decoration:underline;text-underline-offset:2px}
.cpage2 .fld input,.cpage2 .fld textarea{background:#fff;border-color:var(--n300);padding:13px 14px}
.cpage2 .cthanks{margin-top:clamp(28px,3vw,40px);padding:26px 28px;border:1px solid var(--n200);border-radius:var(--rl);background:#fff;max-width:620px}
.cpage2 .cthanks h2{font-size:clamp(22px,2vw,26px);letter-spacing:-.02em;margin:0}
.cpage2 .cthanks p{margin:10px 0 0;color:var(--n500);font-size:15px}
.cpanel{background:var(--n950);color:var(--n50);border-radius:14px;padding:clamp(18px,2vw,26px);
  display:flex;flex-direction:column;gap:12px}
.cpanel figure{margin:0;position:relative}
.cpanel img{display:block;width:100%;object-fit:cover;border-radius:8px;background:var(--n900)}
.cp-main img{aspect-ratio:16/9}
.cp-row{display:grid;grid-template-columns:repeat(3,1fr);gap:10px}
.cp-row img{aspect-ratio:16/10}
.cpanel figcaption{position:absolute;left:9px;bottom:8px;font-family:Geistmono,monospace;font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:#fff;background:rgba(12,11,10,.5);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);border-radius:5px;padding:4px 7px 3px}
.cp-facts{margin-top:10px}
.cp-facts .lrow{border-color:var(--od-5);padding:13px 0}
.cp-facts .lrow:last-child{border-bottom:0}
.cp-facts .lrow .n{color:var(--n50);font-size:15.5px}
.cp-facts .lrow .d{color:var(--od-3);font-size:13.5px}
.cp-facts .lrow .k{color:var(--od-4)}
.cp-logos{border-top:1px solid var(--od-5);padding-top:18px;margin-top:2px}
.cp-logos .small{color:var(--od-3);display:block;margin-bottom:14px}
.cp-logos .logos{display:flex;flex-wrap:wrap;gap:16px 24px;align-items:center}
.cp-logos .logos img{filter:grayscale(1) brightness(0) invert(1);opacity:.62;width:auto;background:none;border-radius:0;transform:scale(.82);transform-origin:left center}
.cp-logos .logos .lg-epic{filter:grayscale(1) invert(1);opacity:.62}
.cp-facts .lrow{margin-inline:0;padding-inline:0}

/* v124 logo strip: out of the dark panel, full width under the form and panel, same look as the Home row */
.cf-logos{margin-top:64px;padding-top:28px;border-top:1px solid var(--n200)}
.cf-logos .small{display:block;margin-bottom:20px;color:var(--n500)}
@media (max-width:860px){.cf-logos{margin-top:40px}}
