/* =====================================================================================
   Gutivel · animaciones e ilustraciones de la portada (tema 2.1.0)
   Nivel: funcional + nivel 1 acotado. CSS + JS propio, sin librerías: el sitio vende velocidad.
   Un solo efecto protagonista por sección, y solo donde explica algo:
     inicio → el informe que cuenta de 41 a 94 · problemas → ilustraciones · portafolio → electrocardiograma
     proceso → línea atada al scroll · compromisos → iconos que se dibujan · contacto → la conversación.
   El texto nunca espera a un observer para verse: títulos, precios, tabla, preguntas y formulario están quietos.
   Tokens: subconjunto de web-creation-pro/referencias/tokens-movimiento.md (fuente canónica).
   Regla: el estado final es el estado por defecto. Sin JS o con movimiento reducido, todo se ve completo y quieto.
   Los estilos fijos de las ilustraciones y del chat están en style.css (se ven aunque se apaguen las animaciones).
   ===================================================================================== */
:root {
  /* Easings: tres y repetidos en todo el sitio */
  --ease-expo:  cubic-bezier(.16, 1, .3, 1);    /* entradas y revelados */
  --ease-inout: cubic-bezier(.77, 0, .175, 1);  /* trazos que se dibujan */
  --ease-ios:   cubic-bezier(.32, .72, 0, 1);   /* paneles y menú */
  /* Duraciones. --d-reveal baja de 1,2 s (canónico) a 0,9 s: en una landing de conversión nada debe hacerse esperar */
  --d-instant: .1s; --d-micro: .25s; --d-ui: .5s; --d-exit: calc(var(--d-ui) * .6);
  --d-reveal: .9s; --d-hero: 1.6s;
  /* Coreografía y distancias */
  --stagger-items: .1s; --dist-sm: 12px; --dist-md: 24px;
  /* Táctil */
  --tap-scale: .97; --touch-target: 44px;
}
/* Teléfonos modestos o ahorro de datos (lo decide el script del <head>): menos recorrido y nada de bucles */
:root[data-motion="lite"] { --d-reveal: .6s; --d-hero: 1s; --dist-md: 12px; }
:root[data-motion="lite"] .typing i { animation: none; }
/* Movimiento reducido: los tokens decorativos se anulan, no solo se aceleran */
@media (prefers-reduced-motion: reduce) {
  :root { --d-reveal: 0s; --d-hero: 0s; --dist-sm: 0px; --dist-md: 0px; --stagger-items: 0s; }
}

/* ---- Movimiento ---- */
@media (prefers-reduced-motion: no-preference) {
  /* Logo: el check de la «v» se dibuja al cargar */
  .site-header .vcheck { stroke-dasharray: 1; animation: draw .8s .2s var(--ease-inout) both; }

  /* Inicio: entrada escalonada y subrayado que marca la promesa */
  .hero-copy > *, .hero .panel { animation: rise var(--d-reveal) var(--ease-expo) both; }
  .hero-copy > :nth-child(1) { animation-delay: .05s; }
  /* El titular es el LCP: entra sin retraso y nunca parte de opacidad 0, para que cuente desde el primer fotograma */
  .hero-copy > h1 { animation-name: rise-lcp; animation-delay: 0s; }
  .hero-copy > :nth-child(3) { animation-delay: .23s; }
  .hero-copy > :nth-child(4) { animation-delay: .32s; }
  .hero-copy > :nth-child(5) { animation-delay: .41s; }
  .hero .panel { animation-delay: .3s; }
  .hero h1 em { animation: mark .9s 1s var(--ease-expo) both; }

  /* Informe de ejemplo: se anima cuando se ve (en celular queda debajo del pliegue); el JS añade .is-live.
     Los puntos se mueven con «left» y no con translate: así funciona también con portadas ya editadas
     en el editor, que guardan --a y --b con «%» (ver LEEME, punto 1). */
  .dot.after { animation: slide var(--d-hero) var(--ease-expo) .5s both; }
  .metric .vals em { animation: fade .6s 1.7s both; }
  .js .panel:not(.is-live) .dot.after { animation: none; left: var(--b); }
  .js .panel:not(.is-live) .metric .vals em { animation: none; opacity: 0; }

  /* Ilustraciones que actúan al verse. Sin ocultar texto: la animación ya está puesta y espera en pausa en su
     primer fotograma; el observer solo le da al play (.is-in). Una vez, sin bucles. Se eligen por clase y no
     por un atributo nuevo, para que funcione igual con una portada editada antes de la 2.1.0. */
  .io :is(.who article, .browser, .promises article, .chat):not(.is-in),
  .io :is(.who article, .browser, .promises article, .chat):not(.is-in) * { animation-play-state: paused !important; }

  /* Problemas: una acción corta por ilustración */
  .io .spot-slow .bar { animation: grow 1.4s .5s var(--ease-expo) both; transform-origin: 0 50%; }
  .io .spot-slow .hourglass { animation: flip .8s 1.5s var(--ease-inout) both; transform-origin: 50% 50%; }
  .io .spot-shop .card { animation: slide-in .9s .5s var(--ease-expo) both; }
  .io .spot-shop .badge, .io .spot-course .play { animation: pop .6s 1.1s var(--ease-expo) both; transform-origin: 50% 50%; }
  .io .spot-course .cap { animation: drop .9s .6s var(--ease-expo) both; transform-origin: 50% 100%; }
  .io .spot-keys .key { animation: slide-in .9s .5s var(--ease-expo) both; }
  .io .spot-keys .shackle { animation: unlock .6s 1.3s var(--ease-expo) both; }
  .io .spot-keys .badge { animation: pop .6s 1.5s var(--ease-expo) both; transform-origin: 50% 50%; }

  /* Portafolio: el electrocardiograma se dibuja y aparece la constancia */
  .io .case-art .ecg { stroke-dasharray: 1; animation: draw 1.6s .4s var(--ease-inout) both; }
  .io .case-art .cert { animation: rise var(--d-reveal) .9s var(--ease-expo) both; }
  .io .case-art .seal { animation: pop .6s 1.6s var(--ease-expo) both; transform-origin: 50% 50%; }

  /* Compromisos: los iconos se dibujan uno tras otro (el JS les pone pathLength="1" y --i) */
  .io .promises svg [pathLength] { stroke-dasharray: 1; animation: draw 1.2s calc(.25s + var(--i, 0) * var(--stagger-items)) var(--ease-inout) both; }

  /* Contacto: la conversación ocurre una vez al verla. Solo opacidad y transform: el alto del chat no cambia
     (el indicador «escribiendo» comparte fila con la respuesta, ver style.css) */
  .io .typing { display: flex; gap: 4px; justify-self: start; align-self: start; background: var(--surface); padding: 10px 12px; border-radius: 12px; opacity: 0; }
  .typing i { width: 6px; height: 6px; border-radius: 50%; background: var(--field); animation: bounce .9s ease-in-out 3; }
  .typing i:nth-child(2) { animation-delay: .15s; } .typing i:nth-child(3) { animation-delay: .3s; }
  .io .chat .msg.out { animation: rise .6s .3s var(--ease-expo) both; }
  .io .chat .typing { animation: typing 1.9s .9s both; }
  .io .chat .msg.in { animation: rise .6s 2.8s var(--ease-expo) both; }
  .io .chat .msg.file { animation: rise .6s 3.3s var(--ease-expo) both; }

  /* Microinteracciones */
  .btn, .wp-block-button__link { transition: filter var(--d-micro), transform var(--d-micro) var(--ease-expo); }
  .btn:active, .wp-block-button__link:active { transform: scale(var(--tap-scale)); transition-duration: var(--d-instant); }
  .wa-float:hover { transform: scale(1.06); }
}

/* Proceso: la línea superior avanza con el scroll (CSS scroll-driven; sin soporte queda completa) */
.steps { position: relative; border-top-color: var(--line); view-timeline: --steps block; }
.steps::before { content: ""; position: absolute; left: 0; right: 0; top: -2px; height: 2px; background: var(--brand); transform-origin: 0 50%; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .steps::before { animation: line linear both; animation-timeline: --steps; animation-range: entry 40% cover 60%; }
  }
}

/* Tarjetas de servicio: elevación al pasar el cursor (solo con puntero fino) */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .service { transition: translate var(--d-micro) var(--ease-expo), box-shadow var(--d-micro) var(--ease-expo); }
  .service:hover { translate: 0 -4px; box-shadow: 0 22px 40px -30px rgba(11, 31, 28, 0.55); }
  .service.featured:hover { box-shadow: 0 0 0 1px var(--brand), 0 22px 40px -30px rgba(11, 31, 28, 0.55); }
}

/* Preguntas: apertura suave (Chrome 131+; en otros navegadores abre como siempre) */
@supports (interpolate-size: allow-keywords) and selector(::details-content) {
  @media (prefers-reduced-motion: no-preference) {
    .faq { interpolate-size: allow-keywords; }
    .faq details::details-content { height: 0; overflow: clip; transition: height var(--d-ui) var(--ease-expo), content-visibility var(--d-ui) allow-discrete; }
    .faq details[open]::details-content { height: auto; }
  }
}

@keyframes rise { from { opacity: 0; transform: translateY(var(--dist-md)); } }
@keyframes rise-lcp { from { opacity: .01; transform: translateY(18px); } }
@keyframes fade { from { opacity: 0; } }
@keyframes draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes mark { from { background-size: 0% .3em; } }
@keyframes grow { from { transform: scaleX(0); } }
@keyframes flip { from { transform: rotate(-180deg); } }
@keyframes slide-in { from { opacity: 0; transform: translateX(24px); } }
@keyframes pop { from { opacity: 0; transform: scale(0); } }
@keyframes drop { from { opacity: 0; transform: translateY(-18px) rotate(-12deg); } }
@keyframes unlock { to { transform: translateY(-7px); } }
@keyframes line { from { transform: scaleX(0); } }
@keyframes bounce { 50% { transform: translateY(-4px); opacity: .5; } }
@keyframes typing { 0% { opacity: 0; } 12%, 85% { opacity: 1; } 100% { opacity: 0; } }
