/* ==========================================================================
   mp360-motion.css — sistema de motion semántico
   --------------------------------------------------------------------------
   Un solo vocabulario para toda la experiencia, construido sobre los tokens
   que ya vivían en `mp360.css`. La regla de reparto es simple:

     mp360.css        define los tokens (--mo-*) y el bloque de reduced motion
     este archivo     define QUÉ significa cada gesto
     mp360-motion.js  decide CUÁNDO empieza y cuándo terminó

   Seis semánticas, ni una más. Un componente no elige duraciones ni curvas:
   elige qué está pasando.

     surfaceEnter        una superficie aparece
     surfaceExit         una superficie se va
     contentCascade      el contenido de una superficie se revela en orden
     listStagger         una lista se puebla
     stateReplace        el contenido cambia dentro de la misma superficie
     selectionFeedback   un control acusa recibo de la elección

   El motion NO produce sonido. Quien ejecuta la acción real emite su evento
   semántico una sola vez y coordina las dos cosas; así un reflow, una
   restauración de estado o una animación interna nunca suenan.

   Este archivo lo cargan `index.html` y los componentes que comparten el
   vocabulario, para que no repitan tokens ni curvas por su cuenta.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Tokens
   Los mismos valores que `mp360.css`, declarados también acá para que un
   componente que cargue este archivo suelto —cotiza, por ejemplo, que no
   carga `mp360.css`— tenga el vocabulario completo. En `index.html`
   `mp360.css` se carga después, así que si algún día divergen manda el suyo.
   -------------------------------------------------------------------------- */
:root {
  --mo-fast: 180ms;
  --mo-base: 300ms;
  --mo-surface: 420ms;
  --mo-sheet: 460ms;
  --mo-exit: 240ms;

  --mo-in: cubic-bezier(0.22, 1, 0.36, 1);
  --mo-out: cubic-bezier(0.4, 0, 1, 1);
  --mo-move: cubic-bezier(0.4, 0, 0.2, 1);

  --mo-stagger: 55ms;
  --mo-shift: 8px;
  --mo-scale: 0.985;
}

/* --------------------------------------------------------------------------
   Keyframes compartidos
   Solo `opacity` y `transform`: son las dos propiedades que el compositor
   resuelve sin recalcular layout.
   -------------------------------------------------------------------------- */
@keyframes mo-rise {
  from { opacity: 0; transform: translateY(var(--mo-shift)); }
  to   { opacity: 1; transform: none; }
}

@keyframes mo-card-in {
  from { opacity: 0; transform: translateY(var(--mo-shift)) scale(var(--mo-scale)); }
  to   { opacity: 1; transform: none; }
}

@keyframes mo-sheet-in {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}

@keyframes mo-step-out {
  to { opacity: 0; transform: translateY(-4px); }
}

@keyframes mo-step-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}

/* --------------------------------------------------------------------------
   1 · surfaceEnter
   Una superficie aparece. Las cards entran con una escala mínima; las hojas
   ancladas al pie entran desde abajo, que es de donde vienen.
   -------------------------------------------------------------------------- */
.mo-enter {
  animation: mo-card-in var(--mo-surface) var(--mo-in) both;
}

.mo-enter[data-mo="hoja"] {
  animation-name: mo-sheet-in;
  animation-duration: var(--mo-sheet);
}

/* Una superficie de apoyo —un aviso, una lista— no necesita escala. */
.mo-enter[data-mo="apoyo"] {
  animation-name: mo-rise;
  animation-duration: var(--mo-base);
}

/* --------------------------------------------------------------------------
   2 · surfaceExit
   La salida es visible y nunca instantánea. Deja de interceptar el puntero en
   el primer cuadro: una capa invisible que todavía recibe eventos bloquea el
   recorrido, y eso ya pasó una vez en este proyecto.
   -------------------------------------------------------------------------- */
.mo-exit {
  opacity: 0;
  transition:
    opacity var(--mo-exit) var(--mo-out),
    transform var(--mo-exit) var(--mo-out);
}

/* La clase repetida sube la especificidad a (0,2,0) sin recurrir a
   `!important`. Hace falta porque `mp360.css` declara despues
   `.mp360__ui > * { pointer-events: auto }` con el mismo peso, y ahi ganaba el
   orden de carga: la capa en salida seguia interceptando el puntero. `inert`
   ya la bloquea, pero una superficie que se va no debe depender de una sola
   defensa. */
.mo-exit.mo-exit { pointer-events: none; }

.mo-exit[data-mo="hoja"] { transform: translateY(12px); }
.mo-exit:not([data-mo="hoja"]) { transform: translateY(4px); }

/* --------------------------------------------------------------------------
   3 · contentCascade
   El contenido se revela de arriba hacia abajo. El orden lo declara el markup
   con `--row`, no un `:nth-child`: así reordenar bloques no reordena el
   motion. Siete filas como techo — 420 + 6 × 55 = 750ms.
   -------------------------------------------------------------------------- */
.mo-cascade > * {
  animation: mo-rise var(--mo-surface) var(--mo-in) both;
  animation-delay: calc(var(--row, 0) * var(--mo-stagger));
}

/* --------------------------------------------------------------------------
   4 · listStagger
   Una lista se puebla. Más rápido y más corto que la cascada de contenido:
   son elementos hermanos equivalentes, no una jerarquía.
   -------------------------------------------------------------------------- */
.mo-list > * {
  animation: mo-rise var(--mo-base) var(--mo-in) both;
  animation-delay: calc(min(var(--row, 0), 8) * 40ms);
}

/* --------------------------------------------------------------------------
   5 · stateReplace
   El contenido cambia dentro de la misma superficie. Sale, se reemplaza,
   entra; y la altura viaja entre los dos estados medidos de verdad, para que
   la superficie se transforme en vez de saltar.
   -------------------------------------------------------------------------- */
.mo-replace {
  transition: height var(--mo-base) var(--mo-in);
}

.mo-replace.is-out > * { animation: mo-step-out var(--mo-fast) var(--mo-out) both; }
.mo-replace.is-in  > * { animation: mo-step-in var(--mo-base) var(--mo-in) both; }

/* --------------------------------------------------------------------------
   6 · selectionFeedback
   Acuse de recibo, no celebración: un hundimiento breve y la vuelta.
   -------------------------------------------------------------------------- */
.mo-select {
  transition:
    scale var(--mo-fast) var(--mo-in),
    background-color var(--mo-fast) var(--mo-move),
    border-color var(--mo-fast) var(--mo-move);
}

.mo-select:active { scale: 0.98; }

/* --------------------------------------------------------------------------
   Movimiento reducido
   Se neutralizan los tokens en vez de apagar reglas una por una: desaparecen
   cascada, desplazamiento y escala sin que quede nada invisible ni a medio
   camino. `mp360.css` hace lo mismo; repetirlo acá permite que un componente
   cargue este archivo solo y siga respetando la preferencia.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  :root {
    --mo-fast: 1ms;
    --mo-base: 1ms;
    --mo-surface: 1ms;
    --mo-sheet: 1ms;
    --mo-exit: 1ms;
    --mo-stagger: 0ms;
    --mo-shift: 0px;
    --mo-scale: 1;
  }

  .mo-list > * { animation-delay: 0ms; }
  .mo-select:active { scale: 1; }
}
