/**
 * LM Contable — Loader de pantalla completa (splash), para transiciones
 * "duras" donde no hay nada más en pantalla que mostrar (recarga completa
 * de página vía syncPortal(), y cualquier otro punto que lo necesite en
 * Admin/Portal Cliente). Ver src/app-loader.js.
 *
 * Adaptado de loader_lmcontable_blanco.html/loader_lmcontable_oscuro.html
 * (prototipos entregados por el usuario, uno por tema): mismo look & feel --
 * isotipo flotando sobre un glow que respira, mensaje que cambia según
 * módulo/submódulo, barra de progreso con destello en loop -- reescrito
 * sobre los tokens --ds-* del design system (los prototipos usaban hex fijos
 * como scaffold de vista previa) y con la barra de progreso indeterminada
 * (loop) en vez de una animación de duración fija: la duración real de cada
 * operación varía, así que no hay timeline fijo que "adivinar". Reemplaza
 * por completo la versión anterior (revelado con máscara + destello
 * barrido) -- no queda nada de esa versión acá.
 */

.lm-app-loader {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ds-bg);
  visibility: hidden;
  pointer-events: none;
}

.lm-app-loader.is-visible {
  visibility: visible;
  pointer-events: auto;
}

.lm-app-loader-glow {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 44%, color-mix(in srgb, var(--ds-accent) 7%, transparent) 0%, transparent 31%);
  pointer-events: none;
}

.lm-app-loader-wrap {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

/* Sin desvanecimiento al cerrar (pedido explícito) -- hideAppLoader() quita
   is-visible directamente después de la pausa de "Listo", el overlay
   desaparece de golpe (ver .lm-app-loader.is-visible arriba: sin esa clase
   vuelve a visibility:hidden, sin transición declarada en ninguna parte).

   Entrada del conjunto logo+glow+texto+barra al mostrarse (equivalente a la
   animación "enter" de .loader en los prototipos, que ahí corría una sola
   vez porque era una página estática -- acá se repite en cada showAppLoader()/
   playLogoutTransition() porque is-entering se vuelve a agregar cada vez).
   Gateada por is-entering, NO por is-playing (que solo controla el destello
   de la barra de progreso, ver más abajo) -- separadas a propósito: la
   recarga de "Sincronizar" (syncPortal() en admin.js) muestra el loader en
   la página actual, recarga a los ~60ms, y la página nueva lo vuelve a
   mostrar de forma síncrona -- si el barrido de entrada se gatea con
   is-playing, ese segundo "aparecer" reinicia la animación de opacidad 0 a
   mitad del primer barrido y se ve como un salto/parpadeo (reportado). Con
   is-entering, showAppLoader({instant:true}) (el que usa ese caso) y el
   <script> inline de continuidad (ver admin.html) simplemente omiten esta
   clase -- el overlay aparece ya asentado, sin reiniciar nada. */
.lm-app-loader.is-entering .lm-app-loader-wrap {
  animation: lm-loader-enter .7s cubic-bezier(.22,1,.36,1) both;
}

@keyframes lm-loader-enter {
  from { opacity: 0; transform: scale(.96) translateY(5px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

/* Isotipo + glow local: mismas medidas que los prototipos (contenedor
   116x116, glow 100x100 detrás, isotipo a 110px de ancho) -- el isotipo ya
   NO se estira a un ancho de frame como antes (esa versión usaba un lockup
   horizontal de 640x165; el isotipo es ~1:1 y se ve mejor a tamaño fijo). */
.lm-app-loader-logo-frame {
  width: 116px;
  height: 116px;
  position: relative;
  display: grid;
  place-items: center;
}

.lm-app-loader-logo-glow {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--ds-accent) 10%, transparent), transparent 72%);
  filter: blur(9px);
  animation: lm-loader-breathe 2.5s ease-in-out infinite;
}

.lm-app-loader-logo {
  display: block;
  width: 110px;
  height: auto;
  position: relative;
  z-index: 1;
  filter: drop-shadow(0 8px 18px color-mix(in srgb, var(--ds-accent) 14%, transparent));
  animation: lm-loader-float 2.5s ease-in-out infinite;
}

@keyframes lm-loader-float {
  0%, 100% { transform: translateY(0) scale(1); }
  50%      { transform: translateY(-3px) scale(1.012); }
}

@keyframes lm-loader-breathe {
  0%, 100% { opacity: .38; transform: translate(-50%, -50%) scale(.96); }
  50%      { opacity: .70; transform: translate(-50%, -50%) scale(1.05); }
}

.lm-app-loader-status { position: relative; height: 20px; min-width: 220px; display: flex; align-items: center; justify-content: center; }

.lm-app-loader-msg {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-size: 13px;
  color: var(--ds-text-secondary);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .35s ease, transform .35s ease;
  white-space: nowrap;
}

.lm-app-loader-msg.is-active { opacity: 1; transform: translateY(0); }

.lm-app-loader-msg--done { color: var(--ds-text); font-weight: 600; }
.lm-app-loader-msg--done .lm-app-loader-check { color: var(--ds-accent); display: inline-block; transform: scale(0); }
.lm-app-loader-msg--done.is-active .lm-app-loader-check { animation: lm-loader-check-pop .4s cubic-bezier(.34,1.56,.64,1) .05s forwards; }
@keyframes lm-loader-check-pop { to { transform: scale(1); } }

/* is-settled: el check ya hizo su pop en la página anterior (playLogoutTransition()
   lo deja asentado antes de navegar, ver app-loader.js) -- a diferencia de
   una transition, una animation SÍ se reproduce en el primerísimo cálculo de
   estilo de un documento nuevo aunque la clase ya venga puesta desde el
   <script> inline síncrono (sin un "antes" pintado que comparar, a
   diferencia de una transition). Sin esto, index.html volvía a reproducir
   el pop del check al llegar -- un segundo "Listo" encima del que ya se
   había visto (reportado). Solo lo usa el <script> inline de index.html
   para la continuación post-logout. */
.lm-app-loader.is-settled .lm-app-loader-msg--done.is-active .lm-app-loader-check { animation: none; transform: scale(1); }

.lm-app-loader-progress-track {
  width: 220px;
  height: 3px;
  position: relative;
  overflow: hidden;
  border-radius: 999px;
  background: linear-gradient(90deg,
    transparent,
    color-mix(in srgb, var(--ds-accent) 11%, transparent) 12%,
    color-mix(in srgb, var(--ds-accent) 15%, transparent) 50%,
    color-mix(in srgb, var(--ds-accent) 11%, transparent) 88%,
    transparent);
}

.lm-app-loader-progress-fill {
  position: absolute;
  top: 0;
  left: 0;
  height: 100%;
  width: 38%;
  border-radius: inherit;
  background: linear-gradient(90deg,
    transparent 0%,
    color-mix(in srgb, var(--ds-accent-light) 38%, transparent) 10%,
    color-mix(in srgb, var(--ds-accent-light) 72%, transparent) 32%,
    var(--ds-accent) 52%,
    color-mix(in srgb, var(--ds-accent-light) 58%, transparent) 72%,
    color-mix(in srgb, var(--ds-accent-light) 10%, transparent) 90%,
    transparent 100%);
  transform: translateX(-130%);
}

/* Indeterminada mientras is-playing (duración real desconocida): un
   destello que recorre la pista en loop -- en vez del fill fijo de los
   prototipos, pensados para una carga de duración fija que no aplica a
   operaciones de duración variable. Al llamar hideAppLoader(), is-finishing
   detiene el loop y completa la barra al 100% antes de que el overlay
   desaparezca (ver hideAppLoader() en app-loader.js), para un cierre
   satisfactorio en vez de un corte abrupto a mitad de barrido. */
.lm-app-loader.is-playing .lm-app-loader-progress-fill { animation: lm-loader-progress-shimmer 2.65s cubic-bezier(.55,0,.35,1) infinite; }
.lm-app-loader.is-finishing .lm-app-loader-progress-fill { animation: none; width: 100%; transform: none; opacity: 1; transition: width .3s ease, transform .3s ease, opacity .3s ease; }

@keyframes lm-loader-progress-shimmer {
  0%          { transform: translateX(-130%); opacity: 0; }
  10%         { opacity: .85; }
  72%         { opacity: .85; }
  88%, 100%   { transform: translateX(310%); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .lm-app-loader.is-entering .lm-app-loader-wrap { animation-duration: .01s !important; }
  .lm-app-loader-logo { animation-duration: .01s !important; }
  .lm-app-loader-logo-glow { animation-duration: .01s !important; }
  .lm-app-loader.is-playing .lm-app-loader-progress-fill { animation: none; width: 60%; transform: none; opacity: 1; }
}

/* Entrada suave del contenido real al reemplazar un skeleton/estado previo
   -- decorativa únicamente, nunca gatea cuándo el contenido real queda
   visible/interactivo (eso sigue pasando exactamente igual que hoy). Se
   quita y se vuelve a agregar en JS (con un reflow forzado en medio) para
   que reinicie limpio en cada navegación, en vez de solo la primera vez. */
@keyframes lm-content-enter { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.lm-content-enter { animation: lm-content-enter .15s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .lm-content-enter { animation-duration: .01s; }
}
