/* ==========================================================================
   ESQUELETOS DE CARGA · CRM                                    [29/10/2026]
   CRM multiempresa · Ingenieros AVI · CALEP

   QUÉ SE PIDIÓ
     «Los spinner solo dicen espera, no dicen qué viene ni cuánto falta.
      Cambia el spinner por un esqueleto: bloques con la forma de lo que
      va a cargar. Que mida lo mismo que el contenido; si no, la pantalla
      brinca. Con un brillo suave, le dice al usuario que algo sigue
      cargando. Muestra lo que ya esté listo: primero los números, luego
      la gráfica y por último la tabla. El spinner sí sirve, pero para
      acciones cortas, como descargar un reporte. Skeleton para
      contenido, spinner para acciones.»

   QUÉ HAY AQUÍ
     · .esq            el bloque gris con el brillo que pasa.
     · .esq-l          un renglón de texto (alto de una línea del texto
                       de alrededor: mide en em).
     · .esq-n          una cifra grande (las de las tarjetas).
     · .esq-sr         «Cargando…» para lectores de pantalla (no se ve).
     · .boot-*         la pantalla de arranque con la forma del CRM.
     · .esq-p26        las tarjetas de Proyectos mientras llegan.
   Lo arma crm-esqueleto.js (window.crmEsq), con la MISMA tarjeta, tabla
   o lista de la pantalla real y la altura que tuvo la última vez.

   EL BRILLO, SUAVE Y QUIETO SI SE PIDE
     Un barrido de 1,6 s. Con «reducir movimiento» (sistema operativo)
     no se mueve: queda el bloque quieto.

   COLORES: solo variables del tema. En claro y en oscuro salen solas.
   ========================================================================== */
:root{ --esq-base:rgba(148,163,184,.16); --esq-luz:rgba(255,255,255,.07); }
html[data-theme="light"]{ --esq-base:#e3e8ee; --esq-luz:rgba(255,255,255,.78); }

.esq{ position:relative; overflow:hidden; display:block; background:var(--esq-base); border-radius:6px; }
.esq::after{ content:""; position:absolute; inset:0; transform:translateX(-100%);
  background:linear-gradient(90deg, transparent 0%, var(--esq-luz) 50%, transparent 100%);
  animation:esqBrillo 1.6s ease-in-out infinite; }
@keyframes esqBrillo{ to{ transform:translateX(100%); } }
@media (prefers-reduced-motion: reduce){ .esq::after{ animation:none; display:none; } }

.esq-l{ height:.85em; margin:.42em 0; border-radius:5px; }
.esq-n{ height:1em; width:3.2ch; border-radius:7px; }
.esq-c{ border-radius:50%; flex:none; }
/* Un texto FIJO (un rótulo, un botón) como bloque: el texto va adentro,
   transparente, y el bloque mide exactamente lo que medirá el texto. */
.esq.esq-txt{ display:inline-block; vertical-align:top; max-width:100%; color:transparent !important; border-radius:5px; user-select:none; }
.esq.esq-txt.btn{ background:var(--esq-base) !important; border-color:transparent !important; box-shadow:none !important; }
.esq-sr{ position:absolute !important; width:1px; height:1px; margin:-1px; padding:0; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0; }
.esq-caja[aria-busy="true"]{ cursor:progress; }

/* Renglones de una lista: el alto de un renglón real, sin texto. */
.esq-lista{ display:flex; flex-direction:column; gap:10px; padding:4px 0; }
.esq-fila{ display:flex; align-items:center; gap:12px; min-height:2.6em; }
.esq-fila .esq-l{ margin:0; }

/* Una tabla: se dibuja con la tabla real (misma clase), celdas grises. */
.esq-td .esq-l{ margin:.15em 0; }

/* Una gráfica: el recuadro de su alto, con barras de fondo. */
.esq-graf{ display:flex; align-items:flex-end; gap:3%; padding:14px 4% 10px; box-sizing:border-box; }
.esq-graf .esq{ flex:1; border-radius:5px 5px 2px 2px; }

/* Encima de un marco (las piezas de Egresos en el Dashboard), hasta que
   el marco avisa que ya pintó. */
.esq-sobre{ position:absolute; inset:0; z-index:2; padding:16px 18px; box-sizing:border-box; background:inherit;
  border-radius:inherit; display:flex; flex-direction:column; gap:12px; transition:opacity .25s ease; }
.esq-sobre.esq-fuera{ opacity:0; pointer-events:none; }
.esq-kpis{ display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:12px; }
.esq-kpi{ border:1px solid var(--line); border-radius:12px; padding:14px 16px; display:flex; align-items:center; gap:12px; min-height:62px; box-sizing:border-box; }

/* ----------------------------------------------------------------------
   PROYECTOS: las tarjetas mientras llegan. Misma rejilla (.p26-cards) y
   misma tarjeta (.p26-card); la altura, la de la última vez.
   ---------------------------------------------------------------------- */
.esq-p26 .p26-card{ padding-right:17px; }
.esq-p26 .esq-p26-cab{ display:flex; justify-content:space-between; align-items:center; gap:10px; }
.esq-p26 .esq-p26-cifras{ display:grid; grid-template-columns:1fr auto; gap:8px 16px; }
.esq-p26 .esq-p26-pie{ margin-top:auto; }

/* ----------------------------------------------------------------------
   LA PANTALLA DE ARRANQUE: la forma del CRM (menú, barra, cifras, dos
   paneles) en vez de un círculo girando. Con las MISMAS medidas del CRM,
   para que al entrar nada salte de sitio:
     · el menú recogido (--side-min, 60 px) en pantallas de 821 px o más;
       abierto (--side-w) si la persona lo dejó fijo con la chincheta
       (crm-esqueleto.js lo marca en <html data-boot-fijo>); escondido en
       820 px o menos, como el menú de verdad;
     · los márgenes de .main en cada ancho (34, 24, 20, 16, 14 y 12 px).
   ---------------------------------------------------------------------- */
#boot-loading.boot-esq{ position:fixed; inset:0; z-index:99999; display:flex; background:var(--bg); color:var(--txt);
  font-family:system-ui,"Segoe UI",Arial,sans-serif; overflow:hidden; }
.boot-side{ width:var(--side-min); flex:none; background:var(--panel); border-right:1px solid var(--line); padding:18px 8px;
  box-sizing:border-box; display:flex; flex-direction:column; gap:14px; overflow:hidden; }
html[data-boot-fijo] .boot-side{ width:var(--side-w); padding:18px 16px; }
.boot-logo{ display:flex; justify-content:center; padding:0 0 14px; border-bottom:1px solid var(--line); margin-bottom:4px; }
.boot-logo img{ height:56px; max-width:100%; object-fit:contain; opacity:.95; }
.boot-menu{ display:flex; align-items:center; justify-content:center; gap:10px; min-height:28px; }
.boot-menu .esq-l{ display:none; }
html[data-boot-fijo] .boot-menu{ justify-content:flex-start; }
html[data-boot-fijo] .boot-menu .esq-l{ display:block; }
.boot-main{ flex:1; min-width:0; padding:26px 34px; box-sizing:border-box; display:flex; flex-direction:column; gap:18px; }
.boot-top{ display:flex; justify-content:space-between; align-items:center; min-height:40px; margin-bottom:4px; }
.boot-kpis{ display:grid; grid-template-columns:repeat(4,1fr); gap:12px; }
.boot-kpi{ background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:14px 16px; display:flex; align-items:center; gap:13px; min-height:66px; box-sizing:border-box; }
.boot-panel{ background:var(--panel); border:1px solid var(--line); border-radius:12px; padding:18px; box-sizing:border-box; }
.boot-panel.alto{ flex:1.4; } .boot-panel.bajo{ flex:1; }
#boot-loading #boot-err{ position:absolute; left:50%; bottom:24px; transform:translateX(-50%); z-index:3; }
@media (max-width:1180px){ .boot-main{ padding:22px 24px; } }
@media (max-width:1024px){ .boot-main{ padding:20px; } }
@media (max-width:820px){
  .boot-side, html[data-boot-fijo] .boot-side{ display:none; }
  .boot-main{ padding:20px 16px; gap:14px; }
  .boot-kpis{ gap:9px; }
  .boot-kpi{ padding:11px; gap:9px; }
}
@media (max-width:640px){ .boot-main{ padding:14px; } .boot-kpis{ grid-template-columns:repeat(2,1fr); gap:8px; } }
@media (max-width:430px){ .boot-main{ padding:12px; } .boot-kpis{ gap:7px; } }
