/* ============================================================
   animations.css
   Animaciones de entrada, parallax helpers, transiciones y
   keyframes utilitarios.
   ============================================================ */

/* ---------- Keyframes base ---------- */

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(28px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes fadeInDown {
  from { opacity: 0; transform: translateY(-28px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes scaleIn {
  from { opacity: 0; transform: scale(0.94); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes pop {
  0%   { transform: scale(0.6); opacity: 0; }
  60%  { transform: scale(1.1); opacity: 1; }
  100% { transform: scale(1); }
}

@keyframes bobble {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-6px); }
}

@keyframes twinkle {
  0%, 100% { opacity: 0.4; transform: scale(1); }
  50%      { opacity: 1;   transform: scale(1.15); }
}

@keyframes spinSlow {
  to { transform: rotate(360deg); }
}

@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

/* Cursor parpadeante (también declarado en panels.css; mantenemos
   uno consolidado aquí por si se importa solo este archivo) */
@keyframes blink {
  to { visibility: hidden; }
}

/* ---------- Preloader: estrella latiendo ---------- */
.preloader__star {
  animation: twinkle 1.4s ease-in-out infinite;
}

.preloader__text {
  animation: fadeIn 1.2s ease-in-out infinite alternate;
}

/* ---------- Header: entrada suave ---------- */
.site-header {
  animation: fadeInDown 0.6s var(--t-base) both;
}

/* ---------- Capítulo intro ---------- */
.chapter__intro {
  animation: fadeInUp 0.7s var(--t-base) both;
}

/* ---------- Panel: aparición al entrar al viewport (desktop) ----------
   En desktop el panel parte oculto (definido en responsive.css). Aquí
   damos timings y micro-rebote a sus hijos cuando la clase .in-view
   se activa. */

.panel.in-view .panel__index {
  animation: pop 0.5s var(--t-base) both;
}

/* Nota: las burbujas ya NO se animan por la clase .panel.in-view —
   el typewriter las orquesta una a una con la clase .bubble--entering
   (definida más abajo). Esto evita que se vean cajas vacías mientras
   esperan su turno. */

.panel.in-view .panel__caption {
  animation: fadeIn 0.6s var(--t-base) both;
  animation-delay: 0.2s;
}

/* Elementos ya colocados (arrastrados): suprimir re-animación.
   IMPORTANTE: dejar pasar bubble--entering para no romper la
   secuencia rítmica de aparición tras un drag. */
.panel.in-view .bubble[data-placed="1"]:not(.bubble--entering):not(.bubble--pending),
.panel.in-view .bubble--placed:not(.bubble--entering):not(.bubble--pending),
.panel.in-view .character-overlay[data-placed="1"],
.panel.in-view .character-overlay--placed {
  animation: none !important;
  opacity: 1 !important;
}

/* Sparkles flotantes dentro de paneles */
.panel__sparkle {
  animation: twinkle 2s ease-in-out infinite;
}

.panel__sparkle--tr { animation-delay: 0.3s; }
.panel__sparkle--bl { animation-delay: 0.6s; }
.panel__sparkle--br { animation-delay: 0.9s; }

/* ---------- Parallax (cooperación con scrollManager.js) ----------
   El JS escribirá en --parallax-y (px) de cada .panel para mover
   el fondo en sentido contrario al scroll. Aquí garantizamos
   transición suave y sin layout shift. */
@media (min-width: 769px) {
  html.is-desktop .panel__media {
    transition: transform 80ms linear;
  }
}

/* ---------- Burbujas: estados typewriter ----------
   Las burbujas son absolutas y centradas con translate(-50%,-50%).
   Para el "pop" final hacemos un breve fade-in extra que no
   sobrescribe el transform centrado. */

@keyframes bubblePop {
  0%   { opacity: 0.6; }
  60%  { opacity: 1; }
  100% { opacity: 1; }
}

.bubble.done {
  animation: bubblePop 0.35s var(--t-base);
}

/* Caret blink (refuerzo) */
.bubble .caret,
.narration .caret {
  animation: blink 1s steps(2, start) infinite;
}

/* ---------- Botones interactivos: micro-rebote ---------- */
.mute-toggle,
.editor-toggle {
  transition: transform var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}

.mute-toggle:hover { animation: bobble 1.2s ease-in-out infinite; }
.editor-toggle:hover { animation: bobble 1.4s ease-in-out infinite; }

/* ---------- Panel del editor: micro-animación al abrir ---------- */
.editor-panel.is-open .editor-section {
  animation: fadeInUp 0.35s var(--t-base) both;
}

.editor-panel.is-open .editor-section:nth-child(2) { animation-delay: 0.05s; }
.editor-panel.is-open .editor-section:nth-child(3) { animation-delay: 0.1s; }

/* ---------- Galería de personajes: items aparecen escalonados ---------- */
.character-gallery__item {
  animation: scaleIn 0.3s var(--t-base) both;
}

/* ---------- Footer: aparece más tarde ---------- */
.site-footer {
  animation: fadeIn 1.2s var(--t-base) both;
  animation-delay: 0.4s;
}

/* ---------- Modo móvil: deshabilitamos parallax para rendimiento ---------- */
@media (max-width: 768px) {
  html.is-mobile .panel__media {
    transform: none !important;
  }
}

/* ============================================================
   Cola secuencial de burbujas (typewriter.js orquesta)
   - .bubble--pending  → en cola, totalmente oculta (ni caja ni caret)
   - .bubble--entering → es el turno: animación bonita de entrada
   ============================================================ */

.bubble.bubble--pending {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  animation: none !important;
}

/* Las keyframes multiplican por var(--panel-scale, 1) para que la
   animación de entrada respete el factor de escala del panel — si no, la
   burbuja "popearía" a tamaño completo antes de encogerse. */
@keyframes bubbleAppear {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(calc(var(--panel-scale, 1) * 0.55)); filter: blur(4px); }
  55%  { opacity: 1; transform: translate(-50%, -50%) scale(calc(var(--panel-scale, 1) * 1.06)); filter: blur(0);   }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--panel-scale, 1));              filter: blur(0);   }
}

@keyframes narrationAppear {
  0%   { opacity: 0; transform: translate(-50%, -38%) scale(calc(var(--panel-scale, 1) * 0.96)); filter: blur(3px); }
  100% { opacity: 1; transform: translate(-50%, -50%) scale(var(--panel-scale, 1));              filter: blur(0);   }
}

.bubble.bubble--entering {
  visibility: visible !important;
  animation: bubbleAppear 520ms cubic-bezier(0.34, 1.4, 0.55, 1) both !important;
}

.bubble.bubble--entering.narration,
.bubble.bubble--entering.bubble-narration {
  animation: narrationAppear 600ms cubic-bezier(0.22, 1, 0.36, 1) both !important;
}

/* ============================================================
   Burbujas vacías (sin texto): solo visibles en modo edición.
   La detección la hace typewriter.js (trim del contenido real) y
   añade .bubble--empty. Así no dependemos del atributo data-full-text
   (que puede tener espacios o no estar presente).
   ============================================================ */
.bubble.bubble--empty {
  display: none !important;
}

html.edit-mode-unlocked.editor-open .bubble.bubble--empty {
  display: inline-block !important;
  opacity: 0.55 !important;
  visibility: visible !important;
  animation: none !important;
}

/* ---------- Movement-sensitive users ---------- */
@media (prefers-reduced-motion: reduce) {
  .preloader__star,
  .preloader__text,
  .panel__sparkle,
  .mute-toggle:hover,
  .editor-toggle:hover,
  .bubble.done,
  .bubble.bubble--entering,
  .panel.in-view .panel__caption,
  .panel.in-view .panel__index,
  .editor-panel.is-open .editor-section,
  .character-gallery__item,
  .site-header,
  .chapter__intro,
  .site-footer,
  .bubble .caret,
  .narration .caret {
    animation: none !important;
  }
}
