/* ============================================================
   JARA Voxbridge — CINEMATIC POLISH LAYER  (voxbridge.html ONLY)
   ------------------------------------------------------------
   Loaded AFTER styles.css. This file never rewrites the page's
   premium language — it adds a depth/light layer on top of it.

   Three hard rules baked into every rule below:
   1) ZERO layout impact. Every new visual is either a pseudo-
      element or an absolutely-positioned decoration, so nothing
      here can move a box → CLS stays 0.
   2) Transform / opacity only. No animated width, height, top,
      left, box-shadow or filter (one-shot filters are fine, but
      nothing filtered is animated) → compositor-friendly 60fps.
   3) prefers-reduced-motion: reduce turns EVERY new animation
      and transition off and freezes each effect on a single,
      still-legible frame (see the block at the bottom).

   Colour discipline: everything reads the live theme tokens
   (--t-accent* / --t-border / --t-bg-*), so the layer recolors
   with the product accent and with light/dark. The only literal
   is JARA gold #E7C887 / rgb(231,200,135), used exactly where
   the brand crest is intended (progress line, CTA sweep, seams).

   Driver: voxbridge-cinema.js (GSAP + ScrollTrigger from vendor/).
   Everything degrades to a static, complete page without it.
   CSP: self-contained, no external URL of any kind.
   ============================================================ */

/* ---------- 0. Shared keyframes ---------- */
@keyframes voxSpin      { to { rotate: 360deg; } }
@keyframes voxAurora {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(12%, 5%, 0) scale(1.13); }
  100% { transform: translate3d(31%, -4%, 0) scale(1.02); }
}
@keyframes voxDrift {
  0%   { opacity: 0;   transform: translate3d(0, 30px, 0) scale(.90); }
  16%  { opacity: .95; transform: translate3d(0, 6px, 0)  scale(1); }
  68%  { opacity: .85; transform: translate3d(0, -28px, 0) scale(1); }
  100% { opacity: 0;   transform: translate3d(0, -64px, 0) scale(.94); }
}
@keyframes voxSheen {
  0%   { opacity: 0; transform: translate3d(-120%, 0, 0); }
  14%  { opacity: 1; }
  100% { opacity: 0; transform: translate3d(120%, 0, 0); }
}
@keyframes voxShine {
  0%, 62%   { background-position: 165% 0; }
  93%, 100% { background-position: -70% 0; }
}
@keyframes voxWaveBreathe {
  0%   { transform: translate3d(-2%, 0, 0) scale(1.02); }
  100% { transform: translate3d(2%, -10px, 0) scale(1.07); }
}

/* ---------- 1. Gold scroll-progress hairline ----------
   Fixed, 2px, above the sticky nav. JS writes scaleX only. */
.vox-progress {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 2px;
  z-index: 60;
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: 0 50%;
  will-change: transform;
  opacity: .92;
  background: linear-gradient(90deg,
    rgba(var(--t-accent-rgb), 0) 0%,
    rgba(var(--t-accent-rgb), .60) 24%,
    rgba(231, 200, 135, .95) 66%,
    #E7C887 100%);
}
[dir="rtl"] .vox-progress { transform-origin: 100% 50%; }

/* ---------- 2. Nav gains contrast once the page starts moving ---------- */
.glass-nav {
  transition: backdrop-filter .45s ease, -webkit-backdrop-filter .45s ease,
              box-shadow .45s ease, border-color .45s ease;
}
body.vox-scrolled .nav { border-color: rgba(var(--t-accent-bright-rgb), .30); }
body.vox-scrolled .glass-nav {
  -webkit-backdrop-filter: blur(30px) saturate(1.3);
  backdrop-filter: blur(30px) saturate(1.3);
  box-shadow: 0 24px 74px var(--t-shadow-deep),
              inset 0 1px 0 rgba(var(--t-accent-bright-rgb), .16);
}

/* ---------- 3. HERO ---------- */
/* 3a. Headline word-stagger. GSAP owns opacity/transform on .vox-w
   ONLY — never on the <h1> itself, which cinematic.js §2b already
   scrubs. inline-block keeps normal line wrapping, so no CLS. */
.detail-hero h1 .vox-w { display: inline-block; will-change: transform, opacity; }

/* 3b. Very slow aurora drift behind the hero copy.
   .detail-hero already has position:relative + isolation:isolate +
   overflow:clip and only uses ::before, so ::after is free and the
   drift can never bleed into page-level horizontal scroll. */
.detail-hero::after {
  content: "";
  position: absolute;
  z-index: -1;
  pointer-events: none;
  left: -12%;
  top: -16%;
  width: 62%;
  aspect-ratio: 1.45;
  border-radius: 50%;
  background: radial-gradient(closest-side,
    rgba(var(--t-accent-rgb), .17),
    rgba(var(--t-accent-rgb), .05) 55%,
    transparent 78%);
  will-change: transform;
  animation: voxAurora 36s ease-in-out infinite alternate;
}

/* 3c. Light sweep circling the lamp. Ring is mask-carved, so it is
   only rendered where masking actually works — a UA without mask
   support gets no element at all instead of a filled disc. */
.detail-hero__visual { position: relative; isolation: isolate; }
@supports ((-webkit-mask-image: radial-gradient(#000, #000)) or (mask-image: radial-gradient(#000, #000))) {
  /* Anchored to .giant-icon, not to the column: the lamp plate is a square
     760x760 PNG, so a circle sized off the icon's own box orbits it cleanly at
     any breakpoint. Sized off the column instead, the ring came out SMALLER
     than the lamp and cut straight through it. */
  .giant-icon::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 116%;
    aspect-ratio: 1;
    translate: -50% -50%;          /* kept OFF `transform` so the sweep can own rotate */
    border-radius: 50%;
    z-index: -1;
    pointer-events: none;
    background: conic-gradient(from 0deg,
      rgba(var(--t-accent-bright-rgb), 0)   0deg,
      rgba(var(--t-accent-bright-rgb), .55) 40deg,
      rgba(231, 200, 135, .78)              66deg,
      rgba(var(--t-accent-bright-rgb), 0)  126deg,
      rgba(var(--t-accent-bright-rgb), 0)  360deg);
    -webkit-mask: radial-gradient(closest-side, transparent 70%, #000 74%, #000 79%, transparent 83%);
            mask: radial-gradient(closest-side, transparent 70%, #000 74%, #000 79%, transparent 83%);
    will-change: transform;
    animation: voxSpin 11s linear infinite;
    opacity: .85;
  }
}

/* 3d. Shimmer across the Allura "voxbridge" accent. The overlay is a
   second copy of the word, gradient-clipped to the glyphs, so the
   base colour is untouched. It inherits the handwrite clip-path, so
   it only becomes visible once the pen finishes writing. */
.detail-lockup .script-label__text { position: relative; }
.detail-lockup .script-label__text::after {
  content: "voxbridge";            /* product name — never translated (data-text is hardcoded too) */
  position: absolute;
  inset: 0;
  white-space: nowrap;
  pointer-events: none;
  background-image: linear-gradient(100deg,
    transparent 40%,
    rgba(255, 255, 255, .92) 48%,
    #E7C887 54%,
    transparent 64%);
  background-size: 250% 100%;
  background-position: 165% 0;
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  animation: voxShine 6.5s ease-in-out 2.6s infinite;
}
/* The overlay PAINTS the glyphs, it does not add light to them — so a white
   highlight on the light theme would blank the word out for the length of the
   sweep. Light gets a darker sweep instead: same gesture, still legible. */
[data-theme="light"] .detail-lockup .script-label__text::after {
  background-image: linear-gradient(100deg,
    transparent 40%,
    rgba(var(--t-accent-rgb), .95) 48%,
    #b8924c 54%,
    transparent 64%);
}

/* ---------- 4. Section seams ----------
   A hairline of light stitches each scene to the next; it draws
   itself open as the section arrives. Decorative only — nothing
   readable is ever gated behind it. */
.detail-section::before,
.detail-final::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  pointer-events: none;
  background: linear-gradient(90deg,
    transparent,
    rgba(var(--t-accent-bright-rgb), .30) 34%,
    rgba(231, 200, 135, .26) 52%,
    transparent);
  opacity: 0;
  transform: scaleX(.35);
  transition: opacity .9s ease, transform 1.25s cubic-bezier(.2, .8, .25, 1);
}
.detail-section.vox-seam::before,
.detail-final.vox-seam::after { opacity: 1; transform: scaleX(1); }

/* ---------- 5. LIVE DEMO — the spotlight scene ---------- */
#live-demo { isolation: isolate; }
/* Named children only. `#live-demo > *` would win on specificity (1,0,0) over
   .vox-scene's own position:absolute (0,1,0) and force the decor layer back
   into flow — where, with only absolute children, it collapses to height 0 and
   its overflow:hidden clips every chip out of existence. */
#live-demo > .detail-heading,
#live-demo > .vox-demo-stage { position: relative; z-index: 1; }

.vox-scene {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

/* 5a. Slowly rotating conic aurora on the section floor.
   No filter: the conic's own soft stops plus the radial mask do the
   blurring, so rotating it costs one composited layer, not a
   full-surface blur repaint every frame. */
@supports ((-webkit-mask-image: radial-gradient(#000, #000)) or (mask-image: radial-gradient(#000, #000))) {
  .vox-scene__conic {
    position: absolute;
    left: 50%;
    top: 54%;
    width: min(150%, 1240px);
    aspect-ratio: 1;
    translate: -50% -50%;
    border-radius: 50%;
    /* Single-hue ramp on purpose. An accent→gold conic has to interpolate
       across the whole hue wheel between stops, and on this page (blue accent)
       the in-between angles land on a muddy teal. Depth here comes from alpha,
       not from a second hue; gold stays reserved for the crest moments. */
    background: conic-gradient(from 0deg,
      rgba(var(--t-accent-rgb), .18),
      rgba(var(--t-accent-bright-rgb), .09) 92deg,
      rgba(var(--t-accent-rgb), .18) 184deg,
      rgba(var(--t-accent-bright-rgb), .06) 276deg,
      rgba(var(--t-accent-rgb), .18) 360deg);
    -webkit-mask: radial-gradient(closest-side, #000 10%, rgba(0, 0, 0, .5) 46%, transparent 74%);
            mask: radial-gradient(closest-side, #000 10%, rgba(0, 0, 0, .5) 46%, transparent 74%);
    will-change: transform;
    animation: voxSpin 52s linear infinite;
  }
}

/* 5b. Language chips drifting up the gutters — the conference story,
   told in pure CSS. Gutters only exist on wide viewports, so below
   1180px they are removed entirely (never overlap the phone). */
.vox-chip {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .16em;
  white-space: nowrap;
  color: var(--t-accent-ink);
  border: 1px solid rgba(var(--t-accent-rgb), .30);
  background: linear-gradient(180deg, var(--t-bg-glass-1), var(--t-bg-glass-2));
  box-shadow: 0 10px 26px rgba(0, 0, 0, .22);
  opacity: 0;
  will-change: transform, opacity;
  animation: voxDrift 18s ease-in-out infinite;
}
.vox-chip b { font-size: 14px; letter-spacing: 0; font-weight: 400; }
.vox-chip:nth-child(1) { left: 3%;  top: 62%; animation-delay: 0s; }
.vox-chip:nth-child(2) { left: 8%;  top: 34%; animation-delay: 3.4s; }
.vox-chip:nth-child(3) { left: 1.5%;top: 16%; animation-delay: 8.6s; }
.vox-chip:nth-child(4) { right: 3%; top: 58%; animation-delay: 1.7s; }
.vox-chip:nth-child(5) { right: 7%; top: 30%; animation-delay: 6.1s; }
.vox-chip:nth-child(6) { right: 2%; top: 13%; animation-delay: 11.2s; }
@media (max-width: 1179px) { .vox-chip { display: none; } }

/* 5c. Phone frame bloom. A separate radial layer behind the frame,
   so the "glow" is an opacity/scale tween on its own compositor
   layer instead of a per-frame box-shadow repaint on a 900px card. */
.vox-demo-stage { position: relative; max-width: 900px; margin: 0 auto; will-change: transform; }
.vox-demo-bloom {
  position: absolute;
  inset: -13%;
  z-index: 0;
  border-radius: 40px;
  pointer-events: none;
  background: radial-gradient(58% 52% at 50% 50%,
    rgba(var(--t-accent-rgb), .34),
    rgba(var(--t-accent-rgb), .11) 48%,
    transparent 74%);
  opacity: 0;
  will-change: opacity, transform;
}
.vox-demo-stage .demo-frame { position: relative; z-index: 1; }

/* Placeholder shown until the 760KB demo document is mounted, so the
   frame is never an empty black rectangle. It OVERLAYS the iframe
   instead of replacing it: the <iframe> keeps its full box from the
   first paint, so (a) nothing shifts when the src lands and (b) the
   demo's own fitPhone() measures a real viewport on its load. */
.demo-frame__wait {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: grid;
  place-items: center;
  background: #050608;
  color: var(--t-text-faded);
  font-size: 12px;
  letter-spacing: .3em;
  text-transform: uppercase;
}
.demo-frame__wait i {
  display: block;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .5);
  border-top-color: transparent;
  animation: voxSpin 1.1s linear infinite;
}
.demo-frame.is-mounted .demo-frame__wait { display: none; }

/* ---------- 6. CAPABILITIES ---------- */
/* 6a. Specular glare that tracks the pointer. Deliberately NOT a 3D
   tilt: cinematic.js §2c pins #capabilities and drives .cap-mock's
   transform (xPercent/scale) from a scrubbed timeline, so any
   transform written here would be overwritten mid-scrub. A masked
   highlight + an inner-layer parallax give the same "solid object
   catching light" read without ever touching GSAP's channel. */
.cap-mock { --vx-gx: 50%; --vx-gy: 0%; }
.cap-mock::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(34% 34% at var(--vx-gx) var(--vx-gy),
    rgba(255, 255, 255, .17),
    rgba(var(--t-accent-bright-rgb), .11) 44%,
    transparent 72%);
  opacity: 0;
  transition: opacity .45s ease;
}
.cap-mock.vox-glare::after { opacity: 1; }
/* Inner layer lags the pointer → parallax depth inside the card. */
.cap-mock__screen {
  transform: translate3d(var(--vx-px, 0px), var(--vx-py, 0px), 0);
  transition: transform .35s cubic-bezier(.2, .8, .25, 1);
}

/* 6b. Real captured footage inside the mock. The clips are portrait
   phone recordings (620x1276), so they are inset as a device rather
   than stretched across a 4:3 card. The device sits on the TRAILING
   edge and the leading side carries a live vignette (§6c) — centred,
   the phone left two dead columns of empty card, which is exactly what
   read as "an empty panel".

   The 38% reserve is derived, not guessed: film width / screen width =
   0.486·(H-59) / (1.333H-32), which stays between .32 and .34 at every
   card height, because both terms scale with the same H and the card
   ratio is locked at 4/3. 38% = the film plus a gutter. */
.cap-mock--film .cap-mock__screen { position: relative; }
.cap-mock--film .cap-vig { padding-inline-end: 38%; }
/* A real still (cap-2 voice library, cap-4 summary) sits in the same device
   inset as the films; it is an <img>, so §8 of the driver never tries to
   play() it — hence its own class name, shared rules. */
.cap-mock__film,
.cap-mock__still {
  width: auto;               /* the <img> carries width/height attributes for CLS; aspect-ratio needs one axis auto */
  position: absolute;
  inset-inline-end: 0;
  top: 50%;
  translate: 0 -50%;
  height: 100%;
  aspect-ratio: 620 / 1276;
  z-index: 1;
  border-radius: 18px;
  object-fit: cover;
  background: #05070c;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .38);
  box-shadow: 0 24px 54px rgba(0, 0, 0, .48), 0 0 0 5px rgba(0, 0, 0, .34);
}

/* ---------- 6c. THE FOUR PANELS, ALIVE ----------
   Each capability panel now performs the thing it claims. All four are
   pure CSS on top of the existing .cap-mock chrome — no JS, no assets,
   no new i18n keys (the only text is language endonyms, one fixed EN→TR
   translation sample, and a timestamp).

   ONE RULE governs every vignette: the element's BASE style is the
   FINISHED frame, and the keyframes reach back to the empty state at 0%.
   So `animation: none` (reduced motion) leaves a complete, legible panel
   instead of a blank one — with no separate still-frame styling to keep
   in sync. */
.cap-vig {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
}

/* Off-screen scenes idle. Between them these panels run ~70 infinite
   animations; left running while the visitor is three screens away they
   burn frame budget for nothing (and on a constrained renderer that
   showed up as dropped frames). The polarity matters: the default is
   RUNNING and JS adds .vox-idle when a section leaves the viewport — so
   with JS off nothing is ever paused mid-keyframe, and the panels still
   play. animation-play-state only suspends the clock; it never resets a
   position, so returning to the section resumes exactly where it was. */
#capabilities.vox-idle .cap-vig *,
#capabilities.vox-idle .cap-vig *::before,
#capabilities.vox-idle .cap-vig *::after,
#live-demo.vox-idle .vox-chip,
#live-demo.vox-idle .vox-scene__conic,
.detail-final.vox-idle::before,
.detail-final.vox-idle .vox-final-wave { animation-play-state: paused; }

/* --- 6c-1 · Capability 01: the caption writing itself --- */
.cap-vig--caption {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: clamp(8px, 3%, 16px);
}
.cv-line { display: flex; align-items: flex-start; gap: 9px; min-width: 0; }
.cv-tag {
  flex: 0 0 auto;
  margin-block-start: 2px;
  padding: 3px 8px;
  border-radius: 7px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .14em;
  color: var(--t-accent-ink);
  border: 1px solid var(--t-border);
  background: rgba(var(--t-accent-rgb), .08);
}
.cv-line--tgt .cv-tag {
  color: #E7C887;
  border-color: rgba(231, 200, 135, .45);
  background: rgba(231, 200, 135, .10);
}
.cv-words { display: flex; flex-wrap: wrap; gap: 3px 6px; min-width: 0; }
.cv-words i {
  display: inline-block;
  font-style: normal;
  font-size: clamp(11px, 1.05vw, 15px);
  line-height: 1.4;
  white-space: nowrap;
  color: var(--t-text-soft);
  animation: voxCapWord 9s ease-out infinite;
}
.cv-line--tgt .cv-words i { color: var(--t-text); }
.cv-line--src .cv-words i:nth-child(1) { animation-delay: .15s; }
.cv-line--src .cv-words i:nth-child(2) { animation-delay: .50s; }
.cv-line--src .cv-words i:nth-child(3) { animation-delay: .85s; }
.cv-line--src .cv-words i:nth-child(4) { animation-delay: 1.2s; }
.cv-line--tgt .cv-words i:nth-child(1) { animation-delay: 3.1s; }
.cv-line--tgt .cv-words i:nth-child(2) { animation-delay: 3.5s; }
@keyframes voxCapWord {
  0%, 3%    { opacity: 0; transform: translateY(5px); }
  8%, 88%   { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
.cv-bridge {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 26px;
}
.cv-bridge b {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 400;
  color: var(--t-accent-bright);
  border: 1px solid rgba(var(--t-accent-bright-rgb), .5);
  background: rgba(var(--t-accent-rgb), .10);
  animation: voxBridgePulse 9s ease-in-out infinite;
}
.cv-beam {
  position: absolute;
  left: 50%;
  top: 62%;
  width: 1px;
  height: 44%;
  translate: -50% 0;
  transform: scaleY(0);
  transform-origin: 50% 0;
  opacity: 0;
  background: linear-gradient(180deg, rgba(var(--t-accent-bright-rgb), .9), rgba(231, 200, 135, 0));
  animation: voxBeam 9s ease-out infinite;
}
@keyframes voxBridgePulse {
  0%, 24%   { box-shadow: 0 0 0 0 rgba(var(--t-accent-bright-rgb), 0); }
  30%       { box-shadow: 0 0 0 7px rgba(var(--t-accent-bright-rgb), .16); }
  38%, 100% { box-shadow: 0 0 0 0 rgba(var(--t-accent-bright-rgb), 0); }
}
@keyframes voxBeam {
  0%, 26%   { opacity: 0; transform: scaleY(0); }
  30%       { opacity: 1; transform: scaleY(1); }
  40%       { opacity: 0; transform: scaleY(1); }
  41%, 100% { opacity: 0; transform: scaleY(0); }
}

/* --- 6c-2 · Capability 02: the living language constellation --- */
/* Beside the voice-library still the constellation keeps the leading 62%
   as a WIDTH (not padding): its rings are absolutely centred, and a padding
   box would have put the core under the phone. Radius shrinks to match. */
.cap-mock--film .cap-vig--constel { padding-inline-end: 0; width: 62%; --cv-ro: clamp(56px, min(8.6vw, 12vh), 112px); }
.cap-vig--constel {
  /* Radius tracks BOTH axes: in the pinned stage the card is sized off
     viewport height, in the stacked fallback off width. min() of the two
     keeps the orbit inside the card in either regime. */
  --cv-ro: clamp(70px, min(12.5vw, 16.5vh), 148px);
  --cv-ri: calc(var(--cv-ro) * .58);
}
/* The core is the light, not the object. It used to BE the blue disc; now it
   is the halo the lamp sits in, so the gradient is pulled back (the old .85
   centre would have burned straight through the lamp's silhouette) and the
   lamp carries the shape. The chips' beams still terminate here, so the glow
   has to stay bright enough to read as their destination. */
.cv-core {
  position: absolute;
  left: 50%;
  top: 50%;
  width: calc(var(--cv-ro) * .42);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: radial-gradient(circle,
    rgba(var(--t-accent-bright-rgb), .42),
    rgba(var(--t-accent-rgb), .22) 56%,
    transparent 76%);
}
/* Real asset, never a hand-drawn path: assets/lamps/lamp-voxbridge.png, the
   same lamp the app ships. Oversized past the halo because at this scale the
   spout and handle are what make it readable as a lamp at all. The two
   drop-shadows are the "same light" the halo is made of — a tight accent
   rim plus a wide bloom — so the lamp reads as lit BY the constellation
   rather than pasted on top of it. */
.cv-lamp {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 168%;
  height: auto;
  translate: -50% -50%;
  pointer-events: none;
  filter:
    drop-shadow(0 0 6px rgba(var(--t-accent-bright-rgb), .85))
    drop-shadow(0 0 22px rgba(var(--t-accent-rgb), .45));
  animation: voxLampBreathe 6.2s ease-in-out infinite;
}
@keyframes voxLampBreathe {
  0%, 100% { opacity: .92; }
  50%      { opacity: 1; }
}
/* Label crossfade for the language rotator (voxbridge-cinema.js §11). Only
   the text swaps — the chip, its beam and its light-up keep running, so the
   ring never stutters. */
.cv-chip i { transition: opacity .34s ease; }
.cv-chip.is-swapping i { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .cv-lamp { animation: none; }
  .cv-chip i { transition: none; }
}
.cv-core i {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .55);
  opacity: 0;
  animation: voxCorePing 3.4s ease-out infinite;
}
.cv-core i:nth-child(2) { animation-delay: 1.7s; }
@keyframes voxCorePing {
  0%   { opacity: .65; transform: scale(1); }
  100% { opacity: 0;   transform: scale(2.7); }
}
.cv-ring { position: absolute; inset: 0; pointer-events: none; will-change: transform; }
.cv-ring--out { animation: voxSpin 46s linear infinite; }
.cv-ring--in  { animation: voxSpinRev 36s linear infinite; }
@keyframes voxSpinRev { to { rotate: -360deg; } }
/* Placement: rotate to the chip's angle, then push out along the local
   -Y axis. That leaves local +Y pointing straight back at the core,
   which is the axis the ::before beam rides on. */
.cv-chip {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) rotate(var(--a, 0deg)) translateY(calc(-1 * var(--r)));
}
.cv-ring--out .cv-chip { --r: var(--cv-ro); }
.cv-ring--in  .cv-chip { --r: var(--cv-ri); }
/* The label cancels BOTH rotations: `transform` undoes the chip's own
   angle, the independent `rotate` property undoes the ring's spin (equal
   duration + linear timing, so it cancels exactly, frame for frame). */
.cv-chip i {
  display: inline-block;
  padding: 4px 9px;
  border-radius: 999px;
  font-style: normal;
  font-size: clamp(8px, .72vw, 11px);
  font-weight: 600;
  letter-spacing: .02em;
  white-space: nowrap;
  color: var(--t-accent-ink);
  border: 1px solid rgba(var(--t-accent-rgb), .30);
  background: linear-gradient(180deg, var(--t-bg-glass-1), var(--t-bg-glass-2));
  box-shadow: 0 6px 16px rgba(0, 0, 0, .20);
  transform: rotate(calc(-1 * var(--a, 0deg)));
  /* Allura and the display face are Latin-only — CJK / Arabic / Devanagari
     / Vietnamese fall back to the system stack, same as the hero rotator. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
.cv-ring--out .cv-chip i { animation: voxSpinRev 46s linear infinite; }
.cv-ring--in  .cv-chip i { animation: voxSpin 36s linear infinite; }
.cv-chip::before {                      /* beam back to the core */
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 1px;
  height: calc(var(--r) - 16px);
  translate: -50% 0;
  opacity: 0;
  background: linear-gradient(180deg, rgba(var(--t-accent-bright-rgb), .8), rgba(var(--t-accent-bright-rgb), 0));
  animation: voxChipBeam 11s ease-out infinite;
}
.cv-chip::after {                       /* the chip lighting up */
  content: "";
  position: absolute;
  inset: -7px;
  border-radius: 999px;
  opacity: 0;
  background: radial-gradient(circle, rgba(var(--t-accent-bright-rgb), .40), transparent 70%);
  animation: voxChipLit 11s ease-in-out infinite;
}
.cv-chip::before, .cv-chip::after { animation-delay: var(--d, 0s); }
@keyframes voxChipLit  { 0%, 88%, 100% { opacity: 0; } 94% { opacity: 1; } }
@keyframes voxChipBeam { 0%, 90%, 100% { opacity: 0; } 95% { opacity: .9; } }
/* angle + light-up phase, one rule per chip */
.cv-ring--out .cv-chip:nth-child(1) { --a:   0deg; --d: 0.0s; }
.cv-ring--out .cv-chip:nth-child(2) { --a:  45deg; --d: 1.3s; }
.cv-ring--out .cv-chip:nth-child(3) { --a:  90deg; --d: 2.6s; }
.cv-ring--out .cv-chip:nth-child(4) { --a: 135deg; --d: 3.9s; }
.cv-ring--out .cv-chip:nth-child(5) { --a: 180deg; --d: 5.2s; }
.cv-ring--out .cv-chip:nth-child(6) { --a: 225deg; --d: 6.5s; }
.cv-ring--out .cv-chip:nth-child(7) { --a: 270deg; --d: 7.8s; }
.cv-ring--out .cv-chip:nth-child(8) { --a: 315deg; --d: 9.1s; }
.cv-ring--in  .cv-chip:nth-child(1) { --a:  30deg; --d: 0.7s; }
.cv-ring--in  .cv-chip:nth-child(2) { --a:  90deg; --d: 2.0s; }
.cv-ring--in  .cv-chip:nth-child(3) { --a: 150deg; --d: 3.3s; }
.cv-ring--in  .cv-chip:nth-child(4) { --a: 210deg; --d: 4.6s; }
.cv-ring--in  .cv-chip:nth-child(5) { --a: 270deg; --d: 5.9s; }
.cv-ring--in  .cv-chip:nth-child(6) { --a: 330deg; --d: 7.2s; }

/* --- 6c-3 · Capability 03: three rooms, drawn by shape --- */
.cap-vig--rooms {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  align-items: end;
  gap: clamp(4px, 2%, 10px);   /* four columns since Live joined (2026-09-06): tighter gutters so "Face to Face" stays on one line */
}
.cv-room {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(6px, 2.4%, 12px);
  min-width: 0;
  animation: voxRoom 9s ease-in-out infinite;
}
.cv-room--conf    { animation-delay: -2.25s; }
.cv-room--whisper { animation-delay: -4.5s; }
.cv-room--live    { animation-delay: -6.75s; }
/* base = lit; each room dims while the other three take the floor */
/* Live (4th room, 2026-09-06): two people again, but the link carries both ways at once
   and a gold live-dot breathes above it — hands-free, nothing to tap. */
.cv-room--live .cv-node { left: 6%; top: 50%; translate: 0 -50%; }
.cv-room--live .cv-node--b { left: auto; right: 6%; }
.cv-room--live .cv-livedot { position: absolute; left: 50%; top: 18%; width: 6px; height: 6px; border-radius: 50%; translate: -50% 0; background: var(--t-accent-bright); box-shadow: 0 0 8px rgba(var(--t-accent-bright-rgb), .9); animation: cvLivePulse 2.4s ease-in-out infinite; }
[dir="rtl"] .cv-room--live .cv-node { left: auto; right: 6%; }
[dir="rtl"] .cv-room--live .cv-node--b { right: auto; left: 6%; }
@keyframes voxRoom { 0%, 30% { opacity: 1; } 40%, 90% { opacity: .36; } 100% { opacity: 1; } }
.cv-room em {
  font-style: normal;
  font-size: clamp(8px, 1.6vh, 10px);
  line-height: 1.2;
  letter-spacing: .05em;
  white-space: nowrap;
  text-transform: uppercase;
  text-align: center;
  color: var(--t-text-muted);
}
.cv-room__art {
  position: relative;
  width: 100%;
  aspect-ratio: 1 / 0.82;
  max-height: clamp(64px, 16vh, 118px);
}
.cv-node {
  position: absolute;
  width: clamp(16px, 4vh, 24px);
  aspect-ratio: 1;
  border-radius: 50%;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .7);
  background: radial-gradient(circle at 40% 35%, rgba(var(--t-accent-bright-rgb), .55), rgba(var(--t-accent-rgb), .18) 70%);
  box-shadow: 0 0 14px rgba(var(--t-accent-rgb), .35);
}
/* Face to Face: two nodes, one line, both directions */
.cv-room--f2f .cv-node { left: 6%; top: 50%; translate: 0 -50%; }
.cv-room--f2f .cv-node--b { left: auto; right: 6%; }
.cv-link {
  position: absolute;
  left: 22%; right: 22%; top: 50%;
  height: 1px;
  background: linear-gradient(90deg, rgba(var(--t-accent-bright-rgb), .2), rgba(var(--t-accent-bright-rgb), .85), rgba(var(--t-accent-bright-rgb), .2));
}
.cv-link::before, .cv-link::after {
  content: ""; position: absolute; top: 50%; width: 6px; height: 6px;
  border-top: 1px solid rgba(var(--t-accent-bright-rgb), .9); border-right: 1px solid rgba(var(--t-accent-bright-rgb), .9);
}
.cv-link::before { left: 0;  transform: translateY(-50%) rotate(-135deg); }
.cv-link::after  { right: 0; transform: translateY(-50%) rotate(45deg); }
/* Conference: a host, a ring of listeners, a six-dot room code */
.cv-room--conf .cv-node--host { left: 50%; top: 42%; translate: -50% -50%; width: clamp(20px, 5vh, 30px); }
.cv-orbit { position: absolute; left: 50%; top: 42%; width: 0; height: 0; }
.cv-orbit i {
  position: absolute; left: 0; top: 0;
  width: clamp(8px, 2.2vh, 12px); aspect-ratio: 1; border-radius: 50%;
  background: rgba(var(--t-accent-bright-rgb), .7);
  box-shadow: 0 0 8px rgba(var(--t-accent-rgb), .45);
  transform: rotate(var(--a)) translate(clamp(26px, 6.4vh, 44px)) translate(-50%, -50%);
}
.cv-orbit i:nth-child(1) { --a: -90deg; } .cv-orbit i:nth-child(2) { --a: -18deg; } .cv-orbit i:nth-child(3) { --a: 54deg; }
.cv-orbit i:nth-child(4) { --a: 126deg; } .cv-orbit i:nth-child(5) { --a: 198deg; }
.cv-code {
  position: absolute; left: 50%; bottom: 0; translate: -50% 0;
  display: flex; gap: 3px; padding: 4px 7px; border-radius: 999px;
  border: 1px solid var(--t-border); background: rgba(var(--t-accent-rgb), .12);
}
.cv-code i { width: 4px; height: 4px; border-radius: 50%; background: rgba(231, 200, 135, .9); }
/* Whisper: one source, beams that flow ONE way, private ears at the end */
.cv-room--whisper .cv-node--src { left: 6%; top: 50%; translate: 0 -50%; }
.cv-fan { position: absolute; left: 24%; top: 50%; right: 30%; height: 0; }
.cv-fan b {
  position: absolute; left: 0; right: 0; height: 1px; top: 0; transform-origin: 0 50%;
  background: linear-gradient(90deg, rgba(var(--t-accent-bright-rgb), .85), rgba(var(--t-accent-bright-rgb), .2));
  background-size: 200% 100%;
  animation: voxBeam 2.4s linear infinite;
}
.cv-fan b:nth-child(1) { transform: rotate(-24deg); }
.cv-fan b:nth-child(3) { transform: rotate(24deg); }
@keyframes voxBeam { from { background-position: 100% 0; } to { background-position: -100% 0; } }
.cv-ears { position: absolute; right: 4%; top: 50%; translate: 0 -50%; display: grid; gap: clamp(8px, 2.4vh, 14px); }
.cv-ears i {
  position: relative; display: block;
  width: clamp(12px, 3vh, 18px); height: clamp(7px, 1.8vh, 10px);
  border: 1.5px solid rgba(var(--t-accent-bright-rgb), .85); border-bottom: 0;
  border-radius: 12px 12px 0 0;
}
.cv-ears i::before, .cv-ears i::after {
  content: ""; position: absolute; bottom: -3px; width: 4px; height: 5px; border-radius: 2px;
  background: rgba(var(--t-accent-bright-rgb), .9);
}
.cv-ears i::before { left: -1.5px; } .cv-ears i::after { right: -1.5px; }
[dir="rtl"] .cv-room--f2f .cv-node { left: auto; right: 6%; }
[dir="rtl"] .cv-room--f2f .cv-node--b { right: auto; left: 6%; }
[dir="rtl"] .cv-room--whisper .cv-node--src { left: auto; right: 6%; }
[dir="rtl"] .cv-fan { left: 30%; right: 24%; transform: scaleX(-1); }
[dir="rtl"] .cv-ears { right: auto; left: 4%; }

/* --- 6c-4 · Capability 04: the summary writing itself --- */
.cap-vig--summary { display: grid; place-items: center; --cv-dx: -14px; }
[dir="rtl"] .cap-vig--summary { --cv-dx: 14px; }

/* ---------- Live translate vignette (capability 05) ----------
   Two people, two languages, both directions streaming. Four transcript bars
   write themselves alternately from each edge, the LIVE pill breathes and a
   five-bar meter keeps ticking — hands-free, nothing to tap. Text-free (bars)
   apart from the language tags, which are product content. Base CSS state =
   every line written and the pill lit, so reduced motion / no-JS see a finished
   frame. Tokens only. Swap for the real capture when the app team ships one. */
.cap-vig--live { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; gap: 13px; padding: 20% 10% 16%; }
.cap-vig--live .cv-live {
  position: absolute; top: 8%; inset-inline-start: 10%;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px; border-radius: 999px;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .6);
  background: rgba(var(--t-accent-rgb), .08);
  color: var(--t-accent-bright); font-size: 11px; font-weight: 600; letter-spacing: .24em;
}
.cap-vig--live .cv-live i { width: 7px; height: 7px; border-radius: 50%; background: var(--t-accent-bright); box-shadow: 0 0 10px rgba(var(--t-accent-bright-rgb), .9); animation: cvLivePulse 2.4s ease-in-out infinite; }
.cap-vig--live .cv-turn { display: flex; align-items: center; gap: 10px; width: 78%; }
.cap-vig--live .cv-turn--b { align-self: flex-end; flex-direction: row-reverse; }
.cap-vig--live .cv-turn b { flex: 0 0 auto; font-size: 10px; letter-spacing: .18em; padding: 4px 8px; border-radius: 8px; border: 1px solid var(--t-border-soft); color: var(--t-text-muted); }
.cap-vig--live .cv-turn--b b { color: var(--t-accent-bright); border-color: rgba(var(--t-accent-bright-rgb), .5); }
.cap-vig--live .cv-turn i {
  flex: 1 1 auto; height: 14px; border-radius: 7px;
  background: linear-gradient(90deg, rgba(var(--t-accent-bright-rgb), .55), rgba(var(--t-accent-bright-rgb), .16));
  transform-origin: left center;
  animation: cvLiveWrite 7.2s cubic-bezier(.2, .7, .2, 1) infinite;
}
.cap-vig--live .cv-turn--b i { background: linear-gradient(270deg, rgba(var(--t-accent-rgb), .62), rgba(var(--t-accent-rgb), .16)); transform-origin: right center; }
[dir="rtl"] .cap-vig--live .cv-turn i { transform-origin: right center; }
[dir="rtl"] .cap-vig--live .cv-turn--b i { transform-origin: left center; }
.cap-vig--live .cv-turn:nth-child(3) i { animation-delay: 1.8s; }
.cap-vig--live .cv-turn:nth-child(4) i { animation-delay: 3.6s; }
.cap-vig--live .cv-turn:nth-child(5) i { animation-delay: 5.4s; }
.cap-vig--live .cv-wave { position: absolute; bottom: 8%; inset-inline-start: 10%; display: flex; align-items: flex-end; gap: 4px; height: 22px; }
.cap-vig--live .cv-wave i { width: 4px; height: 100%; border-radius: 2px; background: var(--t-accent-bright); opacity: .85; transform-origin: bottom; animation: cvLiveMeter 1.1s ease-in-out infinite; }
.cap-vig--live .cv-wave i:nth-child(2) { animation-delay: .15s; }
.cap-vig--live .cv-wave i:nth-child(3) { animation-delay: .3s; }
.cap-vig--live .cv-wave i:nth-child(4) { animation-delay: .45s; }
.cap-vig--live .cv-wave i:nth-child(5) { animation-delay: .6s; }
@keyframes cvLivePulse { 0%, 100% { opacity: .55; transform: scale(.85); } 50% { opacity: 1; transform: scale(1.15); } }
@keyframes cvLiveWrite { 0% { transform: scaleX(.12); opacity: .35; } 22% { transform: scaleX(1); opacity: 1; } 82% { transform: scaleX(1); opacity: 1; } 100% { transform: scaleX(1); opacity: .9; } }
@keyframes cvLiveMeter { 0%, 100% { transform: scaleY(.25); } 50% { transform: scaleY(1); } }
.cv-doc {
  display: flex;
  flex-direction: column;
  gap: clamp(7px, 2.6%, 13px);
  width: min(100%, 320px);
  padding: clamp(12px, 4%, 20px);
  border-radius: 16px;
  border: 1px solid var(--t-border);
  background: linear-gradient(180deg, var(--t-bg-card-1), var(--t-bg-card-2));
  box-shadow: 0 18px 40px rgba(0, 0, 0, .28), inset 0 1px 0 rgba(255, 255, 255, .04);
  animation: voxDocIn 11s ease-out infinite;
}
@keyframes voxDocIn {
  0%, 2%    { opacity: 0; transform: translateY(8px); }
  8%, 90%   { opacity: 1; transform: none; }
  97%, 100% { opacity: 0; transform: none; }
}
.cv-title { display: flex; align-items: center; gap: 4px; height: 11px; }
.cv-title i {
  display: block;
  width: 64%;
  height: 11px;
  border-radius: 6px;
  background: linear-gradient(90deg, rgba(231, 200, 135, .9), rgba(var(--t-accent-bright-rgb), .55));
  animation: voxType 11s steps(14, end) infinite;
}
@keyframes voxType { 0%, 4% { width: 0; } 22%, 88% { width: 64%; } 95%, 100% { width: 0; } }
.cv-caret {
  display: block;
  width: 2px;
  height: 11px;
  background: #E7C887;
  opacity: 0;
  animation: voxCaret 11s steps(1, end) infinite;
}
@keyframes voxCaret {
  0%, 3% { opacity: 0; } 5% { opacity: 1; } 8% { opacity: 0; }
  11% { opacity: 1; } 14% { opacity: 0; } 17% { opacity: 1; }
  22%, 100% { opacity: 0; }
}
.cv-item { display: flex; align-items: center; gap: 8px; animation: voxItemIn 11s ease-out infinite; }
.cv-doc > .cv-item:nth-child(3) { animation-delay: .5s; }
.cv-doc > .cv-item:nth-child(4) { animation-delay: 1s; }
@keyframes voxItemIn {
  0%, 24%   { opacity: 0; transform: translateX(var(--cv-dx)); }
  31%, 88%  { opacity: 1; transform: none; }
  95%, 100% { opacity: 0; transform: none; }
}
.cv-item i {
  display: block;
  flex: 1;
  height: 8px;
  border-radius: 5px;
  background: rgba(var(--t-accent-rgb), .18);
}
.cv-doc > .cv-item:nth-child(3) i { max-width: 84%; }
.cv-doc > .cv-item:nth-child(4) i { max-width: 62%; }
.cv-check { display: grid; place-items: center; flex: 0 0 auto; width: 14px; height: 14px; }
.cv-check svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: #E7C887;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 15;
  stroke-dashoffset: 0;
  animation: voxDraw 11s ease-out infinite;
}
.cv-doc > .cv-item:nth-child(3) .cv-check svg { animation-delay: .5s; }
@keyframes voxDraw { 0%, 28% { stroke-dashoffset: 15; } 36%, 88% { stroke-dashoffset: 0; } 95%, 100% { stroke-dashoffset: 15; } }
.cv-dot {
  flex: 0 0 auto;
  width: 9px;
  height: 9px;
  margin: 0 2px;
  border-radius: 50%;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .55);
}
.cv-stamp {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-block-start: 2px;
  animation: voxItemIn 11s ease-out infinite;
  animation-delay: 1.4s;
}
.cv-stamp em {
  font-style: normal;
  padding: 3px 7px;
  border-radius: 6px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: .08em;
  color: #E7C887;
  border: 1px solid rgba(231, 200, 135, .42);
  background: rgba(231, 200, 135, .10);
  animation: voxStampLit 11s ease-in-out infinite;
}
.cv-stamp i { display: block; flex: 0 0 42%; height: 8px; border-radius: 5px; background: rgba(var(--t-accent-rgb), .18); }
@keyframes voxStampLit {
  0%, 46%   { box-shadow: 0 0 0 0 rgba(231, 200, 135, 0); }
  54%       { box-shadow: 0 0 15px 2px rgba(231, 200, 135, .45); }
  64%, 100% { box-shadow: 0 0 0 0 rgba(231, 200, 135, 0); }
}

/* A narrow card cannot hold a vignette AND a phone side by side. Below
   this width the film returns to centre — exactly how it shipped before
   §6c — and the vignette steps aside rather than being squeezed. */
@media (max-width: 720px) {
  /* Unstaged vertical flow (the pin only exists ≥900px): give the portrait device
     a near-square card so it reads at phone size instead of as a 4:3 thumbnail. */
  .cap-mock--film { aspect-ratio: 1 / 1; }
  .cap-mock--film .cap-vig { display: none; }
  .cap-mock--film .cap-mock__film,
  .cap-mock--film .cap-mock__still { inset-inline-end: auto; left: 50%; translate: -50% -50%; }
}

/* ---------- 7. PROOF BAND — one-shot sheen as the stats arrive ---------- */
.proof-stat { overflow: hidden; }
.proof-stat::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 32%,
    rgba(var(--t-accent-bright-rgb), .22) 46%,
    rgba(231, 200, 135, .28) 52%,
    transparent 68%);
  opacity: 0;
  transform: translate3d(-120%, 0, 0);
}
.proof-stat.vox-sheen::after { animation: voxSheen 1.3s cubic-bezier(.2, .7, .2, 1) forwards; }

/* ---------- 8. FINAL CTA — the closing shot ---------- */
.detail-final { position: relative; isolation: isolate; }

/* 8a. Slow conic halo behind the card (z-index:-1 sits above the
   section background but below .detail-final-inner). */
@supports ((-webkit-mask-image: radial-gradient(#000, #000)) or (mask-image: radial-gradient(#000, #000))) {
  .detail-final::before {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: min(112%, 1080px);
    aspect-ratio: 1.55;
    translate: -50% -50%;
    z-index: -1;
    border-radius: 50%;
    pointer-events: none;
    /* Gold IS coherent here — it echoes the gold CTA at the centre of the card —
       so the ramp keeps it, but only against --t-accent-bright, whose hue sits
       close enough that the interpolation never crosses into teal. */
    background: conic-gradient(from 0deg,
      rgba(var(--t-accent-bright-rgb), .20),
      rgba(231, 200, 135, .16) 100deg,
      rgba(var(--t-accent-bright-rgb), .20) 200deg,
      rgba(231, 200, 135, .11) 300deg,
      rgba(var(--t-accent-bright-rgb), .20) 360deg);
    -webkit-mask: radial-gradient(closest-side, #000 16%, rgba(0, 0, 0, .45) 54%, transparent 76%);
            mask: radial-gradient(closest-side, #000 16%, rgba(0, 0, 0, .45) 54%, transparent 76%);
    will-change: transform;
    animation: voxSpin 44s linear infinite;
  }
}

/* 8b. The captured waveform, mounted lazily by JS (see the .js file
   for the gating). It is a blue-on-black plate, so `screen` drops
   the black; on light themes it would only wash out, so it is not
   rendered there at all. */
.vox-final-wave {
  position: absolute;
  left: 50%;
  bottom: -6%;
  width: min(148%, 1500px);
  translate: -50% 0;
  z-index: -1;
  opacity: 0;
  pointer-events: none;
  mix-blend-mode: screen;
  transition: opacity 1.4s ease;
  will-change: transform;
  animation: voxWaveBreathe 28s ease-in-out infinite alternate;
  /* Feathered on all four edges so the plate reads as ambient depth rather than
     a pasted rectangle — without it the section boundary sliced the wave crests
     off with a hard horizontal edge. Unsupported UAs just get the plain plate. */
  -webkit-mask: linear-gradient(180deg, transparent 0%, #000 34%, #000 76%, transparent 100%),
                linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
          mask: linear-gradient(180deg, transparent 0%, #000 34%, #000 76%, transparent 100%),
                linear-gradient(90deg, transparent 0%, #000 16%, #000 84%, transparent 100%);
  -webkit-mask-composite: source-in;
          mask-composite: intersect;
}
.vox-final-wave.vox-in { opacity: .20; }
[data-theme="light"] .vox-final-wave { display: none; }

/* 8c. Gold light sweep across the closing CTA. z-index:-1 under
   isolation lands it above the button's own gradient and below its
   label, so the text never dims. */
.detail-final .primary-cta { position: relative; overflow: hidden; isolation: isolate; }
.detail-final .primary-cta::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(105deg,
    transparent 34%,
    rgba(255, 255, 255, .55) 47%,
    rgba(231, 200, 135, .95) 54%,
    transparent 70%);
  opacity: 0;
  transform: translate3d(-130%, 0, 0);
}
.detail-final .primary-cta:hover::after,
.detail-final .primary-cta:focus-visible::after { animation: voxSheen .9s cubic-bezier(.25, .7, .2, 1); }

/* ---------- 13. INSIDE THE APP — the real-screen rail ----------
   Five device captures on a native scroll-snap rail. It needs no JS at all
   (drag, trackpad, keyboard once focused); the paddles ship [hidden] and
   §13 of the driver switches them on. Contains its own overflow, so it
   cannot widen the page. Device chrome and captions read the theme tokens. */
.vox-gallery__rail { position: relative; }
.vox-gallery__track {
  display: flex;
  gap: clamp(18px, 2.6vw, 40px);
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scroll-padding-inline: clamp(22px, 8vw, 160px);
  padding: 14px clamp(22px, 8vw, 160px) 30px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.vox-gallery__track::-webkit-scrollbar { display: none; }
.vox-gallery__track:focus-visible { outline: 2px solid rgba(var(--t-accent-bright-rgb), .7); outline-offset: -2px; border-radius: 24px; }
.vox-gallery__slide {
  flex: 0 0 auto;
  width: clamp(210px, 22vw, 300px);
  margin: 0;
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.vox-phone {
  width: 100%;
  aspect-ratio: 780 / 1688;
  padding: 7px;
  border-radius: 34px;
  background: #05070c;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .38);
  box-shadow: 0 30px 70px rgba(0, 0, 0, .5), 0 0 0 6px rgba(0, 0, 0, .32), inset 0 0 0 1px rgba(255, 255, 255, .04);
  overflow: hidden;
  transition: transform .5s cubic-bezier(.2, .7, .2, 1), box-shadow .5s ease;
}
.vox-phone img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: 27px; }
.vox-gallery__slide:hover .vox-phone {
  transform: translateY(-6px);
  box-shadow: 0 40px 80px rgba(0, 0, 0, .55), 0 0 0 6px rgba(0, 0, 0, .32), 0 0 48px rgba(var(--t-accent-rgb), .22);
}
.vox-gallery__slide figcaption { display: flex; flex-direction: column; gap: 6px; padding: 0 4px; }
.vox-gallery__slide figcaption b {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--t-accent-bright);
}
.vox-gallery__slide figcaption span {
  font-family: var(--font-display);
  font-size: clamp(17px, 1.4vw, 21px);
  line-height: 1.25;
  color: var(--t-text);
}
.vox-gallery__paddle {
  position: absolute;
  top: 38%;
  z-index: 2;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid rgba(var(--t-accent-bright-rgb), .5);
  background: linear-gradient(180deg, var(--t-bg-card-1), var(--t-bg-card-2));
  box-shadow: 0 14px 30px rgba(0, 0, 0, .4);
  color: var(--t-text);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: transform .3s ease, border-color .3s ease, opacity .3s ease;
}
.vox-gallery__paddle--prev { inset-inline-start: clamp(8px, 2vw, 28px); }
.vox-gallery__paddle--next { inset-inline-end: clamp(8px, 2vw, 28px); }
.vox-gallery__paddle:hover { transform: scale(1.06); border-color: var(--t-accent-bright); }
.vox-gallery__paddle:focus-visible { outline: 2px solid var(--t-accent-bright); outline-offset: 3px; }
.vox-gallery__paddle[disabled] { opacity: .28; cursor: default; transform: none; }
[dir="rtl"] .vox-gallery__paddle svg { transform: scaleX(-1); }
@media (max-width: 720px) { .vox-gallery__paddle { display: none; } }   /* touch: the rail is the control */

/* ---------- 9. Mobile trims ---------- */
@media (max-width: 900px) {
  .detail-hero::after { width: 92%; }
  .vox-demo-bloom { inset: -8%; }
  .giant-icon::after { width: 118%; }
}

/* ---------- 10. prefers-reduced-motion: everything above freezes ----------
   Each effect keeps a single, deliberately chosen still frame; the
   progress line and the drifting chips (which only exist as motion)
   are removed outright. Nothing that carries meaning is hidden. */
@media (prefers-reduced-motion: reduce) {
  .vox-progress,
  .vox-chip { display: none !important; }

  .detail-hero::after,
  .giant-icon::after,
  .detail-lockup .script-label__text::after,
  .vox-scene__conic,
  .detail-final::before,
  .vox-final-wave,
  .demo-frame__wait i,
  .proof-stat.vox-sheen::after,
  .detail-final .primary-cta:hover::after,
  .detail-final .primary-cta:focus-visible::after { animation: none !important; }

  .detail-lockup .script-label__text::after,
  .proof-stat::after,
  .detail-final .primary-cta::after { display: none !important; }

  .glass-nav,
  .detail-section::before,
  .detail-final::after,
  .cap-mock::after,
  .cap-mock__screen,
  .vox-final-wave { transition: none !important; }

  .detail-section::before,
  .detail-final::after { opacity: 1; transform: none; }
  /* A frozen spinner would read as a broken ring — close the circle instead. */
  .demo-frame__wait i { border-top-color: rgba(var(--t-accent-bright-rgb), .5); }

  /* §6c panels. Because every vignette's BASE style is already the
     finished frame, switching the animations off is all that is needed:
     the caption stays written, the constellation stays lit and readable,
     all three rooms stay lit, and the summary card keeps its
     typed title, its drawn ticks and its timestamp. */
  .cv-words i,
  .cv-bridge b,
  .cv-beam,
  .cv-core i,
  .cv-ring--out,
  .cv-ring--in,
  .cv-ring--out .cv-chip i,
  .cv-ring--in .cv-chip i,
  .cv-chip::before,
  .cv-chip::after,
  .cv-room,
  .cv-livedot,
  .cv-fan b,
  .cv-doc,
  .cv-title i,
  .cv-caret,
  .cv-item,
  .cv-check svg,
  .cv-stamp,
  .cv-stamp em { animation: none !important; }
  /* The beam and the caret exist only as motion — nothing to freeze. */
  .cv-beam,
  .cv-caret { display: none !important; }
  .cap-mock__screen { transform: none !important; }
  .vox-demo-bloom { opacity: .5; transform: none !important; }
  .vox-scene__conic { opacity: .55; }
  .cap-vig--live .cv-live i, .cap-vig--live .cv-turn i, .cap-vig--live .cv-wave i { animation: none; }
  /* §13 rail: no smooth-scroll, no hover lift */
  .vox-gallery__track { scroll-behavior: auto; }
  .vox-phone, .vox-gallery__paddle { transition: none !important; }
  .vox-gallery__slide:hover .vox-phone { transform: none; }
}
