/* ===== Hik-Asistencia — componentes compartidos =====
 *
 * Una sola definición de botón, campo, tabla, chip, aviso flotante, diálogo y
 * pestañas para las cinco páginas (app de RH, login, panel ISCOM, asistente y
 * portal del empleado). Cada página enlaza tokens.css → componentes.css → su
 * hoja propia, que sólo conserva distribución y particularidades. Antes cada
 * hoja repetía estas reglas con medidas distintas y los arreglos se hacían
 * tres veces (o dos, y una se olvidaba).
 *
 * Sin colores fijos: todo sale de tokens.css. El único «color» que se
 * declara aquí es --sobre-primario, que tokens.css define y JS ajusta cuando
 * el color de marca de la empresa es claro.
 */

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/* Al cambiar de tema, tema.js pone esta clase un fotograma: sin ella, sesenta
   cajas, botones y renglones animarían su fondo a la vez. */
html.sin-transicion *, html.sin-transicion *::before, html.sin-transicion *::after { transition: none !important; }

/* Chromium no aplica el atributo hidden a un <svg> raíz: sin esta regla el
   sprite de iconos ocupa 150 px arriba de la página. */
svg[hidden] { display: none !important; }
.icono { width: 1.15em; height: 1.15em; vertical-align: -.2em; flex: none; }
.oculto { display: none !important; }
.texto-suave { color: var(--texto-suave); }
/* Sólo para lectores de pantalla (texto de botones que en pantalla llevan icono) */
.solo-lector { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* ===== Foco de teclado =====
   Un solo anillo azul para todo lo que se pueda enfocar: se ve sobre claro,
   sobre oscuro, sobre el color de marca y sobre la barra lateral. Sólo con
   :focus-visible, así el clic con ratón no lo enciende. */
:focus-visible { outline: 2px solid var(--foco-anillo); outline-offset: 2px; }
input:focus-visible, select:focus-visible, textarea:focus-visible { outline-offset: 0; }

/* ===== Botones ===== */
.boton {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-height: 36px;
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto);
  border-radius: var(--radio); padding: 8px 14px; cursor: pointer;
  font: inherit; font-size: var(--tx-m); font-weight: 600; line-height: 1.2;
  text-decoration: none; white-space: nowrap;
  /* propiedades exactas, nunca `all`: sólo transform y color llegan a la GPU */
  transition: background var(--t-corto) ease, border-color var(--t-corto) ease,
              color var(--t-corto) ease, transform var(--t-pulsa) var(--salida);
}
.boton .icono { width: 1.2em; height: 1.2em; }
/* El hover sólo en equipos con ratón: en una pantalla táctil se dispara al
   tocar y deja el botón «encendido» después de soltarlo. */
@media (hover: hover) and (pointer: fine) {
  .boton:hover { background: var(--superficie-hover); border-color: var(--borde-fuerte); }
  .boton.primario:hover { background: var(--primario-hover); border-color: var(--primario-hover); }
  .boton.peligro:hover { background: color-mix(in srgb, var(--error) 88%, black); border-color: color-mix(in srgb, var(--error) 88%, black); }
  .boton.suave:hover { background: var(--superficie-hover); }
  .boton-icono:hover { background: var(--superficie-hover); color: var(--texto); }
}
/* Hundir el botón al pulsarlo es la confirmación de que la interfaz escuchó. */
.boton:active:not(:disabled) { transform: scale(.97); }
.boton.primario { background: var(--primario); border-color: var(--primario); color: var(--sobre-primario); }
/* Destructivo: rojo de error sólido; se distingue del primario de marca. */
.boton.peligro { background: var(--error); border-color: var(--error); color: #fff; }
.boton.peligro-suave { color: var(--error); }
.boton.suave { border-color: transparent; background: var(--superficie-2); }
.boton.chico { min-height: 30px; padding: 4px 10px; font-size: var(--tx-xs); }
.boton-bloque { display: flex; width: 100%; }
.boton:disabled { opacity: .5; cursor: not-allowed; }

/* Botón en espera (UI.conEspera): conserva su ancho, muestra un anillo que
   gira y no responde a clics repetidos. */
.boton[aria-busy="true"] { position: relative; cursor: progress; opacity: .85; }
.boton[aria-busy="true"] > .icono { display: none; }
.espera-anillo {
  width: 1em; height: 1em; flex: none; border-radius: 50%;
  border: 2px solid currentColor; border-right-color: transparent;
  animation: girar .8s linear infinite;
}
@keyframes girar { to { transform: rotate(360deg); } }

/* Botón que sólo lleva un icono: cuadrado, con área de toque decente incluso
   con ratón (32 px) y del alto de toque en pantallas táctiles. */
.boton-icono {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; padding: 0; flex: none;
  border: none; background: none; color: var(--texto-suave); cursor: pointer;
  border-radius: var(--radio-s); font: inherit; line-height: 1;
  transition: background var(--t-corto) ease, color var(--t-corto) ease, transform var(--t-pulsa) var(--salida);
}
.boton-icono .icono { width: 18px; height: 18px; vertical-align: middle; }
.boton-icono:active { transform: scale(.92); }
.boton-icono.peligro { color: var(--error); }
.boton-icono:disabled { opacity: .4; cursor: not-allowed; }

/* ===== Campos ===== */
.campo { display: flex; flex-direction: column; gap: 4px; min-width: 130px; }
.campo.ancho { flex: 1 1 240px; }
.campo.compacto { min-width: 170px; }
/* Cortos (minutos, cantidades) y medios (fechas, horas): en teléfono no se
   estiran a todo lo ancho como los demás. */
.campo.corto { flex: 0 1 110px; min-width: 0; max-width: 110px; }
.campo.medio { flex: 0 1 190px; min-width: 0; max-width: 190px; }
.campo label, .campo > .etiqueta { font-size: var(--tx-xs); color: var(--texto-suave); font-weight: 600; }
/* Marca de obligatorio: se agrega con la clase, no a mano en cada etiqueta */
.campo.obligatorio > label::after { content: " *"; color: var(--error); font-weight: 700; }
/* Ayuda persistente debajo de un campo (no sólo el placeholder) */
.campo-ayuda { font-size: var(--tx-xs); color: var(--texto-suave); line-height: 1.4; }
/* Fondo con token y no blanco fijo: en oscuro un selector de fecha con fondo
   blanco y tinta clara sería invisible. Borde --borde-fuerte: el borde
   normal (1,3:1) se perdía sobre la superficie. */
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]):not([type=submit]):not([type=button]),
select, textarea {
  border: 1px solid var(--borde-fuerte); border-radius: var(--radio); padding: 8px 10px;
  font: inherit; font-size: var(--tx-m); background: var(--superficie); color: var(--texto); width: 100%;
  min-height: 36px;
  transition: border-color var(--t-corto) ease, box-shadow var(--t-corto) ease;
}
input::placeholder, textarea::placeholder { color: var(--texto-suave); opacity: .8; }
input:focus, select:focus, textarea:focus { border-color: var(--primario); }
/* El autorrelleno del navegador no debe pintar la caja de amarillo/blanco en oscuro */
input:-webkit-autofill { -webkit-box-shadow: 0 0 0 1000px var(--superficie) inset; -webkit-text-fill-color: var(--texto); }
input[type=color] { border: 1px solid var(--borde-fuerte); border-radius: var(--radio); height: 38px; width: 60px; padding: 2px; background: var(--superficie); cursor: pointer; }
input[type=checkbox], input[type=radio] { accent-color: var(--primario); width: 16px; height: 16px; margin: 0; }
textarea { resize: vertical; line-height: 1.5; min-height: 80px; }
textarea.mono { font-family: var(--mono); font-size: var(--tx-s); }
input:disabled, select:disabled, textarea:disabled { opacity: .55; cursor: not-allowed; }
input:read-only:not([type=checkbox]):not([type=radio]) { background: var(--superficie-2); }

/* Validación EN el campo: borde rojo, mensaje debajo y aria-invalid. El
   mensaje se anuncia solo (role=alert) y desaparece al corregir el campo. */
.campo.invalido > label { color: var(--error); }
.campo.invalido input, .campo.invalido select, .campo.invalido textarea,
[aria-invalid="true"] { border-color: var(--error) !important; box-shadow: 0 0 0 3px color-mix(in srgb, var(--error) 20%, transparent); }
.campo-error {
  display: flex; align-items: flex-start; gap: 5px;
  font-size: var(--tx-xs); color: var(--error); font-weight: 600; line-height: 1.4;
}
.campo-error .icono { width: 1.1em; height: 1.1em; margin-top: 1px; }

/* Renglón de formulario y renglones de botones */
.formulario-linea, .linea { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 12px; align-items: flex-end; }
.fila { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.fila.derecha { justify-content: flex-end; }
.fila-entre { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.check-linea { display: flex; gap: 8px; align-items: flex-start; line-height: 1.5; margin: 8px 0; cursor: pointer; }
.campo.casilla {
  flex: 0 0 auto; flex-direction: row; align-items: center; gap: 8px;
  min-height: 36px; font-size: var(--tx-m); color: var(--texto); cursor: pointer;
}
.campo.casilla input { width: 18px; height: 18px; }

/* ===== Tablas =====
   A ras de página: sin marco, sin altura máxima y sin segunda barra de
   desplazamiento. La página es lo único que se desplaza; el encabezado se
   queda pegado arriba. Sólo las matrices de calendario (.calendario, .matriz)
   se desplazan a lo ancho dentro de su envoltura. */
.tabla-envoltura { overflow: visible; border: 0; border-radius: 0; max-height: none !important; background: none; }
.tabla-envoltura:has(> table.calendario) { overflow: auto; -webkit-overflow-scrolling: touch; }
/* Último recurso: una tabla que no cabe se desplaza en su caja (lo marca
   UI.tablasComoTarjetas al medirla), en vez de arrastrar la página a lo ancho. */
.tabla-envoltura.desbordada { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Escotilla: una tabla que de verdad deba desplazarse dentro de su caja
   (vistas previas de importación, listas larguísimas dentro de un diálogo). */
.tabla-envoltura.desplazable { overflow: auto; max-height: min(420px, 60dvh) !important; -webkit-overflow-scrolling: touch; }
.tabla, .tabla-envoltura > table {
  border-collapse: collapse; width: 100%; font-size: var(--tx-s);
  /* Cifras de ancho fijo: 08:13 y 11:07 ocupan lo mismo, así las columnas
     de horas quedan alineadas y no bailan al repintarse. */
  font-variant-numeric: tabular-nums;
}
.tabla th, .tabla-envoltura > table th {
  text-align: left; background: var(--superficie); padding: 8px 10px; font-size: 11px; letter-spacing: .05em; text-transform: uppercase;
  color: var(--texto-suave); position: sticky; top: calc(var(--alto-aviso, 0px) + var(--alto-periodo, 0px)); border-bottom: 1px solid var(--borde); z-index: 1;
  white-space: normal; vertical-align: bottom;
}
.tabla tbody tr.inactivo td, .tabla-envoltura > table tbody tr.inactivo td { color: var(--texto-suave); }
/* Nombre que abre la ficha o el detalle del renglón (clic al nombre, sin botón
   escondido al final). Va en la tinta normal: si cada renglón llevara el color
   de la empresa, la lista entera se leería como un aviso. */
.enlace-fila { background: none; border: none; padding: 0; font: inherit; font-weight: 600; color: inherit; cursor: pointer; text-align: left; }
.enlace-fila:hover { color: var(--primario-texto, var(--primario)); text-decoration: underline; }
/* Las celdas se PARTEN: una tabla debe caber en la pantalla antes que
   desplazarse a lo ancho. Sólo horas, fechas, cifras y chips van en una línea. */
.tabla td, .tabla-envoltura > table td { padding: 7px 10px; border-bottom: 1px solid var(--borde-suave); white-space: normal; overflow-wrap: break-word; vertical-align: top; }
.tabla td.nowrap, .tabla td.num, .tabla-envoltura > table td.nowrap { white-space: nowrap; overflow-wrap: normal; }
.tabla td .sub, .tabla-envoltura > table td .sub { display: block; font-size: 11px; color: var(--texto-suave); margin-top: 1px; }
.tabla tbody tr:last-child td, .tabla-envoltura > table tbody tr:last-child td { border-bottom: none; }
/* Recorrer una tabla larga con la vista es más fácil si el renglón responde;
   sólo color, y sin transición. */
@media (hover: hover) and (pointer: fine) {
  .tabla tbody tr:hover td, .tabla-envoltura > table tbody tr:hover td { background: var(--superficie-hover); }
}
.tabla input:not([type=checkbox]):not([type=radio]), .tabla select { padding: 5px 8px; border-radius: var(--radio-s); min-width: 64px; min-height: 30px; }
.tabla input[type=checkbox], .tabla input[type=radio] { width: 16px; height: 16px; min-width: 0; min-height: 0; padding: 0; }
.tabla td.num, .tabla th.num { text-align: right; }
/* Encabezado ordenable: se ve como botón y dice cómo está ordenado */
.tabla th[aria-sort] { cursor: pointer; user-select: none; }
.tabla th[aria-sort]:hover { color: var(--texto); }
/* Primera columna fija (el nombre del empleado): al desplazar una tabla ancha
   hacia la derecha en un teléfono, se sigue sabiendo de quién es el renglón. */
.tabla .col-fija { position: sticky; left: 0; z-index: 1; background: var(--superficie); }
.tabla th.col-fija { z-index: 3; background: var(--superficie); }
.tabla tfoot td.col-fija { background: var(--superficie-2); z-index: 2; }
@media (hover: hover) and (pointer: fine) {
  .tabla tbody tr:hover td.col-fija { background: var(--superficie-hover); }
}
@media screen and (max-width: 1023px) {
  .tabla .col-fija { box-shadow: 1px 0 0 var(--borde); }
}
/* Sombra que avisa «hay más columnas a la derecha» mientras la envoltura
   pueda desplazarse (la pone UI.vigilarDesborde). */
/* Sólo tiene sentido donde la caja SÍ se desplaza (calendarios y el último
   recurso .desbordada); en una tabla a ras la sombra prometería un scroll que no hay. */
.tabla-envoltura.desbordada.desborda-derecha,
.tabla-envoltura.desplazable.desborda-derecha,
.tabla-envoltura:has(> table.calendario).desborda-derecha { box-shadow: inset -14px 0 12px -12px color-mix(in srgb, var(--texto) 28%, transparent); }

/* ===== Cabecera de vista =====
   Todas las vistas comparten la misma línea: título (con conteo opcional),
   buscador, UNA acción primaria y el menú «⋯» con el resto. Las piezas las
   marca cada vista con data-cabecera y UI.cabeceraVista las coloca aquí.
   El texto instructivo de la cabecera (.sub sin id) vive ahora en la ayuda «?»;
   los .sub con id son estado real (fecha, periodo) y se siguen viendo. */
.vista-cabecera { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 16px; margin-bottom: 16px; padding-right: 48px; position: relative; min-height: 36px; }
.vista-cabecera h1 { margin: 0; font-size: var(--tx-xl); letter-spacing: -.015em; display: inline-flex; align-items: baseline; gap: 8px; }
.vista-cabecera h1 .cuenta { font-size: var(--tx-s); font-weight: 500; color: var(--texto-suave); font-variant-numeric: tabular-nums; }
.vista-cabecera h1 .cuenta:empty { display: none; }
.vista-cabecera .sub:not([id]) { display: none; }
.vista-cabecera .sub[id] { flex-basis: 100%; margin: -4px 0 0; color: var(--texto-suave); }
.cabecera-buscar { flex: 1 1 240px; max-width: 440px; min-width: 0; }
.cabecera-buscar .campo { min-width: 0; }
.cabecera-buscar input[type=search], .cabecera-buscar input[type=text] { width: 100%; }
.cabecera-acciones { margin-left: auto; display: flex; align-items: center; gap: 8px; position: relative; }
.btn-mas {
  width: 36px; height: 36px; padding: 0; border-radius: var(--radio); border: 1px solid var(--borde); background: var(--superficie);
  color: var(--texto-suave); display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
}
.btn-mas .icono { width: 18px; height: 18px; }
.btn-mas:hover, .btn-mas[aria-expanded="true"] { background: var(--superficie-hover); color: var(--texto); }
.menu-mas {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 60; min-width: 260px; max-width: min(360px, 90vw);
  background: var(--superficie); border: 1px solid var(--borde); border-radius: var(--radio); box-shadow: var(--sombra-alta); padding: 6px;
}
.menu-mas[hidden] { display: none; }
.menu-mas .boton, .menu-mas .boton.primario, .menu-mas .boton.suave {
  display: flex; width: 100%; justify-content: flex-start; gap: 10px; min-height: 36px; padding: 6px 10px;
  border: 0; background: none; box-shadow: none; border-radius: var(--radio-s); color: var(--texto); font-weight: 400; text-align: left; white-space: normal;
}
.menu-mas .boton:hover:not(:disabled) { background: var(--superficie-hover); transform: none; }
.menu-mas .boton .icono { color: var(--texto-suave); flex: none; }
.menu-mas .boton.peligro-suave { color: var(--error); }

/* ===== Segmentos con conteo =====
   Filtro de una lista (Activos 45 · Inactivos 2 · Datos faltantes 38): cada
   segmento filtra y a la vez resume. No es una pestaña: no cambia de sección. */
.segmentos { display: inline-flex; max-width: 100%; gap: 2px; padding: 3px; margin: 0 0 12px; background: var(--superficie-2); border-radius: 999px; overflow-x: auto; scrollbar-width: none; }
.segmentos::-webkit-scrollbar { display: none; }
.segmentos > button {
  flex: none; display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 4px 12px; border: 0; border-radius: 999px;
  background: none; color: var(--texto-suave); font: inherit; font-size: var(--tx-s); cursor: pointer; white-space: nowrap;
}
.segmentos > button b { font-weight: 500; color: var(--texto-tenue); font-variant-numeric: tabular-nums; }
.segmentos > button:hover { color: var(--texto); }
.segmentos > button[aria-selected="true"] { background: var(--superficie); color: var(--texto); font-weight: 600; box-shadow: var(--sombra); }
.segmentos > button[aria-selected="true"] b { color: var(--texto-suave); }
.segmentos .punto, .punto-aviso { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--aviso); flex: none; vertical-align: middle; }
.punto-aviso { margin-right: 6px; }

/* Conteo junto a un título de sección (mismo aspecto que .vista-cabecera h1 .cuenta) */
.caja h3 .cuenta { font-size: var(--tx-s); font-weight: 500; color: var(--texto-suave); font-variant-numeric: tabular-nums; }
.caja h3 .cuenta:empty { display: none; }
/* Segmentos en la misma fila que un selector: sin margen propio, para que queden centrados */
.fila-entre > .segmentos { margin-bottom: 0; }

/* ===== Línea de estado =====
   Una frase con los totales en lugar de repetir chips en cada renglón. */
.estado-linea { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0 0 14px; padding: 8px 12px; border-radius: var(--radio); background: var(--superficie-2); color: var(--texto-suave); font-size: var(--tx-s); }
.estado-linea[hidden] { display: none; }
.estado-linea .punto { width: 8px; height: 8px; border-radius: 50%; background: var(--aviso); flex: none; }
.estado-linea.ok .punto { background: var(--ok); }
.estado-linea b { color: var(--texto); font-weight: 600; font-variant-numeric: tabular-nums; }
.estado-linea .sep { color: var(--texto-tenue); }
.estado-linea .enlace { margin-left: auto; border: 0; background: none; padding: 0; color: var(--primario-texto); font: inherit; font-size: var(--tx-s); font-weight: 600; cursor: pointer; }
.estado-linea .enlace:hover { text-decoration: underline; }

/* ===== Barra inferior (teléfono) =====
   Cuatro secciones de uso diario y «Más», que abre el cajón con el menú completo. */
.barra-inferior { display: none; }
@media screen and (max-width: 767px), screen and (max-width: 1023px) and (max-height: 499px) {
  .barra-inferior {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 840;
    display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
    height: calc(56px + env(safe-area-inset-bottom, 0px)); padding-bottom: env(safe-area-inset-bottom, 0px);
    background: var(--superficie); border-top: 1px solid var(--borde);
  }
  .barra-inferior button {
    border: 0; background: none; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
    font: inherit; font-size: 10px; line-height: 1; color: var(--texto-suave); cursor: pointer; padding: 0;
  }
  .barra-inferior button .icono { width: 22px; height: 22px; }
  .barra-inferior button.activo { color: var(--primario-texto); font-weight: 600; }
  .contenido { padding-bottom: calc(76px + env(safe-area-inset-bottom, 0px)) !important; }
  /* Lo que se pega al pie (barra de guardar, avisos flotantes) sube por encima
     de la barra de navegación: si no, el dedo toca «Registros» en vez de «Guardar». */
  .barra-guardar { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); }
  .tabla th, .tabla-envoltura > table th { top: calc(var(--alto-barra) + var(--alto-aviso, 0px) + var(--alto-periodo, 0px)); }
  .cabecera-buscar { flex-basis: 100%; max-width: none; order: 9; }
  .vista-cabecera h1 { font-size: var(--tx-xl); }
}

/* ===== Chips de estado =====
   Par tinta/fondo por estado. El de aviso usa --aviso-texto (el naranja de
   icono no se lee sobre el ámbar del fondo). */
.chip { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: 999px; font-size: var(--tx-xs); font-weight: 600; line-height: 1.5; white-space: nowrap; background: var(--neutro-fondo); color: var(--neutro); }
.chip .icono { width: 1.1em; height: 1.1em; }
.chip-ok { background: var(--ok-fondo); color: var(--ok); }
.chip-aviso { background: var(--aviso-fondo); color: var(--aviso-texto); }
.chip-error { background: var(--error-fondo); color: var(--error); }
.chip-info { background: var(--info-fondo); color: var(--info); }
.chip-neutro { background: var(--neutro-fondo); color: var(--neutro); }
.chip-gris { background: rgba(255,255,255,.12); color: var(--lateral-texto); } /* vive en la barra lateral (oscura siempre) */
.chip-mini { padding: 0 5px; }
.chip.tachado { text-decoration: line-through; }
.chip-grande { font-size: var(--tx-m); padding: 6px 14px; }
/* Punto de estado (● de antes): toma el color del chip */
.punto { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }

/* ===== Avatares =====
   Foto de identificación o iniciales en gris neutro: el color de la interfaz
   se reserva para lo que pide atención (chips, puntos de aviso). */
.avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 32px; height: 32px; border-radius: 50%; overflow: hidden;
  background: var(--neutro-fondo); color: var(--neutro); font-weight: 700; font-size: 12px; letter-spacing: .02em;
  box-shadow: inset 0 0 0 1px rgba(0,0,0,.06);
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-sm { width: 24px; height: 24px; font-size: 10px; }
.avatar-lg { width: 56px; height: 56px; font-size: 20px; }
.avatar-xl { width: 96px; height: 96px; font-size: 32px; }

/* ===== Avisos en línea ===== */
.aviso-error, .aviso-ok, .aviso-atencion, .aviso-info, .aviso-suave {
  display: flex; gap: 8px; align-items: flex-start; flex-wrap: wrap;
  border-radius: var(--radio); padding: 9px 12px; margin: 8px 0; font-size: var(--tx-s); line-height: 1.45;
}
/* El texto de un aviso es una frase larga: sin esto no se encoge por debajo de
   su ancho mínimo (min-width:auto de flex) y empuja la página a lo ancho. */
.aviso-error > *, .aviso-ok > *, .aviso-atencion > *, .aviso-info > *, .aviso-suave > * { min-width: 0; overflow-wrap: anywhere; }
.aviso-error > .icono, .aviso-ok > .icono, .aviso-atencion > .icono, .aviso-info > .icono, .aviso-suave > .icono { flex: none; }
.aviso-error { background: var(--error-fondo); color: var(--error); }
.aviso-ok { background: var(--ok-fondo); color: var(--ok); }
.aviso-atencion, .aviso-suave { background: var(--aviso-fondo-2); color: var(--aviso-texto); }
.aviso-info { background: var(--info-fondo); color: var(--info); }
.aviso-error .icono, .aviso-ok .icono, .aviso-atencion .icono, .aviso-info .icono { margin-top: 2px; }

/* ===== Avisos flotantes (toasts) =====
   Tarjeta sobre la superficie con una franja del color del tipo: se lee igual
   en claro y en oscuro y no depende de invertir la tinta. Cada uno lleva
   icono, texto, botón de cerrar y, si se pide, una acción («Deshacer»). */
#toasts {
  position: fixed; right: 18px; bottom: 18px; z-index: 1000;
  display: flex; flex-direction: column; gap: 8px; max-width: min(420px, calc(100vw - 24px));
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--superficie); color: var(--texto);
  border: 1px solid var(--borde); border-left: 4px solid var(--info);
  padding: 10px 10px 10px 14px; border-radius: var(--radio-l);
  box-shadow: var(--sombra-alta); font-size: var(--tx-s); line-height: 1.45;
  opacity: 1; transform: translateY(0);
  transition: opacity var(--t-medio) var(--salida), transform var(--t-medio) var(--salida);
}
@starting-style { .toast { opacity: 0; transform: translateY(10px); } }
.toast.saliendo { opacity: 0; transform: translateY(6px); }
.toast > .icono { width: 18px; height: 18px; margin-top: 1px; color: var(--info); }
.toast.ok { border-left-color: var(--ok); }        .toast.ok > .icono { color: var(--ok); }
.toast.error { border-left-color: var(--error); }  .toast.error > .icono { color: var(--error); }
.toast.aviso { border-left-color: var(--aviso); }  .toast.aviso > .icono { color: var(--aviso-texto); }
.toast-texto { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.toast-accion {
  border: none; background: none; color: var(--primario-texto); font: inherit; font-weight: 700;
  cursor: pointer; padding: 0 4px; white-space: nowrap;
}
.toast-cerrar { width: 28px; height: 28px; margin: -4px -4px -4px 0; }

/* ===== Carga: esqueletos y velo de espera =====
   Un esqueleto (barras que brillan) donde va a aparecer el contenido, y un
   velo con anillo sobre lo que se está recargando (UI.cargando). */
.esqueleto {
  display: block; height: 12px; border-radius: 6px;
  background: linear-gradient(90deg, var(--superficie-2) 25%, var(--superficie-hover) 50%, var(--superficie-2) 75%);
  background-size: 200% 100%; animation: brillo 1.2s linear infinite;
}
@keyframes brillo { to { background-position: -200% 0; } }
.esqueleto-filas { display: flex; flex-direction: column; gap: 10px; padding: 12px; }
.esqueleto-filas .esqueleto:nth-child(3n+2) { width: 72%; }
.esqueleto-filas .esqueleto:nth-child(3n) { width: 86%; }
.esqueleto-tarjeta .esqueleto:first-child { height: 26px; width: 40%; margin-bottom: 10px; }
.esqueleto-tarjeta .esqueleto:last-child { width: 65%; }
[aria-busy="true"].tabla-envoltura, [aria-busy="true"].caja, [aria-busy="true"].zona-carga { position: relative; }
[aria-busy="true"].tabla-envoltura > table, [aria-busy="true"].caja > :not(.esqueleto-velo), [aria-busy="true"].zona-carga > :not(.esqueleto-velo) { opacity: .45; pointer-events: none; }
.esqueleto-velo {
  position: absolute; inset: 0; z-index: 4; display: flex; align-items: flex-start; justify-content: center; gap: 8px;
  font-size: var(--tx-s); font-weight: 600; color: var(--texto-suave);
  background: color-mix(in srgb, var(--superficie) 35%, transparent);
}
/* La envoltura ya no tiene altura tope: sin esto, en una tabla de miles de
   píxeles el «Cargando…» quedaría fuera de la pantalla. */
.esqueleto-velo > .velo-caja {
  position: sticky; top: 40vh; display: flex; align-items: center; gap: 8px;
  padding: 8px 14px; border-radius: 999px; background: var(--superficie); box-shadow: var(--sombra);
}
.esqueleto-velo .espera-anillo { width: 18px; height: 18px; }
@media (prefers-reduced-motion: reduce) { .esqueleto { animation: none; } }

/* ===== Diálogos ===== */
/* El fondo se funde y el panel crece desde 0.96. Nunca desde scale(0). */
.modal-fondo {
  position: fixed; inset: 0; background: var(--velo);
  display: flex; align-items: center; justify-content: center; z-index: 900; padding: 20px;
  opacity: 1;
  transition: opacity var(--t-corto) var(--salida);
}
@starting-style { .modal-fondo { opacity: 0; } }
/* width:100% + max-width: los anchos por diálogo se dan con max-width y el
   panel se encoge solo cuando la ventana es más angosta. */
.modal {
  background: var(--superficie); color: var(--texto); border: 1px solid var(--borde);
  border-radius: var(--radio-xl); padding: 20px 22px; width: 100%;
  max-width: 640px; max-height: 90dvh; overflow: auto;
  box-shadow: var(--sombra-alta);
  opacity: 1; transform: scale(1);
  transition: opacity var(--t-medio) var(--salida), transform var(--t-medio) var(--salida);
}
@starting-style { .modal { opacity: 0; transform: scale(.96); } }
/* Ficha lateral: el mismo diálogo, anclado a la derecha y a toda la altura.
   La lista queda a la vista tras un velo tenue; Escape o el velo lo cierran.
   Se llama «ficha-lateral» y no «lateral» porque el panel ISCOM ya usa
   .lateral para su carril de navegación (saas.css), que se carga después. */
.modal-fondo.ficha-lateral { justify-content: flex-end; align-items: stretch; padding: 0; background: color-mix(in srgb, var(--velo) 40%, transparent); }
.modal-fondo.ficha-lateral > .modal {
  width: min(560px, 100%); max-width: none !important; height: 100dvh; max-height: none !important;
  border-radius: 0; border-width: 0 0 0 1px; display: flex; flex-direction: column; transform: none;
}
.modal-fondo.ficha-lateral > .modal > .modal-acciones { margin-top: auto; padding-top: 16px; }
@starting-style { .modal-fondo.ficha-lateral > .modal { opacity: 0; transform: translateX(24px); } }
@media (prefers-reduced-motion: reduce) { .modal-fondo.ficha-lateral > .modal { transition: none; } }
.modal h3 { margin: 0 0 12px; font-size: var(--tx-l); display: flex; align-items: center; gap: 8px; }
.modal-acciones { display: flex; gap: 8px; margin-top: 16px; justify-content: flex-end; flex-wrap: wrap; }
.modal-confirmar { max-width: 440px; }
.modal-confirmar p { margin: 0 0 6px; line-height: 1.5; white-space: pre-line; }
.modal-confirmar .detalle { color: var(--texto-suave); font-size: var(--tx-s); }
.modal-confirmar .campo { margin-top: 10px; }
.progreso { height: 10px; background: var(--fondo-hundido); border-radius: 999px; margin-top: 14px; overflow: hidden; }
.progreso-barra { height: 100%; width: 0%; background: var(--primario); transition: width .3s; }

/* ===== Pestañas =====
   Dos formas: píldoras (.pestana / .ay-pestana / .tabs-textos button) y el
   control segmentado del portal (.pestanas). Mismos colores y foco. */
.ay-pestanas, .tabs-textos { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 12px; }
.pestana, .ay-pestana, .tabs-textos button {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid var(--borde); background: var(--superficie); color: var(--texto);
  padding: 7px 14px; border-radius: var(--radio); cursor: pointer; font: inherit; font-size: var(--tx-s);
  min-height: 36px;
  transition: background var(--t-corto) ease, border-color var(--t-corto) ease, color var(--t-corto) ease;
}
@media (hover: hover) and (pointer: fine) {
  .pestana:hover, .ay-pestana:hover, .tabs-textos button:hover { background: var(--superficie-hover); }
}
.pestana.activa, .ay-pestana.activa, .tabs-textos button.activa,
.pestana[aria-selected="true"], .ay-pestana[aria-selected="true"], .tabs-textos button[aria-selected="true"] {
  background: var(--primario); border-color: var(--primario); color: var(--sobre-primario);
}
.pestanas {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px;
  padding: 4px; margin-bottom: 14px;
  background: var(--fondo-hundido); border: 1px solid var(--borde); border-radius: var(--radio-l);
}
.pestanas button {
  min-width: 0; min-height: 40px;
  display: flex; align-items: center; justify-content: center; gap: 6px;
  font: inherit; font-size: var(--tx-m); font-weight: 500; padding: 8px 6px;
  border: none; border-radius: var(--radio); background: transparent; color: var(--texto-suave);
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  transition: background var(--t-corto) ease, color var(--t-corto) ease, box-shadow var(--t-corto) ease;
}
.pestanas button span { overflow: hidden; text-overflow: ellipsis; }
/* En teléfono las pestañas dejan de repartirse el ancho por igual (con cinco
   o seis se leía «Indic…», «Jornada y c…») y se desplazan de lado, como los
   segmentos; el icono sobra ahí, el nombre es lo que importa. */
@media screen and (max-width: 900px) {
  .pestanas {
    grid-auto-columns: max-content; overflow-x: auto; scrollbar-width: none;
    /* difuminado al final: dice que hay más pestañas a la derecha */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  }
  .pestanas::-webkit-scrollbar { display: none; }
  .pestanas button > .icono { display: none; }
  .pestanas button { padding: 8px 12px; font-size: var(--tx-s); }
}
.pestanas button.activa, .pestanas button[aria-selected="true"] { background: var(--superficie); color: var(--primario-texto); font-weight: 600; box-shadow: var(--sombra); }
@media (hover: hover) and (pointer: fine) {
  .pestanas button:not(.activa):hover { color: var(--texto); }
}

/* ===== Botón de tema y hamburguesa =====
   Cuadrados del alto de toque; sin fondo por omisión (heredan la tinta de
   donde estén: barra lateral oscura o barra superior clara). */
.btn-tema, .menu-hamburguesa {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: var(--alto-toque); height: var(--alto-toque); padding: 0;
  border: none; background: none; color: inherit; cursor: pointer;
  border-radius: var(--radio); font: inherit; line-height: 1;
  transition: background var(--t-corto) ease, transform var(--t-pulsa) var(--salida);
}
.btn-tema .icono, .menu-hamburguesa .icono { width: 22px; height: 22px; vertical-align: middle; }
.btn-tema:active { transform: scale(.94); }
/* Variante con borde para páginas sin barra (login, asistente, portal) */
.btn-tema.con-borde { border: 1px solid var(--borde); background: var(--superficie); color: var(--texto-suave); }
@media (hover: hover) and (pointer: fine) {
  .btn-tema:hover, .menu-hamburguesa:hover { background: var(--superficie-hover); }
  .btn-tema.con-borde:hover { border-color: var(--borde-fuerte); color: var(--texto); }
}

/* ===== Hojas inferiores (<640) =====
   Un diálogo centrado en un teléfono queda a media pantalla con el teclado
   encima. Pegado abajo se alcanza con el pulgar y crece hacia arriba. */
@media screen and (max-width: 639px) {
  .modal-fondo { align-items: flex-end; padding: 0; }
  .modal {
    width: 100% !important; max-width: none !important; max-height: 92dvh;
    border-radius: var(--radio-xl) var(--radio-xl) 0 0; border-bottom: none;
    padding: 18px 16px calc(18px + env(safe-area-inset-bottom, 0px));
  }
  @starting-style { .modal { transform: translateY(16px); } }
  .modal-acciones .boton { flex: 1 1 auto; }
  #toasts { left: 12px; right: 12px; bottom: max(12px, env(safe-area-inset-bottom, 0px)); max-width: none; }
}

/* ===== Formularios en pantallas angostas (<600) =====
   Cada campo ocupa su propio renglón; los cortos y medios conservan su ancho. */
@media screen and (max-width: 599px) {
  .campo, .campo.ancho { flex: 1 1 100%; min-width: min(130px, 100%); }
  .campo.compacto { min-width: min(170px, 100%); }
  .campo.corto { flex: 0 1 110px; min-width: 0; }
  .campo.medio { flex: 0 1 190px; min-width: 0; }
  .campo.casilla { flex: 0 0 auto; }
  .tabla-envoltura { border-radius: var(--radio); }
}

/* ===== Tablas como tarjetas (teléfono; en tableta las de 8+ columnas) =====
   Una tabla de 12 columnas con scroll lateral no se puede leer con un dedo.
   ui.js marca con .modo-tarjetas las tablas de 5 o más columnas y copia el
   encabezado de cada columna a data-etiqueta; cada renglón se vuelve una
   tarjeta de dos columnas con la primera celda (el nombre) como título y las
   acciones al pie. */
table.modo-tarjetas thead { display: none; }
table.modo-tarjetas, table.modo-tarjetas tbody, table.modo-tarjetas tfoot { display: block; width: 100%; }
table.modo-tarjetas tr {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px 12px;
  padding: 10px 12px; border-bottom: 1px solid var(--borde-suave);
}
table.modo-tarjetas tbody tr:last-child { border-bottom: none; }
table.modo-tarjetas td { display: block; padding: 0; border: 0; white-space: normal; min-width: 0; overflow-wrap: anywhere; background: transparent !important; }
table.modo-tarjetas td[data-etiqueta]::before {
  content: attr(data-etiqueta); display: block;
  font-size: var(--tx-xs); font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: var(--texto-suave); margin-bottom: 1px;
}
table.modo-tarjetas td:first-child { grid-column: 1 / -1; font-weight: 600; font-size: var(--tx-m); }
table.modo-tarjetas td:first-child::before { content: none; }
table.modo-tarjetas td[colspan] { grid-column: 1 / -1; }
/* columnas sin encabezado = acciones: al pie, a la derecha */
table.modo-tarjetas td[data-etiqueta=""] { grid-column: 1 / -1; display: flex; gap: 6px; justify-content: flex-end; flex-wrap: wrap; }
table.modo-tarjetas td[data-etiqueta=""]::before { content: none; }
table.modo-tarjetas td[data-etiqueta=""]:empty { display: none; }
table.modo-tarjetas .col-fija { position: static; box-shadow: none; }
table.modo-tarjetas tfoot td { font-weight: 700; }
.tabla-envoltura:has(> table.modo-tarjetas) { box-shadow: none; }

/* ===== Pantallas táctiles =====
   Objetivos del alto de toque y campos a 16 px: por debajo de eso iOS hace
   zoom al enfocar un campo. Las casillas se excluyen: un checkbox de 44 px
   de alto se ve roto. */
@media (pointer: coarse) {
  .boton, .boton-icono, .pestana, .ay-pestana, .tabs-textos button, .pestanas button, select,
  input:not([type=checkbox]):not([type=radio]):not([type=file]):not([type=range]) { min-height: var(--alto-toque); }
  .boton-icono { width: var(--alto-toque); }
  .toast-cerrar { width: 36px; height: 36px; }
  /* Con la misma especificidad que la regla base o pierde y el teléfono hace zoom */
  input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]):not([type=color]):not([type=submit]):not([type=button]),
  select, textarea { font-size: 16px; }
}

/* ===== Movimiento reducido =====
   Se conservan los cambios de opacidad y color, que ayudan a entender qué
   pasó, y se quita el desplazamiento y la escala. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  .espera-anillo { animation: none; border-right-color: currentColor; opacity: .6; }
  .boton:active:not(:disabled), .boton-icono:active, .btn-tema:active { transform: none; }
  .modal { transition: opacity 120ms linear; }
  @starting-style {
    .modal { transform: none; }
    .toast { transform: none; }
  }
}

/* ===== Alto contraste forzado (Windows) ===== */
@media (forced-colors: active) {
  .boton, .boton-icono, .chip, .toast, .modal { forced-color-adjust: none; border: 1px solid CanvasText; }
  .boton.primario, .pestana.activa, .ay-pestana.activa { background: Highlight; color: HighlightText; }
  .icono { forced-color-adjust: auto; }
}

@media print {
  #toasts, .modal-fondo, .btn-tema, .menu-hamburguesa { display: none !important; }
  .tabla-envoltura { max-height: none; overflow: visible; }
  .tabla .col-fija { position: static; box-shadow: none; }
}

/* El atributo hidden manda sobre cualquier display de autor (.linea, .pestanas
   button, .formulario-linea…): sin esto, `el.hidden = true` no ocultaba nada
   en los bloques con display:flex. */
[hidden] { display: none !important; }

/* ===== Grupos del menú lateral (app de RH y panel ISCOM) =====
 * El título del grupo es un botón: pliega y despliega sus entradas. UI.gruposMenu
 * recuerda el estado en localStorage y el grupo de la vista activa siempre abre. */
.menu-grupo { display: flex; flex-direction: column; gap: 2px; }
.menu-grupo + .menu-grupo { margin-top: 6px; }
.menu-titulo {
  display: flex; align-items: center; justify-content: space-between; width: 100%;
  background: none; border: none; color: inherit; cursor: pointer; font: inherit; text-align: left;
  font-size: var(--tx-xs); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; opacity: .55;
  padding: 8px 12px 2px; border-radius: var(--radio); min-height: 0;
}
.menu-titulo:hover, .menu-titulo:focus-visible { opacity: .95; }
.menu-titulo:focus-visible { outline: 2px solid var(--sobre-primario, #fff); outline-offset: -2px; }
.menu-titulo .icono { width: 14px; height: 14px; flex: none; transition: transform var(--t-corto) ease; }
.menu-grupo.plegado .menu-titulo .icono { transform: rotate(-90deg); }
.menu-items { display: flex; flex-direction: column; gap: 2px; }
.menu-grupo.plegado .menu-items { display: none; }
