/* ════════════════════════════════════════════════════════════════
   ANIMACIONES · entradas de fragments, cascadas, ECG, ambiente
   Filosofía: el contenido aparece a medida que se habla.
   ════════════════════════════════════════════════════════════════ */

/* ── ENTRADAS DE FRAGMENT (versión agresiva: 3D, zoom y resorte) ──
   Reveal añade .visible al mostrar. Estas reemplazan la animación default. */
.reveal .fragment.fade-up,
.reveal .fragment.fade-left,
.reveal .fragment.fade-right,
.reveal .fragment.zoom-in,
.reveal .fragment.blur-in,
.reveal .fragment.rise-pop,
.reveal .fragment.flip-in,
.reveal .fragment.swing-in,
.reveal .fragment.zoom-punch,
.reveal .fragment.spin-in,
.reveal .fragment.drop-in {
  opacity: 0;
  transition: opacity .6s var(--ease-out), transform .72s var(--ease-spring), filter .6s var(--ease-out);
  transform-origin: center;
  /* Sin backface-visibility persistente: forzaría una capa GPU permanente y, sobre el deck
     escalado (1280×720 → scale()), el fragment se rasteriza a 1× y queda borroso en reposo.
     Los flips animan a rotaciones <90°, así que el reverso nunca queda a la vista. */
}
.reveal .fragment.fade-up    { transform: perspective(1600px) translateY(44px) rotateX(-8deg); }
.reveal .fragment.fade-left  { transform: perspective(1600px) translateX(-52px) rotateY(9deg); }
.reveal .fragment.fade-right { transform: perspective(1600px) translateX(52px) rotateY(-9deg); }
.reveal .fragment.zoom-in    { transform: scale(.55) rotate(-3deg); }
.reveal .fragment.blur-in    { filter: blur(13px); transform: scale(1.16) translateY(12px); }
.reveal .fragment.rise-pop   { transform: perspective(1600px) translateY(40px) rotateX(-12deg) scale(.85); }
.reveal .fragment.flip-in    { transform: perspective(1600px) rotateY(-72deg); transform-origin: left center; }
.reveal .fragment.swing-in   { transform: perspective(1600px) rotateX(56deg); transform-origin: top center; }
.reveal .fragment.zoom-punch { transform: scale(.3) rotate(3deg); }
.reveal .fragment.spin-in    { transform: rotate(-160deg) scale(.42); }
.reveal .fragment.drop-in    { transform: translateY(-64px) rotate(5deg); }
.reveal .fragment.fade-up.visible,
.reveal .fragment.fade-left.visible,
.reveal .fragment.fade-right.visible,
.reveal .fragment.zoom-in.visible,
.reveal .fragment.blur-in.visible,
.reveal .fragment.rise-pop.visible,
.reveal .fragment.flip-in.visible,
.reveal .fragment.swing-in.visible,
.reveal .fragment.zoom-punch.visible,
.reveal .fragment.spin-in.visible,
.reveal .fragment.drop-in.visible {
  opacity: 1; transform: none; filter: none;
}

/* ── CASCADA (un click revela varios hijos escalonados) ── */
.reveal .fragment.cascade.visible > * { animation: cascadeIn .6s var(--ease-spring) both; }
.reveal .fragment.cascade > * { opacity: 0; }
.reveal .fragment.cascade.visible > *:nth-child(1)  { animation-delay: .00s; }
.reveal .fragment.cascade.visible > *:nth-child(2)  { animation-delay: .07s; }
.reveal .fragment.cascade.visible > *:nth-child(3)  { animation-delay: .14s; }
.reveal .fragment.cascade.visible > *:nth-child(4)  { animation-delay: .21s; }
.reveal .fragment.cascade.visible > *:nth-child(5)  { animation-delay: .28s; }
.reveal .fragment.cascade.visible > *:nth-child(6)  { animation-delay: .35s; }
.reveal .fragment.cascade.visible > *:nth-child(7)  { animation-delay: .42s; }
.reveal .fragment.cascade.visible > *:nth-child(8)  { animation-delay: .49s; }
@keyframes cascadeIn { from { opacity: 0; transform: perspective(1600px) translateY(30px) rotateX(-14deg) scale(.96); } to { opacity: 1; transform: none; } }

/* ── ENTRADA AL PRESENTAR (sin click): elementos con .enter ──
   :not(.stack) → en pilas verticales, Reveal marca .present TANTO en la
   subslide visible COMO en su <section.stack> contenedor. Sin el :not, la
   animación de una subslide aún no visitada se dispara al entrar a la PRIMERA
   subslide de la pila (su stack ya es .present) y se "gasta" antes de llegar a
   ella. Gatillamos solo desde la subslide-hoja real (la que no es .stack). */
section.present:not(.stack) .enter { animation: enterUp .8s var(--ease-spring) both; }
section.present .enter.d1 { animation-delay: .08s; }
section.present .enter.d2 { animation-delay: .18s; }
section.present .enter.d3 { animation-delay: .30s; }
section.present .enter.d4 { animation-delay: .42s; }
section.present .enter.d5 { animation-delay: .54s; }
@keyframes enterUp { from { opacity: 0; transform: perspective(1600px) translateY(36px) rotateX(-9deg); } to { opacity: 1; transform: none; } }

section.present:not(.stack) .enter-left { animation: enterLeft .8s var(--ease-spring) both; }
@keyframes enterLeft { from { opacity: 0; transform: perspective(1600px) translateX(-46px) rotateY(10deg); } to { opacity: 1; transform: none; } }
section.present:not(.stack) .enter-right { animation: enterRight .8s var(--ease-spring) both; }
@keyframes enterRight { from { opacity: 0; transform: perspective(1600px) translateX(46px) rotateY(-10deg); } to { opacity: 1; transform: none; } }
section.present:not(.stack) .enter-scale { animation: enterScale .9s var(--ease-spring) both; }
@keyframes enterScale { from { opacity: 0; transform: scale(.6) rotate(-4deg); } to { opacity: 1; transform: none; } }

/* ── ECG: dibujo de línea ── */
.ecg { width: 100%; display: block; }
.ecg path { stroke-dasharray: var(--len, 2000); stroke-dashoffset: var(--len, 2000); }
section.present .ecg.draw path { animation: ecgdraw 2.1s cubic-bezier(.55,.1,.25,1) .25s forwards; }
@keyframes ecgdraw { to { stroke-dashoffset: 0; } }
/* latido ambiental: tras dibujarse, recorre un brillo */
.ecg.live-beat path { animation: ecgdraw 2.1s cubic-bezier(.55,.1,.25,1) .25s forwards, ecgpulse 3.2s ease-in-out 2.4s infinite; }
@keyframes ecgpulse { 0%,100% { opacity: .85; } 50% { opacity: .35; } }

/* ── WORDMARK: el pulso se dibuja como latido ── */
.wm.draw .pulse-l { stroke-dasharray: var(--plen, 520); stroke-dashoffset: var(--plen, 520); }
section.present .wm.draw .pulse-l { animation: ecgdraw 1.7s cubic-bezier(.6,.05,.2,1) .35s forwards; }
.wm.draw .syn, .wm.draw .ppg { opacity: 0; }
section.present .wm.draw .syn { animation: fadein .6s ease .15s forwards; }
section.present .wm.draw .ppg { animation: fadein .6s ease 1.5s forwards; }
@keyframes fadein { to { opacity: 1; } }

/* ── BARRAS DE GRÁFICO: crecen al presentar ── */
.bar-grow { transform: scaleY(0); transform-origin: bottom; }
section.present .bar-grow { animation: barGrow .9s var(--ease-out) both; }
section.present .bar-grow.b1 { animation-delay: .15s; }
section.present .bar-grow.b2 { animation-delay: .30s; }
section.present .bar-grow.b3 { animation-delay: .45s; }
section.present .bar-grow.b4 { animation-delay: .60s; }
section.present .bar-grow.b5 { animation-delay: .75s; }
.fragment:not(.visible) .bar-grow { animation: none !important; }
@keyframes barGrow { to { transform: scaleY(1); } }

/* ── FLOTACIÓN AMBIENTAL (device, halos) ── */
section.present .float { animation: float 6s ease-in-out infinite; }
@keyframes float { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
section.present .float-slow { animation: float 9s ease-in-out infinite; }

/* halos: respiran */
section.present .halo.breathe { animation: breathe 9s ease-in-out infinite; }
@keyframes breathe { 0%,100% { opacity: .35; transform: scale(1); } 50% { opacity: .6; transform: scale(1.12); } }

/* ── PING DE LA BOTONERA (foso): anillos que emanan como señal ESP-NOW ── */
section.present .dev-ring { animation: ping 3.3s var(--ease-out) infinite; }
section.present .dev-ring.d2 { animation-delay: 1.1s; }
section.present .dev-ring.d3 { animation-delay: 2.2s; }
@keyframes ping {
  0%   { transform: translate(-50%,-50%) scale(.72); opacity: 0; }
  14%  { opacity: .55; }
  100% { transform: translate(-50%,-50%) scale(1.7); opacity: 0; }
}

/* ── FOSO: capas concéntricas que se dibujan al entrar ── */
.moat-rings .ring { stroke-dasharray: 100; stroke-dashoffset: 100; }
.moat-rings .node, .moat-rings .core-disc, .moat-rings .core-wave { opacity: 0; }
/* :not(.stack): la 6.2 es una subslide vertical; gatillar el dibujo del foso
   solo cuando ESTA hoja es la presente, no cuando lo es su pila contenedora
   (si no, se dibuja al entrar a la 6.1 y llega "ya dibujado" a la 6.2). */
section.present:not(.stack) .moat-rings .ring { animation: ringDraw 1.1s var(--ease-out) both; }
section.present:not(.stack) .moat-rings .ring.r3 { animation-delay: .15s; }
section.present:not(.stack) .moat-rings .ring.r2 { animation-delay: .35s; }
section.present:not(.stack) .moat-rings .ring.r1 { animation-delay: .55s; }
section.present:not(.stack) .moat-rings .core-disc { animation: fadein .6s ease .75s both; }
section.present:not(.stack) .moat-rings .core-wave { animation: fadein .6s ease .95s both; }
section.present:not(.stack) .moat-rings .node.n3 { animation: fadein .5s ease .5s both; }
section.present:not(.stack) .moat-rings .node.n2 { animation: fadein .5s ease .7s both; }
section.present:not(.stack) .moat-rings .node.n1 { animation: fadein .5s ease .9s both; }
@keyframes ringDraw { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }

/* ── ENFASIS DE READOUT (cuando aparece un número grande) ── */
/* :not(.stack): el readout pop-in aparece en subslides verticales (p.ej. 2.2);
   gatillar solo desde la hoja presente, no desde su pila contenedora. */
section.present:not(.stack) .pop-in { animation: popIn 1s var(--ease-spring) both; }
@keyframes popIn {
  0%   { opacity: 0; transform: scale(.4) rotate(-6deg); }
  55%  { opacity: 1; transform: scale(1.04) rotate(2deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}

/* ── AMBIENTE 3D: cabeceo continuo para piezas hero (gráficos/SVG) ── */
section.present .tilt-3d { animation: tilt3d 8s ease-in-out infinite; transform-style: preserve-3d; }
@keyframes tilt3d {
  0%,100% { transform: perspective(1300px) rotateX(0deg)    rotateY(0deg); }
  25%     { transform: perspective(1300px) rotateX(2.4deg)  rotateY(-3.4deg); }
  50%     { transform: perspective(1300px) rotateX(0deg)    rotateY(3.4deg); }
  75%     { transform: perspective(1300px) rotateX(-2.4deg) rotateY(-1.6deg); }
}

/* ── BRILLO PULSANTE: halo que late alrededor de un elemento clave ── */
section.present .glow-pulse { animation: glowPulse 2.8s ease-in-out infinite; }
@keyframes glowPulse {
  0%,100% { filter: drop-shadow(0 0 0 rgba(56,189,248,0)); }
  50%     { filter: drop-shadow(0 0 30px rgba(56,189,248,.6)); }
}

/* ── SUBRAYADO QUE SE DIBUJA ── */
.uline { position: relative; }
.uline::after {
  content: ''; position: absolute; left: 0; bottom: -2px; height: 3px; width: 100%;
  background: var(--signal); border-radius: 2px; transform: scaleX(0); transform-origin: left;
}
.uline.v::after { background: var(--vital); }
.uline.a::after { background: var(--alert); }
section.present .uline::after { animation: ulineGrow .7s var(--ease-out) .5s both; }
@keyframes ulineGrow { to { transform: scaleX(1); } }

/* respeto a reduced motion: desactiva loops/draws */
@media (prefers-reduced-motion: reduce) {
  .ecg path, .wm.draw .pulse-l { animation: none !important; stroke-dashoffset: 0 !important; }
  .wm.draw .syn, .wm.draw .ppg { animation: none !important; opacity: 1 !important; }
  .live .blip, .float, .float-slow, .halo.breathe, .ecg.live-beat path, .dev-ring,
  .tilt-3d, .glow-pulse { animation: none !important; }
  .tilt-3d { transform: none !important; }
  .dev-ring { display: none !important; }
  .moat-rings .ring { stroke-dashoffset: 0 !important; }
  .moat-rings .node, .moat-rings .core-disc, .moat-rings .core-wave { opacity: 1 !important; }
  .bar-grow { transform: none !important; }
}

/* ── OVERRIDES PARA EXPORTAR A PDF (decktape / print-pdf) ── */
@media print {
  * {
    animation: none !important;
    transition: none !important;
    filter: none !important; /* Desactiva sombras pesadas para un PDF rápido */
  }
  .enter, .enter-left, .enter-right, .enter-scale, .pop-in {
    opacity: 1 !important;
    transform: none !important;
  }
  .reveal .fragment {
    opacity: 1 !important;
    transform: none !important;
  }
  .ecg path, .wm.draw .pulse-l, .moat-rings .ring {
    stroke-dashoffset: 0 !important;
  }
  .wm.draw .syn, .wm.draw .ppg, .moat-rings .node, .moat-rings .core-disc, .moat-rings .core-wave {
    opacity: 1 !important;
  }
  .bar-grow {
    transform: scaleY(1) !important;
  }
  .uline::after {
    transform: scaleX(1) !important;
  }
}

.decktape * {
  animation: none !important;
  transition: none !important;
  filter: none !important;
}
.decktape .enter, .decktape .enter-left, .decktape .enter-right, .decktape .enter-scale, .decktape .pop-in, .decktape .reveal .fragment {
  opacity: 1 !important;
  transform: none !important;
}
.decktape .ecg path, .decktape .wm.draw .pulse-l, .decktape .moat-rings .ring { stroke-dashoffset: 0 !important; }
.decktape .wm.draw .syn, .decktape .wm.draw .ppg, .decktape .moat-rings .node, .decktape .moat-rings .core-disc, .decktape .moat-rings .core-wave { opacity: 1 !important; }
.decktape .bar-grow { transform: scaleY(1) !important; }
.decktape .uline::after { transform: scaleX(1) !important; }
