/* ============================================================
   EJN — Estilos de aplicación
   Se apoya en ejn-tokens.css (fuente de verdad de la marca).
   Regla del manual §04: el color del módulo es ACENTO,
   nunca color dominante. Base neutra siempre.
   ============================================================ */

/* Montserrat self-hosted — tipografía oficial del manual v4 §4.
   La CSP es `font-src 'self'`: no se puede tirar de Google Fonts, hay
   que dejar los .woff2 en /assets/fonts/. Si los archivos todavía no
   están, el navegador cae al fallback del sistema sin romper nada,
   pero el wordmark NO se ve como el manual.

   Archivos esperados (descargar de fonts.google.com/specimen/Montserrat):
     Montserrat-Regular.woff2   (400)
     Montserrat-Medium.woff2    (500)
     Montserrat-SemiBold.woff2  (600)
     Montserrat-Bold.woff2      (700) */
@font-face {
  font-family: 'Montserrat';
  src: url('/assets/fonts/Montserrat-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/assets/fonts/Montserrat-Medium.woff2') format('woff2');
  font-weight: 500; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/assets/fonts/Montserrat-SemiBold.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('/assets/fonts/Montserrat-Bold.woff2') format('woff2');
  font-weight: 700; font-style: normal; font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }

/* Reset de tipografia para controles de formulario (17/09/2026, reporte de
   Daniel: campos en investigacion.php con tipografia nativa del navegador
   pese a que el CSS de la plataforma ya define font-family en body.ejn --
   raiz del problema: <input>/<select>/<textarea>/<button> NO heredan
   font-family del documento por defecto en NINGUN navegador, la hoja de
   estilos del user-agent les fuerza su propia fuente de control nativo
   salvo que se pise explicitamente. Esto se venia parchando caso por caso
   cada vez que alguien lo notaba (fechas sueltas 14/09, RGRL 11/09,
   tabla-simple--formulario) -- pedido explicito de Daniel de "dejarlo
   resuelto para que no se repita". Este reset global, de especificidad
   minima (selectores de elemento sin clase), cierra el hueco de una vez
   para TODO campo -- actual y futuro, .campo o suelto, ERP o publico
   (ejn-app.css la cargan ambos) -- sin que ningun chat tenga que acordarse
   de repetir font-family campo por campo. No pisa ninguna regla mas
   especifica que ya lo fijaba a proposito (fechas, tabla-simple--formulario,
   etc.): esas siguen ganando por especificidad, esto solo cubre los casos
   que hoy no tenian nada. */
input, select, textarea, button { font-family: inherit; }

/* El reset de arriba fija font-family en el <input type="date"> anfitrion,
   pero los "segmentos" que se ven adentro (dd/mm/aaaa) los dibuja el propio
   navegador con un control interno (shadow DOM del user-agent) que en
   motores WebKit/Blink (Chrome, Edge, Safari -- que es como Daniel accede)
   NO siempre hereda el font-family del host aunque el CSS de afuera ya lo
   fije: hay que apuntarle explicitamente a esas partes internas via sus
   pseudo-elementos -webkit-. Encontrado 17/09/2026 (reporte de Daniel,
   captura): el campo "Fecha programada" de Agenda de visitas en
   investigacion.php seguia con tipografia nativa pese al reset de arriba --
   pero el problema es generico a CUALQUIER <input type="date"> de la
   plataforma, no puntual de esa pantalla, por eso el fix va aca y no en una
   vista puntual. Firefox no expone estos pseudo-elementos (los ignora sin
   romper nada) porque ahi el selector nativo de fecha ya hereda bien. */
input[type="date"]::-webkit-datetime-edit,
input[type="date"]::-webkit-datetime-edit-fields-wrapper,
input[type="date"]::-webkit-datetime-edit-text,
input[type="date"]::-webkit-datetime-edit-day-field,
input[type="date"]::-webkit-datetime-edit-month-field,
input[type="date"]::-webkit-datetime-edit-year-field {
  /* 17/09/2026, segundo reporte de Daniel (misma pantalla, seguia mal):
     "font-family: inherit" no alcanzo -- la hipotesis es que estos
     pseudo-elementos del shadow DOM del navegador no resuelven "inherit"
     ni una custom property (var(--font-family)) de forma confiable en
     todas las versiones de Chrome, porque ambos mecanismos dependen de
     la cascada de herencia normal, que el arbol de sombra del user-agent
     no siempre respeta igual que el DOM liviano. Se pisa con el valor
     final ya resuelto, sin depender de herencia ni de variables. */
  font-family: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* [hidden] no siempre gana: cualquier contenedor con display explicito
   (grid/flex, ej. .fila) tiene la misma especificidad que el [hidden]
   del user-agent y, por venir de una hoja de autor, le gana -- el
   elemento queda oculto en el DOM pero sigue pintandose en pantalla.
   Encontrado 09/09/2026: iniciarCamposCondicionales() ocultaba
   correctamente el establecimiento en Tipo=in_itinere (hidden=true en
   el DOM) pero .fila{display:grid} lo mantenia visible igual. Regla
   global, no por componente -- cualquier data-visible-si futuro con
   display explicito tiene la misma falla si no esta esto. */
[hidden] { display: none !important; }

body.ejn {
  margin: 0;
  font-family: var(--font-family);
  font-size: var(--fs-body);
  color: var(--gray-900);
  background: var(--gray-50);
  line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--ejn-blue-dark); }

/* ---------- Pantalla de acceso ---------- */

/* Selector con la misma especificidad que body.ejn, y posterior,
   para que gane el fondo navy de la pantalla de acceso. */
body.ejn-publico {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  /* 06/09/2026: manchas degradadas indigo/celeste detras de la tarjeta de
     vidrio (antes blanco plano) -- pedido de Daniel de estilo "Cristal /
     Vidrio Diurno". Fijo (no scrollea) porque la pantalla de acceso no
     scrollea en la practica. */
  background:
    radial-gradient(760px circle at 14% 10%, rgba(94,92,255,.20), transparent 60%),
    radial-gradient(820px circle at 88% 92%, rgba(143,217,255,.24), transparent 60%),
    var(--gray-50);
  background-attachment: fixed;
}

.acceso {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-5);
}

.acceso__pie {
  text-align: center;
  padding: var(--space-4);
  font-size: var(--fs-small);
  color: var(--gray-400);
}

/* 06/09/2026: pedido nuevo de Daniel ("Cristal / Vidrio Diurno") reemplaza
   el pedido anterior de esta misma sesion (tarjeta blanca fundida con la
   pagina, sin sombra/borde). Ahora la tarjeta es vidrio real -- blur +
   traslucidez + sombra suave -- flotando sobre las manchas degradadas del
   fondo (ver body.ejn-publico). El logo no se toca. */
.tarjeta-acceso {
  width: 100%;
  max-width: 400px;
  background: var(--cristal-glass-bg-strong);
  backdrop-filter: blur(var(--cristal-blur)) saturate(160%);
  -webkit-backdrop-filter: blur(var(--cristal-blur)) saturate(160%);
  border: 1px solid var(--cristal-glass-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-lg);
}

.tarjeta-acceso__marca {
  text-align: center;
  margin-bottom: var(--space-6);
}

/* 21/09/2026: el <select> "Tipo de acceso" del login (reemplaza a las 4
   pestañas, que ya no entraban en el ancho de la tarjeta -- ver
   .pestanas--oculto en rixart-erp.css y el comentario en auth/login.php).
   select{} más abajo ya lo deja con la apariencia estándar de los combos
   públicos; sólo hace falta que ocupe todo el ancho y separe del contenido
   de abajo, igual que .pestanas. */
.campo--selector-acceso { margin-bottom: var(--space-4); }
.selector-acceso { width: 100%; }

/* El ícono va libre, sin contenedor. En el manual el aro circular es
   sólo la variante avatar (§5), no la identidad principal. */
.escudo-circulo {
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* «EJN» en bold y el nombre del producto en regular con su color,
   igual que el bloque de marca del manual. */
.wordmark {
  margin: var(--space-3) 0 0;
  font-size: 34px;
  font-weight: var(--fw-bold);
  letter-spacing: 3px;
  color: var(--ejn-navy);
}

.tagline {
  margin: 6px 0 0;
  font-size: 10.5px;
  font-weight: var(--fw-medium);
  letter-spacing: 2.4px;
  line-height: 1.7;
  text-transform: uppercase;
  color: var(--gray-600);
}

/* ---------- Formularios ---------- */

.formulario { display: flex; flex-direction: column; gap: var(--space-4); }

.campo { display: flex; flex-direction: column; gap: 6px; }

/* Lista compacta de checkboxes (08/09/2026, pedido de Daniel: el bloque
   "Contingencia, enfermedad y objeto reclamado" de Legales perdía mucho
   espacio vertical con un checkbox por línea). Gap chico a propósito --
   son opciones de un mismo grupo, no campos independientes como .campo. */
.lista-check { display: flex; flex-direction: column; gap: 2px; }

/* .campo--check con tipografía propia, en vez de depender de heredarla de
   ".campo label" (08/09/2026, bug reportado por Daniel: los 4 checkboxes de
   "Reclamo" se veían con otra tipografía que los de "Contingencia" -- los
   de Contingencia están anidados en un .campo y sí heredaban el estilo, los
   de Reclamo quedaron sueltos dentro de .lista-check al sacarlos de la
   fila--4 y no heredaban nada, mostrando el estilo default del navegador).
   Poniéndolo acá en vez de en .campo label, .campo--check se ve igual
   tenga o no un .campo como ancestro. */
.campo--check { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--gray-700); }

.campo label {
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  color: var(--gray-700);
}

.campo input {
  font-family: var(--font-family);
  font-size: var(--fs-body);
  padding: 10px 12px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--gray-900);
  transition: border-color .15s, box-shadow .15s;
}

.campo input:focus {
  outline: none;
  border-color: var(--ejn-blue);
  box-shadow: 0 0 0 3px var(--ejn-blue-soft);
}

/* ---------- Desplegables y áreas de texto ----------
   Un desplegable es un campo de texto que además abre una lista: mismo trazo,
   mismo radio, mismo fondo y mismo foco. Se le saca la apariencia nativa del
   sistema operativo y se le dibuja la flecha, porque si no cada navegador lo
   pinta distinto y en la misma fila conviven dos alturas y dos tipografías.

   Vive acá y no en `ejn-erp.css` a propósito: las pantallas públicas —login y
   alta de canal— no cargan la hoja del ERP, y ahí los desplegables quedaban
   nativos al lado de campos de texto ya estilados. */
.campo select,
select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  font-family: var(--font-family);
  font-size: var(--fs-body);
  line-height: 1.4;
  padding: 10px 30px 10px 12px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
  background-color: var(--white);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%234B5563' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  color: var(--gray-900);
  cursor: pointer;
  transition: border-color .15s, box-shadow .15s;
}

.campo textarea {
  font-family: var(--font-family);
  font-size: var(--fs-body);
  line-height: 1.5;
  padding: 10px 12px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--gray-900);
  resize: vertical;
  transition: border-color .15s, box-shadow .15s;
}

select:hover { border-color: var(--gray-400); }

.campo select:focus,
.campo textarea:focus,
select:focus {
  outline: none;
  border-color: var(--ejn-blue);
  box-shadow: 0 0 0 3px var(--ejn-blue-soft);
}

.campo select:disabled,
.campo textarea:disabled,
.campo textarea[readonly],
select:disabled {
  background-color: var(--gray-50);
  color: var(--gray-600);
  cursor: default;
  opacity: 1;
}

/* El input de archivo no se puede estilar por dentro: se estila el botón. */
.campo input[type="file"] { padding: 7px 10px; cursor: pointer; }

.campo input[type="file"]::file-selector-button {
  font-family: var(--font-family);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  margin-right: 10px;
  padding: 5px 12px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
  background: var(--gray-50);
  color: var(--gray-700);
  cursor: pointer;
}

.campo input[type="file"]::file-selector-button:hover {
  border-color: var(--ejn-blue);
  color: var(--ejn-blue);
}

/* Bug real (06/09/2026): un input[type=file] disabled se veia identico al
   habilitado -- el boton nativo no hereda ningun estilo del :disabled del
   input padre por default. Sin esto, el click no abria el picker y no
   habia ninguna pista visual de por que. */
.campo input[type="file"]:disabled {
  cursor: default;
}

.campo input[type="file"]:disabled::file-selector-button {
  cursor: default;
  background-color: var(--gray-50);
  color: var(--gray-400);
  border-color: var(--gray-200);
}

/* El transition faltaba sólo en el input: se unifica para los tres. */
.campo input { transition: border-color .15s, box-shadow .15s; }

/* Campos con error de validación (08/09/2026, pedido de Daniel): al fallar
   un alta/edición se resalta en rojo el campo puntual que causó el rechazo,
   sin perder lo tipeado -- primera implementación en Legales/estudios
   jurídicos, ver docs/PENDIENTES_PLATAFORMA.md para la regla general que se
   pide aplicar a toda la plataforma. Reusa los mismos tokens que ya pintan
   de rojo .badge--dang/.aviso-barra--dang, no crea colores nuevos. */
.campo--error label { color: var(--ejn-red-dark); }

.campo--error input,
.campo--error select,
.campo--error textarea {
  border-color: var(--ejn-red);
  background: var(--ejn-red-soft);
}

.campo--error input:focus,
.campo--error select:focus,
.campo--error textarea:focus {
  border-color: var(--ejn-red);
  box-shadow: 0 0 0 3px var(--ejn-red-soft);
}

/* ---------- Legajo: un archivo por requisito ----------
   Se sube de a uno porque un error en el último documento no debe obligar a
   volver a elegir los seis anteriores. */
/* Texto que el sistema le va a mostrar a otro tal cual está escrito. Se
   destaca para que quien decide vea exactamente qué va a leer el otro. */
.cita {
  margin: 8px 0 0;
  padding: 10px 14px;
  border-left: 3px solid var(--modulo-color, var(--gray-400));
  background: var(--gray-50);
  color: var(--gray-700);
  font-size: var(--fs-small);
  font-style: italic;
}

/* Avisos propios del canal. No son la banda de gestión de la aseguradora:
   ésos hablan de web services e intercambios y el canal no los ve. */
.avisos { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: flex; flex-direction: column; gap: 8px; }

.avisos__item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--ejn-amber-300, #E8C77A);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  background: var(--ejn-amber-50, #FDF8EC);
}

/* Acción que existe pero todavía no corresponde. Se muestra apagada en lugar
   de esconderla: el usuario tiene que saber que el paso está y por qué no. */
.btn--inhabilitado {
  opacity: .45;
  cursor: not-allowed;
}

.avisos__cuerpo { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.avisos__titulo { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--gray-800); }
.avisos__texto  { font-size: var(--fs-small); color: var(--gray-700); }
.avisos__pie    { font-size: 11px; color: var(--gray-500); }

.legajo { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }

.legajo__fila {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-sm);
  background: var(--white);
}

.legajo__fila--ok { border-color: var(--gray-300); background: var(--gray-50); }

.legajo__datos  { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.legajo__nombre { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--gray-800); }
.legajo__obl    { color: var(--ejn-red, #C94434); font-weight: var(--fw-bold); }
.legajo__ayuda  { font-size: 11px; color: var(--gray-500); }
.legajo__archivo{ font-size: 11px; color: var(--gray-600); font-family: var(--font-mono, monospace); }

.legajo__forma  { display: flex; align-items: center; gap: 8px; }
.legajo__forma .campo { gap: 0; }
.legajo__forma input[type="file"] { font-size: 11.5px; padding: 4px 8px; max-width: 260px; }

@media (max-width: 720px) {
  .legajo__fila  { grid-template-columns: 1fr; }
  .legajo__forma { flex-wrap: wrap; }
}

.btn--bloque { width: 100%; justify-content: center; }

.nota {
  margin: var(--space-5) 0 0;
  font-size: var(--fs-small);
  color: var(--gray-600);
  text-align: center;
}
/* Secreto/clave manual de TOTP: monospace, se puede cortar en cualquier
   punto para no desbordar la tarjeta angosta de auth. */
.nota--codigo { font-family: monospace; letter-spacing: .1em; word-break: break-all; }

/* Tarjeta de conformidad legal (Work, "Mis datos de contacto", 21/09/2026,
   pedido de Daniel): mismo criterio que .tarjeta--gris para "tarjetas
   anidadas" dentro de otra .tarjeta (ver rixart-erp.css) -- el texto de
   conformidad queda visualmente agrupado con los checks que gobierna, en
   vez de flotar suelto arriba del formulario. */
.aviso-legal { padding: var(--space-4); margin: var(--space-4) 0; }
.aviso-legal__texto {
  font-size: var(--fs-small);
  color: var(--gray-600);
  line-height: 1.5;
  margin: 0 0 var(--space-3);
}
.aviso-legal .campo--checkbox:last-child { margin-bottom: 0; }
/* Lista de códigos de recuperación 2FA: sin viñetas, un código por línea. */
.nota--codigos-lista { font-family: monospace; font-size: 1.1em; line-height: 2; list-style: none; padding: 0; }

/* Wrapper del QR de configuración TOTP. */
.totp-qr { text-align: center; margin: 1rem 0; }
.totp-qr img { max-width: 100%; }

/* Franja decorativa con la familia de módulos. */
.familia-modulos {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--gray-100);
}

.familia-modulos img {
  opacity: .55;
  transition: opacity .2s;
}

.tarjeta-acceso:hover .familia-modulos img { opacity: .85; }

/* ---------- Alertas ---------- */

.alerta {
  margin: 0 0 var(--space-4);
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  font-size: var(--fs-small);
  border: 1px solid transparent;
}

.alerta--error       { background: var(--ejn-red-soft);   color: var(--ejn-red-dark);   border-color: #F1C4C4; }
.alerta--info        { background: var(--ejn-blue-soft);  color: var(--ejn-blue-dark);  border-color: #C7E0F2; }
.alerta--advertencia { background: var(--ejn-gold-soft);  color: var(--ejn-gold-dark);  border-color: #EFD9A0; }

/* ---------- Layout del panel ---------- */

/* 12/09/2026: el fondo tornasolado (ver historial arriba en el commit
   de esta misma fecha) quedaba lindo pero Daniel prefirio volver a
   fondo blanco plano y usar sombra en las tarjetas/formularios en su
   lugar (.tarjeta, ejn-erp.css) para dar sensacion de profundidad.
   .app es el que realmente pinta el fondo visible (cubre 100vh encima
   de <body>), por eso el valor vive aca. */
.app {
  display: flex; height: 100vh; overflow: hidden;
  background: var(--white);
}

.barra-lateral {
  width: var(--sidebar-width);
  flex-shrink: 0;
  background: var(--sidebar-bg);
  backdrop-filter: blur(var(--cristal-blur));
  -webkit-backdrop-filter: blur(var(--cristal-blur));
  border-right: 1px solid var(--sidebar-borde);
  box-shadow: var(--shadow-sm);
  color: var(--sidebar-texto);
  display: flex;
  flex-direction: column;
  padding: var(--space-5) var(--space-4);
}  /* 06/09/2026: vidrio (blur+sombra suave) -- pedido de Daniel "Cristal / Vidrio Diurno" */

.barra-lateral__marca {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--sidebar-borde);
  text-decoration: none;
  color: var(--ejn-navy);
}

/* Wordmark: «EJN» en bold y el descriptor en regular, como manda el
   manual. El descriptor toma el color del módulo activo. */
.barra-lateral__wordmark {
  font-size: 19px;
  font-weight: var(--fw-regular);
  letter-spacing: .3px;
  line-height: 1.1;
  color: var(--ejn-navy);
}

.barra-lateral__wordmark b {
  font-weight: var(--fw-bold);
}

.barra-lateral__wordmark em {
  font-style: normal;
  color: var(--module-accent, var(--ejn-teal));
}

/* Wordmark RixART trazado (05/09/2026): reemplaza el texto "EJN ART" a
   nivel de marca madre (sin módulo activo) por el SVG real de la placa,
   fiel al manual -- nunca texto con fuente del sistema. currentColor
   toma el color ya definido por el contenedor (.wordmark o
   .barra-lateral__wordmark). */
.wordmark-rixart { display: block; width: auto; }
.wordmark .wordmark-rixart { height: 34px; }
.barra-lateral__wordmark .wordmark-rixart { height: 16px; }

/* Con el menu desplegado se ve solo el wordmark "RIXART"; el isologo (R
   sobre placa navy) sólo aparece cuando el menu esta contraido -- ahí no
   entra texto y hace falta un simbolo (pedido de Daniel, 06/09/2026). */
.barra-lateral__marca .marca-escudo { display: none; }
.app--plegado .barra-lateral__marca .marca-escudo { display: block; }

.barra-lateral__nav {
  flex: 1;
  padding-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: 2px;
  overflow-y: auto;
}

.nav-titulo {
  margin: var(--space-4) 0 6px;
  padding: 0 12px;
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--gray-400);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--sidebar-texto);
  text-decoration: none;
  font-size: var(--fs-body);
  border-left: 3px solid transparent;
}

a.nav-item:hover { background: var(--gray-100); color: var(--ejn-navy); }

/* Punto con el color del módulo: identifica cada entrada de un vistazo. */
.nav-item__punto {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--module-accent, var(--gray-300));
}

/* El ítem activo lleva el acento del módulo en curso. */
.nav-item--activo {
  background: var(--module-accent-soft, var(--ejn-azul-acento-soft));
  color: var(--ejn-navy);
  font-weight: var(--fw-semibold);
  border-left-color: var(--module-accent, var(--ejn-azul-acento));
}

/* Módulo sin permiso: visible pero inerte. */
.nav-item--bloqueado {
  color: var(--gray-400);
  cursor: not-allowed;
}

.nav-item--bloqueado .nav-item__punto { background: var(--gray-300); }

.barra-lateral__pie {
  padding-top: var(--space-4);
  border-top: 1px solid var(--sidebar-borde);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.usuario__nombre { font-size: var(--fs-small); color: var(--gray-600); }

/* Columna derecha: barra superior fija + contenido desplazable. */
.marco {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.barra-superior {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-4);
  height: var(--topbar-height);
  padding: 0 var(--space-6);
  background: var(--white);
  border-bottom: 1px solid var(--gray-200);
  flex-shrink: 0;
}

.usuario-chip {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-width: 0;
}

/* Ahora es un enlace a /mi-cuenta (06/09/2026) -- necesita su propia
   senal de que se puede clicar, texto sin subrayado por defecto. */
.usuario-chip--clicable {
  text-decoration: none;
  border-radius: var(--radius-sm);
  padding: 4px 8px;
  margin: -4px -8px;
  transition: background-color .15s ease;
}
.usuario-chip--clicable:hover,
.usuario-chip--clicable:focus-visible {
  background-color: var(--gray-100);
}

.usuario-chip__nombre {
  font-size: var(--fs-small);
  color: var(--gray-900);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Avatar en la barra superior (28/09/2026, pedido de Daniel) -- foto
   real (usuario-chip__foto) o inicial de respaldo (usuario-chip__inicial)
   cuando todavia no subio ninguna. Mismo tamaño en ambos casos para que
   el layout no salte al elegir/quitar una foto. */
.usuario-chip__foto {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  box-shadow: var(--shadow-sm);
}
.usuario-chip__inicial {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--ejn-azul-acento, var(--ejn-blue));
  color: var(--white);
  font-size: 12px;
  font-weight: var(--fw-semibold);
}

/* Foto de perfil en "Mi cuenta" -- misma pareja foto/inicial que el
   topbar, en tamaño grande (88px) y con las acciones de subir/quitar al
   lado (ver mi_cuenta.php). */
.foto-perfil {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  flex-wrap: wrap;
}
.foto-perfil__vista img,
.foto-perfil__inicial {
  width: 88px;
  height: 88px;
  border-radius: 50%;
}
.foto-perfil__vista img {
  object-fit: cover;
  box-shadow: var(--shadow-sm);
}
.foto-perfil__inicial {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--ejn-azul-acento, var(--ejn-blue));
  color: var(--white);
  font-size: 32px;
  font-weight: var(--fw-semibold);
}
.foto-perfil__acciones {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.foto-perfil__acciones input[type="file"] {
  font-size: var(--fs-small);
  max-width: 220px;
}

/* ---------- Selector de color de tema (Mi cuenta, 07/09/2026) ----------
   Cada boton es un <form> propio que postea a /mi-cuenta/tema -- clic en
   el color = aplicado, sin paso intermedio de "Guardar" (mismo criterio
   que el selector de color de acento de macOS en Preferencias del
   Sistema, que fue justamente la referencia que pidio Daniel).

   Sin display:inline-block en el <form> a proposito: .selector-temas ya
   es flex, y un contenedor flex "blockifica" a sus hijos directos para
   el layout sin importar el display propio de cada uno -- no hace falta
   forzarlo, y forzarlo por style="" inline no funcionaria igual (ver
   nota mas abajo).

   El color de cada bolita NO se manda por style="--swatch: #hex" inline
   -- se probo así primero y quedaban todas blancas/sin color: el sitio
   tiene CSP style-src 'self' (public/.htaccess, endurecido por el chat
   de Seguridad) sin 'unsafe-inline', asi que el navegador ignora
   CUALQUIER atributo style="" del HTML, no solo este. Por eso cada
   color es una clase modificadora fija (.tema-swatch--lila, etc.) con
   el hex hardcodeado -- mismo valor que --ejn-azul-acento de esa
   paleta en ejn-tokens.css y que CuentaRepo::TEMAS[x]['muestra']; si se
   agrega un color nuevo hay que tocar las 3 puntas a mano (documentado
   en docs/ESTADO.md). Hay ~27 archivos en app/Views que todavia usan
   style="" inline en otras pantallas -- funcionan por casualidad si
   nunca se probaron con el CSP real activo; queda como P-89 en
   PENDIENTES_PLATAFORMA.md, fuera de alcance de este cambio. */
.selector-temas__ayuda {
  margin-bottom: 12px;
}
.selector-temas {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}
.tema-swatch {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
  padding: 0;
  box-shadow: var(--shadow-sm);
  transition: transform .15s ease, box-shadow .15s ease;
}
.tema-swatch:hover {
  transform: scale(1.08);
}
.tema-swatch:focus-visible {
  outline: 2px solid var(--gray-900);
  outline-offset: 2px;
}
.tema-swatch--activo {
  box-shadow: 0 0 0 2px var(--white), 0 0 0 4px var(--gray-900), var(--shadow-sm);
}
.tema-swatch--lila    { background: #5E5CFF; }
.tema-swatch--celeste { background: #3E9BE0; }
.tema-swatch--menta   { background: #2FBF9C; }
.tema-swatch--rosa    { background: #F0629A; }
.tema-swatch--durazno { background: #F0985A; }
.tema-swatch--grafito { background: #64748B; }

/* Color de acento LIBRE (18/09/2026, pedido de Daniel -- ver el docblock
   de CuentaRepo::actualizarTemaPersonalizado()): <input type="color">
   nativo en vez de una clase modificadora fija como las 6 de arriba --
   acá no hay un hex predefinido, es justamente el punto. Se le pisan los
   estilos nativos del navegador (appearance/border/padding) para que
   quede redondo del mismo tamaño que el resto de .tema-swatch en vez del
   cuadrado con borde que trae por defecto -- el "relleno" que se ve
   adentro siempre es el color elegido de verdad (mismo valor que viaja
   en tema_color_custom), no un ícono ni un degradé de adorno. */
.tema-swatch--personalizado {
  appearance: none;
  -webkit-appearance: none;
  border: none;
  overflow: hidden;
}
.tema-swatch--personalizado::-webkit-color-swatch-wrapper { padding: 0; }
.tema-swatch--personalizado::-webkit-color-swatch { border: none; border-radius: 50%; }
.tema-swatch--personalizado::-moz-color-swatch { border: none; border-radius: 50%; }

/* Botón de icono (campana, cerrar). */
.btn-icono {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--gray-300);
  background: var(--white);
  color: var(--gray-700);
  cursor: pointer;
  flex-shrink: 0;
  transition: background .15s, border-color .15s, color .15s;
}

.btn-icono:hover {
  background: var(--module-accent-soft, var(--ejn-blue-soft));
  border-color: var(--module-accent, var(--ejn-blue));
  color: var(--module-accent, var(--ejn-blue-dark));
}

.btn-icono:focus-visible {
  outline: 2px solid var(--module-accent, var(--ejn-blue));
  outline-offset: 2px;
}

.btn-icono[aria-expanded="true"] {
  background: var(--module-accent-soft, var(--ejn-blue-soft));
  border-color: var(--module-accent, var(--ejn-blue));
}

.btn-icono--claro {
  border-color: transparent;
  background: transparent;
  color: var(--gray-600);
}

/* Contador de avisos pendientes. */
.btn-icono__contador {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--ejn-red);
  color: var(--white);
  font-size: 10px;
  font-weight: var(--fw-bold);
  line-height: 18px;
  text-align: center;
}

/* Texto solo para lectores de pantalla. */
.visualmente-oculto {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.contenido { flex: 1; padding: var(--space-6); min-width: 0; overflow-y: auto; }

/* ---------- Panel lateral de avisos ----------
   Flotante y superpuesto: NO desplaza ni comprime el contenido.
   Preparado para alertas, notificaciones, advertencias y registros. */

.avisos-fondo {
  position: fixed;
  inset: 0;
  background: rgba(31, 41, 55, .25);
  opacity: 0;
  transition: opacity .2s ease;
  z-index: 40;
}

.avisos-fondo.esta-abierto { opacity: 1; }

.avisos {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 360px;
  max-width: 90vw;
  display: flex;
  flex-direction: column;
  background: var(--white);
  border-left: 3px solid var(--module-accent, var(--ejn-blue));
  box-shadow: var(--shadow-lg);
  transform: translateX(100%);
  transition: transform .2s ease;
  z-index: 50;
}

.avisos.esta-abierto { transform: translateX(0); }

.avisos__cabecera {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--gray-200);
  flex-shrink: 0;
}

.avisos__titulo {
  margin: 0;
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  color: var(--ejn-navy);
}

.avisos__cuerpo {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-4) var(--space-5);
}

.avisos__pie {
  padding: var(--space-3) var(--space-5);
  border-top: 1px solid var(--gray-200);
  flex-shrink: 0;
}

.aviso-grupo { margin-bottom: var(--space-5); }
.aviso-grupo:last-child { margin-bottom: 0; }

.aviso-grupo__titulo {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 6px;
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: .5px;
  text-transform: uppercase;
  color: var(--gray-600);
}

.aviso-grupo__vacio {
  margin: 0;
  font-size: var(--fs-small);
  color: var(--gray-400);
  line-height: var(--lh-normal);
}

/* 21/09/2026, pedido de Daniel (Work, fidelidad al mockup Main.dc.html):
   Mi portal (work/portal.php) tiene 2 bloques -- '.portal-desktop' (lista
   de secciones de siempre) y '.portal-movil' (saludo + tarjeta destacada +
   grilla de accesos, nuevo) -- que se alternan por ancho de pantalla. En
   desktop (fuera del media query de mas abajo) el movil queda oculto acá;
   el desktop no necesita regla propia, ya es block por default. */
.portal-movil { display: none; }

/* 21/09/2026, pedido de Daniel (Mi siniestro, 2da vuelta): las tarjetas de
   acceso (Prestaciones/Turnos/Pagos/Notificaciones) dejan de abrir un panel
   en la misma página y pasan a navegar a una pantalla propia por sección
   (ver WorkController::miSiniestroSeccion() y work/mi_siniestro_seccion.php).
   work/mi_siniestro_detalle.php ahora tiene 2 bloques -- '.siniestro-accesos-movil'
   (las 4 tarjetas <a>, nuevo) y '.siniestro-tabs-desktop' (las pestañas de
   siempre con sus paneles inline, intactas) -- que se alternan por ancho de
   pantalla, mismo patrón que .portal-desktop/.portal-movil de Mi portal. En
   escritorio (fuera del media query de más abajo) el bloque móvil queda
   oculto acá; el de escritorio no necesita regla propia, ya es block. */
.siniestro-accesos-movil { display: none; }

@media (max-width: 860px) {
  .barra-superior { padding: 0 var(--space-4); }
  .usuario-chip .caption { display: none; }

  /* 11/09/2026 (pedido de Daniel): en celular angosto el icono de
     plegar/las migas se superponian con el nombre de usuario. Causa
     real: .barra-superior__der no tenia min-width:0 -- un flex item
     sin eso nunca se achica por debajo del ancho de su contenido, asi
     que el elipsis ya definido en .usuario-chip__nombre nunca llegaba
     a activarse. Se oculta ademas el badge de rol (ej.
     "ADMIN_PLATAFORMA"): en celular alcanza con el nombre, el rol se
     ve completo en /mi-cuenta. Las migas (titulo de pantalla) tambien
     podian desbordar sin achicarse -- se acotan igual. */
  .barra-superior__der,
  .usuario-chip { min-width: 0; }
  .usuario-chip__nombre { max-width: 84px; }
  .usuario-chip .badge { display: none; }
  .migas b,
  .migas a {
    display: inline-block;
    max-width: 130px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

/* Quien pidió menos animación, no la recibe. */
@media (prefers-reduced-motion: reduce) {
  .avisos, .avisos-fondo, .modulo, .tarjeta { transition: none; }
}

/* ---------- Encabezado de página ---------- */

.encabezado {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-5);
  margin-bottom: var(--space-6);
  flex-wrap: wrap;
}

.encabezado h1 { margin: 0; font-size: var(--fs-h1); font-weight: var(--fw-bold); }

.encabezado__sub { margin: 4px 0 0; color: var(--gray-600); font-size: var(--fs-small); }

.encabezado__usuario { text-align: right; display: flex; flex-direction: column; gap: 4px; align-items: flex-end; }

.caption {
  font-size: var(--fs-caption);
  font-weight: var(--fw-medium);
  letter-spacing: .5px;
  text-transform: uppercase;
  color: var(--gray-400);
}

.panel-inicio .encabezado { margin-bottom: var(--space-4); }

/* ---------- Grilla de módulos ----------
   Los 7 módulos (Core/Poliza/Business/Care/Work/Finance/SCI, éste último
   agregado 07/09/2026 -- migración 099) entran en una sola fila; las
   tarjetas se achicaron un poco (ver .modulo* más abajo) para que entren
   sin apretarse. Por debajo de 1280 px se reacomodan solos para no
   comprimir el contenido. */

.grilla-modulos {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: var(--space-2);
  align-items: stretch;
}

@media (max-width: 1280px) {
  .grilla-modulos { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .grilla-modulos { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Telefonos angostos (07/09/2026): 2 columnas con 5 chips de resumen por
   tarjeta queda apretado por debajo de 480px -- una columna se lee mejor. */
@media (max-width: 480px) {
  .grilla-modulos { grid-template-columns: 1fr; }
}

/* ============================================================
   Red RIXART: grafico central del panel de inicio
   Pedido de Daniel (06/09/2026): reemplaza el SVG estatico anterior
   por una red animada -- anillos, particulas, halos -- con los 6 nodos
   representando los modulos reales (mismos iconos que el sidebar,
   ver core/helpers.php::icono()), con resaltado cruzado tarjeta<->nodo
   y respeto a prefers-reduced-motion. Sin JS: el cruce tarjeta<->nodo
   se resuelve con :has() (soportado en navegadores actuales).
   ============================================================ */

/* 07/09/2026 (noche), pedido de Daniel: el grafico ocupaba todo el alto de
   la pantalla, lejos de las tarjetas de arriba. Menos margen superior y
   menos ancho maximo (el alto escala con el ancho por el viewBox fijo). */
.panel-hub {
  margin: var(--space-3) auto 0;
  max-width: 820px;
  width: 100%;
  /* 09/09/2026, pedido de Daniel ("que se convierta en una imagen 3D
     tipo JARVIS de Iron Man"): perspective aca para que el <svg> hijo
     pueda inclinarse en 3D (rotateX/rotateY) -- ver la seccion "Hub:
     holograma 3D" mas abajo y iniciarHubHolograma() en ejn-app.js.
     perspective-origin cerca del centro real del nucleo (325/770 del
     viewBox = 42% de alto) para que la inclinacion pivotee ahi. */
  perspective: 1400px;
  perspective-origin: 50% 42%;
  filter: drop-shadow(0 30px 46px rgba(20, 91, 239, .14));
}

.hub-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  transform-origin: center center;
  animation: rixart-hub-flotar 11s ease-in-out infinite;
  will-change: transform;
}

/* ---------- Halo central ---------- */
.hub-halo {
  transform-box: fill-box;
  transform-origin: center;
  animation: rixart-halo 4s ease-in-out infinite;
}

/* Segunda capa de halo, mas grande y difuminada con feGaussianBlur real
   (no solo gradiente) -- pedido de Daniel (06/09/2026): el centro se
   sentia vacio comparado con su mockup, esto le da mas volumen/efecto
   sin agregar JS ni cambiar la geometria de nodos/conexiones. Late a
   otro ritmo que el halo interior (delay negativo) para que no
   respiren identicas -- mas organico. */
.hub-halo-outer {
  transform-box: fill-box;
  transform-origin: center;
  animation: rixart-halo 7s ease-in-out infinite;
  animation-delay: -2.3s;
}

/* Polvo decorativo: puntos esparcidos dentro y fuera del anillo
   exterior, estaticos (sin animacion -- evita sobrecargar de movimiento
   un fondo que ya tiene 3 anillos rotando + particulas viajando). */
.hub-polvo { fill: var(--rixart-blue-2); }
.hub-polvo--lejos { fill: var(--rixart-blue); }

/* Opacidad individual de cada partícula de polvo (antes venía inline por
   círculo -- CSP style-src la bloqueaba en silencio desde el endurecimiento
   de Seguridad, P-89, 07/09/2026). Son 24 círculos estáticos en un orden
   fijo dentro de .hub-decor, siempre los mismos -- por eso nth-of-type es
   exacto acá y no una aproximación. */
.hub-decor circle:nth-of-type(1)  { opacity: .22; }
.hub-decor circle:nth-of-type(2)  { opacity: .20; }
.hub-decor circle:nth-of-type(3)  { opacity: .28; }
.hub-decor circle:nth-of-type(4)  { opacity: .29; }
.hub-decor circle:nth-of-type(5)  { opacity: .18; }
.hub-decor circle:nth-of-type(6)  { opacity: .21; }
.hub-decor circle:nth-of-type(7)  { opacity: .20; }
.hub-decor circle:nth-of-type(8)  { opacity: .33; }
.hub-decor circle:nth-of-type(9)  { opacity: .29; }
.hub-decor circle:nth-of-type(10) { opacity: .30; }
.hub-decor circle:nth-of-type(11) { opacity: .19; }
.hub-decor circle:nth-of-type(12) { opacity: .18; }
.hub-decor circle:nth-of-type(13) { opacity: .17; }
.hub-decor circle:nth-of-type(14) { opacity: .24; }
.hub-decor circle:nth-of-type(15) { opacity: .20; }
.hub-decor circle:nth-of-type(16) { opacity: .25; }
.hub-decor circle:nth-of-type(17) { opacity: .15; }
.hub-decor circle:nth-of-type(18) { opacity: .29; }
.hub-decor circle:nth-of-type(19) { opacity: .20; }
.hub-decor circle:nth-of-type(20) { opacity: .18; }
.hub-decor circle:nth-of-type(21) { opacity: .28; }
.hub-decor circle:nth-of-type(22) { opacity: .22; }
.hub-decor circle:nth-of-type(23) { opacity: .24; }
.hub-decor circle:nth-of-type(24) { opacity: .20; }

/* ---------- Anillos tecnicos ---------- */
.hub-anillo {
  fill: none;
  stroke: var(--rixart-blue-2);
  stroke-opacity: .28;
  stroke-width: 1.6;
  transform-box: fill-box;
  transform-origin: center;
}
.hub-anillo--1 { animation: rixart-rotate 32s linear infinite; }
.hub-anillo--2 { stroke-opacity: .4; animation: rixart-rotate-reverse 24s linear infinite; }
.hub-anillo--3 { stroke-opacity: .5; animation: rixart-pulse 4s ease-in-out infinite; }

.hub-tic {
  stroke: var(--rixart-blue-2);
  stroke-opacity: .22;
  stroke-width: 2;
}
.hub-tic--mayor { stroke-opacity: .4; stroke-width: 2.6; }

/* ---------- Conexiones ---------- */
.hub-conexion {
  fill: none;
  stroke: var(--rixart-blue-2);
  stroke-width: 2;
  opacity: .55;
  transition: opacity .25s ease, stroke-width .25s ease;
}

.hub-conexion__punto {
  fill: var(--rixart-blue-2);
  opacity: .7;
  transition: opacity .25s ease;
}

.hub-particula {
  fill: var(--rixart-blue);
  filter: drop-shadow(0 0 3px rgba(20, 91, 239, .65));
}

/* ---------- Logo central (fijo, nunca rota) ---------- */
.hub-logo {
  color: var(--rixart-navy);
}

/* ---------- Nodos ---------- */
.hub-nodo {
  cursor: pointer;
  transform-box: fill-box;
  transform-origin: center;
  transition: transform .2s ease, filter .25s ease;
  outline: none;
}

/* La animacion de "flote" (continua) vive en un <g> interno, separado
   del <g> que recibe el hover -- si el scale de :hover fuera al mismo
   elemento que anima transform en loop infinito, la animacion lo pisa
   cada frame y el crecimiento nunca se llega a ver (pedido de Daniel,
   06/09/2026: "aumenten un poco mas el tamaño" al pasar el mouse). */
.hub-nodo__inner {
  animation: rixart-node-in .5s ease both, rixart-node-float 4s ease-in-out infinite;
  transform-box: fill-box;
  transform-origin: center;
}

.hub-nodo__halo {
  fill: var(--rixart-blue-light);
  opacity: .85;
  transition: opacity .25s ease, r .25s ease;
}

.hub-nodo__cuerpo {
  fill: var(--rixart-white);
  stroke: var(--rixart-blue-2);
  stroke-width: 2;
  transition: fill .25s ease, stroke .25s ease;
}

.hub-nodo__anillo {
  fill: none;
  stroke: var(--rixart-blue-light);
  stroke-width: 2;
}

.hub-nodo__icono { color: var(--rixart-blue); transition: color .25s ease; }
.hub-nodo__icono path, .hub-nodo__icono circle, .hub-nodo__icono rect { stroke-width: 2.4; }

.hub-nodo__indicador {
  fill: var(--rixart-blue-2);
  animation: rixart-pulse-dot 2.4s ease-in-out infinite;
}

/* Ruta invisible (sin trazo propio) que el nombre del módulo sigue con
   <textPath> -- pedido de Daniel (07/09/2026): "que el nombre del módulo
   se muestre por el contorno del círculo como si siguiera la línea". Arco
   superior del anillo (r=58, entre __anillo r=43 y __halo r=62), de punta
   a punta en sentido horario -- así el texto queda derecho, curvado hacia
   afuera como un sello, centrado arriba del nodo (startOffset 50%). */
.hub-nodo__ruta-nombre { fill: none; stroke: none; }

.hub-nodo__nombre {
  font-size: 11px;
  font-weight: var(--fw-extrabold);
  letter-spacing: 1.5px;
  fill: var(--ejn-azul-acento);
  opacity: 0;
  transition: opacity .25s ease;
  pointer-events: none;
}

.hub-nodo:hover,
.hub-nodo:focus-visible {
  transform: scale(1.12);
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.hub-nodo:hover .hub-nodo__cuerpo,
.hub-nodo:focus-visible .hub-nodo__cuerpo {
  /* Pintar el fondo del círculo con el color del estilo activo (tema por
     usuario -- lila por defecto) y el ícono en blanco, pedido de Daniel
     (07/09/2026). */
  fill: var(--ejn-azul-acento);
  stroke: var(--ejn-azul-acento-dark);
}
.hub-nodo:hover .hub-nodo__icono,
.hub-nodo:focus-visible .hub-nodo__icono { color: var(--rixart-white); }
.hub-nodo:hover .hub-nodo__halo,
.hub-nodo:focus-visible .hub-nodo__halo { opacity: .95; r: 62; }
.hub-nodo:hover .hub-nodo__nombre,
.hub-nodo:focus-visible .hub-nodo__nombre { opacity: 1; }

/* El delay de cada nodo (entrada + "flote", para que no se muevan juntos)
   venía inline por nodo desde el propio SVG generado (style="animation-
   delay:..."). Roto en silencio por CSP style-src desde el endurecimiento
   de Seguridad (P-89, 07/09/2026): los 6 nodos flotaban todos sincronizados
   en vez de desfasados. Cada .hub-nodo tiene su data-module en el padre, así
   que el delay se resuelve por atributo -- mismo mecanismo que ya usan
   .hub-anillos/.hub-conexiones/.hub-logo un poco más abajo. */
[data-module="core"]     .hub-nodo__inner { animation-delay: 0s; }
[data-module="poliza"]   .hub-nodo__inner { animation-delay: .5s; }
[data-module="business"] .hub-nodo__inner { animation-delay: 1s; }
[data-module="care"]     .hub-nodo__inner { animation-delay: 1.5s; }
[data-module="work"]     .hub-nodo__inner { animation-delay: 2s; }
[data-module="finance"]  .hub-nodo__inner { animation-delay: 2.5s; }
[data-module="sci"]      .hub-nodo__inner { animation-delay: 3s; }  /* 07/09/2026: 7º nodo, abajo-centrado */

/* ---------- Entrada inicial escalonada ---------- */
.hub-halo, .hub-anillos, .hub-conexiones, .hub-logo {
  animation: rixart-fade-in .6s ease both;
}
.hub-anillos    { animation-delay: .05s; }
.hub-conexiones { animation-delay: .15s; }
.hub-logo       { animation-delay: .35s; }
.hub-particulas { animation: rixart-fade-in .6s ease .5s both; }

/* ---------- Resaltado cruzado tarjeta <-> nodo (sin JS, via :has()) ---------- */

.panel-inicio:has([data-module="core"]:hover) .modulo[data-module="core"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="core"]:hover) .hub-nodo[data-module="core"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="core"]:hover) .hub-nodo[data-module="core"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="core"]:hover) .hub-nodo[data-module="core"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="core"]:hover) .hub-conexion[data-module="core"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="core"]:hover) .hub-conexion__punto[data-module="core"] {
  opacity: 1;
}
.panel-inicio:has([data-module="poliza"]:hover) .modulo[data-module="poliza"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="poliza"]:hover) .hub-nodo[data-module="poliza"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="poliza"]:hover) .hub-nodo[data-module="poliza"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="poliza"]:hover) .hub-nodo[data-module="poliza"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="poliza"]:hover) .hub-conexion[data-module="poliza"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="poliza"]:hover) .hub-conexion__punto[data-module="poliza"] {
  opacity: 1;
}
.panel-inicio:has([data-module="business"]:hover) .modulo[data-module="business"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="business"]:hover) .hub-nodo[data-module="business"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="business"]:hover) .hub-nodo[data-module="business"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="business"]:hover) .hub-nodo[data-module="business"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="business"]:hover) .hub-conexion[data-module="business"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="business"]:hover) .hub-conexion__punto[data-module="business"] {
  opacity: 1;
}
.panel-inicio:has([data-module="care"]:hover) .modulo[data-module="care"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="care"]:hover) .hub-nodo[data-module="care"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="care"]:hover) .hub-nodo[data-module="care"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="care"]:hover) .hub-nodo[data-module="care"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="care"]:hover) .hub-conexion[data-module="care"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="care"]:hover) .hub-conexion__punto[data-module="care"] {
  opacity: 1;
}
.panel-inicio:has([data-module="work"]:hover) .modulo[data-module="work"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="work"]:hover) .hub-nodo[data-module="work"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="work"]:hover) .hub-nodo[data-module="work"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="work"]:hover) .hub-nodo[data-module="work"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="work"]:hover) .hub-conexion[data-module="work"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="work"]:hover) .hub-conexion__punto[data-module="work"] {
  opacity: 1;
}
.panel-inicio:has([data-module="finance"]:hover) .modulo[data-module="finance"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="finance"]:hover) .hub-nodo[data-module="finance"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="finance"]:hover) .hub-nodo[data-module="finance"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="finance"]:hover) .hub-nodo[data-module="finance"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="finance"]:hover) .hub-conexion[data-module="finance"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="finance"]:hover) .hub-conexion__punto[data-module="finance"] {
  opacity: 1;
}
.panel-inicio:has([data-module="sci"]:hover) .modulo[data-module="sci"] {
  transform: translateY(-2px);
  box-shadow: 0 8px 24px rgba(20, 91, 239, .10);
  border-color: rgba(20, 91, 239, .35);
}
.panel-inicio:has([data-module="sci"]:hover) .hub-nodo[data-module="sci"] {
  filter: drop-shadow(0 0 14px rgba(20, 91, 239, .28));
}
.panel-inicio:has([data-module="sci"]:hover) .hub-nodo[data-module="sci"] .hub-nodo__cuerpo {
  stroke: var(--rixart-blue);
}
.panel-inicio:has([data-module="sci"]:hover) .hub-nodo[data-module="sci"] .hub-nodo__halo {
  opacity: .95;
}
.panel-inicio:has([data-module="sci"]:hover) .hub-conexion[data-module="sci"] {
  stroke: var(--rixart-blue);
  opacity: 1;
  stroke-width: 2.6;
}
.panel-inicio:has([data-module="sci"]:hover) .hub-conexion__punto[data-module="sci"] {
  opacity: 1;
}

/* ---------- Keyframes ---------- */
@keyframes rixart-rotate         { from { transform: rotate(0deg); }   to { transform: rotate(360deg); } }
@keyframes rixart-rotate-reverse { from { transform: rotate(360deg); } to { transform: rotate(0deg); } }

@keyframes rixart-pulse {
  0%, 100% { opacity: .35; transform: scale(.98); }
  50%      { opacity: .7;  transform: scale(1.03); }
}

@keyframes rixart-halo {
  0%, 100% { opacity: .25; transform: scale(.98); }
  50%      { opacity: .55; transform: scale(1.03); }
}

@keyframes rixart-pulse-dot {
  0%, 100% { opacity: .5; }
  50%      { opacity: 1; }
}

@keyframes rixart-node-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-3px); }
}

@keyframes rixart-node-in {
  from { opacity: 0; transform: scale(.75); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes rixart-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ---------- prefers-reduced-motion: estados estaticos ---------- */
@media (prefers-reduced-motion: reduce) {
  .hub-halo,
  .hub-anillo,
  .hub-nodo,
  .hub-nodo__indicador,
  .hub-halo, .hub-anillos, .hub-conexiones, .hub-logo,
  .hub-svg,
  .hub-sweep-grupo {
    animation: none !important;
  }
  /* 09/09/2026: el holograma 3D (tilt + parallax por capa) tambien se
     apaga entero -- iniciarHubHolograma() en ejn-app.js ya ni siquiera
     engancha los listeners bajo esta preferencia, esto cubre el estado
     visual en caso de que --hub-tilt-x/y/--hub-par-x/y hayan quedado
     con un valor de una sesion anterior (custom properties persisten
     en el elemento, no se resetean solas). */
  .hub-svg,
  .hub-anillos,
  .hub-conexiones,
  .hub-nodos {
    transform: none !important;
  }
  .hub-particulas,
  .hub-sweep-grupo { display: none; }
  .panel-hub { filter: none; }
}

/* ---------- Responsive ---------- */
@media (max-width: 860px) {
  .panel-hub { margin-top: var(--space-4); }
}

@media (max-width: 640px) {
  .hub-nodo__icono { transform-origin: center; }
}

/* ============================================================
   Hub: holograma 3D estilo "JARVIS" (pedido de Daniel, 09/09/2026)
   "la imagen central de la plataforma que esta animada timidamente,
   que se convierta en una imagen 3D tipo JARVIS de Iron Man". Sin
   WebGL/Three.js -- esta app no tiene build step ni bundler, y sumar
   un motor 3D real para un widget decorativo del panel de inicio es
   sobreingenieria frente a lo que CSS 3D puro ya puede lograr. El
   efecto "3D" es: el <svg> entero se inclina en el espacio
   (perspective en .panel-hub + rotateX/rotateY en .hub-svg,
   reaccionando al mouse via iniciarHubHolograma() en ejn-app.js, que
   escribe --hub-tilt-x/--hub-tilt-y/--hub-par-x/--hub-par-y como
   custom properties -- permitido por CSP style-src 'self': la
   restriccion es sobre style="" y <style> en el HTML, no sobre
   asignaciones JS al CSSOM, mismo principio que ya documentaba el fix
   de P-89 para animation-delay). Sin mouse (touch, o antes del primer
   movimiento) el <svg> igual "flota" solo por el keyframe de reposo
   -- nunca queda estatico, que era justamente la queja de Daniel.
   Profundidad simulada sin transform-style:preserve-3d anidado (poco
   confiable entre navegadores dentro de <svg> real): cada capa
   (anillos, conexiones, nodos) se corre en 2D una distancia distinta
   segun --hub-par-x/y (posicion del mouse normalizada -1..1) -- los
   nodos (mas "cerca" del usuario) se mueven mas que los anillos (mas
   "atras"). El nucleo (halo + logo RIXART) queda fijo a proposito: es
   el punto de anclaje del holograma, todo lo demas gira/flota
   alrededor. Respeta prefers-reduced-motion (bloque de arriba).
   ============================================================ */

/* Profundidad por capa. .hub-anillos/.hub-conexiones ya tenian su
   propio animation (rixart-fade-in, solo opacity) -- este transform
   estatico no choca, son propiedades distintas del mismo elemento. */
.hub-anillos {
  transform: translate(calc(var(--hub-par-x, 0) * 4px), calc(var(--hub-par-y, 0) * 4px));
}
.hub-conexiones {
  transform: translate(calc(var(--hub-par-x, 0) * 8px), calc(var(--hub-par-y, 0) * 8px));
}
.hub-nodos {
  transform: translate(calc(var(--hub-par-x, 0) * 15px), calc(var(--hub-par-y, 0) * 15px));
}

/* ---------- Barrido de radar ---------- */
.hub-sweep { opacity: .85; }
.hub-sweep-grupo {
  animation: rixart-rotate 5.5s linear infinite;
  transform-box: view-box;
  transform-origin: 500px 325px;
}

/* ---------- Keyframe del holograma (reposo autonomo + tilt del mouse
   combinados -- ver comentario largo arriba) ---------- */
@keyframes rixart-hub-flotar {
  0%, 100% {
    transform: rotateX(calc(1.6deg + var(--hub-tilt-x, 0deg))) rotateY(calc(-2.6deg + var(--hub-tilt-y, 0deg)));
  }
  50% {
    transform: rotateX(calc(-1.6deg + var(--hub-tilt-x, 0deg))) rotateY(calc(2.6deg + var(--hub-tilt-y, 0deg)));
  }
}

.modulo {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  background: var(--cristal-glass-bg-strong);
  backdrop-filter: blur(var(--cristal-blur));
  -webkit-backdrop-filter: blur(var(--cristal-blur));
  border: 1px solid var(--cristal-glass-border);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  box-shadow: var(--shadow-sm);
  transition: box-shadow .15s, transform .15s;
}  /* 06/09/2026: vidrio (antes blanco solido + borde duro) -- pedido de Daniel "Cristal / Vidrio Diurno" */

/* Solo las tarjetas accesibles reaccionan al mouse. Sombra mas marcada en
   vez de cambiar el borde -- "sombras suaves en vez de bordes duros". */
a.modulo:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px) scale(1.025);
}

a.modulo:focus-visible {
  outline: 2px solid var(--module-accent, var(--ejn-azul-acento));
  outline-offset: 2px;
}

/* Bloqueado: sin color, sin cursor, sin interacción. */
.modulo--bloqueado {
  background: var(--gray-50);
  cursor: not-allowed;
  opacity: .6;
}

.modulo--bloqueado .modulo__escudo { filter: grayscale(1); }
.modulo--bloqueado .modulo__marca  { background: var(--gray-300); }
.modulo--bloqueado .modulo__nombre { color: var(--gray-600); }

/* Banda superior con el color del módulo: acento, no fondo.
   El color llega por [data-module="..."] desde ejn-tokens.css. */
.modulo__marca {
  position: absolute;
  inset: 0 0 auto 0;
  height: 4px;
  background: var(--module-accent, var(--ejn-blue));
}

.modulo__escudo {
  flex-shrink: 0;
  margin-bottom: var(--space-2);
}

/* Azul de acento electrico (pedido de Daniel, 06/09/2026, sobre su
   mockup de referencia) -- ya no navy. Un solo color fijo para los 6
   modulos (no depende de --module-accent, que ademas cambio en este
   mismo commit): contraste verificado sobre blanco, ratio ~4.57:1,
   cumple AA. */
.modulo__nombre {
  margin: 6px 0 4px;
  font-size: 14px;  /* 07/09/2026: antes --fs-h3 (16px) -- con 7 módulos en
                        una fila (SCI agregado) la tarjeta se achicó y
                        BUSINESS/FINANCE quedaban al límite del ancho */
  font-weight: var(--fw-extrabold);
  text-transform: uppercase;
  letter-spacing: 1px;
  color: var(--ejn-azul-acento);
  line-height: var(--lh-tight);
}

.modulo__desc {
  margin: 0 0 var(--space-3);
  font-size: var(--fs-small);
  color: var(--gray-600);
  flex: 1;
}

/* Badge "Ingresar": azul de acento fijo e igual en los 6 módulos (ya no
   depende de --module-accent, que unificamos a navy hace dos pasadas --
   quedaba grisáceo). Pedido de Daniel a partir de su mockup de
   referencia (06/09/2026). */
.badge-modulo {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--ejn-azul-acento-soft);
  color: var(--ejn-azul-acento);
}

/* Resumen de gestión bajo "Ingresar" (pedido de Daniel, 07/09/2026):
   vencimientos/observaciones/errores/pendientes/mensajes de
   PanelResumenRepo. Los chips reusan .badge--ok/--warn/--dang/--info/--neu
   de ejn-erp.css (mismo tamaño 10.5px que el resto de la plataforma) --
   acá sólo se resuelve el layout de fila, no el color. */
.modulo__resumen {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
  width: 100%;
}

.modulo__chip { white-space: nowrap; }

/* En 0 se apaga a gris neutro (ya lo pinta badge--neu) y baja opacidad --
   la fila siempre tiene 5 chips ahora (pedido de Daniel, 07/09/2026,
   "mostralo en todas, lo vamos a ir mejorando"), y lo que sí importa no
   puede competir visualmente con una fila de ceros. */
.modulo__chip--vacio { opacity: .55; }

/* ---------- Portada de módulo ---------- */

.encabezado--modulo { align-items: center; }

.encabezado__titulo {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.alerta--modulo {
  background: var(--module-accent-soft, var(--ejn-blue-soft));
  color: var(--gray-700);
  border-color: var(--module-accent, var(--ejn-blue));
  border-left-width: 3px;
}

/* Titulo de grupo sobre una .grilla-secciones (Work: portal del trabajador
   agrupado en "Siniestros"/"Empleador", pedido de Daniel 21/09/2026). Primer
   grupo sin margen superior extra -- ya lo da el .encabezado de arriba. */
.subtitulo-seccion {
  margin: var(--space-5) 0 var(--space-2);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  color: var(--ejn-navy);
  padding-bottom: 4px;
  border-bottom: 1px solid var(--gray-200);
}
.subtitulo-seccion:first-of-type { margin-top: 0; }

.grilla-secciones {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-4);
}

.seccion {
  position: relative;
  background: var(--white);
  border: 1px solid var(--gray-200);
  border-left: 3px solid var(--module-accent, var(--ejn-blue));
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

.seccion__nombre {
  margin: 0 0 6px;
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  color: var(--ejn-navy);
}

.seccion__desc {
  margin: 0 0 var(--space-4);
  font-size: var(--fs-small);
  color: var(--gray-600);
}

/* ---------- Responsive ---------- */

@media (max-width: 860px) {
  .app { flex-direction: column; height: auto; }

  /* Pedido de Daniel (07/09/2026): el grafico decorativo del panel de
     inicio no debe verse en celular -- ahi importa llegar rapido a las
     tarjetas de modulos, no una animacion. */
  .panel-hub { display: none; }

  /* 21/09/2026, fix real reportado por Daniel: el menu se abria pero el
     contenido de abajo (grilla, filtros) se seguia viendo por encima,
     mezclado con las opciones. Causa: position:relative SIN z-index propio
     deja a .barra-lateral con z-index:auto para el apilamiento real con sus
     hermanos (.marco/.contenido) -- el z-index:40 de .barra-lateral__nav de
     mas abajo queda encerrado dentro del contexto de apilamiento que crea
     .barra-lateral por su backdrop-filter, y no pesa en esa comparacion.
     Cualquier elemento de la pagina con z-index propio que escape de un
     contenedor sin position+z-index propios (ej. .grilla__barra, z-index:5,
     ver rixart-erp.css) terminaba pintandose por encima de TODO
     .barra-lateral, menu incluido. z-index:55 la deja en el mismo nivel
     "overlay" ya documentado en la plataforma (combo/menu, ver comentario
     de .tarjeta:hover en rixart-erp.css), bien por encima de cualquier
     z-index de contenido (grilla__barra:5, tarjeta:hover:10). */
  .barra-lateral {
    position: relative;
    z-index: 55;
    width: 100%;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
  }

  .barra-lateral__marca,
  .barra-lateral__pie { border: none; padding: 0; }

  .barra-lateral__nav {
    display: none;
    position: absolute;
    top: 100%; left: 0; right: 0;
    z-index: 40;
    flex-direction: column;
    max-height: calc(100vh - 64px);
    overflow-y: auto;
    background: var(--white);
    border-top: 1px solid var(--gray-200);
    box-shadow: var(--shadow-lg, 0 8px 24px rgba(10, 31, 68, .18));
    padding: var(--space-3) var(--space-4);
  }

  .app--nav-movil .barra-lateral__nav { display: flex; }

  /* Fondo fijo detras del desplegable de celular (11/09/2026): sin esto,
     en algunas pantallas (ej. Poliza/Tablero, con tarjetas .kpi) el
     contenido de la pagina se veia por encima del menu -- .barra-lateral
     tiene backdrop-filter, que crea su propio contexto de apilamiento y
     puede confundir el orden de pintado en algunos motores moviles. El
     div vive fuera de #app (ver privado.php) con position:fixed, asi que
     no depende de ese contexto -- cubre TODA la pantalla siempre. */
  .nav-movil-fondo {
    position: fixed;
    inset: 0;
    background: rgba(31, 41, 55, .25);
    z-index: 39;
  }

  .nav-item { padding: 10px 8px; }
  .pag, .btn-mini, .btn-icono { min-height: 34px; }

  /* ---------- Tabla -> tarjetas por fila (mobile, opt-in) ----------
     21/09/2026, pedido de Daniel (Work, portal del trabajador): en
     pantallas angostas una tabla ancha con scroll horizontal es incomoda.
     Esta clase transforma cualquier <table> en una lista de tarjetas (una
     por fila), sin tocar la logica de la grilla: buscar/ordenar/filtrar/
     agrupar/paginar (rixart-grilla.js) siguen manipulando los mismos
     <tr>/<td> de siempre, esto solo cambia como se ven en mobile. Uso:
     - componentes/grilla.php: pasar 'tarjetas_movil' => true en la config
       (agrega la clase sola). Default false = ninguna de las ~30 grillas
       existentes cambia.
     - tabla armada a mano: agregar la clase directo, ej.
       <table class="grilla__tabla tabla-tarjetas-movil">, y
       data-etiqueta="<rotulo de columna>" en cada <td>. */
  .tabla-tarjetas-movil thead { display: none; }
  .tabla-tarjetas-movil,
  .tabla-tarjetas-movil tbody,
  .tabla-tarjetas-movil tr,
  .tabla-tarjetas-movil td { display: block; width: 100%; }
  .tabla-tarjetas-movil tr {
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 4px 14px;
    margin-bottom: var(--space-3);
  }
  .tabla-tarjetas-movil tr:last-child { margin-bottom: 0; }
  .tabla-tarjetas-movil tr:hover { background: var(--white); }
  .tabla-tarjetas-movil td {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 10px;
    border: none !important;
    border-bottom: 1px solid var(--gray-100) !important;
    padding: 8px 0;
    font-size: 12.5px;
    text-align: right;
    white-space: normal;
  }
  .tabla-tarjetas-movil tr td:last-child { border-bottom: none !important; }
  .tabla-tarjetas-movil td::before {
    content: attr(data-etiqueta);
    color: var(--gray-400);
    font-weight: var(--fw-semibold);
    text-align: left;
    flex-shrink: 0;
    padding-right: 10px;
  }
  .tabla-tarjetas-movil td:not([data-etiqueta])::before,
  .tabla-tarjetas-movil td[data-etiqueta=""]::before { content: none; }
  .tabla-tarjetas-movil td.col-acc { justify-content: flex-end; }
  .tabla-tarjetas-movil td.col-sel { justify-content: flex-start; }
  .tabla-tarjetas-movil tfoot td { background: var(--ejn-azul-acento-mist); font-weight: var(--fw-bold); }

  /* 21/09/2026, pedido de Daniel (Work): columna oculta por el usuario
     (menu "Columnas visibles", atributo [hidden] nativo) tiene que seguir
     oculta en modo tarjeta -- sin esto, el display:flex de arriba (mas
     especifico que la regla [hidden] del navegador) la volvia a mostrar. */
  .tabla-tarjetas-movil td[hidden] { display: none !important; }

  /* Cabecera de tarjeta (numero/titulo + estado a la misma altura), fiel al
     mockup aprobado por Daniel -- ver componentes/grilla.php para las 3
     flags opt-in (tarjetaTitulo/tarjetaBadge/ocultarTarjeta). Sin estas
     clases una tarjeta sigue siendo la lista simple etiqueta:valor de
     siempre; ninguna grilla que no las use cambia. La fila pasa de
     display:block a grid de 2 columnas: por defecto cada <td> ocupa las 2
     columnas (grid-column:1/-1, una línea por campo, como ya era); el
     titulo y el badge se anclan explícitamente a la fila 1, uno en cada
     columna, sin importar en qué orden aparezcan en el HTML. */
  .tabla-tarjetas-movil tr:has(.td--tarjeta-titulo, .td--tarjeta-badge) {
    display: grid;
    grid-template-columns: 1fr auto;
    column-gap: 10px;
    align-items: start;
  }
  .tabla-tarjetas-movil tr:has(.td--tarjeta-titulo, .td--tarjeta-badge) > td {
    grid-column: 1 / -1;
  }
  .tabla-tarjetas-movil td.td--tarjeta-titulo,
  .tabla-tarjetas-movil td.td--tarjeta-badge {
    grid-row: 1;
    padding-top: 0;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--gray-100) !important;
  }
  .tabla-tarjetas-movil td.td--tarjeta-titulo {
    grid-column: 1;
    justify-content: flex-start;
    font-weight: var(--fw-bold);
    font-size: 14px;
    color: var(--gray-900);
  }
  .tabla-tarjetas-movil td.td--tarjeta-badge {
    grid-column: 2;
    justify-content: flex-end;
  }
  .tabla-tarjetas-movil td.td--tarjeta-titulo::before,
  .tabla-tarjetas-movil td.td--tarjeta-badge::before { content: none; }
  /* La ultima linea normal (etiqueta:valor) ya no debe perder su borde
     inferior solo por ser la ultima del <tr> -- ahora la "ultima" visual
     puede ser el titulo/badge, que ya tienen su propio borde de separacion
     arriba. Se aplica al ultimo <td> de tipo dato (no titulo/badge). */
  .tabla-tarjetas-movil tr:has(.td--tarjeta-titulo, .td--tarjeta-badge) td:last-child:not(.td--tarjeta-titulo):not(.td--tarjeta-badge) {
    border-bottom: none !important;
  }
  /* Campo que el mockup no mostraba en la tarjeta (dato secundario, sigue
     existiendo en la tabla de escritorio y en el Excel exportado). */
  .tabla-tarjetas-movil td.td--tarjeta-oculta { display: none; }

  /* 21/09/2026, pedido de Daniel: al tocar una tarjeta (fila), sus campos
     etiqueta:valor pasan de estar en la misma línea (recortados/apretados
     si el valor es largo) a formato vertical -- etiqueta arriba, valor
     abajo, sin recorte. La clase la agrega rixart-grilla.js al hacer clic
     (ver "Tarjetas móviles: expandir una fila al tocarla" en ese archivo).
     El título/badge de cabecera (si la grilla los usa) NO cambia: sigue
     siendo el encabezado compacto de siempre. */
  .tabla-tarjetas-movil tr { cursor: pointer; }
  .tabla-tarjetas-movil tr.tarjeta-movil--abierta td:not(.td--tarjeta-titulo):not(.td--tarjeta-badge) {
    flex-direction: column;
    align-items: flex-start;
    text-align: left;
  }
  .tabla-tarjetas-movil tr.tarjeta-movil--abierta td:not(.td--tarjeta-titulo):not(.td--tarjeta-badge)::before {
    padding-right: 0;
    margin-bottom: 3px;
  }

  /* Barra de herramientas de una grilla en modo tarjetas-movil (Work,
     21/09/2026, 2da vuelta pedida por Daniel tras ver el mockup: "que sea
     solo para la version celular de WORK, en el resto no se cambia la
     visualizacion"). Exportar/Imprimir/Limpiar/Ocultar/Agrupar -- una sola
     accion cada uno, con icono propio -- quedan solo con icono; el title=
     de siempre sigue explicando que hace cada uno. Los filtros por columna
     (.menu--filtro) NO se tocan a proposito: puede haber varios en la
     misma barra (Tipo/Reingreso/Estado...) y un icono generico los
     volveria indistinguibles entre si -- se quedan con su etiqueta de
     texto, ya de por si corta ("Tipo: todos"). Scope exclusivo de
     .grilla--tarjetas-movil: hoy son las grillas de Work con el flag
     tarjetas_movil activado (ver componentes/grilla.php) -- ninguna otra
     grilla de la plataforma, en ningun modulo, cambia su barra de
     herramientas, ni en mobile ni en desktop. */
  /* 21/09/2026, 4ta vuelta (Work, feedback de Daniel: "sigue todo igual"
     comparado con el mockup, tras ya resueltos el menu, las tarjetas con
     cabecera y la hoja de filtros): el "look" de panel de escritorio --
     recuadro blanco con borde celeste y sombra envolviendo TODO (barra +
     tarjetas + pie), barra con fondo celeste tenue -- es igual en Work que
     en cualquier otra grilla de la plataforma (rixart-erp.css, .grilla/
     .grilla__barra/.grilla__pie), y es justamente lo que hace que se
     "sienta" igual aunque el contenido de adentro haya cambiado. El mockup
     no tiene ese recuadro: la barra flota sobre el fondo de la pantalla y
     cada registro es su propia tarjeta elevada (ver mas arriba,
     .tabla-tarjetas-movil tr). Se saca el recuadro/fondo SOLO en
     .grilla--tarjetas-movil -- ninguna otra grilla, ni Work en desktop,
     cambia. */
  .grilla--tarjetas-movil {
    background: transparent;
    border: none;
    box-shadow: none;
    margin-bottom: 0;
  }
  .grilla--tarjetas-movil .grilla__barra {
    background: transparent;
    border-bottom: none;
    border-radius: 0;
    padding: 10px 0 8px;
  }
  .grilla--tarjetas-movil .grilla__pie {
    background: transparent;
    border-top: none;
    padding: 10px 0;
  }
  .grilla--tarjetas-movil .grilla__barra { gap: 4px; }
  .grilla--tarjetas-movil .grilla__barra .btn-mini__texto,
  .grilla--tarjetas-movil .grilla__barra [data-grilla-columnas-rotulo],
  .grilla--tarjetas-movil .grilla__barra [data-grilla-agrupacion-rotulo] {
    display: none;
  }
  .grilla--tarjetas-movil .grilla__barra .btn-mini,
  .grilla--tarjetas-movil .grilla__barra .menu--columnas > summary,
  .grilla--tarjetas-movil .grilla__barra .menu--agrupacion > summary,
  .grilla--tarjetas-movil .grilla__barra > details.menu:not(.menu--filtro):not(.menu--columnas):not(.menu--agrupacion) > summary {
    gap: 0;
    padding: 8px;
  }
  .grilla--tarjetas-movil .grilla__barra .menu--filtro > summary { padding: 6px 8px; font-size: 12px; }

  /* 21/09/2026, 3ra vuelta (Work): hoja inferior unica de "Filtros",
     reemplazando un boton propio por columna en la barra -- fiel al
     mockup aprobado por Daniel. Reutiliza el <details>/[open] nativo del
     propio boton "Filtros" (ver componentes/grilla.php) como interruptor:
     nada de JS nuevo. Los <details class="menu--filtro"> individuales
     siguen exactamente iguales en el DOM (mismo data-grilla-filtro que ya
     lee rixart-grilla.js) -- esto es 100% visual. Scope exclusivo
     .grilla--tarjetas-movil: ninguna otra grilla de la plataforma cambia. */
  .grilla--tarjetas-movil .grilla__filtros-grupo { display: contents; }
  .grilla--tarjetas-movil .menu--filtro { display: none; }
  .grilla--tarjetas-movil .menu--filtros-todos[open] ~ .grilla__filtros-grupo {
    display: flex;
    flex-direction: column;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: 15%;
    z-index: 200;
    background: rgba(10, 33, 68, .45);
    justify-content: flex-end;
  }
  .grilla--tarjetas-movil .menu--filtros-todos[open] ~ .grilla__filtros-grupo .menu--filtro {
    display: block;
    background: var(--white);
    border: none;
    border-radius: 0;
    padding: 12px 16px;
    border-top: 1px solid var(--gray-100);
    max-height: 42vh;
    overflow-y: auto;
  }
  .grilla--tarjetas-movil .menu--filtros-todos[open] ~ .grilla__filtros-grupo .menu--filtro:first-child {
    border-radius: 16px 16px 0 0;
    border-top: none;
    padding-top: 16px;
  }
  .grilla--tarjetas-movil .menu--filtros-todos[open] ~ .grilla__filtros-grupo .menu--filtro > summary {
    display: none;
  }
  .grilla--tarjetas-movil .menu--filtros-todos[open] ~ .grilla__filtros-grupo .menu__lista {
    display: block !important;
    position: static !important;
    box-shadow: none !important;
    padding: 0 !important;
    border: none !important;
    background: transparent !important;
    max-height: none !important;
  }
  /* Pie fijo dentro de la hoja: recuerda como cerrarla (mismo <details> de
     "Filtros", tocarlo de nuevo lo cierra -- sin backdrop-click porque
     <details> no lo ofrece de forma nativa sin JS). */
  .grilla--tarjetas-movil .menu--filtros-todos[open] ~ .grilla__filtros-grupo::after {
    content: "Volvé a tocar \"Filtros\" para cerrar";
    background: var(--white);
    color: var(--gray-400);
    font-size: 11.5px;
    text-align: center;
    padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
    border-radius: 0 0 16px 16px;
  }

  .contenido { padding: var(--space-4); }

  .grilla__buscar { width: 100%; }
  .grilla__buscar input { width: 100%; max-width: none; }

  /* Mi portal (work/portal.php): alternar los 2 bloques -- ver la regla
     base .portal-movil{display:none} mas arriba, fuera de este media
     query. Acá se invierte para celular. */
  .portal-desktop { display: none; }
  .portal-movil { display: block; }

  .acceso-card {
    display: flex;
    flex-direction: column;
    gap: 3px;
    background: var(--white);
    border: 1px solid var(--gray-200);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    padding: 14px;
    text-decoration: none;
    color: inherit;
    margin-bottom: var(--space-3);
  }
  .acceso-card__icono {
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--ejn-azul-acento-soft);
    color: var(--brand-600, #4f46e5);
    border-radius: var(--radius-sm);
    margin-bottom: 2px;
  }
  .acceso-card__titulo { font-weight: var(--fw-bold); font-size: 14px; color: var(--gray-900); }
  .acceso-card__sub { font-size: 12px; color: var(--gray-500); }

  /* Tarjeta destacada (siniestro activo): oscura, fila en vez de columna,
     icono+texto lado a lado -- mismo criterio visual que el mockup. */
  .acceso-card--destacada {
    flex-direction: row;
    align-items: center;
    gap: 12px;
    background: var(--gray-900);
    border-color: var(--gray-900);
  }
  .acceso-card--destacada .acceso-card__titulo { color: var(--white); }
  .acceso-card--destacada .acceso-card__sub { color: rgba(255, 255, 255, .75); }
  .acceso-card__icono--destacado {
    background: rgba(255, 255, 255, .15);
    color: var(--white);
    margin-bottom: 0;
    flex-shrink: 0;
  }

  .acceso-card__grilla {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
  }
  .acceso-card__grilla .acceso-card { margin-bottom: 0; }

  /* 27/09/2026, pedido de Daniel: boton rojo "SOS - CECAP" (llamar al
     telefono de emergencias de la ART) arriba de todo en el portal
     movil -- reusa la geometria de .acceso-card--destacada (fila, icono
     grande a la izquierda) con su propio color y un poco mas de tamaño,
     para que se note como la accion mas urgente de la pantalla. */
  .acceso-card--sos {
    background: var(--ejn-red);
    border-color: var(--ejn-red);
    padding: 16px;
  }
  .acceso-card--sos .acceso-card__titulo {
    font-size: 16px;
    letter-spacing: .3px;
  }
  .acceso-card--sos:active { background: var(--ejn-red-dark); border-color: var(--ejn-red-dark); }

  /* 28/09/2026, auditoria UX (punto 13/17): tarjeta destacada para la
     citacion a Comision Medica -- misma geometria que .acceso-card--sos
     (fila, icono grande) pero color ambar en vez de rojo: es una fecha
     obligatoria a la que hay que prestar atencion, no una emergencia
     medica en curso como el SOS. */
  .acceso-card--urgente {
    background: #b45309;
    border-color: #b45309;
  }
  .acceso-card--urgente:active { filter: brightness(0.92); }

  /* Mismo pedido: los accesos que antes eran notas sueltas ("Mi
     credencial", "Prestadores cercanos") pasan a ser tarjetas dentro de
     esta misma grilla -- respeta el ancho de columna de las demas y deja
     todo el portal movil mas compacto (menos filas sueltas apiladas). El
     padding-bottom con env(safe-area-inset-bottom) evita que la ultima
     fila quede tapada por la barra de navegación del navegador en iOS. */
  .portal-movil { padding-bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px)); }

  /* Mi siniestro (detalle), celular: mostrar la grilla de tarjetas de
     acceso (reutiliza .acceso-card/.acceso-card__grilla ya definidas más
     arriba para Mi portal) y ocultar el bloque de pestañas de escritorio. */
  .siniestro-accesos-movil { display: grid; }
  .siniestro-tabs-desktop { display: none; }
}

/* ============================================================
   UTILIDADES — reemplazo de los `style="..."` en línea
   ============================================================

   La CSP de EJN es `style-src 'self'`, que descarta **también** el
   atributo `style`. Igual que con el `<script>` embebido (ver
   ejn-app.js), el navegador no dice nada: el margen simplemente no
   se aplica y la pantalla se ve "casi bien".

   El 19/08/2026 había 188 atributos `style` repartidos en 72 vistas
   de los seis módulos, y 665 anchos de columna de grilla. Ninguno
   hacía efecto.

   Estas clases cubren exactamente los valores que estaban en uso.
   No es un framework de utilidades: es la traducción uno a uno de
   lo que ya existía. Antes de agregar una clase nueva acá, revisar
   si el caso no merece una clase con nombre propio en el bloque
   que corresponda.
   ============================================================ */

/* --- Márgenes superiores --- */
.mt-0   { margin-top: 0; }
.mt-2   { margin-top: var(--space-2); }
.mt-3   { margin-top: var(--space-3); }
.mt-4   { margin-top: var(--space-4); }
.mt-06r { margin-top: .6rem; }
.mt-08r { margin-top: .8rem; }

/* --- Márgenes inferiores --- */
.mb-0   { margin-bottom: 0; }
.mb-6   { margin-bottom: 6px; }
.mb-2   { margin-bottom: var(--space-2); }
.mb-3   { margin-bottom: var(--space-3); }
.mb-4   { margin-bottom: var(--space-4); }
.mb-04r { margin-bottom: .4rem; }
.mb-08r { margin-bottom: .8rem; }

/* --- Margen completo --- */
.m-0    { margin: 0; }
.m-t2   { margin: var(--space-2) 0 0; }
.m-t3   { margin: var(--space-3) 0 0; }
.m-t4   { margin: var(--space-4) 0 0; }
.m-y3   { margin: var(--space-3) 0; }
.m-b3   { margin: 0 0 var(--space-3); }

/* --- Grilla de formulario --- */
.col-2  { grid-column: span 2; }
.cols-2 { grid-template-columns: repeat(2, 1fr); }
.cols-3 { grid-template-columns: repeat(3, 1fr); }

/* --- Flex --- */
.fila-fin   { display: flex; align-items: flex-end; align-self: flex-end; } /* align-self: alinea este item contra el borde inferior de la fila --grid--, no solo su propio contenido; sin esto un boton sin etiqueta quedaba a la altura del rotulo del campo vecino (mismo bug de fondo que P-54) */
.just-fin   { justify-content: flex-end; }
.just-entre { justify-content: space-between; }
.flex-1     { flex: 1; }

/* --- Texto --- */
.txt-izq        { text-align: left; }
.txt-der        { text-align: right; }
.fw-normal      { font-weight: 400; }
.lh-19          { line-height: 1.9; }
.romper-palabra { word-break: break-all; }

.fs-105   { font-size: 10.5px; }
.fs-13    { font-size: 13px; }
.fs-14    { font-size: 14px; }
.fs-15    { font-size: 15px; }
.fs-16    { font-size: 16px; }
.fs-105pt { font-size: 10.5pt; }

/* --- Otros --- */
.borde-acento { border-color: var(--module-accent); }
.minw-280 { min-width: 280px; }
.minw-420 { min-width: 420px; }

/* --- Anchos de columna de grilla ---
   `componentes/grilla.php` recibe el ancho por configuración y antes lo
   escribía como `style="width:120px"`. Ahora usa `w-120`, y el ancho se
   redondea al múltiplo de 5 más cercano para que **siempre** caiga en una
   clase existente: un ancho suelto como 107px no puede quedar sin efecto
   en silencio, que es exactamente el error que estamos corrigiendo. */
/* Anchos chicos: columnas de selección e íconos. */
.w-30 { width: 30px; }
.w-35 { width: 35px; }
.w-40 { width: 40px; }
.w-45 { width: 45px; }
.w-50 { width: 50px; }
.w-55 { width: 55px; }
.w-60 { width: 60px; }
.w-65 { width: 65px; }
.w-70 { width: 70px; }
.w-75 { width: 75px; }
.w-80 { width: 80px; }
.w-85 { width: 85px; }
.w-90 { width: 90px; }
.w-95 { width: 95px; }
.w-100 { width: 100px; }
.w-105 { width: 105px; }
.w-110 { width: 110px; }
.w-115 { width: 115px; }
.w-120 { width: 120px; }
.w-125 { width: 125px; }
.w-130 { width: 130px; }
.w-135 { width: 135px; }
.w-140 { width: 140px; }
.w-145 { width: 145px; }
.w-150 { width: 150px; }
.w-155 { width: 155px; }
.w-160 { width: 160px; }
.w-165 { width: 165px; }
.w-170 { width: 170px; }
.w-175 { width: 175px; }
.w-180 { width: 180px; }
.w-185 { width: 185px; }
.w-190 { width: 190px; }
.w-195 { width: 195px; }
.w-200 { width: 200px; }
.w-205 { width: 205px; }
.w-210 { width: 210px; }
.w-215 { width: 215px; }
.w-220 { width: 220px; }
.w-225 { width: 225px; }
.w-230 { width: 230px; }
.w-235 { width: 235px; }
.w-240 { width: 240px; }
.w-245 { width: 245px; }
.w-250 { width: 250px; }
.w-255 { width: 255px; }
.w-260 { width: 260px; }
.w-265 { width: 265px; }
.w-270 { width: 270px; }
.w-275 { width: 275px; }
.w-280 { width: 280px; }
.w-285 { width: 285px; }
.w-290 { width: 290px; }
.w-295 { width: 295px; }
.w-300 { width: 300px; }
.w-305 { width: 305px; }
.w-310 { width: 310px; }
.w-315 { width: 315px; }
.w-320 { width: 320px; }
.w-325 { width: 325px; }
.w-330 { width: 330px; }
.w-335 { width: 335px; }
.w-340 { width: 340px; }
.w-345 { width: 345px; }
.w-350 { width: 350px; }
.w-355 { width: 355px; }
.w-360 { width: 360px; }
.w-365 { width: 365px; }
.w-370 { width: 370px; }
.w-375 { width: 375px; }
.w-380 { width: 380px; }
.w-385 { width: 385px; }
.w-390 { width: 390px; }
.w-395 { width: 395px; }
.w-400 { width: 400px; }

/* ---------- Marca v3: wordmark del producto ----------
   «EJN ART»: EJN en tinta, ART en el turquesa de marca — como lo compone
   el manual v3 (EJN_Soft_Manual_de_Marca_v3.png). */
.wordmark__acento { color: var(--ejn-teal); }

/* Logo completo RixART (placa + wordmark en un solo grafico) en las
   pantallas de auth -- reemplaza el icono chico + texto separados
   (06/09/2026, pedido de Daniel: "quiero que muestre el logo tal como
   te adjunto la imagen"). */
.wordmark-full { margin: 0 0 var(--space-2); display: flex; justify-content: center; }
.logo-rixart-full { display: block; width: min(280px, 80%); height: auto; }

/* Boton "Ingresar" del login con el azul electrico de marca -- scopeado
   solo a esta pantalla. .btn-primary sin scope sigue en --color-primary
   (navy) para el resto de la plataforma, no se toca. */
.tarjeta-acceso .btn-primary { background: var(--ejn-azul-acento); }
.tarjeta-acceso .btn-primary:hover { background: var(--ejn-azul-acento-dark); }

/* ---------- Ayuda contextual ----------
   Panel flotante del botón «?». Reutiliza la estructura de .avisos;
   es más ancho porque adentro viven los circuitos explicados, que son
   franjas horizontales de 5 o 6 pasos. */
.avisos--ayuda { width: 640px; max-width: 94vw; }

.ayuda-bloque { margin-bottom: var(--space-5); }
.ayuda-bloque:last-child { margin-bottom: 0; }

.ayuda-bloque__titulo {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin: 0 0 var(--space-3);
  font-size: var(--fs-h3);
  font-weight: var(--fw-semibold);
  color: var(--ejn-navy);
}

/* Lo que la vista mandó al panel puede traer sus propias tarjetas con
   sombra y borde: acá adentro se aplanan para no encajonar cajas. */
.ayuda-bloque__cuerpo > .panel,
.ayuda-bloque__cuerpo > section {
  border: none;
  box-shadow: none;
  padding: 0;
  margin: 0;
}

/* ---------- Consulta rápida ----------
   Panel de la lupa (Ctrl/Cmd+K): dato puntual de otro módulo sin
   abandonar el formulario en curso. */
.avisos--consulta { width: 460px; max-width: 92vw; }

/* ---------- Panel lateral ancho (tablas con muchas columnas) ----------
   Pedido de Daniel (11/09/2026): el detalle de un trabajador (Poliza,
   pestaña Trabajadores) y el detalle de un período de Emisión muestran
   la nómina real de ARCA con 13 y 21 columnas respectivamente -- en los
   360px de .avisos de base quedaban ilegibles (.grilla__marco las hace
   scrollear, pero casi no entraba ninguna columna antes de tener que
   scrollear). La vista que necesita el ancho extra marca su fragmento
   con <span data-panel-ancho hidden></span>; ejn-app.js lo detecta
   después de cargar el contenido y alterna esta clase en el drawer
   compartido #panel-lateral -- no se ensancha el panel para todo el
   resto de usos (movimiento antes/después, ayuda, consulta rápida),
   sólo para el contenido que lo pide. */
.avisos--ancho { width: 1100px; max-width: 96vw; }

.consulta__buscador {
  padding: var(--space-4) var(--space-5) var(--space-3);
  border-bottom: 1px solid var(--gray-200);
  flex-shrink: 0;
}

.consulta__entrada {
  width: 100%;
  font-family: var(--font-family);
  font-size: var(--fs-body);
  padding: 10px 12px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
}

.consulta__entrada:focus {
  outline: none;
  border-color: var(--ejn-navy);
  box-shadow: 0 0 0 3px var(--ejn-navy-soft);
}

.consulta__pista { margin: 8px 0 0; }

.consulta__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 9px 10px;
  border: 1px solid var(--gray-200);
  border-left: 3px solid var(--module-accent, var(--gray-300));
  border-radius: var(--radius-sm);
  margin-bottom: 8px;
  background: var(--white);
}

.consulta__cuerpo { min-width: 0; display: flex; flex-direction: column; gap: 2px; }

.consulta__titulo {
  font-size: var(--fs-small);
  color: var(--gray-900);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.consulta__linea { font-size: var(--fs-caption); color: var(--gray-600); }

.consulta__acciones { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.consulta__copiar {
  font-family: var(--font-family);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  padding: 4px 9px;
  border: 1px solid var(--gray-300);
  border-radius: var(--radius-sm);
  background: var(--gray-50);
  color: var(--gray-700);
  cursor: pointer;
  white-space: nowrap;
}

.consulta__copiar:hover { border-color: var(--ejn-navy); color: var(--ejn-navy); }

.consulta__copiar--ok {
  border-color: var(--ejn-green);
  background: var(--ejn-green-soft);
  color: var(--ejn-green-dark);
}

.consulta__abrir {
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  color: var(--module-accent, var(--ejn-navy));
  text-decoration: none;
  white-space: nowrap;
}

/* ---------- Borradores (P-61) ----------
   Barra que ofrece restaurar un borrador guardado. Aparece arriba del
   formulario y desaparece al elegir; nunca pisa nada sin preguntar. */
.borrador-barra {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 9px 14px;
  margin-bottom: var(--space-3);
  border: 1px solid var(--ejn-gold);
  border-left-width: 3px;
  border-radius: var(--radius-sm);
  background: var(--ejn-gold-soft);
}

.borrador-barra__texto {
  flex: 1;
  font-size: var(--fs-small);
  color: var(--gray-700);
}

.borrador-barra__accion {
  font-family: var(--font-family);
  font-size: var(--fs-small);
  font-weight: var(--fw-semibold);
  padding: 5px 12px;
  border: 1px solid var(--ejn-gold-dark);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--ejn-gold-dark);
  cursor: pointer;
}

.borrador-barra__accion:hover { background: var(--ejn-gold-soft); }

.borrador-barra__accion--sec {
  border-color: var(--gray-300);
  color: var(--gray-600);
}

/* ============================================================
   Panel de inicio: dashboard interactivo (11/09/2026)
   Reemplaza al holograma SVG (.panel-hub/.hub-* mas arriba, que
   queda sin uso -- pendiente de limpieza, ver ESTADO.md). Mockup
   de layout combinando 3 referencias que le gustaron a Daniel
   (Youcare/Finnova/Ultraleads): tarjetas KPI con anillo, area
   degradada, dona/gauge, barras con una resaltada y una lista con
   avatar+titulo+subtitulo+valor. Un solo acento (--ejn-azul-acento,
   paleta "Cristal") en vez de un color por modulo, siguiendo la
   unificacion ya vigente en el resto de la plataforma (ver
   ejn-tokens.css, "Acento por modulo"). Valores ilustrativos --
   el contenido real por perfil de usuario es la proxima iteracion.
   ============================================================ */
.panel-dashboard {
  margin: var(--space-5) auto 0;
  max-width: 1100px;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.panel-dashboard__cab {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--space-3); flex-wrap: wrap;
}
.panel-dashboard__cab h2 {
  margin: 0; font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--ejn-navy);
}

/* ---- Fila de KPIs con anillo ---- */
.kpi-fila {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3);
}
@media (max-width: 720px) { .kpi-fila { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 480px) { .kpi-fila { grid-template-columns: 1fr; } }

.kpi-tarjeta {
  background: var(--gray-50);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  display: flex; align-items: center; gap: var(--space-3);
  box-shadow: var(--shadow-sm);
}
.kpi-tarjeta__anillo { position: relative; width: 52px; height: 52px; flex-shrink: 0; }
.kpi-tarjeta__anillo svg { transform: rotate(-90deg); }
.kpi-anillo__fondo { fill: none; stroke: var(--gray-200); stroke-width: 6; }
.kpi-anillo__valor {
  fill: none; stroke: var(--ejn-azul-acento); stroke-width: 6; stroke-linecap: round;
  stroke-dasharray: calc(var(--valor, 0) / 100 * 169.65) 169.65;
}
.kpi-tarjeta__icono {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  color: var(--ejn-azul-acento);
}
.kpi-tarjeta__texto { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.kpi-tarjeta__valor { font-size: var(--fs-h3); font-weight: var(--fw-bold); color: var(--ejn-navy); line-height: 1; }
.kpi-tarjeta__etiqueta {
  font-size: var(--fs-small); color: var(--gray-600);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ---- Filas de paneles (area/dona, barras/lista) ---- */
.dash-fila { display: grid; gap: var(--space-4); align-items: stretch; }
.dash-fila--2 { grid-template-columns: 2fr 1fr; }
@media (max-width: 860px) { .dash-fila--2 { grid-template-columns: 1fr; } }
.dash-fila--1 { grid-template-columns: 1fr; }

/* ---- Calendario de traspasos CNO (Tablero de Poliza, 18/09/2026) ----
   Pedido de Daniel, con referencia de CRM.EJNASSISTANCE.COM: 3 colores
   fijos por TIPO de corte (no por periodo) -- pedido = azul, respuesta =
   verde, envio = rojo -- reusando los mismos tokens ya usados por
   .badge--info/--ok/--dang (ver rixart-erp.css), sin crear paleta nueva. */
.dash-panel--calendario { max-width: 420px; }
.calend-cno { display: flex; flex-direction: column; gap: var(--space-3); }
.calend-cno__nav { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.calend-cno__mes { font-weight: var(--fw-semibold); color: var(--ejn-navy); }
.calend-cno__flecha {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--radius-sm);
  border: 1px solid var(--gray-200); color: var(--gray-600);
  text-decoration: none; font-size: 16px; line-height: 1;
}
.calend-cno__flecha:hover { background: var(--gray-50); }
.calend-cno__grilla { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.calend-cno__diasem {
  text-align: center; font-size: var(--fs-caption); color: var(--gray-400);
  font-weight: var(--fw-medium); padding-bottom: 2px;
}
.calend-cno__dia {
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 1 / 1; border-radius: 50%; font-size: var(--fs-small); color: var(--gray-600);
}
.calend-cno__dia--vacio { visibility: hidden; }
.calend-cno__dia--hoy { box-shadow: inset 0 0 0 1.5px var(--ejn-blue-dark); font-weight: var(--fw-semibold); }
.calend-cno__dia--pedido    { background: var(--ejn-blue-dark);  color: var(--white); font-weight: var(--fw-semibold); }
.calend-cno__dia--respuesta { background: var(--ejn-green-dark); color: var(--white); font-weight: var(--fw-semibold); }
.calend-cno__dia--envio     { background: var(--ejn-red-dark);   color: var(--white); font-weight: var(--fw-semibold); }
.calend-cno__leyenda { display: flex; flex-direction: column; gap: 4px; font-size: var(--fs-caption); color: var(--gray-600); }
.calend-cno__ref { position: relative; padding-left: 18px; }
.calend-cno__ref::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 10px; height: 10px; border-radius: 50%;
}
.calend-cno__ref--pedido::before    { background: var(--ejn-blue-dark); }
.calend-cno__ref--respuesta::before { background: var(--ejn-green-dark); }
.calend-cno__ref--envio::before     { background: var(--ejn-red-dark); }
.calend-cno__proximo { border-top: 1px solid var(--gray-200); padding-top: var(--space-3); display: flex; flex-direction: column; gap: 6px; }
.calend-cno__proximo h4 { margin: 0; font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--ejn-navy); }
.calend-cno__proximo p { margin: 0; font-size: var(--fs-small); color: var(--gray-600); display: flex; align-items: center; gap: 8px; }
.calend-cno__punto { width: 10px; height: 10px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.calend-cno__punto--pedido    { background: var(--ejn-blue-dark); }
.calend-cno__punto--respuesta { background: var(--ejn-green-dark); }
.calend-cno__punto--envio     { background: var(--ejn-red-dark); }


.dash-panel {
  background: var(--gray-50);
  border: 1px solid var(--gray-200);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  display: flex; flex-direction: column; gap: var(--space-3);
  box-shadow: var(--shadow-sm);
}
.dash-panel__cab { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
.dash-panel__cab h3 { margin: 0; font-size: var(--fs-h3); font-weight: var(--fw-semibold); color: var(--ejn-navy); }

/* Area degradada */
.dash-area { width: min(100%, 500px); height: auto; aspect-ratio: 480 / 180; display: block; margin: 0 auto; }
.dash-area__linea { stroke: var(--ejn-azul-acento); stroke-width: 2.5; }
.dash-area__punto { fill: var(--white); stroke: var(--ejn-azul-acento); stroke-width: 2.5; }
.dash-area__meses {
  display: flex; justify-content: space-between;
  font-size: var(--fs-caption); color: var(--gray-400); padding: 0 2px;
  max-width: 500px; margin: 0 auto;
}

/* Dona / gauge */
.dash-panel--donut { align-items: center; text-align: center; }
.dash-donut { width: 140px; height: 140px; }
.dash-donut__fondo { fill: none; stroke: var(--gray-200); stroke-width: 10; }
.dash-donut__valor {
  fill: none; stroke: var(--ejn-azul-acento); stroke-width: 10; stroke-linecap: round;
  transform-origin: 60px 60px; transform: rotate(-90deg);
  stroke-dasharray: calc(var(--valor, 0) / 100 * 314.16) 314.16;
}
.dash-donut__num { font: var(--fw-bold) 22px var(--font-family); fill: var(--ejn-navy); }
.dash-donut__sub { font-size: 11px; fill: var(--gray-600); }
.dash-panel__cta { align-self: center; }

/* Barras, una resaltada */
.dash-barras { display: flex; align-items: flex-end; gap: var(--space-3); height: 120px; padding-top: var(--space-2); }
.dash-barra { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); flex: 1 1 0; height: 100%; justify-content: flex-end; }
.dash-barra__col { display: block; width: 100%; max-width: 28px; border-radius: 6px 6px 0 0; background: var(--gray-200); height: calc(var(--alto, 0) * 1%); }
.dash-barra--activa .dash-barra__col { background: var(--ejn-azul-acento); }
.dash-barra__etiqueta { font-size: var(--fs-caption); color: var(--gray-400); }

/* Lista con avatar + titulo/subtitulo + valor */
.dash-lista { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.dash-lista__fila { display: flex; align-items: center; gap: var(--space-3); }
.dash-lista__avatar {
  width: 34px; height: 34px; border-radius: 50%; flex-shrink: 0;
  background: var(--ejn-azul-acento-soft); color: var(--ejn-azul-acento);
  display: flex; align-items: center; justify-content: center;
}
.dash-lista__texto { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.dash-lista__titulo {
  font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--ejn-navy);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dash-lista__subtitulo { font-size: var(--fs-caption); color: var(--gray-400); }
.dash-lista__valor { font-size: var(--fs-small); color: var(--gray-600); flex-shrink: 0; }

/* ============================================================
   Panel de inicio: columnas Usuarios y Resumen general (12/09/2026)
   Pedido de Daniel: agregar 2 columnas a la derecha de la fila
   Actividad por modulo / Ultimos movimientos. A diferencia del resto
   del dashboard (todavia ilustrativo), estas 2 SI son datos reales:
   Usuarios sale de sys_usuario (PanelController::inicio()), Resumen
   general suma $m['resumen'] que PanelResumenRepo ya calcula por
   modulo (mismo dato que los chips de cada tarjeta mas arriba).
   ============================================================ */
.dash-fila--4 { grid-template-columns: 1.3fr 1fr 0.9fr 1fr; }
@media (max-width: 1100px) { .dash-fila--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px)  { .dash-fila--4 { grid-template-columns: 1fr; } }

/* Usuarios: 2 cifras apiladas + icono */
.dash-panel--usuarios { align-items: center; text-align: center; justify-content: center; }
.dash-usuarios { display: flex; flex-direction: column; align-items: center; gap: var(--space-2); }
.dash-usuarios__icono { color: var(--ejn-azul-acento); }
.dash-usuarios__cifra { display: flex; flex-direction: column; gap: 2px; }
.dash-usuarios__numero { font-size: 28px; font-weight: var(--fw-bold); color: var(--ejn-navy); line-height: 1; }
.dash-usuarios__cifra--sec .dash-usuarios__numero { font-size: var(--fs-h3); color: var(--ejn-azul-acento); }
.dash-usuarios__etiqueta { font-size: var(--fs-caption); color: var(--gray-600); }

/* Resumen general: una fila por categoria (punto de color + etiqueta + numero + %) */
.dash-resumen { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.dash-resumen__fila { display: flex; align-items: center; gap: var(--space-2); }
.dash-resumen__punto { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.dash-resumen__punto--ok   { background: var(--ejn-green-dark); }
.dash-resumen__punto--warn { background: var(--ejn-gold-dark); }
.dash-resumen__punto--dang { background: var(--ejn-red-dark); }
.dash-resumen__punto--info { background: var(--ejn-blue-dark); }
.dash-resumen__punto--neu  { background: var(--gray-400); }
.dash-resumen__etiqueta {
  flex: 1 1 auto; min-width: 0; font-size: var(--fs-small); color: var(--ejn-navy);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dash-resumen__numero { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--ejn-navy); flex-shrink: 0; }
.dash-resumen__pct { font-size: var(--fs-caption); color: var(--gray-600); min-width: 32px; text-align: right; flex-shrink: 0; }

/* ---------- Tabla compacta dentro del panel lateral ancho ----------
   Pedido de Daniel (12/09/2026): la nomina real de ARCA que trae el panel
   de un trabajador (13 columnas) o de un periodo de Emision (21 columnas,
   ver .avisos--ancho mas arriba) seguia necesitando la barra de scroll
   horizontal incluso a 1100px -- pidio achicar la letra de la grilla para
   que entre todo sin scroll. Scopeado bajo .avisos--ancho .grilla__tabla
   a proposito: son las UNICAS 2 vistas que usan ese modificador de ancho
   (trabajador_lateral.php, emision_periodo_lateral.php), asi que esto no
   toca el tamano de letra de ninguna otra grilla de la plataforma -- ni
   siquiera el resto de los paneles laterales (.avisos base, ej. el de
   movimiento), que no tienen este problema de columnas. */
.avisos--ancho .grilla__tabla { font-size: 11px; }
.avisos--ancho .grilla__tabla thead th { padding: 5px 6px; }
.avisos--ancho .grilla__tabla tbody td { padding: 3px 6px; }
.avisos--ancho .grilla__tabla .badge { padding: 1px 6px; font-size: 10.5px; }

/* ============================================================
   Panel de inicio: dashboard a todo el ancho (12/09/2026, ajustado
   el mismo dia -- la primera pasada con clamp()/vw se fue al otro
   extremo: la dona y el anillo terminaron ocupando cientos de
   pixeles y el area degradada mas de 500px de alto en pantallas
   anchas, mas un bug real (el selector ".kpi-tarjeta__anillo svg"
   con combinador descendiente tambien agrandaba el icono del modulo
   anidado adentro, no solo el aro de progreso -- se corrige con
   combinador directo "> svg"). Vuelve a tamanos fijos moderados
   (sin vw): el dashboard sigue a todo el ancho (max-width:none,
   igual que la grilla de modulos), pero el contenido interno no
   escala con el viewport -- crece un poco respecto del diseno
   original (52->64px el anillo, 140->170px la dona) y se queda ahi,
   sin depender del ancho de pantalla. La grilla de KPIs sigue en
   minmax(0,1fr) por columna: en 4 columnas, cada tarjeta usa el
   espacio que le toca y el contenido interno no crece con el ancho,
   asi que no fuerza el layout a desbordar. */
.panel-dashboard { max-width: none; }
.kpi-tarjeta, .dash-panel { min-width: 0; }

.kpi-tarjeta__anillo { width: 64px; height: 64px; }
.kpi-tarjeta__anillo > svg { width: 100%; height: 100%; }
.kpi-tarjeta__valor { font-size: 20px; }

.dash-donut { width: 170px; height: 170px; }

.dash-barras { height: 140px; }

.dash-lista__avatar { width: 38px; height: 38px; }

/* 12/09/2026: el height:220px fijo que iba aca se saca -- era la causa
   real de la deformacion del area "Tendencia general" (ver nota junto a
   la regla base .dash-area, mas arriba en este archivo). aspect-ratio ya
   mantiene la proporcion correcta en cualquier ancho, sin necesidad de
   fijar un alto en px. */
.dash-fila--2 { grid-template-columns: 2fr 1fr; }

/* ============================================================
   Panel de inicio: indicadores laterales (12/09/2026)
   Grid de 3 columnas alrededor del panel-dashboard existente:
   izquierda 2 tarjetas (canales por zona / prestadores por
   especializacion, dato real), derecha 4 tarjetas (cotizaciones
   vs polizas -- real -- y 3 ilustrativas: siniestros/trabajadores,
   cobranza/emision, polizas por programa especial -- sin fuente
   de dato real confirmada, ver docs/ESTADO.md). Fijo en px, no
   vw/clamp -- leccion del ajuste de tamaño anterior en esta misma
   sesion (ver seccion de arriba, todo el ancho).
   ============================================================ */
.panel-dashboard-grid {
  display: grid;
  grid-template-columns: 240px minmax(0, 1fr) 240px;
  gap: var(--space-4);
  align-items: stretch;
  width: 100%;
  margin-top: var(--space-4);
}
.panel-dashboard-centro { min-width: 0; }
.panel-dashboard-centro .panel-dashboard { margin-top: 0; }
.panel-dashboard-lateral { display: flex; flex-direction: column; gap: var(--space-4); min-width: 0; }
.panel-dashboard-lateral > .dash-panel { flex: 1 1 0; }

@media (max-width: 1100px) {
  .panel-dashboard-grid { grid-template-columns: 1fr; }
  .panel-dashboard-centro { order: 1; }
  .panel-dashboard-lateral--izq { order: 2; }
  .panel-dashboard-lateral--der { order: 3; }
  .panel-dashboard-lateral { flex-direction: row; flex-wrap: wrap; }
  .panel-dashboard-lateral > .dash-panel { flex: 1 1 260px; }
}

/* Ranking horizontal (etiqueta + barra proporcional + numero) */
.dash-ranking { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.dash-ranking__fila { display: flex; align-items: center; gap: var(--space-2); }
.dash-ranking__etiqueta {
  font-size: var(--fs-small); color: var(--gray-600);
  flex: 0 0 92px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dash-ranking__barra { flex: 1 1 auto; height: 8px; border-radius: 4px; background: var(--gray-200); overflow: hidden; }
.dash-ranking__barra span { display: block; height: 100%; border-radius: 4px; background: var(--ejn-azul-acento); width: calc(var(--alto, 0) * 1%); }
.dash-ranking__numero { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--ejn-navy); flex-shrink: 0; min-width: 20px; text-align: right; }
.dash-ranking__vacio { font-size: var(--fs-small); color: var(--gray-400); text-align: center; padding: var(--space-3) 0; }

/* Comparacion de 2 valores en barras verticales */
.dash-comparacion { display: flex; align-items: flex-end; gap: var(--space-4); height: 90px; padding-top: var(--space-2); }
.dash-comparacion__item { display: flex; flex-direction: column; align-items: center; gap: var(--space-1); flex: 1 1 0; height: 100%; justify-content: flex-end; }
.dash-comparacion__barra { display: flex; align-items: flex-end; width: 100%; max-width: 34px; height: 100%; }
.dash-comparacion__barra span { display: block; width: 100%; border-radius: 6px 6px 0 0; background: var(--ejn-azul-acento); height: calc(var(--alto, 0) * 1%); }
.dash-comparacion__item:nth-child(2) .dash-comparacion__barra span { background: var(--gray-300); }
.dash-comparacion__numero { font-size: var(--fs-small); font-weight: var(--fw-semibold); color: var(--ejn-navy); }
.dash-comparacion__etiqueta { font-size: var(--fs-caption); color: var(--gray-400); text-align: center; }

/* ============================================================
   Bienvenida — intro animada post-login (pedido de Daniel, 14/09/2026)
   Pantalla de transición pura entre el login y /panel, inspirada
   conceptualmente en el efecto de apertura de Netflix (logo con una
   animación breve) pero con 100% identidad RixART -- mismo wordmark y
   misma paleta que ya usa app/Views/auth/login.php. No es una pantalla
   de navegación: sin menú, sin acciones -- sólo se desvanece hacia /panel.
   Ver app/Views/panel/bienvenida.php y public/assets/js/ejn-bienvenida.js.
   ============================================================ */
.bienvenida-intro {
  position: fixed;
  inset: 0;
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: var(--ejn-navy);
}
.bienvenida-intro__fondo {
  position: absolute;
  inset: 0;
  background: radial-gradient(circle at 50% 42%, var(--ejn-navy-dark, #051122) 0%, var(--ejn-navy) 55%, #030b1a 100%);
  opacity: 0;
  animation: bienvenida-fondo-in 1.1s ease-out forwards;
}
.bienvenida-intro__contenido {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.15rem;
  padding: 0 1.5rem;
  text-align: center;
}
.bienvenida-intro__tarjeta {
  /* 25/09/2026, pedido de Daniel (capturas de referencia QINSURE/CRM EJN
     Seguros): el logo ya no flota directo sobre el fondo navy -- va
     dentro de una tarjeta blanca redondeada, con sombra, como en las
     pantallas de referencia. La animación de entrada (antes en
     .bienvenida-intro__logo) pasa a esta tarjeta. */
  width: min(78vw, 420px);
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 2rem 2.25rem;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transform: scale(.86);
  animation: bienvenida-logo-in .9s cubic-bezier(.16,.9,.3,1) .35s forwards;
}
.bienvenida-intro__logo {
  width: 100%;
}
.bienvenida-intro__logo svg {
  width: 100%;
  height: auto;
  display: block;
}
.bienvenida-intro__tagline {
  margin: 0;
  color: #cfe0ff;
  font-size: .95rem;
  letter-spacing: .04em;
  opacity: 0;
  animation: bienvenida-fade-in .7s ease-out 1s forwards;
}
.bienvenida-intro__caption {
  /* 25/09/2026: pista tipo "CARGANDO TU ESPACIO DE TRABAJO" del
     mockup de referencia -- sólo en la intro post-login, la pantalla
     de bloqueo no la usa (no es una carga, ver bloqueo-pantalla__pista). */
  margin: 0;
  color: rgba(255,255,255,.5);
  font-size: .7rem;
  font-weight: var(--fw-semibold);
  letter-spacing: .12em;
  text-transform: uppercase;
  opacity: 0;
  animation: bienvenida-fade-in .7s ease-out 1.1s forwards;
}
.bienvenida-intro__barra {
  width: min(220px, 40vw);
  height: 2px;
  border-radius: 2px;
  background: rgba(255,255,255,.14);
  overflow: hidden;
  opacity: 0;
  animation: bienvenida-fade-in .5s ease-out 1.25s forwards;
}
.bienvenida-intro__barra span {
  display: block;
  height: 100%;
  width: 40%;
  border-radius: 2px;
  background: var(--ejn-azul-acento);
  animation: bienvenida-barra 1.5s ease-in-out 1.3s infinite;
}
.bienvenida-intro__saltar {
  position: absolute;
  right: 1.25rem;
  bottom: 1.25rem;
  z-index: 2;
  color: rgba(255,255,255,.55);
  font-size: .8rem;
  text-decoration: none;
  opacity: 0;
  animation: bienvenida-fade-in .5s ease-out 1.5s forwards;
}
.bienvenida-intro__saltar:hover,
.bienvenida-intro__saltar:focus-visible {
  color: #fff;
}
.bienvenida-intro.es-salida {
  animation: bienvenida-salida .4s ease-in forwards;
}

@keyframes bienvenida-fondo-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes bienvenida-logo-in { from { opacity: 0; transform: scale(.86); } to { opacity: 1; transform: scale(1); } }
@keyframes bienvenida-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes bienvenida-barra {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(350%); }
}
@keyframes bienvenida-salida { from { opacity: 1; } to { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .bienvenida-intro__fondo,
  .bienvenida-intro__tarjeta,
  .bienvenida-intro__tagline,
  .bienvenida-intro__caption,
  .bienvenida-intro__barra,
  .bienvenida-intro__saltar {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
  .bienvenida-intro__barra span {
    animation: none !important;
    width: 100%;
  }
}
/* ============================================================
   Bloquear pantalla — overlay sobre la página actual (14/09/2026)
   Reusa .bienvenida-intro/.es-salida (el intro de /bienvenida, ver más
   arriba) sin modificarlas -- este bloque sólo agrega el modificador
   --bloqueo y la pista de texto. No navega a ningún lado: se muestra y
   se oculta con un clic, tapando/destapando la página tal cual estaba.
   Ver app/Views/layouts/privado.php (id="bloqueo-pantalla") y
   iniciarBloqueoPantalla() en ejn-app.js.
   ============================================================ */
.bienvenida-intro--bloqueo {
  z-index: 2000;
  cursor: pointer;
}
.bloqueo-pantalla__pista {
  margin: 0;
  color: rgba(255,255,255,.6);
  font-size: .85rem;
}

@media (prefers-reduced-motion: reduce) {
  .bienvenida-intro.es-salida {
    animation: none !important;
    opacity: 0 !important;
  }
}