/* Concreta · kit de movimiento (CSS). Va junto con movimiento.js. Ver references/movimiento.md.
   Todo se activa con atributos data-mov="..." y con el nivel en <html data-mov-nivel="sutil|moderno|inmersivo">.
   Solo se animan transform y opacity. Sin JavaScript el contenido se ve completo y quieto. */

:root {
  /* Variables de configuración: cambiar aquí, no en cada componente. */
  --mov-rapido: 120ms;      /* presionar */
  --mov-base: 200ms;        /* encima, foco, cambio de estado */
  --mov-entrada: 360ms;     /* aparición de un bloque; con el escalonado máximo (4 × 50) el último termina en 560 ms */
  --mov-salida: 160ms;      /* lo que se va, se va más rápido */
  --mov-curva: cubic-bezier(.2, .7, .2, 1);        /* entrada: arranca rápido y frena */
  --mov-curva-salida: cubic-bezier(.4, 0, 1, 1);
  --mov-distancia: 16px;    /* cuánto sube un bloque al aparecer (máximo 24) */
  --mov-escala: 1;          /* tamaño de partida al aparecer; .95 lo hace más visible (útil en celular) */
  --mov-escalon: 50ms;      /* retraso entre hermanos que aparecen juntos */
  --mov-elevacion: -4px;    /* cuánto sube una tarjeta con el cursor encima */
  --mov-flotar: 6px;        /* amplitud de los elementos flotantes */
  --mov-flotar-tiempo: 7s;
  --mov-fondo-tiempo: 24s;
  --mov-cursor-tamano: 36px;
  --mov-cursor-color: var(--accent-btn, #0060f0);
  --mov-capa: 2147483000;
}

/* ───────── Nivel sutil: respuesta a acciones. Sirve en todos los niveles. ───────── */

[data-mov~="presionar"] { transition: transform var(--mov-rapido) var(--mov-curva), background-color var(--mov-base), border-color var(--mov-base), box-shadow var(--mov-base); }
[data-mov~="presionar"]:active:not(:disabled) { transform: scale(.97); }

@media (hover: hover) {
  [data-mov~="elevar"] { transition: transform var(--mov-base) var(--mov-curva), box-shadow var(--mov-base), border-color var(--mov-base); }
  [data-mov~="elevar"]:hover, [data-mov~="elevar"]:focus-within { transform: translateY(var(--mov-elevacion)); }
}

/* Subrayado que crece desde la izquierda en enlaces de menú. */
[data-mov~="subrayar"] { position: relative; text-decoration: none; }
[data-mov~="subrayar"]::after { content: ""; position: absolute; left: 0; right: 0; bottom: -4px; height: 2px; background: currentColor; transform: scaleX(0); transform-origin: left; transition: transform var(--mov-base) var(--mov-curva); }
[data-mov~="subrayar"]:hover::after, [data-mov~="subrayar"]:focus-visible::after, [data-mov~="subrayar"][aria-current]::after { transform: scaleX(1); }

/* Mensaje de error o de éxito que entra sin empujar bruscamente. */
[data-mov~="avisar"] { animation: cm-avisar var(--mov-base) var(--mov-curva) both; }
@keyframes cm-avisar { from { opacity: 0; transform: translateY(-4px); } }

/* Botón en estado "enviando": el texto queda y gira un indicador. */
[data-mov~="cargando"][aria-busy="true"] { position: relative; pointer-events: none; }
[data-mov~="cargando"][aria-busy="true"]::after { content: ""; display: inline-block; width: 1em; height: 1em; margin-left: .5em; vertical-align: -.15em; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: cm-girar .7s linear infinite; }
@keyframes cm-girar { to { transform: rotate(360deg); } }

/* <details> que se abre con suavidad donde el navegador lo permite; en los demás, abre de golpe. */
@supports (interpolate-size: allow-keywords) {
  details[data-mov~="desplegar"] { interpolate-size: allow-keywords; }
  details[data-mov~="desplegar"]::details-content { block-size: 0; overflow: clip; opacity: 0; transition: block-size var(--mov-base) var(--mov-curva), opacity var(--mov-base), content-visibility var(--mov-base) allow-discrete; }
  details[data-mov~="desplegar"][open]::details-content { block-size: auto; opacity: 1; }
}

/* ───────── Nivel moderno: aparición al desplazarse, fondo, flotantes. ───────── */

/* El estado oculto solo existe cuando el script ya cargó (clase cm-listo). */
/* Al terminar la entrada el elemento recibe cm-hecho y estas reglas lo sueltan: así no pisan el hover ni las
   transiciones que el componente ya tenía. */
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho) { opacity: 0; transform: translateY(var(--mov-distancia)) scale(var(--mov-escala, 1)); transition: opacity var(--mov-entrada) var(--mov-curva), transform var(--mov-entrada) var(--mov-curva); transition-delay: calc(var(--cm-i, 0) * var(--mov-escalon)); }
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho)[data-mov-desde="izquierda"] { transform: translateX(calc(var(--mov-distancia) * -1)); }
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho)[data-mov-desde="derecha"] { transform: translateX(var(--mov-distancia)); }
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho)[data-mov-desde="nada"] { transform: none; }
/* Entradas distintas para que no todo entre igual: data-mov-efecto="voltear" (se levanta como una tapa) o "crecer". */
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho)[data-mov-efecto="voltear"] { transform: perspective(900px) rotateX(18deg) translateY(var(--mov-distancia)) scale(.95); transform-origin: 50% 0; }
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho)[data-mov-efecto="crecer"] { transform: scale(.82); }
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho).cm-visto { opacity: 1; transform: none; }
html.cm-listo [data-mov~="aparecer"]:not(.cm-hecho).cm-sin-anim { transition: none; }

html:is([data-mov-nivel="moderno"], [data-mov-nivel="inmersivo"]) [data-mov~="flotar"] { animation: cm-flotar var(--mov-flotar-tiempo) ease-in-out infinite alternate; animation-delay: calc(var(--cm-i, 0) * -1.3s); }
@keyframes cm-flotar { from { transform: translateY(calc(var(--mov-flotar) * -1)); } to { transform: translateY(var(--mov-flotar)); } }

/* Fondo con dos manchas del color de acento que se desplazan despacio. No usa blur: es caro en celulares. */
[data-mov~="fondo-gradiente"] { position: relative; isolation: isolate; overflow: hidden; }
[data-mov~="fondo-gradiente"]::before, [data-mov~="fondo-gradiente"]::after { content: ""; position: absolute; z-index: -1; width: 70vmax; height: 70vmax; border-radius: 50%; pointer-events: none; opacity: .5;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--mov-fondo-color, var(--accent-btn, #0060f0)) 28%, transparent), transparent); }
[data-mov~="fondo-gradiente"]::before { top: -35vmax; left: -20vmax; }
[data-mov~="fondo-gradiente"]::after { bottom: -40vmax; right: -25vmax; opacity: .35; }
html:is([data-mov-nivel="moderno"], [data-mov-nivel="inmersivo"]) [data-mov~="fondo-gradiente"]::before { animation: cm-fondo-a var(--mov-fondo-tiempo) ease-in-out infinite alternate; }
html:is([data-mov-nivel="moderno"], [data-mov-nivel="inmersivo"]) [data-mov~="fondo-gradiente"]::after { animation: cm-fondo-b calc(var(--mov-fondo-tiempo) * 1.3) ease-in-out infinite alternate; }
@keyframes cm-fondo-a { to { transform: translate3d(18vmax, 10vmax, 0) scale(1.15); } }
@keyframes cm-fondo-b { to { transform: translate3d(-16vmax, -8vmax, 0) scale(.9); } }

[data-mov~="inclinar"] { transition: transform var(--mov-base) var(--mov-curva); transform-style: preserve-3d; }
[data-mov~="inclinar"].cm-moviendo { transition-duration: 60ms; }

/* ───────── Nivel inmersivo: cursor, partículas, profundidad, botón magnético. ───────── */

[data-mov~="particulas"] { position: relative; }
.cm-particulas { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; }
[data-mov~="particulas"] > :not(.cm-particulas) { position: relative; z-index: 1; }

[data-mov~="magnetico"] { transition: transform var(--mov-base) var(--mov-curva); }
[data-mov~="profundidad"] { will-change: transform; }

/* Cursor acompañante: no recibe clics, no entra al árbol de accesibilidad, no tapa el cursor del sistema. */
.cm-cursor { position: fixed; top: 0; left: 0; z-index: var(--mov-capa); width: var(--mov-cursor-tamano); height: var(--mov-cursor-tamano); margin: calc(var(--mov-cursor-tamano) / -2) 0 0 calc(var(--mov-cursor-tamano) / -2); pointer-events: none; opacity: 0; transition: opacity var(--mov-base); will-change: transform; }
.cm-cursor.cm-cursor--visible { opacity: 1; }
.cm-cursor__forma { width: 100%; height: 100%; display: grid; place-items: center; border: 2px solid var(--mov-cursor-color); border-radius: 50%; color: var(--mov-cursor-color); font-size: calc(var(--mov-cursor-tamano) * .5); line-height: 1; transition: transform var(--mov-base) var(--mov-curva), background-color var(--mov-base), border-color var(--mov-base); }
.cm-cursor--icono .cm-cursor__forma { border-color: transparent; transform: translate(60%, 60%); }      /* el ícono va al costado, no encima de lo que se señala */
.cm-cursor--icono .cm-cursor__forma img, .cm-cursor--icono .cm-cursor__forma svg { width: 100%; height: 100%; }
.cm-cursor--activo .cm-cursor__forma { transform: scale(1.5); background: color-mix(in srgb, var(--mov-cursor-color) 16%, transparent); }
.cm-cursor--icono.cm-cursor--activo .cm-cursor__forma { transform: translate(60%, 60%) scale(1.25) rotate(-8deg); background: none; }
.cm-cursor--presionado .cm-cursor__forma { transform: scale(.85); }
.cm-cursor__etiqueta { position: absolute; top: 100%; left: 100%; white-space: nowrap; padding: 4px 8px; border-radius: 6px; background: var(--text, #111); color: var(--bg, #fff); font: 600 12px/1.2 system-ui, sans-serif; opacity: 0; transform: translateY(-4px); transition: opacity var(--mov-base), transform var(--mov-base) var(--mov-curva); }
.cm-cursor--etiqueta .cm-cursor__etiqueta { opacity: 1; transform: none; }
/* Cursor estilo "retícula": punto luminoso en el puntero y anillo segmentado que gira y lo sigue. */
.cm-cursor--reticula .cm-cursor__forma { border: 0; position: relative; }
.cm-cursor--reticula .cm-cursor__forma::before, .cm-cursor--reticula .cm-cursor__forma::after { content: ""; position: absolute; border-radius: 50%; }
.cm-cursor--reticula .cm-cursor__forma::before { inset: 0; border: 2px solid var(--mov-cursor-color); box-shadow: 0 0 10px color-mix(in srgb, var(--mov-cursor-color) 55%, transparent), inset 0 0 6px color-mix(in srgb, var(--mov-cursor-color) 35%, transparent);
  -webkit-mask: conic-gradient(#000 0 17%, transparent 17% 25%, #000 25% 42%, transparent 42% 50%, #000 50% 67%, transparent 67% 75%, #000 75% 92%, transparent 92%); mask: conic-gradient(#000 0 17%, transparent 17% 25%, #000 25% 42%, transparent 42% 50%, #000 50% 67%, transparent 67% 75%, #000 75% 92%, transparent 92%);
  animation: cm-girar 7s linear infinite; }
.cm-cursor--reticula .cm-cursor__forma::after { inset: -6px; border: 1px solid var(--mov-cursor-color-2, color-mix(in srgb, var(--mov-cursor-color) 60%, #fff));
  -webkit-mask: conic-gradient(#000 0 9%, transparent 9% 50%, #000 50% 59%, transparent 59%); mask: conic-gradient(#000 0 9%, transparent 9% 50%, #000 50% 59%, transparent 59%);
  animation: cm-girar 3.2s linear infinite reverse; }
.cm-cursor--reticula.cm-cursor--activo .cm-cursor__forma { transform: scale(1.5); background: none; }
/* Sobre un enlace o botón el anillo se cierra y pasa al color secundario, que se distingue aunque el botón sea del color de marca. */
.cm-cursor--reticula.cm-cursor--activo .cm-cursor__forma::before { -webkit-mask: none; mask: none; border-color: var(--mov-cursor-color-2, #fff); background: color-mix(in srgb, var(--mov-cursor-color-2, #fff) 16%, transparent); box-shadow: 0 0 12px color-mix(in srgb, var(--mov-cursor-color-2, #fff) 60%, transparent); animation: none; }
.cm-cursor--reticula.cm-cursor--activo .cm-cursor__forma::after { animation-duration: 1.2s; }
.cm-cursor--reticula.cm-cursor--presionado .cm-cursor__forma { transform: scale(.75); }
.cm-cursor-punto { position: fixed; top: 0; left: 0; z-index: var(--mov-capa); width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; pointer-events: none; opacity: 0; transition: opacity var(--mov-base), background-color var(--mov-base);
  background: var(--mov-cursor-punto, #fff); box-shadow: 0 0 0 1.5px var(--mov-cursor-color), 0 0 12px 3px color-mix(in srgb, var(--mov-cursor-color) 75%, transparent); will-change: transform; }
.cm-cursor-punto.cm-visible { opacity: 1; }
.cm-cursor-punto.cm-activo { background: var(--mov-cursor-color-2, #fff); box-shadow: 0 0 0 1.5px #fff, 0 0 12px 3px color-mix(in srgb, var(--mov-cursor-color-2, #fff) 75%, transparent); }
.cm-onda { position: fixed; z-index: var(--mov-capa); width: 14px; height: 14px; margin: -7px 0 0 -7px; border-radius: 50%; border: 1.5px solid var(--mov-cursor-color); pointer-events: none; animation: cm-onda 520ms var(--mov-curva) forwards; }
@keyframes cm-onda { to { transform: scale(4.5); opacity: 0; } }
html.cm-quieto :is(.cm-cursor-punto, .cm-onda) { display: none !important; }
@media (prefers-reduced-motion: reduce) { html:not(.cm-movimiento) :is(.cm-cursor-punto, .cm-onda) { display: none !important; } }
@media (forced-colors: active) { .cm-cursor-punto, .cm-onda { display: none !important; } }
@media print { .cm-cursor-punto, .cm-onda { display: none !important; } }
/* Ocultar el cursor del sistema: solo si se pidió, solo con ratón, y nunca sobre campos de texto. */
/* Se aplica a todo, con !important, para que ningún componente con su propio cursor (pointer, crosshair) rompa
   el estándar; los campos de texto y los marcos externos quedan fuera. */
html.cm-cursor-oculto, html.cm-cursor-oculto *:not(input):not(textarea):not(select):not([contenteditable]):not(iframe) { cursor: none !important; }
html.cm-cursor-oculto :is(input[type="submit"], input[type="button"], input[type="checkbox"], input[type="radio"], input[type="range"], input[type="file"]) { cursor: none !important; }

/* Asistente flotante: un botón que abre un panel. Se coloca con --mov-asistente-abajo para no tapar la acción principal. */
.cm-asistente { position: fixed; right: 16px; bottom: var(--mov-asistente-abajo, 16px); z-index: calc(var(--mov-capa) - 10); display: flex; flex-direction: column; align-items: flex-end; gap: 12px; }
.cm-asistente__boton { width: 56px; height: 56px; border-radius: 50%; border: 0; cursor: pointer; display: grid; place-items: center; font-size: 26px; background: var(--accent-btn, #0060f0); color: var(--on-accent, #fff); box-shadow: 0 8px 24px -8px rgb(0 0 0 / .45); transition: transform var(--mov-base) var(--mov-curva); }
.cm-asistente__boton:hover { transform: translateY(-2px); }
.cm-asistente__boton:active { transform: scale(.95); }
.cm-asistente__boton:focus-visible { outline: 3px solid var(--focus, currentColor); outline-offset: 3px; }
.cm-asistente__panel { width: min(340px, calc(100vw - 32px)); max-height: min(70vh, 480px); overflow: auto; padding: 16px; border-radius: 16px; background: var(--bg-elevated, #fff); color: var(--text, #111); border: 1px solid var(--border, #ddd); box-shadow: 0 16px 48px -16px rgb(0 0 0 / .5); transform-origin: bottom right; animation: cm-panel var(--mov-base) var(--mov-curva) both; }
.cm-asistente__panel[hidden] { display: none; }
@keyframes cm-panel { from { opacity: 0; transform: translateY(8px) scale(.96); } }
.cm-asistente.cm-llamar .cm-asistente__boton { animation: cm-llamar 900ms var(--mov-curva) 2; }      /* dos saltos y se queda quieto */
@keyframes cm-llamar { 40% { transform: translateY(-8px); } }

/* Guía flotante: un personaje que sigue al puntero, comenta lo que se señala y, al tocarlo, abre el asistente.
   En pantalla táctil y con movimiento reducido se queda en su sitio (anclada) y comenta según lo que entra en pantalla. */
.cm-guia { position: fixed; top: 0; left: 0; z-index: calc(var(--mov-capa) - 5); width: var(--mov-guia-tamano, 56px); height: var(--mov-guia-tamano, 56px); pointer-events: none; opacity: 0; transition: opacity var(--mov-base); will-change: transform; }
.cm-guia.cm-guia--lista { opacity: 1; }
.cm-guia[hidden] { display: none; }
.cm-guia__boton { display: block; width: 100%; height: 100%; padding: 0; margin: 0; border: 0; background: none; border-radius: 50%; cursor: pointer; font-size: calc(var(--mov-guia-tamano, 56px) * .7); line-height: 1; filter: drop-shadow(0 6px 12px rgb(0 0 0 / .4)); }
.cm-guia__boton img, .cm-guia__boton svg { display: block; width: 100%; height: 100%; }
.cm-guia__boton:focus-visible { outline: 3px solid var(--focus, var(--accent, #fff)); outline-offset: 3px; }
.cm-guia--anclada { pointer-events: auto; transition: opacity var(--mov-base), transform 520ms var(--mov-curva); }
.cm-guia--anclada .cm-guia__boton { animation: cm-flotar 2.6s ease-in-out infinite alternate; --mov-flotar: 4px; }
.cm-guia--anclada .cm-guia__boton:hover { animation-play-state: paused; }
.cm-guia__globo { position: absolute; left: calc(100% + 8px); top: 4px; width: max-content; max-width: min(260px, 68vw); padding: 8px 12px; border-radius: 4px 14px 14px 14px; background: var(--bg-elevated, #fff); color: var(--text, #111); border: 1px solid var(--border, #ddd); box-shadow: 0 10px 28px -12px rgb(0 0 0 / .55); font: 500 14px/1.4 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; pointer-events: none; opacity: 0; transform: translateY(4px) scale(.96); transform-origin: left top; transition: opacity var(--mov-base), transform var(--mov-base) var(--mov-curva); }
.cm-guia--habla .cm-guia__globo { opacity: 1; transform: none; }
.cm-guia--izq .cm-guia__globo { left: auto; right: calc(100% + 8px); border-radius: 14px 4px 14px 14px; transform-origin: right top; }
.cm-guia--arriba .cm-guia__globo { top: auto; bottom: 4px; }
html.cm-quieto .cm-guia, html.cm-quieto .cm-guia__boton { animation: none !important; transition: opacity var(--mov-base) !important; }
@media (prefers-reduced-motion: reduce) { html:not(.cm-movimiento) .cm-guia, html:not(.cm-movimiento) .cm-guia__boton { animation: none !important; transition: opacity var(--mov-base) !important; } }
@media (forced-colors: active) { .cm-guia__globo { border: 1px solid CanvasText; } }
@media print { .cm-guia { display: none !important; } }

/* Botón para pausar el movimiento: aparece solo si hay algo que se mueve por su cuenta. */
[data-mov-interruptor][hidden] { display: none; }

/* ───────── Movimiento reducido: por el sistema o por el botón de la página. ───────── */

@media (prefers-reduced-motion: reduce) {
  html:not(.cm-movimiento) [data-mov], html:not(.cm-movimiento) [data-mov]::before, html:not(.cm-movimiento) [data-mov]::after { animation: none !important; transition-property: opacity, background-color, border-color, color !important; transition-duration: var(--mov-base) !important; transition-delay: 0s !important; }
  html:not(.cm-movimiento) [data-mov~="aparecer"] { opacity: 1 !important; transform: none !important; }
  html:not(.cm-movimiento) :is([data-mov~="elevar"], [data-mov~="inclinar"], [data-mov~="magnetico"], [data-mov~="profundidad"], [data-mov~="presionar"]) { transform: none !important; }
  html:not(.cm-movimiento) :is(.cm-cursor, .cm-particulas) { display: none !important; }
  html:not(.cm-movimiento) .cm-asistente__panel, html:not(.cm-movimiento) .cm-asistente__boton { animation: none !important; }
  html:not(.cm-movimiento) [data-mov~="cargando"][aria-busy="true"]::after { animation: cm-girar 1.6s linear infinite !important; }
}
html.cm-quieto [data-mov], html.cm-quieto [data-mov]::before, html.cm-quieto [data-mov]::after { animation: none !important; transition-property: opacity, background-color, border-color, color !important; transition-duration: var(--mov-base) !important; transition-delay: 0s !important; }
html.cm-quieto [data-mov~="aparecer"] { opacity: 1 !important; transform: none !important; }
html.cm-quieto :is([data-mov~="elevar"], [data-mov~="inclinar"], [data-mov~="magnetico"], [data-mov~="profundidad"], [data-mov~="presionar"]) { transform: none !important; }
html.cm-quieto :is(.cm-cursor, .cm-particulas) { display: none !important; }
html.cm-quieto .cm-asistente__panel, html.cm-quieto .cm-asistente__boton { animation: none !important; }
/* El indicador de "enviando" informa un estado: se conserva, más lento. */
html.cm-quieto [data-mov~="cargando"][aria-busy="true"]::after { animation: cm-girar 1.6s linear infinite !important; }

@media (forced-colors: active) { .cm-cursor, .cm-particulas { display: none !important; } }
@media print { [data-mov~="aparecer"] { opacity: 1 !important; transform: none !important; } .cm-cursor, .cm-particulas, .cm-asistente { display: none !important; } }
