/* motion.css — vocabulario de movimiento para los modulos del chat (paneles del chat,
   fase 1). Archivo NUEVO a proposito: el rediseno de nav de 4 secciones (worktree
   nav-cuatro-secciones, sin fusionar) reescribe el bloque de .chatpane y agrega ~156
   lineas al final de styles.css -- cualquier cosa que hubieramos anadido ahi habria
   chocado. Aqui no se toca styles.css ni una sola linea; solo se agregan clases nuevas
   sobre los tokens que YA existen (--ease-entra/--ease-estado/--dur-1/2/3,
   styles.css:6-13) y se aprovecha @keyframes rise/pop/rv-shimmer que ya viven ahi (las
   @keyframes son globales al documento, no hace falta redeclararlas).

   Reglas del archivo:
   - Nunca tocar .xa-*, .chatpane, ni anadir nada al final de styles.css (la fase A5 del
     rediseno de nav borra .xa-* por completo).
   - Toda clase de aqui es opt-in (nadie la aplica por accidente via una clase generica ya
     existente): se agregan explicitamente desde JS donde corresponde.
   - Una sola politica de "reducir movimiento", al final, acotada por :where() para no
     tocar los efectos de marca (Filo, xarpen-*, intro-enfoque) que ya tienen su propio
     candado en styles.css. */

:root{
  --stagger: 50ms;                              /* separacion entre la 1a y 2a tarjeta al entrar */
  --sombra-1: 0 1px 3px rgba(41,40,36,.04);      /* la sombra de .widget, con nombre */
  --sombra-2: 0 18px 44px -20px rgba(43,40,36,.5); /* la sombra de overlays/popovers, con nombre */
}

/* ---- Entrada de una tarjeta (m-entra) ----
   rise ya existe (styles.css:62). Solo anima transform+opacity: la caja nunca cambia de
   alto, asi que el ResizeObserver que ancla el chat al fondo (montarVistasDeXarpie,
   app.js) no ve un resize provocado por la animacion y no puede alimentarse a si mismo. */
.m-entra{
  animation: rise var(--dur-3) var(--ease-entra) both;
  animation-delay: calc(min(var(--i, 0), 2) * var(--stagger));
}

/* ---- Cambio de estado en su lugar (pill, chip, conteo, boton) ---- */
.m-estado{
  transition:
    background-color var(--dur-1) var(--ease-estado),
    color var(--dur-1) var(--ease-estado),
    border-color var(--dur-1) var(--ease-estado),
    opacity var(--dur-1) var(--ease-estado);
}

/* ---- Un numero/valor cambia (animarCifra en motion.js la dispara) ---- */
@keyframes m-cifra{ from{ opacity:.55; transform:translateY(-2px); } to{ opacity:1; transform:none; } }
.m-cifra{ animation: m-cifra var(--dur-3) var(--ease-estado) both; }

/* ---- Una accion se logro: un solo destello, sin confeti ---- */
@keyframes m-listo-borde{ 0%{ border-color:var(--hair); } 30%{ border-color:var(--blue); } 100%{ border-color:var(--hair); } }
@keyframes m-listo-check{ 0%{ transform:scale(.8); opacity:0; } 60%{ transform:scale(1.08); opacity:1; } 100%{ transform:scale(1); opacity:1; } }
.m-listo{ animation: m-listo-borde 640ms var(--ease-estado) both; }
.m-listo .ico-listo{ display:inline-block; animation: m-listo-check 180ms var(--ease-estado) both; }

/* ---- Salida de #wexp (la tarjeta expandida se cierra) ----
   pop (entrada, styles.css) ya se aplica via ".wexp:not([hidden])"; esta regla llega
   DESPUES en la cascada (motion.css carga despues de styles.css) y con la misma
   especificidad que ".wexp:not([hidden])" (dos clases vs. clase+atributo), asi que
   ".wexp.m-sale" gana sin necesitar !important. */
@keyframes m-pop-out{ from{ opacity:1; transform:scale(1); } to{ opacity:0; transform:scale(.98); } }
.m-sale{ animation: m-pop-out var(--dur-1) var(--ease-estado) forwards; }

/* ---- Una tarjeta se descarta (quitarConMotion en motion.js la dispara) ----
   --h lo mide JS antes de agregar .saliendo: sin un alto de partida real, max-height no
   tiene de donde encoger (poner "none" como base no es animable). */
.m-quita{ overflow:hidden; max-height:var(--h, 600px); transition: opacity 160ms var(--ease-estado), max-height 160ms var(--ease-estado); }
.m-quita.saliendo{ opacity:0; max-height:0; }

/* ---- Esqueleto de carga: reemplaza el texto "Cargando..." dentro de una tarjeta ----
   Reusa @keyframes rv-shimmer (styles.css:7232, hoy solo la usan las miniaturas de
   Revelado) en vez de declarar un shimmer nuevo. */
.esq{ display:flex; flex-direction:column; gap:8px; padding:2px 0; }
.esq-barra{
  height:12px; border-radius:var(--r);
  background: linear-gradient(90deg, var(--deep) 0%, var(--hair) 50%, var(--deep) 100%);
  background-size:200% 100%;
  animation: rv-shimmer 1.4s infinite linear;
}
.esq-barra.w100{ width:100%; } .esq-barra.w60{ width:60%; } .esq-barra.w40{ width:40%; }

/* ---- Reducir movimiento: UNA politica, acotada por clase ----
   :where() no agrega especificidad, asi que esto nunca compite con las reglas de arriba
   ni con los bloques propios de Filo/xarpen-*/intro-enfoque (que ya tienen su candado en
   styles.css y no se tocan aqui). */
@media (prefers-reduced-motion: reduce){
  :where(.m-entra, .m-listo, .m-sale, .m-cifra, .esq-barra, .mod-mas){
    animation: none !important;
  }
  /* .m-quita no anima con @keyframes (arriba): es transition de opacity/max-height, asi
     que "animation:none" no le hace nada -- necesita su propia entrada aqui, junto con
     .m-estado, para de verdad quedar en "fundido" (casi instantaneo) y no en un colapso
     de 160ms con reduccion de movimiento activada. */
  :where(.m-estado, .m-quita, .mod-pie .btn){
    transition-duration: 1ms !important;
  }
}
