/* Layout stays stationary. Only deliberately selected inner layers move. */
html{scroll-behavior:auto;overflow-x:clip}
.product-stage,.live-scene{perspective:none!important;will-change:auto!important}
.product-stage .scene-chat-panel{backface-visibility:hidden;transition:none!important;will-change:transform}
.vsection:has(.chat-browser){overflow:visible!important}
.product-stage>.signal-bloom{z-index:0;inset:-7% -9%!important;overflow:visible;contain:layout style;pointer-events:none}
.product-stage>:not(.signal-bloom){position:relative;z-index:1}
.signal-bloom i{left:0!important;top:0!important;transform:none!important;width:100%!important;height:100%!important}
.signal-bloom i:nth-child(2){rotate:28deg;scale:.93}
.signal-bloom i:nth-child(3){rotate:75deg;scale:.85}
.signal-bloom i:nth-child(4){rotate:140deg;scale:.97}
.signal-bloom i:nth-child(5){rotate:210deg;scale:.88}
.signal-bloom{contain:paint;backface-visibility:hidden}
.story-canvas .signal-bloom{z-index:-1}
.scene-chat-panel .scene-feed{overflow-anchor:none;scroll-behavior:auto}
.demo-site,.scene-feed{overscroll-behavior:auto!important}
@media(prefers-reduced-motion:reduce){.scene-chat-panel{transform:none!important;opacity:1!important;visibility:visible!important;will-change:auto!important}}

@keyframes signal-breathe{0%{scale:.94;opacity:.38}100%{scale:1.14;opacity:.88}}
.signal-bloom i{animation:signal-breathe 11s ease-in-out infinite alternate;animation-play-state:paused;transform-origin:50% 50%}
.signal-bloom.motion-active i{animation-play-state:running}
.signal-bloom i:nth-child(2){animation-delay:-2.75s}
.signal-bloom i:nth-child(3){animation-delay:-5.5s}
.signal-bloom i:nth-child(4){animation-delay:-8.25s}
.signal-bloom i:nth-child(5){animation-delay:-6s}
@media(prefers-reduced-motion:reduce){.signal-bloom i{animation:none!important}}

/* Consistent independent breathing light plus reversible scroll-turns for every product visual. */
@keyframes product-light-breathe{0%{scale:.94;opacity:.32}100%{scale:1.1;opacity:.8}}
@keyframes voice-aurora-breathe{0%{opacity:.46;scale:.94}100%{opacity:.9;scale:1.08}}
.voice-stage{isolation:isolate;transform-origin:50% 50%;will-change:transform}
.voice-stage:before{z-index:0;box-shadow:0 0 75px 12px #3178ff32,0 0 140px 20px #f0bb5030;animation:product-light-breathe 9s ease-in-out infinite alternate}
.voice-stage:after{content:"";position:absolute;z-index:0;inset:3% -7%;border-radius:48%;pointer-events:none;background:radial-gradient(ellipse at 30% 38%,#3488ff72,transparent 43%),radial-gradient(ellipse at 72% 62%,#e8b94d58,transparent 44%),radial-gradient(ellipse at 50% 50%,#8b6ce33d,transparent 60%);mix-blend-mode:screen;animation:voice-aurora-breathe 8s ease-in-out infinite alternate}
.voice-device,.calendar-preview{z-index:1}
.scene-glow,.signal-bloom,.voice-stage,.screen-frame,.live-scene,.blueprint-scene .blueprint-object,.console-scene{transform-origin:50% 50%;backface-visibility:hidden}
.scene-glow{animation:product-light-breathe 10s ease-in-out infinite alternate;will-change:scale,opacity}
.signal-bloom{animation:none!important}
.signal-bloom i{filter:none!important}
.dark-section .signal-bloom i{opacity:.58}
.voice-bars i{transform-origin:50% 100%;animation:voice-bar-breathe .72s ease-in-out infinite alternate}
.voice-bars i:nth-child(2n){animation-delay:-.33s}.voice-bars i:nth-child(3n){animation-delay:-.51s}
@keyframes voice-bar-breathe{from{scale:1 .52}to{scale:1 1.18}}
@media(prefers-reduced-motion:reduce){.voice-stage:before,.voice-stage:after,.scene-glow,.signal-bloom,.voice-bars i{animation-duration:24s!important;animation-timing-function:linear!important}.voice-stage:after{opacity:.6}}
/* The device frames must NOT breathe. They contain real text and 1px borders, so an
   infinite scale re-rasterizes glyphs every frame (visible shimmer/wobble) and fights the
   GSAP scroll transforms written to .live-scene. Ambient glows below still breathe —
   those are soft blurs where scaling is invisible and costs nothing. */
.live-scene,.screen-frame{animation:none;will-change:auto}

@media(prefers-reduced-motion:reduce){
 .voice-stage,.scene-glow,.screen-frame,.live-scene,.blueprint-scene .blueprint-object,.console-scene{animation:none!important;transform:none!important}
}

/* Keep the paint splashes in front of the section backdrop and behind devices. */
.product-stage{isolation:isolate}
.product-stage>.signal-bloom{z-index:0!important}
.product-stage>:not(.signal-bloom){position:relative;z-index:1}
/* Keep each splatter centered inside its painted area; five inset copies make a boxy frame. */
.product-stage>.signal-bloom i{left:50%!important;top:50%!important;width:92%!important;height:86%!important;translate:-50% -50%!important;transform-box:fill-box}
.product-stage>.signal-bloom i:nth-child(2){rotate:28deg}
.product-stage>.signal-bloom i:nth-child(3){rotate:75deg}
.product-stage>.signal-bloom i:nth-child(4){rotate:140deg}
.product-stage>.signal-bloom i:nth-child(5){rotate:210deg}
/* Do not clip the turning splashes at a rectangular containment edge. */
.product-stage>.signal-bloom{contain:layout style!important}
.product-stage>.signal-bloom i{opacity:.72}

/* ---- Reveals (fail-safe) -------------------------------------------------
   Copy is fully visible by default. It is only pre-hidden when <html> carries
   .js-reveal, which motion-runtime.js adds at runtime -- so if the script is
   blocked, errors, or is slow, the text still renders instead of being stranded
   invisible. Transform+opacity only, so this is compositor-cheap. */
.reveal{opacity:1;transform:none}
html.js-reveal .reveal{opacity:0;transform:translateY(14px);
  transition:opacity .45s cubic-bezier(.22,.61,.36,1),transform .45s cubic-bezier(.22,.61,.36,1)}
html.js-reveal .reveal.is-in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){
  html.js-reveal .reveal{opacity:1!important;transform:none!important;transition:none!important}
}
