/* PrevIA — Design tokens & global styles */
:root{
  /* Safe-area inset for notches / Dynamic Island. Falls back to 0 on platforms
     without env() support so layouts remain valid. JS can also read this via
     getComputedStyle(documentElement).getPropertyValue('--sat'). */
  --sat: env(safe-area-inset-top, 0px);

  /* Brand gradient (logo) */
  --grad-from: #22d3ee;   /* cyan */
  --grad-mid:  #6366f1;   /* indigo */
  --grad-to:   #a855f7;   /* purple */
  --grad: linear-gradient(135deg, var(--grad-from) 0%, var(--grad-mid) 50%, var(--grad-to) 100%);
  --grad-soft: linear-gradient(135deg, rgba(34,211,238,.12), rgba(168,85,247,.12));

  /* Neutrals — light */
  --ink-900:#0a0e1f;
  --ink-800:#171c30;
  --ink-700:#2a2f47;
  --ink-600:#4a5072;
  --ink-500:#6b718e;
  --ink-400:#9aa0b8;
  --ink-300:#c4c8d8;
  --ink-200:#e6e8f0;
  --ink-100:#f3f4f9;
  --ink-50: #fafbff;
  --paper:  #ffffff;

  /* Dark scanner palette */
  --night-950:#05060e;
  --night-900:#0a0c1a;
  --night-800:#0f1226;
  --night-700:#161a35;

  /* Functional */
  --ok:   #10b981;
  --warn: #f59e0b;
  --bad:  #ef4444;

  /* Type */
  --font-display: 'Inter', system-ui, -apple-system, sans-serif;
  --font-text: 'Inter', system-ui, -apple-system, sans-serif;
  --font-mono: 'JetBrains Mono', 'SF Mono', ui-monospace, monospace;

  /* Radii */
  --r-sm: 8px;
  --r-md: 14px;
  --r-lg: 22px;
  --r-xl: 32px;
  --r-pill: 999px;

  /* Shadows */
  --sh-sm: 0 1px 2px rgba(15,18,38,.06), 0 1px 1px rgba(15,18,38,.04);
  --sh-md: 0 6px 24px -8px rgba(15,18,38,.12), 0 2px 6px rgba(15,18,38,.05);
  --sh-lg: 0 24px 60px -20px rgba(15,18,38,.20), 0 8px 24px -8px rgba(15,18,38,.10);
  --sh-glow: 0 0 0 1px rgba(99,102,241,.18), 0 20px 60px -20px rgba(99,102,241,.35);

  /* Density */
  --pad-card: 24px;
  --gap-stack: 16px;

  /* Glass */
  --glass-bg: rgba(255,255,255,0.6);
  --glass-border: rgba(255,255,255,0.7);
  --glass-blur: 18px;
}

[data-theme="dark"]{
  --paper:#0a0c1a;
  --ink-50:#0f1226;
  --ink-100:#161a35;
  --ink-200:#222848;
  --ink-300:#373d65;
  --ink-400:#5a6088;
  --ink-500:#8a90b0;
  --ink-600:#b8bcd4;
  --ink-700:#d6d9e6;
  --ink-800:#eaecf3;
  --ink-900:#ffffff;
  --glass-bg: rgba(20,24,48,0.55);
  --glass-border: rgba(255,255,255,0.08);
}

[data-density="compact"]{
  --pad-card: 16px;
  --gap-stack: 10px;
}
[data-density="airy"]{
  --pad-card: 32px;
  --gap-stack: 22px;
}

[data-glass="low"]   { --glass-blur: 6px;  --glass-bg: rgba(255,255,255,0.85); }
[data-glass="high"]  { --glass-blur: 28px; --glass-bg: rgba(255,255,255,0.45); }

/* Reset */
*,*::before,*::after{ box-sizing:border-box; }
html,body{ margin:0; padding:0; }
body{
  font-family: var(--font-text);
  color: var(--ink-900);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img,svg,video{ display:block; max-width:100%; }
button{ font-family: inherit; }

/* Type scale */
.h-display{ font-family:var(--font-display); font-weight:700; letter-spacing:-0.035em; line-height:0.98; }
.h-1{ font-size: clamp(40px, 5.6vw, 84px); font-weight:700; letter-spacing:-0.035em; line-height:1.02; }
.h-2{ font-size: clamp(32px, 3.6vw, 56px); font-weight:700; letter-spacing:-0.028em; line-height:1.05; }
.h-3{ font-size: clamp(24px, 2.4vw, 36px); font-weight:600; letter-spacing:-0.02em; line-height:1.15; }
.h-4{ font-size: 20px; font-weight:600; letter-spacing:-0.012em; line-height:1.25; }
.eyebrow{
  font-size: 12px; font-weight:600; letter-spacing:.14em; text-transform:uppercase;
  color: var(--ink-500);
}
.lead{ font-size: clamp(17px, 1.3vw, 20px); line-height:1.5; color:var(--ink-600); }
.mono{ font-family: var(--font-mono); font-feature-settings: "tnum" 1; }

/* Brand */
.grad-text{
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.grad-bg{ background: var(--grad); }
.grad-border{
  position:relative; background:var(--paper);
}
.grad-border::before{
  content:""; position:absolute; inset:0; border-radius:inherit;
  padding:1px; background: var(--grad);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events:none;
}

/* Buttons */
.btn{
  display:inline-flex; align-items:center; gap:10px;
  padding: 14px 22px;
  border-radius: var(--r-pill);
  font-weight:600; font-size:15px;
  border:0; cursor:pointer;
  transition: transform .2s ease, box-shadow .2s ease, opacity .2s ease;
  text-decoration:none;
}
.btn-primary{
  color:#fff; background: var(--grad);
  box-shadow: 0 10px 30px -10px rgba(99,102,241,.55), 0 2px 0 rgba(255,255,255,.2) inset;
}
.btn-primary:hover{ transform: translateY(-1px); box-shadow: 0 16px 36px -10px rgba(99,102,241,.7), 0 2px 0 rgba(255,255,255,.2) inset; }
.btn-ghost{
  color: var(--ink-800); background: transparent;
  border: 1px solid var(--ink-200);
}
.btn-ghost:hover{ border-color: var(--ink-400); }
.btn-dark{
  color:#fff; background: var(--ink-900);
}
.btn-lg{ padding: 18px 28px; font-size: 16px; }

/* Pills */
.pill{
  display:inline-flex; align-items:center; gap:8px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  font-size: 12px; font-weight:500;
  background: var(--ink-100); color: var(--ink-700);
}
.pill-grad{
  background: linear-gradient(135deg, rgba(34,211,238,.14), rgba(168,85,247,.14));
  color: var(--ink-800);
  border: 1px solid rgba(99,102,241,.18);
}
.pill-dot{ width:6px; height:6px; border-radius:50%; background: var(--grad-from); }

/* Card */
.card{
  background: var(--paper);
  border-radius: var(--r-lg);
  border: 1px solid var(--ink-200);
  padding: var(--pad-card);
  box-shadow: var(--sh-sm);
}
.card-glass{
  background: var(--glass-bg);
  backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(160%);
  border: 1px solid var(--glass-border);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-md);
}

/* Layout */
.container{ max-width: 1240px; margin: 0 auto; padding: 0 32px; }
.section{ padding: 96px 0; }
.section-tight{ padding: 64px 0; }

/* Grids of bg gradients */
.bg-grid{
  background-image:
    linear-gradient(to right, rgba(15,18,38,0.04) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(15,18,38,0.04) 1px, transparent 1px);
  background-size: 56px 56px;
}
.bg-radial{
  background:
    radial-gradient(60% 50% at 80% 0%, rgba(168,85,247,.12), transparent 70%),
    radial-gradient(50% 60% at 0% 100%, rgba(34,211,238,.12), transparent 70%);
}

/* Marquee */
@keyframes marquee {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}
.marquee{ display:flex; gap: 48px; animation: marquee 28s linear infinite; }

/* Pulse ring */
@keyframes pulse-ring {
  0% { transform: scale(0.95); opacity: 0.7; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* Scroll reveal */
.reveal{
  opacity:0; transform: translateY(20px);
  transition: opacity .9s cubic-bezier(.2,.7,.2,1), transform .9s cubic-bezier(.2,.7,.2,1);
}
.reveal.in{ opacity:1; transform: translateY(0); }

/* Float */
@keyframes float {
  0%,100% { transform: translateY(0); }
  50%    { transform: translateY(-10px); }
}
@keyframes float-x {
  0%,100% { transform: translateX(0); }
  50%    { transform: translateX(8px); }
}

/* Spin slow */
@keyframes spin-slow { to { transform: rotate(360deg); } }

/* Shimmer */
@keyframes shimmer {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}
.shimmer{
  background: linear-gradient(90deg, var(--ink-100) 0%, var(--ink-200) 50%, var(--ink-100) 100%);
  background-size: 200% 100%;
  animation: shimmer 2.4s linear infinite;
}

/* utilities */
.flex{ display:flex; }
.flex-col{ flex-direction:column; }
.items-center{ align-items:center; }
.justify-center{ justify-content:center; }
.justify-between{ justify-content:space-between; }
.gap-2{ gap:8px; } .gap-3{ gap:12px; } .gap-4{ gap:16px; } .gap-6{ gap:24px; } .gap-8{ gap:32px; }
.text-center{ text-align:center; }
.relative{ position:relative; }

/* ============== RESPONSIVE ============== */
@media (max-width: 1024px){
  .container{ padding: 0 24px; }
  .section{ padding: 72px 0; }
}

@media (max-width: 768px){
  :root{
    --pad-card: 18px;
  }
  .container{ padding: 0 16px; }
  .section{ padding: 56px 0; }
  .h-1{ font-size: clamp(34px, 8vw, 48px); }
  .h-2{ font-size: clamp(26px, 6.5vw, 36px); }
  .h-3{ font-size: clamp(22px, 5vw, 28px); }
  .lead{ font-size: 15px; }
  .btn{ padding: 12px 18px; font-size: 14px; }
  .btn-lg{ padding: 14px 22px; font-size: 15px; }
  .pill{ font-size: 11px; padding: 5px 10px; }
  .marquee{ gap: 24px; }
}

@media (max-width: 480px){
  .container{ padding: 0 14px; }
  .section{ padding: 44px 0; }
  .h-1{ font-size: 30px; line-height: 1.05; }
  .h-2{ font-size: 24px; }
  .h-3{ font-size: 20px; }
  .h-4{ font-size: 17px; }
  .eyebrow{ font-size: 11px; letter-spacing: .12em; }
  .lead{ font-size: 14px; }
  .btn{ padding: 11px 16px; font-size: 13px; gap: 8px; }
  .btn-lg{ padding: 13px 20px; font-size: 14px; }
  .card{ border-radius: 16px; }
}

/* Scanner results responsive */
@media (max-width: 900px){
  .results-grid{ grid-template-columns: minmax(0, 1fr) !important; }
}
@media (max-width: 600px){
  .metrics-grid{ grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}
@media (max-width: 380px){
  .metrics-grid{ grid-template-columns: minmax(0, 1fr) !important; }
}

/* Consult responsive — stack video & sidebar */
.consult-grid{ display:grid; grid-template-columns: 1fr 380px; gap:0; height: calc(100vh - 65px); }
@media (max-width: 900px){
  .consult-grid{ grid-template-columns: minmax(0, 1fr); height: auto; }
  .consult-sidebar{ border-left: none !important; border-top: 1px solid rgba(255,255,255,.06); }
}

/* Waiting & Review responsive (use class + media queries since structure is wide) */
.waiting-grid{ display:grid; grid-template-columns: minmax(0,1fr) 380px; gap:32px; align-items:flex-start; padding-top:32px; padding-bottom:60px; }
.waiting-stages{ display:grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap:0; position:relative; }
.waiting-summary-cols{ display:grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap:8px; margin-bottom:18px; }
@media (max-width: 900px){
  .waiting-grid{ grid-template-columns: minmax(0,1fr); gap:20px; }
  .waiting-stages{ grid-template-columns: repeat(2, minmax(0,1fr)); gap:8px; }
}

.review-grid{ display:grid; grid-template-columns: 260px minmax(0,1fr) 320px; gap:0; height: calc(100vh - 65px); }
@media (max-width: 1024px){
  .review-grid{ grid-template-columns: minmax(0,1fr); height: auto; }
}

/* BigNumber responsive + tech widget mobile */
.big-number{ font-size: clamp(32px, 6vw, 48px); }
.biometric-widget{ width: 100%; }
@media (max-width: 768px){
  .biometric-widget{ grid-column: 1 / -1 !important; }
  .big-number{ font-size: 36px; }
}

/* Scanner ring centering helpers */
.scanner-ring-wrap{ position:absolute; left:50%; top:50%; transform: translate(-50%, -50%); pointer-events:none; }

/* ============================================================
   Sofía 3D — TalkingHead avatar + chat panel
   ============================================================ */
:root{
  --sofia-lime: #d4ff7c;
  --sofia-lime-soft: rgba(212,255,124,.35);
  --sofia-glass: rgba(15,18,30,.82);
}

.sofia3d{
  position: fixed;
  right: 4%;
  bottom: 8%;
  z-index: 950;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 12px;
  font-family: var(--font-text);
  pointer-events: none;
  /* Smooth slide when the per-screen anchor changes (e.g. bottom-right →
     top-right between dashboard ↔ onboarding). Only positional props are
     animated — `transform` is left alone so the hero-mode scroll-driven
     translate3d/scale lerp keeps its per-frame fidelity. */
  transition: right 0.35s cubic-bezier(.22,1,.36,1),
              bottom 0.35s cubic-bezier(.22,1,.36,1),
              top 0.35s cubic-bezier(.22,1,.36,1);
  animation: sofia3dIn .6s cubic-bezier(.2,.7,.2,1);
}
/* Hero mode positions Sofía via JS-driven transform updates every scroll frame.
   Suppress positional transitions there so no easing ever fights the rAF lerp. */
.sofia3d--hero{
  transition: none !important;
}
/* relative anchor for absolutely-positioned children (chat panel) */
.sofia3d__avatar-wrap{ position: relative; }
.sofia3d{ /* ensure chat panel anchors here, not to viewport */ }
.sofia3d > *{ pointer-events: auto; }
@keyframes sofia3dIn{
  from{ opacity:0; transform: translateY(24px) scale(.96); }
  to  { opacity:1; transform: translateY(0)    scale(1);   }
}

/* --- Avatar 3D canvas --------------------------------------- */
.sofia3d__avatar-wrap{
  position: relative;
  width: 180px;
  height: 240px;
  cursor: pointer;
  background: transparent;
  /* CRITICAL: overflow:hidden contains the WebRTC <video> at its intrinsic
     1280x720 from bleeding out of the wrap on iOS Safari / real browsers.
     In headless tests the video has no frames so this bug is invisible. */
  overflow: hidden;
  border-radius: 18px;
  animation: sofiaFloat 3.6s cubic-bezier(.45,.05,.55,.95) infinite;
  will-change: transform;
  /* Replaces drop-shadow filter previously on the live <video>. Static
     box-shadow on the wrap = same visual, near-zero GPU cost. */
  box-shadow: 0 18px 38px rgba(0,0,0,.42), 0 4px 14px rgba(99,102,241,.18);
}
@keyframes sofiaFloat{
  0%   { transform: translateY(0)    rotate(0deg) }
  25%  { transform: translateY(-14px) rotate(.6deg) }
  50%  { transform: translateY(-4px)  rotate(0deg) }
  75%  { transform: translateY(-12px) rotate(-.5deg) }
  100% { transform: translateY(0)    rotate(0deg) }
}
.sofia3d--speaking .sofia3d__avatar-wrap{
  animation-duration: 2.2s; /* more excited motion when talking */
}
/* While LiveAvatar is streaming: stop all decorative animations on this wrap
   subtree. Every animation that touches transform/opacity inside the wrap forces
   the browser to recomposite the inner WebRTC <video> at animation framerate,
   which competes with video decode for GPU budget and causes lip-sync drift
   (audio plays at clock rate, video drops frames, drift accumulates over long
   utterances). HeyGen already renders blinks + speaking motion in the avatar
   stream itself, so the overlays are pure overhead while live. */
.sofia3d--live .sofia3d__avatar-wrap,
.sofia3d--live-connecting .sofia3d__avatar-wrap{
  animation: none;
}
.sofia3d--live .sofia3d__avatar-wrap::before,
.sofia3d--live-connecting .sofia3d__avatar-wrap::before{
  animation: none;
  opacity: 0;
}
.sofia3d--live .sofia3d__avatar-canvas,
.sofia3d--live-connecting .sofia3d__avatar-canvas,
.sofia3d--live.sofia3d--speaking .sofia3d__avatar-canvas,
.sofia3d--live-connecting.sofia3d--speaking .sofia3d__avatar-canvas{
  animation: none;
}
.sofia3d__avatar-canvas{
  position: absolute; inset: 0;
  border-radius: 28px;
  overflow: hidden;
  background: transparent;
  transition: transform .25s cubic-bezier(.2,.7,.2,1);
}
.sofia3d__avatar-canvas--hidden{
  /* offscreen but kept mounted for ref stability */
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  overflow: hidden;
  clip: rect(0 0 0 0);
  opacity: 0;
  pointer-events: none;
}

/* Photoreal pose image — main visible avatar */
.sofia3d__pose-img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 30%;
  z-index: 1;
  pointer-events: auto;
  cursor: pointer;
  transition: opacity .25s ease;
  background: transparent;
  filter: drop-shadow(0 12px 28px rgba(0,0,0,.35)) drop-shadow(0 0 18px rgba(212,255,124,.12));
  animation: poseBreathIdle 4.5s ease-in-out infinite, poseSway 7s ease-in-out infinite;
  transform-origin: center bottom;
}
.sofia3d__pose-img--hidden{ opacity: 0; pointer-events: none; }
/* Poster is ALWAYS visible — the WebRTC <video class="sofia3d__live-stream">
   sits on top at z-index 4 and covers the poster when frames are flowing.
   When frames briefly stall (connecting handshake, mid-stream glitch, session
   renew at 10min), the video renders transparent and the poster falls back
   in. Earlier this rule force-hid the poster on `--live`, which produced a
   blank rectangle whenever frames lagged. Keeping the poster behind the video
   gives a graceful, gap-free experience.
   No CSS rule here on purpose — image stays at opacity:1 by default. */
.sofia3d--speaking .sofia3d__pose-img{
  animation: poseBreathSpeak 1.6s ease-in-out infinite, poseSway 4s ease-in-out infinite;
}
@keyframes poseBreathIdle{
  0%,100%{ transform: scale(1)     translateY(0); }
  50%    { transform: scale(1.012) translateY(-1px); }
}
@keyframes poseBreathSpeak{
  0%,100%{ transform: scale(1.005) translateY(0); }
  50%    { transform: scale(1.025) translateY(-2px); }
}
@keyframes poseSway{
  0%,100%{ rotate: 0deg; }
  25%    { rotate: 0.6deg; }
  50%    { rotate: 0deg; }
  75%    { rotate: -0.4deg; }
}

/* Eye blink overlay — periodic blink simulated via gradient sweep */
.sofia3d__avatar-wrap::before{
  content: '';
  position: absolute;
  inset: 24% 18% 50% 18%;       /* eye-area only */
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 35%, rgba(80,60,55,.0) 45%, rgba(80,60,55,.0) 55%, transparent 65%);
  opacity: 0;
  animation: blinkLoop 5.4s ease-in-out infinite;
}
@keyframes blinkLoop{
  0%, 92%, 100%{ opacity: 0; transform: scaleY(1); }
  94%, 98%    { opacity: 0.55; transform: scaleY(0.05); background: rgba(70,50,45,0.55); }
}
.sofia3d--speaking .sofia3d__avatar-canvas{
  animation: sofiaSpeakPulse 1.8s ease-in-out infinite;
}
@keyframes sofiaSpeakPulse{
  0%,100%{ transform: scale(1); }
  50%    { transform: scale(1.025); }
}
.sofia3d__avatar-canvas canvas{
  display: block;
  width: 100% !important;
  height: 100% !important;
  border-radius: 28px;
}
.sofia3d__pulse{
  position: absolute; inset: -8px;
  border-radius: 32px;
  border: 1.5px solid var(--sofia-lime);
  opacity: 0;
  pointer-events: none;
}

/* --- Hero video (HeyGen Talking Photo) overlay -------------- */
/* Hidden video element — only feeds frames to the chromakey canvas */
.sofia3d__hero-video-source{
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}

/* Visible canvas — receives chromakey-processed frames (dark bg removed) */
.sofia3d__hero-canvas{
  position: absolute; inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 3;
  display: none;
  pointer-events: auto;
  cursor: pointer;
  filter: drop-shadow(0 12px 28px rgba(0,0,0,.35)) drop-shadow(0 0 18px rgba(212,255,124,.12));
  /* CSS object-fit on canvas requires it be inside img-like layout; we use width/height + objectFit cover */
}
.sofia3d__hero-canvas--active{
  display: block;
  animation: heroVideoIn .35s cubic-bezier(.2,.7,.2,1);
}
@keyframes heroVideoIn{
  from{ opacity:0; transform: scale(.96); }
  to  { opacity:1; transform: scale(1); }
}
.sofia3d__avatar-wrap--hero{
  /* Slightly bigger during hero video moment for emphasis */
  transform: scale(1.05);
  transition: transform .35s cubic-bezier(.2,.7,.2,1);
}

/* --- LiveAvatar streaming <video> ------------------------- */
.sofia3d__live-stream{
  position: absolute !important;
  inset: 0 !important;
  /* Hard constraints — WebRTC video has intrinsic 1280x720 and on real
     browsers (esp. iOS Safari) it ignores absolute positioning, growing
     to its natural size. These constraints prevent that. */
  width: 100% !important;
  height: 100% !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  object-fit: cover;
  object-position: center top;
  z-index: 4;
  display: none;
  /* Intentionally NO background here. The live-stream is layered above the
     poster (.sofia3d__pose-img) — when WebRTC frames are present they cover
     the poster, when frames briefly stall (connecting → live handshake,
     network glitch, mid-renewal) the video renders transparent and the
     poster shows through. A gradient or color here would mask the poster
     and produce the "blank rectangle with LIVE badge" bug. */
  border-radius: 18px;
  cursor: pointer;
  /* No filter on the WebRTC <video> itself. drop-shadow filters here trash
     mobile GPU (filter pass on every video frame at 30fps) and cause lip-sync
     drift — video frames drop while audio plays at normal rate. The visual
     drop-shadow is now provided by box-shadow on the parent wrap below. */
}
.sofia3d__live-stream--active{
  display: block;
  animation: heroVideoIn .45s cubic-bezier(.2,.7,.2,1);
}
/* Slight size bump while streaming live so the live face is visible enough,
   but stays small/floating bottom-right. */
.sofia3d--live .sofia3d__avatar-wrap,
.sofia3d--live-connecting .sofia3d__avatar-wrap{
  width: 220px !important;
  height: 300px !important;
  max-width: 220px !important;
  max-height: 300px !important;
  transition: width .35s cubic-bezier(.2,.7,.2,1), height .35s cubic-bezier(.2,.7,.2,1);
}
/* Lock desktop sofia container — defensive position + size + reset of any
   inline-style or inherited rule that could move/resize it. */
.sofia3d{
  position: fixed !important;
  z-index: 9999 !important;
  max-width: 280px !important;
  max-height: 80vh !important;
}

/* --- Sofía hero-slot — invisible 380×500 layout anchor in the landing hero.
   The actual SofiaAvatar is rendered globally and overlays this slot via
   position:fixed + transform driven by scrollY. We DO add a soft glow ring
   here so that during the first second (before LiveAvatar connects) there is
   a clean "vessel" visual where Sofía is about to appear — avoids a jarring
   empty right column on hero. */
.sofia-hero-slot{
  width: 380px;
  height: 500px;
  border-radius: 28px;
  background: radial-gradient(ellipse at center, rgba(99,102,241,.08) 0%, rgba(34,211,238,.04) 45%, transparent 80%);
  position: relative;
  justify-self: end;
}
.sofia-hero-slot::after{
  content:'';
  position:absolute;
  inset:-24px;
  border-radius: 36px;
  background: conic-gradient(from 90deg, transparent, rgba(99,102,241,.18), transparent 50%);
  animation: spin-slow 20s linear infinite;
  z-index:-1;
  pointer-events:none;
  opacity:.6;
}
@media (max-width: 768px){
  .sofia-hero-slot{
    width: 100%;
    max-width: 360px;
    height: 460px;
    margin: 0 auto;
  }
  .sofia-hero-slot::after{ inset: -12px; }
}

/* While Sofía is overlaying the hero slot (mode=hero), unlock the .sofia3d
   max-width/max-height that we use for widget mode — the scale needs room. */
.sofia3d--hero{
  max-width: none !important;
  max-height: none !important;
  right: auto !important;
  bottom: auto !important;
  left: 0 !important;
  top: 0 !important;
  transform-origin: top left;
  will-change: transform;
}
/* Lock the avatar-wrap to a known intrinsic size in hero mode so the JS
   transform math is stable regardless of live/non-live state. */
.sofia3d--hero .sofia3d__avatar-wrap{
  width: 220px !important;
  height: 300px !important;
  max-width: 220px !important;
  max-height: 300px !important;
}
/* Hide the speech bubble while in hero mode. Audio is the primary channel
   when Sofía is the protagonist; bubble re-appears in widget mode where
   it provides at-a-glance context. */
.sofia3d--hero .sofia3d__bubble,
.sofia3d--hero .sofia3d__hint{ display: none !important; }

/* Hero-mode entrance: override the default heroVideoIn keyframe (which
   uses `transform: scale()` and would stack with the outer .sofia3d scale,
   forcing the GPU to re-rasterize the WebRTC video layer 60× per second
   during the first 450ms — exactly when the decoder is warming up = visible
   stutter). Use opacity-only fade-in. Zero GPU cost, no double-transform. */
.sofia3d--hero .sofia3d__live-stream--active{
  animation: heroVideoFadeIn .45s ease-out;
}
@keyframes heroVideoFadeIn{
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* --- MOBILE responsive: keep Sofía small + always bottom-right --------------
   NOTE: simple px values (not env() safe-area) — env() can fail to parse on
   some Safari builds, taking the entire rule down and stripping position:fixed. */
@media (max-width: 768px){
  .sofia3d{
    position: fixed !important;
    right: 12px !important;
    bottom: 12px !important;
    top: auto !important;
    left: auto !important;
    z-index: 9999 !important;
    /* Defensive: prevent flex container from growing if a child overflows */
    max-width: 60vw !important;
    max-height: 70vh !important;
    overflow: visible;
  }
  /* Per-screen anchor: tuck the widget under the notch on screens whose
     primary CTA lives bottom-right (onboarding, auth, scanner) so Sofía never
     covers "Continuar". --sat resolves to env(safe-area-inset-top) on iOS/
     Android with safe-area support and 0 elsewhere; +12px keeps the margin
     consistent with the bottom-right state. NOT compounded with
     .sofia3d--hero (the hero block at the end of this stylesheet wins via
     later !important rules). */
  .sofia3d--top-right-mobile{
    top: calc(var(--sat, 0px) + 12px) !important;
    bottom: auto !important;
  }
  .sofia3d__avatar-wrap{
    width: 130px !important;
    height: 175px !important;
    max-width: 130px !important;
    max-height: 175px !important;
  }
  .sofia3d--live .sofia3d__avatar-wrap,
  .sofia3d--live-connecting .sofia3d__avatar-wrap{
    width: 160px !important;
    height: 215px !important;
    max-width: 160px !important;
    max-height: 215px !important;
  }
  /* Smaller badges so they don't dwarf the small avatar */
  .sofia3d__live-badge{
    font-size: 9px;
    padding: 2px 7px;
  }
  .sofia3d__live-credits{ display: none; }
}

/* Small phone (iPhone SE etc.) */
@media (max-width: 380px){
  .sofia3d__avatar-wrap{
    width: 110px;
    height: 145px;
  }
  .sofia3d--live .sofia3d__avatar-wrap,
  .sofia3d--live-connecting .sofia3d__avatar-wrap{
    width: 130px;
    height: 175px;
  }
  /* Hide static greeting bubble on very small screens — it crowds the UI */
  .sofia3d__bubble{ display: none; }
}

/* Landscape phones — keep Sofía from blocking too much horizontal space */
@media (max-width: 900px) and (orientation: landscape){
  .sofia3d__avatar-wrap{
    width: 110px;
    height: 145px;
  }
  .sofia3d--live .sofia3d__avatar-wrap,
  .sofia3d--live-connecting .sofia3d__avatar-wrap{
    width: 130px;
    height: 175px;
  }
}

/* --- Hero mode on mobile/landscape: restore top-left anchor + hero-size wrap.
   On the landing screen .sofia3d--hero is set and Sofía's position is fully
   JS-driven (transform from #sofia-hero-slot → bottom-right widget anchor).
   The mobile widget rules above (right:12; bottom:12; avatar-wrap 130×175)
   target the bottom-right WIDGET state — but they were also winning over
   .sofia3d--hero on phones, anchoring the element bottom-right while the JS
   tried to translate3d() it to viewport-origin coordinates. Result: Sofía
   pushed off-screen, invisible in hero, half-cropped after scroll. These rules
   re-align mobile hero with the desktop hero contract (top-left anchor,
   unlocked max-* , 220×300 wrap) so the morph math works on every viewport.
   The JS scales her down (widgetScale=0.65) at t=1 to land at a ~143×195
   visible widget — same vibe as the static mobile widget, no CSS state swap. */
@media (max-width: 768px){
  .sofia3d--hero{
    right: auto !important;
    bottom: auto !important;
    left: 0 !important;
    top: 0 !important;
    max-width: none !important;
    max-height: none !important;
  }
  .sofia3d--hero .sofia3d__avatar-wrap,
  .sofia3d--hero.sofia3d--live .sofia3d__avatar-wrap,
  .sofia3d--hero.sofia3d--live-connecting .sofia3d__avatar-wrap{
    width: 220px !important;
    height: 300px !important;
    max-width: 220px !important;
    max-height: 300px !important;
  }
}
@media (max-width: 900px) and (orientation: landscape){
  .sofia3d--hero{
    right: auto !important;
    bottom: auto !important;
    left: 0 !important;
    top: 0 !important;
    max-width: none !important;
    max-height: none !important;
  }
  .sofia3d--hero .sofia3d__avatar-wrap,
  .sofia3d--hero.sofia3d--live .sofia3d__avatar-wrap,
  .sofia3d--hero.sofia3d--live-connecting .sofia3d__avatar-wrap{
    width: 220px !important;
    height: 300px !important;
    max-width: 220px !important;
    max-height: 300px !important;
  }
}
/* Smoother pose-img rendering (avoids pixelation when scaled) */
.sofia3d__pose-img{ image-rendering: high-quality; image-rendering: -webkit-optimize-contrast; }
.sofia3d__live-badge{
  position: absolute;
  top: 8px; left: 8px;
  z-index: 6;
  padding: 3px 9px;
  font: 600 10px/1 var(--font-text, system-ui);
  letter-spacing: .12em;
  color: #fff;
  background: rgba(220, 38, 38, .92);
  border-radius: 999px;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(220, 38, 38, .4);
  animation: liveBadgePulse 1.5s ease-in-out infinite;
}
.sofia3d__live-badge--connecting{
  background: rgba(56, 189, 248, .9);
  box-shadow: 0 2px 8px rgba(56, 189, 248, .35);
  animation: none;
}
.sofia3d__live-badge--warn{
  background: rgba(251, 146, 60, .9);
  box-shadow: 0 2px 8px rgba(251, 146, 60, .35);
  animation: none;
}
.sofia3d__live-credits{
  position: absolute;
  top: 8px; right: 8px;
  z-index: 6;
  padding: 3px 8px;
  font: 500 10px/1 var(--font-text, system-ui);
  color: rgba(255,255,255,.8);
  background: rgba(0,0,0,.45);
  border-radius: 999px;
  backdrop-filter: blur(8px);
}
@keyframes liveBadgePulse{
  0%, 100% { opacity: 1; }
  50% { opacity: .65; }
}

/* --- Voice mode state ring -------------------------------- */
.sofia3d__voice-ring,
.sofia3d__voice-ring--listening,
.sofia3d__voice-ring--speaking_user,
.sofia3d__voice-ring--thinking,
.sofia3d__voice-ring--speaking_sofia,
.sofia3d__voice-ring--paused,
.sofia3d__voice-ring--activating,
.sofia3d__voice-ring--denied{
  display: none !important;     /* removed — distracted from photoreal feel */
}
.sofia3d__voice-ring--listening{
  border-color: #4ade80;        /* green - hearing */
  animation: voiceListenPulse 1.6s ease-in-out infinite;
  box-shadow: 0 0 0 0 rgba(74,222,128,.35), inset 0 0 14px rgba(74,222,128,.18);
}
.sofia3d__voice-ring--speaking_user{
  border-color: #4ade80;
  border-width: 4px;
  animation: voiceUserSpeak .6s ease-in-out infinite;
  box-shadow: 0 0 24px rgba(74,222,128,.6), inset 0 0 18px rgba(74,222,128,.3);
}
.sofia3d__voice-ring--thinking{
  border-color: var(--sofia-lime);
  border-style: dashed;
  animation: voiceThinkSpin 1.6s linear infinite;
  box-shadow: 0 0 20px var(--sofia-lime-soft);
}
.sofia3d__voice-ring--speaking_sofia{
  border-color: var(--sofia-lime);
  animation: voiceSofiaSpeak 1s ease-in-out infinite;
  box-shadow: 0 0 28px var(--sofia-lime), inset 0 0 18px var(--sofia-lime-soft);
}
.sofia3d__voice-ring--paused{ border-color: rgba(255,255,255,.3); opacity:.5; }
.sofia3d__voice-ring--activating{ border-color: rgba(255,255,255,.5); animation: voiceListenPulse 1s ease-in-out infinite; }
.sofia3d__voice-ring--denied{ border-color: #ff8898; opacity:.6; }

@keyframes voiceListenPulse{
  0%,100%{ box-shadow: 0 0 0 0 rgba(74,222,128,.35), inset 0 0 14px rgba(74,222,128,.18); }
  50%    { box-shadow: 0 0 0 12px rgba(74,222,128,0),  inset 0 0 22px rgba(74,222,128,.28); }
}
@keyframes voiceUserSpeak{
  0%,100%{ transform: scale(1);    }
  50%    { transform: scale(1.04); }
}
@keyframes voiceThinkSpin{
  to { transform: rotate(360deg); }
}
@keyframes voiceSofiaSpeak{
  0%,100%{ box-shadow: 0 0 22px var(--sofia-lime-soft), inset 0 0 14px var(--sofia-lime-soft); }
  50%    { box-shadow: 0 0 36px var(--sofia-lime),       inset 0 0 22px var(--sofia-lime); }
}

/* --- Subtle hint (replaces CTA) --------------------------- */
.sofia3d__hint{
  position: absolute;
  bottom: -10px;
  left: 50%;
  transform: translateX(-50%);
  padding: 6px 14px;
  border-radius: 999px;
  background: rgba(15,18,30,.85);
  color: var(--sofia-lime);
  font-family: var(--font-text);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  white-space: nowrap;
  border: 1px solid rgba(212,255,124,.25);
  pointer-events: none;
  z-index: 4;
  animation: hintFade 4s ease-in-out infinite;
}
@keyframes hintFade{
  0%,100%{ opacity:.7; }
  50%    { opacity:1;  }
}

/* --- Voice state label ------------------------------------ */
.sofia3d__voice-label{
  position: absolute;
  top: -28px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(15,18,30,.85);
  color: var(--sofia-lime);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .12em;
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid rgba(212,255,124,.25);
  white-space: nowrap;
  pointer-events: none;
  animation: ctaIn .3s ease;
}

/* Make the "thinking" state highly visible — pulsing border + larger pill —
   so users perceive Sofía is working on their question and don't think the
   app is stuck during the 2-3s LLM+TTS latency. */
.sofia3d--vstate-thinking .sofia3d__voice-label{
  font-size: 13px;
  padding: 7px 16px;
  background: linear-gradient(90deg, rgba(168,85,247,.4), rgba(34,211,238,.4));
  color: #fff;
  border-color: rgba(168,85,247,.7);
  animation: thinkingPulse 1.1s ease-in-out infinite;
  box-shadow: 0 0 0 0 rgba(168,85,247,.6);
}
@keyframes thinkingPulse{
  0%   { box-shadow: 0 0 0 0   rgba(168,85,247,.55); }
  70%  { box-shadow: 0 0 0 14px rgba(168,85,247,0);  }
  100% { box-shadow: 0 0 0 0   rgba(168,85,247,0);  }
}

/* Mic-active styling moved below to the SVG-icon button block (line ~1280).
   The new rule uses a lime gradient + glow ring for clearer affordance. */
.sofia3d--speaking .sofia3d__pulse{
  animation: sofia3dPulse 1.8s ease-out infinite;
}
@keyframes sofia3dPulse{
  0%  { opacity:.7; transform: scale(.96); }
  100%{ opacity:0;  transform: scale(1.08); }
}
.sofia3d__loading{
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  background: rgba(0,0,0,.55);
  color: var(--sofia-lime);
  padding: 8px 14px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  border: 1px solid rgba(212,255,124,.25);
}

/* --- Static-line bubble ------------------------------------- */
.sofia3d__bubble{
  max-width: 280px;
  background: var(--sofia-glass);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(212,255,124,.25);
  border-radius: 16px;
  padding: 12px 14px 11px;
  color: #fff;
  box-shadow: 0 12px 36px rgba(0,0,0,.4);
  position: relative;
  cursor: pointer;
  order: -1; /* show above avatar */
  animation: bubbleIn .4s cubic-bezier(.2,.7,.2,1);
}
@keyframes bubbleIn{
  from{ opacity:0; transform: translateY(6px) scale(.97); }
  to  { opacity:1; transform: translateY(0)   scale(1);   }
}
.sofia3d__name{
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--sofia-lime);
  margin-bottom: 4px;
}
.sofia3d__text{
  font-size: 13px;
  line-height: 1.45;
  color: rgba(255,255,255,.92);
}
.sofia3d__bubble-tail{
  position: absolute;
  right: 30px;
  bottom: -7px;
  width: 14px; height: 14px;
  background: var(--sofia-glass);
  border-right: 1px solid rgba(212,255,124,.25);
  border-bottom: 1px solid rgba(212,255,124,.25);
  transform: rotate(45deg);
  border-radius: 2px;
}

/* --- Chat panel — position fixed, decoupled from avatar ----- */
.sofia3d__chat{
  position: fixed;
  right: 4%;
  bottom: calc(8% + 300px);    /* sits above the 280px avatar with 20px gap */
  width: min(340px, calc(100vw - 32px));
  max-height: min(420px, calc(100vh - 360px));   /* never overlap or overflow */
  background: var(--sofia-glass);
  backdrop-filter: blur(24px) saturate(160%);
  -webkit-backdrop-filter: blur(24px) saturate(160%);
  border: 1px solid rgba(212,255,124,.28);
  border-radius: 18px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: 0 24px 64px rgba(0,0,0,.55);
  animation: chatIn .35s cubic-bezier(.2,.7,.2,1);
  z-index: 951;
}
/* When chat is open, hide the static bubble to avoid double-stacking */
.sofia3d--chat .sofia3d__bubble{ display:none; }
/* And shrink avatar a bit so chat has clear visual hierarchy */
.sofia3d--chat .sofia3d__avatar-wrap{ transform: scale(.85); transform-origin: bottom right; }
@keyframes chatIn{
  from{ opacity:0; transform: translateY(10px) scale(.97); }
  to  { opacity:1; transform: translateY(0)    scale(1);   }
}
.sofia3d__chat-header{
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  border-bottom: 1px solid rgba(212,255,124,.15);
  background: linear-gradient(180deg, rgba(212,255,124,.08), transparent);
}
.sofia3d__chat-title{
  font-size: 14px;
  font-weight: 700;
  color: var(--sofia-lime);
  letter-spacing: .04em;
}
.sofia3d__chat-close{
  background: transparent;
  border: 0;
  color: rgba(255,255,255,.7);
  font-size: 22px;
  cursor: pointer;
  padding: 0 6px;
  line-height: 1;
}
.sofia3d__chat-close:hover{ color: #fff; }

.sofia3d__chat-body{
  flex: 1;
  overflow-y: auto;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 120px;
  max-height: 320px;
}
.sofia3d__chat-hint{
  font-size: 12px;
  color: rgba(255,255,255,.55);
  text-align: center;
  padding: 8px;
  font-style: italic;
}
.sofia3d__msg{
  display: flex;
  font-size: 13px;
  line-height: 1.45;
  animation: msgIn .25s ease-out;
}
@keyframes msgIn{
  from{ opacity:0; transform: translateY(4px); }
  to  { opacity:1; transform: translateY(0);   }
}
.sofia3d__msg span{
  max-width: 80%;
  padding: 8px 12px;
  border-radius: 14px;
}
.sofia3d__msg--user{
  justify-content: flex-end;
}
.sofia3d__msg--user span{
  background: linear-gradient(135deg, rgba(212,255,124,.18), rgba(212,255,124,.08));
  border: 1px solid rgba(212,255,124,.25);
  color: #fff;
  border-bottom-right-radius: 4px;
}
.sofia3d__msg--assistant span{
  background: rgba(255,255,255,.07);
  border: 1px solid rgba(255,255,255,.1);
  color: rgba(255,255,255,.95);
  border-bottom-left-radius: 4px;
}
.sofia3d__msg--loading span{ padding: 12px 16px; }
.sofia3d__dots{
  display: inline-flex;
  gap: 4px;
}
.sofia3d__dots i{
  width: 6px; height: 6px;
  border-radius: 999px;
  background: var(--sofia-lime);
  display: inline-block;
  animation: dotPulse 1.2s infinite ease-in-out;
}
.sofia3d__dots i:nth-child(2){ animation-delay: .15s; }
.sofia3d__dots i:nth-child(3){ animation-delay: .30s; }
@keyframes dotPulse{
  0%,100%{ opacity:.3; transform: scale(.85); }
  50%    { opacity:1;  transform: scale(1.1);  }
}
.sofia3d__error{
  font-size: 12px;
  color: #ff8898;
  background: rgba(255,80,100,.08);
  border: 1px solid rgba(255,80,100,.2);
  padding: 6px 10px;
  border-radius: 8px;
}

.sofia3d__chat-input{
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 12px;
  border-top: 1px solid rgba(212,255,124,.15);
  background: rgba(0,0,0,.18);
}
.sofia3d__chat-input input{
  flex: 1;
  background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.1);
  border-radius: 999px;
  padding: 9px 14px;
  color: #fff;
  font-size: 13px;
  outline: none;
  transition: border-color .15s ease;
  font-family: inherit;
}
.sofia3d__chat-input input:focus{ border-color: var(--sofia-lime-soft); }
.sofia3d__chat-input input::placeholder{ color: rgba(255,255,255,.4); }
.sofia3d__chat-input input:disabled{ opacity:.5; }

.sofia3d__mic, .sofia3d__send{
  width: 34px; height: 34px;
  border-radius: 999px;
  border: 1px solid rgba(212,255,124,.3);
  background: rgba(212,255,124,.1);
  color: var(--sofia-lime);
  font-size: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s ease, transform .15s ease;
  padding: 0;
}
.sofia3d__mic:hover, .sofia3d__send:hover{
  background: rgba(212,255,124,.22);
  transform: scale(1.06);
}
.sofia3d__mic:disabled, .sofia3d__send:disabled{
  opacity: .4; cursor: not-allowed; transform: none;
}
.sofia3d__mic--rec{
  background: rgba(255,80,100,.25) !important;
  border-color: rgba(255,80,100,.5) !important;
  color: #ff8898 !important;
  animation: recPulse 1s infinite ease-in-out;
}
@keyframes recPulse{
  0%,100%{ box-shadow: 0 0 0 0 rgba(255,80,100,.5); }
  50%    { box-shadow: 0 0 0 8px rgba(255,80,100,0);  }
}

/* --- Top-right floating controls ---------------------------- */
.sofia3d__controls{
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  gap: 4px;
  z-index: 2;
}
.sofia3d__btn{
  width: 30px; height: 30px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,.18);
  background: rgba(15,18,38,.78);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  color: rgba(255,255,255,.92);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background .2s ease, transform .15s ease, color .2s ease, box-shadow .2s ease;
  padding: 0;
}
.sofia3d__btn:hover{
  background: rgba(212,255,124,.22);
  color: #fff;
  transform: scale(1.08);
}
.sofia3d__btn:active{ transform: scale(.96); }
.sofia3d__btn:focus-visible{ outline: 2px solid rgba(212,255,124,.6); outline-offset: 2px; }

/* Mic active — lime glow ring so users can tell at a glance voice is ON. */
.sofia3d__btn--voice-on{
  background: linear-gradient(135deg, rgba(132,204,22,.95), rgba(212,255,124,.9));
  border-color: rgba(212,255,124,.6);
  color: #0a0c1a;
  box-shadow:
    0 0 0 3px rgba(212,255,124,.18),
    0 4px 12px -2px rgba(212,255,124,.45);
}
.sofia3d__btn--voice-on:hover{
  background: linear-gradient(135deg, rgba(132,204,22,1), rgba(212,255,124,1));
  color: #0a0c1a;
}

/* Mic denied — red slash, clickable to retry. Signals to the user that they
   need to fix permission, not that the app is broken. */
.sofia3d__btn--denied{
  background: rgba(220,38,38,.88);
  border-color: rgba(248,113,113,.5);
  color: #fff;
  box-shadow: 0 0 0 3px rgba(220,38,38,.16);
}
.sofia3d__btn--denied:hover{
  background: rgba(220,38,38,1);
  color: #fff;
}

/* Inline error toast — anchored below the top-right controls strip so it
   appears right next to the button the user just tapped. Auto-dismisses after
   6s (handled in JS). Click anywhere on it to dismiss immediately. */
.sofia3d__error{
  position: absolute;
  top: 44px;
  right: 6px;
  max-width: min(220px, calc(100% - 12px));
  padding: 8px 10px;
  border-radius: 10px;
  background: rgba(15,18,38,.92);
  color: #fff;
  font-size: 11.5px;
  line-height: 1.4;
  letter-spacing: -.005em;
  box-shadow:
    0 12px 30px -12px rgba(15,18,38,.6),
    0 0 0 1px rgba(248,113,113,.35);
  cursor: pointer;
  z-index: 3;
  animation: sofiaErrorIn .25s ease-out;
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}
@keyframes sofiaErrorIn{
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --- Mobile -------------------------------------------------- */
@media (max-width: 768px){
  .sofia3d{ right: 3%; bottom: 4%; gap: 8px; }
  .sofia3d__avatar-wrap{ width: 150px; height: 200px; }
  .sofia3d__chat{
    right: 3%;
    bottom: calc(4% + 220px);
    width: calc(100vw - 24px);
    max-height: min(380px, calc(100vh - 260px));
  }
  .sofia3d__bubble{ max-width: 220px; }
}
@media (max-width: 480px){
  .sofia3d__avatar-wrap{ width: 120px; height: 160px; }
  .sofia3d__chat{
    bottom: calc(4% + 180px);
    max-height: min(340px, calc(100vh - 220px));
  }
  .sofia3d__bubble{ max-width: 180px; font-size: 12px; }
}

/* ============================================================
   SCIENCE SECTION — rPPG pipeline (algorithm diagram)
   ============================================================ */
.science-section{
  background: var(--ink-50);
  position: relative;
  overflow: hidden;
}
.science-section::before{
  content: '';
  position: absolute; inset: 0;
  background-image:
    linear-gradient(rgba(99,102,241,.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(99,102,241,.045) 1px, transparent 1px);
  background-size: 32px 32px;
  pointer-events: none;
  mask-image: radial-gradient(ellipse at center, #000 30%, transparent 80%);
  -webkit-mask-image: radial-gradient(ellipse at center, #000 30%, transparent 80%);
}

.science-frame{
  position: relative;
  border-radius: var(--r-xl);
  padding: 56px;
  background:
    radial-gradient(circle at 18% 0%, rgba(34,211,238,.18), transparent 55%),
    radial-gradient(circle at 82% 100%, rgba(168,85,247,.22), transparent 55%),
    linear-gradient(160deg, var(--night-900) 0%, var(--night-800) 60%, var(--night-700) 100%);
  border: 1px solid rgba(255,255,255,.08);
  box-shadow:
    0 50px 120px -40px rgba(99,102,241,.45),
    0 20px 40px -20px rgba(15,18,38,.55),
    inset 0 1px 0 rgba(255,255,255,.06);
  overflow: hidden;
}

.science-blob{
  position: absolute;
  border-radius: 50%;
  filter: blur(80px);
  pointer-events: none;
  opacity: .55;
}
.science-blob-a{
  top: -15%; right: -10%;
  width: 420px; height: 420px;
  background: radial-gradient(circle, rgba(168,85,247,.55), transparent 60%);
}
.science-blob-b{
  bottom: -25%; left: -8%;
  width: 460px; height: 460px;
  background: radial-gradient(circle, rgba(34,211,238,.5), transparent 60%);
}

.science-card{
  position: relative;
  z-index: 1;
  background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
  border-radius: var(--r-lg);
  padding: 24px;
  box-shadow:
    0 30px 80px -20px rgba(0,0,0,.45),
    0 10px 30px -10px rgba(15,18,38,.35),
    inset 0 1px 0 rgba(255,255,255,1);
  border: 1px solid rgba(255,255,255,.6);
}
.science-card-meta{
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  gap: 12px;
  flex-wrap: wrap;
}
.science-card-eyebrow{
  display: inline-flex;
  gap: 10px;
  align-items: center;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-700);
}
.science-dot{
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--grad);
  box-shadow: 0 0 0 4px rgba(99,102,241,.18);
}
.science-tag{
  font-size: 11px;
  letter-spacing: .08em;
  color: var(--ink-500);
  background: var(--ink-100);
  padding: 4px 10px;
  border-radius: 999px;
  text-transform: uppercase;
}
.science-img-wrap{
  background: #fff;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--ink-200);
  padding: 4px;
}
.science-img{
  width: 100%;
  height: auto;
  display: block;
  border-radius: 8px;
}
.science-card-foot{
  margin-top: 14px;
  font-size: 11px;
  color: var(--ink-500);
  text-align: center;
  letter-spacing: .02em;
}

.science-glossary{
  margin-top: 18px;
  padding: 18px 20px 4px;
  background: linear-gradient(180deg, var(--ink-50), #ffffff);
  border: 1px solid var(--ink-200);
  border-radius: 14px;
}
.science-glossary-head{
  margin-bottom: 12px;
  padding-bottom: 10px;
  border-bottom: 1px dashed var(--ink-200);
}
.science-glossary-title{
  font-size: 13px;
  font-weight: 600;
  color: var(--ink-800);
  letter-spacing: -.005em;
  margin-bottom: 2px;
}
.science-glossary-sub{
  font-size: 12px;
  color: var(--ink-500);
}
.science-glossary-list{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0,1fr));
  column-gap: 24px;
  row-gap: 6px;
}
.science-glossary-row{
  display: grid;
  grid-template-columns: minmax(0, 1fr) 14px minmax(0, 1.1fr);
  align-items: baseline;
  gap: 8px;
  padding: 6px 0;
  font-size: 12px;
  border-bottom: 1px dotted var(--ink-200);
}
.science-glossary-row:last-child{ border-bottom: none; }
.science-glossary-en{
  color: var(--ink-500);
  font-size: 11px;
  letter-spacing: .01em;
}
.science-glossary-arrow{
  color: var(--ink-400);
  font-weight: 600;
  text-align: center;
}
.science-glossary-es{
  color: var(--ink-900);
  font-weight: 500;
}

@media (max-width: 720px){
  .science-glossary-list{ grid-template-columns: minmax(0,1fr); }
}

.science-pair{
  display: grid;
  grid-template-columns: minmax(0,1fr);
  gap: 28px;
}
.science-tile{
  margin: 0;
  display: grid;
  grid-template-columns: minmax(0, 280px) minmax(0, 1fr);
  align-items: stretch;
  background: linear-gradient(180deg, #ffffff 0%, #f8fafc 100%);
  border: 1px solid var(--ink-200);
  border-radius: 16px;
  overflow: hidden;
  transition: transform .25s ease, box-shadow .25s ease, border-color .25s ease;
}
.science-tile:hover{
  transform: translateY(-3px);
  border-color: rgba(99,102,241,.35);
  box-shadow:
    0 28px 60px -28px rgba(15,18,38,.45),
    0 8px 22px -12px rgba(99,102,241,.25);
}
.science-tile-cap{
  padding: 28px 26px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  border-right: 1px solid var(--ink-200);
  background:
    radial-gradient(circle at 0% 0%, rgba(168,85,247,.05), transparent 60%),
    linear-gradient(180deg, #ffffff, #f8fafc);
}
.science-tile-kicker{
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}
.science-tile-title{
  font-size: 22px;
  font-weight: 600;
  color: var(--ink-900);
  letter-spacing: -.015em;
  line-height: 1.2;
}
.science-tile-body{
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-500);
}
.science-tile-img-wrap{
  background:
    radial-gradient(circle at 50% 0%, rgba(99,102,241,.06), transparent 60%),
    #ffffff;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 320px;
}
.science-tile-img{
  width: 100%;
  height: auto;
  display: block;
  border-radius: 0;
}

@media (max-width: 900px){
  .science-pair{ gap: 22px; }
  .science-tile{
    grid-template-columns: minmax(0,1fr);
  }
  .science-tile-cap{
    border-right: none;
    border-bottom: 1px solid var(--ink-200);
    padding: 22px 22px 20px;
  }
  .science-tile-title{ font-size: 19px; }
  .science-tile-img-wrap{ min-height: unset; }
}
@media (max-width: 480px){
  .science-tile-cap{ padding: 18px 18px 16px; }
  .science-tile-title{ font-size: 17px; }
}

.science-steps{
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(4, minmax(0,1fr));
  gap: 14px;
  margin-top: 28px;
}
.science-step{
  background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.08);
  border-radius: var(--r-md);
  padding: 18px 18px 20px;
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: transform .25s ease, border-color .25s ease, background .25s ease;
}
.science-step:hover{
  transform: translateY(-2px);
  border-color: rgba(99,102,241,.45);
  background: rgba(255,255,255,.06);
}
.science-step-num{
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .14em;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  margin-bottom: 10px;
}
.science-step-title{
  font-size: 14px;
  font-weight: 600;
  color: #fff;
  margin-bottom: 6px;
  letter-spacing: -.005em;
}
.science-step-body{
  font-size: 13px;
  line-height: 1.55;
  color: rgba(255,255,255,.7);
}

@media (max-width: 900px){
  .science-frame{ padding: 32px 20px; }
  .science-steps{ grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 480px){
  .science-frame{ padding: 24px 16px; border-radius: var(--r-lg); }
  .science-card{ padding: 14px; }
  .science-card-meta{ margin-bottom: 12px; }
  .science-steps{ grid-template-columns: minmax(0,1fr); gap: 10px; margin-top: 20px; }
  .science-step{ padding: 14px 16px 16px; }
}

/* --- V2/V4 proactive bubble: pop-in + ring pulse to signal Sofía spoke first.
       Overrides the .sofia3d--hero rule that hides the bubble in hero mode,
       since in proactive variants the bubble IS the protagonism signal. --- */
.sofia3d--hero.sofia3d--proactive .sofia3d__bubble{
  display: block !important;
  animation: bubblePop .6s cubic-bezier(.34, 1.56, .64, 1);
  transform-origin: bottom right;
  position: relative;
}
.sofia3d--hero.sofia3d--proactive .sofia3d__bubble::after{
  content: '';
  position: absolute;
  inset: -6px;
  border-radius: 22px;
  border: 2px solid rgba(168, 85, 247, .55);
  animation: bubblePulseRing 1.8s ease-out infinite;
  pointer-events: none;
}
@keyframes bubblePop{
  0%   { transform: scale(.5) translateY(20px); opacity: 0; }
  60%  { transform: scale(1.08) translateY(0);  opacity: 1; }
  100% { transform: scale(1)    translateY(0);  opacity: 1; }
}
@keyframes bubblePulseRing{
  0%   { transform: scale(1);    opacity: .8; }
  100% { transform: scale(1.18); opacity: 0;  }
}

/* ============================================================================
   USER DRAGGABLE WIDGET — drag Sofia anywhere on viewport with finger/mouse.
   Applied when JS sets the `sofia3d--dragged` class (after user moves the
   widget). Position stored in CSS custom properties `--drag-x` and `--drag-y`
   (px from top-left). Position persists across sessions via localStorage in
   sofia.jsx. Disabled in hero mode (landing screen owns positioning via JS).

   Specificity: tripled class names raise specificity to (0,0,3,0), then
   !important wins against the @media (max-width:768px) bottom/right !important
   rules at lines 706-718 of this file. Without both tricks, those mobile
   rules win and the user's dragged position has no effect.
============================================================================ */
.sofia3d:not(.sofia3d--hero){
  cursor: grab;
  touch-action: none; /* prevent page scroll while dragging Sofia */
  user-select: none;
  -webkit-user-select: none;
}
/* GPU-only positioning: translate3d is composited (no layout / paint cost),
   unlike top/left which forces the compositor to re-position the layer every
   frame. On iOS Safari with multiple animated blobs + filter:blur, top/left
   dragging stuttered visibly; transform delivers ~120fps smooth. */
/* Exclude hero (landing) — its positioning is JS-driven via #sofia-hero-slot.
   Without :not(.sofia3d--hero), a saved drag position from another screen
   (lazy-init useState in sofia.jsx reads localStorage on mount) keeps the
   --dragged class on the element in landing too, and this !important rule
   wins over .sofia3d--hero (specificity 0,0,3,0 vs 0,0,1,0), teleporting
   Sofía to top-left (--drag-x/y unset in hero → fallback 0px). */
.sofia3d:not(.sofia3d--hero).sofia3d--dragged.sofia3d--dragged.sofia3d--dragged{
  top: 0 !important;
  left: 0 !important;
  right: auto !important;
  bottom: auto !important;
  transform: translate3d(var(--drag-x, 0px), var(--drag-y, 0px), 0) !important;
  /* Smooth settle after release; overridden to none during active drag below */
  transition: transform 0.18s cubic-bezier(.22,1,.36,1);
  will-change: transform;
}
.sofia3d.sofia3d--dragging.sofia3d--dragging.sofia3d--dragging{
  cursor: grabbing;
  transition: none !important; /* instant follow during active drag */
  filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.28));
  z-index: 99999 !important;
}
/* Drag perf: pause the orb's blob/rim/breath animations while actively dragging
   so the GPU isn't compositing 4 blob translations + conic rotation + breath
   scale + filter:blur all at once on top of the user's drag transform. The
   visual change is barely perceptible (<200ms typical drag) but the framerate
   gain on mid-range Android / older iPhones is dramatic. */
.sofia3d--dragging .sofia3d__orb-circle,
.sofia3d--dragging .sofia3d__orb-circle::after,
.sofia3d--dragging .sofia3d__orb-blob{
  animation-play-state: paused !important;
}
.sofia3d--dragging .sofia3d__orb-blobs{
  filter: blur(8px) saturate(140%); /* lighter blur radius during drag */
}
/* Hero (landing) never participates in drag */
.sofia3d--hero{
  cursor: default;
  touch-action: auto;
}

/* ============ Dashboard polish — CTA card + stats + tabs ============ */

/* Primary CTA card — the dark gradient card on the dashboard greeting row.
   Replaces the previous inline-styled card with a more deliberate hierarchy:
   eyebrow → title → meta → BIG button. The button is the visual anchor. */
.dash-cta-card{
  position: relative;
  padding: 26px 28px 22px;
  border-radius: var(--r-lg);
  background:
    radial-gradient(circle at 10% 0%, rgba(168,85,247,.22), transparent 55%),
    radial-gradient(circle at 100% 100%, rgba(34,211,238,.16), transparent 55%),
    linear-gradient(135deg, #0a0c1a 0%, #161a3a 55%, #1e2455 100%);
  color: #fff;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 20px;
  box-shadow:
    0 28px 70px -30px rgba(15,18,38,.55),
    0 10px 28px -14px rgba(99,102,241,.30);
  border: 1px solid rgba(255,255,255,.08);
}
.dash-cta-glow{
  position: absolute;
  border-radius: 50%;
  filter: blur(50px);
  pointer-events: none;
  opacity: .55;
}
.dash-cta-glow-a{
  top: -40%; right: -10%;
  width: 240px; height: 240px;
  background: radial-gradient(circle, rgba(168,85,247,.5), transparent 60%);
}
.dash-cta-glow-b{
  bottom: -40%; left: -8%;
  width: 200px; height: 200px;
  background: radial-gradient(circle, rgba(34,211,238,.35), transparent 60%);
}
.dash-cta-head{
  position: relative;
  z-index: 1;
}
.dash-cta-eyebrow{
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(255,255,255,.6);
  font-weight: 600;
  margin-bottom: 8px;
}
.dash-cta-title{
  font-size: 22px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -.01em;
  margin-bottom: 8px;
  color: #fff;
}
.dash-cta-meta{
  font-size: 12px;
  letter-spacing: .04em;
  color: rgba(255,255,255,.65);
}

/* Prominent action — gradient bg, glow shadow, lift on hover. */
.dash-cta-btn{
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border: 0;
  border-radius: 14px;
  background: linear-gradient(135deg, #6366f1 0%, #a855f7 55%, #ec4899 100%);
  color: #fff;
  cursor: pointer;
  font: inherit;
  text-align: left;
  box-shadow:
    0 18px 45px -18px rgba(168,85,247,.65),
    0 6px 18px -10px rgba(99,102,241,.55),
    inset 0 1px 0 rgba(255,255,255,.22);
  transition: transform .22s ease, box-shadow .22s ease, filter .22s ease;
  width: 100%;
}
.dash-cta-btn:hover{
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow:
    0 24px 55px -18px rgba(168,85,247,.78),
    0 10px 24px -10px rgba(236,72,153,.5),
    inset 0 1px 0 rgba(255,255,255,.28);
}
.dash-cta-btn:active{ transform: translateY(0); }
.dash-cta-btn:focus-visible{ outline: 2px solid #fff; outline-offset: 3px; }

.dash-cta-btn-icon{
  width: 42px; height: 42px;
  border-radius: 11px;
  background: rgba(255,255,255,.18);
  border: 1px solid rgba(255,255,255,.25);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: #fff;
}
.dash-cta-btn-label{
  flex: 1;
  min-width: 0;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -.005em;
  line-height: 1.2;
  color: #fff;
}
.dash-cta-btn-arrow{
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: rgba(255,255,255,.85);
  transition: transform .22s ease;
}
.dash-cta-btn:hover .dash-cta-btn-arrow{ transform: translateX(4px); }

@media (max-width: 900px){
  .dash-cta-card{ padding: 22px 22px 20px; gap: 16px; }
  .dash-cta-title{ font-size: 20px; }
  .dash-cta-btn{ padding: 12px 14px; }
  .dash-cta-btn-icon{ width: 38px; height: 38px; }
  .dash-cta-btn-label{ font-size: 15px; }
}

/* Stat cards — subtle hover lift, so the user can see they're cards (and
   read the focus state without confusing them with the primary CTA). */
.biometric-widget, .card[style*="biometric-widget"]{
  /* leave existing biometric widget rules alone */
}
.dash-stat{
  transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.dash-stat:hover{
  transform: translateY(-1px);
  border-color: rgba(99,102,241,.25);
  box-shadow: 0 12px 28px -16px rgba(15,18,38,.25);
}

/* Tabs row — pill-style indicator with smoother active state. */
.dash-tabs{
  display: flex;
  gap: 4px;
  padding: 4px;
  background: var(--ink-100);
  border-radius: 12px;
  margin-bottom: 22px;
  overflow-x: auto;
}
.dash-tab{
  flex: 1;
  min-width: 0;
  padding: 10px 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  color: var(--ink-500);
  border-radius: 8px;
  transition: background .2s ease, color .2s ease, box-shadow .2s ease;
}
.dash-tab:hover{ color: var(--ink-800); }
.dash-tab.is-active{
  background: var(--paper);
  color: var(--ink-900);
  box-shadow: 0 4px 12px -4px rgba(15,18,38,.12), 0 1px 2px rgba(15,18,38,.06);
}

/* ============================================================================
   Sofía idle-orb mode — Siri-style ambient orb that takes over the widget
   when there's been no interaction for 30s. Stops the WebRTC stream to save
   credits and waits for "Oye Sofía" wake-word OR a tap to re-summon her.
   ============================================================================ */

/* Force orb mode into a small fixed-bottom-right widget regardless of which
   anchor (hero / top-right / drag) was active before. Smooth transition for
   the size collapse. */
.sofia3d--idle-orb{
  width: 132px !important;
  height: 158px !important;
  max-width: 132px !important;
  max-height: 158px !important;
  position: fixed !important;
  right: 16px !important;
  bottom: 16px !important;
  top: auto !important;
  left: auto !important;
  transform: none !important;
  transition: width .4s cubic-bezier(.4,0,.2,1),
              height .4s cubic-bezier(.4,0,.2,1),
              right .4s cubic-bezier(.4,0,.2,1),
              bottom .4s cubic-bezier(.4,0,.2,1);
}
.sofia3d--idle-orb .sofia3d__avatar-wrap{
  width: 132px !important;
  height: 132px !important;
  max-width: 132px !important;
  max-height: 132px !important;
  border-radius: 50% !important;
  background: radial-gradient(ellipse at 50% 30%, rgba(99,102,241,.18) 0%, rgba(15,17,30,.55) 70%);
  overflow: visible !important;
  transition: width .4s cubic-bezier(.4,0,.2,1), height .4s cubic-bezier(.4,0,.2,1), border-radius .4s ease;
}

/* Sofía visuals dissolve: scale-collapse + heavy blur + desaturation. The
   "she disintegrates" feel. opacity 1→0 + scale 1→.35 over 380ms. */
.sofia3d--idle-orb .sofia3d__pose-img,
.sofia3d--idle-orb .sofia3d__live-stream,
.sofia3d--idle-orb .sofia3d__hero-canvas,
.sofia3d--idle-orb .sofia3d__hero-video-source,
.sofia3d--idle-orb .sofia3d__live-badge,
.sofia3d--idle-orb .sofia3d__hint,
.sofia3d--idle-orb .sofia3d__bubble,
.sofia3d--idle-orb .sofia3d__voice-ring,
.sofia3d--idle-orb .sofia3d__voice-label,
.sofia3d--idle-orb .sofia3d__pulse{
  opacity: 0 !important;
  transform: scale(.35);
  filter: blur(14px) saturate(.3);
  pointer-events: none !important;
  transition: opacity .38s ease-in, transform .38s cubic-bezier(.6,0,.8,.3), filter .38s ease-in;
}

/* The orb itself — multi-gradient ambient sphere, ~88px, soft halos. */
.sofia3d__orb{
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  opacity: 0;
  transform: scale(.6);
  pointer-events: none;
  transition: opacity .42s ease-out,
              transform .55s cubic-bezier(.34,1.56,.64,1);
  z-index: 8;
}
.sofia3d--idle-orb .sofia3d__orb{
  opacity: 1;
  transform: scale(1);
  pointer-events: auto;
}

/* Container is a plain div now (not button) — tap-to-wake is disabled per
   product spec; voice-only invocation via "Oye Sofía". Drag still works
   because it's wired at the .sofia3d outer level. */
.sofia3d__orb-btn{
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  -webkit-tap-highlight-color: transparent;
  pointer-events: none; /* drag handler on parent owns gestures */
  user-select: none;
}

/* ----------------------------------------------------------------------------
   Holographic Sofía orb. Pure CSS+SVG, zero canvas/WebGL.
   Stack (bottom → top):
     1. Nebula blobs (deep, blurred — the "energy plasma" inside the sphere)
     2. Sparkle particles (small twinkling dots — the "life signs")
     3. Glassy highlight (::before, top reflection — gives 3D depth)
     4. Infinity glyph (SVG, brand-gradient stroke — the soul)
     5. Chromatic ring (::after, rotating conic — the holo halo signature)
   Each layer animates independently so it feels alive, not painted.
   ---------------------------------------------------------------------------- */
.sofia3d__orb-circle{
  position: relative;
  width: 112px;
  height: 112px;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 42%, rgba(14,18,40,.85) 0%, rgba(3,5,16,.97) 78%);
  box-shadow:
    0 0 0 1px rgba(255,255,255,.06) inset,
    0 0 28px 6px rgba(99,102,241,.38),
    0 0 60px 18px rgba(168,85,247,.20),
    0 12px 32px rgba(0,0,0,.6);
  overflow: hidden;
  isolation: isolate;
  animation: sofiaOrbBreath 4.2s ease-in-out infinite;
}

/* Nebula plasma — kept blurred + behind everything for "energy" depth */
.sofia3d__orb-blobs{
  position: absolute;
  inset: -6%;
  filter: blur(12px) saturate(170%);
  pointer-events: none;
  z-index: 1;
  opacity: .8;
}
.sofia3d__orb-blob{
  position: absolute;
  width: 62%;
  height: 62%;
  border-radius: 50%;
  mix-blend-mode: screen;
  will-change: transform;
  opacity: .85;
}
.sofia3d__orb-blob--1{
  background: radial-gradient(circle, #93c5fd 0%, rgba(59,130,246,.65) 35%, transparent 70%);
  top: 8%; left: 6%;
  animation: sofiaBlob1 7.5s ease-in-out infinite;
}
.sofia3d__orb-blob--2{
  background: radial-gradient(circle, #c084fc 0%, rgba(168,85,247,.70) 35%, transparent 70%);
  top: 30%; left: 38%;
  animation: sofiaBlob2 6.2s ease-in-out infinite;
}
.sofia3d__orb-blob--3{
  background: radial-gradient(circle, #fbcfe8 0%, rgba(236,72,153,.55) 35%, transparent 70%);
  top: 50%; left: 12%;
  animation: sofiaBlob3 8.4s ease-in-out infinite;
}
.sofia3d__orb-blob--4{
  background: radial-gradient(circle, #67e8f9 0%, rgba(34,211,238,.55) 35%, transparent 70%);
  top: 18%; left: 50%;
  animation: sofiaBlob4 5.6s ease-in-out infinite;
}

/* Sparkles — small twinkling dots scattered inside the sphere. "Life signs". */
.sofia3d__orb-sparkles{
  position: absolute;
  inset: 4%;
  pointer-events: none;
  z-index: 2;
}
.sofia3d__orb-sparkles > i{
  position: absolute;
  width: 2.4px;
  height: 2.4px;
  border-radius: 50%;
  background: radial-gradient(circle, #ffffff 0%, rgba(186,230,253,.65) 45%, transparent 100%);
  box-shadow: 0 0 4px rgba(186,230,253,.85);
  opacity: .25;
  animation: sofiaOrbSparkle 2.6s ease-in-out infinite;
}
.sofia3d__orb-sparkles > i:nth-child(1){ top: 22%; left: 28%; animation-delay: 0s;    }
.sofia3d__orb-sparkles > i:nth-child(2){ top: 38%; left: 72%; animation-delay: .35s;  width: 1.8px; height: 1.8px; }
.sofia3d__orb-sparkles > i:nth-child(3){ top: 60%; left: 22%; animation-delay: .75s;  width: 2.8px; height: 2.8px; }
.sofia3d__orb-sparkles > i:nth-child(4){ top: 74%; left: 64%; animation-delay: 1.15s; }
.sofia3d__orb-sparkles > i:nth-child(5){ top: 44%; left: 84%; animation-delay: 1.55s; width: 1.6px; height: 1.6px; }
.sofia3d__orb-sparkles > i:nth-child(6){ top: 80%; left: 40%; animation-delay: 1.95s; }
.sofia3d__orb-sparkles > i:nth-child(7){ top: 14%; left: 58%; animation-delay: 2.3s;  width: 1.6px; height: 1.6px; }
@keyframes sofiaOrbSparkle{
  0%,100%{ opacity: .15; transform: scale(.6); }
  50%   { opacity: 1;   transform: scale(1.4); }
}

/* Infinity ∞ glyph — the soul of the orb. SVG path is Lucide's `infinity`
   (Heroicon-style, clean cubic curves). Stroke uses a linear brand gradient
   and a double drop-shadow for that "neon glow on glass" feel. Gentle pulse
   so it looks like it's BREATHING, not a static logo. */
.sofia3d__orb-infinity{
  position: absolute;
  width: 62px;
  height: 62px;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  z-index: 4;
  filter:
    drop-shadow(0 0 4px rgba(168,85,247,.85))
    drop-shadow(0 0 10px rgba(34,211,238,.55));
  animation: sofiaInfPulse 3.2s ease-in-out infinite;
  overflow: visible;
}
.sofia3d__orb-infinity path{
  fill: none;
  stroke: url(#sofiaInfGradient);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
@keyframes sofiaInfPulse{
  0%,100%{
    transform: translate(-50%, -50%) scale(1);
    filter: drop-shadow(0 0 4px rgba(168,85,247,.85)) drop-shadow(0 0 10px rgba(34,211,238,.55));
  }
  50%{
    transform: translate(-50%, -50%) scale(1.08);
    filter: drop-shadow(0 0 7px rgba(168,85,247,1)) drop-shadow(0 0 16px rgba(34,211,238,.85));
  }
}

@keyframes sofiaBlob1{
  0%,100%{ transform: translate(0,0) scale(1); }
  33%   { transform: translate(18%, 24%) scale(1.18); }
  66%   { transform: translate(-12%, 32%) scale(.86); }
}
@keyframes sofiaBlob2{
  0%,100%{ transform: translate(0,0) scale(1); }
  50%   { transform: translate(-22%, -18%) scale(1.25); }
}
@keyframes sofiaBlob3{
  0%,100%{ transform: translate(0,0) scale(1); }
  33%   { transform: translate(20%, -24%) scale(1.10); }
  66%   { transform: translate(-18%, 12%) scale(.88); }
}
@keyframes sofiaBlob4{
  0%,100%{ transform: translate(0,0) scale(1); }
  25%   { transform: translate(-14%, 22%) scale(1.15); }
  75%   { transform: translate(26%, -14%) scale(.92); }
}

/* Glassy top highlight — subtle 3D depth */
.sofia3d__orb-circle::before{
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(ellipse 70% 50% at 50% 18%, rgba(255,255,255,.32) 0%, rgba(255,255,255,.06) 30%, transparent 55%);
  pointer-events: none;
  z-index: 3;
  mix-blend-mode: screen;
}

/* Rotating conic rim — the Siri rainbow halo signature */
.sofia3d__orb-circle::after{
  content: '';
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  background: conic-gradient(from 0deg,
    rgba(99,102,241,.95) 0%,
    rgba(168,85,247,.95) 25%,
    rgba(236,72,153,.95) 50%,
    rgba(34,211,238,.95) 75%,
    rgba(99,102,241,.95) 100%);
  -webkit-mask: radial-gradient(circle, transparent calc(50% - 2.5px), #000 calc(50% - 1.5px));
          mask: radial-gradient(circle, transparent calc(50% - 2.5px), #000 calc(50% - 1.5px));
  animation: sofiaOrbRim 9s linear infinite;
  pointer-events: none;
  z-index: 4;
  opacity: .85;
}
@keyframes sofiaOrbRim{
  to { transform: rotate(360deg); }
}

@keyframes sofiaOrbBreath{
  0%,100%{ transform: scale(1);     filter: brightness(1); }
  50%   { transform: scale(1.035);  filter: brightness(1.12); }
}

/* Listening state — VAD picked up voice. Everything intensifies: ring spins
   faster, plasma accelerates, sparkles flicker harder, infinity glow blazes,
   sphere breathes deeper. The orb literally responds to the user. */
.sofia3d__orb-circle--listening{
  animation: sofiaOrbBreathFast 1.6s ease-in-out infinite;
  box-shadow:
    0 0 0 1px rgba(255,255,255,.30) inset,
    0 0 36px 10px rgba(168,85,247,.65),
    0 0 80px 26px rgba(99,102,241,.40),
    0 10px 30px rgba(0,0,0,.55);
}
.sofia3d__orb-circle--listening::after{
  animation-duration: 3s;
  opacity: 1;
}
.sofia3d__orb-circle--listening .sofia3d__orb-blob--1{ animation-duration: 2.5s; }
.sofia3d__orb-circle--listening .sofia3d__orb-blob--2{ animation-duration: 2.1s; }
.sofia3d__orb-circle--listening .sofia3d__orb-blob--3{ animation-duration: 2.8s; }
.sofia3d__orb-circle--listening .sofia3d__orb-blob--4{ animation-duration: 1.9s; }
.sofia3d__orb-circle--listening .sofia3d__orb-sparkles > i{
  animation-duration: 1s;
}
.sofia3d__orb-circle--listening .sofia3d__orb-infinity{
  animation-duration: 1.4s;
}

@keyframes sofiaOrbBreathFast{
  0%,100%{ transform: scale(1.02); }
  50%   { transform: scale(1.12); }
}

/* External pulse ripple — outside the orb body, signals "active listening" */
.sofia3d__orb-ripple{
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 2px solid rgba(168,85,247,.65);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
}
.sofia3d__orb-circle--listening + .sofia3d__orb-ripple,
.sofia3d__orb-circle--listening .sofia3d__orb-ripple{
  animation: sofiaOrbRipple 1.4s ease-out infinite;
}
@keyframes sofiaOrbRipple{
  0%   { transform: scale(1);    opacity: .85; }
  100% { transform: scale(1.50); opacity: 0;   }
}

/* Caption: "Di 'Oye Sofía' para invocarla" — soft 2-line label below the orb.
   Lives outside the .sofia3d__avatar-wrap so it can extend wider than 132px. */
.sofia3d__orb-caption{
  font-size: 10.5px;
  font-weight: 600;
  line-height: 1.3;
  color: rgba(255,255,255,.92);
  text-align: center;
  letter-spacing: .01em;
  max-width: 140px;
  margin-top: 2px;
  text-shadow:
    0 1px 6px rgba(0,0,0,.55),
    0 0 12px rgba(99,102,241,.35);
  pointer-events: none;
  user-select: none;
  white-space: normal;
  animation: sofiaOrbCaptionFade .5s ease-out .2s both;
}
.sofia3d__orb-caption b{
  color: #f5d0fe;
  font-weight: 700;
}
@keyframes sofiaOrbCaptionFade{
  from{ opacity: 0; transform: translateY(4px); }
  to  { opacity: 1; transform: translateY(0); }
}

/* The .sofia3d controls bar and pulse are suppressed in idle-orb. */
.sofia3d--idle-orb .sofia3d__controls,
.sofia3d--idle-orb .sofia3d__error{
  display: none !important;
}

/* Mobile tweak: orb slightly bigger so tap target is comfortable on small phones */
@media (max-width: 380px){
  .sofia3d--idle-orb{ width: 130px !important; height: 162px !important; }
  .sofia3d--idle-orb .sofia3d__avatar-wrap{ width: 130px !important; height: 130px !important; }
  .sofia3d__orb-circle{ width: 100px; height: 100px; }
  .sofia3d__orb-infinity{ width: 54px; height: 54px; }
  .sofia3d__orb-caption{ font-size: 10px; max-width: 134px; }
}

/* ============================================================================
   PRE-ROLL VIDEO INTRO
   Plays once per browser session on first landing visit. Sofía saludates
   verbally in the video while LiveAvatar connects silently in background.
   On `ended` we trigger the Thanos-style disintegration filter (SVG above
   in the JSX) for 1.5s, then fade-in/scale-in the real LiveAvatar.
============================================================================ */
/* Full-width, fixed at top of landing. Rendered via React Portal to <body>
   to escape the .sofia3d wrapper's transform containing-block (without the
   portal, position:fixed gets re-anchored to the 160×215 widget bbox and the
   video appears clipped). 16:9 aspect-ratio so it shows complete (no crop). */
.sofia-preroll{
  position: absolute;
  top: 110px;
  left: 0;
  right: 0;
  margin: 0 auto;          /* center without a transform stacking context */
  width: calc(100% - 64px);
  max-width: 1100px;
  aspect-ratio: 16 / 9;
  z-index: 9000;
  background: #000;
  border-radius: 24px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 22px 60px -28px rgba(99, 102, 241, 0.55);
  contain: layout paint;
}
.sofia-preroll__video{
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: #000;
  border-radius: inherit;
  /* Single GPU-layer hint — translateZ alone is enough to promote. Stacking
     extra will-change/backface hints can over-allocate VRAM and force a
     spill to software compositing on integrated GPUs. */
  transform: translateZ(0);
}
/* Floating "Live" pill — anchored over the top edge of the card, like the
   landing's existing "En vivo · Conoce a Sofía" indicator. */
.sofia-preroll__pill{
  position: absolute;
  top: -22px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 16px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  color: #1e1b4b;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.2px;
  z-index: 9050;
  box-shadow: 0 4px 12px -4px rgba(15, 18, 38, 0.3);
  /* No backdrop-filter — it forced GPU re-sampling of pixels behind the pill
     on every video frame, causing visible jank. Solid bg only. */
  pointer-events: none;
}
.sofia-preroll__pill-dot{
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: linear-gradient(135deg, #22d3ee, #a855f7);
  box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.18);
}
/* Netflix-style explicit play button. Sits dead-center over the video poster
   until clicked. One click = play + audio on + mic permission (via the
   first-gesture useEffect listener that also fires on this click). */
.sofia-preroll__cta{
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 18px 32px 18px 26px;
  border-radius: 999px;
  border: 2px solid rgba(255,255,255,0.85);
  background: linear-gradient(135deg, rgba(99,102,241,0.95), rgba(168,85,247,0.95));
  color: #fff;
  font-family: inherit;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: 0.3px;
  cursor: pointer;
  box-shadow:
    0 18px 48px -12px rgba(99,102,241,0.55),
    0 8px 24px -6px rgba(0,0,0,0.5),
    inset 0 1px 0 rgba(255,255,255,0.25);
  z-index: 9100;
}
.sofia-preroll__cta:hover{
  transform: translate(-50%, -50%) scale(1.03);
}
.sofia-preroll__cta:active{
  transform: translate(-50%, -50%) scale(0.97);
}
.sofia-preroll__cta--loading{
  cursor: progress;
  opacity: 0.85;
}
.sofia-preroll__cta--loading:hover{
  transform: translate(-50%, -50%) scale(1);
}
.sofia-preroll__cta:disabled{
  pointer-events: none;
}
.sofia-preroll__cta-spinner{
  width: 24px;
  height: 24px;
  border: 2.5px solid rgba(255,255,255,0.25);
  border-top-color: #fff;
  border-radius: 50%;
  animation: sofia-preroll-spin 0.8s linear infinite;
}
/* Bottom progress strip inside the CTA pill — tracks blob download. */
.sofia-preroll__cta-progress{
  position: absolute;
  left: 0;
  bottom: 0;
  height: 3px;
  background: rgba(255,255,255,0.9);
  border-radius: 0 0 999px 999px;
  transition: width 0.18s ease-out;
  max-width: 100%;
  pointer-events: none;
}
@keyframes sofia-preroll-spin{
  to { transform: rotate(360deg); }
}
.sofia-preroll__cta-icon{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: rgba(255,255,255,0.18);
  border: 1.5px solid rgba(255,255,255,0.4);
  padding-left: 3px; /* optical center of triangle */
}
.sofia-preroll__cta-label{
  white-space: nowrap;
}
/* Contextual subtitle below the play button — gives the user a clear
   expectation ("15 seconds, this is your guide") before they tap play.
   Adds the polish that elevates the card from utility to product. */
.sofia-preroll__subtitle{
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.3px;
  color: rgba(255,255,255,0.78);
  text-shadow: 0 1px 6px rgba(0,0,0,0.4);
  white-space: nowrap;
  pointer-events: none;
  z-index: 9050;
}
@media (max-width: 640px){
  .sofia-preroll__subtitle{
    font-size: 11px;
    bottom: 16px;
  }
}
/* Hidden SVG def container — holds the Thanos filter, off the rendering grid. */
.sofia-preroll__svgdef{
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
  pointer-events: none;
}

/* Thanos-snap disintegration when the video ends. The SVG <feDisplacementMap>
   `scale` animates 0→80 over 1.5s (begun via JS beginElement()), tearing the
   final video frame into a fractal-noise cloud. Simultaneously the video and
   pill drift upward + fade out so the whole card evaporates. After the 1.5s
   timeout, React unmounts the portal entirely and Sofía's LiveAvatar widget
   takes its place. */
.sofia-preroll--fading{
  pointer-events: none;
}
.sofia-preroll--fading .sofia-preroll__video{
  filter: url(#thanos-disintegrate);
  animation: sofia-preroll-evaporate 1.5s cubic-bezier(0.4, 0, 0.7, 0.3) forwards;
}
.sofia-preroll--fading .sofia-preroll__pill{
  animation: sofia-preroll-evaporate 1.2s cubic-bezier(0.4, 0, 0.7, 0.3) forwards;
}
@keyframes sofia-preroll-evaporate{
  0%   { opacity: 1; transform: translateY(0) scale(1); }
  55%  { opacity: 0.7; transform: translateY(-14px) scale(1.03); }
  100% { opacity: 0; transform: translateY(-44px) scale(1.06); }
}
/* Card outer fade so the box-shadow / rounded edge also dissolves */
.sofia-preroll--fading{
  animation: sofia-preroll-card-fade 1.5s ease-in forwards;
}
@keyframes sofia-preroll-card-fade{
  0%, 60% { opacity: 1; }
  100%    { opacity: 0; }
}
/* Mobile premium UX — designed to feel like a transnational SaaS, not a
   placeholder. Tighter margins, gradient brand background, pill anchored
   INSIDE the card top edge (mobile viewport scroll wouldn't show a floating
   pill above), CTA prominent + a contextual subtitle. */
@media (max-width: 640px){
  .sofia-preroll{
    top: 80px;
    width: calc(100% - 16px);
    border-radius: 22px;
    background:
      linear-gradient(135deg, #0a0c1a 0%, #1e1b4b 40%, #4c1d95 100%);
    box-shadow:
      0 24px 64px -20px rgba(99,102,241,0.6),
      0 4px 16px -4px rgba(15,18,38,0.4),
      0 0 0 1px rgba(255,255,255,0.08) inset;
  }
  .sofia-preroll__pill{
    /* Anchored INSIDE the card on mobile (top:14px) so it's visible regardless
       of where the user scrolls — no risk of being cut by the iOS nav bar. */
    top: 14px;
    font-size: 11px;
    padding: 6px 14px;
    background: rgba(255,255,255,0.96);
    box-shadow: 0 4px 14px -4px rgba(15,18,38,0.4);
  }
  .sofia-preroll__cta{
    padding: 16px 30px 16px 24px;
    font-size: 17px;
    gap: 14px;
    border-width: 1.5px;
    box-shadow:
      0 20px 50px -14px rgba(99,102,241,0.7),
      0 10px 28px -8px rgba(168,85,247,0.5),
      inset 0 1px 0 rgba(255,255,255,0.3);
  }
  .sofia-preroll__cta-icon{
    width: 42px;
    height: 42px;
    background: rgba(255,255,255,0.22);
  }
  .sofia-preroll__cta-icon svg{
    width: 28px;
    height: 28px;
  }
}
/* NUCLEAR ISOLATION while pre-roll is active.
   Goal: eliminate every GPU/CPU cycle competing with the video decoder.
   The video element lives inside .sofia-preroll (portal in <body>); literally
   everything ELSE on the page is frozen for the 15s the intro plays. */

/* Pull the entire LiveAvatar widget tree OUT of layout — display:none kills
   layout, paint, AND any internal animations/effects (CSS or JS-driven via
   IntersectionObserver since the element no longer renders). */
.sofia3d--preroll{
  display: none !important;
}

/* Pause every CSS animation + transition on the whole page. Filter blurs,
   gradient drifts, hero pulse rings, blob metaballs — all halted. The only
   exception is the pre-roll itself (its CTA spinner + progress bar). */
body.preroll-active *,
body.preroll-active *::before,
body.preroll-active *::after{
  animation-play-state: paused !important;
  transition: none !important;
}
body.preroll-active .sofia-preroll,
body.preroll-active .sofia-preroll *,
body.preroll-active .sofia-preroll *::before,
body.preroll-active .sofia-preroll *::after{
  animation-play-state: running !important;
}
